Hi,
I need a little help getting started with AXIS.
I've done some SOAP web services development a few years back using SUN JAXM, but I will be using AXIS for a webservice project in the near term.
In order to get familiar with AXIS I did the GOOGLE thing and aquired a sample WDSL to try out.
I am using 1.2RC3 version of AXIS with Tomcat 5.0.28.
Here is the WSDL I first used:
<wsdl:definitions
name="PhotoCatalogService"
targetNamespace="http://examples.com/PhotoCatalog"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:types="http://examples.com/PhotoCatalog/types"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="http://examples.com/PhotoCatalog">
<wsdl:types>
<xsd:schema targetNamespace="http://examples.com/PhotoCatalog/types"
xmlns:wsi="http://ws-i.org/profiles/basic/1.1/xsd"
xmlns:types="http://examples.com/PhotoCatalog/types">
<xsd:import namespace="http://ws-i.org/profiles/basic/1.1/xsd" schemaLocation="WS-ISwA.xsd"/>
<!-- Status contains the references the old photo available as attachment. -->
<xsd:element name="Status" type="wsi:swaRef" />
<!-- passed in as parameter of replacePhoto operation, contains the order. -->
<xsd:element name="PhotoInfo">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="customerName" type="xsd:string"/>
<xsd:element name="photoID" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="addPhotoRequest">
<wsdl:part name="oldPhoto" element="types:PhotoInfo"/>
<wsdl:part name="photo" type="xsd:hexBinary"/>
</wsdl:message>
<wsdl:message name="addPhotoResponse">
<wsdl:part name="status" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="replacePhotoRequest">
<wsdl:part name="oldPhoto" element="types:PhotoInfo"/>
<wsdl:part name="newPhoto" type="xsd:hexBinary"/>
</wsdl:message>
<wsdl:message name="replacePhotoResponse">
<wsdl:part name="status" element="types:Status"/>
</wsdl:message>
<wsdl:portType name="PhotoCatalog">
<wsdl:operation name="addPhoto">
<wsdl:input message="tns:addPhotoRequest"/>
<wsdl:output message="tns:addPhotoResponse"/>
</wsdl:operation>
<wsdl:operation name="replacePhoto">
<wsdl:input message="tns:replacePhotoRequest"/>
<wsdl:output message="tns:replacePhotoResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="PhotoCatalogBinding" type="tns:PhotoCatalog">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="addPhoto">
<wsdl:input>
<mime:multipartRelated>
<mime:part>
<soap:body parts="oldPhoto" use="literal"/>
</mime:part>
<mime:part>
<mime:content part="photo" type="image/jpeg"/>
</mime:part>
</mime:multipartRelated>
</wsdl:input>
<wsdl:output>
<mime:multipartRelated>
<mime:part>
<soap:body use="literal"/>
</mime:part>
<mime:part>
<mime:content part="status" type="text/plain"/>
<mime:content part="status" type="text/xml"/>
</mime:part>
</mime:multipartRelated>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="replacePhoto">
<wsdl:input>
<mime:multipartRelated>
<mime:part>
<soap:body parts="oldPhoto" use="literal"/>
</mime:part>
<mime:part>
<mime:content part="newPhoto" type="image/jpeg"/>
</mime:part>
</mime:multipartRelated>
</wsdl:input>
<wsdl:output>
<mime:multipartRelated>
<mime:part>
<soap:body parts="status" use="literal"/>
</mime:part>
</mime:multipartRelated>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="PhotoCatalogService">
<wsdl:port name="PhotoCatalogPort" binding="tns:PhotoCatalogBinding">
<soap:address location="http://localhost:8080/jaxrpc-AttachmentsSample/photocatalog"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
When I used the previous WSDL to generate a service and then a client I got the following error on the client side when trying the "addPhoto" service:
AxisFault
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException
faultSubcode:
faultString: org.xml.sax.SAXException: Invalid element in com.examples.PhotoCatalog.types.PhotoInfo - PhotoInfo
faultActor:
faultNode:
faultDetail:
{http://xml.apache.org/axis/}hostname:tislaptop
org.xml.sax.SAXException: Invalid element in com.examples.PhotoCatalog.types.PhotoInfo - PhotoInfo
at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:221)
at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:128)
at org.apache.axis.encoding.DeserializationContext.endElement(DeserializationContext.java:1087)
at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanEndElement(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:345)
at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
at org.apache.axis.Message.getSOAPEnvelope(Message.java:424)
at org.apache.axis.transport.http.HTTPSender.readFromSocket(HTTPSender.java:745)
at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:141)
at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)
at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)
at org.apache.axis.client.AxisClient.invoke(AxisClient.java:165)
at org.apache.axis.client.Call.invokeEngine(Call.java:2754)
at org.apache.axis.client.Call.invoke(Call.java:2737)
at org.apache.axis.client.Call.invoke(Call.java:2413)
at org.apache.axis.client.Call.invoke(Call.java:2336)
at org.apache.axis.client.Call.invoke(Call.java:1793)
at com.examples.PhotoCatalog.PhotoCatalogBindingStub.addPhoto(PhotoCatalogBindingStub.java:190)
at com.examples.PhotoCatalog.PhotoCatalogProxy.addPhoto(PhotoCatalogProxy.java:45)
at com.examples.PhotoCatalog.TestPhotoService.main(TestPhotoService.java:41)
Here is an abridged network trace of the SOAP request sent from client to server...
POST /axis/services/PhotoCatalogPort HTTP/ 1.0
Content-Type: multipart/related;type="text/xml";start="<DBB2B5537065926A4CBC8F8ED8D88F15>";boundary="----=_Part_0_20983130.1113483759295"
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent:Axis/1.2RC3
Host: xxx.xxx.xxx.xxx:8080
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 8466
------=_Part_0_209831301113483759295
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: <DBB2B5537065926A4CBC8F8ED8D88F15>
<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XML Schema-instance">
<soapenv:Body>
<addPhoto xmlns="">
<ns1:PhotoInfo xmlns:ns1="http://examples.com/PhotoCatalog/types">
<customerName>karl</customerName>
<photoID>100</photoID>
</ns1:PhotoInfo>
<photo href="" xsi:type="ns2:Image" xmlns:ns2="http://xml.apache.org/xml-soap"/>
</addPhoto>
</soapenv:Body>
</soapenv:Envelope>
------=_ Part_0_20983130.1113483759295
Content-Type:image/jpeg
Content -Transfer-Encoding:binary
Content-Id: <F2369DA809C4B1B0ADBA8538372E6F23>
...QE..QE.......
------=_Part_0_20983130.1113483759295
After a little searching I found some info that led me to change the WSDL a little. I redefined the "PhotoInfo" type as follows
<xsd:element name="PhotoInfo">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="customerName" type="xsd:string"/>
<xsd:element name="photoID" type="xsd:int"/>
<xsd:any processContents = "lax"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
Now there is no exception thrown, but the PhotoInfo and photo objects are not deserialized. I get null values passed to the PhotoCatalogBindingImpl class.
I noticed that an org.apache.axis.message.MessageElement[] object and associated methods was added to the PhotoInfo class, which I assume is due to adding the <xsd:any processContents = "lax"/> line to the WSDL.
Here is the PhotoInfo and PhotoCatalogBindingImpl class source for reference:
/**
* PhotoCatalogBindingImpl.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2RC3 Feb 28, 2005 (10:15:14 EST) WSDL2Java emitter.
*/
package com.examples.PhotoCatalog;
import javax.xml.transform.Source;
public class PhotoCatalogBindingImpl implements com.examples.PhotoCatalog.PhotoCatalog{
public javax.xml.transform.Source
addPhoto(com.examples.PhotoCatalog.types.PhotoInfo oldPhoto, java.awt.Image photo) throws java.rmi.RemoteException {
return null;
}
public org.apache.axis.types.URI replacePhoto(com.examples.PhotoCatalog.types.PhotoInfo oldPhoto, java.awt.Image newPhoto) throws java.rmi.RemoteException {
return null;
}
}
/**
* PhotoInfo.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2RC3 Feb 28, 2005 (10:15:14 EST) WSDL2Java emitter.
*/
package com.examples.PhotoCatalog.types;
public class PhotoInfo implements java.io.Serializable, org.apache.axis.encoding.AnyContentType {
private java.lang.String customerName;
private int photoID;
private org.apache.axis.message.MessageElement [] _any;
public PhotoInfo() {
}
public PhotoInfo(
org.apache.axis.message.MessageElement [] _any,
java.lang.String customerName,
int photoID) {
this.customerName = customerName;
this.photoID = photoID;
this._any = _any;
}
/**
* Gets the customerName value for this PhotoInfo.
*
* @return customerName
*/
public java.lang.String getCustomerName() {
return customerName;
}
/**
* Sets the customerName value for this PhotoInfo.
*
* @param customerName
*/
public void setCustomerName(java.lang.String customerName) {
this.customerName = customerName;
}
/**
* Gets the photoID value for this PhotoInfo.
*
* @return photoID
*/
public int getPhotoID() {
return photoID;
}
/**
* Sets the photoID value for this PhotoInfo.
*
* @param photoID
*/
public void setPhotoID(int photoID) {
this.photoID = photoID;
}
/**
* Gets the _any value for this PhotoInfo.
*
* @return _any
*/
public org.apache.axis.message.MessageElement [] get_any() {
return _any;
}
/**
* Sets the _any value for this PhotoInfo.
*
* @param _any
*/
public void set_any(org.apache.axis.message.MessageElement [] _any) {
this._any = _any;
}
private java.lang.Object __equalsCalc = null;
public synchronized boolean equals(java.lang.Object obj) {
if (!(obj instanceof PhotoInfo)) return false;
PhotoInfo other = (PhotoInfo) obj;
if (obj == null) return false;
if (this == obj) return true;
if (__equalsCalc != null) {
return (__equalsCalc == obj);
}
__equalsCalc = obj;
boolean _equals;
_equals = true &&
((this.customerName==null && other.getCustomerName()==null) ||
(this.customerName!=null &&
this.customerName.equals(other.getCustomerName()))) &&
this.photoID == other.getPhotoID() &&
((this._any==null && other.get_any()==null) ||
(this._any!=null &&
java.util.Arrays.equals(this._any, other.get_any())));
__equalsCalc = null;
return _equals;
}
private boolean __hashCodeCalc = false;
public synchronized int hashCode() {
if (__hashCodeCalc) {
return 0;
}
__hashCodeCalc = true;
int _hashCode = 1;
if (getCustomerName() != null) {
_hashCode += getCustomerName().hashCode();
}
_hashCode += getPhotoID();
if (get_any() != null) {
for (int i=0;
i<java.lang.reflect.Array.getLength(get_any());
i++) {
java.lang.Object obj = java.lang.reflect.Array.get(get_any(), i);
if (obj != null &&
!obj.getClass().isArray()) {
_hashCode += obj.hashCode();
}
}
}
__hashCodeCalc = false;
return _hashCode;
}
// Type metadata
private static org.apache.axis.description.TypeDesc typeDesc =
new org.apache.axis.description.TypeDesc(PhotoInfo.class, true);
static {
typeDesc.setXmlType(new javax.xml.namespace.QName("http://examples.com/PhotoCatalog/types", ">PhotoInfo"));
org.apache.axis.description.ElementDesc elemField = new org.apache.axis.description.ElementDesc();
elemField.setFieldName("customerName");
elemField.setXmlName(new javax.xml.namespace.QName("", "customerName"));
elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"));
typeDesc.addFieldDesc(elemField);
elemField = new org.apache.axis.description.ElementDesc();
elemField.setFieldName("photoID");
elemField.setXmlName(new javax.xml.namespace.QName("", "photoID"));
elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "int"));
typeDesc.addFieldDesc(elemField);
}
/**
* Return type metadata object
*/
public static org.apache.axis.description.TypeDesc getTypeDesc() {
return typeDesc;
}
/**
* Get Custom Serializer
*/
public static org.apache.axis.encoding.Serializer getSerializer(
java.lang.String mechType,
java.lang.Class _javaType,
javax.xml.namespace.QName _xmlType) {
return
new org.apache.axis.encoding.ser.BeanSerializer(
_javaType, _xmlType, typeDesc);
}
/**
* Get Custom Deserializer
*/
public static org.apache.axis.encoding.Deserializer getDeserializer(
java.lang.String mechType,
java.lang.Class _javaType,
javax.xml.namespace.QName _xmlType) {
return
new org.apache.axis.encoding.ser.BeanDeserializer(
_javaType, _xmlType, typeDesc);
}
}
I guess my questions are as follows:
1. Why is exception thrown in the first scenario? Is there something wrong with the WSDL? I guess there is, but I can't figure it out.
2. When the change is made to the WDSL(adding <xsd:any processContents = "lax"/>) is there something that I need to add to the PhotoInfo class
to process the org.apache.axis.message.MessageElement[] object. Do I need to "manually" parse that object in the PhotoCatalogBindingImpl class to get
the values of customerName and photoID?
Any other help would be appreciated..
thanks,
Karl Schwarz
System Architect
Northrop Grumman
