You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ode.apache.org by mr...@apache.org on 2008/05/20 00:57:26 UTC

svn commit: r658024 [2/4] - in /ode/trunk: ./ axis2-war/src/test/java/org/apache/ode/axis2/ axis2-war/src/test/java/org/apache/ode/axis2/httpbinding/ axis2-war/src/test/java/org/apache/ode/axis2/management/ axis2-war/src/test/resources/TestHttpBinding/...

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ExternalService.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ExternalService.java?rev=658024&r1=658023&r2=658024&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ExternalService.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ExternalService.java Mon May 19 15:57:24 2008
@@ -1,306 +1,16 @@
-/*
- * 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.ode.axis2;
 
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-
-import javax.wsdl.Definition;
-import javax.wsdl.Fault;
-import javax.wsdl.Operation;
-import javax.xml.namespace.QName;
-
-import org.apache.axiom.soap.SOAPEnvelope;
-import org.apache.axis2.AxisFault;
-import org.apache.axis2.addressing.EndpointReference;
-import org.apache.axis2.client.OperationClient;
-import org.apache.axis2.client.Options;
-import org.apache.axis2.client.ServiceClient;
-import org.apache.axis2.context.ConfigurationContext;
-import org.apache.axis2.context.MessageContext;
-import org.apache.axis2.engine.AxisConfiguration;
-import org.apache.axis2.wsdl.WSDLConstants;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.ode.axis2.util.SoapMessageConverter;
-import org.apache.ode.bpel.iapi.BpelServer;
-import org.apache.ode.bpel.iapi.Message;
-import org.apache.ode.bpel.iapi.MessageExchange;
 import org.apache.ode.bpel.iapi.PartnerRoleChannel;
 import org.apache.ode.bpel.iapi.PartnerRoleMessageExchange;
-import org.apache.ode.bpel.iapi.Scheduler;
-import org.apache.ode.bpel.iapi.MessageExchange.FailureType;
-import org.apache.ode.il.OMUtils;
-import org.apache.ode.il.epr.EndpointFactory;
-import org.apache.ode.il.epr.MutableEndpoint;
-import org.apache.ode.il.epr.WSAEndpoint;
-import org.apache.ode.utils.DOMUtils;
-import org.apache.ode.utils.Namespaces;
-import org.apache.ode.utils.uuid.UUID;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
+import javax.xml.namespace.QName;
 
 /**
- * Acts as a service not provided by ODE. Used mainly for invocation as a way to maintain the WSDL decription of used services.
- *
- * @author Matthieu Riou <mriou at apache dot org>
+ +  * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
  */
-public class ExternalService implements PartnerRoleChannel {
-
-    private static final Log __log = LogFactory.getLog(ExternalService.class);
-
-    private static final int EXPIRE_SERVICE_CLIENT = 30000;
-
-    private static ThreadLocal<CachedServiceClient> _cachedClients = new ThreadLocal<CachedServiceClient>();
-
-    private Definition _definition;
-
-    private QName _serviceName;
-
-    private String _portName;
-
-    private AxisConfiguration _axisConfig;
-
-    private SoapMessageConverter _converter;
-
-    private Scheduler _sched;
-
-    private BpelServer _server;
-
-    public ExternalService(Definition definition, QName serviceName, String portName, AxisConfiguration axisConfig,
-                           Scheduler sched, BpelServer server) throws AxisFault {
-        _definition = definition;
-        _serviceName = serviceName;
-        _portName = portName;
-        _axisConfig = axisConfig;
-        _sched = sched;
-        _converter = new SoapMessageConverter(definition, serviceName, portName);
-        _server = server;
-    }
-
-    public void invoke(final PartnerRoleMessageExchange odeMex) {
-        boolean isTwoWay = odeMex.getMessageExchangePattern() == org.apache.ode.bpel.iapi.MessageExchange.MessageExchangePattern.REQUEST_RESPONSE;
-        try {
-            // Override options are passed to the axis MessageContext so we can
-            // retrieve them in our session out handler.
-            MessageContext mctx = new MessageContext();
-            writeHeader(mctx, odeMex);
-
-            _converter.createSoapRequest(mctx, odeMex.getRequest(), odeMex.getOperation());
-
-            SOAPEnvelope soapEnv = mctx.getEnvelope();
-            EndpointReference axisEPR = new EndpointReference(((MutableEndpoint) odeMex.getEndpointReference()).getUrl());
-            if (__log.isDebugEnabled()) {
-                __log.debug("Axis2 sending message to " + axisEPR.getAddress() + " using MEX " + odeMex);
-                __log.debug("Message: " + soapEnv);
-            }
-
-            Options options = new Options();
-            options.setAction(mctx.getSoapAction());
-            options.setTo(axisEPR);
-            options.setTimeOutInMilliSeconds(60000);
-            options.setExceptionToBeThrownOnSOAPFault(false);
-
-            CachedServiceClient cached = _cachedClients.get();
-            long now = System.currentTimeMillis();
-            if (cached == null || cached._expire < now) {
-                cached = new CachedServiceClient();
-                ConfigurationContext ctx = new ConfigurationContext(_axisConfig);
-                cached._client = new ServiceClient(ctx, null);
-                cached._expire = now + EXPIRE_SERVICE_CLIENT;
-                _cachedClients.set(cached);
-            }
-            final OperationClient operationClient = cached._client.createClient(isTwoWay ? ServiceClient.ANON_OUT_IN_OP
-                    : ServiceClient.ANON_OUT_ONLY_OP);
-            operationClient.setOptions(options);
-            operationClient.addMessageContext(mctx);
-
-            if (isTwoWay) {
-                final Operation operation = odeMex.getOperation();
-
-                try {
-                    operationClient.execute(true);
-                    MessageContext response = operationClient.getMessageContext(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
-                    MessageContext flt = operationClient.getMessageContext(WSDLConstants.MESSAGE_LABEL_FAULT_VALUE);
-                    if (response != null && __log.isDebugEnabled())
-                        __log.debug("Service response:\n" + response.getEnvelope().toString());
-
-                    if (flt != null) {
-                        reply(odeMex, operation, flt, true);
-                    } else {
-                        reply(odeMex, operation, response, response.isFault());
-                    }
-                } catch (Throwable t) {
-                    String errmsg = "Error sending message to Axis2 for ODE mex " + odeMex;
-                    __log.error(errmsg, t);
-                    replyWithFailure(odeMex, MessageExchange.FailureType.COMMUNICATION_ERROR, errmsg, null);
-                }
-            } else /* one-way case */{
-                operationClient.execute(false);
-                odeMex.replyOneWayOk();
-            }
-        } catch (AxisFault axisFault) {
-            String errmsg = "Error sending message to Axis2 for ODE mex " + odeMex;
-            __log.error(errmsg, axisFault);
-            odeMex.replyWithFailure(MessageExchange.FailureType.COMMUNICATION_ERROR, errmsg, null);
-        }
-    }
-
-    /**
-     * Extracts the action to be used for the given operation.  It first checks to see
-     * if a value is specified using WS-Addressing in the portType, it then falls back onto 
-     * getting it from the SOAP Binding.
-     * @param operation the name of the operation to get the Action for
-     * @return The action value for the specified operation
-     */
-    private String getAction(String operation)
-    {
-        String action = _converter.getWSAInputAction(operation);
-        if (action == null || "".equals(action))
-        {
-            action = _converter.getSoapAction(operation);
-        }
-        return action;
-    }
-
-    /**
-     * Extracts endpoint information from ODE message exchange to stuff them into Axis MessageContext.
-     */
-    private void writeHeader(MessageContext ctxt, PartnerRoleMessageExchange odeMex) {
-        Options options = ctxt.getOptions();
-        WSAEndpoint targetEPR = EndpointFactory.convertToWSA((MutableEndpoint) odeMex.getEndpointReference());
-        WSAEndpoint myRoleEPR = EndpointFactory.convertToWSA((MutableEndpoint) odeMex.getMyRoleEndpointReference());
-
-        String partnerSessionId = odeMex.getProperty(MessageExchange.PROPERTY_SEP_PARTNERROLE_SESSIONID);
-        String myRoleSessionId = odeMex.getProperty(MessageExchange.PROPERTY_SEP_MYROLE_SESSIONID);
-
-        if (partnerSessionId != null) {
-            if (__log.isDebugEnabled()) {
-                __log.debug("Partner session identifier found for WSA endpoint: " + partnerSessionId);
-            }
-            targetEPR.setSessionId(partnerSessionId);
-        }
-        options.setProperty("targetSessionEndpoint", targetEPR);
-
-        if (myRoleEPR != null) {
-            if (myRoleSessionId != null) {
-                if (__log.isDebugEnabled()) {
-                    __log.debug("MyRole session identifier found for myrole (callback) WSA endpoint: " + myRoleSessionId);
-                }
-                myRoleEPR.setSessionId(myRoleSessionId);
-            }
-            options.setProperty("callbackSessionEndpoint", odeMex.getMyRoleEndpointReference());
-        } else {
-            __log.debug("My-Role EPR not specified, SEP will not be used.");
-        }
-
-        String action = getAction(odeMex.getOperationName());
-        ctxt.setSoapAction(action);
-
-        if (MessageExchange.MessageExchangePattern.REQUEST_RESPONSE == odeMex.getMessageExchangePattern()) {
-            EndpointReference annonEpr =
-                    new EndpointReference(Namespaces.WS_ADDRESSING_ANON_URI);
-            ctxt.setReplyTo(annonEpr);
-            ctxt.setMessageID("uuid:" + new UUID().toString());
-        }
-    }
-
-    public org.apache.ode.bpel.iapi.EndpointReference getInitialEndpointReference() {
-        Element eprElmt = ODEService.genEPRfromWSDL(_definition, _serviceName, _portName);
-        if (eprElmt == null)
-            throw new IllegalArgumentException("Service " + _serviceName + " and port " + _portName
-                    + "couldn't be found in provided WSDL document!");
-        return EndpointFactory.convertToWSA(ODEService.createServiceRef(eprElmt));
-    }
-
-    public void close() {
-        // nothing
-    }
-
-    public String getPortName() {
-        return _portName;
-    }
-
-    public QName getServiceName() {
-        return _serviceName;
-    }
-
-    private void replyWithFailure(final PartnerRoleMessageExchange odeMex, final FailureType error, final String errmsg, final Element details) {
-        try {
-            odeMex.replyWithFailure(error, errmsg, details);
-        } catch (Exception e) {
-            String emsg = "Error executing replyWithFailure; reply will be lost.";
-            __log.error(emsg, e);
-
-        }
-
-    }
-
-    private void reply(final PartnerRoleMessageExchange odeMex, final Operation operation, final MessageContext reply, final boolean fault) {
-        try {
-            if (__log.isDebugEnabled()) __log.debug("Received response for MEX " + odeMex);
-            if (fault) {
-                Document odeMsg = DOMUtils.newDocument();
-                Element odeMsgEl = odeMsg.createElementNS(null, "message");
-                odeMsg.appendChild(odeMsgEl);
-                QName faultType = _converter.parseSoapFault(odeMsgEl, reply.getEnvelope(), operation);
-                if (__log.isDebugEnabled()) __log.debug("Reply is a fault, found type: " + faultType);
-
-                if (faultType != null) {
-                    if (__log.isWarnEnabled())
-                        __log.warn("Fault response: faultType=" + faultType + "\n" + DOMUtils.domToString(odeMsgEl));
-                    QName nonNullFT = new QName(Namespaces.ODE_EXTENSION_NS, "unknownFault");
-                    Fault f = odeMex.getOperation().getFault(faultType.getLocalPart());
-                    if (f != null && f.getMessage().getQName() != null) nonNullFT = f.getMessage().getQName();
-                    else __log.debug("Fault " + faultType + " isn't referenced in the service definition, unknown fault.");
-
-                    Message response = odeMex.createMessage(nonNullFT);
-                    response.setMessage(odeMsgEl);
-
-                    odeMex.replyWithFault(faultType, response);
-                } else {
-                    if (__log.isWarnEnabled())
-                        __log.warn("Fault response: faultType=(unkown)\n" + reply.getEnvelope().toString());
-                    odeMex.replyWithFailure(FailureType.OTHER, reply.getEnvelope().getBody().getFault().getText(),
-                            OMUtils.toDOM(reply.getEnvelope().getBody()));
-                }
-            } else {
-                Message response = odeMex.createMessage(odeMex.getOperation().getOutput().getMessage().getQName());
-                _converter.parseSoapResponse(response, reply.getEnvelope(), operation);
-                if (__log.isInfoEnabled()) __log.info("Response:\n" + (response.getMessage() != null ?
-                        DOMUtils.domToString(response.getMessage()) : "empty"));
-                odeMex.reply(response);
-            }
-        } catch (Exception ex) {
-            String errmsg = "Unable to process response: " + ex.getMessage();
-            __log.error(errmsg, ex);
-            odeMex.replyWithFailure(FailureType.OTHER, errmsg, null);
-        }
-
-    }
-
-    // INNER CLASS
-    static class CachedServiceClient {
-        ServiceClient _client;
+public interface ExternalService extends PartnerRoleChannel {
+    void invoke(PartnerRoleMessageExchange odeMex);
 
-        long _expire;
-    }
+    String getPortName();
 
+    QName getServiceName();
 }

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/MessageExchangeContextImpl.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/MessageExchangeContextImpl.java?rev=658024&r1=658023&r2=658024&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/MessageExchangeContextImpl.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/MessageExchangeContextImpl.java Mon May 19 15:57:24 2008
@@ -63,7 +63,7 @@
 
         ExternalService service = (ExternalService)partnerRoleMessageExchange.getPartnerRoleChannel();
         if (__log.isDebugEnabled())
-            __log.debug("The service to invoke is the external service " + service);
+            __log.debug("The service to invoke is the external service " + service.getServiceName()+":"+service.getPortName());
         service.invoke(partnerRoleMessageExchange);
         
     }

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/Messages.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/Messages.java?rev=658024&r1=658023&r2=658024&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/Messages.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/Messages.java Mon May 19 15:57:24 2008
@@ -107,30 +107,6 @@
         return format("Error shutting down service unit \"{0}\".", serviceUnitID);
     }
 
-    /** Port {0} is missing <wsdl:binding> or <soapbind:binding> */
-    public String msgNoBindingForPort(QName sericeName) {
-        return format("Couldn't find any port in service {0} having <wsdl:binding> and <soapbind:binding>", sericeName);
-    }
-
-    /** Port {0} has multiple <soapbind:binding> elements */
-    public String msgMultipleSoapBindingsForPort(String portName) {
-        return format("Port {0} has multiple <soapbind:binding> elements", portName);
-    }
-
-    /**
-     * Attempted to import WSDL for namespace {0} from multiple locations:
-     * definitions from {1} will be ignored
-     */
-    public String msgDuplicateWSDLImport(String tns, String location) {
-        return format("Attempted to import WSDL for namespace {0} from"
-                + " multiple locations: definitions from {1} will be ignored", tns, location);
-    }
-
-    /** The WSDL for namespace "{0}" could not be found in "{1}". */
-    public String msgWsdlImportNotFound(String wsdlUri, String location) {
-        return format("The WSDL for namespace \"{0}\" could not be found in \"{1}\".", wsdlUri, location);
-    }
-
     public String msgBpelEventListenerRegistered(String listenerCN) {
         return format("Registered custom BPEL event listener: {0}", listenerCN);
     }
@@ -152,93 +128,6 @@
 
     }
 
-    public Throwable msgOdeMessageMissingRequiredPart(String partName) {
-        String s = format("Message is missing required part: {0}", partName);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgServiceDefinitionNotFound(QName serviceName) {
-        String s = format("Servicd definition not found: {0}.", serviceName);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgPortDefinitionNotFound(QName serviceName, String portName) {
-        String s = format("Port definition not found: service {0} port {1}.", serviceName, portName);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgBindingOperationNotFound(QName serviceName, String portName, String name) {
-        String s = format("Binding operation not found: service {0} port {1} name {2}.", serviceName, portName, name);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgBindingInputNotFound(QName serviceName, String portName, String name) {
-        String s = format("Binding input not found: service {0} port {1} name {2}.", serviceName, portName, name);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgBindingNotFound(QName serviceName, String portName) {
-        String s = format("Binding not found: service {0} port {1}.", serviceName, portName);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgNoSOAPBindingForPort(String name) {
-        String s = format("No SOAP binding for port: {0}.", name);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgSoapHeaderReferencesUnkownPart(String part) {
-        String s = format("SOAP header references unknown part: {0}.", part);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgBindingDefinesNonElementDocListParts() {
-        String s = format("Binding defines non-element document literal part(s)");
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgUnexpectedElementInSOAPBody(QName name, QName elementName) {
-        String s = format("Unexpected element in SOAP body: message {0} element {1}.", name, elementName);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgSOAPBodyDoesNotContainAllRequiredParts() {
-        String s = format("SOAP body does not contain all required parts");
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgSOAPBodyDoesNotContainRequiredPart(String name) {
-        String s = format("SOAP body does not contain required part: {0}.", name);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgSoapHeaderMissingRequiredElement(QName elementType) {
-        String s = format("SOAP header missing required element: {0}.", elementType);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgBindingOutputNotFound(QName serviceName, String portName, String name) {
-        String s = format("Binding output not found: service {0} port {1} name {2}.", serviceName, portName, name);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgUndefinedFault(QName serviceName, String portName, String opname, QName faultName) {
-        String s = format("Undefined fault: service {0} port {1} operation {2} fault {3}.", serviceName, portName, opname, faultName);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgOdeMessagePartMissingRequiredElement(QName serviceName, String portName, String opname, QName elementName) {
-        String s = format("Message part is missing required element: service {0} port {1} operation {2} element {3}.",
-                          serviceName, portName, opname, elementName);
-        return new IllegalArgumentException(s);
-    }
-
-    public Throwable msgSoapBodyDoesNotContainExpectedPartWrapper(QName serviceName, String portName, QName rpcWrapQName) {
-        String s = format("SOAP body does not contain expected part wrapper: service {0} port {1} wrapper {2}",
-                          serviceName, portName, rpcWrapQName);
-        return new IllegalArgumentException(s);
-    }
-
     public String msgOdeDbConfigError() {
         return format("Error starting database connections, check the database configuration!");
     }

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ODEServer.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ODEServer.java?rev=658024&r1=658023&r2=658024&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ODEServer.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ODEServer.java Mon May 19 15:57:24 2008
@@ -45,6 +45,7 @@
 import org.apache.ode.axis2.hooks.ODEMessageReceiver;
 import org.apache.ode.axis2.service.DeploymentWebService;
 import org.apache.ode.axis2.service.ManagementService;
+import org.apache.ode.axis2.httpbinding.HttpExternalService;
 import org.apache.ode.bpel.compiler.api.ExtensionValidator;
 import org.apache.ode.bpel.connector.BpelServerConnector;
 import org.apache.ode.bpel.dao.BpelDAOConnectionFactory;
@@ -65,6 +66,7 @@
 import org.apache.ode.scheduler.simple.SimpleScheduler;
 import org.apache.ode.store.ProcessStoreImpl;
 import org.apache.ode.utils.GUID;
+import org.apache.ode.utils.wsdl.WsdlUtils;
 import org.apache.ode.utils.fs.TempFileManager;
 import org.apache.ode.bpel.pmapi.InstanceManagement;
 import org.apache.ode.bpel.pmapi.ProcessManagement;
@@ -207,8 +209,7 @@
      * Shutdown the service engine. This performs cleanup before the BPE is terminated. Once this method has been called, init()
      * must be called before the transformation engine can be started again with a call to start().
      *
-     * @throws AxisFault
-     *             if the engine is unable to shut down.
+     * @throws AxisFault if the engine is unable to shut down.
      */
     public void shutDown() throws AxisFault {
 
@@ -316,18 +317,27 @@
         return odeService;
     }
 
-    public ExternalService createExternalService(Definition def, QName serviceName, String portName) throws ContextException {
+    public ExternalService createExternalService(Definition def, QName serviceName, String portName, ProcessConf pconf) throws ContextException {
         ExternalService extService = (ExternalService) _externalServices.get(serviceName);
         if (extService != null)
             return extService;
 
         try {
-            extService = new ExternalService(def, serviceName, portName, _axisConfig, _scheduler, _server);
+             if (WsdlUtils.useHTTPBinding(def, serviceName, portName)) {
+                 if(__log.isDebugEnabled())__log.debug("Creating HTTP-bound external service " + serviceName);
+                 extService = new HttpExternalService(def, serviceName, portName, _server);
+             } else if (WsdlUtils.useSOAPBinding(def, serviceName, portName)) {
+                 if(__log.isDebugEnabled())__log.debug("Creating SOAP-bound external service " + serviceName);
+                 extService = new SoapExternalService(def, serviceName, portName, _axisConfig, pconf);
+             }
         } catch (Exception ex) {
             __log.error("Could not create external service.", ex);
-            throw new ContextException("Error creating external service.", ex);
+            throw new ContextException("Error creating external service! name:"+serviceName+", port:"+portName, ex);
         }
 
+         // if not SOAP nor HTTP binding
+         if (extService == null) throw new ContextException("Only SOAP and HTTP binding supported!");
+
         _externalServices.put(serviceName, portName, extService);
         __log.debug("Created external service " + serviceName);
         return extService;
@@ -424,7 +434,7 @@
     }
 
     protected ProcessStoreImpl createProcessStore(DataSource ds) {
-        return new ProcessStoreImpl(ds, _odeConfig.getDAOConnectionFactory(),false);
+        return new ProcessStoreImpl(ds, _odeConfig.getDAOConnectionFactory(), _odeConfig, false);
     }
 
     protected Scheduler createScheduler() {
@@ -548,9 +558,9 @@
         jdbcext = new JdbcExternalVariableModule();
         jdbcext.registerDataSource("ode", _db.getDataSource());
         _server.registerExternalVariableEngine(jdbcext);
-        
+
     }
-    
+
     private class ProcessStoreListenerImpl implements ProcessStoreListener {
 
         public void onProcessStoreEvent(ProcessStoreEvent event) {
@@ -567,11 +577,8 @@
                 // bounce the process
                 _server.unregister(pse.pid);
                 ProcessConf pconf = _store.getProcessConfiguration(pse.pid);
-                if (pconf != null)
-                    _server.register(pconf);
-                else {
-                    __log.debug("slighly odd: recevied event " + pse + " for process not in store!");
-                }
+                if (pconf != null) _server.register(pconf);
+                else __log.debug("slighly odd: recevied event " + pse + " for process not in store!");
                 break;
             case DISABLED:
             case UNDEPLOYED:

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ODEService.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ODEService.java?rev=658024&r1=658023&r2=658024&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ODEService.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ODEService.java Mon May 19 15:57:24 2008
@@ -23,11 +23,13 @@
 import javax.wsdl.Port;
 import javax.wsdl.Service;
 import javax.wsdl.extensions.UnknownExtensibilityElement;
+import javax.wsdl.extensions.http.HTTPAddress;
 import javax.wsdl.extensions.soap.SOAPAddress;
 import javax.xml.namespace.QName;
 
-import org.apache.axiom.om.OMElement;
-import org.apache.axiom.soap.*;
+import org.apache.axiom.soap.SOAPEnvelope;
+import org.apache.axiom.soap.SOAPFactory;
+import org.apache.axiom.soap.SOAPFault;
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.context.MessageContext;
 import org.apache.axis2.description.AxisService;
@@ -257,6 +259,10 @@
                         Element soapAddr = doc.createElementNS(Namespaces.SOAP_NS, "address");
                         port.appendChild(soapAddr);
                         soapAddr.setAttribute("location", ((SOAPAddress) extElmt).getLocationURI());
+                    } else if (extElmt instanceof HTTPAddress) {
+                        Element httpAddr = doc.createElementNS(Namespaces.HTTP_NS, "address");
+                        port.appendChild(httpAddr);
+                        httpAddr.setAttribute("location", ((HTTPAddress) extElmt).getLocationURI());
                     } else {
                         port.appendChild(doc.importNode(((UnknownExtensibilityElement) extElmt).getElement(), true));
                     }

Copied: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/SoapExternalService.java (from r658020, ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ExternalService.java)
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/SoapExternalService.java?p2=ode/trunk/axis2/src/main/java/org/apache/ode/axis2/SoapExternalService.java&p1=ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ExternalService.java&r1=658020&r2=658024&rev=658024&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/ExternalService.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/SoapExternalService.java Mon May 19 15:57:24 2008
@@ -1,27 +1,24 @@
 /*
- * 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.
- */
+     * 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.ode.axis2;
 
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-
 import javax.wsdl.Definition;
 import javax.wsdl.Fault;
 import javax.wsdl.Operation;
@@ -29,6 +26,7 @@
 
 import org.apache.axiom.soap.SOAPEnvelope;
 import org.apache.axis2.AxisFault;
+import org.apache.axis2.deployment.ServiceBuilder;
 import org.apache.axis2.addressing.EndpointReference;
 import org.apache.axis2.client.OperationClient;
 import org.apache.axis2.client.Options;
@@ -40,12 +38,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ode.axis2.util.SoapMessageConverter;
-import org.apache.ode.bpel.iapi.BpelServer;
-import org.apache.ode.bpel.iapi.Message;
-import org.apache.ode.bpel.iapi.MessageExchange;
-import org.apache.ode.bpel.iapi.PartnerRoleChannel;
-import org.apache.ode.bpel.iapi.PartnerRoleMessageExchange;
-import org.apache.ode.bpel.iapi.Scheduler;
+import org.apache.ode.bpel.iapi.*;
 import org.apache.ode.bpel.iapi.MessageExchange.FailureType;
 import org.apache.ode.il.OMUtils;
 import org.apache.ode.il.epr.EndpointFactory;
@@ -53,46 +46,40 @@
 import org.apache.ode.il.epr.WSAEndpoint;
 import org.apache.ode.utils.DOMUtils;
 import org.apache.ode.utils.Namespaces;
+import org.apache.ode.utils.fs.FileWatchDog;
 import org.apache.ode.utils.uuid.UUID;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import java.io.File;
+import java.io.InputStream;
+
 /**
  * Acts as a service not provided by ODE. Used mainly for invocation as a way to maintain the WSDL decription of used services.
  *
  * @author Matthieu Riou <mriou at apache dot org>
  */
-public class ExternalService implements PartnerRoleChannel {
+public class SoapExternalService implements ExternalService, PartnerRoleChannel {
 
     private static final Log __log = LogFactory.getLog(ExternalService.class);
-
     private static final int EXPIRE_SERVICE_CLIENT = 30000;
-
     private static ThreadLocal<CachedServiceClient> _cachedClients = new ThreadLocal<CachedServiceClient>();
 
     private Definition _definition;
-
     private QName _serviceName;
-
     private String _portName;
-
     private AxisConfiguration _axisConfig;
-
     private SoapMessageConverter _converter;
+    private ProcessConf _pconf;
 
-    private Scheduler _sched;
-
-    private BpelServer _server;
-
-    public ExternalService(Definition definition, QName serviceName, String portName, AxisConfiguration axisConfig,
-                           Scheduler sched, BpelServer server) throws AxisFault {
+    public SoapExternalService(Definition definition, QName serviceName, String portName,
+                               AxisConfiguration axisConfig, ProcessConf pconf) throws AxisFault {
         _definition = definition;
         _serviceName = serviceName;
         _portName = portName;
         _axisConfig = axisConfig;
-        _sched = sched;
         _converter = new SoapMessageConverter(definition, serviceName, portName);
-        _server = server;
+        _pconf = pconf;
     }
 
     public void invoke(final PartnerRoleMessageExchange odeMex) {
@@ -118,15 +105,8 @@
             options.setTimeOutInMilliSeconds(60000);
             options.setExceptionToBeThrownOnSOAPFault(false);
 
-            CachedServiceClient cached = _cachedClients.get();
-            long now = System.currentTimeMillis();
-            if (cached == null || cached._expire < now) {
-                cached = new CachedServiceClient();
-                ConfigurationContext ctx = new ConfigurationContext(_axisConfig);
-                cached._client = new ServiceClient(ctx, null);
-                cached._expire = now + EXPIRE_SERVICE_CLIENT;
-                _cachedClients.set(cached);
-            }
+            CachedServiceClient cached = getCachedServiceClient();
+
             final OperationClient operationClient = cached._client.createClient(isTwoWay ? ServiceClient.ANON_OUT_IN_OP
                     : ServiceClient.ANON_OUT_ONLY_OP);
             operationClient.setOptions(options);
@@ -142,11 +122,8 @@
                     if (response != null && __log.isDebugEnabled())
                         __log.debug("Service response:\n" + response.getEnvelope().toString());
 
-                    if (flt != null) {
-                        reply(odeMex, operation, flt, true);
-                    } else {
-                        reply(odeMex, operation, response, response.isFault());
-                    }
+                    if (flt != null) reply(odeMex, operation, flt, true);
+                    else reply(odeMex, operation, response, response.isFault());
                 } catch (Throwable t) {
                     String errmsg = "Error sending message to Axis2 for ODE mex " + odeMex;
                     __log.error(errmsg, t);
@@ -163,20 +140,32 @@
         }
     }
 
+    private CachedServiceClient getCachedServiceClient() throws AxisFault {
+        CachedServiceClient cached = _cachedClients.get();
+        if (cached == null) {
+            cached = new CachedServiceClient(new File(_pconf.getBaseURI().resolve(_serviceName.getLocalPart() + ".axis2")), EXPIRE_SERVICE_CLIENT);
+            _cachedClients.set(cached);
+        }
+        try {
+            // call manually the check procedure
+            // we dont want a dedicated thread for that
+            cached.checkAndConfigure();
+        } catch (Exception e) {
+            throw AxisFault.makeFault(e);
+        }
+        return cached;
+    }
+
     /**
      * Extracts the action to be used for the given operation.  It first checks to see
-     * if a value is specified using WS-Addressing in the portType, it then falls back onto 
+     * if a value is specified using WS-Addressing in the portType, it then falls back onto
      * getting it from the SOAP Binding.
      * @param operation the name of the operation to get the Action for
      * @return The action value for the specified operation
      */
-    private String getAction(String operation)
-    {
+    private String getAction(String operation) {
         String action = _converter.getWSAInputAction(operation);
-        if (action == null || "".equals(action))
-        {
-            action = _converter.getSoapAction(operation);
-        }
+        if (action == null || "".equals(action)) action = _converter.getSoapAction(operation);
         return action;
     }
 
@@ -296,11 +285,44 @@
 
     }
 
-    // INNER CLASS
-    static class CachedServiceClient {
+
+    /**
+     * This class wraps a {@link org.apache.axis2.client.ServiceClient} and watches changes (deletions,creations,updates)
+     *  on a  Axis2 service config file named {service-name}.axis2.<p/>
+     * The {@link org.apache.axis2.client.ServiceClient} instance is created from the main Axis2 config instance and
+     * this service-specific config file.
+     */
+    class CachedServiceClient extends FileWatchDog {
         ServiceClient _client;
 
-        long _expire;
+        protected CachedServiceClient(File file, long delay) {
+            super(file, delay);
+        }
+
+        protected boolean isInitialized() throws Exception {
+            return _client != null;
+        }
+
+        protected void init() throws Exception {
+            _client = new ServiceClient(new ConfigurationContext(_axisConfig), null);
+        }
+
+        protected void doOnUpdate() throws Exception {
+            // axis2 service configuration
+            // if the config file has been modified (i.e added or updated), re-create a ServiceClient
+            // and load the new config.
+            init(); //reset the ServiceClient instance
+            try {
+                InputStream ais = file.toURI().toURL().openStream();
+                if (ais != null) {
+                    if (__log.isDebugEnabled()) __log.debug("Configuring service " + _serviceName + " using: " + file);
+                    ServiceBuilder builder = new ServiceBuilder(ais, new ConfigurationContext(_client.getAxisConfiguration()), _client.getAxisService());
+                    builder.populateService(builder.buildOM());
+                }
+            } catch (Exception e) {
+                if (__log.isWarnEnabled()) __log.warn("Exception while configuring service: " + _serviceName, e);
+            }
+        }
     }
 
 }

Added: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpBindingValidator.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpBindingValidator.java?rev=658024&view=auto
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpBindingValidator.java (added)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpBindingValidator.java Mon May 19 15:57:24 2008
@@ -0,0 +1,153 @@
+/*
+ * 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.ode.axis2.httpbinding;
+
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.ode.utils.wsdl.WsdlUtils;
+
+import javax.wsdl.Binding;
+import javax.wsdl.BindingInput;
+import javax.wsdl.BindingOperation;
+import javax.wsdl.BindingOutput;
+import javax.wsdl.extensions.http.HTTPBinding;
+import javax.wsdl.extensions.http.HTTPOperation;
+import java.util.Map;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
+ */
+public class HttpBindingValidator {
+
+    private static final Messages httpMsgs = Messages.getMessages(Messages.class);
+    private static final org.apache.ode.utils.wsdl.Messages wsdlMsgs = Messages.getMessages(org.apache.ode.utils.wsdl.Messages.class);
+
+    protected Binding binding;
+    private String verb;
+
+    public HttpBindingValidator(Binding binding) {
+        this.binding = binding;
+        if (!WsdlUtils.useHTTPBinding(binding))
+            throw new IllegalArgumentException(httpMsgs.msgHttpBindingNotUsed(binding));
+        HTTPBinding httpBinding = (HTTPBinding) WsdlUtils.getBindingExtension(binding);
+        verb = httpBinding.getVerb();
+    }
+
+    public void validate() throws IllegalArgumentException {
+        validatePort();
+    }
+
+    protected void validatePort() {
+
+        if (!"GET".equalsIgnoreCase(verb)
+                && !"DELETE".equalsIgnoreCase(verb)
+                && !"PUT".equalsIgnoreCase(verb)
+                && !"POST".equalsIgnoreCase(verb)) {
+            throw new IllegalArgumentException(httpMsgs.msgUnsupportedHttpMethod(binding, verb));
+        }
+
+        // Validate the given HttpBinding
+        for (int i = 0; i < binding.getBindingOperations().size(); i++) {
+            BindingOperation bindingOperation = (BindingOperation) binding.getBindingOperations().get(i);
+            validateOperation(bindingOperation);
+        }
+    }
+
+    protected void validateOperation(BindingOperation bindingOperation) {
+        BindingOutput output = bindingOperation.getBindingOutput();
+        String outputContentType = WsdlUtils.getMimeContentType(output.getExtensibilityElements());
+        if (!outputContentType.endsWith("text/xml")) {
+            throw new IllegalArgumentException(httpMsgs.msgUnsupportedContentType(binding, bindingOperation));
+        }
+
+        Map outputParts = bindingOperation.getOperation().getOutput().getMessage().getParts();
+        if (outputParts.size() > 1) {
+            throw new IllegalArgumentException(httpMsgs.msgOnePartOnlyForOutput(binding, bindingOperation));
+        }
+
+        BindingInput input = bindingOperation.getBindingInput();
+        String inputContentType = WsdlUtils.getMimeContentType(input.getExtensibilityElements());
+
+        // multipartRelated not supported
+        if (WsdlUtils.useMimeMultipartRelated(input)) {
+            throw new IllegalArgumentException(httpMsgs.msgMimeMultipartRelatedUnsupported(binding, bindingOperation));
+        }
+
+        // only 2 content-types supported
+        if (inputContentType != null) {
+            if (!inputContentType.endsWith("text/xml") && !PostMethod.FORM_URL_ENCODED_CONTENT_TYPE.equalsIgnoreCase(inputContentType)) {
+                throw new IllegalArgumentException(httpMsgs.msgUnsupportedContentType(binding, bindingOperation));
+            }
+            Map inputParts = bindingOperation.getOperation().getInput().getMessage().getParts();
+            if (inputParts.size() > 1) {
+                if (!PostMethod.FORM_URL_ENCODED_CONTENT_TYPE.equalsIgnoreCase(inputContentType)) {
+                    throw new IllegalArgumentException(httpMsgs.msgInvalidContentType(binding, bindingOperation));
+                }
+            }
+        }
+
+        if (WsdlUtils.useUrlReplacement(input)) {
+            validateUrlReplacement(bindingOperation);
+        }
+
+        // other specific validations
+        if ("GET".equalsIgnoreCase(verb) || "DELETE".equalsIgnoreCase(verb)) {
+            validateGetOrDelete(bindingOperation);
+        }
+    }
+
+    protected void validateGetOrDelete(BindingOperation bindingOperation) {
+        BindingInput input = bindingOperation.getBindingInput();
+
+        if (!WsdlUtils.useUrlEncoded(input) && !WsdlUtils.useUrlReplacement(input)) {
+            throw new IllegalArgumentException(httpMsgs.msgOnlySupportsUrlEncodedAndUrlreplacement(binding, bindingOperation));
+        }
+
+        // another test would be to check that all parts use a simple type
+    }
+
+    protected void validateUrlReplacement(BindingOperation bindingOperation) {
+        HTTPOperation httpOperation = (HTTPOperation) WsdlUtils.getOperationExtension(bindingOperation);
+        BindingInput input = bindingOperation.getBindingInput();
+        Map inputParts = bindingOperation.getOperation().getInput().getMessage().getParts();
+
+        // validate the url pattern
+        if (WsdlUtils.useUrlReplacement(input)) {
+            String locationUri = httpOperation.getLocationURI();
+            Set partNames = inputParts.keySet();
+            // Must be *exactly* one search pattern for each message part.
+            for (Iterator it = partNames.iterator(); it.hasNext();) {
+                String name = (String) it.next();
+                Pattern p = Pattern.compile(".*(\\(" + name + "\\)).*");
+                Matcher m = p.matcher(locationUri);
+                // is there a regex to do both validations in one?
+                if (!m.matches() || locationUri.split("(\\(" + name + "\\))", -1).length != 2) {
+                    throw new IllegalArgumentException(httpMsgs.msgInvalidURIPattern(binding, bindingOperation, locationUri));
+                }
+            }
+        }
+
+        // another test would be to check that all parts use a simple type
+    }
+
+}

Added: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java?rev=658024&view=auto
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java (added)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java Mon May 19 15:57:24 2008
@@ -0,0 +1,365 @@
+/*
+ * 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.ode.axis2.httpbinding;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.URIException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ode.axis2.ExternalService;
+import org.apache.ode.axis2.ODEService;
+import org.apache.ode.il.epr.EndpointFactory;
+import org.apache.ode.il.epr.WSAEndpoint;
+import org.apache.ode.bpel.iapi.BpelServer;
+import org.apache.ode.bpel.iapi.EndpointReference;
+import org.apache.ode.bpel.iapi.MessageExchange;
+import org.apache.ode.bpel.iapi.PartnerRoleMessageExchange;
+import org.apache.ode.bpel.iapi.Scheduler;
+import org.apache.ode.utils.DOMUtils;
+import org.apache.ode.utils.Namespaces;
+import org.apache.ode.utils.wsdl.Messages;
+import org.apache.ode.utils.wsdl.WsdlUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import javax.wsdl.Binding;
+import javax.wsdl.Definition;
+import javax.wsdl.Operation;
+import javax.wsdl.Part;
+import javax.wsdl.Port;
+import javax.wsdl.Service;
+import javax.xml.namespace.QName;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+
+
+/**
+ * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
+ */
+public class HttpExternalService implements ExternalService {
+
+    private static final Log log = LogFactory.getLog(HttpExternalService.class);
+    private static final Messages msgs = Messages.getMessages(Messages.class);
+
+    private MultiThreadedHttpConnectionManager connections = new MultiThreadedHttpConnectionManager();
+
+    protected BpelServer server;
+    protected QName serviceName;
+    protected String portName;
+
+    protected HttpMethodBuilder methodBuilder;
+    protected WSAEndpoint endpointReference;
+
+    public HttpExternalService(Definition definition, QName serviceName, String portName, BpelServer server) {
+        this.portName = portName;
+        this.serviceName = serviceName;
+        this.server = server;
+
+        Service serviceDef = definition.getService(serviceName);
+        if (serviceDef == null)
+            throw new IllegalArgumentException(msgs.msgServiceDefinitionNotFound(serviceName));
+        Port port = serviceDef.getPort(portName);
+        if (port == null)
+            throw new IllegalArgumentException(msgs.msgPortDefinitionNotFound(serviceName, portName));
+        Binding binding = port.getBinding();
+        if (binding == null)
+            throw new IllegalArgumentException(msgs.msgBindingNotFound(portName));
+
+        // validate the http binding
+        if (!WsdlUtils.useHTTPBinding(port)) {
+            throw new IllegalArgumentException(msgs.msgNoHTTPBindingForPort(portName));
+        }
+        // throws an IllegalArgumentException if not valid
+        new HttpBindingValidator(binding).validate();
+
+        // initial endpoint reference
+        Element eprElmt = ODEService.genEPRfromWSDL(definition, serviceName, portName);
+        if (eprElmt == null)
+            throw new IllegalArgumentException(msgs.msgPortDefinitionNotFound(serviceName, portName));
+        endpointReference = EndpointFactory.convertToWSA(ODEService.createServiceRef(eprElmt));
+
+        methodBuilder = new HttpMethodBuilder(binding);
+    }
+
+    public String getPortName() {
+        return portName;
+    }
+
+    public QName getServiceName() {
+        return serviceName;
+    }
+
+    public void close() {
+        connections.shutdown();
+    }
+
+    public EndpointReference getInitialEndpointReference() {
+        return endpointReference;
+    }
+
+    public void invoke(PartnerRoleMessageExchange odeMex) {
+        if (log.isDebugEnabled()) log.debug("Preparing " + getClass().getSimpleName() + " invocation...");
+        try {
+            // build the http method
+            final HttpMethod method = methodBuilder.buildHttpMethod(odeMex);
+            // this callable encapsulate the http method execution and the process of the response
+            final Callable executionCallable;
+
+            // execute it
+            boolean isTwoWay = odeMex.getMessageExchangePattern() == org.apache.ode.bpel.iapi.MessageExchange.MessageExchangePattern.REQUEST_RESPONSE;
+            if (isTwoWay) {
+                // two way
+                executionCallable = new HttpExternalService.TwoWayCallable(method, odeMex, odeMex.getOperation());
+                executionCallable.call();
+            } else {
+                // one way, just execute and forget
+                executionCallable = new HttpExternalService.OneWayCallable(method, odeMex, odeMex.getOperation());
+                executionCallable.call();
+                odeMex.replyOneWayOk();
+            }
+        } catch (UnsupportedEncodingException e) {
+            String errmsg = "The HTTP encoding returned isn't supported " + odeMex;
+            log.error(errmsg, e);
+            odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, null);
+        } catch (Exception e) {
+            String errmsg = "Unknown HTTP call error for ODE mex " + odeMex;
+            log.error(errmsg, e);
+            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, null);
+        }
+
+    }
+
+
+    private class OneWayCallable implements Callable<Void> {
+        HttpMethod method;
+        PartnerRoleMessageExchange odeMex;
+        Operation operation;
+
+        public OneWayCallable(HttpMethod method, PartnerRoleMessageExchange odeMex, Operation operation) {
+            this.method = method;
+            this.odeMex = odeMex;
+            this.operation = operation;
+        }
+
+        public Void call() {
+            return callOneWay();
+        }
+
+        public Void callOneWay() {
+            try {
+                // simply execute the http method
+                HttpClient client = new HttpClient(connections);
+                if (log.isDebugEnabled())
+                    log.debug("Executing http request : " + method.getName() + " " + method.getURI());
+                final int statusCode = client.executeMethod(method);
+                // invoke getResponseBody to force the loading of the body 
+                // Actually the processResponse may happen in a separate thread and
+                // as a result the connection might be closed before the body processing (see the finally clause below).
+                byte[] responseBody = method.getResponseBody();
+                // ... and process the response
+                processResponse(statusCode);
+            } catch (final IOException e) {
+                // Shit happened, recording the failure
+                try {
+                    String errmsg = "Unable to execute http request : " + e.getMessage();
+                    log.error(errmsg, e);
+                    odeMex.replyWithFailure(MessageExchange.FailureType.COMMUNICATION_ERROR, errmsg, null);
+                } catch (Exception e1) {
+                    String errmsg = "Error executing reply transaction; reply will be lost.";
+                    log.error(errmsg, e);
+                }
+            } finally {
+                method.releaseConnection();
+            }
+            return null;
+        }
+
+        public void processResponse(int statusCode) {
+            // a one-way message does not care about the response
+            try {
+                // log the URI since the engine may have moved on while this One Way request was executing
+                if (statusCode >= 400) {
+                    if (log.isWarnEnabled()) log.warn("OneWay http request ["+method.getURI()+"] failed with status: " + method.getStatusLine());
+                } else {
+                    if (log.isDebugEnabled()) log.debug("OneWay http request ["+method.getURI()+"] status: " + method.getStatusLine());
+                }
+            } catch (URIException e) {
+                if(log.isDebugEnabled()) log.debug(e);
+            }
+        }
+    }
+
+    private class TwoWayCallable extends OneWayCallable {
+        public TwoWayCallable(HttpMethod method, PartnerRoleMessageExchange odeMex, Operation operation) {
+            super(method, odeMex, operation);
+        }
+
+        public void processResponse(final int statusCode) {
+            try {
+                if (statusCode >= 200 && statusCode < 300) {
+                    success();
+                } else if (statusCode >= 300 && statusCode < 400) {
+                    redirection();
+                } else if (statusCode >= 400 && statusCode < 500) {
+                    badRequest();
+                } else if (statusCode >= 500 && statusCode < 600) {
+                    serverError();
+                } else {
+                    unmanagedStatus();
+                }
+            } catch (Exception e) {
+                String errmsg = "Error executing reply transaction; reply will be lost.";
+                log.error(errmsg, e);
+            }
+        }
+
+        private void unmanagedStatus() {
+            String errmsg = "Unmanaged Status Code! " + method.getStatusLine();
+            log.error(errmsg);
+            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, null);
+        }
+
+        private void serverError() {
+            QName type = new QName(Namespaces.ODE_EXTENSION_NS, "HttpRemoteServerFault");
+
+            Document odeMsg = DOMUtils.newDocument();
+            Element odeMsgEl = odeMsg.createElementNS(null, "message");
+            Element statusEl = odeMsg.createElementNS(null, "statusLine");
+            statusEl.setTextContent(String.valueOf(method.getStatusLine()));
+
+            odeMsg.appendChild(odeMsgEl);
+            odeMsgEl.appendChild(statusEl);
+            org.apache.ode.bpel.iapi.Message response = odeMex.createMessage(type);
+            response.setMessage(odeMsgEl);
+
+            log.error("Http Server Error! " + method.getStatusLine());
+            odeMex.replyWithFault(type, response);
+        }
+
+        private void badRequest() {
+            String errmsg = "Bad Request! " + method.getStatusLine();
+            log.error(errmsg);
+            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, null);
+        }
+
+        private void redirection() {
+            String errmsg = "Redirections are not supported! " + method.getStatusLine();
+            log.error(errmsg);
+            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, null);
+        }
+
+        private void success() {
+            if (log.isDebugEnabled()) log.debug("Http Status Line=" + method.getStatusLine());
+            if (log.isDebugEnabled()) log.debug("Received response for MEX " + odeMex);
+            try {
+                final InputStream bodyAsStream = method.getResponseBodyAsStream();
+                if (bodyAsStream == null) {
+                    String errmsg = "Request body of a Two-way message may be empty! Msg Id=" + odeMex.getMessageExchangeId();
+                    log.error(errmsg);
+                    odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, null);
+                    return;
+                } else {
+                    // only text/xml is supported in the response body
+                    // parse the body
+                    Element bodyElement;
+                    try {
+                        bodyElement = DOMUtils.parse(bodyAsStream).getDocumentElement();
+                    } catch (Exception e) {
+                        String errmsg = "Unable to parse the request body : " + e.getMessage();
+                        log.error(errmsg, e);
+                        odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, null);
+                        return;
+                    }
+                    try {
+                        org.apache.ode.bpel.iapi.Message odeResponse = odeMex.createMessage(odeMex.getOperation().getOutput().getMessage().getQName());
+
+                        // we expect a single part per output message
+                        // see org.apache.ode.axis2.httpbinding.HttpBindingValidator call in constructor
+                        Part part = (Part) operation.getOutput().getMessage().getParts().values().iterator().next();
+
+                        Element partElement = processBodyElement(part, bodyElement);
+                        odeResponse.setPart(part.getName(), partElement);
+
+                        if (log.isInfoEnabled())
+                            log.info("Response:\n" + DOMUtils.domToString(odeResponse.getMessage()));
+                        odeMex.reply(odeResponse);
+                    } catch (Exception ex) {
+                        String errmsg = "Unable to process response: " + ex.getMessage();
+                        log.error(errmsg, ex);
+                        odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, bodyElement);
+                    }
+                }
+            } catch (IOException e) {
+                String errmsg = "Unable to get the request body : " + e.getMessage();
+                log.error(errmsg, e);
+                odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, null);
+            }
+        }
+
+        /**
+         * Create the element to be inserted into org.apache.ode.bpel.iapi.Message.
+         * If the part has a non-null element name, the bodyElement is simply appended.
+         * Else if the bodyElement has a text content, the value is set to the message.
+         * Else append all nodes of bodyElement to the returned element. Attributes are ignored.
+         * <p/>
+         * The name of the returned element is the part name.
+         *
+         * @param part
+         * @param bodyElement
+         * @return the element to insert "as is" to ODE message
+         */
+        private Element processBodyElement(Part part, Element bodyElement) {
+            Document doc = DOMUtils.newDocument();
+            Element partElement = doc.createElementNS(null, part.getName());
+            if (part.getElementName() != null) {
+                partElement.appendChild(doc.importNode(bodyElement, true));
+            } else {
+                if (DOMUtils.isEmptyElement(bodyElement)) {
+                    // Append an empty text node.
+                    // Warning! setting an empty string with setTextContent has not effect. See javadoc.
+                    partElement.appendChild(doc.createTextNode(""));
+                } else {
+                    String textContent = DOMUtils.getTextContent(bodyElement);
+                    if (textContent != null) {
+                        // this is a simple type
+                        partElement.setTextContent(textContent);
+                    } else {
+                        // this is a complex type, import every child
+                        // !!! Attributes are ignored
+                        for (int m = 0; m < bodyElement.getChildNodes().getLength(); m++) {
+                            Node child = bodyElement.getChildNodes().item(m);
+                            partElement.appendChild(doc.importNode(child, true));
+                        }
+                    }
+                }
+
+            }
+            return partElement;
+        }
+    }
+
+}
+

Added: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodBuilder.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodBuilder.java?rev=658024&view=auto
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodBuilder.java (added)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodBuilder.java Mon May 19 15:57:24 2008
@@ -0,0 +1,200 @@
+/*
+ * 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.ode.axis2.httpbinding;
+
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.RequestEntity;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ode.bpel.iapi.PartnerRoleMessageExchange;
+import org.apache.ode.il.epr.MutableEndpoint;
+import org.apache.ode.utils.DOMUtils;
+import org.apache.ode.utils.wsdl.*;
+import org.apache.ode.utils.wsdl.Messages;
+import org.apache.ode.axis2.util.UrlReplacementTransformer;
+import org.apache.ode.axis2.util.URLEncodedTransformer;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import javax.wsdl.Operation;
+import javax.wsdl.BindingOperation;
+import javax.wsdl.Message;
+import javax.wsdl.Part;
+import javax.wsdl.BindingInput;
+import javax.wsdl.Binding;
+import javax.wsdl.extensions.http.HTTPOperation;
+import javax.wsdl.extensions.http.HTTPBinding;
+import javax.xml.namespace.QName;
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.ibm.wsdl.PartImpl;
+
+/**
+ * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
+ */
+public class HttpMethodBuilder {
+
+    private static final String CONTENT_TYPE_TEXT_XML = "text/xml";
+    private static final Log log = LogFactory.getLog(HttpMethodBuilder.class);
+
+    protected static final org.apache.ode.utils.wsdl.Messages msgs = Messages.getMessages(Messages.class);
+    protected Binding binding;
+    protected String verb;
+
+    public HttpMethodBuilder(Binding binding) {
+        this.binding = binding;
+        HTTPBinding httpBinding = (HTTPBinding) WsdlUtils.getBindingExtension(binding);
+        this.verb = httpBinding.getVerb();
+    }
+
+
+    public HttpMethod buildHttpMethod(PartnerRoleMessageExchange odeMex) throws UnsupportedEncodingException {
+        Operation operation = odeMex.getOperation();
+        BindingOperation bindingOperation = binding.getBindingOperation(operation.getName(), operation.getInput().getName(), operation.getOutput().getName());
+        // message to be sent
+        Element message = odeMex.getRequest().getMessage();
+        Message msgDef = operation.getInput().getMessage();
+
+        // base url
+        String url = ((MutableEndpoint) odeMex.getEndpointReference()).getUrl();
+
+        // extract part values into a map and check that all parts are assigned a value
+        Map<String, Element> partElements = extractPartElements(msgDef, message);
+
+        // build the http method
+        HttpMethod method = prepareHttpMethod(bindingOperation, partElements, url);
+        return method;
+    }
+
+    protected Map<String, Element> extractPartElements(Message msgDef, Element message) {
+        Map<String, Element> partValues = new HashMap<String, Element>();
+        for (Iterator iterator = msgDef.getParts().values().iterator(); iterator.hasNext();) {
+            Part part = (Part) iterator.next();
+            Element partEl = DOMUtils.findChildByName(message, new QName(null, part.getName()));
+            if (partEl == null)
+                throw new IllegalArgumentException(msgs.msgOdeMessageMissingRequiredPart(part.getName()));
+            partValues.put(part.getName(), partEl);
+        }
+        return partValues;
+    }
+
+    protected HttpMethod prepareHttpMethod(BindingOperation bindingOperation, Map<String, Element> partValues, final String rootUri) throws UnsupportedEncodingException {
+        if (log.isDebugEnabled()) log.debug("Preparing http request...");
+        // convenience variables...
+        BindingInput bindingInput = bindingOperation.getBindingInput();
+        HTTPOperation httpOperation = (HTTPOperation) WsdlUtils.getOperationExtension(bindingOperation);
+        String contentType = WsdlUtils.getMimeContentType(bindingInput.getExtensibilityElements());
+        boolean useUrlEncoded = WsdlUtils.useUrlEncoded(bindingInput) || PostMethod.FORM_URL_ENCODED_CONTENT_TYPE.equalsIgnoreCase(contentType);
+        boolean useUrlReplacement = WsdlUtils.useUrlReplacement(bindingInput);
+
+        final UrlReplacementTransformer replacementTransformer = new UrlReplacementTransformer(partValues.keySet());
+        final URLEncodedTransformer encodedTransformer = new URLEncodedTransformer();
+
+        // the http method to be built and returned
+        HttpMethod method = null;
+        // the 4 elements the http method may be made of
+        String relativeUri = httpOperation.getLocationURI();
+        String queryPath = null;
+        RequestEntity requestEntity = null;
+        String encodedParams = null;
+
+
+        if (useUrlReplacement) {
+            // insert part values in the url
+            relativeUri = replacementTransformer.transform(relativeUri, partValues);
+        } else if (useUrlEncoded) {
+            // encode part values
+            encodedParams = encodedTransformer.transform(partValues);
+        }
+
+        // http-client api is not really neat
+        // something similar to the following would save some if/else manipulations.
+        // But we have to deal with it as-is.
+        //
+        //  method = new Method(verb);
+        //  method.setRequestEnity(..)
+        //  etc...
+        if ("GET".equalsIgnoreCase(verb) || "DELETE".equalsIgnoreCase(verb)) {
+            if ("GET".equalsIgnoreCase(verb)) {
+                method = new GetMethod();
+            } else if ("DELETE".equalsIgnoreCase(verb)) {
+                method = new DeleteMethod();
+            }
+
+            if (useUrlEncoded) {
+                queryPath = encodedParams;
+            }
+
+            // Let http-client manage the redirection
+            // see org.apache.commons.httpclient.params.HttpClientParams.MAX_REDIRECTS
+            // default is 100
+            method.setFollowRedirects(true);
+        } else if ("POST".equalsIgnoreCase(verb) || "PUT".equalsIgnoreCase(verb)) {
+
+            if ("POST".equalsIgnoreCase(verb)) {
+                method = new PostMethod();
+            } else if ("PUT".equalsIgnoreCase(verb)) {
+                method = new PutMethod();
+            }
+
+            // some body-building...
+            if (useUrlEncoded) {
+                requestEntity = new StringRequestEntity(encodedParams, PostMethod.FORM_URL_ENCODED_CONTENT_TYPE, "UTF-8");
+            } else if (contentType.endsWith(CONTENT_TYPE_TEXT_XML)) {
+                // assumption is made that there is a single part
+                // validation steps in the constructor must warranty that
+                Part part = (Part) bindingOperation.getOperation().getInput().getMessage().getParts().values().iterator().next();
+                Element partValue = partValues.get(part.getName());
+                // if the part has an element name, we must take the first element
+                if (part.getElementName() != null) {
+                    partValue = DOMUtils.getFirstChildElement(partValue);
+                }
+                String xmlString = DOMUtils.domToString(partValue);
+                requestEntity = new ByteArrayRequestEntity(xmlString.getBytes(), contentType);
+            } else {
+                // should not happen because of HttpBindingValidator, but never say never
+                throw new IllegalArgumentException("Unsupported content-type!");
+            }
+
+            // cast safely, PUT and POST are subclasses of EntityEnclosingMethod
+            ((EntityEnclosingMethod) method).setRequestEntity(requestEntity);
+
+        } else {
+            // should not happen because of HttpBindingValidator, but never say never
+            throw new IllegalArgumentException("Unsupported HTTP method: " + verb);
+        }
+
+        // Settings common to all methods
+        String completeUri = rootUri + (rootUri.endsWith("/") || relativeUri.startsWith("/") ? "" : "/") + relativeUri;
+        method.setPath(completeUri); // assumes that the path is properly encoded (URL safe).
+        method.setQueryString(queryPath);
+        return method;
+    }
+}

Added: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/Messages.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/Messages.java?rev=658024&view=auto
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/Messages.java (added)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/Messages.java Mon May 19 15:57:24 2008
@@ -0,0 +1,74 @@
+/*
+ * 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.ode.axis2.httpbinding;
+
+import org.apache.ode.utils.msg.MessageBundle;
+
+import javax.xml.namespace.QName;
+import javax.wsdl.Binding;
+import javax.wsdl.BindingOperation;
+import java.io.File;
+
+/**
+ * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
+ */
+public class Messages extends MessageBundle {
+
+    public String msgUnsupportedHttpMethod(Binding binding, String verb) {
+        return format("Unsupported HTTP method! binding: {0} method: {1}", binding.getQName(), verb);
+    }
+
+    public String msgHttpBindingNotUsed(Binding binding) {
+        return format("This binding does not use http:binding: {0}" + binding.getQName());
+    }
+
+    public String msgUnsupportedContentType(Binding binding, BindingOperation operation) {
+        return format("Unsupported content-type!binding: {0} operation: {1}", binding.getQName(), operation.getName());
+    }
+
+    public String msgOnePartOnlyForOutput(Binding binding, BindingOperation operation) {
+        return format("Output messages may not have more than 1 part! binding: {0} operation: {1}", binding.getQName(), operation.getName());
+    }
+
+    public String msgInvalidURIPattern() {
+        return format("Invalid URI Pattern!");
+    }
+
+    public String msgInvalidURIPattern(Binding binding, BindingOperation operation, String locationUri) {
+        return format("Invalid URI Pattern : all parts must be mentioned exactly once! binding:{0}, operation:{1}, locationUri:{2}", binding.getQName(), operation.getName(), locationUri);
+    }
+    
+    public String msgMimeMultipartRelatedUnsupported(Binding binding, BindingOperation operation) {
+        return format("MimeMultipartRelated is not supported! binding:{0}, operation:{1}", binding.getQName(), operation.getName());
+    }
+
+    public String msgInvalidContentType(Binding binding, BindingOperation operation) {
+        return format("Invalid content-type! binding:{0}, operation:{1}", binding.getQName(), operation.getName());
+    }
+
+    public String msgSimpleTypeExpected(String partName){
+        return format("Simple type expected for {0}", partName);
+    }
+
+    public String msgOnlySupportsUrlEncodedAndUrlreplacement(Binding binding, BindingOperation operation) {
+        return format("Only supports urlEncoded or urlReplacement! binding:{0}, operation:{1}", binding.getQName(), operation.getName());
+    }
+
+}

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/SoapMessageConverter.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/SoapMessageConverter.java?rev=658024&r1=658023&r2=658024&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/SoapMessageConverter.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/SoapMessageConverter.java Mon May 19 15:57:24 2008
@@ -19,6 +19,7 @@
 
 package org.apache.ode.axis2.util;
 
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -59,11 +60,12 @@
 import org.apache.axis2.namespace.Constants;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.ode.axis2.Messages;
 import org.apache.ode.axis2.OdeFault;
 import org.apache.ode.il.OMUtils;
 import org.apache.ode.utils.DOMUtils;
 import org.apache.ode.utils.Namespaces;
+import org.apache.ode.utils.wsdl.Messages;
+import org.apache.ode.utils.wsdl.WsdlUtils;
 import org.apache.ode.utils.stl.CollectionsX;
 import org.w3c.dom.Element;
 
@@ -115,17 +117,17 @@
             throw new OdeFault(__msgs.msgPortDefinitionNotFound(serviceName, portName));
         _binding = _port.getBinding();
         if (_binding == null)
-            throw new OdeFault(__msgs.msgBindingNotFound(serviceName, portName));
-
+            throw new OdeFault(__msgs.msgBindingNotFound(portName));
 
-        Collection<SOAPBinding> soapBindings = CollectionsX.filter(_binding.getExtensibilityElements(), SOAPBinding.class);
-        if (soapBindings.isEmpty())
-            throw new OdeFault(__msgs.msgNoSOAPBindingForPort(_portName));
-        else if (soapBindings.size() > 1) {
-            throw new OdeFault(__msgs.msgMultipleSoapBindingsForPort(_portName));
+        try {
+            if (!WsdlUtils.useSOAPBinding(_port)) {
+                throw new OdeFault(__msgs.msgNoSOAPBindingForPort(_portName));
+            }
+            _soapBinding = (SOAPBinding) WsdlUtils.getBindingExtension(_port);
+        } catch (IllegalArgumentException iae) {
+            throw new OdeFault(iae);
         }
 
-        _soapBinding = soapBindings.iterator().next();
         String style = _soapBinding.getStyle();
         _isRPC = style != null && style.equals("rpc");
 

Added: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/URLEncodedTransformer.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/URLEncodedTransformer.java?rev=658024&view=auto
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/URLEncodedTransformer.java (added)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/URLEncodedTransformer.java Mon May 19 15:57:24 2008
@@ -0,0 +1,55 @@
+/*
+ * 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.ode.axis2.util;
+
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.util.EncodingUtil;
+import org.apache.ode.utils.DOMUtils;
+import org.apache.ode.axis2.httpbinding.Messages;
+import org.w3c.dom.Element;
+
+import javax.wsdl.Part;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
+ */
+public class URLEncodedTransformer {
+
+    private static final Messages msgs = Messages.getMessages(Messages.class);
+
+    public String transform(Map<String, Element> values) {
+        if (values.isEmpty()) return null;
+        NameValuePair[] pairs = new NameValuePair[values.size()];
+        int i = 0;
+        for (Map.Entry<String, Element> e : values.entrySet()) {
+            Element node = e.getValue();
+            String nodeContent = DOMUtils.isEmptyElement(node) ? "" : DOMUtils.getTextContent(node);
+            if (nodeContent == null) {
+                throw new IllegalArgumentException(msgs.msgSimpleTypeExpected(e.getKey()));
+            }
+            NameValuePair p = new NameValuePair(e.getKey(), nodeContent);
+            pairs[i++] = p;
+        }
+        return EncodingUtil.formUrlEncode(pairs, "UTF-8");
+    }
+
+}

Added: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/UrlReplacementTransformer.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/UrlReplacementTransformer.java?rev=658024&view=auto
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/UrlReplacementTransformer.java (added)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/UrlReplacementTransformer.java Mon May 19 15:57:24 2008
@@ -0,0 +1,131 @@
+/*
+ * 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.ode.axis2.util;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.ode.utils.DOMUtils;
+import org.apache.ode.utils.wsdl.Messages;
+import org.w3c.dom.Element;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This encoder applies urlReplacement as defined by the <a href='http://www.w3.org/TR/wsdl#_http:urlReplacement'>WSDL specification</a>.
+ * <br/>
+ *
+ * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
+ */
+public class UrlReplacementTransformer {
+
+    private static final org.apache.ode.utils.wsdl.Messages msgs = Messages.getMessages(Messages.class);
+    private static final org.apache.ode.axis2.httpbinding.Messages httpMsgs = org.apache.ode.axis2.httpbinding.Messages.getMessages(org.apache.ode.axis2.httpbinding.Messages.class);
+
+    protected Set<String> partNames;
+
+    public UrlReplacementTransformer() {
+        partNames = new HashSet<String>();
+    }
+
+    public UrlReplacementTransformer(Set<String> partNames) {
+        this.partNames = partNames;
+    }
+
+    /**
+     * @param baseUri - the base uri template containing part names enclosed within single curly braces
+     * @param values  - a map<String, Object>, the key is a part name (without curly braces), the value the replacement value for the part name.
+     * @return the encoded uri
+     * @throws java.lang.IllegalArgumentException
+     *          if a part (key) is missing in the map, if a replacement value is null in the map, if a part pattern is not found in the uri template, if a part pattern is found more than once
+     */
+    public String transform(String baseUri, Map<String, Element> values) {
+        // each part must be given a replacement value
+        if (values.keySet().size() != partNames.size() || !values.keySet().containsAll(partNames)) {
+            Collection<String> disjunction = CollectionUtils.disjunction(partNames, values.keySet());
+            throw new IllegalArgumentException(msgs.msgMissingReplacementValuesFor(disjunction));
+        }
+
+        // the list containing the final split result
+        List<String> result = new ArrayList<String>();
+
+        // initial value
+        result.add(baseUri);
+
+        // replace each part exactly once
+        for (Map.Entry<String, Element> e : values.entrySet()) {
+
+            String partPattern;
+            String replacementValue;
+            {
+                String partName = e.getKey();
+                partPattern = "\\(" + partName + "\\)";
+                Element value = e.getValue();
+                replacementValue = DOMUtils.isEmptyElement(value) ? "" : DOMUtils.getTextContent(value);
+                if (replacementValue == null) {
+                    throw new IllegalArgumentException(httpMsgs.msgSimpleTypeExpected(partName));
+                }
+            }
+            replace(result, partPattern, replacementValue);
+        }
+
+        // join all the array elements to form the final url
+        StringBuilder sb = new StringBuilder(128);
+        for (String aResult : result) sb.append(aResult);
+        return sb.toString();
+    }
+
+    private void replace(List<String> result, String partPattern, String replacementValue) {
+        // !!!  i=i+2      replacement values will be skipped,
+        // so replaced values do not trigger additional matches
+        for (int i = 0; i < result.size(); i = i + 2) {
+            String segment = result.get(i);
+            // use a negative limit, so empty strings are not discarded
+            String[] matches = segment.split(partPattern, -1);
+            if (matches.length == 1) {
+                if (i == result.size() - 1) {
+                    // last segment, no more string to test
+                    throw new IllegalArgumentException(httpMsgs.msgInvalidURIPattern());
+                } else {
+                    continue;
+                }
+            } else if (matches.length > 2) {
+                throw new IllegalArgumentException(httpMsgs.msgInvalidURIPattern());
+            } else {
+                // if exactly one match...
+
+                // remove the matching segment
+                result.remove(i);
+                // replace it with the replacement value
+                result.add(i, matches[0]);
+                result.add(i + 1, replacementValue);
+                result.add(i + 2, matches[1]);
+
+                // pattern found and replaced, we're done for this pattern
+                // move on to the next part
+                break;
+            }
+        }
+    }
+
+}