These changes fix a critical bug (12347) and also introduce support for Java2WSDL --style WRAPPED.
Please vote whether these changes should be incorporated into Axis 1.0. Rich Scheuerle IBM WebSphere & Axis Web Services Development 512-838-5115 (IBM TL 678-5115) [EMAIL PROTECTED] To: [EMAIL PROTECTED] 09/26/2002 03:32 cc: PM Subject: cvs commit: xml-axis/java/tools/org/apache/axis/tools/ant/wsdl Please respond to Java2WsdlAntTask.java axis-dev scheu 2002/09/26 13:32:55 Modified: java/docs reference.html java/src/org/apache/axis/i18n resource.properties java/src/org/apache/axis/providers/java JavaProvider.java java/src/org/apache/axis/wsdl Java2WSDL.java java/src/org/apache/axis/wsdl/fromJava Emitter.java Types.java java/tools/org/apache/axis/tools/ant/wsdl Java2WsdlAntTask.java Log: Summary of problem(s): 1) Java2WSDL --style DOCUMENT does not work properly. (bug 12347) a) types should be emitted in the types section (currently no types or elements are emitted.) b) the part element attributes are incorrect. c) the code should use the part type attribute for simple types, and use the part element attribute for all other situations. 2) Java2WSDL does not have a --style WRAPPED a) This option would be turned on for ?WSDL generation if the service style is wrapped. b) In this mode, element types are created which wrap the parameter types (and output types). c) In this mode, the message would have one part (body) that references the wrapper element type using the element attribute. d) the name of the element type for a request is the same as the operation name. ------------------- Summary of changes: a) Types class improved to have more descriptive methods writeTypeForPart, writeElementForPart, and writeWrapperForPart. These replace the existing (buggy) writePartType method. b) Other minor simplification improvements to the Types class. c) Emitter class changed to recognize three styles STYLE_DOCUMENT, STYLE_RPC, and STYLE_DOC_WRAPPED. (used to have MODE_DOCUMENT and MODE_RPC). d) Changed all callers to the emitter to appropriately set the style (Java2WSDL, Java2WSDLAntTask, JavaProvider). e) Changed the emitter to implement (1) and (2). Provided ample comments. Logic is actually easier to follow now! Revision Changes Path 1.10 +9 -0 xml-axis/java/docs/reference.html Index: reference.html =================================================================== RCS file: /home/cvs/xml-axis/java/docs/reference.html,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- reference.html 4 Sep 2002 22:47:03 -0000 1.9 +++ reference.html 26 Sep 2002 20:32:55 -0000 1.10 @@ -322,6 +322,10 @@ <argument></font></tt> <br> <tt><font color="#993366"> space or comma separated list of methods not to export</font></tt> <br> + <tt><font color="#993366"> -y, --style + <argument></font></tt> <br> + <tt><font color="#993366"> + the style of the wsdl document: RPC, DOCUMENT or WRAPPED</font></tt> <br> <tt><font color="#993366"> -c, --stopClasses <argument></font></tt> <br> <tt><font color="#993366"> @@ -416,6 +420,11 @@ (No longer used.) <p><b>-x, --exclude <list></b> <br> List of methods to not exclude from the wsdl file. +<p><b>-y, --style <argument></b> <br> + The style of the WSDL document: RPC, DOCUMENT or WRAPPED. + If RPC, a rpc/encoded wsdl is generated. + If DOCUMENT, a document/literal wsdl is generated. + If WRAPPED, a document/literal wsdl is generated using the wrapped approach. <p><b>-c, --stopClasses <list></b> <br> List of classes which stop the Java2WSDL inheritance search. <p><b>-T, --typeMappingVersion <version></b> <br> 1.9 +2 -2 xml-axis/java/src/org/apache/axis/i18n/resource.properties Index: resource.properties =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/i18n/resource.properties,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- resource.properties 25 Sep 2002 16:54:24 -0000 1.8 +++ resource.properties 26 Sep 2002 20:32:55 -0000 1.9 @@ -910,8 +910,8 @@ generating=Generating {0} -j2woptStyle00=The style of binding in the WSDL, either DOCUMENT or RPC. -j2woptBadStyle00=The value of --style must be DOCUMENT or RPC. +j2woptStyle00=The style of binding in the WSDL, either DOCUMENT, RPC, or WRAPPED. +j2woptBadStyle00=The value of --style must be DOCUMENT, RPC, or WRAPPED. noClassForService00=Could not find class for the service named: {0}\nHint: you may need to copy your class files/tree into the right location (which depends on the servlet system you are using). j2wDuplicateClass00=The <class-of-portType> has already been specified as, {0}. It cannot be specified again as {1}. 1.84 +8 -3 xml-axis/java/src/org/apache/axis/providers/java/JavaProvider.java Index: JavaProvider.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/providers/java/JavaProvider.java,v retrieving revision 1.83 retrieving revision 1.84 diff -u -r1.83 -r1.84 --- JavaProvider.java 26 Sep 2002 16:43:55 -0000 1.83 +++ JavaProvider.java 26 Sep 2002 20:32:55 -0000 1.84 @@ -374,9 +374,14 @@ String alias = (String)service.getOption("alias"); if(alias != null) emitter.setServiceElementName(alias); - emitter.setMode( (service.getStyle() == Style.RPC) - ? Emitter.MODE_RPC - : Emitter.MODE_DOCUMENT); + Style style = serviceDesc.getStyle(); + if (style == Style.RPC) { + emitter.setMode(Emitter.STYLE_RPC); + } else if (style == Style.DOCUMENT) { + emitter.setMode(Emitter.STYLE_DOCUMENT); + } else if (style == Style.WRAPPED) { + emitter.setMode(Emitter.STYLE_DOC_WRAPPED); + } emitter.setClsSmart(serviceDesc.getImplClass(), locationUrl); 1.27 +4 -2 xml-axis/java/src/org/apache/axis/wsdl/Java2WSDL.java Index: Java2WSDL.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/Java2WSDL.java,v retrieving revision 1.26 retrieving revision 1.27 diff -u -r1.26 -r1.27 --- Java2WSDL.java 18 Sep 2002 16:10:40 -0000 1.26 +++ Java2WSDL.java 26 Sep 2002 20:32:55 -0000 1.27 @@ -377,9 +377,11 @@ case STYLE_OPT: value = option.getArgument(); if (value.equalsIgnoreCase("DOCUMENT")) { - emitter.setMode(Emitter.MODE_DOCUMENT); + emitter.setMode(Emitter.STYLE_DOCUMENT); } else if (value.equalsIgnoreCase("RPC")) { - emitter.setMode(Emitter.MODE_RPC); + emitter.setMode(Emitter.STYLE_RPC); + } else if (value.equalsIgnoreCase("WRAPPED")) { + emitter.setMode(Emitter.STYLE_DOC_WRAPPED); } else { System.out.println(Messages.getMessage("j2woptBadStyle00")); } 1.62 +86 -26 xml-axis/java/src/org/apache/axis/wsdl/fromJava/Emitter.java Index: Emitter.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/fromJava/Emitter.java,v retrieving revision 1.61 retrieving revision 1.62 diff -u -r1.61 -r1.62 --- Emitter.java 29 Aug 2002 20:05:51 -0000 1.61 +++ Emitter.java 26 Sep 2002 20:32:55 -0000 1.62 @@ -121,13 +121,15 @@ * @author Rich Scheuerle ([EMAIL PROTECTED]) */ public class Emitter { - + // Generated WSDL Modes public static final int MODE_ALL = 0; public static final int MODE_INTERFACE = 1; public static final int MODE_IMPLEMENTATION = 2; - public static final int MODE_RPC = 0; - public static final int MODE_DOCUMENT = 1; + // Style Modes + public static final int STYLE_RPC = 0; + public static final int STYLE_DOCUMENT = 1; + public static final int STYLE_DOC_WRAPPED = 2; private Class cls; private Class implCls; // Optional implementation class @@ -144,7 +146,7 @@ private String serviceElementName; private String targetService = null; private String description; - private int mode = MODE_RPC; + private int mode = STYLE_RPC; private TypeMapping tm = null; // Registered type mapping private TypeMapping defaultTM = null; // Default TM private Namespaces namespaces; @@ -617,7 +619,7 @@ binding.setQName(bindingQName); SOAPBinding soapBinding = new SOAPBindingImpl(); - String modeStr = (mode == MODE_RPC) ? "rpc" : "document"; + String modeStr = (mode == STYLE_RPC) ? "rpc" : "document"; soapBinding.setStyle(modeStr); soapBinding.setTransportURI(Constants.URI_SOAP11_HTTP); @@ -816,8 +818,12 @@ names.add(param.getName()); } - if (names.size() > 0) + if (names.size() > 0) { + if (mode == STYLE_DOC_WRAPPED) { + names.clear(); + } oper.setParameterOrdering(names); + } } /** Create a Operation @@ -899,7 +905,7 @@ private ExtensibilityElement writeSOAPBody(QName operQName) { SOAPBody soapBody = new SOAPBodyImpl(); // for now, if its document, it is literal use. - if (mode == MODE_RPC) { + if (mode == STYLE_RPC) { soapBody.setUse("encoded"); soapBody.setEncodingStyles(encodingList); } else { @@ -1074,30 +1080,84 @@ javaType = JavaUtils.getHolderValueType(javaType); } - // Write the type representing the parameter type - QName elemQName = null; - if (mode != MODE_RPC) - elemQName = param.getQName(); - if (mode == MODE_RPC) { - QName typeQName = types.writePartType(javaType, - param.getTypeQName()); + switch(mode) { + case STYLE_RPC: { + // Add the type representing the param + // For convenience, add an element for the param + // Write <part name=param_name type=param_type> + QName typeQName = + types.writeTypeForPart(javaType, + param.getTypeQName()); + QName elemQName = + types.writeElementForPart(javaType, + param.getTypeQName()); if (typeQName != null) { + part.setName(param.getName()); part.setTypeName(typeQName); + msg.addPart(part); + } + break; + } + case STYLE_DOCUMENT: { + // Write the type representing the param. + // Write the element representing the param + // If an element was written + // Write <part name=param_name element=param_element> + // Else its a simple type, + // Write <part name=param_name type=param_type> + QName typeQName = + types.writeTypeForPart(javaType, + param.getTypeQName()); + QName elemQName = + types.writeElementForPart(javaType, + param.getTypeQName()); + if (elemQName != null) { + part.setName(param.getName()); + part.setElementName(elemQName); + msg.addPart(part); + } else if (typeQName != null) { part.setName(param.getName()); + part.setTypeName(typeQName); msg.addPart(part); } - } else if (elemQName != null) { - String namespaceURI = elemQName.getNamespaceURI(); - if (namespaceURI != null && !namespaceURI.equals("")) { - def.addNamespace(namespaces.getCreatePrefix(namespaceURI), - namespaceURI); - } - part.setElementName(elemQName); - part.setName(param.getName()); - msg.addPart(part); - } else { - // ?? Throw an exception here? Must have an element if not - // RPC style? + break; + } + case STYLE_DOC_WRAPPED: { + // Write type representing the param + QName typeQName = + types.writeTypeForPart(javaType, + param.getTypeQName()); + + // Get the QName of the wrapper element + QName wrapperQName = null; + if (request) { + wrapperQName = + new QName( + msg.getQName().getNamespaceURI(), + msg.getQName().getLocalPart().substring(0, + msg.getQName().getLocalPart().indexOf("Request"))); + } else { + wrapperQName = msg.getQName(); + } + + if (typeQName != null) { + // Write/Get the wrapper element + // and append a child element repesenting + // the parameter + if (types.writeWrapperForPart(wrapperQName, + param.getName(), + typeQName)) { + // If wrapper element is written + // add <part name="body" element=wrapper_elem /> + part.setName("body"); + part.setElementName(wrapperQName); + msg.addPart(part); + } + } + break; + } + default: + // ?? Throw an exception here? } return param.getName(); } 1.61 +143 -39 xml-axis/java/src/org/apache/axis/wsdl/fromJava/Types.java Index: Types.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/fromJava/Types.java,v retrieving revision 1.60 retrieving revision 1.61 diff -u -r1.60 -r1.61 --- Types.java 26 Sep 2002 19:21:27 -0000 1.60 +++ Types.java 26 Sep 2002 20:32:55 -0000 1.61 @@ -115,6 +115,7 @@ HashMap schemaTypes = null; HashMap schemaElementNames = null; HashMap schemaUniqueElementNames = null; + HashMap wrapperMap = new HashMap(); List stopClasses = null; List beanCompatErrs = new ArrayList(); @@ -216,26 +217,23 @@ if (te instanceof org.apache.axis.wsdl.symbolTable.Element) { addToElementsList(te.getQName()); } else if (te instanceof Type) { - addToTypesList(te.getQName(), - te.getQName().getLocalPart()); + addToTypesList(te.getQName()); } } } + /** - * Serialize the Class as XML schema to the document. - * Create a types node for the WSDL if one doesn't exist - * Create a schema node for the Class namespace, if one doesn't exist - * - * In case of a primitive type, no need to stream out anything, just return - * the QName of the primitive type + * Write out a type referenced by a part type attribute. * * @param type <code>Class</code> to generate the XML Schema info for + * @param qname <code>QName</code> of the type. If null, qname is + * defaulted from the class. * @return the QName of the generated Schema type, null if void */ - public QName writePartType(Class type, QName qname) throws AxisFault { + public QName writeTypeForPart(Class type, QName qname) throws AxisFault { //patch by costin to fix an NPE; commented out till we find out what the problem is //if you get NullPointerExceptions in this class, turn it on and submit some //replicable test data to the Axis team via bugzilla @@ -252,38 +250,134 @@ type = JavaUtils.getHolderValueType(type); } - if (qname == null) { + // Get the qname + if (qname == null || + (Constants.isSOAP_ENC(qname.getNamespaceURI()) && + "Array".equals(qname.getLocalPart()))) { qname = getTypeQName(type); if (qname == null) { - throw new AxisFault("Type was " + type.getName()); // FIXME! + throw new AxisFault("Clss:" + type.getName()); } } - /** - * No need to do anything if this is a simple type (i.e. in the - * xsd or soap-enc schemas already) - */ + // Make sure a types section is present + if (wsdlTypesElem == null) { + writeWsdlTypesElement(); + } + + // write the type + writeType(type, qname); + return qname; + } + + /** + * Write out an element referenced by a part element attribute. + * + * @param type <code>Class</code> to generate the XML Schema info for + * @param qname <code>QName</code> of the element. If null, qname is + * defaulted from the class. + * @return the QName of the generated Schema type, null if no element + */ + public QName writeElementForPart(Class type, QName qname) throws AxisFault { + //patch by costin to fix an NPE; commented out till we find out what the problem is + //if you get NullPointerExceptions in this class, turn it on and submit some + //replicable test data to the Axis team via bugzilla + /* + if( type==null ) { + return null; + } + */ + if (type.getName().equals("void")) { + return null; + } + + if (Holder.class.isAssignableFrom(type)) { + type = JavaUtils.getHolderValueType(type); + } + + // Get the qname + if (qname == null || + (Constants.isSOAP_ENC(qname.getNamespaceURI()) && + "Array".equals(qname.getLocalPart()))) { + qname = getTypeQName(type); + if (qname == null) { + throw new AxisFault("Class:" +type.getName()); + } + } + + // Return null it a simple type (not an element) String nsURI = qname.getNamespaceURI(); if (Constants.isSchemaXSD(nsURI) || (Constants.isSOAP_ENC(nsURI) && !"Array".equals(qname.getLocalPart()))) { - return qname; + return null; } + // Make sure a types section is present if (wsdlTypesElem == null) { writeWsdlTypesElement(); } - // If writeTypeAsElement returns null, then - // then no element was written due to problems. - // return an anytype in such situations. - qname = writeTypeAsElement(type, qname); - if (qname == null) { - qname = Constants.XSD_ANYTYPE; - } + + // Write Element + writeTypeAsElement(type, qname); return qname; } /** + * Write wrapper for part. + * + * @param wrapper <code>QName</code> of the wrapper element + * @param name is the name of an element to add to the wrapper element. + * @param type is the QName of the type of the element. + * @return true if the wrapperQName was created, false if it already exists. + */ + public boolean writeWrapperForPart(QName wrapper, String name, QName type) + throws AxisFault { + + // Make sure a types section is present + if (wsdlTypesElem == null) { + writeWsdlTypesElement(); + } + + // Write the namespace definition for the wrapper + writeTypeNamespace(wrapper); + + // See if the wrapper already exists. + Element sequence = (Element) wrapperMap.get(wrapper); + boolean isNew = (sequence == null); + + // Create a type if this is a new wrapper + if (isNew) { + // Create an <element> for the wrapper + Element wrapperElement = + docHolder.createElement("element"); + writeSchemaElement(wrapper, wrapperElement); + wrapperElement.setAttribute("name", + wrapper.getLocalPart()); + + // Create an anonymous <complexType> for the wrapper + Element complexType = docHolder.createElement("complexType"); + wrapperElement.appendChild(complexType); + + // Create a <sequence> under the complexType and save it. + sequence = docHolder.createElement("sequence"); + complexType.appendChild(sequence); + wrapperMap.put(wrapper, sequence); + + } + + // Create the child <element> and add it to the wrapper <sequence> + Element childElem = docHolder.createElement("element"); + childElem.setAttribute("name", name); + String prefix = namespaces.getCreatePrefix(type.getNamespaceURI()); + String prefixedName = prefix+":"+type.getLocalPart(); + childElem.setAttribute("type", prefixedName); + sequence.appendChild(childElem); + + return isNew; + } + + /** * Create a schema element for the given type * @param type the class type * @return the QName of the generated Element or null if no element written @@ -316,14 +410,26 @@ if (qName == null) { qName = getTypeQName(type); } - String pref = def.getPrefix(qName.getNamespaceURI()); - if (pref == null) - def.addNamespace(namespaces.getCreatePrefix(qName.getNamespaceURI()), - qName.getNamespaceURI()); + writeTypeNamespace(qName); return qName; } /** + * write out the namespace declaration. + * + * @param qName qname of the type + */ + private void writeTypeNamespace(QName qName) { + if (qName != null) { + String pref = def.getPrefix(qName.getNamespaceURI()); + if (pref == null) + def.addNamespace(namespaces.getCreatePrefix(qName.getNamespaceURI()), + qName.getNamespaceURI()); + + } + } + + /** * Return the QName of the specified javaType * @param javaType input javaType Class * @return QName @@ -558,19 +664,17 @@ componentTypeName = writeType(componentType, null) + dimString; } - String soapTypeName = qName.getLocalPart(); String prefix = namespaces.getCreatePrefix(qName.getNamespaceURI()); - String prefixedName = prefix+":"+soapTypeName; + String prefixedName = prefix+":"+qName.getLocalPart(); // If processed before, or this is a known namespace, return - if (!addToTypesList(qName, soapTypeName)) + if (!addToTypesList(qName)) return prefixedName; - if (type.isArray()) { // ComplexType representation of array Element complexType = docHolder.createElement("complexType"); writeSchemaElement(qName, complexType); - complexType.setAttribute("name", soapTypeName); + complexType.setAttribute("name", qName.getLocalPart()); Element complexContent = docHolder.createElement("complexContent"); complexType.appendChild(complexContent); @@ -818,22 +922,22 @@ * If the type already exists, just return false to indicate that the type is already * generated in a previous iteration * - * @param qName the name space of the type - * @param typeName the name of the type - * @return if the type is added returns true, else if the type is already present returns false + * @param qName of the type. + * @return if the type is added returns true, + * else if the type is already present returns false */ - private boolean addToTypesList (QName qName, String typeName) { + private boolean addToTypesList (QName qName) { boolean added = false; ArrayList types = (ArrayList)schemaTypes.get(qName.getNamespaceURI()); if (types == null) { types = new ArrayList(); - types.add(typeName); + types.add(qName.getLocalPart()); schemaTypes.put(qName.getNamespaceURI(), types); added = true; } else { - if (!types.contains(typeName)) { - types.add(typeName); + if (!types.contains(qName.getLocalPart())) { + types.add(qName.getLocalPart()); added = true; } } 1.3 +4 -2 xml-axis/java/tools/org/apache/axis/tools/ant/wsdl/Java2WsdlAntTask.java Index: Java2WsdlAntTask.java =================================================================== RCS file: /home/cvs/xml-axis/java/tools/org/apache/axis/tools/ant/wsdl/Java2WsdlAntTask.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Java2WsdlAntTask.java 5 Sep 2002 21:06:10 -0000 1.2 +++ Java2WsdlAntTask.java 26 Sep 2002 20:32:55 -0000 1.3 @@ -149,9 +149,11 @@ } if (style != null) { if (style.equalsIgnoreCase("DOCUMENT")) { - emitter.setMode(Emitter.MODE_DOCUMENT); + emitter.setMode(Emitter.STYLE_DOCUMENT); } else if (style.equalsIgnoreCase("RPC")) { - emitter.setMode(Emitter.MODE_RPC); + emitter.setMode(Emitter.STYLE_RPC); + } else if (style.equalsIgnoreCase("WRAPPED")) { + emitter.setMode(Emitter.STYLE_DOC_WRAPPED); } } if (input != null) {