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 parameters; protected List servicePresets; protected List 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 parameters, List 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 getPresets() { List 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 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 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 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(); } }