/*
* AxisTypeMappingUtil.java
*
* Copyright 2001-2004 The Apache Software Foundation.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
* Original author: Jonathan Colwell
*/
package org.apache.beehive.wsm.axis.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.io.File;
import java.io.Serializable;
import java.rmi.Remote;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.jws.WebParam;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPHeader;
import javax.wsdl.OperationType;
import org.apache.axis.Message;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.client.Stub;
import org.apache.axis.description.ElementDesc;
import org.apache.axis.description.FaultDesc;
import org.apache.axis.description.FieldDesc;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.description.ParameterDesc;
import org.apache.axis.description.TypeDesc;
import org.apache.axis.encoding.DeserializerFactory;
import org.apache.axis.encoding.SerializerFactory;
import org.apache.axis.encoding.TypeMapping;
import org.apache.axis.encoding.ser.ArraySerializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;
import org.apache.axis.encoding.ser.ArrayDeserializerFactory;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.VectorDeserializerFactory;
import org.apache.axis.message.SOAPHeaderElement;
import org.apache.axis.utils.BeanPropertyDescriptor;
import org.apache.axis.wsdl.fromJava.Namespaces;
import org.apache.axis.wsdl.fromJava.Types;
import org.apache.beehive.wsm.axis.util.encoding.XmlBeanDeserializerFactory;
import org.apache.beehive.wsm.axis.util.encoding.XmlBeanSerializerFactory;
import org.apache.beehive.wsm.util.InvalidTypeMappingException;
import org.apache.beehive.wsm.util.XmlBeanTypeMappingUtil;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SchemaTypeLoader;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlObject;
import org.w3c.dom.Element;
/*******************************************************************************
*
* @author Jonathan Colwell
*/
public class AxisTypeMappingUtil extends XmlBeanTypeMappingUtil {
private TypeMapping mTypeMapping;
public AxisTypeMappingUtil(TypeMapping tm) {
super();
mTypeMapping = tm;
}
public QName registerType(Class cls) throws InvalidTypeMappingException {
return registerType(cls, null);
}
public QName registerType(Class cls, QName expectedType)
throws InvalidTypeMappingException {
QName q;
if (Void.TYPE.equals(cls)) {
q = null;
}
else {
q = mTypeMapping.getTypeQName(cls);
if (q == null ||
(expectedType != null && !expectedType.equals(q))) {
if (expectedType == null) {
q = generateQName(cls, "http://no.namespace.specified");
}
else {
q = expectedType;
}
if (cls.isArray()) {
if (!mTypeMapping.isRegistered(cls, q)) {
mTypeMapping.register(cls, q,
new ArraySerializerFactory(cls, q),
new ArrayDeserializerFactory());
}
q = registerType(cls.getComponentType());
// TODO: fix the expected type thing for arrays.
if (expectedType != null) {
q = expectedType;
}
}
else if (!mTypeMapping.isRegistered(cls, q)) {
if (XmlObject.class.isAssignableFrom(cls)) {
mTypeMapping.register(cls, q,
new XmlBeanSerializerFactory(cls, q),
new XmlBeanDeserializerFactory(cls, q));
}
/*
* NOTE jcolwell@bea.com 2004-Oct-11 -- these datahandler
* using classes are generally already registered but
* just in case...
*/
else if (isActivationEnabled() &&
(java.awt.Image.class.isAssignableFrom(cls)
|| getMultipartClass().isAssignableFrom(cls)
|| getDataHandlerClass().isAssignableFrom(cls))) {
try {
/*
* NOTE jcolwell@bea.com 2004-Oct-08 -- doing
* reflection here in case AXIS was built without
* attachment support.
*/
ClassLoader cl = getClass().getClassLoader();
Class<SerializerFactory> sfClass =
(Class<SerializerFactory>)
cl.loadClass("org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory");
Class<DeserializerFactory> dsfClass =
(Class<DeserializerFactory>)
cl.loadClass("org.apache.axis.encoding.ser.JAFDataHandlerDeserializerFactory");
Constructor<SerializerFactory> sfCon =
sfClass.getConstructor(Class.class,
QName.class);
Constructor<DeserializerFactory> dsfCon =
dsfClass.getConstructor(Class.class,
QName.class);
SerializerFactory sf = sfCon.newInstance(cls, q);
DeserializerFactory dsf = dsfCon.newInstance(cls, q);
mTypeMapping.register(cls, q, sf, dsf);
} catch (Exception e) {
/*
* FIXME jcolwell@bea.com 2004-Oct-08 --
* log this properly
*/
e.printStackTrace();
}
} else if (! Remote.class.isAssignableFrom(cls)
/*
* NOTE jcolwell@bea.com 2004-Oct-11 --
* java.rmi.Remote is prohibited
* by the jax-rpc spec.
*/
/*
* NOTE jcolwell@bea.com 2004-Oct-11 --
* restricting against File since, it doesn't make
* sense to serialize as a bean.
* That and it causes an infinite
* loop as it keeps returning itself from the
* getAbsoluteFile and getCanonicalFile calls
*/
&& !File.class.isAssignableFrom(cls)) {
TypeDesc td = TypeDesc.getTypeDescForClass(cls);
TypeDesc superTd = null;
BeanPropertyDescriptor[] superPd = null;
if (null == td) {
td = new TypeDesc(cls);
Class supa = cls.getSuperclass();
if ((supa != null)
&& (supa != java.lang.Object.class)
&& (supa != java.lang.Exception.class)
&& (supa != java.lang.Throwable.class)
&& (supa != java.rmi.RemoteException.class)
&& (supa != org.apache.axis.AxisFault.class)) {
registerType(supa);
}
superTd = TypeDesc
.getTypeDescForClass(supa);
if (superTd != null) {
superPd = superTd.getPropertyDescriptors();
}
td.setXmlType(q);
TypeDesc.registerTypeDescForClass(cls, td);
} else {
td = null;
}
mTypeMapping.register(cls, q,
new BeanSerializerFactory(cls, q),
/*
* NOTE jcolwell@bea.com 2004-Oct-11 --
* should check that the type to deserialize
* has a default contructor but with this
* setup there is no way to know if it is
* used only in serialization.
*/
new BeanDeserializerFactory(cls, q));
Map serProps = BeanDeserializerFactory
.getProperties(cls, null);
for (BeanPropertyDescriptor beanProps :
(Collection<BeanPropertyDescriptor>) serProps
.values()) {
Class subType = beanProps.getType();
if (!(subType.isPrimitive()
|| subType.getName().startsWith("java.")
|| subType.getName().startsWith("javax."))) {
registerType(subType);
}
if (td != null) {
String ns = q.getNamespaceURI();
if (superTd != null && superPd != null) {
for (int j = 0; j < superPd.length; j++) {
if (beanProps.getName()
.equals(superPd[j]
.getName())) {
ns = superTd.getXmlType()
.getNamespaceURI();
break;
}
}
}
FieldDesc fd = new ElementDesc();
fd.setJavaType(subType);
fd.setFieldName(beanProps.getName());
fd.setXmlName(new QName(ns,
beanProps.getName()));
// NOTE jcolwell@bea.com 2004-Oct-28 -- might need
// to do more to ensure a useful type QName.
fd.setXmlType(mTypeMapping.getTypeQName(subType));
((ElementDesc) fd).setNillable(true);
// mmerz@apache.com 2005-Mar-09: required since Axis 1.2RC3 to allow for null values in complex objects; note that there is no (JSR-181) annotation that allows configuring this value.
td.addFieldDesc(fd);
}
}
} else {
throw new InvalidTypeMappingException
("failed to register " + cls.getName()
+ " as a valid web service datatype,"
+ " consider using a custom type mapping");
}
}
}
}
return q;
}
public Class q2Class(QName qType) {
Class cls = super.q2Class(qType);
if (Object.class.equals(cls) && mTypeMapping != null) {
cls = mTypeMapping.getClassForQName(qType);
return cls;
}
else {
return null;
}
}
private boolean isActivationEnabled() {
return null != getDataHandlerClass() && null != getMultipartClass();
}
private Class getDataHandlerClass() {
try {
return getClass().getClassLoader()
.loadClass("javax.activation.DataHandler");
} catch (Exception e) {
}
return null;
}
private Class getMultipartClass() {
try {
return getClass().getClassLoader()
.loadClass("javax.mail.internet.MimeMultipart");
} catch (Exception e) {
}
return null;
}
public QName generateQName(Class type, String defaultNS) {
QName generated = super.generateQName(type, defaultNS);
if (generated == null) {
String namespace = Namespaces.makeNamespace(type.getName());
if (namespace == null || namespace
.endsWith("DefaultNamespace")) {
namespace = defaultNS;
}
generated = new QName(namespace,
Types.getLocalNameFromFullName(type
.getName()));
}
return generated;
}
}