org.kalypso.service.wps.client.simulation.SimulationDelegate.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.service.wps.client.simulation.SimulationDelegate.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  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; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  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.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.service.wps.client.simulation;

import java.io.File;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.DatatypeConverter;

import net.opengeospatial.ows.CodeType;
import net.opengeospatial.wps.IOValueType.ComplexValueReference;
import net.opengeospatial.wps.InputDescriptionType;
import net.opengeospatial.wps.LiteralInputType;
import net.opengeospatial.wps.ProcessDescriptionType;
import net.opengeospatial.wps.ProcessDescriptionType.DataInputs;
import net.opengeospatial.wps.SupportedCRSsType;
import net.opengeospatial.wps.SupportedComplexDataType;

import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemManager;
import org.eclipse.core.internal.boot.PlatformURLHandler;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.kalypso.commons.io.VFSUtilities;
import org.kalypso.commons.java.net.UrlUtilities;
import org.kalypso.commons.vfs.FileSystemManagerWrapper;
import org.kalypso.contribs.eclipse.core.resources.CollectFilesVisitor;
import org.kalypso.contribs.eclipse.core.resources.ResourceUtilities;
import org.kalypso.contribs.eclipse.core.runtime.StatusUtilities;
import org.kalypso.service.wps.client.WPSRequest;
import org.kalypso.service.wps.client.exceptions.WPSException;
import org.kalypso.service.wps.i18n.Messages;
import org.kalypso.service.wps.internal.KalypsoServiceWPSDebug;
import org.kalypso.service.wps.utils.WPSUtilities;
import org.kalypso.simulation.core.simspec.Modeldata;
import org.kalypso.simulation.core.simspec.Modeldata.Input;
import org.kalypso.simulation.core.simspec.Modeldata.Output;

/**
 * This client can work with simulations.
 *
 * @author Holger Albert
 */
public class SimulationDelegate {
    private static final String SERVER_INPUT_LOCAL = "InputLocal"; //$NON-NLS-1$

    /**
     * The id identifying the simulation.
     */
    private final String m_identifier;

    /**
     * The calc case folder.
     */
    private final IContainer m_calcCaseFolder;

    /**
     * The model data for this simulation.
     */
    private final Modeldata m_data;

    /**
     * The URL to the wps service.
     */
    private String m_service;

    /**
     * The path to the place on the server, where the client can put his files, as configured in the config.ini from
     * Kalypso.
     */
    private String m_input;

    /**
     * The filesystem manager.
     */
    private FileSystemManagerWrapper m_fsManager;

    /**
     * The temporary directory on the server.
     */
    private FileObject m_serverTmpDirectory;

    /**
     * The constructor.
     *
     * @param identifier
     *          The id identifying the simulation.
     * @param calcCaseFolder
     *          The folder of the calc case.
     * @param data
     *          The model data.
     */
    // TODO: remove argument identifier: use data.getTypeID() instead
    public SimulationDelegate(final String identifier, final IContainer calcCaseFolder, final Modeldata data) {
        /* Initializing the other variables. */
        m_identifier = identifier;
        m_calcCaseFolder = calcCaseFolder;
        m_data = data;

        /* Initializing the variables from the properties of the config.ini. */
        m_service = System.getProperty("org.kalypso.service.wps.service"); //$NON-NLS-1$
        m_input = System.getProperty("org.kalypso.service.wps.input"); //$NON-NLS-1$
        if (m_service == null || m_service.equals("")) //$NON-NLS-1$
        {
            m_service = WPSRequest.SERVICE_LOCAL;
        }
        if (m_input == null || m_input.equals("")) //$NON-NLS-1$
        {
            m_input = SERVER_INPUT_LOCAL;
        }
        /* Variables that are initialized during run time. */
        m_fsManager = null;
        m_serverTmpDirectory = null;
    }

    /**
     * @see org.kalypso.service.wps.client.IWPSDelegate#init()
     */
    public void init() throws CoreException {
        /* The file system manager needs to be set. */
        initVFSManager();

        KalypsoServiceWPSDebug.DEBUG.printf("Checking for service URL ...\n"); //$NON-NLS-1$
        if (m_service == null) {
            KalypsoServiceWPSDebug.DEBUG.printf(
                    "No URL to the service is given. Be sure to check the config.ini for the org.kalypso.service.wps.service property.\n"); //$NON-NLS-1$
            throw new CoreException(StatusUtilities.createStatus(IStatus.ERROR,
                    Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.0"), null)); //$NON-NLS-1$
        }
    }

    /**
     * This function inits the VFS manager.
     */
    private void initVFSManager() throws CoreException {
        try {
            if (m_fsManager == null) {
                /* The file system manager needs to be set. */
                m_fsManager = VFSUtilities.getNewManager();
            }
        } catch (final Exception ex) {
            throw new CoreException(StatusUtilities.createStatus(IStatus.ERROR,
                    Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.1"), ex)); //$NON-NLS-1$
        }
    }

    /**
     * This function copies all input files.
     *
     * @param files
     *          The files to copy.
     */
    private void copyInputFiles(final IFile[] files) throws WPSException {
        if (files.length > 0) {
            /* Get the directory for server access. */
            initServerTmpDirectory();

            /* Copy the files. */
            for (final IFile element : files) {
                copyInputFile(element);
            }
        }
    }

    /**
     * This function copies one input file to the place, where the server can read it.
     *
     * @param ifile
     *          The file to copy.
     */
    private void copyInputFile(final IFile ifile) throws WPSException {
        if (SERVER_INPUT_LOCAL.equals(m_input))
            return;
        try {
            /* Get the relative path of the file. */
            final File file = ifile.getLocation().toFile();
            final String relativePathTo = ifile.getFullPath().makeRelative().toString();

            /* Create the file objects. */
            final FileObject source = m_fsManager.toFileObject(file);
            final FileObject destination = VFSUtilities
                    .checkProxyFor(m_serverTmpDirectory.getName() + "/" + relativePathTo, m_fsManager); //$NON-NLS-1$

            /* Copy file. */
            VFSUtilities.copyFileTo(source, destination);
        } catch (final Exception ex) {
            throw new WPSException(Messages.getString(
                    "org.kalypso.service.wps.client.simulation.SimulationDelegate.2", ifile.getName()), ex); //$NON-NLS-1$
        }
    }

    /**
     * This function inits the temporary directory of the server, where the client has to put his files.
     */
    private void initServerTmpDirectory() throws WPSException {
        try {
            /* If the directory is not initialized, it will be generated and created (if necessary). */
            if (m_serverTmpDirectory == null) {
                KalypsoServiceWPSDebug.DEBUG
                        .printf("Checking for server URL, where the input data can be copied ...\n"); //$NON-NLS-1$
                if (m_input == null) {
                    KalypsoServiceWPSDebug.DEBUG.printf(
                            "No URL to the server of the service is given, where the input data can be copied. Be sure to check the config.ini for the org.kalypso.service.wps.input property.\n"); //$NON-NLS-1$
                    throw new WPSException(
                            Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.3")); //$NON-NLS-1$
                } else if (SERVER_INPUT_LOCAL.equals(m_input)) {
                    // do not use server directory, but calculate in calcCaseFolder
                    KalypsoServiceWPSDebug.DEBUG
                            .printf("Local calculation! Using calcCaseFolder as input directory.\n"); //$NON-NLS-1$

                    // the "calculate in calcCaseFolder" leads to creation of redundant data in each calculation in project folder
                    // so we are now using for local case already existing data from the project and not copied in this temporary
                    // folder
                    // but for the case that we do need a copied data, we should create correct temp directory and
                    // not additional directory in the project.
                    //File rootTmpDirectory = FileUtilities.createNewTempDir( "SimulationLocalInput_" );  //$NON-NLS-1$
                    // m_serverTmpDirectory = m_fsManager.toFileObject( rootTmpDirectory );

                    // final String calcCaseFolderLocation = m_calcCaseFolder.getLocationURI().toString();
                    // m_serverTmpDirectory = VFSUtilities.checkProxyFor( calcCaseFolderLocation, m_fsManager );
                } else {
                    /* Get the directory for server access. */
                    final FileObject serverDirectory = VFSUtilities.checkProxyFor(m_input, m_fsManager);
                    m_serverTmpDirectory = VFSUtilities.createTempDirectory("Simulation_", serverDirectory, //$NON-NLS-1$
                            m_fsManager);
                    if (!m_serverTmpDirectory.exists()) {
                        KalypsoServiceWPSDebug.DEBUG
                                .printf("Creating folder " + m_serverTmpDirectory.getName().getPath() + " ...\n"); //$NON-NLS-1$ //$NON-NLS-2$
                        m_serverTmpDirectory.createFolder();
                    }
                }

            }
        } catch (final WPSException e) {
            // Do not hide original WPSException
            throw e;
        } catch (final Exception ex) {
            throw new WPSException(
                    Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.4"), ex); //$NON-NLS-1$
        }
    }

    /**
     * @see org.kalypso.service.wps.client.IWPSDelegate#copyResults(java.util.Map)
     */
    public void copyResults(final Map<String, ComplexValueReference> references) throws CoreException {
        /* If there are no references, do nothing. */
        if (references == null) {
            return;
        }

        try {
            /* The project is needed. */
            final IProject project = m_calcCaseFolder.getProject();

            /* Get the model data outputs. */
            final List<Output> outputs = m_data.getOutput();

            /* All results, which are references. */
            final Iterator<String> keys = references.keySet().iterator();
            while (keys.hasNext()) {
                /* Get the next key. */
                final String key = keys.next();

                /* Get the complex value reference. */
                final ComplexValueReference complexValueReference = references.get(key);
                if (complexValueReference != null) {
                    /* Building the source object. */
                    final String reference = complexValueReference.getReference();
                    final FileObject source = VFSUtilities.checkProxyFor(reference, m_fsManager);

                    /* Building the destination object. */
                    final Output output = SimulationUtilities.findOutput(key, outputs);

                    // TODO Is that wanted (that all from the client not expected output is ignored)?
                    if (output == null)
                        continue;

                    /* Everything should be relative to the project! */
                    final String outputPath = output.getPath();
                    final IContainer baseresource = output.isRelativeToCalcCase() ? m_calcCaseFolder : project;
                    final File baseFile = baseresource.getLocation().toFile();
                    final File outputFile = new File(baseFile, outputPath);
                    final FileObject destination = m_fsManager.toFileObject(outputFile);

                    /* Copy ... */
                    VFSUtilities.copy(source, destination);

                    final IResource destResource = baseresource.findMember(new Path(outputPath));
                    if (destResource != null) {
                        /* Refresh. */
                        destResource.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());

                        // TODO: NO!!!! We do not know that!
                        if (destResource.getType() == IResource.FILE)
                            ((IFile) destResource).setCharset("UTF-8", new NullProgressMonitor()); //$NON-NLS-1$
                    }
                }
            }
        } catch (final CoreException ex) {
            throw ex;
        } catch (final Exception ex) {
            throw new CoreException(StatusUtilities.createStatus(IStatus.ERROR,
                    Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.5"), ex)); //$NON-NLS-1$
        }
    }

    /**
     * @see org.kalypso.service.wps.client.IWPSDelegate#finish()
     */
    public void finish() {
        try {
            /* Delete the input files. */
            deleteInputFiles();
        } catch (final WPSException e) {
            /* If an error has occurred while deleting the files, finish the job without error. A warning should be ok. */
            // TODO Perhaps show a warning.
        } finally {
            m_fsManager.close();
        }
    }

    /**
     * Deletes all input files, which have been copied so far.
     */
    private void deleteInputFiles() throws WPSException {
        try {
            // do not delete local input files (original files)
            if (!SERVER_INPUT_LOCAL.equals(m_input) && m_serverTmpDirectory != null
                    && m_serverTmpDirectory.exists()) {
                VFSUtilities.deleteFiles(m_serverTmpDirectory);
            }
        } catch (final Exception ex) {
            throw new WPSException(
                    Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.6"), ex); //$NON-NLS-1$
        } finally {
            try {
                if (m_serverTmpDirectory != null)
                    m_serverTmpDirectory.close();
            } catch (final FileSystemException e) {
                // ignore
            }
        }
    }

    /**
     * @see org.kalypso.service.wps.client.IWPSDelegate#getIdentifier()
     */
    public String getIdentifier() {
        return m_identifier;
    }

    /**
     * @see org.kalypso.service.wps.client.IWPSDelegate#getServiceURL()
     */
    public String getServiceURL() {
        return m_service;
    }

    /**
     * This function creates the inputs for the server. It will also copy the data to the right place, if needed and
     * ajdust the references according to it.
     *
     * @param description
     *          The process description type.
     * @param monitor
     *          A progress monitor.
     * @return The inputs.
     */
    public Map<String, Object> createInputs(final ProcessDescriptionType description, IProgressMonitor monitor)
            throws CoreException {
        /* Monitor. */
        if (monitor == null) {
            monitor = new NullProgressMonitor();
        }

        try {
            /* Monitor. */
            monitor.beginTask(Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.7"), //$NON-NLS-1$
                    500);
            KalypsoServiceWPSDebug.DEBUG.printf("Collecting data ...\n"); //$NON-NLS-1$

            /* Need the filesystem manager. */
            final FileSystemManager fsManager = m_fsManager;

            /* Get the list with the input. */
            final Map<String, Object> wpsInputs = new HashMap<>();

            /* Get the input list. */
            final DataInputs dataInputs = description.getDataInputs();
            final List<InputDescriptionType> inputDescriptions = dataInputs.getInput();

            /* Create a resource visitor. */
            final CollectFilesVisitor visitor = new CollectFilesVisitor();

            /* Get the inputs. */
            final List<Input> inputList = m_data.getInput();

            /* Iterate over all inputs and build the data inputs for the execute request. */
            for (final InputDescriptionType inputDescription : inputDescriptions) {
                final CodeType identifier = inputDescription.getIdentifier();

                /* Check if the input is in our model data, too. */
                final Input input = SimulationUtilities.findInput(identifier.getValue(), inputList);
                if (input == null) {
                    /* Check, if it is an optional one. */
                    if (inputDescription.getMinimumOccurs().intValue() == 1) {
                        /* Ooops, it is a mandatory one, but it is missing in our model data. */
                        final IStatus status = StatusUtilities.createStatus(IStatus.ERROR,
                                Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.8", //$NON-NLS-1$
                                        identifier.getValue()),
                                null);
                        throw new CoreException(status);
                    }

                    continue;
                }

                /* Input is here. */
                final String inputPath = input.getPath();

                /* Supported complex data type. */
                final SupportedComplexDataType complexData = inputDescription.getComplexData();
                if (complexData != null) {
                    /* Get the protocol if it is one. */
                    final String protocol = SimulationUtilities.getProtocol(inputPath);

                    /* If the protocol is null, it is a local file resource, otherwise it is a remote resource, */
                    /* which is not allowed to be copied or it is a complex value type (file-protocol). */
                    if ("file".equals(protocol)) //$NON-NLS-1$
                    {
                        // TODO: Why do we need this?
                        final URL localFileUrl = new URL(inputPath);
                        final byte[] bytes = UrlUtilities.toByteArray(localFileUrl);
                        final String hexString = DatatypeConverter.printHexBinary(bytes);
                        wpsInputs.put(identifier.getValue(), hexString);
                        continue;
                    } else if (protocol == null || protocol.equals("project") || protocol.equals("platform")) //$NON-NLS-1$ //$NON-NLS-2$
                    {
                        /* If protocol is null or protocol is "project", it is a local file resource. */
                        /*
                         * If protocol is "platform", it is a resource from another project, but the same platform (i.e. same
                         * eclipse workspace).
                         */
                        if (m_calcCaseFolder == null) {
                            throw new WPSException(Messages
                                    .getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.9")); //$NON-NLS-1$
                        }

                        final IProject project = m_calcCaseFolder.getProject();
                        final IResource inputResource;
                        if (protocol != null && protocol.equals(PlatformURLHandler.PROTOCOL)) {
                            final IContainer baseresource = project.getWorkspace().getRoot();
                            final String path = ResourceUtilities.findPathFromURL(new URL(inputPath))
                                    .toPortableString();
                            inputResource = baseresource.findMember(path);
                        } else {
                            final IContainer baseresource = input.isRelativeToCalcCase() ? m_calcCaseFolder
                                    : project;
                            inputResource = baseresource.findMember(inputPath);
                        }

                        if (inputResource == null) {
                            if (inputDescription.getMinimumOccurs().intValue() == 0) {
                                continue;
                            }

                            throw new CoreException(StatusUtilities.createErrorStatus(Messages.getString(
                                    "org.kalypso.service.wps.client.simulation.SimulationDelegate.10", inputPath))); //$NON-NLS-1$
                        }

                        /* Collect all files. */
                        inputResource.accept(visitor);

                        /* Initialize the temporary directory. */
                        initServerTmpDirectory();

                        /* Build the URL for this input. */
                        /* Resource will be copied to server later (for example see SimulationDelegate.copyInputFiles). */
                        final String relativePathTo = inputResource.getFullPath().makeRelative().toString();

                        /**
                         * just put the existing resource to the inputs and DO NOT copy it in case of local calculation!! also
                         * prevent the creation of redundant data in base project folder
                         */
                        FileObject destination = fsManager.toFileObject(inputResource.getLocation().toFile());
                        if (!SERVER_INPUT_LOCAL.equals(m_input)) {
                            destination = fsManager.resolveFile(m_serverTmpDirectory, relativePathTo);
                        }

                        final String serverUrl = WPSUtilities
                                .convertInternalToServer(destination.getURL().toExternalForm(), m_input);
                        wpsInputs.put(identifier.getValue(), new URI(URIUtil.encodePath(serverUrl)));
                    } else
                    // maybe check the protocols?
                    {
                        // Remote resource, will be passed to the service as reference
                        final URL clientUrl = new URL(inputPath);
                        final String serverUrl = WPSUtilities.convertInternalToServer(clientUrl.toExternalForm(),
                                m_input);
                        wpsInputs.put(identifier.getValue(), new URI(serverUrl));
                    }
                }

                /* Literal input type */
                final LiteralInputType literalInput = inputDescription.getLiteralData();
                if (literalInput != null) {
                    /* Add the input. */
                    // TODO: normally we should marshall the string to the requested type
                    // (the WPS-Client will unmarshall it again).
                    // For the moment this works, as the WPS-Client just forwards any strings.
                    wpsInputs.put(identifier.getValue(), inputPath);

                    continue;
                }

                /* Supported CRSs type. */
                final SupportedCRSsType supportedCRSsType = inputDescription.getBoundingBoxData();
                if (supportedCRSsType != null) {
                    // TODO Add supported CRSs type (bounding boxes).
                    continue;
                }
            }

            /* Monitor. */
            monitor.worked(200);
            monitor.setTaskName(
                    Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.11")); //$NON-NLS-1$
            KalypsoServiceWPSDebug.DEBUG.printf("Copy to the server ...\n"); //$NON-NLS-1$

            /* Copy all collected files. */
            final IFile[] files = visitor.getFiles();
            if (files.length > 0)
                copyInputFiles(files);

            /* Monitor. */
            monitor.worked(300);

            return wpsInputs;
        } catch (final CoreException ex) {
            throw ex;
        } catch (final Exception ex) {
            throw new CoreException(StatusUtilities.createStatus(IStatus.ERROR,
                    Messages.getString("org.kalypso.service.wps.client.simulation.SimulationDelegate.12"), ex)); //$NON-NLS-1$
        } finally {
            /* Monitor. */
            monitor.done();
        }
    }

    /**
     * This function creates the outputs from the model data.
     *
     * @return The output from the model data.
     */
    public List<String> createOutputs() {
        /* Get the list with the output. */
        final List<Output> outputList = m_data.getOutput();

        /* The storage for the output values. */
        final List<String> outputs = new LinkedList<>();

        for (final Output output : outputList)
            outputs.add(output.getId());

        return outputs;
    }
}