Index: src/nongnu/cashews/commons/PairList.java =================================================================== RCS file: src/nongnu/cashews/commons/PairList.java diff -N src/nongnu/cashews/commons/PairList.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nongnu/cashews/commons/PairList.java 8 May 2005 11:54:20 -0000 @@ -0,0 +1,194 @@ +/* PairList.java -- A list of heterogenous pairs. + Copyright (C) 2005 The University of Sheffield. + + This file is part of the CASheW-s editor. + + The CASheW-s editor 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, or (at your option) + any later version. + + The CASheW-s editor 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 The CASheW-s editor; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. +*/ + +package nongnu.cashews.commons; + +import java.util.LinkedList; + +/** + * A list consisting of pairs of values. + * + * @author Andrew John Hughes (address@hidden) + * @see java.util.List + */ +public class PairList + extends LinkedList> +{ + + /** + * Serialization ID. + */ + + /** + * Constructs an empty PairList. + */ + public PairList() + { + super(); + } + + /** + * Constructs a PairList using the contents of the supplied + * pair list. + * + * @param l the list whose contents are to be used as the start of the + * contents for the new list. + */ + public PairList(PairList l) + { + super(l); + } + + /** + * Returns true if the list contains the specified value. + * The value is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return true if the set contains the specified value. + */ + public boolean contains(A left, B right) + { + return super.contains(new Pair(left,right)); + } + + /** + * Adds the specified value to the list. The value + * is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return true. + */ + public boolean add(A left, B right) + { + return super.add(new Pair(left,right)); + } + + /** + * Adds the specified value to the list at the supplied index. + * Anything already at that position is shifted to the right (the + * index is incremented by one). The value is constructed as the + * pair of the two supplied values. + * + * @param index the index at which to place this pair. + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + */ + public void add(int index, A left, B right) + { + super.add(index, new Pair(left,right)); + } + + /** + * Adds the specified value to the front of this list. Anything + * already at that position is shifted to the right (the index is + * incremented by one). The value is constructed as the pair of the + * two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + */ + public void addFirst(A left, B right) + { + super.addFirst(new Pair(left,right)); + } + + /** + * Adds the specified value to the end of this list. The value is + * constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + */ + public void addLast(A left, B right) + { + super.addLast(new Pair(left,right)); + } + + /** + * Returns the index of the first occurrence of the supplied value. + * The value is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return the index of the first occurrence. + */ + public int indexOf(A left, B right) + { + return super.indexOf(new Pair(left,right)); + } + + /** + * Returns the index of the last occurrence of the supplied value. + * The value is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return the index of the last occurrence. + */ + public int lastIndexOf(A left, B right) + { + return super.lastIndexOf(new Pair(left,right)); + } + + /** + * Appends the specified value to the end of the queue. The value + * is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return true. + */ + public boolean offer(A left, B right) + { + return super.offer(new Pair(left,right)); + } + + /** + * Removes the specified value from the set. The value + * is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return true if the set contained the value. + */ + public boolean remove(A left, B right) + { + return super.remove(new Pair(left,right)); + } + + /** + * Replaces the value at the specified index with the supplied + * value. The value is constructed as the pair of the two + * supplied values. + * + * @param index the index at which to place this pair. + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return the previous value at the index. + */ + public Pair set(int index, A left, B right) + { + return super.set(index, new Pair(left,right)); + } + +} Index: src/nongnu/cashews/language/grounding/SoapOperation.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/language/grounding/SoapOperation.java,v retrieving revision 1.2 diff -u -3 -p -u -r1.2 SoapOperation.java --- src/nongnu/cashews/language/grounding/SoapOperation.java 7 May 2005 21:22:53 -0000 1.2 +++ src/nongnu/cashews/language/grounding/SoapOperation.java 8 May 2005 11:54:20 -0000 @@ -26,6 +26,7 @@ import java.net.URISyntaxException; import javax.xml.namespace.QName; +import nongnu.cashews.xml.XmlField; import nongnu.cashews.xml.Xmlizable; /** @@ -43,6 +44,18 @@ public class SoapOperation { /** + * Serialization fields which specify how to serialize this class. + */ + private static final XmlField[] serialPersistentFields + = new XmlField[] + { + new XmlField("endpoint",URI.class), + new XmlField("namespace",URI.class), + new XmlField("inputMessage",SoapMessage.class,false,true,false), + new XmlField("outputMessage",SoapMessage.class,false,true,false) + }; + + /** * The endpoint where the operation is located. * * @serial the endpoint of the operation. Index: src/nongnu/cashews/language/process/AtomicProcess.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/language/process/AtomicProcess.java,v retrieving revision 1.3 diff -u -3 -p -u -r1.3 AtomicProcess.java --- src/nongnu/cashews/language/process/AtomicProcess.java 6 May 2005 10:26:51 -0000 1.3 +++ src/nongnu/cashews/language/process/AtomicProcess.java 8 May 2005 11:54:20 -0000 @@ -26,6 +26,8 @@ import java.net.URISyntaxException; import nongnu.cashews.language.grounding.Grounding; +import nongnu.cashews.xml.XmlField; + /** * Represents a simple process with a set of inputs and outputs, * grounded in a web service. The AtomicProcess provides @@ -39,6 +41,15 @@ public class AtomicProcess { /** + * Serialization fields which specify how to serialize this class. + */ + private static final XmlField[] serialPersistentFields + = new XmlField[] + { + new XmlField("grounding",Grounding.class,false,true,true) + }; + + /** * The grounding for this AtomicProcess, which links * it to a real web service. * Index: src/nongnu/cashews/services/TypeChecker.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/services/TypeChecker.java,v retrieving revision 1.1 diff -u -3 -p -u -r1.1 TypeChecker.java --- src/nongnu/cashews/services/TypeChecker.java 4 May 2005 14:30:27 -0000 1.1 +++ src/nongnu/cashews/services/TypeChecker.java 8 May 2005 11:54:20 -0000 @@ -85,16 +85,11 @@ public class TypeChecker try { Service service = new Service(); - Call call = (Call) service.createCall(); - call.setTargetEndpointAddress( new java.net.URL(TEST_ENDPOINT) ); - call.setOperationName("typeCheckRequest"); - call.addParameter("expr", org.apache.axis.Constants.XSD_STRING, javax.xml.rpc.ParameterMode.IN); - call.setReturnType( org.apache.axis.Constants.XSD_STRING ); String result = (String) call.invoke( new Object[] { expression } ); Index: src/nongnu/cashews/xml/Serializer.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/xml/Serializer.java,v retrieving revision 1.3 diff -u -3 -p -u -r1.3 Serializer.java --- src/nongnu/cashews/xml/Serializer.java 7 May 2005 21:22:54 -0000 1.3 +++ src/nongnu/cashews/xml/Serializer.java 8 May 2005 11:54:20 -0000 @@ -21,7 +21,7 @@ package nongnu.cashews.xml; -import java.io.ObjectStreamClass; +import java.io.ObjectStreamField; import java.io.Serializable; import java.lang.reflect.Field; @@ -40,6 +40,9 @@ import static javax.xml.XMLConstants.W3C import javax.xml.namespace.QName; +import nongnu.cashews.commons.Pair; +import nongnu.cashews.commons.PairList; + import nongnu.cashews.language.grounding.MessagePart; import nongnu.cashews.language.grounding.SoapMessage; import nongnu.cashews.language.grounding.SoapOperation; @@ -107,8 +110,9 @@ public class Serializer /** * Serializes the specified object into an XML tree. If the supplied - * document argument is not null, the resulting tree - * is appended it. Otherwise, a new document is created. + * root argument is not null, the resulting tree + * is appended to it. Otherwise, the top-level element of the + * class is the root. * * @param object the object to serialize. * @param root the root node to append to, or null @@ -121,28 +125,104 @@ public class Serializer Document document) throws IllegalAccessException { - List fields = new LinkedList(); + return serialize(object, root, document, true); + } + + /** + * Serializes the specified object into an XML tree. If the supplied + * root argument is not null, the resulting tree + * is appended to it. Otherwise, the class name node is used. + * + * @param object the object to serialize. + * @param root the root node to append to, or null + * if a new root node should be created. + * @param document the document to use for creation. + * @param includeClassNameElement a flag which, when false, + * causes the root node with the name of the class to be + * suppressed. + * @return the serialized object in XML form. + * @throws IllegalAccessException if a field can't be accessed. + * @throws IllegalStateException if the root node is null and the + * class name node is suppressed. + */ + public static Element serialize(Serializable object, Element root, + Document document, + boolean includeClassNameElement) + throws IllegalAccessException + { + PairList fields = new PairList(); Class clazz = object.getClass(); - String elementName = null; Xmlizable customObject = null; - if (object instanceof Xmlizable) + Element objRoot; + if (!includeClassNameElement) { - customObject = (Xmlizable) object; - elementName = customObject.getElementName(); + if (root == null) + throw new IllegalStateException("Impossible to serialize a class "+ + "with no supplied root node or "+ + "class name root node."); + objRoot = root; + root = null; + } + else + { + String elementName = null; + if (object instanceof Xmlizable) + { + customObject = (Xmlizable) object; + elementName = customObject.getElementName(); + } + if (elementName == null) + elementName = clazz.getSimpleName(); + objRoot = createElement(document, elementName); } - if (elementName == null) - elementName = clazz.getSimpleName(); - Element objRoot = createElement(document, elementName); if (customObject != null) addNamespaceDeclarations(customObject.getDeclaredNamespaces(), objRoot); while (clazz != null) { - fields.addAll(0, Arrays.asList(clazz.getDeclaredFields())); + PairList newFields = new PairList(); + try + { + Field serialField = + clazz.getDeclaredField("serialPersistentFields"); + ObjectStreamField[] osFields = (ObjectStreamField[]) + serialField.get(null); + for (ObjectStreamField osField : osFields) + { + XmlField xField; + if (osField instanceof XmlField) + xField = (XmlField) osField; + else + xField = new XmlField(osField); + try + { + newFields.add(xField, + clazz.getDeclaredField(xField.getName())); + } + catch (NoSuchFieldException e) + { + throw new + IllegalStateException("Inconsistency between "+ + "listed and actual serializable " + + "fields in " + osField.getName() + + ".",e); + } + } + } + catch (NoSuchFieldException e) + { + Field[] clFields = clazz.getDeclaredFields(); + for (Field field : clFields) + newFields.add(new XmlField(field.getName(), + field.getType()),field); + } + fields.addAll(0,newFields); clazz = clazz.getSuperclass(); } TypeMapper mapper = new TypeMapper(); - for (Field field: fields) + for (Pair pair: fields) { + XmlField xField = pair.getLeft(); + Field field = pair.getRight(); if (Modifier.isTransient(field.getModifiers())) continue; System.out.println("field: " + field); @@ -166,7 +246,18 @@ public class Serializer serialize((Serializable) obj, objRoot, document); } else if (value instanceof Serializable) - serialize((Serializable) value, objRoot, document); + { + Element element; + if (xField.isFieldNameSerialized()) + { + element = createElement(document, field.getName()); + objRoot.appendChild(element); + } + else + element = objRoot; + serialize((Serializable) value, element, document, + xField.isClassNameSerialized()); + } else { Element element = createElement(document, field.getName()); Index: src/nongnu/cashews/xml/XmlField.java =================================================================== RCS file: src/nongnu/cashews/xml/XmlField.java diff -N src/nongnu/cashews/xml/XmlField.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nongnu/cashews/xml/XmlField.java 8 May 2005 11:54:20 -0000 @@ -0,0 +1,189 @@ +/* XmlField.java -- Represents a field serialized to XML. + Copyright (C) 2005 The University of Sheffield. + + This file is part of the CASheW-s editor. + + The CASheW-s editor 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, or (at your option) + any later version. + + The CASheW-s editor 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 The CASheW-s editor; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. +*/ + +package nongnu.cashews.xml; + +import java.io.ObjectStreamField; + +/** + * Represents a field that can be serialized to XML. XML fields + * allow the serialization process to be customised. + * + * @author Andrew John Hughes (address@hidden) + */ +public class XmlField + extends ObjectStreamField +{ + + /** + * Flag to specify whether or not the field name is serialized + * as an element. + */ + private boolean fieldElement; + + /** + * Flag to specify whether or not the class name is serialized + * as an element. + */ + private boolean classElement; + + /** + * Constructs a new XmlField with the specified field + * name and type. The flags are set to a default of a shared field + * with an element for the class name and none for the field name. + * + * @param name the name of the field. + * @param type the type of the field. + */ + public XmlField(String name, Class type) + { + this(name, type, false); + } + + /** + * Constructs a new XmlField with the specified field + * name and type. The field is either shared or unshared depending + * on the value supplied. Shared fields are written using + * writeObject and read using readObject, + * while unshared fields are read and written using + * readUnshared and writeUnshared + * respectively. The other flags are set to give the default + * serialization of an element for the class name and none for the + * field name. + * + * @param name the name of the field. + * @param type the type of the field. + * @param unshared a flag to specify whether or not this field is unshared. + */ + public XmlField(String name, Class type, boolean unshared) + { + this(name,type,unshared,false,true); + } + + /** + * Constructs a new XmlField with the specified field + * name and type. The field is either shared or unshared depending + * on the value supplied. Shared fields are written using + * writeObject and read using readObject, + * while unshared fields are read and written using + * readUnshared and writeUnshared + * respectively. If a value of true is given for + * fieldElement, then an element is included using the + * name supplied here. If a value of true is given for + * classElement, then an element is included using the + * name of the type. This only is the default. + * + * @param name the name of the field. + * @param type the type of the field. + * @param unshared a flag to specify whether or not this field is unshared. + * @param fieldElement a flag to specify whether to include an XML element + * baring the name of the field. + * @param classElement a flag to specify whether to include an XML element + * baring the name of the class. + */ + public XmlField(String name, Class type, boolean unshared, + boolean fieldElement, boolean classElement) + { + super(name,type,unshared); + setFieldElement(fieldElement); + setClassElement(classElement); + } + + /** + * Constructs a new XmlField using the contents + * of the specified ObjectStreamField. + * + * @param field the object stream field whose contents should + * be used to populate this XmlField. + */ + public XmlField(ObjectStreamField field) + { + this(field.getName(), field.getType(), field.isUnshared()); + } + + /** + * Sets the field element flag to the value supplied. If this + * is true, an XML element containing the field + * name is included. + * + * @param fieldElement the new setting of the field element flag. + */ + public void setFieldElement(boolean fieldElement) + { + this.fieldElement = fieldElement; + } + + /** + * Sets the class element flag to the value supplied. If this + * is true, an XML element containing the class + * name is included. + * + * @param classElement the new setting of the class element flag. + */ + public void setClassElement(boolean classElement) + { + this.classElement = classElement; + } + + /** + * Returns true if an XML element is included, which + * bares the name of the field. + * + * @return true if the field name is serialized. + */ + public boolean isFieldNameSerialized() + { + return fieldElement; + } + + /** + * Returns true if an XML element is included, which + * bares the name of the class of which this field is an instance. + * + * @return true if the class name is serialized. + */ + public boolean isClassNameSerialized() + { + return classElement; + } + + /** + * Returns a String representation of this XML field. + * + * @return a textual representation. + */ + public String toString() + { + return getClass().getName() + + "[name=" + + getName() + + ",type=" + + getType() + + ",unshared=" + + isUnshared() + + ",fieldElement=" + + fieldElement + + ",classElement=" + + classElement + + "]"; + } + +}