Package de.danet.an.workflow.util

Source Code of de.danet.an.workflow.util.XPDLUtil

/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
* 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: XPDLUtil.java 2904 2009-01-28 22:21:36Z mlipp $
*
* $Log$
* Revision 1.7  2007/02/27 14:34:17  drmlipp
* Some refactoring to reduce cyclic dependencies.
*
* Revision 1.6  2006/11/20 09:52:37  drmlipp
* Fixed problems with using URL class.
*
* Revision 1.5  2006/11/19 11:16:35  mlipp
* Made ExternalReference an interface.
*
* Revision 1.4  2006/11/17 21:39:44  mlipp
* Adapted to Java type support.
*
* Revision 1.3  2006/11/17 16:16:12  drmlipp
* Started support for Java native types.
*
* Revision 1.2  2006/09/29 12:32:10  drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.1.1.5  2004/08/18 15:17:39  drmlipp
* Update to 1.2
*
* Revision 1.22  2004/04/29 15:39:31  lipp
* Getting on with SAX based initialization.
*
* Revision 1.21  2004/03/25 14:41:47  lipp
* Added possibility to specify actual parameters as XML.
*
* Revision 1.20  2004/01/19 12:30:58  lipp
* SchemaType now supported properly.
*
* Revision 1.19  2003/10/23 08:50:42  lipp
* Fixed comment.
*
* Revision 1.18  2003/09/25 11:02:10  lipp
* Added support for remote resources in evaluation.
*
* Revision 1.17  2003/09/20 22:57:20  lipp
* Added variant for parseDuration.
*
* Revision 1.16  2003/09/20 19:26:06  lipp
* Modified complex time value specification handling.
*
* Revision 1.15  2003/09/05 12:38:12  lipp
* Added duration parsing for XPDL.
*
* Revision 1.14  2003/07/04 08:08:45  lipp
* Started variable performer.
*
* Revision 1.13  2003/06/27 08:51:44  lipp
* Fixed copyright/license information.
*
* Revision 1.12  2003/06/10 14:46:44  huaiyang
* Fix the error in generating sax events.
*
* Revision 1.11  2003/06/05 21:30:35  lipp
* Better handling of initial XML values.
*
* Revision 1.10  2003/06/03 16:38:56  lipp
* Updated to jdom b9.
*
* Revision 1.9  2003/05/15 07:25:54  lipp
* Javadoc fix.
*
* Revision 1.8  2003/04/25 20:05:32  lipp
* Retrieving participants from SAX now.
*
* Revision 1.7  2003/04/22 16:56:12  lipp
* Added missing pack().
*
* Revision 1.6  2003/04/22 16:36:28  lipp
* Handling schema types.
*
* Revision 1.5  2003/04/22 14:34:57  lipp
* Retrieving context signature from SAX.
*
* Revision 1.4  2003/04/01 11:16:08  lipp
* Handling for XML init data added.
*
* Revision 1.3  2003/03/28 14:42:35  lipp
* Moved some code to XPDLUtil.
*
* Revision 1.2  2003/03/28 12:45:24  lipp
* Moved XPDL related constants to XPDLUtil.
*
* Revision 1.1  2003/03/28 11:41:59  lipp
* More changes for data type support.
*
*/
package de.danet.an.workflow.util;

import java.io.IOException;
import java.io.StringReader;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import java.net.URI;
import java.net.URISyntaxException;
import java.rmi.RemoteException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;

import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.output.SAXOutputter;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLFilterImpl;

import de.danet.an.util.Duration;
import de.danet.an.util.Duration.ValueEvaluator;
import de.danet.an.util.XMLUtil;
import de.danet.an.util.sax.SAXContentBuffer;
import de.danet.an.util.sax.StackedHandler;
import de.danet.an.util.sax.XmlnsUrisPatcher;

import de.danet.an.workflow.api.ExternalReference;
import de.danet.an.workflow.api.Participant;
import de.danet.an.workflow.api.SAXEventBuffer;

/**
* This class provides some methods that help handling XPDL.
*
* @author <a href="mailto:lipp@danet.de">Michael Lipp</a>
* @version $Revision: 2904 $
*/

public class XPDLUtil {

    private static final org.apache.commons.logging.Log logger
  = org.apache.commons.logging.LogFactory.getLog(XPDLUtil.class);

    /** The XPDL version used. */
    public static final String XPDL_VERSION
  = "WFMC-TC-1025 Version 1.0 (Beta)";

    /** The URI of the XPDL version used. */
    public static final String XPDL_NS
  = "http://www.wfmc.org/2002/XPDL1.0";

    /** The URI of the supported XPDL extensions. */
    public static final String XPDL_EXTN_NS
  = "http://www.an.danet.de/2002/XPDL-Extensions1.0";
    /** The URI of the supported XPDL extensions (v1.1). */
    public static final String XPDL_EXTN_V1_1_NS
        = "http://www.an.danet.de/2009/XPDL-Extensions1.1";

    private static DateFormat dfRfc822plus = new SimpleDateFormat
  ("d MMM yy HH:mm:ss z", Locale.US);
    private static DateFormat dfRfc822 = new SimpleDateFormat
  ("d MMM yy HH:mm z", Locale.US);

    /**
     * Check if the given namespace is our XPDL extension namespace.
     * @param ns the namespace to check
     * @return the result
     */
    public static boolean isXpdlExtNs (String ns) {
        return (ns.equals(XPDL_EXTN_NS) || ns.equals(XPDL_EXTN_V1_1_NS));
    }
   
    /**
     * Extract the Java data type information from a
     * <code>DataType</code> node. The type information is coded as follows:
     * <ul>
     *   <li>
     *     if the type is a <code>&lt;BasicType&gt;</code>, the corresponding
     *     Java class is returned, with
     *     {@link de.danet.an.workflow.api.Participant <code>Participant</code>}
     *     used to denote "PERFORMER".
     *   </li>
     *   <li>
     *     if the type is <code>&lt;SchemaType&gt;</code>, but no schema is
     *     specified, <code>org.w3c.dom.Element.class</code> is returned.
     *   </li>
     *   <li>
     *     if the type is <code>&lt;SchemaType&gt;</code>, and the schema is
     *     specified, the schema is returned is returned
     *     (as <code>SAXEventBuffer</code>).
     *   </li>
     *   <li>
     *     if the type is <code>&lt;ExternalReference&gt;</code>,
     *     an <code>ExternalReference</code> is returned.
     *   </li>
     * </ul>
     * @param typeElem a <code>&lt;DataType&gt;</code> element.
     * @return the type information as specified above.
     * @throws IllegalArgumentException if the type is not recognized.
     */
    public static Object extractDataType (Element typeElem)
  throws IllegalArgumentException {
  Namespace xpdlns = Namespace.getNamespace (XPDL_NS);
  Element bt = typeElem.getChild ("BasicType", xpdlns);
  if (bt != null) {
      if (bt.getAttributeValue("Type").equals("STRING")) {
    return String.class;
      }
      if (bt.getAttributeValue("Type").equals("FLOAT")) {
    return Double.class;
      }
      if (bt.getAttributeValue("Type").equals("INTEGER")) {
    return Long.class;
      }
      if (bt.getAttributeValue("Type").equals("DATETIME")) {
    return Date.class;
      }
      if (bt.getAttributeValue("Type").equals("BOOLEAN")) {
    return Boolean.class;
      }
      if (bt.getAttributeValue("Type").equals("PERFORMER")) {
    return Participant.class;
      }
  }
  Element st = typeElem.getChild ("SchemaType", xpdlns);
  if (st != null) {
      List sd = st.getChildren();
      if (sd.size () == 0) {
    return org.w3c.dom.Element.class;
      }
      SAXEventBufferImpl seb = new SAXEventBufferImpl ();
      try {
    (new SAXOutputter (seb)).output (sd);
      } catch (JDOMException e) {
    new IllegalArgumentException ("Cannot convert schema to SAX: "
                + e.getMessage ());
      }
      seb.pack();
      return seb;
  }
  Element er = typeElem.getChild ("ExternalReference", xpdlns);
  if (er != null) {
      try {
    return new DefaultExternalReference
        (makeURI(er.getAttributeValue("location")),
                     er.getAttributeValue("xref"),
                     er.getAttributeValue("namespace"));
      } catch (URISyntaxException e) {
    throw new IllegalArgumentException (e.getMessage ());
      }
  }
  throw new IllegalArgumentException ("Unknown type");
    }   

    /**
     * Helper class for retrieving a data type from the process
     * definition.<P>
     *
     * The type information is coded as follows:
     * <ul>
     *   <li>
     *     if the type is a <code>&lt;BasicType&gt;</code>, the corresponding
     *     Java class is returned, with
     *     {@link de.danet.an.workflow.api.Participant <code>Participant</code>}
     *     used to denote "PERFORMER".
     *   </li>
     *   <li>
     *     if the type is <code>&lt;SchemaType&gt;</code>, but no schema is
     *     specified, <code>org.w3c.dom.Element.class</code> is returned.
     *   </li>
     *   <li>
     *     if the type is <code>&lt;SchemaType&gt;</code>, and the schema is
     *     specified, the schema is returned  as a
     *     {@link de.danet.an.workflow.api.SAXEventBuffer
     *     <code>SAXEventBuffer</code>}.
     *   </li>
     *   <li>
     *     if the type is <code>&lt;ExternalReference&gt;</code>,
     *     an <code>ExternalReference</code> is returned.
     *   </li>
     * </ul>
     */
    public static class SAXDataTypeHandler extends StackedHandler {

  private boolean waitingForSchema = false;
  private boolean gotSchema = false;
  private SAXEventBufferImpl schemaInfo = null;

  /**
   * Receive notification of the beginning of an element.
   *
   * @param uri the Namespace URI, or the empty string if the
   * element has no Namespace URI or if Namespace processing is not
   * being performed.
   * @param loc the local name (without prefix), or the empty string
   * if Namespace processing is not being performed.
   * @param raw the raw XML 1.0 name (with prefix), or the empty
   * string if raw names are not available.
   * @param a the attributes attached to the element. If there are
   * no attributes, it shall be an empty Attributes object.
   * @throws SAXException not thrown.
   */
  public void startElement
      (String uri, String loc, String raw, Attributes a)
      throws SAXException {
      if (waitingForSchema) {
    gotSchema = true;
    schemaInfo = new SAXEventBufferImpl ();
    getStack().push (schemaInfo);
      }
      if (loc.equals ("BasicType")) {
    String type = a.getValue("Type");
    if (type.equals ("STRING")) {
        setContextData ("DataType", String.class);
    } else if (type.equals ("FLOAT")) {
        setContextData ("DataType", Double.class);
    } else if (type.equals ("INTEGER")) {
        setContextData ("DataType", Long.class);
    } else if (type.equals ("DATETIME")) {
        setContextData ("DataType", Date.class);
    } else if (type.equals ("BOOLEAN")) {
        setContextData ("DataType", Boolean.class);
    } else if (type.equals ("PERFORMER")) {
        setContextData ("DataType", Participant.class);
    }
      } else if (loc.equals ("SchemaType")) {
    waitingForSchema = true;
      } else if (loc.equals ("ExternalReference")) {
    try {
        setContextData
      ("DataType", new DefaultExternalReference
       (makeURI (a.getValue("location")), a.getValue ("xref"),
                          a.getValue ("namespace")));
    } catch (URISyntaxException e) {
        // shouldn't happen, has been checked on import
        throw new SAXException (e);
    }
      }
  }

  /**
   * Receive notification of the end of an element.
   *
   * @param uri the Namespace URI, or the empty string if the
   * element has no Namespace URI or if Namespace processing is not
   * being performed.
   * @param loc the local name (without prefix), or the empty string
   * if Namespace processing is not being performed.
   * @param raw the raw XML 1.0 name (with prefix), or the empty
   * string if raw names are not available.
   * @throws SAXException not thrown.
   */
  public void endElement(String uri, String loc, String raw)
      throws SAXException {
      if (loc.equals ("SchemaType")) {
    if (gotSchema) {
        schemaInfo.pack ();
        setContextData ("DataType", schemaInfo);
    } else {
        setContextData ("DataType", org.w3c.dom.Element.class);
    }
      }
  }
    }

    /**
     * Extract the value from a <code>&lt;DataType&gt;</code> and
     * a value representing node.
     * @param typeElem the <code>&lt;DataType&gt;</code> element.
     * @param valueElem the value element.
     * @return the extracted value which may be <code>null</code>.
     * @throws IllegalArgumentException if the value cannot be extracted.
     * @deprecated no longer used with SAX initialization
     */
    public static Object extractValue (Element typeElem, Element valueElem)
  throws IllegalArgumentException {
  if (valueElem == null) {
      return null;
  }
  Namespace xpdlns = Namespace.getNamespace (XPDLUtil.XPDL_NS);
  Element bt = typeElem.getChild ("BasicType", xpdlns);
  if (bt != null) {
      try {
    if (bt.getAttributeValue("Type").equals("STRING")) {
        return valueElem.getText();
    }
    if (bt.getAttributeValue("Type").equals("FLOAT")) {
        return new Double (valueElem.getText());
    }
    if (bt.getAttributeValue("Type").equals("INTEGER")) {
        return new Long (valueElem.getText());
    }
    if (bt.getAttributeValue("Type").equals("DATETIME")) {
        return XMLUtil.parseXsdDateTime (valueElem.getText());
    }
    if (bt.getAttributeValue("Type").equals("BOOLEAN")) {
        return new Boolean (valueElem.getText());
    }
    if (bt.getAttributeValue("Type").equals("PERFORMER")) {
        return valueElem.getText();
    }
      } catch (NumberFormatException e) {
    throw new IllegalArgumentException
        ("Cannot convert to type: " + e.getMessage ());
      } catch (ParseException e) {
    throw new IllegalArgumentException
        ("Cannot convert to type: " + e.getMessage ());
      }
  }
  if (typeElem.getChild ("SchemaType", xpdlns) != null
      || typeElem.getChild ("ExternalReference", xpdlns) != null) {
      List cl = valueElem.getChildren();
      if (cl.size () == 1) {
    return ((Element)cl.get(0)).clone ();
      }
      if (cl.size () > 0) {
    List res = new ArrayList ();
    for (Iterator i = cl.iterator (); i.hasNext ();) {
        Element el = (Element)i.next ();
        res.add (el.clone());
    }
    return res;
      }
      try {
    SAXParserFactory spf = SAXParserFactory.newInstance ();
    spf.setValidating (false);
    spf.setNamespaceAware (true);
    spf.setFeature
        ("http://xml.org/sax/features/namespace-prefixes", true);
    XMLReader xr = null;
    try {
        spf.setFeature
      ("http://xml.org/sax/features/xmlns-uris", true);
        xr = spf.newSAXParser().getXMLReader();
    } catch (SAXException e) {
        xr = new XmlnsUrisPatcher
      (spf.newSAXParser().getXMLReader());
    }
    SAXContentBuffer seb = new SAXEventBufferImpl ();
    XMLFilterImpl filter = new XMLFilterImpl () {
      private int level = 0;
      public void startElement
          (String uri, String localName, String qName,
           Attributes atts) throws SAXException {
          if (level > 0) {
        super.startElement (uri,localName,qName,atts);
          }
          level += 1;
      }
      public void endElement
          (String uri, String localName, String qName)
          throws SAXException{
          level -= 1;
          if (level > 0) {
        super.endElement (uri, localName, qName);
          }
      }
        };
    filter.setContentHandler (seb);
    xr.setContentHandler (filter);
    xr.parse (new InputSource
        (new StringReader
         ("<temporary-root>" + valueElem.getText()
          + "</temporary-root>")));
    seb.pack();
    return seb;
      } catch (ParserConfigurationException e) {
    throw new IllegalArgumentException
        ("Error initiliazing schema type: " + e.getMessage ());
      } catch (SAXException e) {
    throw new IllegalArgumentException
        ("Error initiliazing schema type: " + e.getMessage ());
      } catch (IOException e) {
    throw new IllegalArgumentException
        ("Error initiliazing schema type: " + e.getMessage ());
      }
  }
  throw new IllegalArgumentException ("Unknown data type");
    }

    /**
     * Check if the given object is one of the possible
     * representations of XML types used in WfMOpen.
     *
     * @param type the object representing the type
     * @return <code>true</code> if the argument represents an XML type
     */
    public static boolean isXMLType (Object type) {
  return (type instanceof SAXEventBuffer)
      || type.equals(org.w3c.dom.Element.class)
      || ((type instanceof ExternalReference)
                && !isJavaType((ExternalReference)type));
    }

    /**
     * Retrieve a duration from the given String. The result can be a
     * {@link de.danet.an.util.Duration <code>Duration</code>} if the
     * duration is specified as a delta or a {@link java.util.Date
     * <code>Date</code>} if the duration is specified as an absolute
     * value.<P>
     *
     * Attempts to parse the string are made in the following order:
     * <ol>
     *   <li>
     *     As XSD duration (see {@link de.danet.an.util.XMLUtil#parseXsdDuration
     *     <code>parseXsdDuration</code>}).
     *   </li>
     *   <li>
     *     As an XSD dateTime (see {@link
     *     de.danet.an.util.XMLUtil#parseXsdDateTime
     *     <code>parseXsdDateTime</code>}).
     *   </li>
     *   <li>
     *     As duration specification as described in
     *     {@link de.danet.an.util.Duration <code>Duration</code>}.
     *   </li>
     *   <li>
     *     As a date time specification in the formats "d MMM yy HH:mm:ss z"
     *     and "d MMM yy HH:mm z" (see {@link java.text.SimpleDateFormat
     *     <code>SimpleDateFormat</code>}). An optionally leading "EEE, "
     *     is ignored. This includes RFC822 conformant date time specifications.
     *   </li>
     * </ol>
     *
     * @param s the string to be parsed
     * @param e an evaluator to be passed to {@link Duration#parse
     * (String,ValueEvaluator) <code>Duration.parse</code>}
     * @return the result
     * @throws ParseException if the string cannot be parsed
     */
    public static Object parseDuration (String s, ValueEvaluator e)
  throws ParseException {
  try {
      return XMLUtil.parseXsdDuration(s);
  } catch (ParseException e1) {
      try {
    return XMLUtil.parseXsdDateTime(s);
      } catch (ParseException e2) {
    try {
        return Duration.parse(s, e);
    } catch (ParseException e3) {
        int c = s.indexOf (',');
        if (c >= 0) {
      s = s.substring (c + 1);
        }
        try {
      return ((DateFormat)dfRfc822plus.clone()).parse (s);
        } catch (ParseException e4) {
      try {
          return ((DateFormat)dfRfc822.clone()).parse (s);
      } catch (ParseException e5) {
          throw new ParseException
        ("Invalid duration: " + s, 0);
      }
        }
    }
      }
  }
    }

    /**
     * Retrieve a duration from the given String. Handles numbers as
     * values in duration parsing only.
     *
     * @param s the string to be parsed
     * @return the result
     * @throws ParseException if the string cannot be parsed
     * @see #parseDuration(String,ValueEvaluator)
     */
    public static Object parseDuration (String s)
  throws ParseException {
        return parseDuration (s, null);
    }
   
    /**
     * Create an URI, adding the java scheme if necessary.
     */
    private static URI makeURI (String uri) throws URISyntaxException {
        URI res = new URI (uri);
        if (res.getScheme() == null && res.getFragment() == null) {
            res = new URI ("java", res.getSchemeSpecificPart(), null);
        }
        return res;
    }
   
    /**
     * Checks if the external reference is a Java type.
     * @param extRef the external reference.
     * @return <code>true</code> if the extzernal reference
     * describes a Java type.
     */
    public static boolean isJavaType (ExternalReference extRef) {
        return extRef.location().getScheme() != null
            && extRef.location().getScheme().equals("java");
    }
   
    /**
     * Retrieves the Java type from the external reference.
     * @param extRef the external reference.
     * @return the Java type described by this external reference
     * @throws IllegalStateException if this external reference does not
     * describe a Java type
     */
    public static Class getJavaType (ExternalReference extRef)
        throws ClassNotFoundException {
        if (!isJavaType(extRef)) {
            throw new IllegalStateException ("Not a Java type");
        }
        return Class.forName
            (extRef.location().getSchemeSpecificPart(), true,
             Thread.currentThread().getContextClassLoader());
    }
}
TOP

Related Classes of de.danet.an.workflow.util.XPDLUtil

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.