modularize project

This commit is contained in:
wea_ondara
2022-11-23 14:21:11 +01:00
parent 915fc4a87b
commit 481280ed88
200 changed files with 177 additions and 101 deletions

46
cli/pom.xml Normal file
View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jef</artifactId>
<groupId>jef</groupId>
<version>0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cli</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>jef.main.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>jef</groupId>
<artifactId>core</artifactId>
<version>0.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,27 @@
package jef.main;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
if (args.length == 0) {
printHelp();
System.exit(1);
}
switch (args[0].toLowerCase()) {
case "help":
printHelp();
case "migration":
MigrationCommandHandler.handleMigration(Arrays.copyOfRange(args, 1, args.length));
default:
printHelp();
}
}
static void printHelp() {
System.out.println("Usage: java -jar thisfile <command> [options]");
MigrationCommandHandler.printHelp();
System.exit(1);
}
}

View File

@@ -0,0 +1,294 @@
package jef.main;
import jef.Database;
import jef.model.DbContext;
import jef.model.DbContextOptions;
import jef.model.ModelBuilder;
import jef.model.migration.creator.MigrationCreator;
import jef.mysql.MysqlDatabase;
import jef.util.Util;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.JarURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class MigrationCommandHandler {
static void handleMigration(String[] args) {
if (args.length == 0) {
Main.printHelp();
}
try {
switch (args[0].toLowerCase()) {
case "add":
handleMigrationAdd(Arrays.copyOfRange(args, 1, args.length));
case "remove":
handleMigrationRemove(Arrays.copyOfRange(args, 1, args.length));
case "list":
handleMigrationList(Arrays.copyOfRange(args, 1, args.length));
default:
Main.printHelp();
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
System.exit(0);
}
private static void handleMigrationList(String[] args) {
}
private static void handleMigrationRemove(String[] args) {
}
private static void handleMigrationAdd(String[] args) throws Exception {
String contextName = null;
String migrationPackage = null;
String targetFolder = null;
String name = null;
var classPath = new ArrayList<String>();
for (int i = 0; i < args.length; i++) {
switch (args[i].toLowerCase()) {
case "--cp":
if (i + 1 >= args.length) {
Main.printHelp();
}
classPath.addAll(List.of(args[++i].split(":")));//TODO does not work well on windows (:)
break;
case "--context":
case "-c":
if (i + 1 >= args.length) {
Main.printHelp();
}
contextName = args[++i];
break;
case "--output":
case "-o":
if (i + 1 >= args.length) {
Main.printHelp();
}
targetFolder = args[++i];
break;
default:
if (name != null) {
Main.printHelp();
}
name = args[i];
break;
}
}
// if (Set.of(contextName, targetFolder, name).contains(null)) {
// Main.printUsage();
// }
if (name == null) {
System.err.println("The migration requires a name.");
System.exit(1);
}
//find data locations
var urls = classPath.stream().map(e -> Util.tryGet(() -> new File(e).toURI().toURL()).orElseThrow()).toArray(URL[]::new);
var cl = new URLClassLoader(urls, MigrationCommandHandler.class.getClassLoader());
var context = contextName == null ? findAnyContext(cl) : findContextByName(cl, contextName);
targetFolder = targetFolder == null ? System.getProperty("user.dir") : targetFolder;
var targetFolderFile = new File(targetFolder);
targetFolderFile.mkdirs();
migrationPackage = findMigrationPackageName(targetFolder);
//find data
var currentSnapshotFile = new File(targetFolderFile, "CurrentSnapshot.java");
var from = !currentSnapshotFile.isFile()
? new ModelBuilder()
: (ModelBuilder) cl.loadClass((migrationPackage != null ? migrationPackage + "." : "") + "CurrentSnapshot").getConstructor().newInstance();
var to = ModelBuilder.from(context.orElseThrow().getClass());
// context.orElseThrow().onModelCreate(to);
//begin
var date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
var className = "M" + date + "_" + name;
var creator = new MigrationCreator();
var result = creator.createMigration(from, to, className, migrationPackage, currentSnapshotFile.isFile() ? Files.readString(currentSnapshotFile.toPath()) : null);
Files.writeString(new File(targetFolder, className + ".java").toPath(), result.getMigration(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
Files.writeString(new File(targetFolder, className + "Snapshot.java").toPath(), result.getMigrationSnapshot(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
Files.writeString(new File(targetFolder, "CurrentSnapshot.java").toPath(), result.getCurrentSnapshot(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
System.exit(0);
}
private static Optional<DbContext> findAnyContext(URLClassLoader cl) {
return findContextByName(cl, "");
}
private static Optional<DbContext> findContextByName(URLClassLoader cl, String contextName) {
Util.ThrowableFunction<String, DbContext> finder = (String entryName) -> {
var cls = cl.loadClass(entryName.substring(0, entryName.length() - ".class".length()).replace("/", "."));
var parent = cls;
// var interfaces = cls.getInterfaces();
// while (parent != Object.class && !Set.of(interfaces).contains(DbContext.class)) {
while (parent != Object.class && parent != DbContext.class) {
parent = parent.getSuperclass();
// interfaces = cls.getInterfaces();
}
// if (Set.of(interfaces).contains(DbContext.class)) {
if (parent == DbContext.class) {
var paramInitializer = new HashMap<Class<?>, Supplier<?>>();
paramInitializer.put(Database.class, () -> new MysqlDatabase(null, null));
paramInitializer.put(DbContextOptions.class, () -> new DbContextOptions(null));
var ctors = cls.getDeclaredConstructors();//TODO create a function for initializing db contexts
if (ctors.length == 0) {
System.err.println("No constructor found in " + cls.getName());
return null;
}
var ctor = Arrays.stream(ctors)
.filter(e -> Arrays.stream(e.getParameterTypes())
.allMatch(p -> Database.class.isAssignableFrom(p) || DbContextOptions.class.isAssignableFrom(p)))
.findFirst().orElse(null);
if (ctor == null) {
return null;
}
var args = Arrays.stream(ctor.getParameterTypes()).map(p -> paramInitializer.get(p).get()).toArray();
return Util.tryGet(() -> (DbContext) ctor.newInstance(args)).orElse(null);
}
return null;
};
return Arrays.stream(cl.getURLs()).map(url -> {
URLConnection conn;
try {
conn = url.openConnection();
} catch (IOException ignored) {
return null;
}
if (conn instanceof JarURLConnection) {
try (var zip = new ZipInputStream(conn.getInputStream())) {
ZipEntry entry;
while ((entry = zip.getNextEntry()) != null) {
if (entry.isDirectory() || !entry.getName().endsWith(contextName + ".class")) {
continue;
}
return finder.apply(entry.getName());
}
} catch (Throwable ignored) {
}
} else {
var search = new ArrayList<URL>();
search.add(url);
while (search.size() > 0) {
try {
var currentUrl = search.remove(0);
conn = currentUrl.openConnection();
try (var is = conn.getInputStream();
var isr = new InputStreamReader(is);
var br = new BufferedReader(isr)) {
String entry;
while ((entry = br.readLine()) != null) {
// System.out.println(entry);
var newUri = currentUrl.toURI().toString();
newUri = newUri.endsWith("/") ? newUri : newUri + "/";
newUri += entry;
search.add(new URI(newUri).toURL());
if (!entry.endsWith(contextName + ".class")) {//entry.isDirectory() ||
continue;
}
return finder.apply(new URI(newUri).getPath().substring(url.toURI().getPath().length()));
}
}
} catch (Throwable ignored) {
}
}
}
return null;
})
.filter(Objects::nonNull)
.findFirst();
}
private static String findMigrationPackageName(String dir) {
//search for java file in dir and take package name from there
var javaFiles = new File(dir).listFiles(file -> file.isFile() && file.getName().endsWith(".java"));
if (javaFiles.length > 0) {
try {
var contextFileString = Files.readAllLines(javaFiles[0].toPath()).stream().collect(Collectors.joining(" "));
var pattern = Pattern.compile("\\s*package\\s+(.*?);");
var matcher = pattern.matcher(contextFileString);
if (matcher.find()) {
return matcher.group(1);
}
} catch (IOException ignored) {
}
}
// //try finding out from dir path
var path = new File(dir).getAbsolutePath();
var i = path.indexOf("/src/");
if (i >= 0) {
path = path.substring(i + "/src/".length());
if (path.startsWith("main/")) {
path = path.substring("main/".length());
if (path.startsWith("java/")) {
path = path.substring("java/".length());
}
}
}
i = path.indexOf("/target/");
if (i >= 0) {
path = path.substring(i + "/target/".length());
if (path.startsWith("generated-migrations/")) {
path = path.substring("generated-migrations/".length());
if (path.startsWith("src/")) {
path = path.substring("src/".length());
}
}
}
return path.replace("/", ".");
// return null;
}
public static void printHelp() {
System.out.println("migration add --cp <classpath> [--context/-c <context class name>] [--output/-o <folder for migrations>] <name>");
System.out.println("migration remove --cp <classpath> [--context/-c <context class name>] [--output/-o <folder for migrations>] <name>");
System.out.println("migration list");
}
// private static String findMigrationSnapshot(String dir) {
// var javaFiles = new File(dir).listFiles(file -> file.isFile() && file.getName().endsWith(".java"));
// if (javaFiles.length > 0) {
// try {
// var contextFileString = Files.readAllLines(javaFiles[0].toPath()).stream().collect(Collectors.joining(" "));
// var pattern = Pattern.compile("\\s*package\\s+(.*?);");
// var matcher = pattern.matcher(contextFileString);
// if (matcher.find()) {
// return matcher.group(1);
// }
// } catch (IOException ignored) {
// }
// }
// }
}

View File

@@ -0,0 +1,23 @@
package jef.util;
import java.util.Optional;
public abstract class Util {
public static <T> Optional<T> tryGet(ThrowableSupplier<T> s) {
try {
return Optional.ofNullable(s.get());
} catch (Throwable t) {
return Optional.empty();
}
}
@FunctionalInterface
public interface ThrowableSupplier<T> {
T get() throws Throwable;
}
@FunctionalInterface
public interface ThrowableFunction<T, R> {
R apply(T t) throws Throwable;
}
}