You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by gd...@apache.org on 2001/05/07 21:56:41 UTC
cvs commit: xml-axis/java/src/org/apache/axis/message MessageElement.java RPCParam.java SOAPEnvelope.java SOAPSAXHandler.java
gdaniels 01/05/07 12:56:40
Modified: java/src/org/apache/axis/encoding SerializationContext.java
TypeMappingRegistry.java
java/src/org/apache/axis/message MessageElement.java
RPCParam.java SOAPEnvelope.java SOAPSAXHandler.java
Log:
Some improvements to ID/HREF serialization.
Enable multi-ref outputs, triggered by the "doMultiRefs"
swtich in the SerializationContext. If this is on, all non-basic
(i.e. non-string non-number) Objects will be written as hrefs,
and the actual serializations will happen at the end of the
body element.
Move the type handling and basic deserialization knowledge
up from RPCParam into MessageElement.
Revision Changes Path
1.10 +93 -1 xml-axis/java/src/org/apache/axis/encoding/SerializationContext.java
Index: SerializationContext.java
===================================================================
RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/SerializationContext.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- SerializationContext.java 2001/05/06 21:00:48 1.9
+++ SerializationContext.java 2001/05/07 19:56:14 1.10
@@ -88,6 +88,32 @@
private MessageContext msgContext;
+ /**
+ * Should I write out objects as multi-refs?
+ *
+ * !!! For now, this is an all-or-nothing flag. Either ALL objects will
+ * be written in-place as hrefs with the full serialization at the end
+ * of the body, or we'll write everything inline (potentially repeating
+ * serializations of identical objects).
+ */
+ private boolean doMultiRefs = false;
+
+ /**
+ * A place to hold objects we cache for multi-ref serialization, and
+ * remember the IDs we assigned them.
+ */
+ private Hashtable multiRefValues = null;
+ private int multiRefIndex = -1;
+
+ /**
+ * These two let us deal with multi-level object graphs for multi-ref
+ * serialization. Each time around the serialization loop, we'll fill
+ * in any new objects into the secondLevelObjects vector, and then write
+ * those out the same way the next time around.
+ */
+ private Object currentSer = null;
+ private Vector secondLevelObjects = null;
+
public SerializationContext(Writer writer, MessageContext msgContext)
{
this.writer = writer;
@@ -134,7 +160,6 @@
/*if ((pendingNSMappings.get(uri) != null) ||
(nsStack.getPrefix(uri) != null))
return;*/
-
pendingNSMappings.put(uri, prefix);
}
}
@@ -154,7 +179,74 @@
public void serialize(QName qName, Attributes attributes, Object value)
throws IOException
{
+ if (value == null)
+ return;
+
+ if (doMultiRefs && (value != currentSer) &&
+ !(value.getClass().equals(String.class)) &&
+ !(value instanceof Number)) {
+ if (multiRefIndex == -1)
+ multiRefValues = new Hashtable();
+
+ String href = (String)multiRefValues.get(value);
+ if (href == null) {
+ multiRefIndex++;
+ href = "id" + multiRefIndex;
+ multiRefValues.put(value, href);
+
+ /** Problem - if we're in the middle of writing out
+ * the multi-refs and hit another level of the
+ * object graph, we need to make sure this object
+ * will get written. For now, add it to a list
+ * which we'll check each time we're done with
+ * outputMultiRefs().
+ */
+ if (currentSer != null) {
+ if (secondLevelObjects == null)
+ secondLevelObjects = new Vector();
+ secondLevelObjects.addElement(value);
+ }
+ }
+
+ AttributesImpl attrs = new AttributesImpl();
+ if (attributes != null)
+ attrs.setAttributes(attributes);
+ attrs.addAttribute("", Constants.ATTR_HREF, "href",
+ "CDATA", "#" + href);
+
+ startElement(qName, attrs);
+ endElement();
+ return;
+ }
+
getTypeMappingRegistry().serialize(qName, attributes, value, this);
+ }
+
+ public void outputMultiRefs() throws IOException
+ {
+ if (!doMultiRefs || (multiRefValues == null))
+ return;
+
+ AttributesImpl attrs = new AttributesImpl();
+ attrs.addAttribute("","","","","");
+
+ Enumeration e = multiRefValues.keys();
+ while (e.hasMoreElements()) {
+ while (e.hasMoreElements()) {
+ Object val = e.nextElement();
+ String id = (String)multiRefValues.get(val);
+ attrs.setAttribute(0, "", Constants.ATTR_ID, "id", "CDATA",
+ id);
+ currentSer = val;
+ serialize(new QName("","multiRef"), attrs, val);
+ }
+
+ if (secondLevelObjects != null) {
+ e = secondLevelObjects.elements();
+ secondLevelObjects = null;
+ }
+ }
+ currentSer = null;
}
public void startElement(QName qName, Attributes attributes)
1.8 +21 -0 xml-axis/java/src/org/apache/axis/encoding/TypeMappingRegistry.java
Index: TypeMappingRegistry.java
===================================================================
RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/TypeMappingRegistry.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- TypeMappingRegistry.java 2001/05/05 13:47:12 1.7
+++ TypeMappingRegistry.java 2001/05/07 19:56:17 1.8
@@ -56,12 +56,14 @@
package org.apache.axis.encoding;
import java.util.Hashtable;
+import org.apache.axis.Constants;
import org.apache.axis.utils.*;
import org.apache.axis.utils.events.*;
import org.apache.axis.message.*;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.xml.sax.*;
+import org.xml.sax.helpers.AttributesImpl;
import java.io.*;
/**
@@ -188,6 +190,23 @@
load(fis);
}
+ public Attributes setTypeAttribute(Attributes attributes, QName type,
+ SerializationContext context)
+ {
+ if ((attributes != null) &&
+ (attributes.getIndex(Constants.URI_CURRENT_SCHEMA_XSI,
+ "type") != -1))
+ return attributes;
+
+ AttributesImpl attrs = new AttributesImpl();
+ if (attributes != null)
+ attrs.setAttributes(attributes);
+
+ attrs.addAttribute(Constants.URI_CURRENT_SCHEMA_XSI, "type",
+ "xsi:type", "CDATA", context.qName2String(type));
+ return attrs;
+ }
+
public void serialize(QName name, Attributes attributes,
Object value, SerializationContext context)
throws IOException
@@ -196,6 +215,8 @@
Class _class = value.getClass();
Serializer ser = getSerializer(_class);
if (ser != null) {
+ QName type = getTypeQName(_class);
+ attributes = setTypeAttribute(attributes, type, context);
ser.serialize(name, attributes, value, context);
} else {
throw new IOException("No serializer found for class " + _class.getName());
1.17 +112 -3 xml-axis/java/src/org/apache/axis/message/MessageElement.java
Index: MessageElement.java
===================================================================
RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/message/MessageElement.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- MessageElement.java 2001/05/05 22:16:58 1.16
+++ MessageElement.java 2001/05/07 19:56:29 1.17
@@ -87,6 +87,8 @@
protected String stringRep = null;
protected ElementRecorder recorder = null;
+ protected DeserializerBase deserializer = null;
+ protected boolean deserializing = true;
/** No-arg constructor for building messages?
*/
@@ -110,6 +112,8 @@
if (attributes == null) {
this.attributes = new AttributesImpl();
} else {
+ typeQName = context.getTypeFromAttributes(attributes);
+
this.attributes = new AttributesImpl(attributes);
String rootVal = attributes.getValue(Constants.URI_SOAP_ENV, Constants.ATTR_ROOT);
// !!! This currently defaults to false... should it default to true?
@@ -153,13 +157,118 @@
{
return null;
}
+
+ public Object getValue()
+ {
+ if (value instanceof ElementRecorder) {
+ // !!! Lazy deserialization here... We have the SAX events,
+ // but haven't run them through a deserializer yet.
+ StringWriter xml = new StringWriter();
+ try {
+ SerializationContext xmlContext = new SerializationContext(xml, context.getMessageContext());
+ ((ElementRecorder)value).outputChildren(xmlContext);
+ } catch (Exception e) {
+ if (DEBUG_LOG) e.printStackTrace();
+ return null;
+ }
+ return xml.getBuffer().toString();
+ }
+
+ if (deserializer != null) {
+ value = deserializer.getValue();
+ deserializer = null;
+ }
+
+ return value;
+ }
+ public void startElement(String namespace, String localName,
+ String qName, Attributes attributes)
+ throws SAXException
+ {
+ if (DEBUG_LOG) {
+ System.err.println("Start element in MessageElement.");
+ }
+
+ if (typeQName == null)
+ typeQName = context.getTypeFromAttributes(attributes);
+
+ // !!! This check might not be complete; in the case of
+ // a multi-ref, we might need to check BOTH the name
+ // of the element with the href AND the referenced
+ // one. Right now this will just check the referenced one.
+ if (typeQName == null) {
+ QName myQName = new QName(namespace, localName);
+ if (myQName.equals(SOAPTypeMappingRegistry.SOAP_ARRAY)) {
+ typeQName = SOAPTypeMappingRegistry.SOAP_ARRAY;
+ } else if (myQName.equals(SOAPTypeMappingRegistry.SOAP_INT)) {
+ typeQName = SOAPTypeMappingRegistry.XSD_INT;
+ } else if (myQName.equals(SOAPTypeMappingRegistry.SOAP_BOOLEAN)) {
+ typeQName = SOAPTypeMappingRegistry.XSD_BOOLEAN;
+ } else if (myQName.equals(SOAPTypeMappingRegistry.SOAP_SHORT)) {
+ typeQName = SOAPTypeMappingRegistry.XSD_SHORT;
+ }
+ }
+
+ if (typeQName == null) {
+ // No type inline, so check service description.
+ ServiceDescription serviceDesc = context.getServiceDescription();
+ if (serviceDesc != null) {
+ setType(serviceDesc.getParamTypeByName(getEnvelope().getMessageType(),
+ name));
+ }
+ }
+
+ /** !!! If we have a service description and this is an
+ * explicitly-typed param, we might want to check here to
+ * see if the xsi:type val is indeed a subtype of the type
+ * we expect from the service description.
+ */
+
+ DeserializerBase dSer = getContentHandler();
+
+ context.getSAXHandler().replaceElementHandler(dSer);
+
+ if (dSer != this)
+ dSer.startElement(namespace,localName,qName,attributes);
+ }
+
public DeserializerBase getContentHandler()
{
- if (recorder == null)
- recorder = new ElementRecorder();
+ if (deserializing) {
+ // Look up type and return an appropriate deserializer
+ if ((typeQName != null) && (deserializer == null)) {
+ deserializer = context.getDeserializer(typeQName);
+ if (DEBUG_LOG) {
+ System.err.println(typeQName + " maps to " + deserializer);
+ }
+ }
+
+ if (deserializer != null) {
+ return deserializer;
+ }
+ }
+
+ /** !!! Is it possible that we'll do this now, but
+ * later on we'll figure out the type (via some OOB
+ * means)? In that case we want an easy way to
+ * squirt these SAX events to a deserializer.
+ */
+ if (DEBUG_LOG) {
+ System.err.println("Creating recorder for " + this.getName());
+ }
+ value = new ElementRecorder();
+ recorder = (ElementRecorder)value;
+ return (ElementRecorder)value;
+ }
+
+ public void setContentHandler(DeserializerBase handler)
+ {
+ if (deserializer != null) {
+ System.err.println("Non-null deser while setting content handler?");
+ }
- return recorder;
+ deserializer = handler;
}
public void publishToHandler(ContentHandler handler) throws SAXException
1.17 +1 -100 xml-axis/java/src/org/apache/axis/message/RPCParam.java
Index: RPCParam.java
===================================================================
RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/message/RPCParam.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- RPCParam.java 2001/05/06 16:08:17 1.16
+++ RPCParam.java 2001/05/07 19:56:31 1.17
@@ -71,7 +71,6 @@
public class RPCParam extends MessageElement
{
private static boolean DEBUG_LOG = false;
- private DeserializerBase deserializer = null;
// Who's your daddy?
RPCElement myRPCElement;
@@ -117,105 +116,7 @@
return super.getEnvelope();
}
- public void startElement(String namespace, String localName,
- String qName, Attributes attributes)
- throws SAXException
- {
- if (DEBUG_LOG) {
- System.err.println("Start element in RPCParam.");
- }
- typeQName = context.getTypeFromAttributes(attributes);
-
- // !!! This check might not be complete; in the case of
- // a multi-ref, we might need to check BOTH the name
- // of the element with the href AND the referenced
- // one. Right now this will just check the referenced one.
- if (typeQName == null) {
- QName myQName = new QName(namespace, localName);
- if (myQName.equals(SOAPTypeMappingRegistry.SOAP_ARRAY)) {
- typeQName = SOAPTypeMappingRegistry.SOAP_ARRAY;
- } else if (myQName.equals(SOAPTypeMappingRegistry.SOAP_INT)) {
- typeQName = SOAPTypeMappingRegistry.XSD_INT;
- } else if (myQName.equals(SOAPTypeMappingRegistry.SOAP_BOOLEAN)) {
- typeQName = SOAPTypeMappingRegistry.XSD_BOOLEAN;
- } else if (myQName.equals(SOAPTypeMappingRegistry.SOAP_SHORT)) {
- typeQName = SOAPTypeMappingRegistry.XSD_SHORT;
- }
- }
-
- if (typeQName == null) {
- // No type inline, so check service description.
- ServiceDescription serviceDesc = context.getServiceDescription();
- if (serviceDesc != null) {
- setType(serviceDesc.getParamTypeByName(getEnvelope().getMessageType(),
- name));
- }
- }
-
- /** !!! If we have a service description and this is an
- * explicitly-typed param, we might want to check here to
- * see if the xsi:type val is indeed a subtype of the type
- * we expect from the service description.
- */
-
- DeserializerBase dSer = getContentHandler(context);
-
- context.getSAXHandler().replaceElementHandler(dSer);
-
- dSer.startElement(namespace,localName,qName,attributes);
- }
-
- public DeserializerBase getContentHandler(DeserializationContext context)
- {
- // Look up type and return an appropriate deserializer
- if (typeQName != null) {
- deserializer = context.getDeserializer(typeQName);
- if (DEBUG_LOG) {
- System.err.println(typeQName + " maps to " + deserializer);
- }
- if (deserializer != null) {
- return deserializer;
- }
- }
-
- // If we couldn't find one, just record...
-
- /** !!! Is it possible that we'll do this now, but
- * later on we'll figure out the type (via some OOB
- * means)? In that case we want an easy way to
- * squirt these SAX events to a deserializer.
- */
- if (DEBUG_LOG) {
- System.err.println("Creating recorder for " + this.getName());
- }
- value = new ElementRecorder();
- return (ElementRecorder)value;
- }
-
- public Object getValue()
- {
- if (value instanceof ElementRecorder) {
- // !!! Lazy deserialization here... We have the SAX events,
- // but haven't run them through a deserializer yet.
- StringWriter xml = new StringWriter();
- try {
- SerializationContext xmlContext = new SerializationContext(xml, context.getMessageContext());
- ((ElementRecorder)value).outputChildren(xmlContext);
- } catch (Exception e) {
- if (DEBUG_LOG) e.printStackTrace();
- return null;
- }
- return xml.getBuffer().toString();
- }
-
- if (deserializer != null) {
- value = deserializer.getValue();
- deserializer = null;
- }
-
- return value;
- }
-
+
public void output(SerializationContext context) throws IOException
{
AttributesImpl attrs;
1.24 +3 -0 xml-axis/java/src/org/apache/axis/message/SOAPEnvelope.java
Index: SOAPEnvelope.java
===================================================================
RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/message/SOAPEnvelope.java,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- SOAPEnvelope.java 2001/05/06 15:57:20 1.23
+++ SOAPEnvelope.java 2001/05/07 19:56:32 1.24
@@ -325,6 +325,9 @@
// Output this body element.
}
+ // Output multi-refs
+ context.outputMultiRefs();
+
// Output </SOAP-ENV:Body>
context.endElement();
1.11 +6 -4 xml-axis/java/src/org/apache/axis/message/SOAPSAXHandler.java
Index: SOAPSAXHandler.java
===================================================================
RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/message/SOAPSAXHandler.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- SOAPSAXHandler.java 2001/05/06 15:57:20 1.10
+++ SOAPSAXHandler.java 2001/05/07 19:56:34 1.11
@@ -421,7 +421,6 @@
if (rec instanceof ElementRecorder) {
((ElementRecorder)rec).publishToHandler(context.getSAXHandler());
} else {
- System.out.println("Setting value to " + rec.getValue());
elementHandler.setValue(rec.getValue());
}
@@ -575,9 +574,12 @@
handler = context.getHandlerForID(element.getID());
if (handler == null) {
handler = element.getContentHandler();
- } /* else {
- System.out.println("found it " + handler);
- } */
+ } else {
+ if (DEBUG_LOG) {
+ System.out.println("found handler for ID " + element.getID() + " : " + handler);
+ }
+ element.setContentHandler(handler);
+ }
} else {
handler = element.getContentHandler();
}