JAL-3878 update branch from 2.12 merge from 2.11.2
[jalview.git] / src / jalview / ws2 / params / SimpleParamDatastore.java
1 package jalview.ws2.params;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.StringReader;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.List;
10
11 import javax.xml.bind.JAXBContext;
12 import javax.xml.bind.JAXBException;
13 import javax.xml.bind.Marshaller;
14 import javax.xml.bind.Unmarshaller;
15
16 import jalview.bin.Cache;
17 import jalview.bin.Console;
18 import jalview.util.MessageManager;
19 import jalview.ws.params.ArgumentI;
20 import jalview.ws.params.ParamDatastoreI;
21 import jalview.ws.params.ParamManager;
22 import jalview.ws.params.WsParamSetI;
23
24 /**
25  * A web client agnostic parameters datastore that provides view of the
26  * parameters and delegates parameters storage to {@link ParamManager}
27  * if given. Parameter datastore maintains the applicable service url
28  * the list of service parameters and both presets and user defined
29  * parameter sets 
30  */
31 public class SimpleParamDatastore implements ParamDatastoreI
32 {
33   protected URL serviceUrl;
34   protected List<ArgumentI> parameters;
35   protected List<SimpleParamSet> servicePresets;
36   protected List<SimpleParamSet> userPresets = new ArrayList<>();
37   protected ParamManager manager;
38
39   /**
40    * Create new parameter datastore bound to the specified url with
41    * given service parameters and presets. Additionally, a parameters
42    * manager may be provided that will be used to load and store
43    * user parameter sets.
44    *  
45    * @param serviceUrl applicable url
46    * @param parameters service parameters
47    * @param presets unmodifiable service presets
48    * @param manager parameter manager used to load and store user presets
49    */
50   public SimpleParamDatastore(URL serviceUrl, List<ArgumentI> parameters,
51       List<? extends WsParamSetI> presets, ParamManager manager)
52   {
53     this.serviceUrl = serviceUrl;
54     this.parameters = Collections.unmodifiableList(new ArrayList<>(parameters));
55     this.servicePresets = new ArrayList<>(presets.size());
56     for (var preset : presets)
57     {
58       if (preset instanceof SimpleParamSet)
59         servicePresets.add((SimpleParamSet) preset);
60       else
61         servicePresets.add(new SimpleParamSet(preset));
62     }
63     this.servicePresets = Collections.unmodifiableList(this.servicePresets);
64     this.manager = manager;
65     if (manager != null)
66       _initManager(manager);
67   }
68   
69   private void _initManager(ParamManager manager)
70   {
71     manager.registerParser(serviceUrl.toString(), this);
72     WsParamSetI[] paramSets = manager.getParameterSet(null, serviceUrl.toString(),
73         true, false);
74     if (paramSets != null)
75     {
76       for (WsParamSetI paramSet : paramSets)
77       {
78         // TODO: handle mismatch between preset and current parameters
79         if (paramSet instanceof SimpleParamSet)
80           userPresets.add((SimpleParamSet) paramSet);
81         else
82         {
83           userPresets.add(new SimpleParamSet(paramSet));
84           Console.warn(String.format(
85               "Parameter set instance type %s is not applicable to service"
86               + "at %s.", paramSet.getClass(), serviceUrl));
87         }
88       }
89     }
90   }
91   
92   @Override
93   public List<WsParamSetI> getPresets()
94   {
95     List<WsParamSetI> presets = new ArrayList<>();
96     presets.addAll(servicePresets);
97     presets.addAll(userPresets);
98     return presets;
99   }
100
101   @Override
102   public SimpleParamSet getPreset(String name)
103   {
104     SimpleParamSet preset = null;
105     preset = getUserPreset(name);
106     if (preset != null)
107       return preset;
108     preset = getServicePreset(name);
109     if (preset != null)
110       return preset;
111     return null;
112   }
113   
114   public SimpleParamSet getUserPreset(String name)
115   {
116     for (SimpleParamSet preset : userPresets)
117     {
118       if (name.equals(preset.getName()))
119         return preset;
120     }
121     return null;
122   }
123   
124   public SimpleParamSet getServicePreset(String name)
125   {
126     for (SimpleParamSet preset : servicePresets)
127     {
128       if (name.equals(preset.getName()))
129         return preset;
130     }
131     return null;
132   }
133
134   @Override
135   public List<ArgumentI> getServiceParameters()
136   {
137     return parameters;
138   }
139
140   @Override
141   public boolean presetExists(String name)
142   {
143     return getPreset(name) != null;
144   }
145
146   @Override
147   public void deletePreset(String name)
148   {
149     var userPreset = getUserPreset(name);
150     if (userPreset != null)
151     {
152       userPresets.remove(userPreset);
153       if (manager != null)
154       {
155         manager.deleteParameterSet(userPreset);
156       }
157     }
158     else if (getServicePreset(name) != null)
159     {
160       throw new RuntimeException(MessageManager.getString(
161           "error.implementation_error_attempt_to_delete_service_preset"));
162     }
163     else
164     {
165       Console.warn("Implementation error: no preset to delete");
166     }
167   }
168
169   @Override
170   public void storePreset(String presetName, String text, List<ArgumentI> jobParams)
171   {
172     var builder = SimpleParamSet.newBuilder();
173     builder.name(presetName);
174     builder.description(text);
175     builder.arguments(jobParams);
176     builder.url(serviceUrl.toString());
177     builder.modifiable(true);
178     var preset = builder.build();
179     userPresets.add(preset);
180     if (manager != null)
181       manager.storeParameterSet(preset);
182   }
183
184   @Override
185   public void updatePreset(String oldName, String newName, String text, List<ArgumentI> jobParams)
186   {
187     var preset = getPreset(oldName != null ? oldName : newName);
188     if (preset == null)
189       throw new RuntimeException(MessageManager.formatMessage(
190           "error.implementation_error_cannot_locate_oldname_presetname",
191           oldName, newName));
192     preset.setName(newName);
193     preset.setDescription(text);
194     preset.setArguments(jobParams);
195     preset.setApplicableUrls(new String[] { serviceUrl.toString() });
196     if (manager != null)
197       manager.storeParameterSet(preset);
198   }
199
200   @Override
201   public WsParamSetI parseServiceParameterFile(String name, String description,
202       String[] serviceURL, String parameters)
203       throws IOException
204   {
205     var builder = SimpleParamSet.newBuilder();
206     builder.name(name);
207     builder.description(description);
208     builder.urls(serviceURL);
209     builder.modifiable(true);
210     Unmarshaller unmarshaller;
211     try
212     {
213       var ctx = JAXBContext.newInstance(ArgumentBeanList.class);
214       unmarshaller = ctx.createUnmarshaller();
215     } catch (JAXBException e)
216     {
217       throw new RuntimeException(e);
218     }
219     ArgumentBeanList argList;
220     try
221     {
222       argList = (ArgumentBeanList) unmarshaller.unmarshal(new StringReader(parameters));
223     } catch (JAXBException | ClassCastException e)
224     {
225       throw new IOException("Unable to load parameters from file", e);
226     }
227     builder.arguments(argList.arguments);
228     return builder.build();
229   }
230
231   @Override
232   public String generateServiceParameterFile(WsParamSetI pset) throws IOException
233   {
234     Marshaller marshaller;
235     try 
236     {
237       var ctx = JAXBContext.newInstance(ArgumentBeanList.class);
238       marshaller = ctx.createMarshaller();
239       marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
240       marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
241     } catch (JAXBException e)
242     {
243       throw new RuntimeException(e);
244     }
245     ArgumentBeanList argList = ArgumentBeanList.fromList(pset.getArguments());
246     var out = new ByteArrayOutputStream();
247     try
248     {
249       marshaller.marshal(argList, out);
250     } catch (JAXBException e)
251     {
252       throw new IOException("Unable to generate parameters file", e);
253     }
254     return out.toString();
255   }
256
257 }