/* * JBoss, Home of Professional Open Source. * Copyright 2011, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.xts; import static org.jboss.as.xts.XTSSubsystemDefinition.DEFAULT_CONTEXT_PROPAGATION; import static org.jboss.as.xts.XTSSubsystemDefinition.ENVIRONMENT_URL; import static org.jboss.as.xts.XTSSubsystemDefinition.HOST_NAME; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import com.arjuna.schemas.ws._2005._10.wsarjtx.TerminationCoordinatorRPCService; import com.arjuna.schemas.ws._2005._10.wsarjtx.TerminationCoordinatorService; import com.arjuna.schemas.ws._2005._10.wsarjtx.TerminationParticipantService; import com.arjuna.webservices11.wsarjtx.sei.TerminationCoordinatorPortTypeImpl; import com.arjuna.webservices11.wsarjtx.sei.TerminationCoordinatorRPCPortTypeImpl; import com.arjuna.webservices11.wsarjtx.sei.TerminationParticipantPortTypeImpl; import com.arjuna.webservices11.wsat.sei.CompletionCoordinatorPortTypeImpl; import com.arjuna.webservices11.wsat.sei.CompletionCoordinatorRPCPortTypeImpl; import com.arjuna.webservices11.wsat.sei.CompletionInitiatorPortTypeImpl; import com.arjuna.webservices11.wsat.sei.CoordinatorPortTypeImpl; import com.arjuna.webservices11.wsat.sei.ParticipantPortTypeImpl; import com.arjuna.webservices11.wsba.sei.BusinessAgreementWithCoordinatorCompletionCoordinatorPortTypeImpl; import com.arjuna.webservices11.wsba.sei.BusinessAgreementWithCoordinatorCompletionParticipantPortTypeImpl; import com.arjuna.webservices11.wsba.sei.BusinessAgreementWithParticipantCompletionCoordinatorPortTypeImpl; import com.arjuna.webservices11.wsba.sei.BusinessAgreementWithParticipantCompletionParticipantPortTypeImpl; import com.arjuna.webservices11.wscoor.sei.ActivationPortTypeImpl; import com.arjuna.webservices11.wscoor.sei.RegistrationPortTypeImpl; import org.jboss.as.controller.AbstractBoottimeAddStepHandler; import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationFailedException; import org.jboss.as.server.AbstractDeploymentChainStep; import org.jboss.as.server.DeploymentProcessorTarget; import org.jboss.as.server.deployment.Phase; import org.jboss.as.txn.service.TxnServices; import org.jboss.as.webservices.service.EndpointPublishService; import org.jboss.as.webservices.util.WSServices; import org.jboss.as.xts.logging.XtsAsLogger; import org.jboss.dmr.ModelNode; import org.jboss.jbossts.XTSService; import org.jboss.msc.service.ServiceBuilder; import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceController.Mode; import org.jboss.msc.service.ServiceTarget; import org.jboss.wsf.spi.invocation.RejectionRule; import org.jboss.wsf.spi.management.ServerConfig; import org.jboss.wsf.spi.publish.Context; import org.oasis_open.docs.ws_tx.wsat._2006._06.CompletionCoordinatorRPCService; import org.oasis_open.docs.ws_tx.wsat._2006._06.CompletionCoordinatorService; import org.oasis_open.docs.ws_tx.wsat._2006._06.CompletionInitiatorService; import org.oasis_open.docs.ws_tx.wsat._2006._06.CoordinatorService; import org.oasis_open.docs.ws_tx.wsat._2006._06.ParticipantService; import org.oasis_open.docs.ws_tx.wsba._2006._06.BusinessAgreementWithCoordinatorCompletionCoordinatorService; import org.oasis_open.docs.ws_tx.wsba._2006._06.BusinessAgreementWithCoordinatorCompletionParticipantService; import org.oasis_open.docs.ws_tx.wsba._2006._06.BusinessAgreementWithParticipantCompletionCoordinatorService; import org.oasis_open.docs.ws_tx.wsba._2006._06.BusinessAgreementWithParticipantCompletionParticipantService; import org.oasis_open.docs.ws_tx.wscoor._2006._06.ActivationService; import org.oasis_open.docs.ws_tx.wscoor._2006._06.RegistrationService; /** * Adds the transaction management subsystem. * * @author <a href="mailto:adinn@redhat.com">Andrew Dinn</a> */ class XTSSubsystemAdd extends AbstractBoottimeAddStepHandler { static final XTSSubsystemAdd INSTANCE = new XTSSubsystemAdd(); private static final String[] WAR_DEPLOYMENT_NAMES = { "ws-c11.war", "ws-t11-coordinator.war", "ws-t11-participant.war", "ws-t11-client.war", }; /** * class used to record the url pattern and service endpoint implementation class name of * an XTS JaxWS endpoint associated with one of the XTS context paths. this is equivalent * to the information contained in a single matched pair of servlet:servletName and * servlet-mapping:url-pattern fields in the web.xml */ private static class EndpointInfo { String SEIClassname; String URLPattern; EndpointInfo(String seiClassname, String urlPattern) { this.SEIClassname = seiClassname; this.URLPattern = urlPattern; } } /** * class grouping togeher details of all XTS JaxWS endpoints associated with a given XTS context * path. this groups together all the paired servlet:servletName and* servlet-mapping:url-pattern * fields in the web.xml */ static class ContextInfo { String contextPath; EndpointInfo[] endpointInfo; ContextInfo(String contextPath, EndpointInfo[] endpointInfo) { this.contextPath = contextPath; this.endpointInfo = endpointInfo; } } /** * a collection of all the context and associated endpoint information for the XTS JaxWS endpoints. * this is the bits of the variosu web.xml files which are necessary to deploy via the endpoint * publisher API rather than via war files containing web.xml descriptors */ private static final ContextInfo[] contextDefinitions = { new ContextInfo("ws-c11", new EndpointInfo[]{ new EndpointInfo(ActivationPortTypeImpl.class.getName(), ActivationService.class.getSimpleName()), new EndpointInfo(RegistrationPortTypeImpl.class.getName(), RegistrationService.class.getSimpleName()) }), new ContextInfo("ws-t11-coordinator", new EndpointInfo[]{ new EndpointInfo(CoordinatorPortTypeImpl.class.getName(), CoordinatorService.class.getSimpleName()), new EndpointInfo(CompletionCoordinatorPortTypeImpl.class.getName(), CompletionCoordinatorService.class.getSimpleName()), new EndpointInfo(CompletionCoordinatorRPCPortTypeImpl.class.getName(), CompletionCoordinatorRPCService.class.getSimpleName()), new EndpointInfo(BusinessAgreementWithCoordinatorCompletionCoordinatorPortTypeImpl.class.getName(), BusinessAgreementWithCoordinatorCompletionCoordinatorService.class.getSimpleName()), new EndpointInfo(BusinessAgreementWithParticipantCompletionCoordinatorPortTypeImpl.class.getName(), BusinessAgreementWithParticipantCompletionCoordinatorService.class.getSimpleName()), new EndpointInfo(TerminationCoordinatorPortTypeImpl.class.getName(), TerminationCoordinatorService.class.getSimpleName()), new EndpointInfo(TerminationCoordinatorRPCPortTypeImpl.class.getName(), TerminationCoordinatorRPCService.class.getSimpleName()) }), new ContextInfo("ws-t11-participant", new EndpointInfo[]{ new EndpointInfo(ParticipantPortTypeImpl.class.getName(), ParticipantService.class.getSimpleName()), new EndpointInfo(BusinessAgreementWithCoordinatorCompletionParticipantPortTypeImpl.class.getName(), BusinessAgreementWithCoordinatorCompletionParticipantService.class.getSimpleName()), new EndpointInfo(BusinessAgreementWithParticipantCompletionParticipantPortTypeImpl.class.getName(), BusinessAgreementWithParticipantCompletionParticipantService.class.getSimpleName()), }), new ContextInfo("ws-t11-client", new EndpointInfo[]{ new EndpointInfo(CompletionInitiatorPortTypeImpl.class.getName(), CompletionInitiatorService.class.getSimpleName()), new EndpointInfo(TerminationParticipantPortTypeImpl.class.getName(), TerminationParticipantService.class.getSimpleName()) }) }; private XTSSubsystemAdd() { } static ContextInfo[] getContextDefinitions() { return contextDefinitions; } @Override protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { HOST_NAME.validateAndSet(operation, model); ENVIRONMENT_URL.validateAndSet(operation, model); DEFAULT_CONTEXT_PROPAGATION.validateAndSet(operation, model); } @Override protected void performBoottime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { final String hostName = HOST_NAME.resolveModelAttribute(context, model).asString(); final ModelNode coordinatorURLAttribute = ENVIRONMENT_URL.resolveModelAttribute(context, model); String coordinatorURL = coordinatorURLAttribute.isDefined() ? coordinatorURLAttribute.asString() : null; if (coordinatorURL != null) { String[] attrs = coordinatorURL.split("/"); boolean isIPv6Address = false; for (int i = 0; i < attrs.length; i++) { if (attrs[i].startsWith("::1")) { attrs[i] = "[" + attrs[i].substring(0, 3) + "]" + attrs[i].substring(3); isIPv6Address = true; break; } } if (isIPv6Address) { StringBuffer sb = new StringBuffer(attrs[0]); for (int i = 1; i < attrs.length; i++) { sb.append('/').append(attrs[i]); } coordinatorURL = sb.toString(); } } if (coordinatorURL != null) { XtsAsLogger.ROOT_LOGGER.debugf("nodeIdentifier=%s%n", coordinatorURL); } final boolean isDefaultContextPropagation = model.hasDefined(CommonAttributes.DEFAULT_CONTEXT_PROPAGATION) ? model.get(CommonAttributes.DEFAULT_CONTEXT_PROPAGATION).asBoolean() : false; context.addStep(new AbstractDeploymentChainStep() { protected void execute(DeploymentProcessorTarget processorTarget) { processorTarget.addDeploymentProcessor(XTSExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_XTS_COMPONENT_INTERCEPTORS, new XTSInterceptorDeploymentProcessor()); processorTarget.addDeploymentProcessor(XTSExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_XTS_SOAP_HANDLERS, new XTSHandlerDeploymentProcessor()); processorTarget.addDeploymentProcessor(XTSExtension.SUBSYSTEM_NAME, Phase.DEPENDENCIES, Phase.DEPENDENCIES_XTS, new XTSDependenciesDeploymentProcessor()); processorTarget.addDeploymentProcessor(XTSExtension.SUBSYSTEM_NAME, Phase.POST_MODULE, Phase.POST_MODULE_XTS_PORTABLE_EXTENSIONS, new GracefulShutdownDeploymentProcessor()); } }, OperationContext.Stage.RUNTIME); final ServiceTarget target = context.getServiceTarget(); // TODO eventually we should add a config service which manages the XTS configuration // this will allow us to include a switch enabling or disabling deployment of // endpoints specific to client, coordinator or participant and then deploy // and redeploy the relevant endpoints as needed/ the same switches can be used // byte the XTS service to decide whether to perfomr client, coordinator or // participant initialisation. we should also provide config switches which // decide whether to initialise classes and deploy services for AT, BA or both. // for now we will just deploy all the endpoints and always do client, coordinator // and participant init for both AT and BA. // add an endpoint publisher service for each of the required endpoint contexts // specifying all the relevant URL patterns and SEI classes final ClassLoader loader = XTSService.class.getClassLoader(); ServiceBuilder<Context> endpointBuilder; ArrayList<ServiceController<Context>> controllers = new ArrayList<ServiceController<Context>>(); Map<Class<?>, Object> attachments = new HashMap<>(); attachments.put(RejectionRule.class, new GracefulShutdownRejectionRule()); for (ContextInfo contextInfo : contextDefinitions) { String contextName = contextInfo.contextPath; Map<String, String> map = new HashMap<String, String>(); for (EndpointInfo endpointInfo : contextInfo.endpointInfo) { map.put(endpointInfo.URLPattern, endpointInfo.SEIClassname); } endpointBuilder = EndpointPublishService.createServiceBuilder(target, contextName, loader, hostName, map, null, null, null, attachments); controllers.add(endpointBuilder.setInitialMode(Mode.ACTIVE) .install()); } XTSHandlersService.install(target, isDefaultContextPropagation); // add an XTS service which depends on all the WS endpoints final XTSManagerService xtsService = new XTSManagerService(coordinatorURL); // this service needs to depend on the transaction recovery service // because it can only initialise XTS recovery once the transaction recovery // service has initialised the orb layer ServiceBuilder<?> xtsServiceBuilder = target.addService(XTSServices.JBOSS_XTS_MAIN, xtsService); xtsServiceBuilder .addDependency(TxnServices.JBOSS_TXN_ARJUNA_TRANSACTION_MANAGER); // this service needs to depend on JBossWS Config Service to be notified of the JBoss WS config (bind address, port etc) xtsServiceBuilder.addDependency(WSServices.CONFIG_SERVICE, ServerConfig.class, xtsService.getWSServerConfig()); xtsServiceBuilder.addDependency(WSServices.XTS_CLIENT_INTEGRATION_SERVICE); // the service also needs to depend on the endpoint services for (ServiceController<Context> controller : controllers) { xtsServiceBuilder.addDependency(controller.getName()); } xtsServiceBuilder .setInitialMode(Mode.ACTIVE) .install(); // WS-AT / JTA Transaction bridge services: final TxBridgeInboundRecoveryService txBridgeInboundRecoveryService = new TxBridgeInboundRecoveryService(); ServiceBuilder<?> txBridgeInboundRecoveryServiceBuilder = target.addService(XTSServices.JBOSS_XTS_TXBRIDGE_INBOUND_RECOVERY, txBridgeInboundRecoveryService); txBridgeInboundRecoveryServiceBuilder.addDependency(XTSServices.JBOSS_XTS_MAIN); txBridgeInboundRecoveryServiceBuilder.setInitialMode(Mode.ACTIVE).install(); final TxBridgeOutboundRecoveryService txBridgeOutboundRecoveryService = new TxBridgeOutboundRecoveryService(); ServiceBuilder<?> txBridgeOutboundRecoveryServiceBuilder = target.addService(XTSServices.JBOSS_XTS_TXBRIDGE_OUTBOUND_RECOVERY, txBridgeOutboundRecoveryService); txBridgeOutboundRecoveryServiceBuilder.addDependency(XTSServices.JBOSS_XTS_MAIN); txBridgeOutboundRecoveryServiceBuilder.setInitialMode(Mode.ACTIVE).install(); } }