You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by sc...@apache.org on 2006/11/17 05:01:50 UTC
svn commit: r476045 [2/2] - in /webservices/axis2/trunk/java/modules/jaxws:
src/org/apache/axis2/jaxws/ src/org/apache/axis2/jaxws/client/proxy/
src/org/apache/axis2/jaxws/description/impl/
src/org/apache/axis2/jaxws/i18n/ src/org/apache/axis2/jaxws/ma...
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java Thu Nov 16 20:01:48 2006
@@ -17,19 +17,52 @@
* under the License.
*/
package org.apache.axis2.jaxws.marshaller.impl.alt;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Future;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.ws.AsyncHandler;
+import javax.xml.ws.Holder;
+import javax.xml.ws.Response;
import javax.xml.ws.WebServiceException;
+import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.description.EndpointDescription;
+import org.apache.axis2.jaxws.description.FaultDescription;
import org.apache.axis2.jaxws.description.OperationDescription;
+import org.apache.axis2.jaxws.description.ParameterDescription;
import org.apache.axis2.jaxws.description.ServiceDescription;
+import org.apache.axis2.jaxws.i18n.Messages;
import org.apache.axis2.jaxws.marshaller.MethodMarshaller;
import org.apache.axis2.jaxws.marshaller.impl.MethodMarshallerImpl;
+import org.apache.axis2.jaxws.message.Block;
import org.apache.axis2.jaxws.message.Message;
+import org.apache.axis2.jaxws.message.MessageException;
import org.apache.axis2.jaxws.message.Protocol;
+import org.apache.axis2.jaxws.message.XMLFault;
+import org.apache.axis2.jaxws.message.XMLFaultReason;
+import org.apache.axis2.jaxws.message.databinding.JAXBBlockContext;
+import org.apache.axis2.jaxws.message.factory.JAXBBlockFactory;
+import org.apache.axis2.jaxws.message.util.MessageUtils;
+import org.apache.axis2.jaxws.registry.FactoryRegistry;
+import org.apache.axis2.jaxws.util.ClassUtils;
+import org.apache.axis2.jaxws.util.XMLRootElementUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import javax.jws.WebParam.Mode;
+import javax.jws.soap.SOAPBinding.Style;
/**
@@ -38,6 +71,9 @@
class MethodMarshallerUtils {
private static Log log = LogFactory.getLog(MethodMarshallerUtils.class);
+
+ private static JAXBBlockFactory factory =
+ (JAXBBlockFactory)FactoryRegistry.getFactory(JAXBBlockFactory.class);
/**
* Intentionally Private. This is a static utility class
@@ -45,6 +81,571 @@
private MethodMarshallerUtils() {
}
+ /**
+ * Returns the list of PDElements that need to be marshalled onto the wire
+ *
+ * @param params ParameterDescription for this operation
+ * @param sigArguments arguments
+ * @param isInput indicates if input or output params(input args on client, output args on server)
+ * @param usePartName indicates whether to use the partName or name for the name of the xml element
+ * partName is used for RPC and doc/lit wrapped, name is used for doc/lit bare
+ * @param forceXSIType if upgrading a type to an element
+ * @return PDElements
+ */
+ static List<PDElement> getPDElements(ParameterDescription[] params, Object[] sigArguments, boolean isInput, boolean usePartName, boolean forceXSIType) {
+ List<PDElement> pvList = new ArrayList<PDElement>();
+
+ int index = 0;
+ for (int i=0; i<params.length; i++) {
+ ParameterDescription pd = params[i];
+
+ if (pd.getMode() == Mode.IN && isInput ||
+ pd.getMode() == Mode.INOUT ||
+ pd.getMode() == Mode.OUT && !isInput) {
+
+ // Get the matching signature argument
+ Object value = sigArguments[i];
+
+ // Don't consider async handlers, they are are not represented on the wire,
+ // thus they don't have a PDElement
+ if (isAsyncHandler(value)) {
+ continue;
+ }
+
+ // Convert from Holder into value
+ if (isHolder(value)) {
+ value =((Holder)value).value;
+ }
+
+ // Get the formal type representing the value
+ Class formalType = pd.getParameterActualType();
+
+ // If this value is element enabled, then we are okay
+ // Otherwise make an element enabled value
+ if (!XMLRootElementUtil.isElementEnabled(formalType)) {
+ String localName = (usePartName) ? pd.getPartName() : pd.getParameterName();
+ value = XMLRootElementUtil.getElementEnabledObject(pd.getTargetNamespace(), localName, formalType, value, forceXSIType);
+ }
+
+ // The object is now ready for marshalling
+ PDElement pv = new PDElement(pd, value);
+ pvList.add(pv);
+ }
+ }
+
+ return pvList;
+ }
+
+ /**
+ * Return the list of PDElements that is unmarshalled from the wire
+ *
+ * @param params ParameterDescription for this operation
+ * @param message Message
+ * @param packages set of packages needed to unmarshal objects for this operation
+ * @param isInput indicates if input or output params (input on server, output on client)
+ * @param usePartName indicates whether to use the partName or name for the name of the xml element
+ * @return ParamValues
+ */
+ static List<PDElement> getPDElements(ParameterDescription[] params,
+ Message message,
+ Set<Package> packages,
+ boolean isInput,
+ boolean usePartName) throws MessageException, XMLStreamException {
+
+ List<PDElement> pvList = new ArrayList<PDElement>();
+
+ int index = 0;
+ for (int i=0; i<params.length; i++) {
+ ParameterDescription pd = params[i];
+
+ if (pd.getMode() == Mode.IN && isInput ||
+ pd.getMode() == Mode.INOUT ||
+ pd.getMode() == Mode.OUT && !isInput) {
+
+ // Don't consider async handlers, they are are not represented on the wire,
+ // thus they don't have a PDElement
+ // TODO
+ //if (isAsyncHandler(param)) {
+ // continue;
+ //}
+
+ // Unmarshal the object into a JAXB object or JAXBElement
+ Block block = null;
+ if (pd.isHeader()) {
+
+ // Get the Block from the header
+ if (message.getStyle() == Style.RPC) {
+ // TODO add xsi type
+ }
+ String localName = (usePartName) ? pd.getPartName() : pd.getParameterName();
+ block = message.getHeaderBlock(pd.getTargetNamespace(), localName, new JAXBBlockContext(packages), factory);
+ } else {
+ if (message.getStyle() == Style.RPC) {
+ // TODO add xsi type
+ }
+ block = message.getBodyBlock(index, new JAXBBlockContext(packages), factory);
+ }
+
+ // The object is now ready for marshalling
+ PDElement pv = new PDElement(pd, block.getBusinessObject(true));
+ pvList.add(pv);
+ }
+ }
+
+ return pvList;
+ }
+
+ /**
+ * Creates the request signature arguments (server) from a list
+ * of element eabled object (PDEements)
+ * @param pds ParameterDescriptions for this Operation
+ * @param pvList Element enabled object
+ * @return Signature Args
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ * @throws ClassNotFoundException
+ */
+ static Object[] createRequestSignatureArgs(ParameterDescription[] pds, List<PDElement> pvList)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ Object[] args = new Object[pds.length];
+ int pvIndex = 0;
+ for (int i=0; i< args.length; i++) {
+ // Get the paramValue
+ PDElement pv = (pvIndex < pvList.size()) ? pvList.get(pvIndex) : null;
+ ParameterDescription pd = pds[i];
+ if (pv == null ||
+ pv.getParam() != pd) {
+ // We have a ParameterDesc but there is not an equivalent PDElement.
+ // Provide the default
+ if (pd.isHolderType()) {
+ args[i] = createHolder(pd.getParameterType(), null);
+ } else {
+ args[i] = null;
+ }
+ } else {
+
+ // We have a matching paramValue
+ Object value = pv.getElementValue();
+ pvIndex++;
+
+ // The signature wants the object that is rendered as the type
+ value = XMLRootElementUtil.getTypeEnabledObject(value);
+
+ // The signature may want a holder representation
+ if (pd.isHolderType()) {
+ args[i] = createHolder(pd.getParameterType(), value);
+ } else {
+ args[i] = value;
+ }
+ }
+
+ }
+ return args;
+ }
+
+ /**
+ * Update the signature arguments on the client with the unmarshalled element enabled objects (pvList)
+ * @param pds ParameterDescriptions
+ * @param pvList Element Enabled objects
+ * @param signatureArgs Signature Arguments (the out/inout holders are updated)
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ * @throws ClassNotFoundException
+ */
+ static void updateResponseSignatureArgs(ParameterDescription[] pds, List<PDElement> pvList, Object[] signatureArgs)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ int pvIndex = 0;
+
+ // Each ParameterDescriptor has a correspondinging signatureArg from the
+ // the initial client call. The pvList contains the response values from the message.
+ // Walk the ParameterDescriptor/SignatureArg list and populate the holders with
+ // the match PDElement
+ for (int i=0; i< pds.length; i++) {
+ // Get the paramValue
+ PDElement pv = (pvIndex < pvList.size()) ? pvList.get(pvIndex) : null;
+ ParameterDescription pd = pds[i];
+ if (pv != null && pv.getParam() == pd) {
+ // We have a matching paramValue
+ Object value = pv.getElementValue();
+ pvIndex++;
+
+ // The signature wants the object that is rendered as the type
+ value = XMLRootElementUtil.getTypeEnabledObject(value);
+
+ // TODO Assert that this ParameterDescriptor must represent
+ // an OUT or INOUT and must have a non-null holder object to
+ // store the value
+ if (isHolder(signatureArgs[i])) {
+ ((Holder) signatureArgs[i]).value = value;
+ }
+ }
+ }
+ }
+
+ /**
+ * Marshal the element enabled objects (pvList) to the Message
+ * @param pvList element enabled objects
+ * @param message Message
+ * @param packages Packages needed to do a JAXB Marshal
+ * @throws MessageException
+ */
+ static void toMessage(List<PDElement> pvList, Message message, Set<Package> packages) throws MessageException {
+
+ int index = message.getNumBodyBlocks();
+ for (int i=0; i<pvList.size(); i++) {
+ PDElement pv = pvList.get(i);
+
+ // Create a JAXBBlock out of the value.
+ // (Note that the PDElement.getValue always returns an object
+ // that has an element rendering...ie. it is either a JAXBElement o
+ // has @XmlRootElement defined
+ Block block = factory.createFrom(pv.getElementValue(),
+ new JAXBBlockContext(packages),
+ null); // The factory will get the qname from the value
+
+ if (pv.getParam().isHeader()) {
+ // Header block
+ QName qname = block.getQName();
+ message.setHeaderBlock(qname.getNamespaceURI(),
+ qname.getLocalPart(),
+ block);
+ } else {
+ // Body block
+ message.setBodyBlock(index, block);
+ index++;
+ }
+ }
+ }
+
+ /**
+ * Marshals the return object to the message (used on server to marshal return object)
+ * @param returnValue
+ * @param returnType
+ * @param returnNS
+ * @param returnLocalPart
+ * @param packages
+ * @param message
+ * @param forceXSIType if upgrading type to an element
+ * @throws MessageException
+ */
+ static void toMessage(Object returnValue,
+ Class returnType,
+ String returnNS,
+ String returnLocalPart,
+ Set<Package> packages,
+ Message message,
+ boolean forceXSIType)
+ throws MessageException {
+ // If this type is an element rendering, then we are okay
+ // If it is a type rendering then make a JAXBElement
+ if (!XMLRootElementUtil.isElementEnabled(returnType)) {
+ returnValue = XMLRootElementUtil.getElementEnabledObject(returnNS, returnLocalPart,returnType, returnValue, forceXSIType);
+ }
+
+ // Create a JAXBBlock out of the value.
+ Block block = factory.createFrom(returnValue,
+ new JAXBBlockContext(packages),
+ null); // The factory will get the qname from the value
+ message.setBodyBlock(0, block);
+ }
+
+ /**
+ * Unmarshal the return object from the message
+ * @param packages
+ * @param message
+ * @return type enabled object
+ * @throws MessageException
+ * @throws XMLStreamException
+ */
+ static Object getReturnValue(Set<Package> packages, Message message)
+ throws MessageException, XMLStreamException {
+
+
+ // The return object is the first block in the body
+ if (message.getStyle() == Style.RPC) {
+ // TODO add xsi type
+ }
+ Block block = message.getBodyBlock(0, new JAXBBlockContext(packages), factory);
+
+ // Get the business object. We want to return the object that represents the type.
+ Object returnValue = block.getBusinessObject(true);
+ // The signature wants the object that is rendered as the type
+ returnValue = XMLRootElementUtil.getTypeEnabledObject(returnValue);
+ return returnValue;
+ }
+
+ /**
+ * Utility method to get the Class representing the actual return type
+ *
+ * @param operationDesc
+ * @return actual return type
+ */
+ static Class getActualReturnType(OperationDescription operationDesc){
+ Method seiMethod = operationDesc.getSEIMethod();
+ Class returnType = seiMethod.getReturnType();
+ if(isAsync(operationDesc)){
+ //pooling implementation
+ if(Response.class == returnType){
+ Type type = seiMethod.getGenericReturnType();
+ ParameterizedType pType = (ParameterizedType) type;
+ return (Class)pType.getActualTypeArguments()[0];
+ }
+ //Callback Implementation
+ else{
+ Type[] type = seiMethod.getGenericParameterTypes();
+ Class parameters[]= seiMethod.getParameterTypes();
+ int i=0;
+ for(Class param:parameters){
+ if(AsyncHandler.class.isAssignableFrom(param)){
+ ParameterizedType pType = (ParameterizedType)type[i];
+ return (Class)pType.getActualTypeArguments()[0];
+ }
+ i++;
+ }
+ }
+
+ }
+
+ return returnType;
+ }
+
+ /**
+ * Marshaling a fault is essentially the same for rpc/lit and doc/lit.
+ * This method is used by all of the MethodMarshallers
+ * @param throwable Throwable to marshal
+ * @param operationDesc OperationDescription
+ * @param packages Packages needed to marshal the object
+ * @param message Message
+ * @param forceXSIType if the faultbean
+ * @throws MessageException
+ * @throws NoSuchMethodException
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ */
+ static void marshalFaultResponse(Throwable throwable, OperationDescription operationDesc, Set<Package> packages, Message message,
+ boolean forceXSIType)
+ throws MessageException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+
+ // Get the root cause of the throwable object
+ if (log.isDebugEnabled()) {
+ log.debug("Marshal Throwable =" + throwable.getClass().getName());
+ log.debug(" message=" + throwable.getMessage());
+ log.debug(" stack=" + MessageUtils.stackToString(throwable));
+ }
+ Throwable t = ClassUtils.getRootCause(throwable);
+
+ XMLFault xmlfault = null;
+
+ // Get the FaultDescriptor matching this Exception.
+ // If FaultDescriptor is found, this is a JAX-B Service Exception.
+ // If not found, this is a System Exception
+ FaultDescription fd = operationDesc.resolveFaultByExceptionName(t.getClass().getName());
+
+ String text = null;
+ if (fd != null) {
+ // Service Exception.
+
+ // Get the fault bean object. Make sure it can be rendered as an element
+ Method getFaultInfo = t.getClass().getMethod("getFaultInfo", null);
+ Object faultBeanObject = getFaultInfo.invoke(t, null);
+ if (!XMLRootElementUtil.isElementEnabled(faultBeanObject.getClass())) {
+ faultBeanObject = XMLRootElementUtil.getElementEnabledObject(fd.getTargetNamespace(), fd.getName(),
+ faultBeanObject.getClass(), faultBeanObject, forceXSIType);
+ }
+
+ // Create a detailblock representing the faultBeanObject
+ JAXBBlockContext context = new JAXBBlockContext(packages);
+ Block[] detailBlocks = new Block[1];
+ detailBlocks[0] = factory.createFrom(faultBeanObject,context,null);
+
+ // Now make a XMLFault containing the detailblock
+ text = t.getMessage();
+ xmlfault = new XMLFault(null, new XMLFaultReason(text), detailBlocks);
+ } else {
+ // System Exception
+ xmlfault = new XMLFault(null, // Use the default XMLFaultCode
+ new XMLFaultReason(text)); // Assumes text is the language supported by the current Locale
+ }
+ // Add the fault to the message
+ message.setXMLFault(xmlfault);
+ }
+
+ /**
+ * Unmarshal the service/system exception from a Message.
+ * This is used by all of the marshallers
+ * @param operationDesc
+ * @param packages
+ * @param message
+ * @param isRPC
+ * @return Throwable
+ * @throws MessageException
+ * @throws ClassNotFoundException
+ * @throws IllegalAccessException
+ * @throws InstantiationException
+ * @throws XMLStreamException
+ * @throws InvocationTargetException
+ * @throws NoSuchMethodException
+ */
+ static Throwable demarshalFaultResponse(OperationDescription operationDesc, Set<Package> packages,Message message, boolean isRPC)
+ throws MessageException, ClassNotFoundException, IllegalAccessException,
+ InstantiationException, XMLStreamException, InvocationTargetException, NoSuchMethodException {
+
+ Throwable exception = null;
+ // Get the fault from the message and get the detail blocks (probably one)
+ XMLFault xmlfault = message.getXMLFault();
+ Block[] detailBlocks = xmlfault.getDetailBlocks();
+
+
+ if ((operationDesc.getFaultDescriptions().length == 0) || (detailBlocks == null)) {
+ // This is a system exception if the method does not throw a checked exception or if
+ // there is nothing in the detail element.
+ // Shouldn't this create
+
+ // Create SystemException
+ // TODO shouldn't the exception capture the contents of the detail blocks
+ exception = createSystemException(xmlfault.getReason().getText());
+ } else {
+
+ // TODO what if there are multiple blocks in the detail ?
+ // We should create a generic fault with the appropriate detail
+
+ // Get the JAXB object from the block
+ JAXBBlockContext blockContext = new JAXBBlockContext(packages);
+
+ if (isRPC) {
+ //TODO add xsi:type
+ }
+ Block jaxbBlock = factory.createFrom(detailBlocks[0], blockContext);
+ Object faultBeanObject = jaxbBlock.getBusinessObject(true);
+
+ // At this point, faultBeanObject is an object that can be rendered as an
+ // element. We want the object that represents the type. Also get the
+ // name of the element.
+ QName faultBeanQName = null;
+ if (faultBeanObject instanceof JAXBElement) {
+ faultBeanQName = ((JAXBElement)faultBeanObject).getName();
+ faultBeanObject = ((JAXBElement)faultBeanObject).getValue();
+ } else {
+ faultBeanQName = XMLRootElementUtil.getXmlRootElementQName(faultBeanObject);
+ }
+
+ // Using the faultBeanQName, find the matching faultDescription
+ FaultDescription faultDesc = null;
+ for(int i=0; i<operationDesc.getFaultDescriptions().length && faultDesc == null; i++) {
+ FaultDescription fd = operationDesc.getFaultDescriptions()[i];
+ QName tryQName = new QName(fd.getTargetNamespace(), fd.getName());
+
+ if (faultBeanQName == null || faultBeanQName.equals(tryQName)) {
+ faultDesc = fd;
+
+ }
+ }
+ if (faultDesc == null) {
+ throw ExceptionFactory.makeWebServiceException(Messages.getMessage("MethodMarshallerErr1", faultBeanObject.getClass().toString()));
+ }
+
+ // Construct the JAX-WS generated exception that holds the faultBeanObject
+ Class exceptionClass = loadClass(faultDesc.getExceptionClassName());
+ Class faultBeanFormalClass = loadClass(faultDesc.getFaultBean());
+ exception =createServiceException(xmlfault.getReason().getText(), exceptionClass, faultBeanObject, faultBeanFormalClass);
+ }
+ return exception;
+ }
+
+ /**
+ * @param operationDesc
+ * @return if asyc operation
+ */
+ static boolean isAsync(OperationDescription operationDesc){
+ Method method = operationDesc.getSEIMethod();
+ if(method == null){
+ return false;
+ }
+ String methodName = method.getName();
+ Class returnType = method.getReturnType();
+ return methodName.endsWith("Async") && (returnType.isAssignableFrom(Response.class) || returnType.isAssignableFrom(Future.class));
+ }
+
+ /**
+ * @param value
+ * @return if async handler
+ */
+ static boolean isAsyncHandler(Object value){
+ return (value instanceof AsyncHandler);
+ }
+
+ /**
+ * @param value
+ * @return true if value is holder
+ */
+ static boolean isHolder(Object value){
+ return value!=null && Holder.class.isAssignableFrom(value.getClass());
+ }
+
+ /** Crate a Holder
+ * @param <T>
+ * @param paramType
+ * @param value
+ * @return
+ * @throws IllegalAccessException
+ * @throws InstantiationException
+ * @throws ClassNotFoundException
+ */
+ static <T> Holder<T> createHolder(Class paramType, T value) throws IllegalAccessException, InstantiationException, ClassNotFoundException{
+ if(Holder.class.isAssignableFrom(paramType)){
+ Class holderClazz = loadClass(paramType.getName());
+ Holder<T> holder = (Holder<T>) holderClazz.newInstance();
+ holder.value = value;
+ return holder;
+ }
+ return null;
+ }
+
+ /**
+ * Load the class
+ * @param className
+ * @return loaded class
+ * @throws ClassNotFoundException
+ */
+ static Class loadClass(String className)throws ClassNotFoundException{
+ // TODO J2W AccessController Needed
+ // Don't make this public, its a security exposure
+ return Class.forName(className, true, Thread.currentThread().getContextClassLoader());
+ }
+
+ /** Create a JAX-WS Service Exception (Generated Exception)
+ * @param message
+ * @param exceptionclass
+ * @param bean
+ * @param beanFormalType
+ * @return
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws InstantiationException
+ * @throws NoSuchMethodException
+ */
+ private static Exception createServiceException(String message, Class exceptionclass, Object bean, Class beanFormalType) throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {
+ // All webservice exception classes are required to have a constructor that takes a (String, bean) argument
+ // TODO necessary to be more careful here with instantiating, cassting, etc?
+ if (log.isDebugEnabled()) {
+ log.debug("Constructing JAX-WS Exception:" + exceptionclass);
+ }
+ Constructor constructor = exceptionclass.getConstructor(new Class[] { String.class, beanFormalType });
+ Object exception = constructor.newInstance(new Object[] { message, bean });
+ return (Exception) exception;
+
+ }
+
+ /**
+ * Create a system exception
+ * @param message
+ * @return
+ */
+ private static Exception createSystemException(String message) {
+ return ExceptionFactory.makeWebServiceException(message);
+ }
+
+
}
Added: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/PDElement.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/PDElement.java?view=auto&rev=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/PDElement.java (added)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/PDElement.java Thu Nov 16 20:01:48 2006
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.axis2.jaxws.marshaller.impl.alt;
+
+import org.apache.axis2.jaxws.description.ParameterDescription;
+
+
+/**
+ * A PDElement object holds a ParameterDescription (Param) and
+ * the "Element" value.
+ * Characteristics of the "Element" value.
+ * * The Element value is ready for marshalling or is the result of unmarshalling.
+ * * The Element value represents the element rendering. Thus it is either
+ * a JAXBElement or has the @XmlRootElement annotation. (i.e. it is never a
+ * java.lang.String)
+ * * The Element value is not a JAX-WS object. (i.e. it is not a holder or exception)
+ */
+public class PDElement {
+ private ParameterDescription param;
+ private Object value;
+
+ public PDElement(ParameterDescription param, Object value) {
+ super();
+ this.param = param;
+ this.value = value;
+ }
+
+ public ParameterDescription getParam() {
+ return param;
+ }
+
+ public Object getElementValue() {
+ return value;
+ }
+
+}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/RPCLitMethodMarshaller.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/RPCLitMethodMarshaller.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/RPCLitMethodMarshaller.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/RPCLitMethodMarshaller.java Thu Nov 16 20:01:48 2006
@@ -18,17 +18,23 @@
*/
package org.apache.axis2.jaxws.marshaller.impl.alt;
+import java.util.List;
+import java.util.Set;
+
+import javax.jws.soap.SOAPBinding.Style;
import javax.xml.namespace.QName;
import javax.xml.ws.WebServiceException;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.description.EndpointDescription;
import org.apache.axis2.jaxws.description.OperationDescription;
+import org.apache.axis2.jaxws.description.ParameterDescription;
import org.apache.axis2.jaxws.description.ServiceDescription;
import org.apache.axis2.jaxws.marshaller.MethodMarshaller;
-import org.apache.axis2.jaxws.marshaller.impl.MethodMarshallerImpl;
import org.apache.axis2.jaxws.message.Message;
import org.apache.axis2.jaxws.message.Protocol;
+import org.apache.axis2.jaxws.message.factory.MessageFactory;
+import org.apache.axis2.jaxws.registry.FactoryRegistry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -50,44 +56,222 @@
this.protocol = protocol;
}
- public Object demarshalResponse(Message message, Object[] inputArgs)
- throws WebServiceException {
+ public Message marshalRequest(Object[] signatureArguments) throws WebServiceException {
// Note all exceptions are caught and rethrown with a WebServiceException
try {
- // TODO Add Real Code
- throw new UnsupportedOperationException();
+
+ // Sample RPC message
+ // ..
+ // <soapenv:body>
+ // <m:op xmlns:m="urn://api">
+ // <m:param xsi:type="data:foo" xmlns:data="urn://mydata" >...</m:param>
+ // </m:op>
+ // </soapenv:body>
+ //
+ // Important points.
+ // 1) RPC has an operation element under the body. This is the name of the
+ // wsdl operation.
+ // 2) The data blocks are located underneath the operation element. (In doc/lit
+ // the data elements are underneath the body.
+ // 3) The name of the data blocks (m:param) are defined by the wsdl:part not the
+ // schema.
+ // 4) The type of the data block (data:foo) is defined by schema (thus there is
+ // JAXB type rendering. Since we are using JAXB to marshal the data,
+ // we always generate an xsi:type attribute. This is an implemenation detail
+ // and is not defined by any spec.
+
+
+ // Get the operation information
+ ParameterDescription[] pds =operationDesc.getParameterDescriptions();
+ Set<Package> packages = endpointDesc.getPackages();
+
+ // Create the message
+ MessageFactory mf = (MessageFactory)FactoryRegistry.getFactory(MessageFactory.class);
+ Message m = mf.create(protocol);
+
+ // Indicate the style and operation element name. This triggers the message to
+ // put the data blocks underneath the operation element
+ m.setStyle(Style.RPC);
+ m.setOperationElement(operationDesc.getName());
+
+ // The input object represent the signature arguments.
+ // Signature arguments are both holders and non-holders
+ // Convert the signature into a list of JAXB objects for marshalling
+ List<PDElement> pvList =
+ MethodMarshallerUtils.getPDElements(pds,
+ signatureArguments,
+ true, // input
+ true, // use partName since this is rpc/lit
+ true); // always force xsi:type since this is rpc/lit
+
+ // Put values onto the message
+ MethodMarshallerUtils.toMessage(pvList, m, packages);
+
+ return m;
} catch(Exception e) {
throw ExceptionFactory.makeWebServiceException(e);
}
}
-
+
public Object[] demarshalRequest(Message message)
- throws WebServiceException {
+ throws WebServiceException {
// Note all exceptions are caught and rethrown with a WebServiceException
try {
- // TODO Add Real Code
- throw new UnsupportedOperationException();
+ // Sample RPC message
+ // ..
+ // <soapenv:body>
+ // <m:op xmlns:m="urn://api">
+ // <m:param xsi:type="data:foo" xmlns:data="urn://mydata" >...</m:param>
+ // </m:op>
+ // </soapenv:body>
+ //
+ // Important points.
+ // 1) RPC has an operation element under the body. This is the name of the
+ // wsdl operation.
+ // 2) The data blocks are located underneath the operation element. (In doc/lit
+ // the data elements are underneath the body.
+ // 3) The name of the data blocks (m:param) are defined by the wsdl:part not the
+ // schema.
+ // 4) The type of the data block (data:foo) is defined by schema (thus there is
+ // JAXB type rendering.
+ // 5) We always send an xsi:type, but other vendor's may not.
+ // Get the operation information
+ ParameterDescription[] pds =operationDesc.getParameterDescriptions();
+ Set<Package> packages = endpointDesc.getPackages();
+
+ // Indicate that the style is RPC. This is important so that the message understands
+ // that the data blocks are underneath the operation element
+ message.setStyle(Style.RPC);
+
+ // Unmarshal the ParamValues from the Message
+ List<PDElement> pvList = MethodMarshallerUtils.getPDElements(pds, message, packages, true, true);
+
+ // Build the signature arguments
+ Object[] sigArguments = MethodMarshallerUtils.createRequestSignatureArgs(pds, pvList);
+
+ return sigArguments;
} catch(Exception e) {
throw ExceptionFactory.makeWebServiceException(e);
}
}
- public Message marshalResponse(Object returnObject, Object[] holderObjects)
+
+
+ public Message marshalResponse(Object returnObject, Object[] signatureArgs)
throws WebServiceException {
// Note all exceptions are caught and rethrown with a WebServiceException
try {
- // TODO Add Real Code
- throw new UnsupportedOperationException();
+ // Sample RPC message
+ // ..
+ // <soapenv:body>
+ // <m:opResponse xmlns:m="urn://api">
+ // <m:param xsi:type="data:foo" xmlns:data="urn://mydata" >...</m:param>
+ // </m:op>
+ // </soapenv:body>
+ //
+ // Important points.
+ // 1) RPC has an operation element under the body. This is the name of the
+ // wsdl operation.
+ // 2) The data blocks are located underneath the operation element. (In doc/lit
+ // the data elements are underneath the body.
+ // 3) The name of the data blocks (m:param) are defined by the wsdl:part not the
+ // schema.
+ // 4) The type of the data block (data:foo) is defined by schema (thus there is
+ // JAXB type rendering. Since we are using JAXB to marshal the data,
+ // we always generate an xsi:type attribute. This is an implemenation detail
+ // and is not defined by any spec.
+
+ // Get the operation information
+ ParameterDescription[] pds =operationDesc.getParameterDescriptions();
+ Set<Package> packages = endpointDesc.getPackages();
+
+ // Create the message
+ MessageFactory mf = (MessageFactory)FactoryRegistry.getFactory(MessageFactory.class);
+ Message m = mf.create(protocol);
+
+ // Indicate the style and operation element name. This triggers the message to
+ // put the data blocks underneath the operation element
+ m.setStyle(Style.RPC);
+
+ // TODO Is there an annotation for the operation element response ?
+ String localPart = operationDesc.getName().getLocalPart() + "Response";
+ QName responseOp = new QName(operationDesc.getName().getNamespaceURI(), localPart);
+ m.setOperationElement(responseOp);
+
+ // Put the return object onto the message
+ Class returnType = MethodMarshallerUtils.getActualReturnType(operationDesc);
+ if (returnType != void.class) {
+ MethodMarshallerUtils.toMessage(returnObject,
+ returnType,
+ operationDesc.getResultTargetNamespace(),
+ operationDesc.getResultPartName(),
+ packages,
+ m,
+ true); // forceXSI since this is rpc/lit
+ }
+
+ // Convert the holder objects into a list of JAXB objects for marshalling
+ List<PDElement> pvList =
+ MethodMarshallerUtils.getPDElements(pds,
+ signatureArgs,
+ false, // output
+ true, // use partName since this is rpc/lit
+ true); // forceXSI since this is rpc/lit
+
+ // Put values onto the message
+ MethodMarshallerUtils.toMessage(pvList, m, packages);
+
+ return m;
} catch(Exception e) {
throw ExceptionFactory.makeWebServiceException(e);
}
}
- public Message marshalRequest(Object[] object) throws WebServiceException {
+
+ public Object demarshalResponse(Message message, Object[] signatureArgs)
+ throws WebServiceException {
// Note all exceptions are caught and rethrown with a WebServiceException
try {
- // TODO Add Real Code
- throw new UnsupportedOperationException();
+ // Sample RPC message
+ // ..
+ // <soapenv:body>
+ // <m:opResponse xmlns:m="urn://api">
+ // <m:param xsi:type="data:foo" xmlns:data="urn://mydata" >...</m:param>
+ // </m:op>
+ // </soapenv:body>
+ //
+ // Important points.
+ // 1) RPC has an operation element under the body. This is the name of the
+ // wsdl operation.
+ // 2) The data blocks are located underneath the operation element. (In doc/lit
+ // the data elements are underneath the body.
+ // 3) The name of the data blocks (m:param) are defined by the wsdl:part not the
+ // schema.
+ // 4) The type of the data block (data:foo) is defined by schema (thus there is
+ // JAXB type rendering.
+ // 5) We always send an xsi:type, but other vendor's may not.
+ // Get the operation information
+ ParameterDescription[] pds =operationDesc.getParameterDescriptions();
+ Set<Package> packages = endpointDesc.getPackages();
+
+ // Indicate that the style is RPC. This is important so that the message understands
+ // that the data blocks are underneath the operation element
+ message.setStyle(Style.RPC);
+
+ // Get the return value.
+ Class returnType = MethodMarshallerUtils.getActualReturnType(operationDesc);
+ Object returnValue = null;
+ if (returnType != void.class) {
+ returnValue = MethodMarshallerUtils.getReturnValue(packages, message);
+ }
+
+ // Unmarshall the ParamValues from the Message
+ List<PDElement> pvList = MethodMarshallerUtils.getPDElements(pds, message, packages, false, true);
+
+ // Populate the response Holders
+ MethodMarshallerUtils.updateResponseSignatureArgs(pds, pvList, signatureArgs);
+
+ return returnValue;
} catch(Exception e) {
throw ExceptionFactory.makeWebServiceException(e);
}
@@ -96,18 +280,27 @@
public Message marshalFaultResponse(Throwable throwable) throws WebServiceException {
// Note all exceptions are caught and rethrown with a WebServiceException
try {
- // TODO Add Real Code
- throw new UnsupportedOperationException();
+ // Create the message
+ MessageFactory mf = (MessageFactory)FactoryRegistry.getFactory(MessageFactory.class);
+ Message m = mf.create(protocol);
+
+ // Put the fault onto the message
+ MethodMarshallerUtils.marshalFaultResponse(throwable,
+ operationDesc,
+ endpointDesc.getPackages(),
+ m,
+ true); // always marshal xsi:type if rpc/lit
+ return m;
} catch(Exception e) {
throw ExceptionFactory.makeWebServiceException(e);
}
}
- public Object demarshalFaultResponse(Message message) throws WebServiceException {
+ public Throwable demarshalFaultResponse(Message message) throws WebServiceException {
// Note all exceptions are caught and rethrown with a WebServiceException
try {
- // TODO Add Real Code
- throw new UnsupportedOperationException();
+ Throwable t = MethodMarshallerUtils.demarshalFaultResponse(operationDesc, endpointDesc.getPackages(), message, true);
+ return t;
} catch(Exception e) {
throw ExceptionFactory.makeWebServiceException(e);
}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/JAXBBlockFactoryImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/JAXBBlockFactoryImpl.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/JAXBBlockFactoryImpl.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/JAXBBlockFactoryImpl.java Thu Nov 16 20:01:48 2006
@@ -29,7 +29,7 @@
import org.apache.axis2.jaxws.message.databinding.JAXBBlockContext;
import org.apache.axis2.jaxws.message.factory.JAXBBlockFactory;
import org.apache.axis2.jaxws.message.impl.BlockFactoryImpl;
-import org.apache.axis2.jaxws.util.ClassUtils;
+import org.apache.axis2.jaxws.util.XMLRootElementUtil;
/**
* JAXBBlockFactoryImpl
@@ -77,7 +77,7 @@
// The business object must be either a JAXBElement or a block with an @XmlRootElement qname. The best way
// to verify this is to get the QName from the business object.
- QName bQName = ClassUtils.getXmlRootElementQName(businessObject);
+ QName bQName = XMLRootElementUtil.getXmlRootElementQName(businessObject);
if (bQName == null) {
throw ExceptionFactory.makeMessageException(Messages.getMessage("JAXBBlockFactoryErr2", businessObject.getClass().getName()), null);
}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/JAXBBlockImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/JAXBBlockImpl.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/JAXBBlockImpl.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/JAXBBlockImpl.java Thu Nov 16 20:01:48 2006
@@ -44,7 +44,7 @@
import org.apache.axis2.jaxws.message.databinding.JAXBUtils;
import org.apache.axis2.jaxws.message.factory.BlockFactory;
import org.apache.axis2.jaxws.message.impl.BlockImpl;
-import org.apache.axis2.jaxws.util.ClassUtils;
+import org.apache.axis2.jaxws.util.XMLRootElementUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -110,7 +110,7 @@
jaxb = u.unmarshal(reader);
// Set the qname
- QName qName = ClassUtils.getXmlRootElementQName(jaxb);
+ QName qName = XMLRootElementUtil.getXmlRootElementQName(jaxb);
if (qName != null) { // qname should always be non-null
setQName(qName);
}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/util/MessageUtils.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/util/MessageUtils.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/util/MessageUtils.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/util/MessageUtils.java Thu Nov 16 20:01:48 2006
@@ -96,7 +96,7 @@
equals(e.getNamespace().getNamespaceURI())) {
return OMAbstractFactory.getSOAP11Factory();
} else {
- return OMAbstractFactory.getSOAP11Factory();
+ return OMAbstractFactory.getSOAP12Factory();
}
}
return null;
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/JAXWSMessageReceiver.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/JAXWSMessageReceiver.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/JAXWSMessageReceiver.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/JAXWSMessageReceiver.java Thu Nov 16 20:01:48 2006
@@ -124,7 +124,6 @@
}
} catch (Exception e) {
- // TODO NLS
ThreadContextMigratorUtil.performThreadCleanup(Constants.THREAD_CONTEXT_MIGRATOR_LIST_ID, axisRequestMsgCtx);
throw ExceptionFactory.makeWebServiceException(e);
}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaBeanDispatcher.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaBeanDispatcher.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaBeanDispatcher.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaBeanDispatcher.java Thu Nov 16 20:01:48 2006
@@ -80,6 +80,19 @@
response = target.invoke(serviceInstance, methodInputParams);
} catch (Exception e) {
response = e;
+ if (log.isDebugEnabled()) {
+ log.debug("Exception invoking a method of " +
+ serviceImplClass.toString() + " of instance " +
+ serviceInstance.toString());
+
+ log.debug("Method = " + target.toGenericString());
+
+ for (int i=0; i<methodInputParams.length; i++) {
+ String value = (methodInputParams[i] == null) ? "null" :
+ methodInputParams[i].getClass().toString();
+ log.debug(" Argument[" + i +"] is " + value);
+ }
+ }
}
Message message = null;
@@ -203,12 +216,12 @@
parameterStyle = javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED;
}
return cf.createMethodMarshaller(Style.DOCUMENT, parameterStyle,
- serviceDesc, endpointDesc, operationDesc, protocol);
+ serviceDesc, endpointDesc, operationDesc, protocol, false);
}
private MethodMarshaller createRPCLitMessageConvertor(MethodMarshallerFactory cf, Protocol protocol){
return cf.createMethodMarshaller(Style.RPC, ParameterStyle.WRAPPED,
- serviceDesc, endpointDesc, operationDesc, protocol);
+ serviceDesc, endpointDesc, operationDesc, protocol, false);
}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/util/ClassUtils.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/util/ClassUtils.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/util/ClassUtils.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/util/ClassUtils.java Thu Nov 16 20:01:48 2006
@@ -29,10 +29,6 @@
import java.util.List;
import javax.jws.WebService;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchema;
-import javax.xml.namespace.QName;
import javax.xml.ws.Holder;
import javax.xml.ws.WebFault;
import javax.xml.ws.WebServiceClient;
@@ -331,6 +327,10 @@
* @return true if this is a JAX-WS or JAX-WS generated class
*/
public static final boolean isJAXWSClass(Class cls) {
+ // TODO Processing all of these annotations is very expensive. We need to cache the
+ // result in a static WeakHashMap<Class, Boolean>
+
+
// Kinds of generated classes: Service, Provider, Impl, Exception, Holder
// Or the class is in the jaxws.xml.ws package
@@ -367,65 +367,6 @@
return true;
}
return false;
- }
-
-
- /**
- * @param clazz
- * @return namespace of root element qname or null if this is not object does not represent a root element
- */
- public static QName getXmlRootElementQName(Object obj){
-
- // A JAXBElement stores its name
- if (obj instanceof JAXBElement) {
- return ((JAXBElement) obj).getName();
- }
-
- Class clazz = obj.getClass();
-
- // If the clazz is a primitive, then it does not have a corresponding root element.
- if (clazz.isPrimitive() ||
- getWrapperClass(clazz) != null) {
- return null;
- }
-
- // See if the object represents a root element
- XmlRootElement root = (XmlRootElement) clazz.getAnnotation(XmlRootElement.class);
- if (root == null) {
- return null;
- }
-
- String namespace = root.namespace();
- String localPart = root.name();
-
- // The namespace may need to be defaulted
- if (namespace == null || namespace.length() == 0 || namespace.equals("##default")) {
- Package pkg = clazz.getPackage();
- XmlSchema schema = (XmlSchema) pkg.getAnnotation(XmlSchema.class);
- if (schema != null) {
- namespace = schema.namespace();
- } else {
- return null;
- }
- }
- return new QName(namespace, localPart);
- }
-
- /**
- * @param clazz
- * @return true if this class has a corresponding xml root element
- */
- public static boolean isXmlRootElementDefined(Class clazz){
- // If the clazz is a primitive, then it does not have a corresponding root element.
- if (clazz.isPrimitive() ||
- getWrapperClass(clazz) != null) {
- return false;
- }
- // TODO We could also prune out other known classes that will not have root elements defined.
- // java.util.Date, arrays, java.math.BigInteger.
-
- XmlRootElement root = (XmlRootElement) clazz.getAnnotation(XmlRootElement.class);
- return root !=null;
}
}
Added: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/util/XMLRootElementUtil.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/util/XMLRootElementUtil.java?view=auto&rev=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/util/XMLRootElementUtil.java (added)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/util/XMLRootElementUtil.java Thu Nov 16 20:01:48 2006
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2004,2005 The Apache Software Foundation.
+ * Copyright 2006 International Business Machines Corp.
+ *
+ * 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.apache.axis2.jaxws.util;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchema;
+import javax.xml.namespace.QName;
+
+/**
+ * This utility contains code to determine if an Object is
+ * "element enabled" or "type enabled".
+ *
+ * Here is an example for illustration:
+ * <element name='e1'>
+ * <complexType>...</complexType>
+ * </element>
+ *
+ * <element name='e2' type='t2' />
+ * <complexType name= 't2'>..
+ *
+ * <element name='e3' type='e3' /> <!-- note element and type have same name -->
+ * <complexType name= 'e3'>..
+ *
+ * JAXB will generate the following objects: E1, T2, E3
+ * E1 will have an @XMLRootElement annotation. It is "element" and "type" enabled.
+ * e2 does not have a generated object. So it will be represented as a JAXBElement
+ * that contains an object T2. The JAXBElement is "element" enabled.
+ * T2 represents a complexType. It is only "type" enabled.
+ * E3 represents the e3 complexType (it does not represent the e3 element). Thus E3
+ * is "type enabled".
+ *
+ * When JAXB unmarshals an object, it will return an "element" enabled object (either
+ * a generatated object with @XMLRootElement or a JAXBElement).
+ * Conversely, you must always marshal "element" enabled objects.
+ * @see org.apache.axis2.jaxws.marshaller.impl.alt.PDElement
+ *
+ * At the signature level, the values passed as arguments in an SEI operation represent
+ * type enabled objects. Each of the object must be converted to an element enabled object
+ * to marshal (or conversely converted to a type enabled object when unmarshalling)
+ *
+ * -----------------------------------------
+ * There are other simular utility methods in this class. Including utilities to get
+ * a xml name -> bean property map.
+ *
+ * -----------------------------------------
+ *
+ * @TODO A secondary reason usage of XMLRootElementUtil is to isolate all of the
+ * @XMLRootElement and related annotation queries. Annotation queries are expensive.
+ * A follow-on version of this class will cache the results so that we can improve performance.
+ *
+ */
+public class XMLRootElementUtil {
+
+ /**
+ * Constructor is intentionally private. This class only provides static utility methods
+ */
+ private XMLRootElementUtil() {
+
+ }
+
+ /**
+ * Return true if this class is element enabled
+ * @param clazz
+ * @return true if this class has a corresponding xml root element
+ */
+ public static boolean isElementEnabled(Class clazz){
+ if (clazz.equals(JAXBElement.class)) {
+ return true;
+ }
+
+ // If the clazz is a primitive, then it does not have a corresponding root element.
+ if (clazz.isPrimitive() || ClassUtils.getWrapperClass(clazz) != null) {
+ return false;
+ }
+
+ // Presence of an annotation means that it can be rendered as a root element
+ XmlRootElement root = (XmlRootElement) clazz.getAnnotation(XmlRootElement.class);
+ return root !=null;
+ }
+
+ /**
+ * Returns ture if this class is type enabled
+ * @param clazz
+ * @return
+ */
+ public static boolean isTypeEnabled(Class clazz) {
+ // Primitives, Primitive wrappers, BigDecimal, etc. are all type enabled
+ // So are all classes with @XmlRootElement or @XmlType.
+ // For now I am only going to assume that the class is type enabled unless it is JAXBElement
+ return (!clazz.equals(JAXBElement.class));
+ }
+
+ /**
+ * Return type enabled object
+ * @param obj type or element enabled object
+ * @return type enabled object
+ */
+ public static Object getTypeEnabledObject(Object obj) {
+ if (obj == null) {
+ return null;
+ }
+ if (obj instanceof JAXBElement) {
+ return ((JAXBElement) obj).getValue();
+ }
+ return obj;
+ }
+
+ /**
+ * Return an object that can be marshalled/unmarshalled as an element
+ * If the specified object is already element enabled, it is returned.
+ * @param namespace
+ * @param localPart
+ * @param cls either the class or super class of obj
+ * @param type element or type enabled object
+ * @return
+ */
+ public static Object getElementEnabledObject(String namespace, String localPart, Class cls, Object obj, boolean forceXSIType) {
+ if (obj != null && isElementEnabled(obj.getClass())) {
+ return obj;
+ }
+
+ QName qName = new QName(namespace, localPart);
+
+ // I think the way to force an xsi:type is to use Object as the class
+ if (forceXSIType) {
+ cls = Object.class;
+ }
+ JAXBElement element = new JAXBElement(qName, cls, obj);
+ return element;
+ }
+
+
+
+ /**
+ * @param clazz
+ * @return namespace of root element qname or null if this is not object does not represent a root element
+ */
+ public static QName getXmlRootElementQName(Object obj){
+
+ // A JAXBElement stores its name
+ if (obj instanceof JAXBElement) {
+ return ((JAXBElement) obj).getName();
+ }
+
+ Class clazz = obj.getClass();
+
+ // If the clazz is a primitive, then it does not have a corresponding root element.
+ if (clazz.isPrimitive() ||
+ ClassUtils.getWrapperClass(clazz) != null) {
+ return null;
+ }
+
+ // See if the object represents a root element
+ XmlRootElement root = (XmlRootElement) clazz.getAnnotation(XmlRootElement.class);
+ if (root == null) {
+ return null;
+ }
+
+ String namespace = root.namespace();
+ String localPart = root.name();
+
+ // The namespace may need to be defaulted
+ if (namespace == null || namespace.length() == 0 || namespace.equals("##default")) {
+ Package pkg = clazz.getPackage();
+ XmlSchema schema = (XmlSchema) pkg.getAnnotation(XmlSchema.class);
+ if (schema != null) {
+ namespace = schema.namespace();
+ } else {
+ return null;
+ }
+ }
+ return new QName(namespace, localPart);
+ }
+
+
+ /**
+ * The JAXBClass has a set of bean properties each represented by a PropertyDescriptor
+ * Each of the fields of the class has an associated xml name.
+ * The method returns a map where the key is the xml name and value is the PropertyDescriptor
+ * @param jaxbClass
+ * @return map
+ */
+ public static Map<String, PropertyDescriptor> createPropertyDescriptorMap(Class jaxbClass) throws NoSuchFieldException, IntrospectionException {
+
+ // TODO This is a very performance intensive search we should cache the calculated map keyed by the jaxbClass
+
+ PropertyDescriptor[] pds = Introspector.getBeanInfo(jaxbClass).getPropertyDescriptors();
+ // Make this a weak map in case we want to cache the resolts
+ Map<String, PropertyDescriptor> map = new WeakHashMap<String, PropertyDescriptor>();
+
+ // Unfortunately the element names are stored on the fields.
+ // Therefore we need to to match up the field and property descriptor
+ Field[] fields = jaxbClass.getDeclaredFields();
+ for(PropertyDescriptor pd:pds){
+ for(Field field:fields){
+ String fieldName = field.getName();
+
+ // Use the name of the field and property to find the match
+ if (fieldName.equalsIgnoreCase(pd.getDisplayName()) ||
+ fieldName.equalsIgnoreCase(pd.getName()) ) {
+ // Get the xmlElement name for this field
+ String xmlName =getXmlElementName(jaxbClass, field);
+ map.put(xmlName, pd);
+ break;
+ }
+
+ // Unfortunately, sometimes the field name is preceeded by an underscore
+ if (fieldName.startsWith("_")) {
+ fieldName = fieldName.substring(1);
+ if (fieldName.equalsIgnoreCase(pd.getDisplayName()) ||
+ fieldName.equalsIgnoreCase(pd.getName())) {
+ // Get the xmlElement name for this field
+ String xmlName =getXmlElementName(jaxbClass, field);
+ map.put(xmlName, pd);
+ break;
+ }
+ }
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Get the name of the field by looking at the XmlElement annotation.
+ * @param jaxbClass
+ * @param fieldName
+ * @return
+ * @throws NoSuchFieldException
+ */
+ private static String getXmlElementName(Class jaxbClass, Field field)throws NoSuchFieldException{
+ XmlElement xmlElement =field.getAnnotation(XmlElement.class);
+
+
+ // If XmlElement does not exist, default to using the field name
+ if (xmlElement == null ||
+ xmlElement.name().equals("##default")) {
+ return field.getName();
+ }
+ return xmlElement.name();
+
+ }
+
+
+
+}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/JAXBWrapperTool.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/JAXBWrapperTool.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/JAXBWrapperTool.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/JAXBWrapperTool.java Thu Nov 16 20:01:48 2006
@@ -17,7 +17,7 @@
package org.apache.axis2.jaxws.wrapper;
-import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import org.apache.axis2.jaxws.wrapper.impl.JAXBWrapperException;
@@ -34,9 +34,9 @@
* @param jaxbObject that is the wrapper element (JAXBElement or object with @XMLRootElement)
* @param jaxbContext JAXBContext
* @param childNames list of xml child names as String
- * @return list of Objects in the same order as the element names.
+ * @return list of Objects in the same order as the element names.
*/
- public Object[] unWrap(Object jaxbObject, ArrayList<String> childNames) throws JAXBWrapperException;
+ public Object[] unWrap(Object jaxbObject, List<String> childNames) throws JAXBWrapperException;
/**
@@ -46,11 +46,10 @@
* Note that the jaxbClass must be the class the represents the complexType. (It should never be JAXBElement)
*
* @param jaxbClass
- * @param childObjects, component objects
+ * @param childObjects, component type objects
* @param childNames list of xml child names as String
- * @return list of Objects in the same order as the element names.
*/
- public Object wrap(Class jaxbClass, ArrayList<String> childNames, Map<String, Object> childObjects) throws JAXBWrapperException;
+ public Object wrap(Class jaxbClass, List<String> childNames, Map<String, Object> childObjects) throws JAXBWrapperException;
}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/impl/JAXBWrapperToolImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/impl/JAXBWrapperToolImpl.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/impl/JAXBWrapperToolImpl.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/impl/JAXBWrapperToolImpl.java Thu Nov 16 20:01:48 2006
@@ -23,6 +23,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -30,6 +31,7 @@
import javax.xml.bind.annotation.XmlElement;
import org.apache.axis2.jaxws.i18n.Messages;
+import org.apache.axis2.jaxws.util.XMLRootElementUtil;
import org.apache.axis2.jaxws.wrapper.JAXBWrapperTool;
@@ -45,7 +47,7 @@
*/
public Object[] unWrap(Object jaxbObject,
- ArrayList<String> childNames) throws JAXBWrapperException{
+ List<String> childNames) throws JAXBWrapperException{
try{
if(jaxbObject == null){
throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr1"));
@@ -54,6 +56,7 @@
throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr2"));
}
+ // Review: I think that we can remove the next statement. This is an assertion of the tool
// Get the object that will have the property descriptors (i.e. the object representing the complexType)
Object jaxbComplexTypeObj = (jaxbObject instanceof JAXBElement) ?
((JAXBElement)jaxbObject).getValue() : // Type object is the value of the JAXBElement
@@ -84,7 +87,7 @@
* @see org.apache.axis2.jaxws.wrapped.JAXBWrapperTool#wrap(java.lang.Class, java.lang.String, java.util.ArrayList, java.util.ArrayList)
*/
public Object wrap(Class jaxbClass,
- ArrayList<String> childNames, Map<String, Object> childObjects)
+ List<String> childNames, Map<String, Object> childObjects)
throws JAXBWrapperException {
try{
@@ -120,91 +123,40 @@
* childName if not use xmlElement annotation name and create PropertyInfo add childName or xmlElement name there, set propertyDescriptor
* and return Map<ChileName, PropertyInfo>.
* @param jaxbClass - Class jaxbClass name
- * @param childNames - ArrayList<String> of childNames
+ * @param childNames - ArrayList<String> of xml childNames
* @return Map<String, PropertyInfo> - map of ChildNames that map to PropertyInfo that hold the propertyName and PropertyDescriptor.
* @throws IntrospectionException, NoSuchFieldException
*/
- private Map<String, PropertyInfo> createPropertyDescriptors(Class jaxbClass, ArrayList<String> childNames) throws IntrospectionException, NoSuchFieldException, JAXBWrapperException{
+ private Map<String, PropertyInfo> createPropertyDescriptors(Class jaxbClass, List<String> childNames) throws IntrospectionException, NoSuchFieldException, JAXBWrapperException{
Map<String, PropertyInfo> map = new WeakHashMap<String, PropertyInfo>();
- PropertyDescriptor[] pds = Introspector.getBeanInfo(jaxbClass).getPropertyDescriptors();
- Map<String, PropertyDescriptor> jaxbClassPds = filterDescriptors(pds, jaxbClass);
+
+ Map<String, PropertyDescriptor> pdMap = XMLRootElementUtil.createPropertyDescriptorMap(jaxbClass);
Field field[] = jaxbClass.getDeclaredFields();
- if(field.length != childNames.size()){
+
+ // It is possible the that the number of fields is greater than the number of child elements due
+ // to customizations.
+ if(field.length < childNames.size()){
throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr4", jaxbClass.getName()));
}
- pds=null;
+
+
+ // Create property infos for each class name
+ for (int i=0; i<childNames.size(); i++) {
+ PropertyInfo propInfo= null;
+ String childName = childNames.get(i);
+ PropertyDescriptor pd = pdMap.get(childName);
+ if(pd == null){
+ throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr6", jaxbClass.getName(), childName));
+ }
+ propInfo = new PropertyInfo(pd);
+ map.put(childName, propInfo);
+ }
+
- for(int i=0; i<field.length ;i++){
- PropertyInfo propInfo= null;
- String fieldName = field[i].getName();
- String childName = childNames.get(i);
- PropertyDescriptor pd = jaxbClassPds.get(childName);
- if(pd == null){
- pd = jaxbClassPds.get(fieldName);
- if(pd == null){
- throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr4", jaxbClass.getName(), childName));
- }
- }
- propInfo = new PropertyInfo(fieldName, pd);
- map.put(childName, propInfo);
- }
- jaxbClassPds = null;
- field = null;
return map;
}
- /** Filter PropertyDescriptors that belong to super class, return only the ones that belong to JABXClass
- * create map of java fieldName and propertyDescriptor, if propertyName different than java fieldName then
- * check the xmlElementName ensure they are same if not do conver both xmlName and propertyName to lowercase and
- * ensure they are same if they match then add the corrosponding javaFieldName and PropertyDescriptor in map. If they dont
- * match the propertyName belongs to super class and we ignore it.
- * @param allPds
- * @param jaxbClass
- * @return
- */
- private Map<String, PropertyDescriptor> filterDescriptors(PropertyDescriptor[] allPds, Class jaxbClass) throws NoSuchFieldException{
- Map<String, PropertyDescriptor> filteredPds = new WeakHashMap<String, PropertyDescriptor>();
- Field[] fields = jaxbClass.getDeclaredFields();
- for(PropertyDescriptor pd:allPds){
- for(Field field:fields){
- if(field.getName().equals(pd.getDisplayName())){
- filteredPds.put(pd.getDisplayName(), pd);
- break;
- }else{
- String xmlName =getXmlElementName(jaxbClass, field.getName());
- if(xmlName.equals(pd.getDisplayName())){
- filteredPds.put(field.getName(), pd);
- break;
- }
- if(xmlName.toLowerCase().equals(pd.getDisplayName().toLowerCase())){
- filteredPds.put(field.getName(), pd);
- break;
- }
- }
- }
- }
- allPds=null;
- return filteredPds;
- }
- /**
- * Get the name of the xml element by looking at the XmlElement annotation.
- * @param jaxbClass
- * @param fieldName
- * @return
- * @throws NoSuchFieldException
- */
- private String getXmlElementName(Class jaxbClass, String fieldName)throws NoSuchFieldException{
- Field field = jaxbClass.getDeclaredField(fieldName);
- XmlElement xmlElement =field.getAnnotation(XmlElement.class);
-
- // If XmlElement does not exist, default to using the field name
- if (xmlElement == null) {
- return fieldName;
- }
- return xmlElement.name();
-
- }
}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/impl/PropertyInfo.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/impl/PropertyInfo.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/impl/PropertyInfo.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/wrapper/impl/PropertyInfo.java Thu Nov 16 20:01:48 2006
@@ -25,30 +25,44 @@
import org.apache.commons.logging.LogFactory;
+/**
+ * A PropertyInfo is constructed with a PropertyDescriptor and
+ * exposes get/set methods to access the object on a bean that matches the PropertyDescriptor
+ *
+ */
public class PropertyInfo {
- String propertyName;
PropertyDescriptor descriptor;
private static Log log = LogFactory.getLog(PropertyInfo.class);
/**
* @param propertyName
* @param descriptor
*/
- public PropertyInfo(String propertyName, PropertyDescriptor descriptor) {
+ public PropertyInfo(PropertyDescriptor descriptor) {
super();
-
- this.propertyName = propertyName;
this.descriptor = descriptor;
}
- public String getPropertyName(){
- return this.propertyName;
- }
+ /**
+ * Get the object
+ * @param targetBean
+ * @return Object for this property or null
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ */
public Object get(Object targetBean)throws InvocationTargetException, IllegalAccessException{
Method method = descriptor.getReadMethod();
return method.invoke(targetBean, null);
}
+ /**
+ * Set the object
+ * @param targetBean
+ * @param propValue
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws JAXBWrapperException
+ */
public void set(Object targetBean, Object propValue)throws InvocationTargetException, IllegalAccessException, JAXBWrapperException{
Method method = descriptor.getWriteMethod();
Object[] object = new Object[]{propValue};
Modified: webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/message/MessageRPCTests.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/message/MessageRPCTests.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/message/MessageRPCTests.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/message/MessageRPCTests.java Thu Nov 16 20:01:48 2006
@@ -300,7 +300,11 @@
// Check to make sure the right object was returned
assertNotNull(bo);
+ if (bo instanceof JAXBElement) {
+ bo = ((JAXBElement) bo).getValue();
+ }
assertTrue(bo instanceof StockPrice);
+
// Check to make sure the content of that object is correct
StockPrice obj = (StockPrice) bo;
Modified: webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/sample/AddressBookTests.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/sample/AddressBookTests.java?view=diff&rev=476045&r1=476044&r2=476045
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/sample/AddressBookTests.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/sample/AddressBookTests.java Thu Nov 16 20:01:48 2006
@@ -49,6 +49,7 @@
* Test the endpoint by invoking it with a JAX-WS Dispatch.
*/
public void testAddressBookWithDispatch() throws Exception {
+ try {
System.out.println("----------------------------------");
System.out.println("test: " + getName());
@@ -80,6 +81,10 @@
assertTrue(response.isStatus());
System.out.println("[pass] - valid response received");
System.out.println("[response] - " + response.isStatus());
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ }
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: axis-cvs-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-cvs-help@ws.apache.org