/******************************************************************************* * Copyright (c) 2009 MATERNA Information & Communications. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html. For further * project-related information visit http://www.ws4d.org. The most recent * version of the JMEDS framework can be obtained from * http://sourceforge.net/projects/ws4d-javame. ******************************************************************************/ package org.ws4d.java.service.parameter; import java.io.IOException; import org.ws4d.java.constants.SchemaConstants; import org.ws4d.java.constants.XOPConstants; import org.ws4d.java.schema.ComplexType; import org.ws4d.java.schema.Element; import org.ws4d.java.schema.Schema; import org.ws4d.java.schema.SchemaUtil; import org.ws4d.java.schema.Type; import org.ws4d.java.service.OperationDescription; import org.ws4d.java.service.Service; import org.ws4d.java.structures.HashMap; import org.ws4d.java.structures.Iterator; import org.ws4d.java.types.QName; import org.ws4d.java.util.Log; import org.ws4d.java.wsdl.WSDL; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; public abstract class ParameterDefinition extends ParameterValue { public abstract String serialize(); public abstract void parse(String content); public abstract void parseContent(XmlPullParser parser) throws IOException, XmlPullParserException; public abstract void serializeContent(XmlSerializer serializer) throws IOException; public int getValueType() { return TYPE_UNKNOWN; } /** * This method parses an given XML Parser object (XML instance document) * into a equivalent parameter value. * * @param parser the XML Parser. * @return the parsed parameter value. * @throws XmlPullParserException throws this exception if the parser cannot * correctly parse the XML. * @throws IOException throws this exception if the parser cannot correctly * parse the XML. */ public static ParameterValue parse(XmlPullParser parser, Element base, OperationDescription operation) throws XmlPullParserException, IOException { return parse0(parser, base, operation); } private final static ParameterValue[] parse1(XmlPullParser parser) throws XmlPullParserException, IOException { QName parsedName = new QName(parser.getName(), parser.getNamespace(), parser.getPrefix()); ParameterValue[] pv = new ParameterValue[2]; pv[0] = new ParameterValue(); pv[0].setName(parsedName); int attributeCount = parser.getAttributeCount(); if (attributeCount > 0) { for (int i = 0; i < attributeCount; i++) { QName attName = new QName(parser.getAttributeName(i), parser.getAttributeNamespace(i), parser.getAttributePrefix(i)); if (SchemaConstants.XSI_NAMESPACE.equals(attName.getNamespace()) && SchemaConstants.ATTRIBUTE_XSINIL.equals(attName.getLocalPart())) { /* * XML instance <strong>nil</code> set? This parameter can * have a nil value. */ pv[0].setNil(true); } else { ParameterAttribute attribute = new ParameterAttribute(attName); attribute.setValue(parser.getAttributeValue(i)); pv[0].add(attribute); } } } int tag = parser.getEventType(); switch (tag) { case XmlPullParser.START_DOCUMENT: tag = parser.nextTag(); break; case XmlPullParser.START_TAG: if (XOPConstants.XOP_NAMESPACE_NAME.equals(parser.getNamespace()) && XOPConstants.XOP_ELEM_INCLUDE.equals(parser.getName())) { pv[1] = load(SchemaUtil.getSchemaType(SchemaUtil.TYPE_BASE64_BINARY)); ParameterDefinition pd = (ParameterDefinition) pv[1]; pd.parseContent(parser); tag = parser.nextTag(); return pv; } else { tag = parser.next(); break; } } if (tag == XmlPullParser.TEXT) { pv[0] = load(null); ParameterDefinition pd = (ParameterDefinition) pv[0]; pd.parseContent(parser); tag = parser.nextTag(); pv[0].setName(parsedName); return pv; } int d = parser.getDepth(); while (tag != XmlPullParser.END_TAG && parser.getDepth() >= d) { ParameterValue[] child = ParameterDefinition.parse1(parser); if (child[1] != null && child[1].getValueType() == ParameterValue.TYPE_ATTACHMENT) { child[1].setName(parsedName); pv[0] = child[1]; child[1] = null; } else { pv[0].add(child[0]); } tag = parser.nextTag(); // check tag if (tag == XmlPullParser.END_TAG && parser.getDepth() == d) { // own end tag, go to next start tag tag = parser.nextTag(); } } return pv; } private final static ParameterValue parse0(XmlPullParser parser, Element base, OperationDescription operation) throws XmlPullParserException, IOException { Type t = base.getType(); Type instanceType = t; QName parsedName = new QName(parser.getName(), parser.getNamespace(), parser.getPrefix()); /* * check given element and parsed element */ if (!parsedName.equals(base.getName())) { throw new IOException("Cannot create parameter. Element mismatch. Should be " + base.getName() + ", but " + parsedName + " was found."); } boolean nil = false; HashMap attrs = null; int attributeCount = parser.getAttributeCount(); if (attributeCount > 0) { attrs = new HashMap(); for (int i = 0; i < attributeCount; i++) { String localPart = parser.getAttributeName(i); String ns = parser.getAttributeNamespace(i); QName attName = new QName(localPart, ns, parser.getAttributePrefix(i)); if (SchemaConstants.XSI_NAMESPACE.equals(ns)) { if (SchemaConstants.ATTRIBUTE_XSINIL.equals(localPart)) { /* * XML instance <strong>nil</code> set? This parameter * can have a nil value. */ nil = true; } else if (SchemaConstants.ATTRIBUTE_XSITYPE.equals(localPart)) { String xsiType = parser.getAttributeValue(i); if (xsiType != null && xsiType.trim().length() > 0) { // xsi:type support, thx to Stefan Schlichting String nsp = null; int index = xsiType.indexOf(":"); if (index >= 0) { if (index > 0) { nsp = xsiType.substring(0, index); } xsiType = xsiType.substring(index + 1); } QName qn = new QName(xsiType, parser.getNamespace(nsp)); // lookup type from operation if (operation != null) { Service service = operation.getService(); for (Iterator it = service.getDescriptions(); it.hasNext();) { WSDL wsdl = (WSDL) it.next(); Type iType = wsdl.getSchemaType(qn); if (iType != null) { instanceType = iType; break; } } } } } else { ParameterAttribute attribute = new ParameterAttribute(attName); attribute.setValue(parser.getAttributeValue(i)); attrs.put(localPart, attribute); } } else { ParameterAttribute attribute = new ParameterAttribute(attName); attribute.setValue(parser.getAttributeValue(i)); attrs.put(localPart, attribute); } } } ParameterValue pv = null; /* * Eat text or check for children. */ if (!instanceType.isComplexType()) { pv = load(instanceType); ParameterDefinition pd = (ParameterDefinition) pv; pd.parseContent(parser); } else { int tag = parser.nextTag(); int d = parser.getDepth(); pv = new ParameterValue(); ComplexType complex = (ComplexType) instanceType; while (tag != XmlPullParser.END_TAG && parser.getDepth() >= d) { QName nextStartName = new QName(parser.getName(), parser.getNamespace(), parser.getPrefix()); /* * TODO: This is a very simple parser implementation. It should * be better if we check for occurrence and container type like * ALL, SEQUENCE and CHOICE. At the moment we just check whether * the element name is possible or not. */ Element nextElement = searchElement(complex, nextStartName); ParameterValue child = null; if (nextElement == null) { if (complex.getName() != null && complex.getName().equals(new QName(SchemaUtil.TYPE_ANYTYPE, SchemaConstants.XMLSCHEMA_NAMESPACE))) { /* * is ANY type */ /* * TODO 13.05.2011: We should create a schema repository * ... the definition for the searched type can be part * of any schema we ever used within a service. */ Schema s = base.getParentSchema(); if (s != null) { /* * search inside linked schema */ nextElement = s.getElement(nextStartName); child = parse0(parser, nextElement, operation); if (nextElement == null) { parseAnyChild(parser, parsedName, nextStartName); } } else { child = parseAnyChild(parser, parsedName, nextStartName); } } else { /* * maybe ANY type?! */ child = parseAnyChild(parser, parsedName, nextStartName); // throw new IOException("Element " + nextStartName + // " is not allowed as child of " + parsedName + "."); } } else { child = parse0(parser, nextElement, operation); } pv.add(child); tag = parser.nextTag(); // check tag if (tag == XmlPullParser.END_TAG && parser.getDepth() == d) { // own end tag, go to next start tag tag = parser.nextTag(); } } } if (attrs != null) { pv.attributes = attrs; pv.setNil(nil); } pv.setMaxOccurs(base.getMaxOccurs()); pv.setMinOccurs(base.getMinOccurs()); pv.setName(parsedName); pv.setType(t); pv.setInstanceType(instanceType == t ? null : instanceType); return pv; } private static final ParameterValue parseAnyChild(XmlPullParser parser, QName parsedName, QName nextStartName) throws XmlPullParserException, IOException { if (Log.isDebug()) { Log.debug("Cannot determinate element with name " + nextStartName + ". Assuming ANY type.", Log.DEBUG_LAYER_FRAMEWORK); } ParameterValue child = null; ParameterValue[] pvv = parse1(parser); if (pvv[1] != null && pvv[1].getValueType() == ParameterValue.TYPE_ATTACHMENT) { pvv[1].setName(parsedName); child = pvv[1]; pvv[1] = null; } else { child = pvv[0]; } child = pvv[0]; return child; } protected synchronized void serialize0(XmlSerializer serializer, HashMap nsCache) throws IOException { if (nsCache == null) { namespaceCache = collectNamespaces(serializer); nsCache = namespaceCache; } serializeStartTag(serializer, nsCache); serializeAttributes(serializer); if (hasChildren()) { serializeChildren(serializer, nsCache); } else { serializeContent(serializer); } serializeEndTag(serializer); } public String toString() { StringBuffer sBuf = new StringBuffer(); sBuf.append("PV [ name="); sBuf.append(name); String value = serialize(); if (value != null) { sBuf.append(", value="); sBuf.append(value); } if (attributes.size() > 0) { sBuf.append(", attributes="); sBuf.append("("); for (Iterator it = attributes(); it.hasNext();) { ParameterAttribute pa = (ParameterAttribute) it.next(); sBuf.append(pa.toString()); if (it.hasNext()) { sBuf.append(", "); } } sBuf.append(")"); } if (children.size() > 0) { sBuf.append(", children="); sBuf.append("("); for (Iterator it = children(); it.hasNext();) { ParameterValue pv = (ParameterValue) it.next(); sBuf.append(pv.toString()); if (it.hasNext()) { sBuf.append(", "); } } sBuf.append(")"); } sBuf.append(", min="); sBuf.append(min); sBuf.append(", max="); sBuf.append(max); sBuf.append(" ]"); return sBuf.toString(); } }