hlship 2003/08/05 08:41:44 Modified: hivemind/src/test/hivemind/test/config TestExtensionPoint.java hivemind/src/java/org/apache/commons/hivemind HiveMindMessages.properties hivemind/xdocs descriptor.xml extension-points.xml registry.xml hivemind/src/java/org/apache/commons/hivemind/parse DescriptorParser.java hivemind/src/META-INF hivemodule.xml hivemind/src/test/hivemind/test HiveMindTestCase.java hivemind/src/java/org/apache/commons/hivemind/impl RegistryBuilder.java Added: hivemind/src/test/hivemind/test/config ToUpperCaseTranslator.java TranslatorClass.xml hivemind/src/java/org/apache/commons/hivemind/impl ErrorHandler.java Log: Handle class loader issues when creating translators from class names. Add hook for handling module parse errors inside RegistryBuilder. Add <set-int> element to hivemind.BuilderFactory. Revision Changes Path 1.6 +20 -0 jakarta-commons-sandbox/hivemind/src/test/hivemind/test/config/TestExtensionPoint.java Index: TestExtensionPoint.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/src/test/hivemind/test/config/TestExtensionPoint.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- TestExtensionPoint.java 4 Aug 2003 14:25:44 -0000 1.5 +++ TestExtensionPoint.java 5 Aug 2003 15:41:44 -0000 1.6 @@ -334,4 +334,24 @@ assertEquals("message", d.getKey()); assertEquals("Some Damn Thing", d.getValue()); } + + public void testTranslatorClass() throws Exception + { + Registry r = buildRegistry("TranslatorClass.xml"); + + List l = r.getExtensionPointElements("hivemind.test.config.TranslatorClass"); + + assertEquals(2, l.size()); + + Datum d = (Datum) l.get(0); + + assertEquals("key1", d.getKey()); + assertEquals("VALUE1", d.getValue()); + assertNotNull(d.getLocation()); + + d = (Datum) l.get(1); + + assertEquals("key2", d.getKey()); + assertEquals("VALUE2", d.getValue()); + } } 1.1 jakarta-commons-sandbox/hivemind/src/test/hivemind/test/config/ToUpperCaseTranslator.java Index: ToUpperCaseTranslator.java =================================================================== /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package hivemind.test.config; import org.apache.commons.hivemind.Element; import org.apache.commons.hivemind.schema.SchemaProcessor; import org.apache.commons.hivemind.schema.Translator; import org.apache.commons.lang.StringUtils; /** * Converts the input value, if not null, to upper case. * * @author Howard Lewis Ship * @version $Id: ToUpperCaseTranslator.java,v 1.1 2003/08/05 15:41:44 hlship Exp $ */ public class ToUpperCaseTranslator implements Translator { public Object translate(SchemaProcessor processor, Element element, String inputValue) { if (StringUtils.isEmpty(inputValue)) return null; return inputValue.toUpperCase(); } } 1.1 jakarta-commons-sandbox/hivemind/src/test/hivemind/test/config/TranslatorClass.xml Index: TranslatorClass.xml =================================================================== <?xml version="1.0" encoding="UTF-8"?> <!-- $Id: TranslatorClass.xml,v 1.1 2003/08/05 15:41:44 hlship Exp $ --> <module id="hivemind.test.config" version="1.0.0"> <extension-point id="TranslatorClass"> <schema> <element name="datum"> <attribute name="key" required="true"/> <attribute name="value" required="true"/> <rules> <create-object class="hivemind.test.config.impl.Datum"/> <read-attribute property="key" attribute="key"/> <read-attribute property="value" attribute="value" translator="hivemind.test.config.ToUpperCaseTranslator"/> <invoke-parent method="addElement"/> </rules> </element> </schema> </extension-point> <extension point-id="TranslatorClass"> <datum key="key1" value="value1"/> <datum key="key2" value="value2"/> </extension> </module> 1.19 +2 -1 jakarta-commons-sandbox/hivemind/src/java/org/apache/commons/hivemind/HiveMindMessages.properties Index: HiveMindMessages.properties =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/src/java/org/apache/commons/hivemind/HiveMindMessages.properties,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- HiveMindMessages.properties 5 Aug 2003 00:50:36 -0000 1.18 +++ HiveMindMessages.properties 5 Aug 2003 15:41:44 -0000 1.19 @@ -57,6 +57,7 @@ RegistryBuilder.optional=an optional RegistryBuilder.required=exactly one RegistryBuilder.unable-to-find-modules=Unable to locate HiveMind module deployment descriptors in {0}: {1} +RegistryBuilder.unable-to-parse=Unable to parse module deployment descriptor {0}: {1} InterceptorStack.interceptor-does-not-implement-interface=The service interceptor ({0}) generated by service {1} for service extension point {2} does not implement the {3} interface defined by the extension point. InterceptorStack.null-interceptor=Service {0} generated a null interceptor (for service extension point {1}). 1.17 +9 -2 jakarta-commons-sandbox/hivemind/xdocs/descriptor.xml Index: descriptor.xml =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/xdocs/descriptor.xml,v retrieving revision 1.16 retrieving revision 1.17 diff -u -r1.16 -r1.17 --- descriptor.xml 1 Aug 2003 19:05:24 -0000 1.16 +++ descriptor.xml 5 Aug 2003 15:41:44 -0000 1.17 @@ -82,7 +82,9 @@ <section name="description"> <p>The &_description; element provides a user-readable description as the - content of the element.</p> + content of the element. This description is used + in the generated + <a href="registry.html">registry documentation</a></p> </section> <section name="element"> @@ -364,6 +366,11 @@ </table> <p> + Contains: &element; + + </p> + + <p> At a future time, the &_schema; element will be extended to provide more options, to provide more precise control over the elements that may be provided in an &_extension;. At this time, a &_schema; is simply a list of &_element; elements. 1.3 +66 -13 jakarta-commons-sandbox/hivemind/xdocs/extension-points.xml Index: extension-points.xml =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/xdocs/extension-points.xml,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- extension-points.xml 1 Aug 2003 14:21:38 -0000 1.2 +++ extension-points.xml 5 Aug 2003 15:41:44 -0000 1.3 @@ -32,12 +32,32 @@ <section name="Defining a Extension Point"> <p> -A module may include &extension-point; elements to define new extension points. A significant portion of +A module may include &extension-point; elements to define new extension points. + +An extension point may specify the expected, or allowed, number of contributions: +<ul> +<li>Zero or one (the default)</li> +<li>Zero or more</li> +<li>At least one</li> +<li>Exactly one</li> +</ul> +</p> + +<p> +At runtime, the number of actual contributions is checked against the constraint and an error occurs +if the number doesn't match. +</p> + +<subsection name="Defining the Contribution Format"> + +<p> +A significant portion of an extension point is the &schema; element ... this is used to define the format of contributions that may be made inside &extension; elements. Contributions take the form of XML elements and attributes, the &_schema; element identifies which elements and which attributes and provides rules that transform the contributions into Java objects. -</p> + </p> + <p> If a contribution from an &extension; is invalid, then a runtime error is logged and the contribution is ignored. @@ -45,21 +65,54 @@ of the contribution so you can go fix it. </p> +<p> +The &schema; element contains &element; elements to describe the XML elements that may be contributed. +&_element;s contain &attribute;s to define the attributes allowed for those elements. &_element;s +also contain &rules; used to convert the contributed XML into Java objects. +</p> <p> -An extension point may also specify the expected, or allowed, number of contributions: -<ul> -<li>Zero or one</li> -<li>Zero or more</li> -<li>At least one</li> -<li>Exactly one</li> -</ul> +Here's an example from the HiveMind test suite. The <code>Datum</code> object has two +properties: key and value. +</p> + +<source><![CDATA[ + <extension-point id="Simple"> + <schema> + <element name="datum"> + <attribute name="key" required="true"/> + <attribute name="value" required="true"/> + <rules> + <create-object class="hivemind.test.config.impl.Datum"/> + <read-attribute property="key" attribute="key"/> + <read-attribute property="value" attribute="value"/> + <invoke-parent method="addElement"/> + </rules> + </element> + </schema> + </extension-point> + <extension point-id="Simple"> + <datum key="key1" value="value1"/> + <datum key="key2" value="value2"/> + </extension> +]]></source> + +<p> +The <code>create-object</code> rule creates an instance of <code>Datum</code>. +The <code>read-attribute</code> rules read attributes from the contributed <code><datum></code> +element and assign them to properties of the <code>Datum</code>. The <code>invoke-parent</code> +rule adds the configured <code>Datum</code> element to the extension point. </p> <p> -At runtime, the number of actual contributions is checked against the constraint and an error occurs -if the number doesn't match. +This extra work in the module descriptor eliminates a large amount of custom Java code that would +otherwise be necessary to walk the XML contributions tree and convert elements and attributes +into objects and properties. The end result is very concise, readable contributions (as shown in the &_extension; +in the example). </p> + +</subsection> + </section> <section name="Accessing Extension Points"> @@ -184,7 +237,7 @@ </p> <p> - You can omit the schema, in which case the elements are left in as XML and your code + You can omit the schema, in which case the elements are left as XML and your code is responsible for walking the elements and attributes ... but why bother? Far easier to let HiveMind do the conversions and validations. </p> 1.2 +3 -3 jakarta-commons-sandbox/hivemind/xdocs/registry.xml Index: registry.xml =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/xdocs/registry.xml,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- registry.xml 20 Jun 2003 14:00:29 -0000 1.1 +++ registry.xml 5 Aug 2003 15:41:44 -0000 1.2 @@ -19,7 +19,7 @@ HiveMind includes tools for documentating a HiveMind registry. At build time, all related <code>hivemodule.xml</code> descriptors are parsed, combined into a single file, and then converted using XSLT. The end result is much like JavaDoc ... its fully - hyperlinked and allows you to see all services and contributions clearly. + hyperlinked and allows you to see all services, extension points and contributions clearly. </p> @@ -39,7 +39,7 @@ <td> <a href="sample-registry/index.html">sample-registry</a></td> <td> - Documentation for a hypothetical application; this allow you to see + Documentation for a hypothetical application; this allows you to see more clearly how the hyperlinking occurs. </td> 1.20 +5 -2 jakarta-commons-sandbox/hivemind/src/java/org/apache/commons/hivemind/parse/DescriptorParser.java Index: DescriptorParser.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/src/java/org/apache/commons/hivemind/parse/DescriptorParser.java,v retrieving revision 1.19 retrieving revision 1.20 diff -u -r1.19 -r1.20 --- DescriptorParser.java 5 Aug 2003 00:50:36 -0000 1.19 +++ DescriptorParser.java 5 Aug 2003 15:41:44 -0000 1.20 @@ -419,7 +419,8 @@ return item._object; } - public ModuleDescriptor parse(IResourceLocation location) throws DocumentParseException + public ModuleDescriptor parse(IResourceLocation location, IResourceResolver resolver) + throws DocumentParseException { try { @@ -427,6 +428,7 @@ LOG.debug("Parsing " + location); _resourceLocation = location; + _resolver = resolver; URL url = location.getResourceURL(); @@ -466,6 +468,7 @@ _moduleDescriptor = null; _attributes.clear(); _schemas.clear(); + _resolver = null; } } 1.11 +21 -1 jakarta-commons-sandbox/hivemind/src/META-INF/hivemodule.xml Index: hivemodule.xml =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/src/META-INF/hivemodule.xml,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- hivemodule.xml 5 Aug 2003 00:50:36 -0000 1.10 +++ hivemodule.xml 5 Aug 2003 15:41:44 -0000 1.11 @@ -106,6 +106,26 @@ </rules> </element> + + <element name="set-int"> + <description> + Configures a property of the service instance to an integer value. + </description> + <attribute name="property" required="true"> + <description>The name of a property of the service instance to configure.</description> + </attribute> + <attribute name="value" required="true"> + <description>An integer value to set the property to.</description> + </attribute> + + <rules> + <create-object class="org.apache.commons.hivemind.service.impl.SetPropertyValue"/> + <read-attribute property="propertyName" attribute="property"/> + <read-attribute property="value" attribute="value" translator="int"/> + <invoke-parent method="addProperty"/> + </rules> + </element> + <element name="set-service"> <description> Configures a property of the service instance to another service. 1.14 +4 -4 jakarta-commons-sandbox/hivemind/src/test/hivemind/test/HiveMindTestCase.java Index: HiveMindTestCase.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/src/test/hivemind/test/HiveMindTestCase.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- HiveMindTestCase.java 29 Jul 2003 22:20:32 -0000 1.13 +++ HiveMindTestCase.java 5 Aug 2003 15:41:44 -0000 1.14 @@ -120,7 +120,7 @@ builder.processModule(_resolver, md); } - builder.processModule(_resolver, _parser.parse(getMasterModuleLocation())); + builder.processModule(_resolver, _parser.parse(getMasterModuleLocation(), _resolver)); return builder.constructRegistry(Locale.getDefault()); } @@ -129,7 +129,7 @@ { RegistryBuilder builder = new RegistryBuilder(); - ModuleDescriptor md = _parser.parse(l); + ModuleDescriptor md = _parser.parse(l, _resolver); builder.processModule(_resolver, md); return builder.constructRegistry(Locale.getDefault()); @@ -139,7 +139,7 @@ { IResourceLocation location = getLocation(file); - return _parser.parse(location); + return _parser.parse(location, _resolver); } protected IResourceLocation getLocation(String file) 1.18 +54 -6 jakarta-commons-sandbox/hivemind/src/java/org/apache/commons/hivemind/impl/RegistryBuilder.java Index: RegistryBuilder.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/src/java/org/apache/commons/hivemind/impl/RegistryBuilder.java,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- RegistryBuilder.java 4 Aug 2003 14:21:56 -0000 1.17 +++ RegistryBuilder.java 5 Aug 2003 15:41:44 -0000 1.18 @@ -100,7 +100,7 @@ * here and in many of the related classes is divided into construction-time logic * and runtime logic. Runtime logic is synchronized and threadsafe. Construction-time logic * is not threadsafe. Methods such as [EMAIL PROTECTED] org.apache.commons.hivemind.impl.RegistryImpl#addModule(Module)}, - * [EMAIL PROTECTED] org.apache.commons.hivemind.impl.ModuleImpl#addExtensionPoint(ExtensionPoint))}, + * [EMAIL PROTECTED] org.apache.commons.hivemind.impl.ModuleImpl#addExtensionPoint(ExtensionPoint)}, * [EMAIL PROTECTED] org.apache.commons.hivemind.impl.ExtensionPointImpl#addExtension(Extension)} * and the like are construction-time. Once the registry is fully constructed, it is not * allowed to invoke those methods (though, at this time, no checks occur). @@ -151,6 +151,39 @@ private Map _extensionPoints = new HashMap(); /** + * Delegate used for handling errors. + */ + + private ErrorHandler _errorHandler; + + private static class DefaultErrorHandler implements ErrorHandler + { + + public void handleModuleParseError( + IResourceLocation moduleDescriptorLocation, + RuntimeException ex) + { + LOG.error( + HiveMind.format( + "RegistryBuilder.unable-to-parse", + moduleDescriptorLocation, + ex.getMessage()), + ex); + } + + } + + public RegistryBuilder() + { + this(new DefaultErrorHandler()); + } + + public RegistryBuilder(ErrorHandler handler) + { + _errorHandler = handler; + } + + /** * Processes all modules that can be found using the resolver. */ public void processModules(IResourceResolver resolver) @@ -175,18 +208,33 @@ ex); } - DescriptorParser parser = new DescriptorParser(); + DescriptorParser parser = null; while (e.hasMoreElements()) { URL descriptorURL = (URL) e.nextElement(); IResourceLocation descriptorLocation = new URLResourceLocation(descriptorURL); - ModuleDescriptor md = parser.parse(descriptorLocation); + if (parser == null) + parser = new DescriptorParser(); + + try + { + ModuleDescriptor md = parser.parse(descriptorLocation, resolver); + + processModule(resolver, md); + + count++; + } + catch (RuntimeException ex) + { + // An exception may leave the parser in an unknown state, so + // give up on that instance and start with a fresh one. - processModule(resolver, md); + parser = null; - count++; + _errorHandler.handleModuleParseError(descriptorLocation, ex); + } } long elapsedMillis = System.currentTimeMillis() - startMillis; 1.1 jakarta-commons-sandbox/hivemind/src/java/org/apache/commons/hivemind/impl/ErrorHandler.java Index: ErrorHandler.java =================================================================== /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.commons.hivemind.impl; import org.apache.tapestry.IResourceLocation; /** * Pluggable handler for errors by [EMAIL PROTECTED] org.apache.commons.hivemind.impl.RegistryBuilder}. * * @author Howard Lewis Ship * @version $Id: ErrorHandler.java,v 1.1 2003/08/05 15:41:44 hlship Exp $ */ public interface ErrorHandler { /** * Invoked by [EMAIL PROTECTED] RegistryBuilder#processModule(IResourceResolver, ModuleDescriptor)} * if there is an error parsing a module deployment descriptor. */ public void handleModuleParseError( IResourceLocation moduleDescriptorLocation, RuntimeException ex); }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]