/* * 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.client.dispatch; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.jaxws.ExceptionFactory; import org.apache.axis2.jaxws.utility.DataSourceFormatter; import org.apache.axis2.jaxws.client.async.AsyncResponse; import org.apache.axis2.jaxws.core.MessageContext; import org.apache.axis2.jaxws.description.EndpointDescription; import org.apache.axis2.jaxws.message.Block; import org.apache.axis2.jaxws.message.Message; import org.apache.axis2.jaxws.message.Protocol; import org.apache.axis2.jaxws.message.factory.BlockFactory; import org.apache.axis2.jaxws.message.factory.DataSourceBlockFactory; import org.apache.axis2.jaxws.message.factory.MessageFactory; import org.apache.axis2.jaxws.message.factory.OMBlockFactory; import org.apache.axis2.jaxws.message.factory.SOAPEnvelopeBlockFactory; import org.apache.axis2.jaxws.message.factory.SourceBlockFactory; import org.apache.axis2.jaxws.message.factory.XMLStringBlockFactory; import org.apache.axis2.jaxws.registry.FactoryRegistry; import org.apache.axis2.jaxws.spi.ServiceDelegate; import org.apache.axis2.Constants; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.axiom.om.OMElement; import org.apache.axis2.jaxws.message.databinding.OMBlock; import org.apache.axis2.jaxws.message.databinding.impl.OMBlockFactoryImpl; import javax.activation.DataSource; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPMessage; import javax.xml.stream.XMLStreamException; import javax.xml.transform.Source; import javax.xml.ws.Service.Mode; import javax.xml.ws.WebServiceException; import javax.xml.ws.WebServiceFeature; public class XMLDispatch<T> extends BaseDispatch<T> { private static final Log log = LogFactory.getLog(XMLDispatch.class); private Class type; private Class blockFactoryType; public XMLDispatch(ServiceDelegate svcDelegate, EndpointDescription endpointDesc, WebServiceFeature... features) { this(svcDelegate, endpointDesc, null, null, features); } public XMLDispatch(ServiceDelegate svcDelegate, EndpointDescription endpointDesc, EndpointReference epr, String addressingNamespace, WebServiceFeature... features) { super(svcDelegate, endpointDesc, epr, addressingNamespace, features); } public Class getType() { return type; } public void setType(Class c) { type = c; } public AsyncResponse createAsyncResponseListener() { if (log.isDebugEnabled()) { log.debug("Creating new AsyncListener for XMLDispatch"); } XMLDispatchAsyncListener al = new XMLDispatchAsyncListener(getEndpointDescription()); al.setMode(mode); al.setType(type); al.setBlockFactoryType(blockFactoryType); return al; } public Message createMessageFromValue(Object value) { if (value != null) { type = value.getClass(); if (log.isDebugEnabled()) { log.debug("Parameter type: " + type.getName()); log.debug("Message mode: " + mode.name()); } } else { if (log.isDebugEnabled()) { log.debug("Dispatch invoked with null parameter Value"); log.debug("creating empty soap message"); } try { blockFactoryType = getBlockFactory(); return createEmptyMessage( Protocol.getProtocolForBinding(endpointDesc.getClientBindingID())); } catch (XMLStreamException e) { throw ExceptionFactory.makeWebServiceException(e); } } Block block = null; blockFactoryType = getBlockFactory(value); BlockFactory factory = (BlockFactory)FactoryRegistry.getFactory(blockFactoryType); if (log.isDebugEnabled()) { log.debug("Loaded block factory type [" + blockFactoryType.getName()); } // The protocol of the Message that is created should be based // on the binding information available. Protocol proto = Protocol.getProtocolForBinding(endpointDesc.getClientBindingID()); Message message = null; if (mode.equals(Mode.PAYLOAD)) { try { MessageFactory mf = (MessageFactory)FactoryRegistry.getFactory(MessageFactory.class); block = factory.createFrom(value, null, null); message = mf.create(proto); message.setBodyBlock(block); } catch (Exception e) { throw ExceptionFactory.makeWebServiceException(e); } } else if (mode.equals(Mode.MESSAGE)) { try { MessageFactory mf = (MessageFactory)FactoryRegistry.getFactory(MessageFactory.class); // If the value contains just the xml data, then you can create the Message directly from the // Block. If the value contains attachments, you need to do more. // TODO For now the only value that contains Attachments is SOAPMessage if (value instanceof SOAPMessage) { message = mf.createFrom((SOAPMessage)value); } else { block = factory.createFrom(value, null, null); message = mf.createFrom(block, null, proto); } } catch (Exception e) { throw ExceptionFactory.makeWebServiceException(e); } } return message; } public Object getValueFromMessage(Message message) { return getValue(message, mode, blockFactoryType); } /** * Common code used by XMLDispatch and XMLDispatchAsyncListener * * @param message * @return object */ static Object getValue(Message message, Mode mode, Class blockFactoryType) { Object value = null; Block block = null; if (log.isDebugEnabled()) { log.debug("Attempting to get the value object from the returned message"); } try { if (mode.equals(Mode.PAYLOAD)) { BlockFactory factory = (BlockFactory)FactoryRegistry .getFactory(blockFactoryType); block = message.getBodyBlock(null, factory); if (block != null) { value = block.getBusinessObject(true); } else { // REVIEW This seems like the correct behavior. If the body is empty, return a null // Any changes here should also be made to XMLDispatch.getValue if (log.isDebugEnabled()) { log.debug( "There are no elements in the body to unmarshal. XMLDispatch returns a null value"); } value = null; } } else if (mode.equals(Mode.MESSAGE)) { BlockFactory factory = (BlockFactory)FactoryRegistry.getFactory(blockFactoryType); if (factory instanceof OMBlockFactory) { /* * see MessageImpl.getValue(Object, BlockFactory) * The getValue method is not performant; it uses an intermediate StringBlock. To support OMElement in a * performant way, we simply retrieve the OMElement from the Message object, rather than unnecessarily * using the non-performant code in MessageImpl.getValue. * * TODO: when MessageImpl.getValue is fixed, this code can be removed, and the check for (value instanceof OMBlock) * placed below. However, the solution here actually traverses less code, so perhaps it should remain as-is. */ value = (OMElement)message.getAsOMElement(); } else { value = message.getValue(null, factory); } if (value == null) { if (log.isDebugEnabled()) { log.debug( "There are no elements to unmarshal. XMLDispatch returns a null value"); } } } } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("An error occured while creating the block"); } throw ExceptionFactory.makeWebServiceException(e); } finally { if (!(value instanceof OMElement)) { message.close(); } } if (log.isDebugEnabled()) { if (value == null) log.debug("Returning a null value"); else log.debug("Returning value of type: " + value.getClass().getName()); } return value; } private Class getBlockFactory(Object o) { if (o instanceof String) { if (log.isDebugEnabled()) { log.debug(">> returning XMLStringBlockFactory"); } return XMLStringBlockFactory.class; } else if (Source.class.isAssignableFrom(o.getClass())) { if (log.isDebugEnabled()) { log.debug(">> returning SourceBlockFactory"); } return SourceBlockFactory.class; } else if (DataSource.class.isAssignableFrom(o.getClass())) { if (log.isDebugEnabled()) { log.debug(">> returning DataSourceBlockFactory"); } return DataSourceBlockFactory.class; } else if (SOAPMessage.class.isAssignableFrom(o.getClass())) { if (log.isDebugEnabled()) { log.debug(">> returning SOAPMessageFactory"); } return SOAPEnvelopeBlockFactory.class; } else if (SOAPEnvelope.class.isAssignableFrom(o.getClass())) { if (log.isDebugEnabled()) { log.debug(">> returning SOAPEnvelope"); } return SOAPEnvelopeBlockFactory.class; } else if (OMElement.class.isAssignableFrom(o.getClass())) { if (log.isDebugEnabled()) { log.debug(">> returning OMBlockFactory"); } return OMBlockFactory.class; } if (log.isDebugEnabled()) { log.debug(">> ERROR: Factory not found"); } return null; } private Class getBlockFactory() { if (String.class.isAssignableFrom(type)) { if (log.isDebugEnabled()) { log.debug(">> returning XMLStringBlockFactory"); } return XMLStringBlockFactory.class; } else if (Source.class.isAssignableFrom(type)) { if (log.isDebugEnabled()) { log.debug(">> returning SourceBlockFactory"); } return SourceBlockFactory.class; } else if (SOAPMessage.class.isAssignableFrom(type)) { if (log.isDebugEnabled()) { log.debug(">> returning SOAPMessageFactory"); } return SOAPEnvelopeBlockFactory.class; } else if (SOAPEnvelope.class.isAssignableFrom(type)) { if (log.isDebugEnabled()) { log.debug(">> returning SOAPEnvelope"); } return SOAPEnvelopeBlockFactory.class; } else if (OMElement.class.isAssignableFrom(type)) { if (log.isDebugEnabled()) { log.debug(">> returning OMBlockFactory"); } return OMBlockFactory.class; } if (log.isDebugEnabled()) { log.debug(">> ERROR: Factory not found"); } return null; } private Message createEmptyMessage(Protocol protocol) throws WebServiceException, XMLStreamException { MessageFactory mf = (MessageFactory)FactoryRegistry.getFactory(MessageFactory.class); Message m = mf.create(protocol); return m; } protected void initMessageContext(Object obj, MessageContext requestMsgCtx) { super.initMessageContext(obj, requestMsgCtx); if(obj instanceof DataSource){ requestMsgCtx.setProperty(Constants.Configuration.MESSAGE_FORMATTER, new DataSourceFormatter(((DataSource)obj).getContentType())); } } }