[MOBY-guts] biomoby commit
Martin Senger
senger at dev.open-bio.org
Thu Feb 28 05:21:48 UTC 2008
senger
Thu Feb 28 00:21:48 EST 2008
Update of /home/repository/moby/moby-live/Java/src/main/org/biomoby/shared/parser
In directory dev.open-bio.org:/tmp/cvs-serv20124/src/main/org/biomoby/shared/parser
Modified Files:
MobyPackage.java MobyParser.java
Log Message:
* the jMoby XML message parser can accept now more specialized types of members than the ones its parent was registered with
* added junit tests for the parser
moby-live/Java/src/main/org/biomoby/shared/parser MobyPackage.java,1.7,1.8 MobyParser.java,1.7,1.8
===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/org/biomoby/shared/parser/MobyPackage.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- /home/repository/moby/moby-live/Java/src/main/org/biomoby/shared/parser/MobyPackage.java 2006/06/28 16:28:30 1.7
+++ /home/repository/moby/moby-live/Java/src/main/org/biomoby/shared/parser/MobyPackage.java 2008/02/28 05:21:48 1.8
@@ -19,6 +19,7 @@
import org.jdom.output.XMLOutputter;
import org.jdom.output.Format;
+import java.util.Map;
import java.util.Vector;
import java.util.Enumeration;
import java.io.StringReader;
@@ -78,7 +79,7 @@
*************************************************************************/
public static MobyPackage createFromXML (Object xmlData)
throws MobyException {
- return createFromXML (xmlData, null);
+ return createFromXML (xmlData, null, null);
}
/**************************************************************************
@@ -92,8 +93,43 @@
public static MobyPackage createFromXML (Object xmlData,
String lowestKnownDataType)
throws MobyException {
+ return createFromXML (xmlData, lowestKnownDataType, null);
+ }
+
+ /**************************************************************************
+ * Constructing a MobyPackage object from XML. The input XML can
+ * be given as a String, byte[], or a File. <p>
+ *
+ * Additionally, it passes to the XML parser the
+ * 'lowestKnownDataType' as a falback object (the role of a
+ * fallback object is explained in {@link MobyParser}.
+ *************************************************************************/
+ public static MobyPackage createFromXML (Object xmlData,
+ Map<String,String> lowestKnownDataTypes)
+ throws MobyException {
+ return createFromXML (xmlData, null, lowestKnownDataTypes);
+ }
+
+ /**************************************************************************
+ * Constructing a MobyPackage object from XML. The input XML can
+ * be given as a String, byte[], or a File. <p>
+ *
+ * Additionally, it passes to the XML parser the
+ * 'lowestKnownDataType' as a falback object (the role of a
+ * fallback object is explained in {@link MobyParser}.
+ *************************************************************************/
+ protected static MobyPackage createFromXML (Object xmlData,
+ String lowestKnownDataType,
+ Map<String,String> lowestKnownDataTypes)
+ throws MobyException {
- MobyParser parser = new MobyParser (lowestKnownDataType);
+ MobyParser parser = null;
+ if (lowestKnownDataTypes != null && lowestKnownDataTypes.size() > 0) {
+ parser = new MobyParser (lowestKnownDataTypes);
+ } else {
+ parser = new MobyParser (lowestKnownDataType);
+ }
+
if (xmlData instanceof byte[]) {
return parser.parse ( new ByteArrayInputStream ((byte[])xmlData) );
} else if (xmlData instanceof File) {
===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/org/biomoby/shared/parser/MobyParser.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- /home/repository/moby/moby-live/Java/src/main/org/biomoby/shared/parser/MobyParser.java 2006/02/14 15:35:26 1.7
+++ /home/repository/moby/moby-live/Java/src/main/org/biomoby/shared/parser/MobyParser.java 2008/02/28 05:21:48 1.8
@@ -22,6 +22,8 @@
import org.tulsoft.tools.xml.XMLUtils2;
import org.tulsoft.tools.xml.XMLErrorHandler;
+import org.apache.commons.lang.StringUtils;
+
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.Locator;
@@ -32,6 +34,9 @@
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.Stack;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
import java.util.HashSet;
import java.io.InputStream;
import java.io.Reader;
@@ -65,7 +70,7 @@
*
* Because also skeletons for services can be generated, it is easy to
* ensure that a service knows its "the most specialized" data type it
- * can still served, and that it passes it to the parser constructor. <p>
+ * can still serve, and that it passes it to the parser constructor. <p>
*
* If the parser finds an unknown object/tag but no substitute was
* passed in the parser constructor, it prints a warning and ignores
@@ -92,13 +97,13 @@
* the Biomoby registry. An example, I know about at the time of
* writing this, is a service <tt>MIPSBlastXMLClickableImage</tt> that
* returns object of type <tt>NCBI_Blast_XML_Gif_Map</tt> which has a
- * member object of type <tt>b64_encoded_gig</tt>. This member was
+ * member object of type <tt>b64_encoded_gif</tt>. This member was
* registered with the article name "hitGraph" but the service returns
* an article name "image". Parser spots it and stops parsing (because
* it does not know where to put this member object). However, if you
* insist that you still want to get such XML parsed, even without one
* part, you can set Java property "biomoby.parser.forgiving" to true,
- * and run ti again. <p>
+ * and run it again. <p>
*
* You can test parser by using a simple <tt>TestingMobyParser</tt>
* client. This is how to invoke it and how to get its help:
@@ -152,6 +157,9 @@
* processed by this parser are stored as constants in class {@link
* MobyTags}. <p>
*
+ * The parser is not thread-safe. Make a new instance for each parsed
+ * input. <p>
+ *
* @author <A HREF="mailto:martin.senger at gmail.com">Martin Senger</A>
* @version $Id$
*/
@@ -172,6 +180,7 @@
Locator locator;
XMLReader parser = null;
String lowestKnownDataType = null;
+ Map<String,String> lowestKnownDataTypes = new HashMap<String,String>();
/**************************************************************************
* Default constructor.
@@ -187,13 +196,24 @@
**************************************************************************/
public MobyParser (String lowestKnownDataType) {
super();
- if ("".equals (lowestKnownDataType))
+ if (StringUtils.isBlank (lowestKnownDataType))
this.lowestKnownDataType = null;
else
this.lowestKnownDataType = lowestKnownDataType;
}
/**************************************************************************
+ * Another constructor, taking more "fallback" data type names
+ * (indexed by their article names). See the full documentation at
+ * the top of this class what is "fallback" data type and when it
+ * is used.
+ **************************************************************************/
+ public MobyParser (Map<String,String> lowestKnownDataTypes) {
+ super();
+ this.lowestKnownDataTypes = lowestKnownDataTypes;
+ }
+
+ /**************************************************************************
* Parse the contents of the given file.
**************************************************************************/
public MobyPackage parse (String xmlFilename)
@@ -251,13 +271,13 @@
MOBYBOOLEAN,
MOBYDATETIME
};
- static HashSet pcdataNames = new HashSet();
+ static Set<String> pcdataNames = new HashSet<String>();
static {
for (int i = 0; i < pcdataNamesArray.length; i++) {
pcdataNames.add (pcdataNamesArray[i]);
}
}
- static HashSet pcdataNamesForPrimitives = new HashSet();
+ static Set<String> pcdataNamesForPrimitives = new HashSet<String>();
static {
for (int i = 0; i < pcdataNamesArrayForPrimitives.length; i++) {
pcdataNamesForPrimitives.add (pcdataNamesArrayForPrimitives[i]);
@@ -273,8 +293,8 @@
********************************************************************/
MapDataTypesIfc mapDataTypes; // dynamically created (org.biomoby.shared.datatypes.MapDataTypes)
- Stack objectStack; // it has elements of type Object
- Stack pcdataStack; // it has elements of type StringBuffer
+ Stack<Object> objectStack; // it has elements of type Object
+ Stack<StringBuffer> pcdataStack; // it has elements of type StringBuffer
boolean readingMobyObject; // true if inside Simple
boolean readingXrefs; // true if inside CrossReference
boolean readingProvision; // true if inside Provision[Information]
@@ -313,8 +333,8 @@
("Class '" + MAPPING_CLASS + "' was not found.\n" +
"It may indicate that you have not generated all Biomoby data types from a Biomoby registry.\n" +
"See http://www.biomoby.org/moby-live/Java/docs/Moses.html for details.\n" +
- "If you are a jMoby developer just type: ./build-dev.sh moses-datatypes.\n" +
- "Or perhaps, they just need to be compiled: ./build-dev.sh moses-compile.");
+ "If you are a jMoby developer just type: ant moses-datatypes.\n" +
+ "Or perhaps, they just need to be compiled: ant moses-compile.");
}
}
@@ -398,8 +418,8 @@
********************************************************************/
public void startDocument()
throws SAXException {
- objectStack = new Stack();
- pcdataStack = new Stack();
+ objectStack = new Stack<Object>();
+ pcdataStack = new Stack<StringBuffer>();
ignoring = 0;
}
@@ -517,23 +537,47 @@
//
try {
Class theClass = mapDataTypes.getClass (name);
+ if (theClass == null) {
- // start a substitution mode?
- if (theClass == null && ! inSubstitution) {
-
- // makes sense only for 'top-level' objects
Object obj = objectStack.peek();
+
+ // is this a 'top-level' object?
if (obj instanceof MobySimple) {
- // ...and only if we have a substitutee
- if (lowestKnownDataType != null)
+ // ...and only if we have a substitute
+ if (lowestKnownDataType != null) {
theClass = mapDataTypes.getClass (lowestKnownDataType);
+ // ...or more substitutes
+ } else {
+ String articleName = ((MobySimple)obj).getName();
+ if (articleName != null &&
+ lowestKnownDataTypes.containsKey (articleName)) {
+ theClass =
+ mapDataTypes.getClass (lowestKnownDataTypes.get (articleName));
+ }
+ }
// ...whose Class is known to us
if (theClass != null) {
inSubstitution = true;
- log.warn ("Warning: '" + name +
- "' substituted by '" + lowestKnownDataType + "'.");
+ if (log.isWarnEnabled()) {
+ log.warn ("Object '" + name +
+ "' substituted by '" +
+ theClass.getSimpleName() + "'.");
+ }
+ }
+
+ } else {
+ // no, it is a member (and an unknown one)
+ String articleName = getValue (attrs, ARTICLENAME);
+ theClass = articleName2Class (obj, articleName);
+ if (theClass != null && log.isWarnEnabled()) {
+ log.warn ("Object '" + obj.getClass().getSimpleName() +
+ "' has an unknown member '" + name +
+ "' (article name '" + articleName +
+ "'). Substituted by '" +
+ theClass.getSimpleName() +
+ "'.");
}
}
}
@@ -546,7 +590,9 @@
mobyObj.setName (getValue (attrs, ARTICLENAME));
objectStack.push (mobyObj);
} else {
- ignoring++; // or the same: ignoring = 1
+ // if we still do not have any class from this
+ // element, we ignore it - and also all its children
+ ignoring++;
if (! inSubstitution)
log.warn ("Ignoring unknown element '" + name + "'.");
}
@@ -663,44 +709,41 @@
((MobyProvisionInfo)vPeek (MobyProvisionInfo.class)).setComment (new String ((StringBuffer)obj));
}
+ } else {
//
// finally, here we deal with the real data objects
//
- } else {
- try {
- if (mapDataTypes.getClass (name) != null || inSubstitution) {
- if (inSubstitution && name.equals (lowestKnownDataType))
- inSubstitution = false;
+ // this is the just-finished MobyObject
+ MobyObject mobyObj = (MobyObject)objectStack.pop();
- MobyObject mobyObj = (MobyObject)objectStack.pop(); // this is just-finished MobyObject
+ try {
- // primitive types may have a PCDATA value
- if (pcdataNamesForPrimitives.contains (name)) {
- String value = new String ((StringBuffer)pcdataStack.pop());
- mobyObj.setValue (value);
- }
+ // primitive types may have a PCDATA value
+ if (pcdataNamesForPrimitives.contains (name)) {
+ String value = new String (pcdataStack.pop());
+ mobyObj.setValue (value);
+ }
- // put just-finished MobyObject into its container
- obj2 = objectStack.peek();
- if (obj2 instanceof MobySimple) {
- ((MobySimple)obj2).setData (mobyObj);
- } else {
- String methodName = articleName2methodName (mobyObj);
- try {
- callMethod ((MobyObject)obj2, methodName, mobyObj);
- } catch (SAXException e2) {
- // perhaps we should just ignore it here and go on... I don't know
- String msg = "Object " + name +
- ": either missing or unknown article name '" +
- mobyObj.getName() + "'.";
- log.error (msg);
- String s = System.getProperty (BIOMOBY_PARSER_FORGIVING);
- if ( s == null || new Boolean (s).booleanValue() == false )
- throw error (msg);
- }
+ // put just-finished MobyObject into its container
+ obj2 = objectStack.peek();
+ if (obj2 instanceof MobySimple) {
+ ((MobySimple)obj2).setData (mobyObj);
+ // ...and forget about (potential) substitution
+ inSubstitution = false;
+
+ } else {
+ String methodName = articleName2methodName (mobyObj);
+ try {
+ callMethod ((MobyObject)obj2, methodName, mobyObj);
+ } catch (SAXException e2) {
+ log.warn ("Object type '" + name +
+ "' in object '" + obj2.getClass().getSimpleName() +
+ "' (or in its child), with article name '" + mobyObj.getName() +
+ "', is ignored.");
}
}
+
} catch (MobyException e) {
throw error (e.getMessage());
}
@@ -781,7 +824,7 @@
// ignore white-spaces, and text where should not be any
if (pcdataStack.empty()) return;
- StringBuffer buf = (StringBuffer)pcdataStack.peek();
+ StringBuffer buf = pcdataStack.peek();
buf.append (ch, start, length);
}
@@ -827,6 +870,52 @@
}
/*********************************************************************
+ * An 'obj' should be a MobyObject instance that should have a
+ * method for setting given 'articleName'. If not return null. If
+ * yes, use reflection to find what is the return type of this
+ * method and return such class.
+ *
+ * This is used when an object has an unknown member (its type is
+ * unknown because it can be a more specialized one, but its
+ * article name is known).
+ ********************************************************************/
+ static protected Class articleName2Class (Object obj,
+ String articleName) {
+ if (! (obj instanceof MobyObject)) {
+ log.error ("Unexpected object of type '" + obj.getClass().getName() +
+ "' when a MobyObj was expected.");
+ return null;
+ }
+ if (StringUtils.isBlank (articleName)) {
+ log.error ("An unknown member found in object '" +
+ obj.getClass().getName() +
+ "' that even does not have any article name.");
+ return null;
+ }
+
+ // this is the method we are looking for
+ String methodName =
+ "getMoby_" + Utils.mobyEscape (Utils.javaEscape (articleName.trim()));
+
+ // here are all methods of the class whose member is unknown
+ for (Method method: obj.getClass().getMethods()) {
+ if (! methodName.equals (method.getName()))
+ continue;
+ Class returnType = method.getReturnType();
+ if (returnType.isArray()) {
+ return returnType.getComponentType();
+ } else {
+ return returnType;
+ }
+ }
+ log.error ("An unknown member found in object '" +
+ obj.getClass().getName() +
+ "' with unrecognized article name '" +
+ articleName + "'.");
+ return null;
+ }
+
+ /*********************************************************************
* Call a method (named 'methodName') on object 'actor', using
* 'parameter'.
********************************************************************/
More information about the MOBY-guts
mailing list