You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beehive.apache.org by ek...@apache.org on 2005/06/08 03:39:58 UTC

svn commit: r189487 [1/2] - in /incubator/beehive/trunk/wsm: drt/tests/org/apache/beehive/wsm/axis/handlers/ drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/ src/runtime/org/apache/beehive/wsm/axis/

Author: ekoneil
Date: Tue Jun  7 18:39:57 2005
New Revision: 189487

URL: http://svn.apache.org/viewcvs?rev=189487&view=rev
Log:
Commit patch for JIRA 717 contributed by Daryoush Mehrtash.

This patch provides the AxisFaultAdaptor class for converting Exceptions thrown during Beehive WSM web service execution into something that looks like an AxisFault.

The commit is slightly different from the patch in the following ways:

- removes unused imports from AnnotatedWebServiceDeploymentHandlerTest
- removes the .java file name in one of the Exceptions
- adds an assert in the place of a defensive instanceof check in ControlProvider
- adds asserts in AxisFaultAdaptor

BB: self
DRT: WSM / service control pass


Added:
    incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/FaultTest.java   (with props)
    incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/ComplexUserDefinedException.java   (with props)
    incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/SimpleUserDefinedException.java   (with props)
    incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisFaultAdaptor.java   (with props)
Modified:
    incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/AnnotatedWebServiceDeploymentHandlerTest.java
    incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/FakeDocWebService.jws
    incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisHook.java
    incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/ControlProvider.java

Modified: incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/AnnotatedWebServiceDeploymentHandlerTest.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/AnnotatedWebServiceDeploymentHandlerTest.java?rev=189487&r1=189486&r2=189487&view=diff
==============================================================================
--- incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/AnnotatedWebServiceDeploymentHandlerTest.java (original)
+++ incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/AnnotatedWebServiceDeploymentHandlerTest.java Tue Jun  7 18:39:57 2005
@@ -17,6 +17,7 @@
  * 
  */
 import junit.framework.TestCase;
+
 import org.apache.axis.Message;
 import org.apache.axis.MessageContext;
 import org.apache.axis.handlers.soap.SOAPService;

Added: incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/FaultTest.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/FaultTest.java?rev=189487&view=auto
==============================================================================
--- incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/FaultTest.java (added)
+++ incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/FaultTest.java Tue Jun  7 18:39:57 2005
@@ -0,0 +1,177 @@
+package org.apache.beehive.wsm.axis.handlers;
+
+/*
+ * 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.
+ * 
+ */
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.Detail;
+import javax.xml.soap.DetailEntry;
+import org.apache.axis.message.SOAPFault;
+
+import junit.framework.TestCase;
+
+import org.apache.axis.AxisFault;
+import org.apache.axis.Message;
+import org.apache.axis.MessageContext;
+import org.apache.axis.handlers.soap.SOAPService;
+import org.apache.axis.message.MessageElement;
+import org.apache.axis.message.RPCElement;
+import org.apache.axis.message.SOAPEnvelope;
+import org.apache.axis.server.AxisServer;
+import org.apache.beehive.wsm.wsdl.WSDLProcessor;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xmlsoap.schemas.wsdl.DefinitionsDocument;
+import org.xmlsoap.schemas.wsdl.TBinding;
+import org.xmlsoap.schemas.wsdl.TBindingOperation;
+import org.xmlsoap.schemas.wsdl.TDefinitions;
+import org.xmlsoap.schemas.wsdl.TService;
+import org.xmlsoap.schemas.wsdl.soap.TOperation;
+import org.xmlsoap.schemas.wsdl.soap.TStyleChoice;
+
+public class FaultTest extends TestCase {
+
+    SOAPService fakeSOAPService;
+
+    public void setUp() throws Exception {
+        final String classname = "org.apache.beehive.wsm.axis.FakeDocWebService";
+        AnnotatedWebServiceDeploymentHandler hdlr = new AnnotatedWebServiceDeploymentHandler();
+        Class clazz = Class.forName(classname);
+        fakeSOAPService = hdlr.getSOAPService(clazz);
+    }
+
+    public void tearDown() {
+        // empty
+    }
+
+    public void testSimpleUserDefinedExceptions() throws Exception {
+
+        MessageContext mc = new MessageContext(new AxisServer());
+        SOAPEnvelope env = new SOAPEnvelope();
+        env.addBodyElement(new RPCElement("doThrowSimpleUserDefinedFault"));
+        mc.setRequestMessage(new Message(env));
+        mc.setService(fakeSOAPService);
+        try {
+            fakeSOAPService.invoke(mc);
+            fail("The Expected exception didn't happen!");
+        } catch (AxisFault e) {
+        } // expected a fault
+        Message msg = mc.getResponseMessage();
+        msg.saveChanges();
+        assertNotNull(msg);
+        if (null != msg) {
+            SOAPFault n = (SOAPFault) msg.getSOAPBody().getFirstChild();
+            MessageElement detail = n.getChildElement(new QName("detail"));
+
+            for (Iterator it = detail.getChildElements(); it.hasNext();) {
+                Element de = (Element) it.next();
+                String localName = de.getLocalName();
+                String namespace = de.getNamespaceURI();
+                if (localName.equals("SimpleUserDefinedExceptionFault")
+                        && namespace.equals("http://fake.target.namespace/")) {
+                    NodeList nl = de.getChildNodes();
+                    assertTrue(nl.getLength() == 0);
+                    return;
+                }
+            }
+            fail("Didn't find the exception name in the Fault detail");
+
+        }
+    }
+
+    public void testComplexUserDefinedExceptions() throws Exception {
+        MessageContext mc = new MessageContext(new AxisServer());
+        SOAPEnvelope env = new SOAPEnvelope();
+        env.addBodyElement(new RPCElement("doThrowComplexUserDefinedFault"));
+        mc.setRequestMessage(new Message(env));
+        mc.setService(fakeSOAPService);
+        try {
+            fakeSOAPService.invoke(mc);
+            fail("The Expected exception didn't happen!");
+        } catch (AxisFault e) {
+        } // expected a fault
+        Message msg = mc.getResponseMessage();
+        msg.saveChanges();
+        assertNotNull(msg);
+        if (null != msg) {
+            SOAPFault n = (SOAPFault) msg.getSOAPBody().getFirstChild();
+            MessageElement detail = n.getChildElement(new QName("detail"));
+
+            for (Iterator it = detail.getChildElements(); it.hasNext();) {
+                Element de = (Element) it.next();
+                String localName = de.getLocalName();
+                String namespace = de.getNamespaceURI();
+                if (localName.equals("ComplexUserDefinedExceptionFault")
+                        && namespace.equals("http://fake.target.namespace/")) {
+                    NodeList nl = de.getChildNodes();
+                    assertTrue(nl.getLength() == 2);
+
+                    // make sure both nodes are on right namespace
+                    Node firstNode = nl.item(0);
+                    assertTrue(firstNode.getNamespaceURI().equals(
+                            "http://fake.target.namespace/"));
+                    Node secondNode = nl.item(1);
+                    assertTrue(secondNode.getNamespaceURI().equals(
+                            "http://fake.target.namespace/"));
+                    // make sure the both attributes of the exception is
+                    // serialized
+                    assertTrue("str1".equals(firstNode.getLocalName())
+                            || "str1".equals(secondNode.getLocalName()));
+                    assertTrue("str2".equals(firstNode.getLocalName())
+                            || "str2".equals(secondNode.getLocalName()));
+                    return;
+                }
+                // TODO: Check the other elements in the fault
+            }
+            fail("Didn't find the exception name in the Fault detail");
+
+        }
+    }
+
+    public void testRuntimeExceptions() throws Exception {
+        MessageContext mc = new MessageContext(new AxisServer());
+        SOAPEnvelope env = new SOAPEnvelope();
+        env.addBodyElement(new RPCElement("doThrowRuntimeException"));
+        mc.setRequestMessage(new Message(env));
+        mc.setService(fakeSOAPService);
+        try {
+            fakeSOAPService.invoke(mc);
+            fail("The Expected exception didn't happen!");
+        } catch (AxisFault e) {
+        } // expected a fault
+        Message msg = mc.getResponseMessage();
+        msg.saveChanges();
+        assertNotNull(msg);
+        if (null != msg) {
+            SOAPFault f = (SOAPFault) msg.getSOAPBody().getFirstChild();
+            MessageElement faultString = f.getChildElement(new QName(
+                    "faultstring"));
+            // we should have
+            // <faultstring>java.lang.NullPointerException</faultstring>
+            //quick hack to validate the faultString is set correctly
+            // at this point I can't seem to walk the xml tree properly
+            // but the toString works on the element.
+            "<faultstring>java.lang.NullPointerException</faultstring>"
+                    .equals(faultString.toString());
+            // TODO: Check the other elements in the fault
+        }
+    }
+}

Propchange: incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/axis/handlers/FaultTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/ComplexUserDefinedException.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/ComplexUserDefinedException.java?rev=189487&view=auto
==============================================================================
--- incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/ComplexUserDefinedException.java (added)
+++ incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/ComplexUserDefinedException.java Tue Jun  7 18:39:57 2005
@@ -0,0 +1,50 @@
+package org.apache.beehive.wsm.axis;
+/*
+ * 
+ * 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.
+ * 
+ */
+
+public class ComplexUserDefinedException 
+    extends Exception 
+    implements java.io.Serializable {
+
+    private String str1;
+    private String str2;
+
+    public ComplexUserDefinedException(String str1, String str2 ) {
+        this.str1 = str1;
+        this.str2 = str2;
+    }
+
+    public String getStr1() {
+        return str1;
+    }
+    
+
+    public String getStr2() {
+        return str2;
+    }
+
+    public void setStr1(String str1) {
+        this.str1 = str1;
+    }
+    
+
+    public void setStr2(String str2) {
+        this.str2 = str2;
+    }
+}

Propchange: incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/ComplexUserDefinedException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/FakeDocWebService.jws
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/FakeDocWebService.jws?rev=189487&r1=189486&r2=189487&view=diff
==============================================================================
--- incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/FakeDocWebService.jws (original)
+++ incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/FakeDocWebService.jws Tue Jun  7 18:39:57 2005
@@ -1,51 +1,63 @@
-package org.apache.beehive.wsm.axis;
-
-/*
- * FakeDocWebService.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.
- * 
- */
-
-import javax.jws.Oneway;
-import javax.jws.WebMethod;
-import javax.jws.WebParam;
-import javax.jws.WebResult;
-import javax.jws.WebService;
-import javax.jws.soap.SOAPBinding;
-
-
-@WebService(
-    name = "FakeDocName",
-    serviceName = "FakeDocServiceName",
-    targetNamespace = "http://fake.target.namespace/")
-@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
-public class FakeDocWebService {
-
-    @WebMethod(action = "invocationAction")
-    @WebResult(
-        name = "invocationSucceeded",
-        targetNamespace = "http://result.target.namespace/")
-    public String doInvocation() {
-        return "true";
-    }
-
-    @WebMethod(operationName = "processThingy")
-    @Oneway
-    public void processModeratelyComplexObject(@WebParam(name = "thingy") ModeratelyComplexObject mco) {
-        // empty: return values not allowed for @Oneway
-    }
-}
+package org.apache.beehive.wsm.axis;
+
+/*
+ * 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.
+ * 
+ */
+
+import javax.jws.Oneway;
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.jws.WebService;
+import javax.jws.soap.SOAPBinding;
+
+
+@WebService(
+    name = "FakeDocName",
+    serviceName = "FakeDocServiceName",
+    targetNamespace = "http://fake.target.namespace/")
+@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
+public class FakeDocWebService {
+
+    @WebMethod(action = "invocationAction")
+    @WebResult(
+        name = "invocationSucceeded",
+        targetNamespace = "http://result.target.namespace/")
+    public String doInvocation() {
+        return "true";
+    }
+
+    @WebMethod(operationName = "processThingy")
+    @Oneway
+    public void processModeratelyComplexObject(@WebParam(name = "thingy") ModeratelyComplexObject mco) {
+        // empty: return values not allowed for @Oneway
+    }
+    
+    @WebMethod
+    public String doThrowSimpleUserDefinedFault()  throws SimpleUserDefinedException {
+        throw new SimpleUserDefinedException();
+    }
+    
+    @WebMethod
+    public String doThrowComplexUserDefinedFault()  throws SimpleUserDefinedException, ComplexUserDefinedException {
+        throw new ComplexUserDefinedException("FirstString", "SecondString");
+    }
+    
+    @WebMethod
+    public String doThrowRuntimeException()  throws SimpleUserDefinedException, ComplexUserDefinedException {
+        throw new java.lang.NullPointerException();
+    }
+}

Added: incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/SimpleUserDefinedException.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/SimpleUserDefinedException.java?rev=189487&view=auto
==============================================================================
--- incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/SimpleUserDefinedException.java (added)
+++ incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/SimpleUserDefinedException.java Tue Jun  7 18:39:57 2005
@@ -0,0 +1,25 @@
+package org.apache.beehive.wsm.axis;
+
+/*
+ * 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.
+ * 
+ */
+public class SimpleUserDefinedException extends Exception implements
+        java.io.Serializable {
+
+    public SimpleUserDefinedException() {
+    }
+}

Propchange: incubator/beehive/trunk/wsm/drt/webapp/WEB-INF/src/org/apache/beehive/wsm/axis/SimpleUserDefinedException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisFaultAdaptor.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisFaultAdaptor.java?rev=189487&view=auto
==============================================================================
--- incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisFaultAdaptor.java (added)
+++ incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisFaultAdaptor.java Tue Jun  7 18:39:57 2005
@@ -0,0 +1,85 @@
+package org.apache.beehive.wsm.axis;
+/*
+ * 
+ * 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.
+ * 
+ * 
+ */
+import java.util.ArrayList;
+import javax.xml.namespace.QName;
+
+import org.apache.axis.AxisFault;
+import org.apache.axis.Constants;
+import org.apache.axis.MessageContext;
+import org.apache.axis.description.FaultDesc;
+import org.apache.axis.description.ParameterDesc;
+
+/**
+ * <p>
+ * This class is an adapter for handling exceptions generated while running a Beehive
+ * WSM web service and converting those exceptions into AxisFaults.
+ * </p>
+ * <p>
+ * Axis seems to only work well with AxisFaults.  Application level faults work ok
+ * for the WSDL but Axis doesn't generate the correct Fault Message for them.  To
+ * fix this problem, the Adaptor class exposes the AxisFault API but uses TypeMapping
+ * to perform serialization.
+ * </p>
+ */
+public class AxisFaultAdaptor extends AxisFault {
+
+    private transient MessageContext msgContext;
+
+    private transient Throwable origExp;
+
+    public AxisFaultAdaptor(MessageContext msgContext, Throwable origExp) {
+        this.msgContext = msgContext;
+
+        /* todo: why is the origExp set twice as this.origExp and detail? */
+        this.origExp = origExp;
+        detail = origExp;
+
+        removeFaultDetail(Constants.QNAME_FAULTDETAIL_EXCEPTIONNAME);
+        addFaultDetail(Constants.QNAME_FAULTDETAIL_EXCEPTIONNAME, origExp.getClass().getName());
+
+        // add the hostname
+        addHostnameIfNeeded();
+    }
+
+    /**
+     * Writes the exception data to the faultDetails
+     */
+    public void writeDetails(javax.xml.namespace.QName qname, org.apache.axis.encoding.SerializationContext context)
+        throws java.io.IOException {
+        FaultDesc fd = null;
+        QName faultQname = null;
+
+        assert msgContext != null : "Found null MessageContext";
+        fd = msgContext.getOperation().getFaultByClass(origExp.getClass());
+        assert fd != null : "Received null FaultDesc";
+
+        ArrayList parameters = fd.getParameters();
+        if (parameters != null) {
+            ParameterDesc parameter = (ParameterDesc) parameters.get(0);
+            if(parameter != null)
+                faultQname = parameter.getQName();
+        }
+        if( faultQname == null)
+            faultQname = fd.getQName();
+
+        context.serialize(faultQname, null, origExp);
+    }
+}

Propchange: incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisFaultAdaptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisHook.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisHook.java?rev=189487&r1=189486&r2=189487&view=diff
==============================================================================
--- incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisHook.java (original)
+++ incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/axis/AxisHook.java Tue Jun  7 18:39:57 2005
@@ -1,599 +1,632 @@
-/*
- * 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.
- */
-package org.apache.beehive.wsm.axis;
-
-import java.io.File;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.rmi.Remote;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import javax.jws.WebParam;
-import javax.jws.soap.SOAPBinding;
-import javax.wsdl.OperationType;
-import javax.xml.namespace.QName;
-import javax.xml.rpc.holders.Holder;
-
-import org.apache.axis.constants.Style;
-import org.apache.axis.constants.Use;
-import org.apache.axis.description.ElementDesc;
-import org.apache.axis.description.FaultDesc;
-import org.apache.axis.description.FieldDesc;
-import org.apache.axis.description.JavaServiceDesc;
-import org.apache.axis.description.OperationDesc;
-import org.apache.axis.description.ParameterDesc;
-import org.apache.axis.description.ServiceDesc;
-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.TypeMappingRegistry;
-import org.apache.axis.encoding.TypeMappingRegistryImpl;
-import org.apache.axis.encoding.ser.ArrayDeserializerFactory;
-import org.apache.axis.encoding.ser.ArraySerializerFactory;
-import org.apache.axis.encoding.ser.BeanDeserializerFactory;
-import org.apache.axis.encoding.ser.BeanSerializerFactory;
-import org.apache.axis.utils.BeanPropertyDescriptor;
-import org.apache.axis.utils.BeanUtils;
-import org.apache.axis.wsdl.fromJava.Namespaces;
-import org.apache.axis.wsdl.fromJava.Types;
-import org.apache.beehive.wsm.axis.databinding.SystemTypeLookupService;
-import org.apache.beehive.wsm.axis.registration.AxisTypeMappingMetaData;
-import org.apache.beehive.wsm.axis.util.encoding.XmlBeanDeserializerFactory;
-import org.apache.beehive.wsm.axis.util.encoding.XmlBeanSerializerFactory;
-import org.apache.beehive.wsm.databinding.BindingLookupService;
-import org.apache.beehive.wsm.model.BeehiveWsMethodMetadata;
-import org.apache.beehive.wsm.model.BeehiveWsParameterMetadata;
-import org.apache.beehive.wsm.model.BeehiveWsSOAPBindingInfo;
-import org.apache.beehive.wsm.model.BeehiveWsTypeMetadata;
-import org.apache.beehive.wsm.registration.TypeRegistrar;
-import org.apache.beehive.wsm.util.InvalidTypeMappingException;
-import org.apache.log4j.Logger;
-import org.apache.xmlbeans.XmlBeans;
-import org.apache.xmlbeans.XmlObject;
-
-/**
- * ****************************************************************************
- *
- * @author Jonathan Colwell
- */
-public class AxisHook {
-    static Logger logger = Logger.getLogger(AxisHook.class);
-
-    public static ServiceDesc createServiceDesc(BeehiveWsTypeMetadata wsm, ClassLoader cl)
-        throws ClassNotFoundException, InvalidTypeMappingException {
-
-        JavaServiceDesc sd = new JavaServiceDesc();
-        if(null == cl) {
-            /*
-             * NOTE jcolwell@bea.com 2004-Aug-30 -- if no classloader was
-             * provided, use the one that loaded this Class
-             */
-            cl = AxisHook.class.getClassLoader();
-        }
-        final Class serviceClass = cl.loadClass(wsm.getClassName());
-
-        // Create a list of the allowed methods
-        List<String> allowedMethods = new ArrayList<String>();
-        for(BeehiveWsMethodMetadata meth : wsm.getMethods()) {
-            String method = meth.getJavaMethodName();
-            allowedMethods.add(method);
-        }
-
-        // set the ServiceDesc base information
-        sd.setName(wsm.getWsName());
-        sd.setImplClass(serviceClass);
-        String targetNamespace = wsm.getWsTargetNamespace();
-        sd.setDefaultNamespace(targetNamespace);
-        sd.setAllowedMethods(allowedMethods);
-        configureSoapBinding(sd, wsm.getSoapBinding());
-
-        TypeMappingRegistry tmr = new TypeMappingRegistryImpl(true);
-        TypeMapping tm = tmr.getOrMakeTypeMapping
-            (sd.getUse() == Use.ENCODED ? "http://schemas.xmlsoap.org/soap/encoding/" : "");
-        sd.setTypeMappingRegistry(tmr);
-        sd.setTypeMapping(tm);
-
-        /*
-         * jongjinchoi@apache.org 2005-Mar-16 -- Use Axis's introspection
-         * feature instead of creating new OperationDesc and ParameterDescs
-         * directly. The introspected OperationDesc and ParameterDescs are
-         * overrided by WSM. When appropriate type mapping registry is set, Axis
-         * fills the ParameterDesc's typeEntry from the preset typemapping
-         * registry, which is required for Axis to work in wrapped/lit mode.
-         */
-        sd.getOperations();
-
-        // Walk the methods
-        for(BeehiveWsMethodMetadata meth : wsm.getMethods()) {
-            String operationName = meth.getWmOperationName();
-            if(null != operationName && 0 < operationName.length()) {
-                // set the Operations properties
-                OperationDesc od = sd.getOperationByName(meth.getJavaMethodName());
-                od.setElementQName(new QName(targetNamespace, operationName));
-                od.setName(operationName);
-                od.setSoapAction(meth.getWmAction());
-                if(meth.isOneWay()) {
-                    od.setMep(OperationType.ONE_WAY);
-                }
-                else {
-                    String namespace = "";
-                    // namespace only should be added for document style, RPC style doesn't need name space for return type.
-                    if(wsm.getSoapBinding().getStyle() == SOAPBinding.Style.DOCUMENT)
-                        namespace = meth.getWrTargetNamespace();
-
-                    od.setReturnQName(new QName(namespace, meth.getWrName()));
-                    final Class returnType = meth.getJavaReturnType();
-                    QName qn = configureTypeMapping(sd, returnType, meth.getWrTargetNamespace());
-                    od.setReturnType(qn);
-                    od.setReturnClass(returnType);
-                }
-
-                // process the parameters
-                int pcnt = 0;
-                for(BeehiveWsParameterMetadata param : meth.getParams()) {
-                    ParameterDesc pd = od.getParameter(pcnt++);
-                    final Class paramType = param.getJavaType();
-
-                    if(pd.getTypeQName() == null) {
-                        // set the typeQName if it is not set already
-                        QName typeQName = configureTypeMapping(sd, paramType, param.getWpTargetNamespace());
-                        /*
-                         * jongjinchoi@apache.org 2005-Mar-16 -- The typeQName
-                         * from configureTypeMapping() is not dummy. This is
-                         * required to find ArrayDeserializer when the
-                         * document/literal bare array is deserialized.
-                         */
-                        pd.setTypeQName(typeQName);
-                    }
-
-                    // set QName
-                    String namespace = "";
-                    // namespace only should be added for document style, RPC style doesn't need name space for parameter names.
-                    if(wsm.getSoapBinding().getStyle() == SOAPBinding.Style.DOCUMENT)
-                        namespace = param.getWpTargetNamespace();
-                    QName paramQName = new QName(namespace, param.getWpName());
-                    pd.setQName(paramQName);
-
-                    // set Mode
-                    final boolean header = param.isWpHeader();
-                    final WebParam.Mode mode = param.getWpMode();
-                    switch(mode) {
-                        case IN:
-                            pd.setMode(ParameterDesc.IN);
-                            pd.setInHeader(header);
-                            pd.setOutHeader(false);
-                            break;
-                        case OUT:
-                            pd.setMode(ParameterDesc.OUT);
-                            pd.setInHeader(false);
-                            pd.setOutHeader(header);
-                            break;
-                        case INOUT:
-                            pd.setMode(ParameterDesc.INOUT);
-                            pd.setInHeader(header);
-                            pd.setOutHeader(header);
-                            break;
-                        default:
-                            throw new IllegalArgumentException("Illegal value for WebParam.Mode: " + mode);
-                    }
-
-                    // set JavaType
-                    pd.setJavaType(paramType);
-                }
-
-                // set Exceptions
-                Method javaMethod = od.getMethod();
-                for(Class thrown : javaMethod.getExceptionTypes()) {
-                    FaultDesc fd = od.getFaultByClass(thrown);
-                    if(null == fd) {
-                        logger.info("Exception: "
-                            + thrown.getCanonicalName()
-                            + " is not picked up by the Axis, only non Remote and Application Specific exceptions are registed in Axis.  This is not a fatal error.");
-                        continue;
-                    }
-                    QName qname = configureTypeMapping(sd, thrown, meth.getWrTargetNamespace());
-                    fd.setXmlType(qname);
-                    fd.setQName(qname);
-                    fd.setComplex(true);
-                }
-            }
-        }
-        return sd;
-    }
-
-    /**
-     * This method will return a boolean value indicating that Activation is
-     * enabled. Activation requires the DataHandler and the Multipart Classes to
-     * both be found.
-     *
-     * @return boolean indicating that Activation is enabled.
-     */
-    private static boolean isActivationEnabled() {
-        return null != getDataHandlerClass() && null != getMultipartClass();
-    }
-
-    /**
-     * This will return the Class for the DataHandler. This will return null if
-     * the DataHandler is not available.
-     *
-     * @return The DataHandler Class or null if the DataHandler is not found
-     */
-    private static Class getDataHandlerClass() {
-        try {
-            return AxisHook.class.getClassLoader().loadClass("javax.activation.DataHandler");
-        }
-        catch(ClassNotFoundException e) {
-            /* todo: this should log a warning */
-        }
-        return null;
-    }
-
-    /**
-     * This will return the Class for the MimeMultipart handler. It will return
-     * null if the MimMultipart class is not available.
-     *
-     * @return The MimeMultipart Class or null if the DataHandler is not found.
-     */
-    private static Class getMultipartClass() {
-        try {
-            return AxisHook.class.getClassLoader().loadClass(
-                "javax.mail.internet.MimeMultipart");
-        }
-        catch(ClassNotFoundException e) {
-            /* todo: this should log a warning */
-        }
-        return null;
-    }
-
-    private static QName configureTypeMapping(ServiceDesc desc, Class type, String defaultNameSpace)
-        throws InvalidTypeMappingException {
-        try {
-            if(Void.TYPE.equals(type))
-                return null;
-
-//            // If type is holder or it is generic holder, strip it to its base type
-//            type = TypeRegistrar.getUnderlyingType(type);
-//
-            if(AxisTypeMappingMetaData.isBuiltInType(type))
-                return AxisTypeMappingMetaData.getBuiltInTypeQname(type);
-
-            if(Holder.class.isAssignableFrom(type)) {
-                type = TypeRegistrar.getHoldersValueClass(type);
-                // NOTE: May need to register the holder type also.
-            }
-
-            // if type needs to be registered
-            TypeMapping tm = desc.getTypeMapping();
-            // QName q = tm.getTypeQName(type);
-            // System.out.println("###################################type: "
-            // + type.getCanonicalName() + " qname is: " + q
-            // + " default namesapce: " + defaultNameSpace);
-            // if (null == q || // Not registered
-            // !q.getNamespaceURI().equals(defaultNameSpace)) { // registered
-            // // but not
-            // // in
-            // // current
-            // // namespace
-            // // q = generateQName(type, desc);
-            // q = new QName(defaultNameSpace, Types
-            // .getLocalNameFromFullName(type.getName()));
-            // System.out
-            // .println("CREATE QNAME: #############################type: "
-            // + type.getCanonicalName() + " qname is: " + q);
-            // }
-
-            BindingLookupService lookupService = new SystemTypeLookupService();  // move this to the constructor
-            QName q = lookupService.class2qname(type, defaultNameSpace);
-
-            if(type.isArray()) {
-                /*
-                 * jongjinchoi@apache.org 2005-Mar-16 -- don't register array
-                 * serializer in document(bare or wrapped)/literal mode.
-                 */
-                if(!tm.isRegistered(type, q) && desc.getStyle() == Style.RPC && desc.getUse() == Use.ENCODED) {
-                    tm.register(type,
-                                q,
-                                new ArraySerializerFactory(type, q),
-                                new ArrayDeserializerFactory());
-                }
-                QName qcomp = configureTypeMapping(desc, type.getComponentType(), defaultNameSpace);
-                if(desc.getUse() == Use.LITERAL)
-                    q = qcomp;
-            }
-            else if(!tm.isRegistered(type, q)) {
-                if(XmlObject.class.isAssignableFrom(type)) {
-                    q = XmlBeans.typeForClass(type).getName();
-                    tm.register(type,
-                                q,
-                                new XmlBeanSerializerFactory(type, q),
-                                new XmlBeanDeserializerFactory(type, 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(type) ||
-                        getMultipartClass().isAssignableFrom(type) ||
-                        getDataHandlerClass().isAssignableFrom(type))) {
-                    try {
-                        /*
-                         * NOTE jcolwell@bea.com 2004-Oct-08 -- doing reflection
-                         * here in case AXIS was built without attachment
-                         * support.
-                         */
-                        ClassLoader cl = AxisHook.class.getClassLoader();
-                        // Loadclass could have been done in import also, but if
-                        // there are no activation.jar then this would
-                        // cause error when the class is loaded. To prevent that
-                        // we load the class explicitly at this point.
-                        // if we had done the "new
-                        // org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory"
-                        // then the class
-                        // would have had dependecies to the org.apache... class
-                        // which would not have worked in case activation was
-                        // not on the path.
-                        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(type, q);
-                        DeserializerFactory dsf = dsfCon.newInstance(type, q);
-                        tm.register(type, q, sf, dsf);
-                    }
-                    catch(Exception e) {
-                        /*
-                         * FIXME jcolwell@bea.com 2004-Oct-08 -- log this
-                         * properly
-                         */
-                        e.printStackTrace();
-                    }
-                }
-                /*
-                * NOTE jcolwell@bea.com 2004-Dec-01 -- 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. It
-                * causes an infinite loop as it keeps returning itself from the
-                * getAbsoluteFile and getCanonicalFile calls
-                */
-                else if(!Remote.class.isAssignableFrom(type) && !File.class.isAssignableFrom(type)) {
-                    TypeDesc td = TypeDesc.getTypeDescForClass(type);
-
-                    // if type was registered in a different namespace, then
-                    // ignore this and create a new td
-                    if(td != null && !td.getXmlType().getNamespaceURI().equals(q.getNamespaceURI())) {
-                        td = null;
-                    }
-
-                    TypeDesc superTd = null;
-                    BeanPropertyDescriptor[] superPd = null;
-                    // type desc is used for java-xml mapping, make sure the
-                    // class and all its super classes have a type desc defined.
-                    if(null == td) {
-                        td = new TypeDesc(type); // create type descriptor
-                        // for this class --- NOT
-                        // its super classes at this
-                        // point.
-                        // add super class types.
-                        Class supa = type.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)) {
-                            configureTypeMapping(desc, supa, defaultNameSpace);
-                        }
-                        // check to see if a type mapping was created for the
-                        // super class.
-                        superTd = TypeDesc.getTypeDescForClass(supa);
-                        if(superTd != null) {
-                            // super class is a regular javabean with axis typedesc
-                            superPd = superTd.getPropertyDescriptors();
-                            // this is mapping for all my super classes
-                        }
-                        td.setXmlType(q);
-                        TypeDesc.registerTypeDescForClass(type, td);
-                        // NOTE: this is partially finished td, so more
-                        // processing to follow that is why its td is not set to
-                        // null as it is
-                        // for the case when it is already provided (when td
-                        // !=null)
-                    }
-                    else {
-                        // we don't need type desc. any more this is a complete td
-                        td = null;
-                    }
-                    //
-                    // // At this all parent bean classes and their properties
-                    // // (attributes) have been registered with typedecriptor
-                    // and
-                    // // type mapping.
-                    // // next regidster type for this class.
-                    // tm.register(type, q, new BeanSerializerFactory(type, 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(type, q));
-
-                    // At this all parent bean classes and their properties
-                    // (attributes) have been registered with typedecriptor and
-                    // type mapping.
-                    // next regidster type for this class.
-                    tm.register(type,
-                                q,
-                                new EnhancedBeanSerializerFactory(type, q, td),
-                                /*
-                                * 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 EnhancedBeanDeSerializerFactory(type, q, td));
-
-                    // now register the types for this bean properties
-                    // (attributes)
-                    // Note: we have to consider the case that one of the
-                    // properties may be XML bean
-                    // or a class that can deal with its own serialization.
-
-                    // Note this is all of the bean properties
-                    Map serProps = BeanDeserializerFactory.getProperties(type, null);
-                    for(BeanPropertyDescriptor beanProps : (Collection<BeanPropertyDescriptor>)serProps.values()) {
-                        Class subType = beanProps.getType();
-                        // make sure the property type is configred with Type
-                        // mapping and its serializer information
-                        if(!(subType.isPrimitive() ||
-                            subType.getName().startsWith("java.") ||
-                            subType.getName().startsWith("javax."))) {
-                            configureTypeMapping(desc, subType, defaultNameSpace);
-                            // if this was XML bean this recursion would take care of it
-                        }
-
-                        if(td != null) {
-                            // if I didn't have type descriptor when I came to this method... I
-                            // created partially filled one above now need to complete this.
-                            String ns = q.getNamespaceURI();
-                            // name space for the class if there is no parent
-                            // find proper namespace for this element... we need
-                            // to find out whihc class in the hierarchy the
-                            // element came from once you know where the element came form (which
-                            // class) then you know the element's name space.
-                            if(superTd != null && superPd != null) {
-                                // if I had a parent
-                                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(tm.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 "
-                        + type.getName()
-                        + " as a valid web service datatype,"
-                        + " consider using a custom type mapping");
-                }
-            }
-            return q;
-
-        }
-        catch(RuntimeException e) {
-            logger.error("Error in type registeration", e);
-            e.printStackTrace();
-            throw e;
-        }
-    }
-
-    protected static void configureSoapBinding(ServiceDesc sd, BeehiveWsSOAPBindingInfo sbi) {
-        javax.jws.soap.SOAPBinding.Style style = javax.jws.soap.SOAPBinding.Style.DOCUMENT;
-        javax.jws.soap.SOAPBinding.Use use = javax.jws.soap.SOAPBinding.Use.LITERAL;
-        javax.jws.soap.SOAPBinding.ParameterStyle paramStyle = javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED;
-        if(sbi != null) {
-            style = sbi.getStyle();
-            use = sbi.getUse();
-            paramStyle = sbi.getParameterStyle();
-        }
-        if(style == javax.jws.soap.SOAPBinding.Style.RPC) {
-            sd.setStyle(Style.RPC);
-            if(use == javax.jws.soap.SOAPBinding.Use.ENCODED) {
-                sd.setUse(Use.ENCODED);
-            }
-            else {
-                sd.setUse(Use.LITERAL);
-            }
-        }
-        else {
-            /*
-             * since DOCUMENT ENCODED is not valid so force to use LITERAL
-             */
-            sd.setUse(Use.LITERAL);
-
-            // check if this is a wrapped document literal
-            if(paramStyle == javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED) {
-                sd.setStyle(Style.WRAPPED);
-            }
-            else {
-                // just regular document style
-                sd.setStyle(Style.DOCUMENT);
-            }
-        }
-    }
-}
-
-/*
- * A TEMP SOLUTION TO BEAN Serialization/Deserialization problem The problem is
- * that the Axis factories use the types that are defined for a class, so a
- * given class can't be in multiple name spaces. In this solution the factory
- * gets the type descriptor in the constructor
- */
-
-class EnhancedBeanSerializerFactory
-    extends BeanSerializerFactory {
-
-    public EnhancedBeanSerializerFactory(Class javaType, QName xmlType, TypeDesc typeDesc) {
-        super(javaType, xmlType);
-
-        this.typeDesc = typeDesc;
-
-        if(typeDesc != null) {
-            propertyDescriptor = typeDesc.getPropertyDescriptors();
-        }
-        else {
-            propertyDescriptor = BeanUtils.getPd(javaType, null);
-        }
-    }
-}
-
-class EnhancedBeanDeSerializerFactory
-    extends BeanDeserializerFactory {
-    public EnhancedBeanDeSerializerFactory(Class javaType, QName xmlType, TypeDesc typeDesc) {
-        super(javaType, xmlType);
-
-        this.typeDesc = typeDesc;
-        propertyMap = getProperties(javaType, typeDesc);
-    }
-}
+/*
+ * 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.
+ */
+package org.apache.beehive.wsm.axis;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.rmi.Remote;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import javax.jws.WebParam;
+import javax.jws.soap.SOAPBinding;
+import javax.wsdl.OperationType;
+import javax.xml.namespace.QName;
+import javax.xml.rpc.holders.Holder;
+
+import org.apache.axis.constants.Style;
+import org.apache.axis.constants.Use;
+import org.apache.axis.description.ElementDesc;
+import org.apache.axis.description.FaultDesc;
+import org.apache.axis.description.FieldDesc;
+import org.apache.axis.description.JavaServiceDesc;
+import org.apache.axis.description.OperationDesc;
+import org.apache.axis.description.ParameterDesc;
+import org.apache.axis.description.ServiceDesc;
+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.TypeMappingRegistry;
+import org.apache.axis.encoding.TypeMappingRegistryImpl;
+import org.apache.axis.encoding.ser.ArrayDeserializerFactory;
+import org.apache.axis.encoding.ser.ArraySerializerFactory;
+import org.apache.axis.encoding.ser.BeanDeserializerFactory;
+import org.apache.axis.encoding.ser.BeanSerializerFactory;
+import org.apache.axis.utils.BeanPropertyDescriptor;
+import org.apache.axis.utils.BeanUtils;
+import org.apache.axis.wsdl.fromJava.Namespaces;
+import org.apache.axis.wsdl.fromJava.Types;
+import org.apache.beehive.wsm.axis.databinding.SystemTypeLookupService;
+import org.apache.beehive.wsm.axis.registration.AxisTypeMappingMetaData;
+import org.apache.beehive.wsm.axis.util.encoding.XmlBeanDeserializerFactory;
+import org.apache.beehive.wsm.axis.util.encoding.XmlBeanSerializerFactory;
+import org.apache.beehive.wsm.databinding.BindingLookupService;
+import org.apache.beehive.wsm.model.BeehiveWsMethodMetadata;
+import org.apache.beehive.wsm.model.BeehiveWsParameterMetadata;
+import org.apache.beehive.wsm.model.BeehiveWsSOAPBindingInfo;
+import org.apache.beehive.wsm.model.BeehiveWsTypeMetadata;
+import org.apache.beehive.wsm.registration.TypeRegistrar;
+import org.apache.beehive.wsm.util.InvalidTypeMappingException;
+import org.apache.log4j.Logger;
+import org.apache.xmlbeans.XmlBeans;
+import org.apache.xmlbeans.XmlObject;
+
+/**
+ * ****************************************************************************
+ *
+ * @author Jonathan Colwell
+ */
+public class AxisHook {
+    static Logger logger = Logger.getLogger(AxisHook.class);
+
+    public static ServiceDesc createServiceDesc(BeehiveWsTypeMetadata wsm, ClassLoader cl)
+        throws ClassNotFoundException, InvalidTypeMappingException {
+
+        JavaServiceDesc sd = new JavaServiceDesc();
+        if(null == cl) {
+            /*
+             * NOTE jcolwell@bea.com 2004-Aug-30 -- if no classloader was
+             * provided, use the one that loaded this Class
+             */
+            cl = AxisHook.class.getClassLoader();
+        }
+        final Class serviceClass = cl.loadClass(wsm.getClassName());
+
+        // Create a list of the allowed methods
+        List<String> allowedMethods = new ArrayList<String>();
+        for(BeehiveWsMethodMetadata meth : wsm.getMethods()) {
+            String method = meth.getJavaMethodName();
+            allowedMethods.add(method);
+        }
+
+        // set the ServiceDesc base information
+        sd.setName(wsm.getWsName());
+        sd.setImplClass(serviceClass);
+        String targetNamespace = wsm.getWsTargetNamespace();
+        sd.setDefaultNamespace(targetNamespace);
+        sd.setAllowedMethods(allowedMethods);
+        configureSoapBinding(sd, wsm.getSoapBinding());
+
+        TypeMappingRegistry tmr = new TypeMappingRegistryImpl(true);
+        TypeMapping tm = tmr.getOrMakeTypeMapping
+            (sd.getUse() == Use.ENCODED ? "http://schemas.xmlsoap.org/soap/encoding/" : "");
+        sd.setTypeMappingRegistry(tmr);
+        sd.setTypeMapping(tm);
+
+        /*
+         * jongjinchoi@apache.org 2005-Mar-16 -- Use Axis's introspection
+         * feature instead of creating new OperationDesc and ParameterDescs
+         * directly. The introspected OperationDesc and ParameterDescs are
+         * overrided by WSM. When appropriate type mapping registry is set, Axis
+         * fills the ParameterDesc's typeEntry from the preset typemapping
+         * registry, which is required for Axis to work in wrapped/lit mode.
+         */
+        sd.getOperations();
+
+        // Walk the methods
+        for(BeehiveWsMethodMetadata meth : wsm.getMethods()) {
+            String operationName = meth.getWmOperationName();
+            if(null != operationName && 0 < operationName.length()) {
+                // set the Operations properties
+                OperationDesc od = sd.getOperationByName(meth.getJavaMethodName());
+                od.setElementQName(new QName(targetNamespace, operationName));
+                od.setName(operationName);
+                od.setSoapAction(meth.getWmAction());
+                if(meth.isOneWay()) {
+                    od.setMep(OperationType.ONE_WAY);
+                }
+                else {
+                    String namespace = "";
+                    // namespace only should be added for document style, RPC style doesn't need name space for return type.
+                    if(wsm.getSoapBinding().getStyle() == SOAPBinding.Style.DOCUMENT)
+                        namespace = meth.getWrTargetNamespace();
+
+                    od.setReturnQName(new QName(namespace, meth.getWrName()));
+                    final Class returnType = meth.getJavaReturnType();
+                    QName qn = configureTypeMapping(sd, returnType, meth.getWrTargetNamespace());
+                    od.setReturnType(qn);
+                    od.setReturnClass(returnType);
+                }
+
+                // process the parameters
+                int pcnt = 0;
+                for(BeehiveWsParameterMetadata param : meth.getParams()) {
+                    ParameterDesc pd = od.getParameter(pcnt++);
+                    final Class paramType = param.getJavaType();
+
+                    if(pd.getTypeQName() == null) {
+                        // set the typeQName if it is not set already
+                        QName typeQName = configureTypeMapping(sd, paramType, param.getWpTargetNamespace());
+                        /*
+                         * jongjinchoi@apache.org 2005-Mar-16 -- The typeQName
+                         * from configureTypeMapping() is not dummy. This is
+                         * required to find ArrayDeserializer when the
+                         * document/literal bare array is deserialized.
+                         */
+                        pd.setTypeQName(typeQName);
+                    }
+
+                    // set QName
+                    String namespace = "";
+                    // namespace only should be added for document style, RPC style doesn't need name space for parameter names.
+                    if(wsm.getSoapBinding().getStyle() == SOAPBinding.Style.DOCUMENT)
+                        namespace = param.getWpTargetNamespace();
+                    QName paramQName = new QName(namespace, param.getWpName());
+                    pd.setQName(paramQName);
+
+                    // set Mode
+                    final boolean header = param.isWpHeader();
+                    final WebParam.Mode mode = param.getWpMode();
+                    switch(mode) {
+                        case IN:
+                            pd.setMode(ParameterDesc.IN);
+                            pd.setInHeader(header);
+                            pd.setOutHeader(false);
+                            break;
+                        case OUT:
+                            pd.setMode(ParameterDesc.OUT);
+                            pd.setInHeader(false);
+                            pd.setOutHeader(header);
+                            break;
+                        case INOUT:
+                            pd.setMode(ParameterDesc.INOUT);
+                            pd.setInHeader(header);
+                            pd.setOutHeader(header);
+                            break;
+                        default:
+                            throw new IllegalArgumentException("Illegal value for WebParam.Mode: " + mode);
+                    }
+
+                    // set JavaType
+                    pd.setJavaType(paramType);
+                }
+
+                // set Exceptions
+                Method javaMethod = od.getMethod();
+                boolean hasUserDefinedFaults = false;
+                for(Class thrown : javaMethod.getExceptionTypes()) {
+                    FaultDesc fd = od.getFaultByClass(thrown);
+                    if(null == fd) {
+                        logger.info("Exception: "
+                            + thrown.getCanonicalName()
+                            + " is not picked up by the Axis, only non Remote and Application Specific exceptions are registed in Axis.  This is not a fatal error.");
+                        continue;
+                    }
+                    QName qname = configureTypeMapping(sd, thrown, meth.getWrTargetNamespace());
+                    fd.setXmlType(qname);
+                    fd.setQName(qname);
+                    fd.setComplex(true);
+                    
+                    
+                    ArrayList parameters = fd.getParameters();
+
+                    if (parameters != null) {
+                        // Based on JavaServiceDesc.createFaultMetadata comments
+                        // there should
+                        // only be one parameter on the fd that points to the
+                        // type
+                        /*
+                         * comments form Axis JavaServiceDesc class (around line
+                         * 1366)
+                         *  // Parameters // We add a single parameter which
+                         * points to the type if (fault.getParameters() == null) {
+                         * if (xmlType == null) { ......
+                         * 
+                         */
+                        // make sure the parmeter description points to the
+                        // type, since the
+                        // type was not registered at the time of creating the
+                        // fault, we
+                        // need to set the type
+                        ParameterDesc parameter = (ParameterDesc) parameters.get(0);
+                        parameter.setTypeQName(qname);
+                        
+                        // give each fault a unique name, the name will be used
+                        // in the "<details>" section of the soapfault message
+                        parameter.setQName( new QName(qname.getNamespaceURI(), qname.getLocalPart()+"Fault"));
+                        hasUserDefinedFaults = true;
+                    }
+                }
+                if(hasUserDefinedFaults) configureTypeMapping(sd, AxisFaultAdaptor.class, meth
+                        .getWrTargetNamespace());
+            }
+        }
+        return sd;
+    }
+
+    /**
+     * This method will return a boolean value indicating that Activation is
+     * enabled. Activation requires the DataHandler and the Multipart Classes to
+     * both be found.
+     *
+     * @return boolean indicating that Activation is enabled.
+     */
+    private static boolean isActivationEnabled() {
+        return null != getDataHandlerClass() && null != getMultipartClass();
+    }
+
+    /**
+     * This will return the Class for the DataHandler. This will return null if
+     * the DataHandler is not available.
+     *
+     * @return The DataHandler Class or null if the DataHandler is not found
+     */
+    private static Class getDataHandlerClass() {
+        try {
+            return AxisHook.class.getClassLoader().loadClass("javax.activation.DataHandler");
+        }
+        catch(ClassNotFoundException e) {
+            /* todo: this should log a warning */
+        }
+        return null;
+    }
+
+    /**
+     * This will return the Class for the MimeMultipart handler. It will return
+     * null if the MimMultipart class is not available.
+     *
+     * @return The MimeMultipart Class or null if the DataHandler is not found.
+     */
+    private static Class getMultipartClass() {
+        try {
+            return AxisHook.class.getClassLoader().loadClass(
+                "javax.mail.internet.MimeMultipart");
+        }
+        catch(ClassNotFoundException e) {
+            /* todo: this should log a warning */
+        }
+        return null;
+    }
+
+    private static QName configureTypeMapping(ServiceDesc desc, Class type, String defaultNameSpace)
+        throws InvalidTypeMappingException {
+        try {
+            if(Void.TYPE.equals(type))
+                return null;
+
+//            // If type is holder or it is generic holder, strip it to its base type
+//            type = TypeRegistrar.getUnderlyingType(type);
+//
+            if(AxisTypeMappingMetaData.isBuiltInType(type))
+                return AxisTypeMappingMetaData.getBuiltInTypeQname(type);
+
+            if(Holder.class.isAssignableFrom(type)) {
+                type = TypeRegistrar.getHoldersValueClass(type);
+                // NOTE: May need to register the holder type also.
+            }
+
+            // if type needs to be registered
+            TypeMapping tm = desc.getTypeMapping();
+            // QName q = tm.getTypeQName(type);
+            // System.out.println("###################################type: "
+            // + type.getCanonicalName() + " qname is: " + q
+            // + " default namesapce: " + defaultNameSpace);
+            // if (null == q || // Not registered
+            // !q.getNamespaceURI().equals(defaultNameSpace)) { // registered
+            // // but not
+            // // in
+            // // current
+            // // namespace
+            // // q = generateQName(type, desc);
+            // q = new QName(defaultNameSpace, Types
+            // .getLocalNameFromFullName(type.getName()));
+            // System.out
+            // .println("CREATE QNAME: #############################type: "
+            // + type.getCanonicalName() + " qname is: " + q);
+            // }
+
+            BindingLookupService lookupService = new SystemTypeLookupService();  // move this to the constructor
+            QName q = lookupService.class2qname(type, defaultNameSpace);
+
+            if(type.isArray()) {
+                /*
+                 * jongjinchoi@apache.org 2005-Mar-16 -- don't register array
+                 * serializer in document(bare or wrapped)/literal mode.
+                 */
+                if(!tm.isRegistered(type, q) && desc.getStyle() == Style.RPC && desc.getUse() == Use.ENCODED) {
+                    tm.register(type,
+                                q,
+                                new ArraySerializerFactory(type, q),
+                                new ArrayDeserializerFactory());
+                }
+                QName qcomp = configureTypeMapping(desc, type.getComponentType(), defaultNameSpace);
+                if(desc.getUse() == Use.LITERAL)
+                    q = qcomp;
+            }
+            else if(!tm.isRegistered(type, q)) {
+                if(XmlObject.class.isAssignableFrom(type)) {
+                    q = XmlBeans.typeForClass(type).getName();
+                    tm.register(type,
+                                q,
+                                new XmlBeanSerializerFactory(type, q),
+                                new XmlBeanDeserializerFactory(type, 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(type) ||
+                        getMultipartClass().isAssignableFrom(type) ||
+                        getDataHandlerClass().isAssignableFrom(type))) {
+                    try {
+                        /*
+                         * NOTE jcolwell@bea.com 2004-Oct-08 -- doing reflection
+                         * here in case AXIS was built without attachment
+                         * support.
+                         */
+                        ClassLoader cl = AxisHook.class.getClassLoader();
+                        // Loadclass could have been done in import also, but if
+                        // there are no activation.jar then this would
+                        // cause error when the class is loaded. To prevent that
+                        // we load the class explicitly at this point.
+                        // if we had done the "new
+                        // org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory"
+                        // then the class
+                        // would have had dependecies to the org.apache... class
+                        // which would not have worked in case activation was
+                        // not on the path.
+                        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(type, q);
+                        DeserializerFactory dsf = dsfCon.newInstance(type, q);
+                        tm.register(type, q, sf, dsf);
+                    }
+                    catch(Exception e) {
+                        /*
+                         * FIXME jcolwell@bea.com 2004-Oct-08 -- log this
+                         * properly
+                         */
+                        e.printStackTrace();
+                    }
+                }
+                /*
+                * NOTE jcolwell@bea.com 2004-Dec-01 -- 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. It
+                * causes an infinite loop as it keeps returning itself from the
+                * getAbsoluteFile and getCanonicalFile calls
+                */
+                else if(!Remote.class.isAssignableFrom(type) && !File.class.isAssignableFrom(type)) {
+                    TypeDesc td = TypeDesc.getTypeDescForClass(type);
+
+                    // if type was registered in a different namespace, then
+                    // ignore this and create a new td
+                    if(td != null && !td.getXmlType().getNamespaceURI().equals(q.getNamespaceURI())) {
+                        td = null;
+                    }
+
+                    TypeDesc superTd = null;
+                    BeanPropertyDescriptor[] superPd = null;
+                    // type desc is used for java-xml mapping, make sure the
+                    // class and all its super classes have a type desc defined.
+                    if(null == td) {
+                        td = new TypeDesc(type); // create type descriptor
+                        // for this class --- NOT
+                        // its super classes at this
+                        // point.
+                        // add super class types.
+                        Class supa = type.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)) {
+                            configureTypeMapping(desc, supa, defaultNameSpace);
+                        }
+                        // check to see if a type mapping was created for the
+                        // super class.
+                        superTd = TypeDesc.getTypeDescForClass(supa);
+                        if(superTd != null) {
+                            // super class is a regular javabean with axis typedesc
+                            superPd = superTd.getPropertyDescriptors();
+                            // this is mapping for all my super classes
+                        }
+                        td.setXmlType(q);
+                        TypeDesc.registerTypeDescForClass(type, td);
+                        // NOTE: this is partially finished td, so more
+                        // processing to follow that is why its td is not set to
+                        // null as it is
+                        // for the case when it is already provided (when td
+                        // !=null)
+                    }
+                    else {
+                        // we don't need type desc. any more this is a complete td
+                        td = null;
+                    }
+                    //
+                    // // At this all parent bean classes and their properties
+                    // // (attributes) have been registered with typedecriptor
+                    // and
+                    // // type mapping.
+                    // // next regidster type for this class.
+                    // tm.register(type, q, new BeanSerializerFactory(type, 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(type, q));
+
+                    // At this all parent bean classes and their properties
+                    // (attributes) have been registered with typedecriptor and
+                    // type mapping.
+                    // next regidster type for this class.
+                    tm.register(type,
+                                q,
+                                new EnhancedBeanSerializerFactory(type, q, td),
+                                /*
+                                * 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 EnhancedBeanDeSerializerFactory(type, q, td));
+
+                    // now register the types for this bean properties
+                    // (attributes)
+                    // Note: we have to consider the case that one of the
+                    // properties may be XML bean
+                    // or a class that can deal with its own serialization.
+
+                    // Note this is all of the bean properties
+                    Map serProps = BeanDeserializerFactory.getProperties(type, null);
+                    for(BeanPropertyDescriptor beanProps : (Collection<BeanPropertyDescriptor>)serProps.values()) {
+                        Class subType = beanProps.getType();
+                        // make sure the property type is configred with Type
+                        // mapping and its serializer information
+                        if(!(subType.isPrimitive() ||
+                            subType.getName().startsWith("java.") ||
+                            subType.getName().startsWith("javax."))) {
+                            configureTypeMapping(desc, subType, defaultNameSpace);
+                            // if this was XML bean this recursion would take care of it
+                        }
+
+                        if(td != null) {
+                            // if I didn't have type descriptor when I came to this method... I
+                            // created partially filled one above now need to complete this.
+                            String ns = q.getNamespaceURI();
+                            // name space for the class if there is no parent
+                            // find proper namespace for this element... we need
+                            // to find out whihc class in the hierarchy the
+                            // element came from once you know where the element came form (which
+                            // class) then you know the element's name space.
+                            if(superTd != null && superPd != null) {
+                                // if I had a parent
+                                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(tm.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 "
+                        + type.getName()
+                        + " as a valid web service datatype,"
+                        + " consider using a custom type mapping");
+                }
+            }
+            return q;
+
+        }
+        catch(RuntimeException e) {
+            logger.error("Error in type registeration", e);
+            e.printStackTrace();
+            throw e;
+        }
+    }
+
+    protected static void configureSoapBinding(ServiceDesc sd, BeehiveWsSOAPBindingInfo sbi) {
+        javax.jws.soap.SOAPBinding.Style style = javax.jws.soap.SOAPBinding.Style.DOCUMENT;
+        javax.jws.soap.SOAPBinding.Use use = javax.jws.soap.SOAPBinding.Use.LITERAL;
+        javax.jws.soap.SOAPBinding.ParameterStyle paramStyle = javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED;
+        if(sbi != null) {
+            style = sbi.getStyle();
+            use = sbi.getUse();
+            paramStyle = sbi.getParameterStyle();
+        }
+        if(style == javax.jws.soap.SOAPBinding.Style.RPC) {
+            sd.setStyle(Style.RPC);
+            if(use == javax.jws.soap.SOAPBinding.Use.ENCODED) {
+                sd.setUse(Use.ENCODED);
+            }
+            else {
+                sd.setUse(Use.LITERAL);
+            }
+        }
+        else {
+            /*
+             * since DOCUMENT ENCODED is not valid so force to use LITERAL
+             */
+            sd.setUse(Use.LITERAL);
+
+            // check if this is a wrapped document literal
+            if(paramStyle == javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED) {
+                sd.setStyle(Style.WRAPPED);
+            }
+            else {
+                // just regular document style
+                sd.setStyle(Style.DOCUMENT);
+            }
+        }
+    }
+}
+
+/*
+ * A TEMP SOLUTION TO BEAN Serialization/Deserialization problem The problem is
+ * that the Axis factories use the types that are defined for a class, so a
+ * given class can't be in multiple name spaces. In this solution the factory
+ * gets the type descriptor in the constructor
+ */
+
+class EnhancedBeanSerializerFactory
+    extends BeanSerializerFactory {
+
+    public EnhancedBeanSerializerFactory(Class javaType, QName xmlType, TypeDesc typeDesc) {
+        super(javaType, xmlType);
+
+        this.typeDesc = typeDesc;
+
+        if(typeDesc != null) {
+            propertyDescriptor = typeDesc.getPropertyDescriptors();
+        }
+        else {
+            propertyDescriptor = BeanUtils.getPd(javaType, null);
+        }
+    }
+}
+
+class EnhancedBeanDeSerializerFactory
+    extends BeanDeserializerFactory {
+    public EnhancedBeanDeSerializerFactory(Class javaType, QName xmlType, TypeDesc typeDesc) {
+        super(javaType, xmlType);
+
+        this.typeDesc = typeDesc;
+        propertyMap = getProperties(javaType, typeDesc);
+    }
+}