/*
* 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.muse.core.proxy;
import javax.xml.namespace.QName;
import org.w3c.dom.Element;
import org.apache.muse.core.serializer.Serializer;
import org.apache.muse.core.serializer.SerializerRegistry;
import org.apache.muse.util.messages.Messages;
import org.apache.muse.util.messages.MessagesFactory;
import org.apache.muse.util.xml.XmlUtils;
import org.apache.muse.ws.addressing.soap.SoapFault;
/**
*
* ReflectionProxyHandler is a generic implementation of
* {@linkplain org.apache.muse.core.proxy.ProxyHandler ProxyHandler}
* that can be applied to any web service operation. It uses reflection to
* determine what types are being sent to/from the operation and then invokes
* the {@linkplain Serializer Serializers} that have been registered with
* Muse to do the XML/POJO transformations. If a type is used that is
* not included in Muse's set of built-in Serializers, you must register
* a Serializer for that type in order to take advantage of this class.
*
* @author Dan Jemiolo (danj)
*
* @see Serializer
*
*/
public class ReflectionProxyHandler extends AbstractProxyHandler
{
//
// Used to lookup all exception messages
//
private static Messages _MESSAGES =
MessagesFactory.get(ReflectionProxyHandler.class);
/**
*
* Deserializes the given DOM Element using the Serializer registered
* for the given type.
*
* @param xml
* @param theClass
*
* @return An instance of the given type, created from the given XML. If
* the type is null (or void), the method returns null.
*
* @throws SoapFault
* <ul>
* <li>If the XML cannot be deserialized to the given type.</li>
* </ul>
*
*/
protected Object deserialize(Element xml, Class theClass)
throws SoapFault
{
if (theClass == null || theClass == Void.TYPE)
return null;
SerializerRegistry registry = SerializerRegistry.getInstance();
Serializer deser = registry.getSerializer(theClass);
return deser.fromXML(xml);
}
public Object fromXML(Element xml)
throws SoapFault
{
//
// make sure the response fits the callout definition
//
QName correctName = getResponseName();
QName actualName = XmlUtils.getElementQName(xml);
//
// if no response name is provided, it means we accept "xsd:anyType"
//
if (correctName != null && !correctName.equals(actualName))
{
Object[] filler = { correctName, actualName };
String message = _MESSAGES.get("InvalidProxyResponse", filler);
throw new SoapFault(message);
}
//
// if the value is a simple type, use the root of the
// response body
//
Element child = XmlUtils.getFirstElement(xml);
Class returnType = getReturnType();
if (child == null || returnType.isArray())
child = xml;
//
// now we can deserialize the contents
//
return deserialize(child, returnType);
}
/**
*
* Serializes the given object using the Serializer registered for the
* object's type. The XML is wrapped in an element whose name is the
* one given.
*
* @param obj
* The object to transform into XML.
*
* @param qname
* The name of the root Element returned by this method.
*
* @return The XML version of the object, wrapped in an element that has
* the given name.
*
* @throws SoapFault
* <ul>
* <li>If the object could not be serialized to XML.</li>
* </ul>
*
*/
protected Element serialize(Object obj, QName qname)
throws SoapFault
{
if (obj == null)
return XmlUtils.createElement(qname);
Class theClass = obj.getClass();
SerializerRegistry registry = SerializerRegistry.getInstance();
Serializer ser = registry.getSerializer(theClass);
return ser.toXML(obj, qname);
}
public Element toXML(Object[] parameters)
throws SoapFault
{
QName requestName = getRequestName();
QName[] inputParts = getRequestParameterNames();
if (requestName == null)
throw new IllegalStateException(_MESSAGES.get("NoRequestName"));
if (inputParts == null)
throw new IllegalStateException(_MESSAGES.get("NoRequestParams"));
//
// special case: empty parameters or simple parameter types
//
if (inputParts.length == 0)
{
//
// treat null and empty arrays the same
//
if (parameters == null || parameters.length == 0)
return XmlUtils.createElement(requestName);
//
// no input part name means that the parameter data is tucked
// under the root request element
//
else if (parameters.length == 1)
return serialize(parameters[0], requestName);
}
//
// make sure we have the correct number of parameters for the
// general case
//
if (parameters.length != inputParts.length)
{
Object[] filler = {
requestName, new Integer(inputParts.length), new Integer(parameters.length)
};
throw new RuntimeException(_MESSAGES.get("IncorrectParams", filler));
}
//
// general case: copy each parameter into a child DOM Element
//
Element root = XmlUtils.createElement(requestName);
for (int n = 0; n < inputParts.length; ++n)
{
Element child = serialize(parameters[n], inputParts[n]);
root.appendChild(child);
}
return root;
}
}