net.refractions.udig.wps.WPSProcessImpl.java Source code

Java tutorial

Introduction

Here is the source code for net.refractions.udig.wps.WPSProcessImpl.java

Source

/*
 * 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.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import net.opengis.wps10.WPSCapabilitiesType;
import net.refractions.udig.catalog.CatalogPlugin;
import net.refractions.udig.catalog.IProcess;
import net.refractions.udig.catalog.IProcessInfo;
import net.refractions.udig.catalog.IResolve;
import net.refractions.udig.catalog.IService;
import net.refractions.udig.catalog.ui.CatalogUIPlugin;
import net.refractions.udig.catalog.ui.ISharedImages;
import net.refractions.udig.wps.internal.Messages;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Rectangle;
import org.geotools.data.wms.xml.WMSSchema;
import org.geotools.data.wps.WPSFactory;
import org.geotools.data.wps.WebProcessingService;
import org.geotools.feature.NameImpl;
import org.geotools.process.ProcessFactory;

/**
 * Process provided by WPS.
 * </p>
 *
 * @author gdavis, Refractions Research Inc
 * @author Lucas Reed, Refractions Research Inc
 */
public class WPSProcessImpl extends IProcess {

    private WPSServiceImpl service;
    private ProcessFactory processFactory;
    private IProcessInfo info;
    private ImageDescriptor icon;
    private URL identifier;
    private ArrayList<IResolve> members;
    private IResolve parent;
    private Lock iconLock = new ReentrantLock();

    /**
     * Construct <code>WPSProcessImpl</code>.
     * 
     * @param service
     * @param parent the parent Process may be null if parent is the service.
     * @param process
     */
    public WPSProcessImpl(WPSServiceImpl service, IResolve parent, ProcessFactory processFactory) {
        this.service = service;
        if (parent == null) {
            this.parent = service;
        } else {
            this.parent = parent;
        }
        this.processFactory = processFactory;
        members = new ArrayList<IResolve>();
        //        for( Layer child : process.getChildren() ) {
        //            if (child != process) {
        //                if (child.getName() == null) {
        //                    members.add(new WPSFolder(service, this, child));
        //                } else {
        //                    members.add(new WPSProcessImpl(service, this, child));
        //                }
        //            }
        //        }

        try {
            String name = ((WPSFactory) processFactory).getIdentifier();
            if (name == null) {
                WpsPlugin.log("Can't get a unique name for the identifier of WPSProcess: " + processFactory, null); //$NON-NLS-1$
                throw new RuntimeException("This should be a WPSFolder not an IProcess"); //$NON-NLS-1$
            }

            identifier = new URL(service.getIdentifier().toString() + "#" + name); //$NON-NLS-1$

        } catch (Throwable e) {
            WpsPlugin.log(null, e);
            identifier = service.getIdentifier();
        }
    }

    @Override
    public IResolve parent(IProgressMonitor monitor) throws IOException {
        return parent;
    }

    /*
     * @see net.refractions.udig.catalog.IGeoResource#getStatus()
     */
    public Status getStatus() {
        return service.getStatus();
    }

    public String getTitle() {
        return null;
    }

    public IProcessInfo getInfo(IProgressMonitor monitor) throws IOException {
        if (info == null) {
            service.rLock.lock();
            try {
                if (info == null) {
                    info = new WPSProcessInfo(this.processFactory, monitor);
                }
            } finally {
                service.rLock.unlock();
            }
        }
        return info;
    }

    public URL getIdentifier() {
        return identifier;
    }

    @Override
    public List<IResolve> members(IProgressMonitor monitor) {
        return this.members;
    }

    /*
     * @see net.refractions.udig.catalog.IGeoResource#resolve(java.lang.Class,
     *      org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    public <T> T resolve(Class<T> adaptee, IProgressMonitor monitor) throws IOException {
        if (adaptee == null) {
            throw new NullPointerException();
        }

        // if (adaptee.isAssignableFrom(IService.class)) {
        // return adaptee.cast( parent);
        // }

        if (adaptee.isAssignableFrom(IProcess.class)) {
            return adaptee.cast(this);
        }

        if (adaptee.isAssignableFrom(IProcessInfo.class)) {
            return adaptee.cast(getInfo(monitor));
        }

        if (adaptee.isAssignableFrom(WebProcessingService.class)) {
            return adaptee.cast(service.getWPS(monitor));
        }

        if (adaptee.isAssignableFrom(org.geotools.process.ProcessFactory.class)) {
            return adaptee.cast(processFactory);
        }

        if (adaptee.isAssignableFrom(ImageDescriptor.class)) {
            return adaptee.cast(getIcon(monitor));
        }

        return super.resolve(adaptee, monitor);
    }

    public WPSServiceImpl service(IProgressMonitor monitor) throws IOException {
        return service;
    }

    /** Must be the same as resolve( ImageDescriptor.class ) */
    public ImageDescriptor getIcon(IProgressMonitor monitor) {
        iconLock.lock();
        try {
            if (icon == null) {
                icon = fetchIcon(monitor, processFactory, service);
                if (icon == null) {
                    icon = CatalogUIPlugin.getDefault().getImageDescriptor(ISharedImages.GRID_OBJ);
                }
            }
            return icon;
        } finally {
            iconLock.unlock();
        }
    }

    /**
     * This method will fetch the Icon associated with this url (if such is available).
     * 
     * @see WPSFolder
     * @param monitor
     * @return Requested Icon or ISharedImages.GRID_OBJ
     */
    protected static ImageDescriptor fetchIcon(IProgressMonitor monitor, ProcessFactory processFactory,
            WPSServiceImpl service) {
        try {
            if (monitor != null)
                monitor.beginTask(Messages.WPSProcessImpl_acquiring_task, 3);
            if (monitor != null)
                monitor.worked(1);

            //            if (process.getChildren() != null && process.getChildren().length != 0) {
            //                // Do not request "parent" layer graphics - this kills Mapserver
            //                return CatalogUIPlugin.getDefault().getImages().getImageDescriptor(
            //                        ISharedImages.GRID_OBJ);
            //            }

            ImageDescriptor imageDescriptor = requestImage(monitor, processFactory, service);

            Image image = null;
            Image swatch = null;
            try {
                if (monitor != null)
                    monitor.worked(2);
                if (monitor != null)
                    monitor.subTask(Messages.WPSProcessImpl_downloading_icon);
                image = imageDescriptor.createImage();
                Rectangle bound = image.getBounds();
                if (bound.width == 16 && bound.height == 16) {
                    final ImageData data = (ImageData) image.getImageData().clone();
                    return new ImageDescriptor() {
                        public ImageData getImageData() {
                            return (ImageData) data.clone();
                        }
                    };
                }
                if (bound.height < 16 || bound.width < 16) {
                    if (WpsPlugin.getDefault().isDebugging())
                        System.out.println("Icon scaled up to requested size"); //$NON-NLS-1$                                        
                    final ImageData data = image.getImageData().scaledTo(16, 16);
                    return new ImageDescriptor() {
                        public ImageData getImageData() {
                            return (ImageData) data.clone();
                        }
                    };
                }
                swatch = new Image(null, 16, 16);
                GC gc = new GC(swatch);
                int sy = 0; // (bound.height / 2 ) - 8;
                int sx = 0;
                int sw = 0;
                int sh = 0;
                ImageData contents = image.getImageData();
                if (contents == null) {
                    return CatalogUIPlugin.getDefault().getImageDescriptor(ISharedImages.GRID_MISSING);
                }
                if (contents.maskData != null) {
                    // ((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad
                    int maskPad = contents.maskPad;
                    int scanLine = ((contents.width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad;
                    // skip leading mask ...
                    SKIPY: for (int y = 0; y < contents.height / 2; y++) {
                        sy = y;
                        for (int x = 0; x < contents.width / 2; x++) {
                            int mask = contents.maskData[y * scanLine + x];
                            if (mask != 0)
                                break SKIPY;
                        }
                    }
                    SKIPX: for (int x = 0; x < contents.width / 2; x++) {
                        sx = x;
                        for (int y = sy; y < contents.height / 2; y++) {
                            int mask = contents.maskData[y * scanLine + x];
                            if (mask != 0)
                                break SKIPX;
                        }
                    }
                    sh = Math.min(contents.height - sy, 16);
                    sw = Math.min(contents.width - sx, 16);
                    if (WpsPlugin.getDefault().isDebugging())
                        System.out.println("Mask offset to " + sx + "x" + sy); //$NON-NLS-1$ //$NON-NLS-2$                        
                } else if (contents.alphaData != null) {
                    SKIPY: for (int y = 0; y < contents.height / 2; y++) {
                        sy = y;
                        for (int x = 0; x < contents.width / 2; x++) {
                            int alpha = contents.alphaData[y * contents.width + x];
                            if (alpha != 0)
                                break SKIPY;
                        }
                    }
                    SKIPX: for (int x = 0; x < contents.width / 2; x++) {
                        sx = x;
                        for (int y = sy; y < contents.height / 2; y++) {
                            int alpha = contents.alphaData[y * contents.width + x];
                            if (alpha != 0)
                                break SKIPX;
                        }
                    }
                    sh = Math.min(contents.height - sy, 16);
                    sw = Math.min(contents.width - sx, 16);
                    if (WpsPlugin.getDefault().isDebugging())
                        System.out.println("Alpha offset to " + sx + "x" + sy); //$NON-NLS-1$ //$NON-NLS-2$                        
                } else {
                    // try ignoring "white"
                    int depth = contents.depth;
                    int scanLine = contents.bytesPerLine;
                    SKIPY: for (int y = 0; y < contents.height / 2; y++) {
                        sy = y;
                        for (int x = 0; x < contents.width / 2; x++) {
                            int datum = contents.data[y * scanLine + x * depth];
                            if (datum != 0)
                                break SKIPY;
                        }
                    }
                    SKIPX: for (int x = 0; x < contents.width / 2; x++) {
                        sx = x;
                        for (int y = sy; y < contents.height / 2; y++) {
                            int datum = contents.data[y * scanLine + x * depth];
                            if (datum != 0)
                                break SKIPX;
                        }
                    }
                    sh = Math.min(contents.height - sy, 16);
                    sw = Math.min(contents.width - sx, 16);
                    if (WpsPlugin.getDefault().isDebugging())
                        System.out.println("Alpha offset to " + sx + "x" + sy); //$NON-NLS-1$ //$NON-NLS-2$                        
                }
                // else {
                // sh = Math.min( bound.height, bound.width );
                // sw = Math.min( bound.height, bound.width );
                // }
                if (WpsPlugin.getDefault().isDebugging())
                    System.out.println("Image resized to " + sh + "x" + sw); //$NON-NLS-1$ //$NON-NLS-2$

                gc.drawImage(image, sx, sy, sw, sh, 0, 0, 16, 16);
                final ImageData data = (ImageData) swatch.getImageData().clone();
                return new ImageDescriptor() {
                    public ImageData getImageData() {
                        return (ImageData) data.clone();
                    }
                };
            } finally {
                if (image != null) {
                    image.dispose();
                }
                if (swatch != null) {
                    swatch.dispose();
                }
                if (monitor != null)
                    monitor.worked(3);
            }
        } catch (IOException t) {
            WpsPlugin.trace("Could not get icon", t); //$NON-NLS-1$
            return CatalogUIPlugin.getDefault().getImageDescriptor(ISharedImages.GRID_MISSING);
        }
    }

    @SuppressWarnings("unchecked")
    private static ImageDescriptor requestImage(IProgressMonitor monitor,
            org.geotools.process.ProcessFactory processFactory, WPSServiceImpl service) throws IOException {
        WebProcessingService wps = service.getWPS(monitor);

        // TODO: is there any possible way to set a legend graphic in a wps capabilities doc?
        return CatalogUIPlugin.getDefault().getImageDescriptor(ISharedImages.GRID_OBJ);

        //        if (wps.getCapabilities().getRequest().getGetLegendGraphic() == null) {
        //            return CatalogUIPlugin.getDefault().getImages().getImageDescriptor(
        //                    ISharedImages.GRID_OBJ);
        //        }
        //
        //        ImageDescriptor imageDescriptor = null;
        //        try {
        //            GetLegendGraphicRequest request = wps.createGetLegendGraphicRequest();
        //            request.setLayer(layer.getName());
        //            request.setWidth("16"); //$NON-NLS-1$
        //            request.setHeight("16"); //$NON-NLS-1$
        //
        //            List<String> formats = wps.getCapabilities().getRequest()
        //                    .getGetLegendGraphic().getFormats();
        //            
        //            Collections.sort(formats, new Comparator<String>(){
        //
        //                public int compare( String format1, String format2 ) {
        //                    if( format1.trim().equalsIgnoreCase("image/png") ){ //$NON-NLS-1$
        //                        return -1;
        //                    }
        //                    if( format2.trim().equalsIgnoreCase("image/png") ){ //$NON-NLS-1$
        //                        return 1;
        //                    }
        //                    if( format1.trim().equalsIgnoreCase("image/gif") ){ //$NON-NLS-1$
        //                        return -1;
        //                    }
        //                    if( format2.trim().equalsIgnoreCase("image/gif") ){ //$NON-NLS-1$
        //                        return 1;
        //                    }
        //                    return 0;
        //                }
        //                
        //            });
        //            
        //            for( Iterator<String> iterator = formats.iterator(); iterator.hasNext() && imageDescriptor==null; ) {
        //                String format = iterator.next();
        //                
        //                imageDescriptor = loadImageDescriptor(wps, request, format );
        //            }
        //
        //            if (imageDescriptor == null) {
        //                // cannot understand any of the provided formats
        //                return CatalogUIPlugin.getDefault().getImages().getImageDescriptor(
        //                        ISharedImages.GRID_OBJ);
        //            }
        //        } catch (UnsupportedOperationException notAvailable) {
        //            WpsPlugin.trace("Icon is not available", notAvailable); //$NON-NLS-1$                
        //            return CatalogUIPlugin.getDefault().getImages().getImageDescriptor(
        //                    ISharedImages.GRID_OBJ);
        //        } catch (ServiceException e) {
        //            WpsPlugin.trace("Icon is not available", e); //$NON-NLS-1$                
        //            return CatalogUIPlugin.getDefault().getImages().getImageDescriptor(
        //                    ISharedImages.GRID_OBJ);
        //        }
        //        
        //        return imageDescriptor;
    }

    //    private static ImageDescriptor loadImageDescriptor( WebProcessingService wps,
    //            GetLegendGraphicRequest request, String desiredFormat ) throws IOException,
    //            ServiceException {
    //        // TODO: is there any way to issue a request to a WPS server for a legend graphic?
    //        return null;
    //        
    ////        if (desiredFormat == null) {
    ////            return null;
    ////        }
    ////        try {
    ////            ImageDescriptor imageDescriptor;
    ////            request.setFormat(desiredFormat);
    ////
    ////            request.setStyle(""); //$NON-NLS-1$
    ////
    ////            System.out.println(request.getFinalURL().toExternalForm());
    ////
    ////            GetLegendGraphicResponse response = wps.issueRequest(request);
    ////
    ////            imageDescriptor = ImageDescriptor.createFromImageData(getImageData(response
    ////                    .getInputStream()));
    ////            return imageDescriptor;
    ////        } catch (SWTException exc) {
    ////            WpsPlugin.trace("Icon is not available or has unsupported format", exc); //$NON-NLS-1$                
    ////            return null;
    ////        }
    //    }

    private static ImageData getImageData(InputStream in) {
        ImageData result = null;
        if (in != null) {
            try {
                result = new ImageData(in);
            } catch (SWTException e) {
                if (e.code != SWT.ERROR_INVALID_IMAGE)
                    throw e;
                // fall through otherwise
            } finally {
                try {
                    in.close();
                } catch (IOException e) {
                    // System.err.println(getClass().getName()+".getImageData(): "+
                    // "Exception while closing InputStream : "+e);
                }
            }
        }
        return result;
    }

    /*
     * @see net.refractions.udig.catalog.IResolve#canResolve(java.lang.Class)
     */
    @Override
    public <T> boolean canResolve(Class<T> adaptee) {
        if (adaptee == null) {
            return false;
        }

        if (adaptee.isAssignableFrom(IProcess.class) || adaptee.isAssignableFrom(WebProcessingService.class)
                || adaptee.isAssignableFrom(org.geotools.process.ProcessFactory.class)
                || adaptee.isAssignableFrom(ImageDescriptor.class) || adaptee.isAssignableFrom(IService.class)
                || super.canResolve(adaptee)) {
            return true;
        }

        return false;
    }

    /*
     * @see net.refractions.udig.catalog.IResolve#getMessage()
     */
    public Throwable getMessage() {
        return service.getMessage();
    }

    private class WPSProcessInfo extends IProcessInfo {

        @SuppressWarnings("unchecked")
        WPSProcessInfo(final ProcessFactory pf, final IProgressMonitor monitor) throws IOException {

            this.processFactory = pf;

            String factoryName = pf.getClass().getSimpleName();
            String localName;
            if (factoryName.endsWith("Factory") && !factoryName.equals("Factory")) {
                localName = factoryName.substring(0, factoryName.length() - 7);
            } else {
                localName = factoryName;
            }

            processName = new NameImpl("gt", localName);

            WebProcessingService wps = service.getWPS(monitor);
            WPSCapabilitiesType caps = wps.getCapabilities();

            if (processFactory.getTitle(processName) != null
                    && processFactory.getTitle(processName).length() != 0) {
                title = processFactory.getTitle(processName).toString();
            }

            // TODO: get input params
            //calculateBounds();

            String parentid = service != null && service.getIdentifier() != null ? getIdentifier().toString() : ""; //$NON-NLS-1$
            name = processFactory.getTitle(processName).toString();

            getKeywords(caps, parentid);

            if (processFactory.getDescription(processName) != null
                    && processFactory.getDescription(processName).length() != 0) {
                description = processFactory.getDescription(processName).toString();
            } else {
                EList abstract1 = caps.getServiceIdentification().getAbstract();
                if (!abstract1.isEmpty() && abstract1.get(0).toString().length() != 0) {
                    description = abstract1.get(0).toString();
                } else {
                    description = "";
                }
            }
            EList abstract1 = caps.getServiceIdentification().getAbstract();
            if (!abstract1.isEmpty() && abstract1.get(0).toString().length() != 0) {
                description = abstract1.get(0).toString();
            } else {
                description = "";
            }

            icon = CatalogUIPlugin.getDefault().getImageDescriptor(ISharedImages.GRID_OBJ);

            //icon = fetchIcon( monitor, this.processFactory );
        }

        private void getKeywords(WPSCapabilitiesType caps, String parentid) {
            List<String> keywordsFromWPS = new ArrayList<String>();
            keywordsFromWPS = WPSUtils.getKeywords(caps, keywordsFromWPS);

            // TODO:  should processes have keywords?  Currently they do not
            //            if (process.getKeywords() != null) {
            //                keywordsFromWPS.addAll(Arrays.asList(process.getKeywords()));
            //            }

            keywordsFromWPS.add("WPS"); //$NON-NLS-1$
            keywordsFromWPS.add(processFactory.getTitle(processName).toString());
            if (!caps.getServiceIdentification().getTitle().isEmpty()
                    && caps.getServiceIdentification().getTitle().get(0).toString().length() != 0) {
                keywordsFromWPS.add(caps.getServiceIdentification().getTitle().get(0).toString());
            }
            keywordsFromWPS.add(parentid);
            keywords = keywordsFromWPS.toArray(new String[keywordsFromWPS.size()]);
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public URI getSchema() {

            return WMSSchema.NAMESPACE;

            //            try {
            //                return new URI("http://www.opengis.net/wps"); //$NON-NLS-1$
            //            } catch (URISyntaxException e) {
            //                // do nothing
            //                return null;
            //            }
        }

        @Override
        public String getTitle() {
            return title;
        }
    }
}