From: Christian Femers Date: Tue, 3 Sep 2019 04:28:01 +0000 (+0200) Subject: A proposal for resolving the loading problem of json files X-Git-Url: https://mograsim.net/gitweb/?p=Mograsim.git;a=commitdiff_plain;h=8e8d5776ccc95a08885789834abd55cc50e18a24 A proposal for resolving the loading problem of json files --- diff --git a/net.mograsim.logic.model.am2900/META-INF/MANIFEST.MF b/net.mograsim.logic.model.am2900/META-INF/MANIFEST.MF index fb03a1f6..6dfa1831 100644 --- a/net.mograsim.logic.model.am2900/META-INF/MANIFEST.MF +++ b/net.mograsim.logic.model.am2900/META-INF/MANIFEST.MF @@ -3,11 +3,15 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: net.mograsim.logic.model.am2900;singleton:=true Bundle-Version: 0.1.0.qualifier -Export-Package: net.mograsim.logic.model.am2900.components, +Export-Package: net.mograsim.logic.model.am2900, + net.mograsim.logic.model.am2900.components, net.mograsim.logic.model.am2900.components.am2904, net.mograsim.logic.model.am2900.components.am2910, + net.mograsim.logic.model.am2900.machine, net.mograsim.logic.model.examples Bundle-RequiredExecutionEnvironment: JavaSE-11 -Require-Bundle: net.mograsim.logic.model;bundle-version="0.1.0";visibility:=reexport +Require-Bundle: net.mograsim.machine;bundle-version="0.1.0";visibility:=reexport, + org.eclipse.osgi Automatic-Module-Name: net.mograsim.logic.model.am2900 Bundle-Vendor: Mograsim Team +Bundle-Activator: net.mograsim.logic.model.am2900.Am2900Loader diff --git a/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/Am2900Loader.java b/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/Am2900Loader.java new file mode 100644 index 00000000..a2142341 --- /dev/null +++ b/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/Am2900Loader.java @@ -0,0 +1,59 @@ +package net.mograsim.logic.model.am2900; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator; +import net.mograsim.logic.model.serializing.ResourceLoader; + +public class Am2900Loader implements BundleActivator +{ + private static AtomicBoolean activated = new AtomicBoolean(false); + + @Override + public void start(BundleContext context) throws Exception + { + setup(); // TODO: useful? + } + + @Override + public void stop(BundleContext context) throws Exception + { + // nothing + } + + public static void setup() + { + if (activated.getAndSet(true)) + return; + IndirectGUIComponentCreator.registerResourceLoader(new Am2900ResourceLoader(), "Am2900Loader"); + IndirectGUIComponentCreator.loadStandardComponentIDs(Am2900Loader.class.getResourceAsStream("standardComponentIDMapping.json")); + System.out.println("SETUP DONE"); + } + + static + { + setup(); + } + + /** + * @see ResourceLoader + */ + public static ResourceLoader resourceLoader() + { + return new Am2900ResourceLoader(); + } + + static class Am2900ResourceLoader implements ResourceLoader + { + @Override + public InputStream loadResource(String path) throws IOException + { + return Am2900ResourceLoader.class.getResourceAsStream(path); + } + } +} diff --git a/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/standardComponentIDMapping.json b/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/standardComponentIDMapping.json new file mode 100644 index 00000000..b111b71f --- /dev/null +++ b/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/standardComponentIDMapping.json @@ -0,0 +1,54 @@ +mograsim version: 0.1.3 +{ + "GUIAm2904RegCTInstrDecode": "class:net.mograsim.logic.model.am2900.components.am2904.GUIAm2904RegCTInstrDecode", + "GUIAm2904ShiftInstrDecode": "class:net.mograsim.logic.model.am2900.components.am2904.GUIAm2904ShiftInstrDecode", + "GUIAm2910InstrPLA": "class:net.mograsim.logic.model.am2900.components.am2910.GUIAm2910InstrPLA", + "GUIAm2910RegCntr": "class:net.mograsim.logic.model.am2900.components.am2910.GUIAm2910RegCntr", + "GUIAm2910SP": "class:net.mograsim.logic.model.am2900.components.am2910.GUIAm2910SP", + "GUIdff12": "class:net.mograsim.logic.model.am2900.components.GUIdff12", + "GUIdff4_finewe": "class:net.mograsim.logic.model.am2900.components.GUIdff4_finewe", + "GUIinc12": "class:net.mograsim.logic.model.am2900.components.GUIinc12", + "GUInor12": "class:net.mograsim.logic.model.am2900.components.GUInor12", + "GUIram5_12": "class:net.mograsim.logic.model.am2900.components.GUIram5_12", + "GUIsel4_12": "class:net.mograsim.logic.model.am2900.components.GUIsel4_12", + + "GUIAm2901": "resource:Am2900Loader:/components/am2901/GUIAm2901.json", + "GUIAm2901ALUFuncDecode": "resource:Am2900Loader:/components/am2901/GUIAm2901ALUFuncDecode.json", + "GUIAm2901ALUInclDecode": "resource:Am2900Loader:/components/am2901/GUIAm2901ALUInclDecode.json", + "GUIAm2901ALUInclSourceDecodeInclFunctionDecode": "resource:Am2900Loader:/components/am2901/GUIAm2901ALUInclSourceDecodeInclFunctionDecode.json", + "GUIAm2901ALUOneBit": "resource:Am2900Loader:/components/am2901/GUIAm2901ALUOneBit.json", + "GUIAm2904": "resource:Am2900Loader:/components/am2904/GUIAm2904.json", + "GUIAm2910": "resource:Am2900Loader:/components/am2910/GUIAm2910.json", + "GUIAm2904MSR": "resource:Am2900Loader:/components/am2904/GUIAm2904MSR.json", + "GUIAm2904muSR": "resource:Am2900Loader:/components/am2904/GUIAm2904muSR.json", + "GUIAm2904TestLogic": "resource:Am2900Loader:/components/am2904/GUIAm2904TestLogic.json", + "GUIAm2901DestDecode": "resource:Am2900Loader:/components/am2901/GUIAm2901DestDecode.json", + "GUIAm2901SourceDecode": "resource:Am2900Loader:/components/am2901/GUIAm2901SourceDecode.json", + "GUI_rsLatch": "resource:Am2900Loader:/components/GUI_rsLatch.json", + "GUIand": "resource:Am2900Loader:/components/GUIand.json", + "GUIand41": "resource:Am2900Loader:/components/GUIand41.json", + "GUIandor414": "resource:Am2900Loader:/components/GUIandor414.json", + "GUIdemux2": "resource:Am2900Loader:/components/GUIdemux2.json", + "GUIdff": "resource:Am2900Loader:/components/GUIdff.json", + "GUIdff4": "resource:Am2900Loader:/components/GUIdff4.json", + "GUIdff4_invwe": "resource:Am2900Loader:/components/GUIdff4_invwe.json", + "GUIdlatch": "resource:Am2900Loader:/components/GUIdlatch.json", + "GUIdlatch4": "resource:Am2900Loader:/components/GUIdlatch4.json", + "GUIfulladder": "resource:Am2900Loader:/components/GUIfulladder.json", + "GUIhalfadder": "resource:Am2900Loader:/components/GUIhalfadder.json", + "GUImux1": "resource:Am2900Loader:/components/GUImux1.json", + "GUImux1_4": "resource:Am2900Loader:/components/GUImux1_4.json", + "GUImux2": "resource:Am2900Loader:/components/GUImux2.json", + "GUImux2_4": "resource:Am2900Loader:/components/GUImux2_4.json", + "GUImux3": "resource:Am2900Loader:/components/GUImux3.json", + "GUInand3": "resource:Am2900Loader:/components/GUInand3.json", + "GUInot4": "resource:Am2900Loader:/components/GUInot4.json", + "GUIor4": "resource:Am2900Loader:/components/GUIor4.json", + "GUIor_4": "resource:Am2900Loader:/components/GUIor_4.json", + "GUIram2": "resource:Am2900Loader:/components/GUIram2.json", + "GUIram4": "resource:Am2900Loader:/components/GUIram4.json", + "GUIsel1": "resource:Am2900Loader:/components/GUIsel1.json", + "GUIsel2_4": "resource:Am2900Loader:/components/GUIsel2_4.json", + "GUIsel3_4": "resource:Am2900Loader:/components/GUIsel3_4.json", + "GUIxor": "resource:Am2900Loader:/components/GUIxor.json" +} \ No newline at end of file diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/IndirectGUIComponentCreator.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/IndirectGUIComponentCreator.java index 6ff8adb1..f346d029 100644 --- a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/IndirectGUIComponentCreator.java +++ b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/IndirectGUIComponentCreator.java @@ -3,9 +3,12 @@ package net.mograsim.logic.model.serializing; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; +import java.lang.reflect.InvocationTargetException; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; import com.google.gson.JsonElement; import com.google.gson.JsonNull; @@ -13,6 +16,7 @@ import com.google.gson.JsonObject; import net.mograsim.logic.model.model.ViewModelModifiable; import net.mograsim.logic.model.model.components.GUIComponent; +import net.mograsim.logic.model.model.components.submodels.SubmodelComponent; import net.mograsim.logic.model.snippets.CodeSnippetSupplier; import net.mograsim.logic.model.util.JsonHandler; @@ -22,10 +26,16 @@ public class IndirectGUIComponentCreator private static final Map standardComponentIDsUnmodifiable = Collections.unmodifiableMap(standardComponentIDs); private static final Map componentSuppliers = new HashMap<>(); + private static final Map resourceLoaders = new HashMap<>(); static { - try (InputStream s = IndirectGUIComponentCreator.class.getResourceAsStream("standardComponentIDMapping.json")) + loadStandardComponentIDs(IndirectGUIComponentCreator.class.getResourceAsStream("standardComponentIDMapping.json")); + } + + public static void loadStandardComponentIDs(InputStream standardComponentIdMappingStream) + { + try (InputStream s = standardComponentIdMappingStream) { if (s == null) throw new IOException("Resource not found"); @@ -51,7 +61,7 @@ public class IndirectGUIComponentCreator public static void addStandardComponentID(String standardComponentID, String associatedComponentID) { - if (!associatedComponentID.startsWith("file:") && !associatedComponentID.startsWith("class:")) + if (!associatedComponentID.matches("(file|class|resource):.+")) throw new IllegalArgumentException("Unrecognized component ID format: " + associatedComponentID); standardComponentIDs.put(standardComponentID, associatedComponentID); } @@ -96,25 +106,56 @@ public class IndirectGUIComponentCreator if (componentSupplier != null) return componentSupplier.create(model, params, name); throw new IllegalArgumentException("Component supplier not found for ID " + id + " (resolved: " + resolvedID + ")"); - } else - // we know id has to start with "file:" here - // because standardComponentIDs only contains strings starting with "class:" or "file:" - if (params != null && !JsonNull.INSTANCE.equals(params)) + } else if (params != null && !JsonNull.INSTANCE.equals(params)) throw new IllegalArgumentException("Can't give params to a component deserialized from a JSON file"); - try + if (resolvedID.startsWith("resource:")) { - String filename = resolvedID.substring(5); - JsonObject jsonContents = JsonHandler.readJson(filename, JsonObject.class); - SerializablePojo jsonContentsAsSerializablePojo = JsonHandler.parser.fromJson(jsonContents, SerializablePojo.class); - if (jsonContentsAsSerializablePojo.version == null) - return LegacySubmodelComponentSerializer.deserialize(model, - JsonHandler.parser.fromJson(jsonContents, LegacySubmodelComponentParams.class), name, id, null); - return SubmodelComponentSerializer.deserialize(model, - JsonHandler.parser.fromJson(jsonContents, SubmodelComponentParams.class), name, id, null); - } - catch (IOException e) + String[] parts = resolvedID.split(":"); + if (parts.length != 3) + throw new IllegalArgumentException("invaild resource id: " + resolvedID); + String rLoadID = parts[1]; + String resID = parts[2]; + try + { + ResourceLoader loader; + if (!resourceLoaders.containsKey(rLoadID)) + { + Class c = Class.forName(rLoadID); + if (ResourceLoader.class.isAssignableFrom(c)) + loader = (ResourceLoader) c.getConstructor().newInstance(); + else + loader = (ResourceLoader) Objects.requireNonNull(c.getMethod("resourceLoader").invoke(null)); + resourceLoaders.put(rLoadID, loader); + } else + { + loader = Objects.requireNonNull(resourceLoaders.get(parts[1])); + } + JsonObject jsonContents = JsonHandler.readJson(loader.loadResource(resID), JsonObject.class); + return loadComponentFromJsonObject(model, id, name, jsonContents); + } + catch (IOException e) + { + throw new UncheckedIOException(e); + } + catch (ClassCastException | ReflectiveOperationException e) + { + throw new IllegalArgumentException("invaild resource loader specified:" + parts[1], e); + } + } else if (resolvedID.startsWith("file:")) + { + try + { + String filename = resolvedID.substring(5); + JsonObject jsonContents = JsonHandler.readJson(filename, JsonObject.class); + return loadComponentFromJsonObject(model, id, name, jsonContents); + } + catch (IOException e) + { + throw new UncheckedIOException(e); + } + } else { - throw new UncheckedIOException(e); + throw new IllegalArgumentException("unable to resolve/interpret id" + resolvedID); } } } @@ -123,11 +164,36 @@ public class IndirectGUIComponentCreator public static String resolveID(String id) { - if (id.startsWith("class:") || id.startsWith("file:")) + if (id.matches("(file|class|resource):.+")) return id; return standardComponentIDs.get(id); } + private static SubmodelComponent loadComponentFromJsonObject(ViewModelModifiable model, String id, String name, JsonObject jsonContents) + { + SerializablePojo jsonContentsAsSerializablePojo = JsonHandler.parser.fromJson(jsonContents, SerializablePojo.class); + if (jsonContentsAsSerializablePojo.version == null) + return LegacySubmodelComponentSerializer.deserialize(model, + JsonHandler.parser.fromJson(jsonContents, LegacySubmodelComponentParams.class), name, id, null); + return SubmodelComponentSerializer.deserialize(model, JsonHandler.parser.fromJson(jsonContents, SubmodelComponentParams.class), + name, id, null); + } + + public static void registerResourceLoader(ResourceLoader resourceLoader) + { + registerResourceLoader(resourceLoader, resourceLoader.getClass()); + } + + public static void registerResourceLoader(ResourceLoader resourceLoader, Class reference) + { + resourceLoaders.put(reference.getName(), Objects.requireNonNull(resourceLoader)); + } + + public static void registerResourceLoader(ResourceLoader resourceLoader, String reference) + { + resourceLoaders.put(reference, Objects.requireNonNull(resourceLoader)); + } + private static void tryLoadComponentClass(String componentClassName) { CodeSnippetSupplier.tryInvokeStaticInitializer(componentClassName, "Error loading component class %s: %s\n"); diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/ResourceLoader.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/ResourceLoader.java new file mode 100644 index 00000000..83dd745c --- /dev/null +++ b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/ResourceLoader.java @@ -0,0 +1,23 @@ +package net.mograsim.logic.model.serializing; + +import java.io.IOException; +import java.io.InputStream; + +import net.mograsim.logic.model.model.components.GUIComponent; + +/** + * For loading JSON {@link GUIComponent}s from other OSGI-Modules or jar-Files. + *

+ * An implementation must conform to either of the following rules: + *

    + *
  • A ResourceLoader class can be referenced directly in resource:qualifiedClassName:jsonResourcePath and is then + * instantiated using the public default constructor.
  • + *
  • A class referenced in resource:qualifiedClassName:jsonResourcePath provides a public static method called + * resourceLoader that returns an (non-null) object of the type {@link ResourceLoader}
  • + *
+ * + */ +public interface ResourceLoader +{ + InputStream loadResource(String path) throws IOException; +} diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/standardComponentIDMapping.json b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/standardComponentIDMapping.json index ec15a5a6..ded55bac 100644 --- a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/standardComponentIDMapping.json +++ b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/standardComponentIDMapping.json @@ -2,62 +2,13 @@ mograsim version: 0.1.3 { "GUIManualSwitch": "class:net.mograsim.logic.model.model.components.atomic.GUIManualSwitch", "GUIBitDisplay": "class:net.mograsim.logic.model.model.components.atomic.GUIBitDisplay", - "GUIAm2901": "file:components/am2901/GUIAm2901.json", - "GUIAm2901ALUFuncDecode": "file:components/am2901/GUIAm2901ALUFuncDecode.json", - "GUIAm2901ALUInclDecode": "file:components/am2901/GUIAm2901ALUInclDecode.json", - "GUIAm2901ALUInclSourceDecodeInclFunctionDecode": "file:components/am2901/GUIAm2901ALUInclSourceDecodeInclFunctionDecode.json", - "GUIAm2901ALUOneBit": "file:components/am2901/GUIAm2901ALUOneBit.json", - "GUIAm2904": "file:components/am2904/GUIAm2904.json", - "GUIAm2904MSR": "file:components/am2904/GUIAm2904MSR.json", - "GUIAm2904muSR": "file:components/am2904/GUIAm2904muSR.json", - "GUIAm2904RegCTInstrDecode": "class:net.mograsim.logic.model.am2900.components.am2904.GUIAm2904RegCTInstrDecode", - "GUIAm2904ShiftInstrDecode": "class:net.mograsim.logic.model.am2900.components.am2904.GUIAm2904ShiftInstrDecode", - "GUIAm2904TestLogic": "file:components/am2904/GUIAm2904TestLogic.json", - "GUIAm2901DestDecode": "file:components/am2901/GUIAm2901DestDecode.json", - "GUIAm2901SourceDecode": "file:components/am2901/GUIAm2901SourceDecode.json", - "GUIAm2910InstrPLA": "class:net.mograsim.logic.model.am2900.components.am2910.GUIAm2910InstrPLA", - "GUIAm2910RegCntr": "class:net.mograsim.logic.model.am2900.components.am2910.GUIAm2910RegCntr", - "GUIAm2910SP": "class:net.mograsim.logic.model.am2900.components.am2910.GUIAm2910SP", "GUIAndGate": "class:net.mograsim.logic.model.model.components.atomic.GUIAndGate", "GUIMerger": "class:net.mograsim.logic.model.model.components.atomic.GUIMerger", "GUINandGate": "class:net.mograsim.logic.model.model.components.atomic.GUINandGate", "GUIOrGate": "class:net.mograsim.logic.model.model.components.atomic.GUIOrGate", - "GUI_rsLatch": "file:components/GUI_rsLatch.json", - "GUIand": "file:components/GUIand.json", - "GUIand41": "file:components/GUIand41.json", - "GUIandor414": "file:components/GUIandor414.json", - "GUIdemux2": "file:components/GUIdemux2.json", - "GUIdff": "file:components/GUIdff.json", - "GUIdff12": "class:net.mograsim.logic.model.am2900.components.GUIdff12", - "GUIdff4": "file:components/GUIdff4.json", - "GUIdff4_finewe": "class:net.mograsim.logic.model.am2900.components.GUIdff4_finewe", - "GUIdff4_invwe": "file:components/GUIdff4_invwe.json", - "GUIdlatch": "file:components/GUIdlatch.json", - "GUIdlatch4": "file:components/GUIdlatch4.json", - "GUIfulladder": "file:components/GUIfulladder.json", - "GUIhalfadder": "file:components/GUIhalfadder.json", - "GUIinc12": "class:net.mograsim.logic.model.am2900.components.GUIinc12", - "GUImux1": "file:components/GUImux1.json", - "GUImux1_4": "file:components/GUImux1_4.json", - "GUImux2": "file:components/GUImux2.json", - "GUImux2_4": "file:components/GUImux2_4.json", - "GUImux3": "file:components/GUImux3.json", - "GUInand3": "file:components/GUInand3.json", - "GUInor12": "class:net.mograsim.logic.model.am2900.components.GUInor12", - "GUInot4": "file:components/GUInot4.json", - "GUIor4": "file:components/GUIor4.json", - "GUIor_4": "file:components/GUIor_4.json", - "GUIram2": "file:components/GUIram2.json", - "GUIram4": "file:components/GUIram4.json", - "GUIram5_12": "class:net.mograsim.logic.model.am2900.components.GUIram5_12", - "GUIsel1": "file:components/GUIsel1.json", - "GUIsel2_4": "file:components/GUIsel2_4.json", - "GUIsel3_4": "file:components/GUIsel3_4.json", - "GUIsel4_12": "class:net.mograsim.logic.model.am2900.components.GUIsel4_12", "GUISplitter": "class:net.mograsim.logic.model.model.components.atomic.GUISplitter", "GUITriStateBuffer": "class:net.mograsim.logic.model.model.components.atomic.GUITriStateBuffer", "GUIClock": "class:net.mograsim.logic.model.model.components.atomic.GUIClock", - "GUIxor": "file:components/GUIxor.json", "TextComponent": "class:net.mograsim.logic.model.model.components.atomic.TextComponent", "WireCrossPoint": "class:net.mograsim.logic.model.model.wires.WireCrossPoint" } \ No newline at end of file