/*
* uDig - User Friendly Desktop Internet GIS client http://udig.refractions.net (C) 2004,
* Refractions Research Inc. This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free Software
* Foundation; version 2.1 of the License. This library is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*/
package net.refractions.udig.wps;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import net.opengis.ows11.LanguageStringType;
import net.opengis.wps10.ProcessBriefType;
import net.opengis.wps10.ProcessDescriptionType;
import net.opengis.wps10.WPSCapabilitiesType;
import net.refractions.udig.catalog.CatalogPlugin;
import net.refractions.udig.catalog.IGeoResource;
import net.refractions.udig.catalog.IResolve;
import net.refractions.udig.catalog.IService;
import net.refractions.udig.catalog.IServiceInfo;
import net.refractions.udig.ui.ErrorManager;
import net.refractions.udig.ui.UDIGDisplaySafeLock;
import net.refractions.udig.wps.internal.Messages;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.emf.common.util.EList;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.geotools.data.ows.AbstractWPSGetCapabilitiesResponse;
import org.geotools.data.ows.GetCapabilitiesRequest;
import org.geotools.data.ows.Specification;
import org.geotools.data.wps.WPS1_0_0;
import org.geotools.data.wps.WPSFactory;
import org.geotools.data.wps.WebProcessingService;
import org.geotools.data.wps.request.DescribeProcessRequest;
import org.geotools.data.wps.request.ExecuteProcessRequest;
import org.geotools.data.wps.response.DescribeProcessResponse;
import org.geotools.data.wps.response.ExecuteProcessResponse;
import org.geotools.ows.ServiceException;
import org.xml.sax.SAXException;
/**
* Connect to a WPS.
*
* @author gdavis, Refractions Research Inc
* @author Lucas Reed, Refractions Research Inc
*/
public class WPSServiceImpl extends IService {
/**
* <code>WPS_URL_KEY</code> field Magic param key for Catalog WPS persistence.
*/
public static final String WPS_URL_KEY = "net.refractions.udig.wps.WPSServiceImpl.WPS_URL_KEY"; //$NON-NLS-1$
public static final String WPS_WPS_KEY = "net.refractions.udig.wps.WPSServiceImpl.WPS_WMS_KEY"; //$NON-NLS-1$
private Map<String, Serializable> params;
private Throwable error;
private URL url;
private volatile WebProcessingService wps = null;
private volatile WPSServiceInfo info;
protected final Lock rLock = new UDIGDisplaySafeLock();
private volatile List<IResolve> members;
private int currentFolderID = 0;
private WPSCapabilitiesType caps = null;
/**
* Construct <code>WPSServiceImpl</code>.
*
* @param url
* @param params
*/
public WPSServiceImpl( URL url, Map<String, Serializable> params ) {
this.params = params;
this.url = url;
if (params.containsKey(WPS_WPS_KEY)) {
Object obj = params.get(WPS_WPS_KEY);
if (obj instanceof WebProcessingService) {
this.wps = (WebProcessingService) obj;
}
}
}
public Status getStatus() {
return error != null ? Status.BROKEN : wps == null ? Status.NOTCONNECTED : Status.CONNECTED;
}
private static final Lock dsLock = new UDIGDisplaySafeLock();
/**
* Aquire the actual geotools WebProcessingService instance.
* <p>
* Note this method is blocking and throws an IOException to indicate such.
* </p>
*
* @param theUserIsWatching
* @return WebProcessingService instance
* @throws IOException
*/
protected WebProcessingService getWPS( IProgressMonitor theUserIsWatching ) throws IOException {
if (wps == null) {
dsLock.lock();
try {
if (wps == null) {
try {
if (theUserIsWatching != null) {
String message = MessageFormat.format(
Messages.WPSServiceImpl_connecting_to, new Object[]{url});
theUserIsWatching.beginTask(message, 100);
}
URL url1 = (URL) getConnectionParams().get(WPS_URL_KEY);
if (theUserIsWatching != null)
theUserIsWatching.worked(5);
wps = new CustomWPS(url1);
if (theUserIsWatching != null)
theUserIsWatching.done();
} catch (IOException persived) {
error = persived;
throw persived;
} catch (Throwable nak) {
IOException broken = new IOException(MessageFormat.format(
Messages.WPSServiceImpl_could_not_connect, new Object[]{nak
.getLocalizedMessage()}));
broken.initCause(nak);
error = broken;
throw broken;
}
}
} finally {
dsLock.unlock();
}
}
return wps;
}
public IServiceInfo createInfo( IProgressMonitor monitor ) throws IOException {
if (info == null) {
getWPS(monitor);
rLock.lock();
try {
if (info == null) {
info = new WPSServiceInfo(monitor);
}
} finally {
rLock.unlock();
}
}
return info;
}
/*
* @see net.refractions.udig.catalog.IService#resolve(java.lang.Class,
* org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public <T> T resolve( Class<T> adaptee, IProgressMonitor monitor ) throws IOException {
if (adaptee == null) {
return null;
}
if (adaptee.isAssignableFrom(IServiceInfo.class)) {
return adaptee.cast(getInfo(monitor));
}
if (adaptee.isAssignableFrom(List.class)) {
return adaptee.cast(members(monitor));
}
if (adaptee.isAssignableFrom(WebProcessingService.class)) {
return adaptee.cast(getWPS(monitor));
}
return super.resolve(adaptee, monitor);
}
/**
* @see net.refractions.udig.catalog.IService#getConnectionParams()
*/
public Map<String, Serializable> getConnectionParams() {
return params;
}
/*
* @see net.refractions.udig.catalog.IResolve#canResolve(java.lang.Class)
*/
@Override
public <T> boolean canResolve( Class<T> adaptee ) {
if (adaptee == null)
return false;
return adaptee.isAssignableFrom(WebProcessingService.class) || super.canResolve(adaptee);
}
@Override
public void dispose( IProgressMonitor monitor ) {
if (members == null)
return;
int steps = (int) ((double) 99 / (double) members.size());
for( IResolve resolve : members ) {
try {
SubProgressMonitor subProgressMonitor = new SubProgressMonitor(monitor, steps);
resolve.dispose(subProgressMonitor);
subProgressMonitor.done();
} catch (Throwable e) {
ErrorManager.get().displayException(e,
"Error disposing members of service: " + getIdentifier(), CatalogPlugin.ID); //$NON-NLS-1$
}
}
}
/**
* This Serivce does not provide any GeoResources.
*/
public List< ? extends IGeoResource> resources( IProgressMonitor monitor ) throws IOException {
return null;
}
@SuppressWarnings("unchecked")
@Override
public List<IResolve> members( IProgressMonitor monitor ) throws IOException {
if (null == this.members) {
rLock.lock();
try {
if (caps == null) {
try {
caps = getWPS(monitor).getCapabilities();
} catch (Throwable t) {
t.printStackTrace();
caps = null;
}
}
this.members = new LinkedList<IResolve>();
EList processes = getWPS(monitor).getCapabilities().getProcessOfferings()
.getProcess();
String pString = ""; //$NON-NLS-1$
// Concatenate the identifiers to request all ProcessDescriptions
for( int i = 0; i < processes.size(); i++ ) {
ProcessBriefType process = (ProcessBriefType) processes.get(i);
pString += process.getIdentifier().getValue() + ","; //$NON-NLS-1$
}
DescribeProcessRequest req = getWPS(monitor).createDescribeProcessRequest();
DescribeProcessResponse response = null;
req.setIdentifier(pString.substring(0, pString.length() - 1));
try {
response = getWPS(monitor).issueRequest(req);
} catch (ServiceException e) {
throw new IOException(e.getMessage());
}
List<ProcessDescriptionType> processDescriptionBeans = response.getProcessDesc()
.getProcessDescription();
for( ProcessDescriptionType processDesc : processDescriptionBeans ) {
try {
WPSFactory processFactory = new WPSFactory(processDesc, this.url);
WPSProcessImpl process = new WPSProcessImpl(this, null, processFactory);
this.members.add(process);
WpsPlugin.log("Added " + processDesc.getIdentifier().getValue(), null); //$NON-NLS-1$
} catch (Exception e) {
WpsPlugin.log("Failed process schema definition, not adding: "
+ processDesc.getIdentifier().getValue(), null); //$NON-NLS-1$
}
}
} finally {
rLock.unlock();
}
}
return this.members;
}
/*
* @see net.refractions.udig.catalog.IResolve#getMessage()
*/
public Throwable getMessage() {
return error;
}
/*
* @see net.refractions.udig.catalog.IResolve#getIdentifier()
*/
public URL getIdentifier() {
return url;
}
class WPSServiceInfo extends IServiceInfo {
WPSServiceInfo( IProgressMonitor monitor ) {
try {
caps = getWPS(monitor).getCapabilities();
} catch (Throwable t) {
t.printStackTrace();
caps = null;
}
if (caps == null || caps.getServiceIdentification() == null
|| caps.getServiceIdentification().getKeywords().isEmpty()) {
keywords = null;
} else {
List<String> s = WPSUtils.getKeywords(caps, null);
keywords = new String[s.size()];
keywords = s.toArray(keywords);
}
String[] t;
if (keywords == null) {
t = new String[2];
} else {
t = new String[keywords.length + 2];
System.arraycopy(keywords, 0, t, 2, keywords.length);
}
t[0] = "WPS"; //$NON-NLS-1$
t[1] = getIdentifier().toString();
keywords = t;
icon = AbstractUIPlugin.imageDescriptorFromPlugin(WpsPlugin.ID,
"icons/obj16/wms_obj.gif"); //$NON-NLS-1$
}
@Override
public String getAbstract() {
// return caps == null ? null : caps.getService() == null ? null : caps
// .getService().get_abstract();
if (caps == null
|| caps.getServiceIdentification() == null
|| caps.getServiceIdentification().getAbstract().isEmpty()
|| caps.getServiceIdentification().getAbstract().get(0).toString().length() == 0) {
return null;
}
return caps.getServiceIdentification().getAbstract().get(0).toString();
}
@Override
public String getDescription() {
return getIdentifier().toString();
}
// public URI getSchema() {
// return WPSSchema.NAMESPACE;
// }
@Override
public URI getSource() {
try {
return getIdentifier().toURI();
} catch (URISyntaxException e) {
// This would be bad
throw (RuntimeException) new RuntimeException().initCause(e);
}
}
@Override
public String getTitle() {
if (caps == null || caps.getServiceIdentification() == null
|| caps.getServiceIdentification().getTitle().isEmpty()
|| caps.getServiceIdentification().getTitle().get(0).toString().length() == 0) {
return getIdentifier().toString();
}
Object str = caps.getServiceIdentification().getTitle().get(0);
String title;
if (str instanceof LanguageStringType) {
LanguageStringType a = (LanguageStringType) caps.getServiceIdentification()
.getTitle().get(0);
title = a.getValue().toString();
} else {
title = caps.getServiceIdentification().getTitle().get(0).toString();
}
return title;
}
}
public static class CustomWPS extends WebProcessingService {
/**
* @throws SAXException
* @throws ServiceException
* @param serverURL
* @throws IOException
*/
public CustomWPS( URL serverURL ) throws IOException, ServiceException, SAXException {
super(serverURL);
// if( WpsPlugin.isDebugging( REQUEST ) )
WpsPlugin.log("Connection to WPS located at: " + serverURL, null); //$NON-NLS-1$
if (getCapabilities() == null) {
throw new IOException("Unable to parse capabilities document."); //$NON-NLS-1$
}
}
@Override
public AbstractWPSGetCapabilitiesResponse issueRequest( GetCapabilitiesRequest arg0 )
throws IOException, ServiceException {
WpsPlugin.log("GetCapabilities: " + arg0.getFinalURL(), null); //$NON-NLS-1$
return super.issueRequest(arg0);
}
@Override
public DescribeProcessResponse issueRequest( DescribeProcessRequest arg0 )
throws IOException, ServiceException {
WpsPlugin.log("DescribeProcessRequest: " + arg0.getFinalURL(), null); //$NON-NLS-1$
return super.issueRequest(arg0);
}
@Override
public ExecuteProcessResponse issueRequest( ExecuteProcessRequest arg0 )
throws IOException, ServiceException {
WpsPlugin.log("ExecuteProcessRequest: " + arg0.getFinalURL(), null); //$NON-NLS-1$
return super.issueRequest(arg0);
}
@Override
protected void setupSpecifications() {
specs = new Specification[1];
specs[0] = new WPS1_0_0();
}
}
public int nextFolderID() {
return currentFolderID++;
}
}