
org.ow2.bonita.env.xml.WireParser Maven / Gradle / Ivy
/**
* Copyright (C) 2007 Bull S. A. S.
* Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois
* 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.
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301, USA.
**/
package org.ow2.bonita.env.xml;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.ow2.bonita.env.Descriptor;
import org.ow2.bonita.env.WireContext;
import org.ow2.bonita.env.WireDefinition;
import org.ow2.bonita.env.binding.BooleanBinding;
import org.ow2.bonita.env.binding.ByteBinding;
import org.ow2.bonita.env.binding.CharBinding;
import org.ow2.bonita.env.binding.ClassBinding;
import org.ow2.bonita.env.binding.DoubleBinding;
import org.ow2.bonita.env.binding.FloatBinding;
import org.ow2.bonita.env.binding.IntBinding;
import org.ow2.bonita.env.binding.ListBinding;
import org.ow2.bonita.env.binding.MapBinding;
import org.ow2.bonita.env.binding.NullBinding;
import org.ow2.bonita.env.binding.ObjectBinding;
import org.ow2.bonita.env.binding.RefBinding;
import org.ow2.bonita.env.binding.SetBinding;
import org.ow2.bonita.env.binding.StringBinding;
import org.ow2.bonita.env.descriptor.AbstractDescriptor;
import org.ow2.bonita.env.descriptor.ArgDescriptor;
import org.ow2.bonita.env.descriptor.ObjectDescriptor;
import org.ow2.bonita.util.Misc;
import org.ow2.bonita.util.ReflectUtil;
import org.ow2.bonita.util.xml.Bindings;
import org.ow2.bonita.util.xml.Parse;
import org.ow2.bonita.util.xml.Parser;
import org.ow2.bonita.util.xml.XmlUtil;
import org.w3c.dom.Element;
/**
* parses object wiring xml and constructs a WireDefinition.
*
*
* To learn the full XML syntax, check out the xsd docs
*
*
* - To describe an object:
*
* <object .../>
: see {@link ObjectBinding}
*
*
* - To describe basic types:
*
* <boolean .../>
, <true />
and <false/>
: see
* {@link BooleanBinding}
* <byte .../>
: see {@link ByteBinding}
* <char .../>
: see {@link CharBinding}
* <double .../>
: see {@link DoubleBinding}
* <float .../>
: see {@link FloatBinding}
* <int .../>
: see {@link IntBinding}
* <string .../>
: see {@link StringBinding}
*
*
* - To describe collections:
*
* <map .../>
: see {@link MapBinding}
* <set .../>
: see {@link SetBinding}
* <list .../>
: see {@link ListBinding}
*
*
* - Others:
*
* <class .../>
: see {@link ClassBinding}
* <ref .../>
: see {@link RefBinding}
* <null .../>
: see {@link NullBinding}
*
*
*
*
* Bindings
*
*
* The defaults bindings for the Wiring XML are divided in two categories:
*
*
*
* - Descriptors, registered with the {@link #CATEGORY_DESCRIPTOR} category
* - Operations, registered with the {@link #CATEGORY_OPERATION} category
*
*
*
* Once a parser is created, bindings can be added, overwritten and removed to customize that parser instance.
*
*
* Describing arguments
*
*
* An ArgDescriptor is defined by a <arg>
xml element.
*
*
*
* This element can have an attribute "type", which specifies name of the argument's type.
*
*
* This element contains one child element that defines a {@link Descriptor}. This descriptor specifies the value
* to give to the argument.
*
*
* Example
*
* Consider the following class:
*
*
* public class Hello {
* public static String sayHello(String name) {
* return "Hello " + name + " !";
* }
* }
*
*
* The following Xml declaration will create an object 's' of class 'String' (see {@link ObjectDescriptor}). This object
* is created by invoking Hello.sayHello
with the value world
as a parameter.
*
*
* <objects>
* <object name="s" class='Hello' method='sayHello'>
* <arg>
* <string value='world' />
* </arg>
* </object>
* </objects>
*
*
* The created object 's' will be a String, containing "Hello world !".
*
* Initialization
*
*
* The initialization method can be defined with the init
attribute. For more details on how initialization
* works, see section 'Initialization' of {@link WireContext}.
*
*
* The init
attribute can have these values:
*
* lazy
: for lazy creation and delayed initialization
* required
: for lazy creation and immediate initialization
* eager
: for eager creation and delayed initialization
* immediate
: for eager creation and immediate initialization
*
*
* @author Tom Baeyens
* @author Guillaume Porcher (documentation)
*/
public class WireParser extends Parser {
public static final String PVM_WIRE_BINDINGS_RESOURCES = "bonita.wire.bindings.xml";
private static final Logger LOG = Logger.getLogger(WireParser.class.getName());
public static final String CATEGORY_DESCRIPTOR = "descriptor";
public static final String CATEGORY_OPERATION = "operation";
public static final String CATEGORY_INTERCEPTOR = "interceptor";
/** static instance of WireParser */
private static WireParser instance;
/** default bindings for handling wiring xml elements. */
private static Bindings defaultBindings; // initialized at the bottom of this
// file
/**
* Constructs a new WireParser with the default bindings.
*/
public WireParser() {
super(defaultBindings);
}
/**
* Default method to get an instance of the WireParser
*
* @return the static instance of WireParser
*/
public static synchronized WireParser getInstance() {
if (instance == null) {
instance = new WireParser();
}
return instance;
}
/**
* Convenience method to parse a wiring xml.
*
* @param xmlString
* the xml string to parse
* @return the WireDefinition created by parsing the xml given in input.
* @see #parseXmlString(String)
*/
public static WireDefinition parseXmlString(final String xmlString) {
final Parse parse = getInstance().createParse().setString(xmlString).execute();
Misc.showProblems(parse.getProblems(), "wire definition xml string");
return (WireDefinition) parse.getDocumentObject();
}
// document element parsing /////////////////////////////////////////////////
/**
* This method builds the WireDefinition from the DOM tree. This methods parses all child nodes of the documentElement
* that correspond to a Descriptor definition.
*
* @param documentElement
* the root element of the document
* @param parse
* Parse object that contains all information for the current parse operation.
* @return an instance of WireDefinition containing the resulting WireDefinition.
* @see Parser#parseDocumentElement(Element, Parse)
*/
@Override
public Object parseDocumentElement(final Element documentElement, final Parse parse) {
final List elements = XmlUtil.elements(documentElement);
final WireDefinition wireDefinition = new WireDefinition();
wireDefinition.setClassLoader(classLoader);
if (elements != null) {
parse.pushObject(wireDefinition);
try {
for (final Element descriptorElement : elements) {
parseElement(descriptorElement, parse, CATEGORY_DESCRIPTOR);
}
} finally {
parse.popObject();
}
}
return wireDefinition;
}
/**
* This method parses an arbitrary element in the document based on the bindings in the given category. This method
* calls the {@link Parser#parseElement(Element, Parse, String)} method to build the resulting object. If the
* resulting object is a subclass of {@link AbstractDescriptor}, the related fields are initialized.
*
* @param element
* the element to parse
* @param parse
* Parse object that contains all information for the current parse operation.
* @param category
* is the category in which the tagName should be resolved to an ElementHandler. If category is null, all the
* categories will be scanned for an appropriate binding in random order.
* @return the java object created from the DOM element
*/
@Override
public Object parseElement(final Element element, final Parse parse, final String category) {
if (element == null) {
return null;
}
final Object object = super.parseElement(element, parse, category);
if (object instanceof Descriptor) {
final Descriptor descriptor = (Descriptor) object;
if (descriptor instanceof AbstractDescriptor) {
final AbstractDescriptor abstractDescriptor = (AbstractDescriptor) descriptor;
if (element.hasAttribute("name")) {
final String name = element.getAttribute("name");
// get the name
abstractDescriptor.setName(name);
}
if (element.hasAttribute("init")) {
// get the init
final String initText = element.getAttribute("init");
if ("eager".equalsIgnoreCase(initText)) {
abstractDescriptor.setInit(AbstractDescriptor.INIT_EAGER);
} else if ("immediate".equalsIgnoreCase(initText)) {
abstractDescriptor.setInit(AbstractDescriptor.INIT_IMMEDIATE);
} else if ("required".equalsIgnoreCase(initText)) {
abstractDescriptor.setInit(AbstractDescriptor.INIT_REQUIRED);
} else {
// init='lazy' or default value
abstractDescriptor.setInit(AbstractDescriptor.INIT_LAZY);
}
}
}
// add the descriptor
final WireDefinition wireDefinition = parse.findObject(WireDefinition.class);
wireDefinition.addDescriptor(descriptor);
}
return object;
}
// other methods ////////////////////////////////////////////////////////////
/**
* Parses the list of arguments of a method. This method creates a list of {@link ArgDescriptor} from the given list
* of DOM elements
*
* @param argElements
* the list of argument DOM elements
* @param parse
* Parse object that contains all information for the current parse operation.
* @return the list of ArgDescriptor created from the DOM elements
* @see ArgDescriptor
*/
public List parseArgs(final List argElements, final Parse parse) {
List args = null;
if (argElements != null) {
if (argElements.size() > 0) {
args = new ArrayList(argElements.size());
}
for (final Element argElement : argElements) {
final ArgDescriptor argDescriptor = new ArgDescriptor();
argDescriptor.setTypeName(XmlUtil.attribute(argElement, "type"));
final Element descriptorElement = XmlUtil.element(argElement);
if (descriptorElement == null) {
parse.addProblem("arg must contain exactly one descriptor element out of "
+ bindings.getTagNames(CATEGORY_DESCRIPTOR) + " as contents:"
+ XmlUtil.toString((Element) argElement.getParentNode()));
} else {
final Descriptor descriptor = (Descriptor) parseElement(descriptorElement, parse, CATEGORY_DESCRIPTOR);
argDescriptor.setDescriptor(descriptor);
}
args.add(argDescriptor);
}
}
return args;
}
static {
// default descriptor parsers
// ///////////////////////////////////////////////
defaultBindings = new Bindings();
final BindingParser bindingParser = new BindingParser();
final Enumeration enumeration = ReflectUtil.getResources(null, PVM_WIRE_BINDINGS_RESOURCES);
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
final URL url = enumeration.nextElement();
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("parsing bindings from resource url: " + url);
}
final Parse parse = bindingParser.createParse().setUrl(url).pushObject(defaultBindings).execute();
Misc.showProblems(parse.getProblems(), "default wire bindings");
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy