/* * 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.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.wsdl.Definition; import javax.wsdl.PortType; import javax.xml.namespace.QName; import org.apache.axis2.AxisFault; import org.apache.axis2.description.AxisOperation; import org.apache.axis2.description.AxisService; import org.apache.axis2.description.Parameter; import org.apache.axis2.engine.AxisConfigurator; import org.apache.commons.collections.map.MultiKeyMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.ode.agents.memory.SizingAgent; import org.apache.ode.axis2.hooks.ODEAxisService; import org.apache.ode.axis2.hooks.ODEMessageReceiver; import org.apache.ode.axis2.httpbinding.HttpExternalService; import org.apache.ode.bpel.iapi.BindingContext; import org.apache.ode.bpel.iapi.ContextException; import org.apache.ode.bpel.iapi.Endpoint; import org.apache.ode.bpel.iapi.EndpointReference; import org.apache.ode.bpel.iapi.PartnerRoleChannel; import org.apache.ode.bpel.iapi.ProcessConf; import org.apache.ode.utils.wsdl.WsdlUtils; /** * AXIS2 implementation of the {@link org.apache.ode.bpel.iapi.BindingContext} * interface. Deals with the activation of endpoints. * * @author Maciej Szefler - m s z e f l e r @ g m a i l . c o m * */ public class BindingContextImpl implements BindingContext { protected final Logger __log = LoggerFactory.getLogger(getClass()); private ODEServer _server; private MultiKeyMap _services = new MultiKeyMap(); private Map<ODEService, EndpointReference> _serviceEprMap = new HashMap<ODEService, EndpointReference>(); public BindingContextImpl(ODEServer server) { _server = server; } public EndpointReference activateMyRoleEndpoint(QName processId, Endpoint myRoleEndpoint) { try { ProcessConf pconf = _server._store.getProcessConfiguration(processId); Definition wsdl = pconf.getDefinitionForService(myRoleEndpoint.serviceName); if (wsdl == null) throw new ContextException("Unable to access WSDL definition to activate MyRole endpoint for service " + myRoleEndpoint.serviceName + " and port " + myRoleEndpoint.portName); ODEService svc = createService(pconf, myRoleEndpoint.serviceName, myRoleEndpoint.portName); EndpointReference epr = svc.getMyServiceRef(); _serviceEprMap.put(svc, epr); return epr; } catch (AxisFault axisFault) { throw new ContextException("Could not activate endpoint for service " + myRoleEndpoint.serviceName + " and port " + myRoleEndpoint.portName, axisFault); } } public void deactivateMyRoleEndpoint(Endpoint myRoleEndpoint) { ODEService service = destroyService(myRoleEndpoint.serviceName, myRoleEndpoint.portName); if (service != null) { _serviceEprMap.remove(service); } } public PartnerRoleChannel createPartnerRoleChannel(QName processId, PortType portType, Endpoint initialPartnerEndpoint) { // NOTE: This implementation assumes that the initial value of the // partner role determines the binding. ProcessConf pconf = _server._store.getProcessConfiguration(processId); Definition wsdl = pconf.getDefinitionForService(initialPartnerEndpoint.serviceName); if (wsdl == null) { throw new ContextException("Cannot find definition for service " + initialPartnerEndpoint.serviceName + " in the context of process "+processId); } return createExternalService(pconf, initialPartnerEndpoint.serviceName, initialPartnerEndpoint.portName); } public long calculateSizeofService(EndpointReference epr) { if (_server._odeConfig.isProcessSizeThrottled()) { for (ODEService service : _serviceEprMap.keySet()) { if (epr.equals(_serviceEprMap.get(epr))) { return SizingAgent.deepSizeOf(service); } } } return 0; } protected ODEService createService(ProcessConf pconf, QName serviceName, String portName) throws AxisFault { AxisService axisService = ODEAxisService.createService(_server._configContext.getAxisConfiguration(), pconf, serviceName, portName); ODEService odeService = new ODEService(axisService, pconf, serviceName, portName, _server._bpelServer, _server._txMgr); destroyService(serviceName, portName); _services.put(serviceName, portName, odeService); // Setting our new service on the ODE receiver Iterator operationIterator = axisService.getOperations(); while (operationIterator.hasNext()) { AxisOperation op = (AxisOperation) operationIterator.next(); if (op.getMessageReceiver() instanceof ODEMessageReceiver) { ((ODEMessageReceiver) op.getMessageReceiver()).setService(odeService); break; } } // We're public! _server._configContext.getAxisConfiguration().addService(axisService); if (__log.isDebugEnabled()) { __log.debug("Created Axis2 service " + serviceName); } return odeService; } protected ODEService destroyService(QName serviceName, String portName) { if (__log.isDebugEnabled()) { __log.debug("Destroying service " + serviceName + " port " + portName); } ODEService service = (ODEService) _services.remove(serviceName, portName); if (service != null) { // try to clean up the service after itself try { String axisServiceName = service.getAxisService().getName(); AxisService axisService = _server._configContext.getAxisConfiguration().getService(axisServiceName); //axisService might be null if it could not be properly activated before. if (axisService != null) { // first, de-allocate its schemas axisService.releaseSchemaList(); // then, de-allocate its parameters // the service's wsdl object model is stored as one of its parameters! // can't stress strongly enough how important it is to clean this up. ArrayList<Parameter> parameters = (ArrayList<Parameter>) axisService.getParameters(); for (Parameter parameter : parameters) { axisService.removeParameter(parameter); } } // now, stop the service _server._configContext.getAxisConfiguration().stopService(axisServiceName); // if only this method did a good job of cleaning up after itself _server._configContext.getAxisConfiguration().removeService(service.getName()); completeCleanup(axisService); //ODE-994: commenting the cleanup on axisConfig as it cleansup everything on axis2 1.6 //_server._axisConfig.cleanup(); //For backward compatibility with older versions of axis2 that is below 1.6 AxisConfigurator configurator = _server._configContext.getAxisConfiguration().getConfigurator(); if(configurator != null) configurator.cleanup(); } catch (AxisFault axisFault) { __log.error("Couldn't destroy service " + serviceName); } } else { if (__log.isDebugEnabled()) { __log.debug("Couldn't find service " + serviceName + " port " + portName + " to destroy."); } } return service; } /** * /!\ Monkey patching to remove references to the service: * Manually & externally & really really horribly fix for ODE-580/AXIS2-3870 * The exception handling is for locked down environment where reflection would not be allowed... * * This patch is needed for Axis2 1.3 and 1.4.1 * @param service * @throws AxisFault */ private void completeCleanup(AxisService service) { try { Field field= _server._configContext.getAxisConfiguration().getClass().getDeclaredField("allEndpoints"); field.setAccessible(true); synchronized (_server._configContext.getAxisConfiguration()) { //removes the endpoints to this service Map allEndpoints = (Map) field.get(_server._configContext.getAxisConfiguration()); //removes the service endpoints for (Iterator<String> iter = service.getEndpoints().keySet().iterator(); iter.hasNext();) { allEndpoints.remove(service.getName() + "." + iter.next()); } } } catch(Exception e) { __log.error("Workaround for ODE-580/AXIS2-3870 failed. AxisConfig clean up might be incomplete.", e); } } protected ExternalService createExternalService(ProcessConf pconf, QName serviceName, String portName) throws ContextException { ExternalService extService = null; Definition def = pconf.getDefinitionForService(serviceName); try { if (WsdlUtils.useHTTPBinding(def, serviceName, portName)) { if (__log.isDebugEnabled()) __log.debug("Creating HTTP-bound external service " + serviceName); extService = new HttpExternalService(pconf, serviceName, portName, _server._executorService, _server._scheduler, _server._bpelServer, _server.httpConnectionManager, _server._clusterUrlTransformer); } else if (WsdlUtils.useSOAPBinding(def, serviceName, portName)) { if (__log.isDebugEnabled()) __log.debug("Creating SOAP-bound external service " + serviceName); extService = new SoapExternalService(pconf, serviceName, portName, _server._executorService, _server._configContext, _server._scheduler, _server._bpelServer, _server.httpConnectionManager, _server._clusterUrlTransformer); } } catch (Exception ex) { __log.error("Could not create 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!"); } if (__log.isDebugEnabled()) { __log.debug("Created external service " + serviceName); } return extService; } }