Package de.danet.an.workflow.clients.wfxml

Source Code of de.danet.an.workflow.clients.wfxml.ResourceReference

/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2006 Danet GmbH (www.danet.de), BU BTS.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* $Id: ResourceReference.java 2576 2007-11-02 16:00:34Z drmlipp $
*
* $Log$
* Revision 1.9  2007/09/26 20:24:22  mlipp
* Removed superfluous import.
*
* Revision 1.8  2007/03/29 11:46:54  schnelle
* Reactivated ASAPException to propagate ASAP error messages in cases of an invalid key, a missing resource or an invalid factory.
*
* Revision 1.7  2007/03/27 21:59:42  mlipp
* Fixed lots of checkstyle warnings.
*
* Revision 1.6  2007/03/01 12:32:57  schnelle
* Enhanced Instance.SetProperties to process ContextData.
*
* Revision 1.5  2007/02/01 13:44:43  schnelle
* Using namespace for factory schemas that do not contain '&'.
*
* Revision 1.4  2007/02/01 10:08:36  drmlipp
* Removed no longer used observer resource.
*
* Revision 1.3  2007/01/31 22:55:36  mlipp
* Some more refactoring and fixes of problems introduced by refactoring.
*
* Revision 1.2  2007/01/31 14:53:06  schnelle
* Small corrections wvaluating the resource reference.
*
* Revision 1.1  2007/01/31 12:24:05  drmlipp
* Design revisited.
*
* Revision 1.3  2007/01/30 13:11:37  schnelle
* Corrected check to decide the sending of a completed message.
*
* Revision 1.2  2007/01/30 11:56:14  drmlipp
* Merged Wf-XML branch.
*
* Revision 1.1.2.1  2007/01/29 15:04:23  schnelle
* Renaming of Observer to ObserverRegistry and URIDecoder to ResourceReference.
*
* Revision 1.1.2.7  2007/01/29 13:40:31  schnelle
* Storing of the sender base in the servlet context.
*
* Revision 1.1.2.6  2007/01/29 10:48:28  schnelle
* Using a key-value encoding of the parameters instead of the directory approach.
*
* Revision 1.1.2.5  2007/01/26 15:50:28  schnelle
* Added encoding for process id and package id.
*
* Revision 1.1.2.4  2007/01/24 14:22:38  schnelle
* Observer handler starts on servlet startup.
*
* Revision 1.1.2.3  2007/01/24 11:46:35  schnelle
* Moved wsdl files and xsd files intot resources subdirectory.
*
* Revision 1.1.2.2  2007/01/24 10:56:50  schnelle
* Prepared return of a result for aobservers.
*
* Revision 1.1.2.1  2007/01/19 12:34:56  schnelle
* Moved generation and decoding of the URI that is used as the receiver key to new class URIDecoder.
*
*/
package de.danet.an.workflow.clients.wfxml;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;

import de.danet.an.workflow.api.Activity;
import de.danet.an.workflow.api.Process;
import de.danet.an.workflow.api.ProcessDefinition;

/**
* This class wraps the URI encoding and decoding of the
* <code>ReceiverKey</code> that is used in the ASAP header. Moreover is it
* used to retrieve the attributes that were given in a request to this
* service.
*
* <p>
* The <code>ReceiverKey</code> is a {@link java.net.URI} with the following
* structure
* <code>
* &lt;schema:&gt;//&lt;authority&gt;/&lt;base path&gt;[?&lt;query&gt;]
* </code>
* </p>
*
* <p>
* The parts up to <code>base path</code> describe the path to this service.
* For the servlet this is e.g. <code>http://localhost:8080/wfxml</code>.
* </p>
*
* <p>
* All parts that are needed to identify the specific instance are encoded in
* the <code>query</code> part of the URI as key-value pairs.
* The <code>instance</code> is given as such a query parameter and names the
* addressed resource instance of the request. If it is omitted the
* <code>Service Registry</code> is taken as the instance.
* A request to the
* <code>Factory</code> for the process <code>proc</code> that is described in
* package <code>pkg</code> is made using the following
* <code>ReceiverKey</code>, (assuming the base path above):<br>
* <code>
* http://localhost:8080/wfxml?Resource=Factory&PackageId=pkg&ProcessId=proc
* </code>
* </p>
*
* TODO: Add the unique identifier for the workflow engine.
*
* @author Dirk Schnelle
*
*/
class ResourceReference {
    /** Logger instance. */
    private static final org.apache.commons.logging.Log logger
        = org.apache.commons.logging.LogFactory.getLog(ResourceReference.class);

    /** The used encoding. */
    private static final String UTF_8 = "UTF-8";
   
    /** Name of the attribute for the instance. */
    private static final String ATTRIBUTE_RESOURCE = "Resource";
   
    /** Name of the attribute for the package id. */
    private static final String ATTRIBUTE_PACKAGE_ID = "PackageId";
   
    /** Name of the attribute for the process id. */
    private static final String ATTRIBUTE_PROCESS_ID = "ProcessId";
   
    /** Name of the attribute for the process key. */
    private static final String ATTRIBUTE_PROCESS_KEY = "ProcessKey";
   
    /** Name of the attribute for the activity key. */
    private static final String ATTRIBUTE_ACTIVITY_KEY = "ActivityKey";
   
    /** The base url of this WfXML server. */
    private String baseUrl;

    /** Name of the resource. */
    private String resource;
       
    /** Name of the package id. */
    private String packageId;
   
    /** Name of the process id. */
    private String processId;
   
    /** Name of the process key. */
    private String processKey;
   
    /** Name of the activity key. */
    private String activityKey;

    /**
     * Create a new instance that references a process definition.
     *
     * @param baseUrl the sender base
     * @param procDef the process definition
     */
    public ResourceReference(String baseUrl, ProcessDefinition procDef) {
        if (baseUrl == null || procDef == null) {
            throw new IllegalArgumentException();
        }
        this.baseUrl = baseUrl;
        this.resource = AbstractResponseGenerator.RESOURCE_FACTORY;
        this.packageId = procDef.packageId();
        this.processId = procDef.processId();
    }
   
    /**
     * Create a new instance that references an instance.
     *
     * @param baseUrl
     * @param packageId
     * @param processId
     * @param processKey
     */
    public ResourceReference
        (String baseUrl,
         String packageId, String processId, String processKey) {
        if (baseUrl == null || packageId == null || processId == null
            || processKey == null) {
            throw new IllegalArgumentException();
        }
        this.baseUrl = baseUrl;
        this.resource = AbstractResponseGenerator.RESOURCE_INSTANCE;
        this.packageId = packageId;
        this.processId = processId;
        this.processKey = processKey;
    }

    /**
     * Create a new instance that references an instance.
     *
     * @param baseUrl
     * @param process
     */
    public ResourceReference (String baseUrl, Process process)
        throws RemoteException {
        if (baseUrl == null || process == null) {
            throw new IllegalArgumentException();
        }
        this.baseUrl = baseUrl;
        this.resource = AbstractResponseGenerator.RESOURCE_INSTANCE;
        ProcessDefinition procDef = process.processDefinition();
        this.packageId = procDef.packageId();
        this.processId = procDef.processId();
        this.processKey = process.key();
    }

    /**
     * Create a new instance that references an activity.
     *
     * @param baseUrl the base URL
     * @param activity the activity
     */
    public ResourceReference (String baseUrl, Activity activity)
        throws RemoteException {
        if (baseUrl == null || activity == null) {
            throw new IllegalArgumentException();
        }
        this.baseUrl = baseUrl;
        this.resource = AbstractResponseGenerator.RESOURCE_ACTIVITY;
        Process process = (Process)activity.container();
        ProcessDefinition procDef = process.processDefinition();
        this.packageId = procDef.packageId();
        this.processId = procDef.processId();
        this.processKey = process.key();
        this.activityKey = activity.key();
    }

    /**
     * Constructs a new object.
     * @param baseUrl base url of the main servlet.
     * @param key <code>ReceiverKey</code> of a request.
     * @exception ASAPException
     *            Error parsing the receiver key.
     */
    public ResourceReference(String baseUrl, String key)
        throws ASAPException {
        if (baseUrl == null) {
            throw new IllegalArgumentException();
        }
        this.baseUrl = baseUrl;

        parseReceiverKey(key);
        if (resource.equals
            (AbstractResponseGenerator.RESOURCE_SERVICE_REGISTRY)) {
            // nothing required
            return;
        }
       
        if (resource.equals (AbstractResponseGenerator.RESOURCE_FACTORY)) {
            if (packageId == null || processId == null) {
                throw new IllegalArgumentException("Invalid key: " + key);
            }
            return;
        }
       
        if (resource.equals(AbstractResponseGenerator.RESOURCE_INSTANCE)) {
            if (packageId == null || processId == null || processKey == null) {
                throw new IllegalArgumentException("Invalid key: " + key);
            }
            return;
        }
       
        if (resource.equals(AbstractResponseGenerator.RESOURCE_ACTIVITY)) {
            if (packageId == null || processId == null
                || processKey == null || activityKey == null) {
                throw new IllegalArgumentException("Invalid key: " + key);
            }
            return;
        }
       
        throw new ASAPException(ASAPException.ASAP_INVALID_FACTORY,
                "Key '" + key + "' could not be mapped to a resource.");
    }
   
    /**
     * Parses the <code>ReceiverKey</code> and extracts all addresses resources.
     * @exception ASAPException
     *            Error parsing the receiver key.
     */
    private void parseReceiverKey(String receiverKey)
        throws ASAPException  {
        if (receiverKey == null) {
            throw new IllegalArgumentException("Key may not be null");
        }
        URI uri;
        try {
            uri = new URI(receiverKey);
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException
                (receiverKey + " is not a valid URI: " + e.getMessage());
        }
        // The receiver key is always transferred in the SOAP envelope.
        // Any character decoding will have happened already. And we
        // don't give out keys or valued that contain "&" or "=".
        String query = uri.getRawQuery();
        String[] params = query.split("&");
        Map parameters = new HashMap ();
        for (int i = 0; i < params.length; i++) {
            String param = params[i];
            String[] keyValuePair = param.split("=");
            try {
                String value = URLDecoder.decode(keyValuePair[1], UTF_8);
                parameters.put(keyValuePair[0], value);
            } catch (ArrayIndexOutOfBoundsException e) {
                throw new ASAPException(ASAPException.ASAP_INVALID_KEY,
                        "Invalid receiver key: '" + receiverKey + "'");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException("Broken VM does not support UTF-8");
            }
        }
       
        // Pre-set the resource. It may be overridden later.
        resource = AbstractResponseGenerator.RESOURCE_SERVICE_REGISTRY;

        resource = (String) parameters.get(ATTRIBUTE_RESOURCE);
        packageId = (String) parameters.get(ATTRIBUTE_PACKAGE_ID);
        processId = (String) parameters.get(ATTRIBUTE_PROCESS_ID);
        processKey = (String) parameters.get(ATTRIBUTE_PROCESS_KEY);
        activityKey = (String) parameters.get(ATTRIBUTE_ACTIVITY_KEY);
    }
   
    /**
     * Retrieves the name of the resource to which the receiver key points to.
     * @return name of the resource.
     */
    public String getResource() {
        return resource;
    }
   
    /**
     * Retrieves the base URL of this WfXML server.
     * @return base URL.
     */
    public String getBaseUrl() {
        return baseUrl;
    }

    /**
     * Retrieves the package id as it is specified in the
     * <code>ReceiverKey</code>.
     * @return package id.
     */
    public String getPackageId() {
        if (packageId == null) {
            throw new IllegalStateException("Resource has no packaged id.");
        }
        return packageId;
    }
   
    /**
     * Retrieves the process id as it is specified in the
     * <code>ReceiverKey</code>.
     * @return process id.
     */
    public String getProcessId() {
        if (processId == null) {
            throw new IllegalStateException("Resource has no process id.");
        }
        return processId;
    }
   
    /**
     * Retrieves the process key as it is specified in the
     * <code>ReceiverKey</code>.
     * @return process id.
     */
    public String getProcessKey() {
        if (processKey == null) {
            throw new IllegalStateException("Resource has no process key.");
        }
        return processKey;
    }
   
    /**
     * Retrieves the activity key as it is specified in the
     * <code>ReceiverKey</code>.
     * @return activity key.
     */
    public String getActivityKey() {
        if (activityKey == null) {
            throw new IllegalStateException("Resource has no activity key.");
        }

        return activityKey;
    }
   
    /**
     * Retrieves the sender key.
     * @return sender key for the observer.
     */
    public String getResourceKey() {
        StringBuffer res = new StringBuffer (baseUrl);
        if (res.indexOf("?") < 0) {
            res.append("?");
        } else {
            res.append("&");
        }
        res.append(ATTRIBUTE_RESOURCE + "=" + resource);
        appendParameter(res, ATTRIBUTE_PACKAGE_ID, packageId);
        appendParameter(res, ATTRIBUTE_PROCESS_ID, processId);
        appendParameter(res, ATTRIBUTE_PROCESS_KEY, processKey);
        appendParameter(res, ATTRIBUTE_ACTIVITY_KEY, activityKey);
        return res.toString();
    }

    /**
     * Adds the given parameter to the given url.
     * @param url the base url.
     * @param
     * @return url with parameters if any.
     */
    private void appendParameter(StringBuffer url, String key, String value) {
        if (value == null) {
            return;
        }
        url.append("&" + key + "=" + encode (value));
    }
   
    /**
     * Generates a namespace for the current resource.
     *
     * <p>
     * Namespaces are defined for the factories and are used in the instances.
     * </p>
     * @return namespace.
     */
    public String getNamespace() {
        if(resource.equals(AbstractResponseGenerator.RESOURCE_SERVICE_REGISTRY)
            || resource.equals(AbstractResponseGenerator.RESOURCE_ACTIVITY)) {
            throw new IllegalStateException("Namespaces can only be generated"
                    + " for factory and instance");
        }
       
        StringBuffer str = new StringBuffer (baseUrl);
       
        // Since we are in the world of the factory, we use the values of
        // the factory.
        str.append('/');
        str.append(AbstractResponseGenerator.RESOURCE_FACTORY);
        str.append('/');
        str.append(packageId);
        str.append('/');
        str.append(processId);

        return str.toString();
    }
   
    /**
     * Translates a string into <code>application/x-www-form-urlencoded</code>
     * format using the <code>UTF-8</code> encoding scheme.
     * @param str the string to encode.
     * @return <code>UTF-8</code> encoded string.
     */
    private String encode(String str) {
        try {
            return URLEncoder.encode(str, UTF_8);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Broken VM does not support UTF-8");
        }
    }   
}
TOP

Related Classes of de.danet.an.workflow.clients.wfxml.ResourceReference

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.