Merge branch 'JAL-3878_ws-overhaul-3' into mmw/Release_2_12_ws_merge
[jalview.git] / src / jalview / ws2 / params / SimpleParamDatastore.java
diff --git a/src/jalview/ws2/params/SimpleParamDatastore.java b/src/jalview/ws2/params/SimpleParamDatastore.java
new file mode 100644 (file)
index 0000000..259bdca
--- /dev/null
@@ -0,0 +1,256 @@
+package jalview.ws2.params;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.ParamManager;
+import jalview.ws.params.WsParamSetI;
+
+/**
+ * A web client agnostic parameters datastore that provides view of the
+ * parameters and delegates parameters storage to {@link ParamManager}
+ * if given. Parameter datastore maintains the applicable service url
+ * the list of service parameters and both presets and user defined
+ * parameter sets 
+ */
+public class SimpleParamDatastore implements ParamDatastoreI
+{
+  protected URL serviceUrl;
+  protected List<ArgumentI> parameters;
+  protected List<SimpleParamSet> servicePresets;
+  protected List<SimpleParamSet> userPresets = new ArrayList<>();
+  protected ParamManager manager;
+
+  /**
+   * Create new parameter datastore bound to the specified url with
+   * given service parameters and presets. Additionally, a parameters
+   * manager may be provided that will be used to load and store
+   * user parameter sets.
+   *  
+   * @param serviceUrl applicable url
+   * @param parameters service parameters
+   * @param presets unmodifiable service presets
+   * @param manager parameter manager used to load and store user presets
+   */
+  public SimpleParamDatastore(URL serviceUrl, List<ArgumentI> parameters,
+      List<? extends WsParamSetI> presets, ParamManager manager)
+  {
+    this.serviceUrl = serviceUrl;
+    this.parameters = Collections.unmodifiableList(new ArrayList<>(parameters));
+    this.servicePresets = new ArrayList<>(presets.size());
+    for (var preset : presets)
+    {
+      if (preset instanceof SimpleParamSet)
+        servicePresets.add((SimpleParamSet) preset);
+      else
+        servicePresets.add(new SimpleParamSet(preset));
+    }
+    this.servicePresets = Collections.unmodifiableList(this.servicePresets);
+    this.manager = manager;
+    if (manager != null)
+      _initManager(manager);
+  }
+  
+  private void _initManager(ParamManager manager)
+  {
+    manager.registerParser(serviceUrl.toString(), this);
+    WsParamSetI[] paramSets = manager.getParameterSet(null, serviceUrl.toString(),
+        true, false);
+    if (paramSets != null)
+    {
+      for (WsParamSetI paramSet : paramSets)
+      {
+        // TODO: handle mismatch between preset and current parameters
+        if (paramSet instanceof SimpleParamSet)
+          userPresets.add((SimpleParamSet) paramSet);
+        else
+        {
+          userPresets.add(new SimpleParamSet(paramSet));
+          Cache.log.warn(String.format(
+              "Parameter set instance type %s is not applicable to service"
+              + "at %s.", paramSet.getClass(), serviceUrl));
+        }
+      }
+    }
+  }
+  
+  @Override
+  public List<WsParamSetI> getPresets()
+  {
+    List<WsParamSetI> presets = new ArrayList<>();
+    presets.addAll(servicePresets);
+    presets.addAll(userPresets);
+    return presets;
+  }
+
+  @Override
+  public SimpleParamSet getPreset(String name)
+  {
+    SimpleParamSet preset = null;
+    preset = getUserPreset(name);
+    if (preset != null)
+      return preset;
+    preset = getServicePreset(name);
+    if (preset != null)
+      return preset;
+    return null;
+  }
+  
+  public SimpleParamSet getUserPreset(String name)
+  {
+    for (SimpleParamSet preset : userPresets)
+    {
+      if (name.equals(preset.getName()))
+        return preset;
+    }
+    return null;
+  }
+  
+  public SimpleParamSet getServicePreset(String name)
+  {
+    for (SimpleParamSet preset : servicePresets)
+    {
+      if (name.equals(preset.getName()))
+        return preset;
+    }
+    return null;
+  }
+
+  @Override
+  public List<ArgumentI> getServiceParameters()
+  {
+    return parameters;
+  }
+
+  @Override
+  public boolean presetExists(String name)
+  {
+    return getPreset(name) != null;
+  }
+
+  @Override
+  public void deletePreset(String name)
+  {
+    var userPreset = getUserPreset(name);
+    if (userPreset != null)
+    {
+      userPresets.remove(userPreset);
+      if (manager != null)
+      {
+        manager.deleteParameterSet(userPreset);
+      }
+    }
+    else if (getServicePreset(name) != null)
+    {
+      throw new RuntimeException(MessageManager.getString(
+          "error.implementation_error_attempt_to_delete_service_preset"));
+    }
+    else
+    {
+      Cache.log.warn("Implementation error: no preset to delete");
+    }
+  }
+
+  @Override
+  public void storePreset(String presetName, String text, List<ArgumentI> jobParams)
+  {
+    var builder = SimpleParamSet.newBuilder();
+    builder.name(presetName);
+    builder.description(text);
+    builder.arguments(jobParams);
+    builder.url(serviceUrl.toString());
+    builder.modifiable(true);
+    var preset = builder.build();
+    userPresets.add(preset);
+    if (manager != null)
+      manager.storeParameterSet(preset);
+  }
+
+  @Override
+  public void updatePreset(String oldName, String newName, String text, List<ArgumentI> jobParams)
+  {
+    var preset = getPreset(oldName != null ? oldName : newName);
+    if (preset == null)
+      throw new RuntimeException(MessageManager.formatMessage(
+          "error.implementation_error_cannot_locate_oldname_presetname",
+          oldName, newName));
+    preset.setName(newName);
+    preset.setDescription(text);
+    preset.setArguments(jobParams);
+    preset.setApplicableUrls(new String[] { serviceUrl.toString() });
+    if (manager != null)
+      manager.storeParameterSet(preset);
+  }
+
+  @Override
+  public WsParamSetI parseServiceParameterFile(String name, String description,
+      String[] serviceURL, String parameters)
+      throws IOException
+  {
+    var builder = SimpleParamSet.newBuilder();
+    builder.name(name);
+    builder.description(description);
+    builder.urls(serviceURL);
+    builder.modifiable(true);
+    Unmarshaller unmarshaller;
+    try
+    {
+      var ctx = JAXBContext.newInstance(ArgumentBeanList.class);
+      unmarshaller = ctx.createUnmarshaller();
+    } catch (JAXBException e)
+    {
+      throw new RuntimeException(e);
+    }
+    ArgumentBeanList argList;
+    try
+    {
+      argList = (ArgumentBeanList) unmarshaller.unmarshal(new StringReader(parameters));
+    } catch (JAXBException | ClassCastException e)
+    {
+      throw new IOException("Unable to load parameters from file", e);
+    }
+    builder.arguments(argList.arguments);
+    return builder.build();
+  }
+
+  @Override
+  public String generateServiceParameterFile(WsParamSetI pset) throws IOException
+  {
+    Marshaller marshaller;
+    try 
+    {
+      var ctx = JAXBContext.newInstance(ArgumentBeanList.class);
+      marshaller = ctx.createMarshaller();
+      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+      marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
+    } catch (JAXBException e)
+    {
+      throw new RuntimeException(e);
+    }
+    ArgumentBeanList argList = ArgumentBeanList.fromList(pset.getArguments());
+    var out = new ByteArrayOutputStream();
+    try
+    {
+      marshaller.marshal(argList, out);
+    } catch (JAXBException e)
+    {
+      throw new IOException("Unable to generate parameters file", e);
+    }
+    return out.toString();
+  }
+
+}