A proposal for resolving the loading problem of json files
[Mograsim.git] / net.mograsim.logic.model / src / net / mograsim / logic / model / serializing / IndirectGUIComponentCreator.java
index 6ff8adb..f346d02 100644 (file)
@@ -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<String, String> standardComponentIDsUnmodifiable = Collections.unmodifiableMap(standardComponentIDs);
 
        private static final Map<String, ComponentSupplier> componentSuppliers = new HashMap<>();
+       private static final Map<String, ResourceLoader> 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");