A use case would have been an ServiceFactory using BuilderFactory which chosses at runtime between different implementations. In generaly if you reuse a service having access to it's parameters-schema is not bad.
Apart of this I am not sure how private even the processing part of a schema is. Configurations can be accessed by anyone and should therefore be considered public. There is no way to express 'no stable result'. Schemas for services are defined in the service-point and not in the implementation. They are part of the service-interface and implementations will have to rely on the processing.
IMO that's just a consequence of combining the processing with the xml-defintion. The public xml-def trags the procssing-result into public.
So while I've strong doubts about this promis on stability I agree that expressing it explicitly is a good idea. I also agree with you that HiveMind is build around use-cases and I've to say that all the use cases I can imagine can also be full-filled if recursion is supported and if plain elements are returned.
Thank you. Eclosed is my new diff.
On Mon, 8 Mar 2004 17:28:44 -0500, Howard M. Lewis Ship <[EMAIL PROTECTED]> wrote:
The act of assigning an id to a <schema> is, in effect, a promise on the part of the developer that
the <schema> (and the Java objects assembled from contributions to that schema) are stable enough
for others to reuse.
In the case that no id is provided, it may be an oversight, or it may be that the Java objects are
not reusable.
Can you give me reasonable examples of why you think this change is necessary? To date, in HiveMind,
everything really has been driven by real experience (generally, anti-patterns in other software,
but still).
-- Howard M. Lewis Ship Independent J2EE / Open-Source Java Consultant Creator, Tapestry: Java Web Components http://howardlewisship.com
-----Original Message----- From: Christian Essl [mailto:[EMAIL PROTECTED] Sent: Monday, March 08, 2004 4:07 PM To: [EMAIL PROTECTED] Subject: Re: [HiveMind] nested schemas
Thanks for the hint on schema-id!
I've added it now. Checking and complaining early :).
I removed the configuration-id and service-id atts and have just schema-id.
However I still want to access schemas even if they don't provide an id. Therefore in my current implementation I give each schema which has no id set a default id. For configuration schemas 'c:'+config-id, for service schemas 's:'+service-id. (This ids can also be used in <schema id-ref=""> ).
What do you think of that, is this too much change?
Thanks, Chris
-- Christian Essl
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
--
Christian Essl
Index: framework/src/java/org/apache/hivemind/impl/SchemaElement.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/hivemind/impl/SchemaElement.java,v
retrieving revision 1.1
diff -u -r1.1 SchemaElement.java
--- framework/src/java/org/apache/hivemind/impl/SchemaElement.java 26 Feb 2004
23:07:40 -0000 1.1
+++ framework/src/java/org/apache/hivemind/impl/SchemaElement.java 9 Mar 2004
05:45:58 -0000
@@ -30,6 +30,7 @@
import org.apache.hivemind.schema.ElementModel;
import org.apache.hivemind.schema.Rule;
import org.apache.hivemind.schema.SchemaProcessor;
+import org.apache.hivemind.schema.impl.SchemaContent;
/**
* A wrapper around [EMAIL PROTECTED] org.apache.hivemind.schema.ElementModel} used
@@ -182,5 +183,9 @@
r.end(processor, element);
}
+ }
+
+ SchemaContent getSchemaContent(){
+ return _model.getSchemaContent();
}
}
Index: framework/src/java/org/apache/hivemind/impl/SchemaProcessorImpl.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/hivemind/impl/SchemaProcessorImpl.java,v
retrieving revision 1.1
diff -u -r1.1 SchemaProcessorImpl.java
--- framework/src/java/org/apache/hivemind/impl/SchemaProcessorImpl.java 26 Feb
2004 23:07:40 -0000 1.1
+++ framework/src/java/org/apache/hivemind/impl/SchemaProcessorImpl.java 9 Mar
2004 05:45:59 -0000
@@ -14,19 +14,23 @@
package org.apache.hivemind.impl;
+import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.Element;
import org.apache.hivemind.HiveMind;
import org.apache.hivemind.Module;
import org.apache.hivemind.schema.ElementModel;
import org.apache.hivemind.schema.Schema;
import org.apache.hivemind.schema.SchemaProcessor;
+import org.apache.hivemind.schema.impl.SchemaContent;
/**
* Used to assemble all the [EMAIL PROTECTED] org.apache.hivemind.Contribution}s
@@ -196,8 +200,17 @@
schemaElement.validateAttributes(this, element);
schemaElement.fireBegin(this, element);
- processNestedElements(element, schemaElement);
-
+ SchemaContent schemaContent = schemaElement.getSchemaContent();
+
+ if(schemaContent == null)
+ {
+ processNestedElements(element, schemaElement);
+ }
+ else
+ {
+ processNestedSchema(element, schemaContent);
+ }
+
schemaElement.fireEnd(this, element);
}
@@ -217,4 +230,78 @@
processElement(nested, schemaElement.getNestedElement(name));
}
}
+
+ private void processNestedSchema(Element element, SchemaContent schemaContent)
+ {
+ //the list which will be set on the parent
+ List contL;
+
+ //In case we have no childs, we set
+ //an emptyList; also stops recursions
+ if(element.getElements().size() == 0){
+ contL = Collections.EMPTY_LIST;
+ }else{
+ //otherwise we populate
+ //the list with the conten
+ Schema contS = schemaContent.getSchema(_module);
+
+ if(contS == null){
+ contL = new ArrayList(element.getElements());
+ }else{
+ SchemaProcessorImpl nested = new
SchemaProcessorImpl(contS);
+ nested.process(element.getElements(), _module);
+ contL = nested.getElements();
+ }
+ }
+
+ //call the parent-method
+ Object parent = peek();
+ String methodName = schemaContent.getParentMethod();
+
+ try
+ {
+ Method m = findMethod(parent, methodName, List.class);
+
+ m.invoke(parent, new Object[] { contL });
+ }
+ catch (Exception ex)
+ {
+ throw new ApplicationRuntimeException(
+ HiveMind.format(
+ "InvokeParentRule.error-invoking-method",
+ new Object[] { methodName, parent,
schemaContent.getLocation(), ex.getMessage()}),
+ schemaContent.getLocation(),
+ ex);
+ }
+ }
+
+ /** Copied from InvokeParentRule
+ * Searches for the *first* public method the has the right name, and takes a
+ * single parameter that is compatible with the parameter type.
+ *
+ * @throws NoSuchMethodException if a method can't be found
+ */
+ private Method findMethod(Object target, String name, Class parameterType)
+ throws NoSuchMethodException
+ {
+ Method[] methods = target.getClass().getMethods();
+
+ for (int i = 0; i < methods.length; i++)
+ {
+ Method m = methods[i];
+
+ if (m.getParameterTypes().length != 1)
+ continue;
+
+ if (!m.getName().equals(name))
+ continue;
+
+ if (m.getParameterTypes()[0].isAssignableFrom(parameterType))
+ return m;
+
+ }
+
+ throw new NoSuchMethodException(name);
+ }
+
}
Index: framework/src/java/org/apache/hivemind/parse/DescriptorParser.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/hivemind/parse/DescriptorParser.java,v
retrieving revision 1.4
diff -u -r1.4 DescriptorParser.java
--- framework/src/java/org/apache/hivemind/parse/DescriptorParser.java 1 Mar 2004
22:56:27 -0000 1.4
+++ framework/src/java/org/apache/hivemind/parse/DescriptorParser.java 9 Mar 2004
05:46:03 -0000
@@ -47,6 +47,7 @@
import org.apache.hivemind.schema.Translator;
import org.apache.hivemind.schema.impl.AttributeModelImpl;
import org.apache.hivemind.schema.impl.ElementModelImpl;
+import org.apache.hivemind.schema.impl.SchemaContent;
import org.apache.hivemind.schema.impl.SchemaImpl;
import org.apache.hivemind.schema.rules.BooleanTranslator;
import org.apache.hivemind.schema.rules.ClassTranslator;
@@ -138,6 +139,33 @@
PropertyUtils.write(_container, _propertyName, s, _referenceLocation);
}
}
+
+ private class SchemaContentRelinker implements Runnable
+ {
+ private String _schemaId;
+ private SchemaContent _schemaContent;
+
+ private SchemaContentRelinker(String schemaId, SchemaContent schemaContent){
+ _schemaId = schemaId;
+ _schemaContent = schemaContent;
+ }
+
+ public void run()
+ {
+ Schema s = _registryAssembly.getSchema(_schemaId);
+
+ if (s == null)
+ {
+ LOG.error(
+ HiveMind.format(
+
"DescriptorParser.unable-to-resolve-schema",
+ _schemaId,
+ _schemaContent.getLocation()));
+ }
+
+ _schemaContent.setSchema(s);
+ }
+ }
/**
* Used to resolve schema references during the parse.
@@ -333,6 +361,13 @@
MAP_ATTRIBUTES.put("property", Boolean.FALSE);
MAP_ATTRIBUTES.put("translator", Boolean.FALSE);
}
+
+ private final Map CONTENT_ATTRIBUTES = new HashMap();
+
+ {
+ CONTENT_ATTRIBUTES.put("schema-id",Boolean.FALSE);
+ CONTENT_ATTRIBUTES.put("parent-method", Boolean.FALSE);
+ }
private final Map OCCURS_MAP = new HashMap();
@@ -1266,11 +1301,54 @@
// <element> is recursive ... possible, but tricky, if using Digester.
- if (elementName.equals("element"))
+ if (elementName.equals("element") && elementModel.getSchemaContent() == null)
{
elementModel.addElementModel(enterStateElement(elementName));
return;
}
+
+ if (elementName.equals("content") &&
elementModel.getElementModel().size() == 0)
+ {
+ SchemaContent content = new SchemaContent();
+
+ push(elementName, content, STATE_ALLOW_DESCRIPTION);
+
+ checkAttributes(CONTENT_ATTRIBUTES);
+
+ if(isAttribute("parent-method"))
+ content.setParentMethod(getAttribute("parent-method"));
+
+ if(isAttribute("schema-id"))
+ {
+ //qualify the id
+ String id = qualify(getAttribute("schema-id"));
+
+ Schema reffed = _registryAssembly.getSchema(id);
+
+ // Not found! We don't know what order modules are
parsed in,
+ // so this is not necessarily an error (it could even
be a forward
+ // reference within the same module). In any case, set
up to relink
+ // to the resolved Schema object after all modules are
parsed.
+
+ if (reffed == null)
+ {
+ Runnable r =
+ new SchemaContentRelinker(id,content);
+
+ _registryAssembly.addPostProcessor(r);
+ }
+ else
+ {
+ content.setSchema(reffed);
+ }
+ }else{
+ content.setSchema(null);
+ }
+
+ elementModel.setSchemaContent(content);
+ return;
+ }
+
unexpectedElement(elementName);
}
Index: framework/src/java/org/apache/hivemind/schema/ElementModel.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/hivemind/schema/ElementModel.java,v
retrieving revision 1.1
diff -u -r1.1 ElementModel.java
--- framework/src/java/org/apache/hivemind/schema/ElementModel.java 26 Feb 2004
23:07:38 -0000 1.1
+++ framework/src/java/org/apache/hivemind/schema/ElementModel.java 9 Mar 2004
05:46:03 -0000
@@ -16,6 +16,8 @@
import java.util.List;
+import org.apache.hivemind.schema.impl.SchemaContent;
+
/**
* Identifies an element that may occur within some schema. Because elements
@@ -43,5 +45,11 @@
*/
public List getRules();
+
+ /**
+ * If the elements content is represented by another Schema the SchemaContent
describing this Schema is
+ * returned. Otherwise null is returned
+ */
+ public SchemaContent getSchemaContent();
}
Index: framework/src/java/org/apache/hivemind/schema/impl/ElementModelImpl.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/hivemind/schema/impl/ElementModelImpl.java,v
retrieving revision 1.1
diff -u -r1.1 ElementModelImpl.java
--- framework/src/java/org/apache/hivemind/schema/impl/ElementModelImpl.java 26 Feb
2004 23:08:02 -0000 1.1
+++ framework/src/java/org/apache/hivemind/schema/impl/ElementModelImpl.java 9 Mar
2004 05:46:03 -0000
@@ -35,6 +35,8 @@
private List _shareableAttributeModels;
private List _rules;
private List _shareableRules;
+ private SchemaContent _schemaContent;
+
public String getElementName()
{
return _elementName;
@@ -83,4 +85,13 @@
return _shareableRules;
}
+ public SchemaContent getSchemaContent()
+ {
+ return _schemaContent;
+ }
+
+ public void setSchemaContent(SchemaContent _cont){
+ _schemaContent = _cont;
+ }
+
}
Index: framework/src/java/org/apache/hivemind/schema/impl/SchemaContent.java
===================================================================
RCS file: framework/src/java/org/apache/hivemind/schema/impl/SchemaContent.java
diff -N framework/src/java/org/apache/hivemind/schema/impl/SchemaContent.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ framework/src/java/org/apache/hivemind/schema/impl/SchemaContent.java 9 Mar
2004 05:46:03 -0000
@@ -0,0 +1,67 @@
+package org.apache.hivemind.schema.impl;
+
+import org.apache.hivemind.ApplicationRuntimeException;
+import org.apache.hivemind.ConfigurationPoint;
+import org.apache.hivemind.ExtensionPoint;
+import org.apache.hivemind.HiveMind;
+import org.apache.hivemind.Module;
+import org.apache.hivemind.ServiceExtensionPoint;
+import org.apache.hivemind.impl.BaseLocatable;
+import org.apache.hivemind.schema.Schema;
+
+/**
+ * Describes a Schema which defines the content of an [EMAIL PROTECTED]
org.apache.hivemind.schema.ElementModel}.
+ */
+public class SchemaContent extends BaseLocatable
+{
+
+ private String _parentMethod = "addElement";
+ private Schema _schema = null;
+
+ /**
+ *
+ */
+ public SchemaContent()
+ {
+ super();
+ }
+
+ /**
+ * The method-name of the top object on the processing stack to wich the List
generated from the
+ * schema should be passed as an argument. The method must have one argument
of type java.util.List.
+ * Default is addElement(Object ob);
+ * @return
+ */
+ public String getParentMethod()
+ {
+ return _parentMethod;
+ }
+
+
+ /**
+ *
+ * @param string
+ */
+ public void setParentMethod(String string)
+ {
+ _parentMethod = string;
+ }
+
+
+ /**
+ * return the schema or null if no schema is used.
+ * @param module the contribution module
+ * @return
+ */
+ public Schema getSchema(Module module){
+ return _schema;
+ }
+
+ /**
+ * Used to set the Schema.
+ * @param schema
+ */
+ public void setSchema(Schema schema){
+ _schema = schema;
+ }
+}
Index: framework/src/test/hivemind/test/config/NestedDataItem.java
===================================================================
RCS file: framework/src/test/hivemind/test/config/NestedDataItem.java
diff -N framework/src/test/hivemind/test/config/NestedDataItem.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ framework/src/test/hivemind/test/config/NestedDataItem.java 9 Mar 2004 05:46:04
-0000
@@ -0,0 +1,43 @@
+/*
+ * Created on 06.03.2004
+ *
+ * To change the template for this generated file go to
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+package hivemind.test.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author chris
+ *
+ * To change the template for this generated type comment go to
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+public class NestedDataItem
+{
+
+ public NestedDataItem _child = null;
+ public String _type;
+ public boolean _endCalled = false;
+
+ public NestedDataItem()
+ {
+ super();
+ }
+
+ public void setType(String type){
+ _type = type;
+ }
+
+ public void addContent(List cont){
+ if(cont.size() != 0){
+ NestedDataItem item = (NestedDataItem)cont.get(0);
+ _child = item;
+ }else{
+ _endCalled = true;
+ }
+ }
+
+}
Index: framework/src/test/hivemind/test/config/SchemaContent.xml
===================================================================
RCS file: framework/src/test/hivemind/test/config/SchemaContent.xml
diff -N framework/src/test/hivemind/test/config/SchemaContent.xml
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ framework/src/test/hivemind/test/config/SchemaContent.xml 9 Mar 2004 05:46:04
-0000
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<!-- $Id: Basics.xml,v 1.1 2004/03/01 01:08:02 hlship Exp $ -->
+<module id="hivemind.test.config" version="1.0.0">
+
+ <!-- schema-id,forward-refering,qualifying -->
+
+ <configuration-point id="config">
+ <schema>
+ <element name="cont">
+ <content schema-id="schema1"/>
+ </element>
+ </schema>
+ </configuration-point>
+
+ <contribution configuration-id="config">
+ <cont>
+ <config1/>
+ <config1/>
+ </cont>
+ </contribution>
+
+ <configuration-point id="config1">
+ <schema id="schema1">
+ <element name="config1">
+ <rules>
+ <create-object class="java.lang.String"/>
+ <invoke-parent method="addElement"/>
+ </rules>
+ </element>
+ </schema>
+ </configuration-point>
+
+ <contribution configuration-id="config1">
+ <config/>
+ <config/>
+ </contribution>
+
+ <!-- No schema, but method name-->
+ <configuration-point id="noschema">
+ <schema>
+ <element name="cont">
+ <content parent-method="add"/>
+ <rules>
+ <create-object class="java.util.HashSet"/>
+ <invoke-parent method="addElement"/>
+ </rules>
+ </element>
+ </schema>
+ </configuration-point>
+
+ <contribution configuration-id="noschema">
+ <cont>
+ <some/>
+ <other/>
+ </cont>
+ </contribution>
+
+
+ <!-- recursion, unqualified configuration-id -->
+ <configuration-point id="recursion">
+ <schema id="rec">
+ <element name="rec">
+ <attribute name="type" required="true"/>
+
+ <content parent-method="addContent" schema-id="rec"/>
+ <conversion class="hivemind.test.config.NestedDataItem"/>
+ </element>
+ </schema>
+ </configuration-point>
+
+ <contribution configuration-id="recursion">
+ <rec type="add">
+ <rec type="or">
+ <rec type="and">
+ <rec type="minus"/>
+ </rec>
+ </rec>
+ </rec>
+ </contribution>
+
+
+</module>
\ No newline at end of file
Index: framework/src/test/hivemind/test/config/TestContent.java
===================================================================
RCS file: framework/src/test/hivemind/test/config/TestContent.java
diff -N framework/src/test/hivemind/test/config/TestContent.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ framework/src/test/hivemind/test/config/TestContent.java 9 Mar 2004 05:46:05
-0000
@@ -0,0 +1,75 @@
+package hivemind.test.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hivemind.Element;
+import org.apache.hivemind.Registry;
+import org.apache.hivemind.service.impl.BuilderParameter;
+
+import hivemind.test.FrameworkTestCase;
+
+
+public class TestContent extends FrameworkTestCase
+{
+
+ public void testConfigSchema() throws Exception
+ {
+ Registry r = buildFrameworkRegistry("SchemaContent.xml");
+
+ List l = r.getConfiguration("hivemind.test.config.config");
+
+
+ assertEquals(1, l.size());
+
+ List lc = (List) l.get(0);
+ assertEquals(2,lc.size());
+ assertTrue(lc.get(0) instanceof String);
+
+ }
+
+ public void testNoSchema() throws Exception
+ {
+ Registry r = buildFrameworkRegistry("SchemaContent.xml");
+
+ List l = r.getConfiguration("hivemind.test.config.noschema");
+
+ assertEquals(1, l.size());
+
+ Set sc = (Set) l.get(0);
+ assertEquals(1,sc.size());
+ Object[] sar = sc.toArray();
+
+ List lc = (List) sar[0];
+ assertTrue(lc.get(0) instanceof Element);
+ Element el = (Element) lc.get(0);
+ assertEquals("some",el.getElementName());
+ el = (Element) lc.get(1);
+ assertEquals("other",el.getElementName());
+ }
+
+ public void testRecursion() throws Exception
+ {
+ Registry r = buildFrameworkRegistry("SchemaContent.xml");
+
+ List l = r.getConfiguration("hivemind.test.config.recursion");
+
+ l = new ArrayList(l);
+
+ NestedDataItem dI = (NestedDataItem) l.get(0);
+
+ assertEquals("add",dI._type);
+ dI = dI._child;
+ assertEquals("or",dI._type);
+ dI = dI._child;
+ assertEquals("and",dI._type);
+ dI = dI._child;
+ assertEquals("minus",dI._type);
+
+ assertTrue(dI._endCalled);
+
+
+ }
+
+}--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
