All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.jca.endpoint.GenericMessageEndpointManager Maven / Gradle / Ivy

There is a newer version: 6.2.0
Show newest version
/*
 * Copyright 2002-2023 the original author or authors.
 *
 * Licensed 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
 *
 *      https://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.springframework.jca.endpoint;

import jakarta.resource.ResourceException;
import jakarta.resource.spi.ActivationSpec;
import jakarta.resource.spi.ResourceAdapter;
import jakarta.resource.spi.endpoint.MessageEndpointFactory;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.SmartLifecycle;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
 * Generic bean that manages JCA 1.7 message endpoints within a Spring
 * application context, activating and deactivating the endpoint as part
 * of the application context's lifecycle.
 *
 * 

This class is completely generic in that it may work with any * ResourceAdapter, any MessageEndpointFactory, and any ActivationSpec. * It can be configured in standard bean style, for example through * Spring's XML bean definition format, as follows: * *

 * <bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager">
 *  <property name="resourceAdapter" ref="resourceAdapter"/>
 *  <property name="messageEndpointFactory">
 *    <bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory">
 *      <property name="messageListener" ref="messageListener"/>
 *    </bean>
 *  </property>
 *  <property name="activationSpec">
 *    <bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
 *      <property name="destination" value="myQueue"/>
 *      <property name="destinationType" value="jakarta.jms.Queue"/>
 *    </bean>
 *  </property>
 * </bean>
 * 
* *

In this example, Spring's own {@link GenericMessageEndpointFactory} is used * to point to a standard message listener object that happens to be supported * by the specified target ResourceAdapter: in this case, a JMS * {@link jakarta.jms.MessageListener} object as supported by the ActiveMQ * message broker, defined as a Spring bean: * *

 * <bean id="messageListener" class="com.myorg.messaging.myMessageListener">
 *   <!-- ... -->
 * </bean>
 * 
* *

The target ResourceAdapter may be configured as a local Spring bean as well * (the typical case) or obtained from JNDI. For the example above, a local * ResourceAdapter bean could be defined as follows (matching the "resourceAdapter" * bean reference above): * *

 * <bean id="resourceAdapter" class="org.springframework.jca.support.ResourceAdapterFactoryBean">
 *  <property name="resourceAdapter">
 *    <bean class="org.apache.activemq.ra.ActiveMQResourceAdapter">
 *      <property name="serverUrl" value="tcp://localhost:61616"/>
 *    </bean>
 *  </property>
 *  <property name="workManager">
 *    <bean class="..."/>
 *  </property>
 * </bean>
 * 
* *

For a different target resource, the configuration would simply point to a * different ResourceAdapter and a different ActivationSpec object (which are * both specific to the resource provider), and possibly a different message * listener (e.g. a CCI {@link jakarta.resource.cci.MessageListener} for a * resource adapter which is based on the JCA Common Client Interface). * *

The asynchronous execution strategy can be customized through the * "workManager" property on the ResourceAdapterFactoryBean as shown above, * where {@code } should be replaced with configuration for * any JCA-compliant {@code WorkManager}. * *

Transactional execution is a responsibility of the concrete message endpoint, * as built by the specified MessageEndpointFactory. {@link GenericMessageEndpointFactory} * supports XA transaction participation through its "transactionManager" property, * typically with a Spring {@link org.springframework.transaction.jta.JtaTransactionManager} * or a plain {@link jakarta.transaction.TransactionManager} implementation specified there. * *

 * <bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager">
 *  <property name="resourceAdapter" ref="resourceAdapter"/>
 *  <property name="messageEndpointFactory">
 *    <bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory">
 *      <property name="messageListener" ref="messageListener"/>
 *      <property name="transactionManager" ref="transactionManager"/>
 *    </bean>
 *  </property>
 *  <property name="activationSpec">
 *    <bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
 *      <property name="destination" value="myQueue"/>
 *      <property name="destinationType" value="jakarta.jms.Queue"/>
 *    </bean>
 *  </property>
 * </bean>
 *
 * <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
 * 
* *

Alternatively, check out your resource provider's ActivationSpec object, * which should support local transactions through a provider-specific config flag, * e.g. ActiveMQActivationSpec's "useRAManagedTransaction" bean property. * *

 * <bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager">
 *  <property name="resourceAdapter" ref="resourceAdapter"/>
 *  <property name="messageEndpointFactory">
 *    <bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory">
 *      <property name="messageListener" ref="messageListener"/>
 *    </bean>
 *  </property>
 *  <property name="activationSpec">
 *    <bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
 *      <property name="destination" value="myQueue"/>
 *      <property name="destinationType" value="jakarta.jms.Queue"/>
 *      <property name="useRAManagedTransaction" value="true"/>
 *    </bean>
 *  </property>
 * </bean>
 * 
* * @author Juergen Hoeller * @since 2.5 * @see jakarta.resource.spi.ResourceAdapter#endpointActivation * @see jakarta.resource.spi.ResourceAdapter#endpointDeactivation * @see jakarta.resource.spi.endpoint.MessageEndpointFactory * @see jakarta.resource.spi.ActivationSpec */ public class GenericMessageEndpointManager implements SmartLifecycle, InitializingBean, DisposableBean { @Nullable private ResourceAdapter resourceAdapter; @Nullable private MessageEndpointFactory messageEndpointFactory; @Nullable private ActivationSpec activationSpec; private boolean autoStartup = true; private int phase = DEFAULT_PHASE; private volatile boolean running; private final Object lifecycleMonitor = new Object(); /** * Set the JCA ResourceAdapter to manage endpoints for. */ public void setResourceAdapter(@Nullable ResourceAdapter resourceAdapter) { this.resourceAdapter = resourceAdapter; } /** * Return the JCA ResourceAdapter to manage endpoints for. */ @Nullable public ResourceAdapter getResourceAdapter() { return this.resourceAdapter; } /** * Set the JCA MessageEndpointFactory to activate, pointing to a * MessageListener object that the endpoints will delegate to. *

A MessageEndpointFactory instance may be shared across multiple * endpoints (i.e. multiple GenericMessageEndpointManager instances), * with different {@link #setActivationSpec ActivationSpec} objects applied. * @see GenericMessageEndpointFactory#setMessageListener */ public void setMessageEndpointFactory(@Nullable MessageEndpointFactory messageEndpointFactory) { this.messageEndpointFactory = messageEndpointFactory; } /** * Return the JCA MessageEndpointFactory to activate. */ @Nullable public MessageEndpointFactory getMessageEndpointFactory() { return this.messageEndpointFactory; } /** * Set the JCA ActivationSpec to use for activating the endpoint. *

Note that this ActivationSpec instance should not be shared * across multiple ResourceAdapter instances. */ public void setActivationSpec(@Nullable ActivationSpec activationSpec) { this.activationSpec = activationSpec; } /** * Return the JCA ActivationSpec to use for activating the endpoint. */ @Nullable public ActivationSpec getActivationSpec() { return this.activationSpec; } /** * Set whether to auto-start the endpoint activation after this endpoint * manager has been initialized and the context has been refreshed. *

Default is "true". Turn this flag off to defer the endpoint * activation until an explicit {@link #start()} call. */ public void setAutoStartup(boolean autoStartup) { this.autoStartup = autoStartup; } /** * Return the value for the 'autoStartup' property. If "true", this * endpoint manager will start upon a ContextRefreshedEvent. */ @Override public boolean isAutoStartup() { return this.autoStartup; } /** * Specify the phase in which this endpoint manager should be started * and stopped. The startup order proceeds from lowest to highest, and * the shutdown order is the reverse of that. By default, this value is * {@code Integer.MAX_VALUE} meaning that this endpoint manager starts * as late as possible and stops as soon as possible. */ public void setPhase(int phase) { this.phase = phase; } /** * Return the phase in which this endpoint manager will be started and stopped. */ @Override public int getPhase() { return this.phase; } /** * Prepares the message endpoint, and automatically activates it * if the "autoStartup" flag is set to "true". */ @Override public void afterPropertiesSet() throws ResourceException { if (getResourceAdapter() == null) { throw new IllegalArgumentException("Property 'resourceAdapter' is required"); } if (getMessageEndpointFactory() == null) { throw new IllegalArgumentException("Property 'messageEndpointFactory' is required"); } ActivationSpec activationSpec = getActivationSpec(); if (activationSpec == null) { throw new IllegalArgumentException("Property 'activationSpec' is required"); } if (activationSpec.getResourceAdapter() == null) { activationSpec.setResourceAdapter(getResourceAdapter()); } else if (activationSpec.getResourceAdapter() != getResourceAdapter()) { throw new IllegalArgumentException("ActivationSpec [" + activationSpec + "] is associated with a different ResourceAdapter: " + activationSpec.getResourceAdapter()); } } /** * Activates the configured message endpoint. */ @Override public void start() { synchronized (this.lifecycleMonitor) { if (!this.running) { ResourceAdapter resourceAdapter = getResourceAdapter(); Assert.state(resourceAdapter != null, "No ResourceAdapter set"); try { resourceAdapter.endpointActivation(getMessageEndpointFactory(), getActivationSpec()); } catch (ResourceException ex) { throw new IllegalStateException("Could not activate message endpoint", ex); } this.running = true; } } } /** * Deactivates the configured message endpoint. */ @Override public void stop() { synchronized (this.lifecycleMonitor) { if (this.running) { ResourceAdapter resourceAdapter = getResourceAdapter(); Assert.state(resourceAdapter != null, "No ResourceAdapter set"); resourceAdapter.endpointDeactivation(getMessageEndpointFactory(), getActivationSpec()); this.running = false; } } } @Override public void stop(Runnable callback) { synchronized (this.lifecycleMonitor) { stop(); callback.run(); } } /** * Return whether the configured message endpoint is currently active. */ @Override public boolean isRunning() { return this.running; } /** * Deactivates the message endpoint, preparing it for shutdown. */ @Override public void destroy() { stop(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy