From b8699860653e593271e50c8ba1b73f66fcb6287c Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Wed, 6 Jan 2021 12:05:23 +0100 Subject: Starting on splitting up into different modules. --- .../main/java/io/trygvis/rules/acme/AcmeIo.java | 260 +++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeIo.java (limited to 'module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeIo.java') diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeIo.java b/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeIo.java new file mode 100644 index 0000000..456195d --- /dev/null +++ b/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeIo.java @@ -0,0 +1,260 @@ +package io.trygvis.rules.acme; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; +import org.apache.commons.collections4.OrderedMap; +import org.drools.core.common.DefaultFactHandle; +import org.kie.api.KieBase; +import org.kie.api.runtime.rule.FactHandle; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.*; +import java.util.function.Function; + +@SuppressWarnings("unchecked") +public class AcmeIo { + private final ObjectMapper mapper; + + public AcmeIo(KieBase kieBase) { + var factory = new YAMLFactory(); + factory.enable(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID); + factory.enable(YAMLGenerator.Feature.USE_NATIVE_OBJECT_ID); + mapper = new ObjectMapper(factory); + var typeFactory = TypeFactory.defaultInstance() + .withClassLoader(new AcmeClassLoader(kieBase)); + mapper.setTypeFactory(typeFactory); + mapper.findAndRegisterModules(); + } + + public List load(String file) throws IOException { + var parser = mapper.getFactory().createParser(new File(file)); + + var objects = mapper.readValues(parser, AcmeObject.class).readAll(new ArrayList<>()); + + List items = new ArrayList<>(objects.size()); + for (AcmeObject object : objects) { + try { + var type = mapper.getTypeFactory().findClass(object.type); + var x = mapper.treeToValue(object.data, type); + items.add(x); + } catch (ClassNotFoundException e) { + throw new IOException(e); + } + } + + return items; + } + + public void dump(String s, Collection factHandles) throws IOException { + dump(s, factHandles, (o) -> true); + } + + // This should just sort by all getters instead. + static class FactCollection { + public final Class type; + public final List values; + + public FactCollection(Class type) { + this.type = type; + this.values = new ArrayList<>(); + } + + public void sort() { + var comparator = comparable(type); + + this.values.sort(comparator); + } + } + + private static final Map, Comparator> comparators = new HashMap<>(); + + private static > Comparator comparable(Class klass) { + var comparator = comparators.get(klass); + if (comparator != null) { + return comparator; + } + + // TODO: check if klass is a Comparable directly. + + var prioritizedKeys = List.of("key", "name", "fqdn"); + + var discoveredFieldsP1 = new LinkedHashMap>(); + var discoveredFieldsP2 = new LinkedHashMap>(); + + var prioritizedTypes = List.of(String.class, int.class, Number.class); + + for (var f : klass.getDeclaredFields()) { + if (f.getDeclaringClass() == Object.class) { + continue; + } + + if (!f.trySetAccessible()) { + continue; + } + + var collection = discoveredFieldsP2; + + if (prioritizedTypes.contains(f.getType())) { + collection = discoveredFieldsP1; + } + + collection.put(f.getName(), (Object o) -> { + try { + return f.get(o); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }); + } + +// for (var m : klass.getFields()) { +// if (m.getParameterCount() != 0) { +// continue; +// } +// +// var name = m.getName(); +// +// if (name.startsWith("get") && name.length() > 3 && Character.isUpperCase(name.charAt(4))) { +// name = name.substring(3, 3).toLowerCase() + name.substring(4); +// } else { +// continue; +// } +// +// if (!m.isAccessible()) { +// if (!m.trySetAccessible()) +// return null; +// } +// +// discoveredFields.put(name, m); +// } + +// System.out.printf("Sorting %s by:%n", klass.getName()); + + var discoveredFields = new LinkedHashMap<>(discoveredFieldsP1); + discoveredFields.putAll(discoveredFieldsP2); + + List> accessors = new ArrayList<>(); + for (String prioritizedKey : prioritizedKeys) { + var m = discoveredFields.remove(prioritizedKey); + if (m == null) { + continue; + } + + accessors.add(m); +// System.out.println(" + " + prioritizedKey); + } + accessors.addAll(discoveredFields.values()); +// discoveredFields.keySet().forEach((s)-> System.out.println(" - " + s)); + + comparator = (a, b) -> { +// if (klass.getName().contains("AcmeServer")) { +// System.out.println("AcmeIo.comparable"); +// } + + for (var method : accessors) { + var x = method.apply(a); + var y = method.apply(b); + + if (x == null && y == null) { + continue; + } + + if (x == null) { + return -1; + } else if (y == null) { + return 1; + } else { + var res = x.toString().compareTo(y.toString()); + if (res != 0) { + return res; + } + } + } + + return 0; + }; + + comparators.put(klass, comparator); + + return comparator; + } + + public void dump(String s, Collection factHandles, Function filter) throws IOException { + var out = new File("out"); + + if (!out.isDirectory()) { + if (!out.mkdirs()) { + throw new IOException("Could not create directory: " + out); + } + } + + var facts = new TreeMap, FactCollection>(Comparator.comparing(Class::getName)); + for (var handle : factHandles) { + if (handle instanceof DefaultFactHandle h) { + var obj = h.getObject(); + if (!filter.apply(obj)) { + continue; + } + + Class type = obj.getClass(); + var collection = facts.get(type); + + if (collection == null) { + collection = new FactCollection(type); + facts.put(type, collection); + } + + collection.values.add(obj); + } + } + + var factory = mapper.getFactory(); + try (var writer = new FileWriter(new File(out, s + ".yaml")); + var g = factory.createGenerator(writer)) { + for (var e : facts.entrySet()) { + var name = e.getKey().getName(); + + var collection = e.getValue(); + collection.sort(); + for (var fact : collection.values) { + g.writeObject(new AcmeObject(name, mapper.valueToTree(fact))); + } + } + } + } + + private static class AcmeClassLoader extends ClassLoader { + private final KieBase kieBase; + + public AcmeClassLoader(KieBase kieBase) { + this.kieBase = kieBase; + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + try { + return super.loadClass(name); + } catch (ClassNotFoundException e) { + var i = name.lastIndexOf('.'); + String pkg, klass; + if (i == -1) { + pkg = null; + klass = name; + } else { + pkg = name.substring(0, i); + klass = name.substring(i + 1); + } + var clazz = kieBase.getFactType(pkg, klass); + if (clazz == null) { + throw e; + } + + return clazz.getFactClass(); + } + } + } +} -- cgit v1.2.3