org.springframework.remoting.jaxrpc.support.AxisBeanMappingServicePostProcessor Maven / Gradle / Ivy
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
package org.springframework.remoting.jaxrpc.support;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.encoding.TypeMapping;
import javax.xml.rpc.encoding.TypeMappingRegistry;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.remoting.jaxrpc.JaxRpcServicePostProcessor;
import org.springframework.util.ClassUtils;
/**
* Axis-specific {@link JaxRpcServicePostProcessor} that registers bean
* mappings for domain objects that follow the JavaBean pattern.
*
* The same mappings are usually also registered at the server in
* Axis' "server-config.wsdd" file.
*
*
To be registered as a service post-processor on a
* {@link org.springframework.remoting.jaxrpc.LocalJaxRpcServiceFactoryBean} or
* {@link org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean},
* carrying appropriate configuration.
*
*
Note: Without such explicit bean mappings, a complex type like a
* domain object cannot be transferred via SOAP.
*
* @author Juergen Hoeller
* @since 2.0
* @see org.apache.axis.encoding.ser.BeanSerializerFactory
* @see org.apache.axis.encoding.ser.BeanDeserializerFactory
* @see org.springframework.remoting.jaxrpc.LocalJaxRpcServiceFactoryBean#setServicePostProcessors
* @see org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean#setServicePostProcessors
*/
public class AxisBeanMappingServicePostProcessor implements JaxRpcServicePostProcessor, BeanClassLoaderAware {
private String encodingStyleUri;
private String typeNamespaceUri;
private Map beanMappings;
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
/**
* Set the encoding style URI to use for the type mapping.
*
A typical value is "http://schemas.xmlsoap.org/soap/encoding/",
* as suggested by the JAX-RPC javadoc. However, note that the default
* behavior of this post-processor is to register the type mapping
* as JAX-RPC default if no explicit encoding style URI is given.
* @see javax.xml.rpc.encoding.TypeMappingRegistry#register
* @see javax.xml.rpc.encoding.TypeMappingRegistry#registerDefault
*/
public void setEncodingStyleUri(String encodingStyleUri) {
this.encodingStyleUri = encodingStyleUri;
}
/**
* Set the application-specific namespace to use for XML types,
* for example "urn:JPetStore".
* @see javax.xml.rpc.encoding.TypeMapping#register
*/
public void setTypeNamespaceUri(String typeNamespaceUri) {
this.typeNamespaceUri = typeNamespaceUri;
}
/**
* Specify the bean mappings to register as String-String pairs,
* with the Java type name as key and the WSDL type name as value.
*/
public void setBeanMappings(Properties beanMappingProps) {
if (beanMappingProps != null) {
this.beanMappings = new HashMap(beanMappingProps.size());
Enumeration propertyNames = beanMappingProps.propertyNames();
while (propertyNames.hasMoreElements()) {
String javaTypeName = (String) propertyNames.nextElement();
String wsdlTypeName = beanMappingProps.getProperty(javaTypeName);
this.beanMappings.put(javaTypeName, wsdlTypeName);
}
}
else {
this.beanMappings = null;
}
}
/**
* Specify the bean mappings to register as Java types,
* with the WSDL type names inferred from the Java type names
* (using the short, that is, non-fully-qualified class name).
*/
public void setBeanClasses(Class[] beanClasses) {
if (beanClasses != null) {
this.beanMappings = new HashMap(beanClasses.length);
for (int i = 0; i < beanClasses.length; i++) {
Class beanClass = beanClasses[i];
String wsdlTypeName = ClassUtils.getShortName(beanClass);
this.beanMappings.put(beanClass, wsdlTypeName);
}
}
else {
this.beanMappings = null;
}
}
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
/**
* Register the specified bean mappings on the given Service's
* {@link TypeMappingRegistry}.
* @see javax.xml.rpc.Service#getTypeMappingRegistry()
* @see #setBeanMappings
* @see #registerBeanMappings(javax.xml.rpc.encoding.TypeMapping)
*/
public void postProcessJaxRpcService(Service service) {
TypeMappingRegistry registry = service.getTypeMappingRegistry();
TypeMapping mapping = registry.createTypeMapping();
registerBeanMappings(mapping);
if (this.encodingStyleUri != null) {
registry.register(this.encodingStyleUri, mapping);
}
else {
registry.registerDefault(mapping);
}
}
/**
* Perform the actual bean mapping registration.
* @param mapping the JAX-RPC {@link TypeMapping} to operate on
* @see #setBeanMappings
* @see #registerBeanMapping(javax.xml.rpc.encoding.TypeMapping, Class, String)
*/
protected void registerBeanMappings(TypeMapping mapping) {
if (this.beanMappings != null) {
for (Iterator it = this.beanMappings.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
Object key = entry.getKey();
Class javaType = null;
if (key instanceof Class) {
javaType = (Class) key;
}
else {
javaType = ClassUtils.resolveClassName((String) key, this.beanClassLoader);
}
String wsdlTypeName = (String) entry.getValue();
registerBeanMapping(mapping, javaType, wsdlTypeName);
}
}
}
/**
* Register a bean mapping for the given Java type and WSDL type name.
* @param mapping the JAX-RPC {@link TypeMapping} to operate on
* @param javaType the Java type
* @param wsdlTypeName the WSDL type name (as a {@link String})
*/
protected void registerBeanMapping(TypeMapping mapping, Class javaType, String wsdlTypeName) {
registerBeanMapping(mapping, javaType, getTypeQName(wsdlTypeName));
}
/**
* Register a bean mapping for the given Java type and WSDL type.
* @param mapping the JAX-RPC {@link TypeMapping} to operate on
* @param javaType the Java type
* @param wsdlType the WSDL type (as XML {@link QName})
*/
protected void registerBeanMapping(TypeMapping mapping, Class javaType, QName wsdlType) {
mapping.register(javaType, wsdlType,
new BeanSerializerFactory(javaType, wsdlType),
new BeanDeserializerFactory(javaType, wsdlType));
}
/**
* Return a {@link QName} for the given name, relative to the
* {@link #setTypeNamespaceUri namespace URI} of this post-processor, if given.
*/
protected final QName getTypeQName(String name) {
return (this.typeNamespaceUri != null ? new QName(this.typeNamespaceUri, name) : new QName(name));
}
}