/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wps.remote; import java.awt.RenderingHints.Key; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; import org.geoserver.platform.GeoServerExtensions; import org.geotools.data.Parameter; import org.geotools.process.Process; import org.geotools.process.ProcessFactory; import org.geotools.text.Text; import org.geotools.util.SimpleInternationalString; import org.geotools.util.logging.Logging; import org.opengis.feature.type.Name; import org.opengis.util.InternationalString; /** * A process factory that wraps a {@link RemoteProcessClient} and can be used to get information about it and create the corresponding process. * * @author Alessio Fabiani, GeoSolutions * */ public class RemoteProcessFactory implements ProcessFactory, RemoteProcessFactoryListener { public static final String WPS_VERSION = "1.0.0"; /** The LOGGER */ public static final Logger LOGGER = Logging .getLogger(RemoteProcessFactory.class.getPackage().getName()); /** Associates the generic sets of inputs and outputs declared by the remote service to the {@link RemoteProcess} instance */ private Map<Name, RemoteServiceDescriptor> descriptors = new ConcurrentHashMap<Name, RemoteServiceDescriptor>(); /** * The list of currently running {@link RemoteProcess} instances; each of them is identified by a unique pId generated by the * {@link RemoteProcessClient} which must be used to honor the asynchronous communication handshake. Remember that only the * {@link RemoteProcessClient} specific implementation knows how to handle the communication with the remote service. */ private Map<Name, RemoteProcess> remoteInstances = new ConcurrentHashMap<Name, RemoteProcess>(); /** The {@link RemoteProcessClient} instance */ private RemoteProcessClient remoteClient; /** * Constructs a {@link RemoteProcessFactory} able to dynamically create stubs for the remote communication */ public RemoteProcessFactory() { try { List<RemoteProcessClient> availableRemoteClientInstances = GeoServerExtensions .extensions(RemoteProcessClient.class); for (RemoteProcessClient ext : availableRemoteClientInstances) { if (ext.isEnabled()) { remoteClient = ext; remoteClient.init(); if (remoteClient.isEnabled()) { remoteClient.registerProcessFactoryListener(this); break; } } } } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } } /** * @return the remoteClient */ public RemoteProcessClient getRemoteClient() { return remoteClient; } /** * @param remoteClient the remoteClient to set */ public void setRemoteClient(RemoteProcessClient remoteClient) { this.remoteClient = remoteClient; } /** The Title of the {@link RemoteProcessFactory} */ public InternationalString getTitle() { return new SimpleInternationalString("Remote"); } /** The currently available {@link RemoteProcess} stubs on the {@link RemoteProcessFactory} */ public Set<Name> getNames() { return descriptors.keySet(); } /** Utility method to check if a {@link RemoteProcess} stub has been already registered */ boolean checkName(Name name) { if (name == null) throw new NullPointerException("Process name cannot be null"); if (!descriptors.containsKey(name)) { LOGGER.warning("Unknown process '" + name + "'"); return false; } for (Name registeredService : descriptors.keySet()) { if (registeredService.getLocalPart().equalsIgnoreCase((name.getLocalPart()))) { return true; } } return true; } /** * Creates a new {@link RemoteProcess} stub * * @throws IllegalArgumentException */ public Process create(Name name) throws IllegalArgumentException { synchronized (remoteInstances) { if (checkName(name)) { try { RemoteProcess process = new RemoteProcess(name, remoteClient, descriptors.get(name).getMetadata()); remoteInstances.put(name, process); return process; } catch (Exception e) { throw new RuntimeException("Error occurred cloning the prototype " + "algorithm... this should not happen", e); } } return null; } } /** Get the {@link RemoteProcess} textual description */ public InternationalString getDescription(Name name) { synchronized (descriptors) { if (checkName(name)) return Text.text(descriptors.get(name).getDescription()); return null; } } /** Get the {@link RemoteProcess} title */ public InternationalString getTitle(Name name) { synchronized (descriptors) { if (checkName(name)) return Text.text(descriptors.get(name).getTitle()); return null; } } /** Get the {@link RemoteProcess} short name */ public String getName(Name name) { if (checkName(name)) { return name.getLocalPart(); } return null; } /** */ public boolean supportsProgress(Name name) { return true; } /** */ public String getVersion(Name name) { return WPS_VERSION; } /** Get the {@link RemoteProcess} textual description */ public Map<String, Parameter<?>> getParameterInfo(Name name) { synchronized (descriptors) { if (checkName(name)) return descriptors.get(name).getParamInfo(); return null; } } /** Get the {@link RemoteProcess} textual description */ public Map<String, Parameter<?>> getResultInfo(Name name, Map<String, Object> inputs) throws IllegalArgumentException { synchronized (descriptors) { if (checkName(name)) return descriptors.get(name).getOutputInfo(); return null; } } @Override public String toString() { return "RemoteProcessFactory"; } /** */ public boolean isAvailable() { return true; } /** */ public Map<Key, ?> getImplementationHints() { return Collections.EMPTY_MAP; } /** Registers a new remote service */ @Override public void registerProcess(RemoteServiceDescriptor serviceDescriptor) { Name name = serviceDescriptor.getName(); if (descriptors.containsKey(name)) { LOGGER.warning("Service " + name + " already registered!"); return; } descriptors.put(name, serviceDescriptor); create(name); LOGGER.info("Registered Service [" + name + "]"); } /** De-registers a remote service */ @Override public void deregisterProcess(Name name) { if (checkName(name)) { descriptors.remove(name); remoteInstances.remove(name); LOGGER.info("Deregistered Service [" + name + "]"); } } }