Here are the examples of the java api org.springframework.util.ErrorHandler taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.
56 Examples
19
View Source File : JmsNamespaceHandlerTests.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
@Test
public void testErrorHandlers() {
ErrorHandler expected = this.context.getBean("testErrorHandler", ErrorHandler.clreplaced);
ErrorHandler errorHandler1 = getErrorHandler("listener1");
ErrorHandler errorHandler2 = getErrorHandler("listener2");
ErrorHandler defaultErrorHandler = getErrorHandler(DefaultMessageListenerContainer.clreplaced.getName() + "#0");
replacedertSame(expected, errorHandler1);
replacedertSame(expected, errorHandler2);
replacedertNull(defaultErrorHandler);
}
19
View Source File : AbstractMessageListenerContainer.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Abstract base clreplaced for Spring message listener container implementations.
* Can either host a standard JMS {@link javax.jms.MessageListener} or Spring's
* {@link SessionAwareMessageListener} for actual message processing.
*
* <p>Usually holds a single JMS {@link Connection} that all listeners are supposed
* to be registered on, which is the standard JMS way of managing listener sessions.
* Can alternatively also be used with a fresh Connection per listener, for Java EE
* style XA-aware JMS messaging. The actual registration process is up to concrete
* subclreplacedes.
*
* <p><b>NOTE:</b> The default behavior of this message listener container is to
* <b>never</b> propagate an exception thrown by a message listener up to the JMS
* provider. Instead, it will log any such exception at the error level.
* This means that from the perspective of the attendant JMS provider no such
* listener will ever fail. However, if error handling is necessary, then
* any implementation of the {@link ErrorHandler} strategy may be provided to
* the {@link #setErrorHandler(ErrorHandler)} method. Note that JMSExceptions
* <b>will</b> be preplaceded to the ErrorHandler in addition to (but after) being
* preplaceded to an {@link ExceptionListener}, if one has been provided.
*
* <p>The listener container offers the following message acknowledgment options:
* <ul>
* <li>"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default):
* This mode is container-dependent: For {@link DefaultMessageListenerContainer},
* it means automatic message acknowledgment <i>before</i> listener execution, with
* no redelivery in case of an exception and no redelivery in case of other listener
* execution interruptions either. For {@link SimpleMessageListenerContainer},
* it means automatic message acknowledgment <i>after</i> listener execution, with
* no redelivery in case of a user exception thrown but potential redelivery in case
* of the JVM dying during listener execution. In order to consistently arrange for
* redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
* preferably - setting "sessionTransacted" to "true" instead.
* <li>"sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE":
* <i>Lazy</i> message acknowledgment during ({@link DefaultMessageListenerContainer})
* or shortly after ({@link SimpleMessageListenerContainer}) listener execution;
* no redelivery in case of a user exception thrown but potential redelivery in case
* of the JVM dying during listener execution. In order to consistently arrange for
* redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
* preferably - setting "sessionTransacted" to "true" instead.
* <li>"sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE":
* Automatic message acknowledgment <i>after</i> successful listener execution;
* best-effort redelivery in case of a user exception thrown as well as in case
* of other listener execution interruptions (such as the JVM dying).
* <li>"sessionTransacted" set to "true":
* Transactional acknowledgment after successful listener execution;
* <i>guaranteed redelivery</i> in case of a user exception thrown as well as
* in case of other listener execution interruptions (such as the JVM dying).
* </ul>
*
* <p>There are two solutions to the duplicate message processing problem:
* <ul>
* <li>Either add <i>duplicate message detection</i> to your listener, in the
* form of a business enreplacedy existence check or a protocol table check. This
* usually just needs to be done in case of the JMSRedelivered flag being
* set on the incoming message (otherwise just process straightforwardly).
* Note that with "sessionTransacted" set to "true", duplicate messages will
* only appear in case of the JVM dying at the most unfortunate point possible
* (i.e. after your business logic executed but before the JMS part got committed),
* so duplicate message detection is just there to cover a corner case.
* <li>Or wrap your <i>entire processing with an XA transaction</i>, covering the
* reception of the JMS message as well as the execution of the business logic in
* your message listener (including database operations etc). This is only
* supported by {@link DefaultMessageListenerContainer}, through specifying
* an external "transactionManager" (typically a
* {@link org.springframework.transaction.jta.JtaTransactionManager}, with
* a corresponding XA-aware JMS {@link javax.jms.ConnectionFactory} preplaceded in
* as "connectionFactory").
* </ul>
* Note that XA transaction coordination adds significant runtime overhead,
* so it might be feasible to avoid it unless absolutely necessary.
*
* <p><b>Recommendations:</b>
* <ul>
* <li>The general recommendation is to set "sessionTransacted" to "true",
* typically in combination with local database transactions triggered by the
* listener implementation, through Spring's standard transaction facilities.
* This will work nicely in Tomcat or in a standalone environment, often
* combined with custom duplicate message detection (if it is unacceptable
* to ever process the same message twice).
* <li>Alternatively, specify a
* {@link org.springframework.transaction.jta.JtaTransactionManager} as
* "transactionManager" for a fully XA-aware JMS provider - typically when
* running on a Java EE server, but also for other environments with a JTA
* transaction manager present. This will give full "exactly-once" guarantees
* without custom duplicate message checks, at the price of additional
* runtime processing overhead.
* </ul>
*
* <p>Note that the "sessionTransacted" flag is strongly recommended over
* {@link org.springframework.jms.connection.JmsTransactionManager}, provided
* that transactions do not need to be managed externally. As a consequence,
* set the transaction manager only if you are using JTA or if you need to
* synchronize with custom external transaction arrangements.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 2.0
* @see #setMessageListener
* @see javax.jms.MessageListener
* @see SessionAwareMessageListener
* @see #handleListenerException
* @see DefaultMessageListenerContainer
* @see SimpleMessageListenerContainer
* @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
*/
public abstract clreplaced AbstractMessageListenerContainer extends AbstractJmsListeningContainer implements MessageListenerContainer {
@Nullable
private volatile Object destination;
@Nullable
private volatile String messageSelector;
@Nullable
private volatile Object messageListener;
private boolean subscriptionDurable = false;
private boolean subscriptionShared = false;
@Nullable
private String subscriptionName;
@Nullable
private Boolean replyPubSubDomain;
@Nullable
private QosSettings replyQosSettings;
private boolean pubSubNoLocal = false;
@Nullable
private MessageConverter messageConverter;
@Nullable
private ExceptionListener exceptionListener;
@Nullable
private ErrorHandler errorHandler;
private boolean exposeListenerSession = true;
private boolean acceptMessagesWhileStopping = false;
/**
* Specify concurrency limits.
*/
public abstract void setConcurrency(String concurrency);
/**
* Set the destination to receive messages from.
* <p>Alternatively, specify a "destinationName", to be dynamically
* resolved via the {@link org.springframework.jms.support.destination.DestinationResolver}.
* <p>Note: The destination may be replaced at runtime, with the listener
* container picking up the new destination immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
* @see #setDestinationName(String)
*/
public void setDestination(@Nullable Destination destination) {
this.destination = destination;
if (destination instanceof Topic && !(destination instanceof Queue)) {
// Clearly a Topic: let's set the "pubSubDomain" flag accordingly.
setPubSubDomain(true);
}
}
/**
* Return the destination to receive messages from. Will be {@code null}
* if the configured destination is not an actual {@link Destination} type;
* c.f. {@link #setDestinationName(String) when the destination is a String}.
*/
@Nullable
public Destination getDestination() {
return (this.destination instanceof Destination ? (Destination) this.destination : null);
}
/**
* Set the name of the destination to receive messages from.
* <p>The specified name will be dynamically resolved via the configured
* {@link #setDestinationResolver destination resolver}.
* <p>Alternatively, specify a JMS {@link Destination} object as "destination".
* <p>Note: The destination may be replaced at runtime, with the listener
* container picking up the new destination immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
* @see #setDestination(javax.jms.Destination)
*/
public void setDestinationName(@Nullable String destinationName) {
this.destination = destinationName;
}
/**
* Return the name of the destination to receive messages from.
* Will be {@code null} if the configured destination is not a
* {@link String} type; c.f. {@link #setDestination(Destination) when
* it is an actual Destination}.
*/
@Nullable
public String getDestinationName() {
return (this.destination instanceof String ? (String) this.destination : null);
}
/**
* Return a descriptive String for this container's JMS destination
* (never {@code null}).
*/
protected String getDestinationDescription() {
Object destination = this.destination;
return (destination != null ? destination.toString() : "");
}
/**
* Set the JMS message selector expression (or {@code null} if none).
* Default is none.
* <p>See the JMS specification for a detailed definition of selector expressions.
* <p>Note: The message selector may be replaced at runtime, with the listener
* container picking up the new selector value immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
*/
public void setMessageSelector(@Nullable String messageSelector) {
this.messageSelector = messageSelector;
}
/**
* Return the JMS message selector expression (or {@code null} if none).
*/
@Nullable
public String getMessageSelector() {
return this.messageSelector;
}
/**
* Set the message listener implementation to register.
* This can be either a standard JMS {@link MessageListener} object
* or a Spring {@link SessionAwareMessageListener} object.
* <p>Note: The message listener may be replaced at runtime, with the listener
* container picking up the new listener object immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
* @throws IllegalArgumentException if the supplied listener is not a
* {@link MessageListener} or a {@link SessionAwareMessageListener}
* @see javax.jms.MessageListener
* @see SessionAwareMessageListener
*/
public void setMessageListener(@Nullable Object messageListener) {
checkMessageListener(messageListener);
this.messageListener = messageListener;
if (messageListener != null && this.subscriptionName == null) {
this.subscriptionName = getDefaultSubscriptionName(messageListener);
}
}
/**
* Return the message listener object to register.
*/
@Nullable
public Object getMessageListener() {
return this.messageListener;
}
/**
* Check the given message listener, throwing an exception
* if it does not correspond to a supported listener type.
* <p>By default, only a standard JMS {@link MessageListener} object or a
* Spring {@link SessionAwareMessageListener} object will be accepted.
* @param messageListener the message listener object to check
* @throws IllegalArgumentException if the supplied listener is not a
* {@link MessageListener} or a {@link SessionAwareMessageListener}
* @see javax.jms.MessageListener
* @see SessionAwareMessageListener
*/
protected void checkMessageListener(@Nullable Object messageListener) {
if (messageListener != null && !(messageListener instanceof MessageListener || messageListener instanceof SessionAwareMessageListener)) {
throw new IllegalArgumentException("Message listener needs to be of type [" + MessageListener.clreplaced.getName() + "] or [" + SessionAwareMessageListener.clreplaced.getName() + "]");
}
}
/**
* Determine the default subscription name for the given message listener.
* @param messageListener the message listener object to check
* @return the default subscription name
* @see SubscriptionNameProvider
*/
protected String getDefaultSubscriptionName(Object messageListener) {
if (messageListener instanceof SubscriptionNameProvider) {
return ((SubscriptionNameProvider) messageListener).getSubscriptionName();
} else {
return messageListener.getClreplaced().getName();
}
}
/**
* Set whether to make the subscription durable. The durable subscription name
* to be used can be specified through the "subscriptionName" property.
* <p>Default is "false". Set this to "true" to register a durable subscription,
* typically in combination with a "subscriptionName" value (unless
* your message listener clreplaced name is good enough as subscription name).
* <p>Only makes sense when listening to a topic (pub-sub domain),
* therefore this method switches the "pubSubDomain" flag as well.
* @see #setSubscriptionName
* @see #setPubSubDomain
*/
public void setSubscriptionDurable(boolean subscriptionDurable) {
this.subscriptionDurable = subscriptionDurable;
if (subscriptionDurable) {
setPubSubDomain(true);
}
}
/**
* Return whether to make the subscription durable.
*/
public boolean isSubscriptionDurable() {
return this.subscriptionDurable;
}
/**
* Set whether to make the subscription shared. The shared subscription name
* to be used can be specified through the "subscriptionName" property.
* <p>Default is "false". Set this to "true" to register a shared subscription,
* typically in combination with a "subscriptionName" value (unless
* your message listener clreplaced name is good enough as subscription name).
* Note that shared subscriptions may also be durable, so this flag can
* (and often will) be combined with "subscriptionDurable" as well.
* <p>Only makes sense when listening to a topic (pub-sub domain),
* therefore this method switches the "pubSubDomain" flag as well.
* <p><b>Requires a JMS 2.0 compatible message broker.</b>
* @since 4.1
* @see #setSubscriptionName
* @see #setSubscriptionDurable
* @see #setPubSubDomain
*/
public void setSubscriptionShared(boolean subscriptionShared) {
this.subscriptionShared = subscriptionShared;
if (subscriptionShared) {
setPubSubDomain(true);
}
}
/**
* Return whether to make the subscription shared.
* @since 4.1
*/
public boolean isSubscriptionShared() {
return this.subscriptionShared;
}
/**
* Set the name of a subscription to create. To be applied in case
* of a topic (pub-sub domain) with a shared or durable subscription.
* <p>The subscription name needs to be unique within this client's
* JMS client id. Default is the clreplaced name of the specified message listener.
* <p>Note: Only 1 concurrent consumer (which is the default of this
* message listener container) is allowed for each subscription,
* except for a shared subscription (which requires JMS 2.0).
* @since 4.1
* @see #setPubSubDomain
* @see #setSubscriptionDurable
* @see #setSubscriptionShared
* @see #setClientId
* @see #setMessageListener
*/
public void setSubscriptionName(@Nullable String subscriptionName) {
this.subscriptionName = subscriptionName;
}
/**
* Return the name of a subscription to create, if any.
* @since 4.1
*/
@Nullable
public String getSubscriptionName() {
return this.subscriptionName;
}
/**
* Set the name of a durable subscription to create. This method switches
* to pub-sub domain mode and activates subscription durability as well.
* <p>The durable subscription name needs to be unique within this client's
* JMS client id. Default is the clreplaced name of the specified message listener.
* <p>Note: Only 1 concurrent consumer (which is the default of this
* message listener container) is allowed for each durable subscription,
* except for a shared durable subscription (which requires JMS 2.0).
* @see #setPubSubDomain
* @see #setSubscriptionDurable
* @see #setSubscriptionShared
* @see #setClientId
* @see #setMessageListener
*/
public void setDurableSubscriptionName(@Nullable String durableSubscriptionName) {
this.subscriptionName = durableSubscriptionName;
this.subscriptionDurable = (durableSubscriptionName != null);
}
/**
* Return the name of a durable subscription to create, if any.
*/
@Nullable
public String getDurableSubscriptionName() {
return (this.subscriptionDurable ? this.subscriptionName : null);
}
/**
* Set whether to inhibit the delivery of messages published by its own connection.
* Default is "false".
* @since 4.1
* @see javax.jms.Session#createConsumer(javax.jms.Destination, String, boolean)
*/
public void setPubSubNoLocal(boolean pubSubNoLocal) {
this.pubSubNoLocal = pubSubNoLocal;
}
/**
* Return whether to inhibit the delivery of messages published by its own connection.
* @since 4.1
*/
public boolean isPubSubNoLocal() {
return this.pubSubNoLocal;
}
/**
* Configure the reply destination type. By default, the configured {@code pubSubDomain}
* value is used (see {@link #isPubSubDomain()}.
* <p>This setting primarily indicates what type of destination to resolve if dynamic
* destinations are enabled.
* @param replyPubSubDomain "true" for the Publish/Subscribe domain ({@link Topic Topics}),
* "false" for the Point-to-Point domain ({@link Queue Queues})
* @since 4.2
* @see #setDestinationResolver
*/
public void setReplyPubSubDomain(boolean replyPubSubDomain) {
this.replyPubSubDomain = replyPubSubDomain;
}
/**
* Return whether the Publish/Subscribe domain ({@link javax.jms.Topic Topics}) is used
* for replies. Otherwise, the Point-to-Point domain ({@link javax.jms.Queue Queues})
* is used.
* @since 4.2
*/
@Override
public boolean isReplyPubSubDomain() {
if (this.replyPubSubDomain != null) {
return this.replyPubSubDomain;
} else {
return isPubSubDomain();
}
}
/**
* Configure the {@link QosSettings} to use when sending a reply. Can be set to
* {@code null} to indicate that the broker's defaults should be used.
* @param replyQosSettings the QoS settings to use when sending a reply or {@code null}
* to use the default vas.
* @since 5.0
*/
public void setReplyQosSettings(@Nullable QosSettings replyQosSettings) {
this.replyQosSettings = replyQosSettings;
}
@Override
@Nullable
public QosSettings getReplyQosSettings() {
return this.replyQosSettings;
}
/**
* Set the {@link MessageConverter} strategy for converting JMS Messages.
* @since 4.1
*/
public void setMessageConverter(@Nullable MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
@Override
@Nullable
public MessageConverter getMessageConverter() {
return this.messageConverter;
}
/**
* Set the JMS ExceptionListener to notify in case of a JMSException thrown
* by the registered message listener or the invocation infrastructure.
*/
public void setExceptionListener(@Nullable ExceptionListener exceptionListener) {
this.exceptionListener = exceptionListener;
}
/**
* Return the JMS ExceptionListener to notify in case of a JMSException thrown
* by the registered message listener or the invocation infrastructure, if any.
*/
@Nullable
public ExceptionListener getExceptionListener() {
return this.exceptionListener;
}
/**
* Set the ErrorHandler to be invoked in case of any uncaught exceptions thrown
* while processing a Message.
* <p>By default, there will be <b>no</b> ErrorHandler so that error-level
* logging is the only result.
*/
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Return the ErrorHandler to be invoked in case of any uncaught exceptions thrown
* while processing a Message.
* @since 4.1
*/
@Nullable
public ErrorHandler getErrorHandler() {
return this.errorHandler;
}
/**
* Set whether to expose the listener JMS Session to a registered
* {@link SessionAwareMessageListener} as well as to
* {@link org.springframework.jms.core.JmsTemplate} calls.
* <p>Default is "true", reusing the listener's {@link Session}.
* Turn this off to expose a fresh JMS Session fetched from the same
* underlying JMS {@link Connection} instead, which might be necessary
* on some JMS providers.
* <p>Note that Sessions managed by an external transaction manager will
* always get exposed to {@link org.springframework.jms.core.JmsTemplate}
* calls. So in terms of JmsTemplate exposure, this setting only affects
* locally transacted Sessions.
* @see SessionAwareMessageListener
*/
public void setExposeListenerSession(boolean exposeListenerSession) {
this.exposeListenerSession = exposeListenerSession;
}
/**
* Return whether to expose the listener JMS {@link Session} to a
* registered {@link SessionAwareMessageListener}.
*/
public boolean isExposeListenerSession() {
return this.exposeListenerSession;
}
/**
* Set whether to accept received messages while the listener container
* in the process of stopping.
* <p>Default is "false", rejecting such messages through aborting the
* receive attempt. Switch this flag on to fully process such messages
* even in the stopping phase, with the drawback that even newly sent
* messages might still get processed (if coming in before all receive
* timeouts have expired).
* <p><b>NOTE:</b> Aborting receive attempts for such incoming messages
* might lead to the provider's retry count decreasing for the affected
* messages. If you have a high number of concurrent consumers, make sure
* that the number of retries is higher than the number of consumers,
* to be on the safe side for all potential stopping scenarios.
*/
public void setAcceptMessagesWhileStopping(boolean acceptMessagesWhileStopping) {
this.acceptMessagesWhileStopping = acceptMessagesWhileStopping;
}
/**
* Return whether to accept received messages while the listener container
* in the process of stopping.
*/
public boolean isAcceptMessagesWhileStopping() {
return this.acceptMessagesWhileStopping;
}
@Override
protected void validateConfiguration() {
if (this.destination == null) {
throw new IllegalArgumentException("Property 'destination' or 'destinationName' is required");
}
}
@Override
public void setupMessageListener(Object messageListener) {
setMessageListener(messageListener);
}
// -------------------------------------------------------------------------
// Template methods for listener execution
// -------------------------------------------------------------------------
/**
* Execute the specified listener,
* committing or rolling back the transaction afterwards (if necessary).
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @see #invokeListener
* @see #commitIfNecessary
* @see #rollbackOnExceptionIfNecessary
* @see #handleListenerException
*/
protected void executeListener(Session session, Message message) {
try {
doExecuteListener(session, message);
} catch (Throwable ex) {
handleListenerException(ex);
}
}
/**
* Execute the specified listener,
* committing or rolling back the transaction afterwards (if necessary).
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see #invokeListener
* @see #commitIfNecessary
* @see #rollbackOnExceptionIfNecessary
* @see #convertJmsAccessException
*/
protected void doExecuteListener(Session session, Message message) throws JMSException {
if (!isAcceptMessagesWhileStopping() && !isRunning()) {
if (logger.isWarnEnabled()) {
logger.warn("Rejecting received message because of the listener container " + "having been stopped in the meantime: " + message);
}
rollbackIfNecessary(session);
throw new MessageRejectedWhileStoppingException();
}
try {
invokeListener(session, message);
} catch (JMSException | RuntimeException | Error ex) {
rollbackOnExceptionIfNecessary(session, ex);
throw ex;
}
commitIfNecessary(session, message);
}
/**
* Invoke the specified listener: either as standard JMS MessageListener
* or (preferably) as Spring SessionAwareMessageListener.
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see #setMessageListener
*/
@SuppressWarnings("rawtypes")
protected void invokeListener(Session session, Message message) throws JMSException {
Object listener = getMessageListener();
if (listener instanceof SessionAwareMessageListener) {
doInvokeListener((SessionAwareMessageListener) listener, session, message);
} else if (listener instanceof MessageListener) {
doInvokeListener((MessageListener) listener, message);
} else if (listener != null) {
throw new IllegalArgumentException("Only MessageListener and SessionAwareMessageListener supported: " + listener);
} else {
throw new IllegalStateException("No message listener specified - see property 'messageListener'");
}
}
/**
* Invoke the specified listener as Spring SessionAwareMessageListener,
* exposing a new JMS Session (potentially with its own transaction)
* to the listener if demanded.
* @param listener the Spring SessionAwareMessageListener to invoke
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see SessionAwareMessageListener
* @see #setExposeListenerSession
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void doInvokeListener(SessionAwareMessageListener listener, Session session, Message message) throws JMSException {
Connection conToClose = null;
Session sessionToClose = null;
try {
Session sessionToUse = session;
if (!isExposeListenerSession()) {
// We need to expose a separate Session.
conToClose = createConnection();
sessionToClose = createSession(conToClose);
sessionToUse = sessionToClose;
}
// Actually invoke the message listener...
listener.onMessage(message, sessionToUse);
// Clean up specially exposed Session, if any.
if (sessionToUse != session) {
if (sessionToUse.getTransacted() && isSessionLocallyTransacted(sessionToUse)) {
// Transacted session created by this container -> commit.
JmsUtils.commitIfNecessary(sessionToUse);
}
}
} finally {
JmsUtils.closeSession(sessionToClose);
JmsUtils.closeConnection(conToClose);
}
}
/**
* Invoke the specified listener as standard JMS MessageListener.
* <p>Default implementation performs a plain invocation of the
* {@code onMessage} method.
* @param listener the JMS MessageListener to invoke
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see javax.jms.MessageListener#onMessage
*/
protected void doInvokeListener(MessageListener listener, Message message) throws JMSException {
listener.onMessage(message);
}
/**
* Perform a commit or message acknowledgement, as appropriate.
* @param session the JMS Session to commit
* @param message the Message to acknowledge
* @throws javax.jms.JMSException in case of commit failure
*/
protected void commitIfNecessary(Session session, @Nullable Message message) throws JMSException {
// Commit session or acknowledge message.
if (session.getTransacted()) {
// Commit necessary - but avoid commit call within a JTA transaction.
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> commit.
JmsUtils.commitIfNecessary(session);
}
} else if (message != null && isClientAcknowledge(session)) {
message.acknowledge();
}
}
/**
* Perform a rollback, if appropriate.
* @param session the JMS Session to rollback
* @throws javax.jms.JMSException in case of a rollback error
*/
protected void rollbackIfNecessary(Session session) throws JMSException {
if (session.getTransacted()) {
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> rollback.
JmsUtils.rollbackIfNecessary(session);
}
} else if (isClientAcknowledge(session)) {
session.recover();
}
}
/**
* Perform a rollback, handling rollback exceptions properly.
* @param session the JMS Session to rollback
* @param ex the thrown application exception or error
* @throws javax.jms.JMSException in case of a rollback error
*/
protected void rollbackOnExceptionIfNecessary(Session session, Throwable ex) throws JMSException {
try {
if (session.getTransacted()) {
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> rollback.
if (logger.isDebugEnabled()) {
logger.debug("Initiating transaction rollback on application exception", ex);
}
JmsUtils.rollbackIfNecessary(session);
}
} else if (isClientAcknowledge(session)) {
session.recover();
}
} catch (IllegalStateException ex2) {
logger.debug("Could not roll back because Session already closed", ex2);
} catch (JMSException | RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback error", ex);
throw ex2;
}
}
/**
* Check whether the given Session is locally transacted, that is, whether
* its transaction is managed by this listener container's Session handling
* and not by an external transaction coordinator.
* <p>Note: The Session's own transacted flag will already have been checked
* before. This method is about finding out whether the Session's transaction
* is local or externally coordinated.
* @param session the Session to check
* @return whether the given Session is locally transacted
* @see #isSessionTransacted()
* @see org.springframework.jms.connection.ConnectionFactoryUtils#isSessionTransactional
*/
protected boolean isSessionLocallyTransacted(Session session) {
return isSessionTransacted();
}
/**
* Create a JMS MessageConsumer for the given Session and Destination.
* <p>This implementation uses JMS 1.1 API.
* @param session the JMS Session to create a MessageConsumer for
* @param destination the JMS Destination to create a MessageConsumer for
* @return the new JMS MessageConsumer
* @throws javax.jms.JMSException if thrown by JMS API methods
*/
protected MessageConsumer createConsumer(Session session, Destination destination) throws JMSException {
if (isPubSubDomain() && destination instanceof Topic) {
if (isSubscriptionShared()) {
return (isSubscriptionDurable() ? session.createSharedDurableConsumer((Topic) destination, getSubscriptionName(), getMessageSelector()) : session.createSharedConsumer((Topic) destination, getSubscriptionName(), getMessageSelector()));
} else if (isSubscriptionDurable()) {
return session.createDurableSubscriber((Topic) destination, getSubscriptionName(), getMessageSelector(), isPubSubNoLocal());
} else {
// Only preplaced in the NoLocal flag in case of a Topic (pub-sub mode):
// Some JMS providers, such as WebSphere MQ 6.0, throw IllegalStateException
// in case of the NoLocal flag being specified for a Queue.
return session.createConsumer(destination, getMessageSelector(), isPubSubNoLocal());
}
} else {
return session.createConsumer(destination, getMessageSelector());
}
}
/**
* Handle the given exception that arose during listener execution.
* <p>The default implementation logs the exception at warn level,
* not propagating it to the JMS provider — replaceduming that all handling of
* acknowledgement and/or transactions is done by this listener container.
* This can be overridden in subclreplacedes.
* @param ex the exception to handle
*/
protected void handleListenerException(Throwable ex) {
if (ex instanceof MessageRejectedWhileStoppingException) {
// Internal exception - has been handled before.
return;
}
if (ex instanceof JMSException) {
invokeExceptionListener((JMSException) ex);
}
if (isActive()) {
// Regular case: failed while active.
// Invoke ErrorHandler if available.
invokeErrorHandler(ex);
} else {
// Rare case: listener thread failed after container shutdown.
// Log at debug level, to avoid spamming the shutdown log.
logger.debug("Listener exception after container shutdown", ex);
}
}
/**
* Invoke the registered JMS ExceptionListener, if any.
* @param ex the exception that arose during JMS processing
* @see #setExceptionListener
*/
protected void invokeExceptionListener(JMSException ex) {
ExceptionListener exceptionListener = getExceptionListener();
if (exceptionListener != null) {
exceptionListener.onException(ex);
}
}
/**
* Invoke the registered ErrorHandler, if any. Log at warn level otherwise.
* @param ex the uncaught error that arose during JMS processing.
* @see #setErrorHandler
*/
protected void invokeErrorHandler(Throwable ex) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
errorHandler.handleError(ex);
} else {
logger.warn("Execution of JMS message listener failed, and no ErrorHandler has been set.", ex);
}
}
/**
* Internal exception clreplaced that indicates a rejected message on shutdown.
* Used to trigger a rollback for an external transaction manager in that case.
*/
@SuppressWarnings("serial")
private static clreplaced MessageRejectedWhileStoppingException extends RuntimeException {
}
}
19
View Source File : AbstractMessageListenerContainer.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Set the ErrorHandler to be invoked in case of any uncaught exceptions thrown
* while processing a Message.
* <p>By default, there will be <b>no</b> ErrorHandler so that error-level
* logging is the only result.
*/
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
19
View Source File : AbstractMessageListenerContainer.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Invoke the registered ErrorHandler, if any. Log at warn level otherwise.
* @param ex the uncaught error that arose during JMS processing.
* @see #setErrorHandler
*/
protected void invokeErrorHandler(Throwable ex) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
errorHandler.handleError(ex);
} else {
logger.warn("Execution of JMS message listener failed, and no ErrorHandler has been set.", ex);
}
}
19
View Source File : AbstractJmsListenerContainerFactory.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Base {@link JmsListenerContainerFactory} for Spring's base container implementation.
*
* @author Stephane Nicoll
* @since 4.1
* @param <C> the container type
* @see AbstractMessageListenerContainer
*/
public abstract clreplaced AbstractJmsListenerContainerFactory<C extends AbstractMessageListenerContainer> implements JmsListenerContainerFactory<C> {
protected final Log logger = LogFactory.getLog(getClreplaced());
@Nullable
private ConnectionFactory connectionFactory;
@Nullable
private DestinationResolver destinationResolver;
@Nullable
private ErrorHandler errorHandler;
@Nullable
private MessageConverter messageConverter;
@Nullable
private Boolean sessionTransacted;
@Nullable
private Integer sessionAcknowledgeMode;
@Nullable
private Boolean pubSubDomain;
@Nullable
private Boolean replyPubSubDomain;
@Nullable
private QosSettings replyQosSettings;
@Nullable
private Boolean subscriptionDurable;
@Nullable
private Boolean subscriptionShared;
@Nullable
private String clientId;
@Nullable
private Integer phase;
@Nullable
private Boolean autoStartup;
/**
* @see AbstractMessageListenerContainer#setConnectionFactory(ConnectionFactory)
*/
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
/**
* @see AbstractMessageListenerContainer#setDestinationResolver(DestinationResolver)
*/
public void setDestinationResolver(DestinationResolver destinationResolver) {
this.destinationResolver = destinationResolver;
}
/**
* @see AbstractMessageListenerContainer#setErrorHandler(ErrorHandler)
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* @see AbstractMessageListenerContainer#setMessageConverter(MessageConverter)
*/
public void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
/**
* @see AbstractMessageListenerContainer#setSessionTransacted(boolean)
*/
public void setSessionTransacted(Boolean sessionTransacted) {
this.sessionTransacted = sessionTransacted;
}
/**
* @see AbstractMessageListenerContainer#setSessionAcknowledgeMode(int)
*/
public void setSessionAcknowledgeMode(Integer sessionAcknowledgeMode) {
this.sessionAcknowledgeMode = sessionAcknowledgeMode;
}
/**
* @see AbstractMessageListenerContainer#setPubSubDomain(boolean)
*/
public void setPubSubDomain(Boolean pubSubDomain) {
this.pubSubDomain = pubSubDomain;
}
/**
* @see AbstractMessageListenerContainer#setReplyPubSubDomain(boolean)
*/
public void setReplyPubSubDomain(Boolean replyPubSubDomain) {
this.replyPubSubDomain = replyPubSubDomain;
}
/**
* @see AbstractMessageListenerContainer#setReplyQosSettings(QosSettings)
*/
public void setReplyQosSettings(QosSettings replyQosSettings) {
this.replyQosSettings = replyQosSettings;
}
/**
* @see AbstractMessageListenerContainer#setSubscriptionDurable(boolean)
*/
public void setSubscriptionDurable(Boolean subscriptionDurable) {
this.subscriptionDurable = subscriptionDurable;
}
/**
* @see AbstractMessageListenerContainer#setSubscriptionShared(boolean)
*/
public void setSubscriptionShared(Boolean subscriptionShared) {
this.subscriptionShared = subscriptionShared;
}
/**
* @see AbstractMessageListenerContainer#setClientId(String)
*/
public void setClientId(String clientId) {
this.clientId = clientId;
}
/**
* @see AbstractMessageListenerContainer#setPhase(int)
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* @see AbstractMessageListenerContainer#setAutoStartup(boolean)
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
@Override
public C createListenerContainer(JmsListenerEndpoint endpoint) {
C instance = createContainerInstance();
if (this.connectionFactory != null) {
instance.setConnectionFactory(this.connectionFactory);
}
if (this.destinationResolver != null) {
instance.setDestinationResolver(this.destinationResolver);
}
if (this.errorHandler != null) {
instance.setErrorHandler(this.errorHandler);
}
if (this.messageConverter != null) {
instance.setMessageConverter(this.messageConverter);
}
if (this.sessionTransacted != null) {
instance.setSessionTransacted(this.sessionTransacted);
}
if (this.sessionAcknowledgeMode != null) {
instance.setSessionAcknowledgeMode(this.sessionAcknowledgeMode);
}
if (this.pubSubDomain != null) {
instance.setPubSubDomain(this.pubSubDomain);
}
if (this.replyPubSubDomain != null) {
instance.setReplyPubSubDomain(this.replyPubSubDomain);
}
if (this.replyQosSettings != null) {
instance.setReplyQosSettings(this.replyQosSettings);
}
if (this.subscriptionDurable != null) {
instance.setSubscriptionDurable(this.subscriptionDurable);
}
if (this.subscriptionShared != null) {
instance.setSubscriptionShared(this.subscriptionShared);
}
if (this.clientId != null) {
instance.setClientId(this.clientId);
}
if (this.phase != null) {
instance.setPhase(this.phase);
}
if (this.autoStartup != null) {
instance.setAutoStartup(this.autoStartup);
}
initializeContainer(instance);
endpoint.setupListenerContainer(instance);
return instance;
}
/**
* Create an empty container instance.
*/
protected abstract C createContainerInstance();
/**
* Further initialize the specified container.
* <p>Subclreplacedes can inherit from this method to apply extra
* configuration if necessary.
*/
protected void initializeContainer(C instance) {
}
}
19
View Source File : AbstractJmsListenerContainerFactory.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* @see AbstractMessageListenerContainer#setErrorHandler(ErrorHandler)
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
19
View Source File : TimerManagerTaskScheduler.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Implementation of Spring's {@link TaskScheduler} interface, wrapping
* a CommonJ {@link commonj.timers.TimerManager}.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @since 3.0
* @deprecated as of 5.1, in favor of EE 7's
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler}
*/
@Deprecated
public clreplaced TimerManagerTaskScheduler extends TimerManagerAccessor implements TaskScheduler {
@Nullable
private volatile ErrorHandler errorHandler;
/**
* Provide an {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
@Override
@Nullable
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
return new ReschedulingTimerListener(errorHandlingTask(task, true), trigger).schedule();
}
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, false));
Timer timer = obtainTimerManager().schedule(futureTask, startTime);
futureTask.setTimer(timer);
return futureTask;
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
Timer timer = obtainTimerManager().scheduleAtFixedRate(futureTask, startTime, period);
futureTask.setTimer(timer);
return futureTask;
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
Timer timer = obtainTimerManager().scheduleAtFixedRate(futureTask, 0, period);
futureTask.setTimer(timer);
return futureTask;
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
Timer timer = obtainTimerManager().schedule(futureTask, startTime, delay);
futureTask.setTimer(timer);
return futureTask;
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
Timer timer = obtainTimerManager().schedule(futureTask, 0, delay);
futureTask.setTimer(timer);
return futureTask;
}
private Runnable errorHandlingTask(Runnable delegate, boolean isRepeatingTask) {
return TaskUtils.decorateTaskWithErrorHandler(delegate, this.errorHandler, isRepeatingTask);
}
/**
* ScheduledFuture adapter that wraps a CommonJ Timer.
*/
private static clreplaced TimerScheduledFuture extends FutureTask<Object> implements TimerListener, ScheduledFuture<Object> {
@Nullable
protected transient Timer timer;
protected transient boolean cancelled = false;
public TimerScheduledFuture(Runnable runnable) {
super(runnable, null);
}
public void setTimer(Timer timer) {
this.timer = timer;
}
@Override
public void timerExpired(Timer timer) {
runAndReset();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
boolean result = super.cancel(mayInterruptIfRunning);
if (this.timer != null) {
this.timer.cancel();
}
this.cancelled = true;
return result;
}
@Override
public long getDelay(TimeUnit unit) {
replacedert.state(this.timer != null, "No Timer available");
return unit.convert(this.timer.getScheduledExecutionTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed other) {
if (this == other) {
return 0;
}
long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS);
return (diff == 0 ? 0 : ((diff < 0) ? -1 : 1));
}
}
/**
* ScheduledFuture adapter for trigger-based rescheduling.
*/
private clreplaced ReschedulingTimerListener extends TimerScheduledFuture {
private final Trigger trigger;
private final SimpleTriggerContext triggerContext = new SimpleTriggerContext();
private volatile Date scheduledExecutionTime = new Date();
public ReschedulingTimerListener(Runnable runnable, Trigger trigger) {
super(runnable);
this.trigger = trigger;
}
@Nullable
public ScheduledFuture<?> schedule() {
Date nextExecutionTime = this.trigger.nextExecutionTime(this.triggerContext);
if (nextExecutionTime == null) {
return null;
}
this.scheduledExecutionTime = nextExecutionTime;
setTimer(obtainTimerManager().schedule(this, this.scheduledExecutionTime));
return this;
}
@Override
public void timerExpired(Timer timer) {
Date actualExecutionTime = new Date();
super.timerExpired(timer);
Date completionTime = new Date();
this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
if (!this.cancelled) {
schedule();
}
}
}
}
19
View Source File : TimerManagerTaskScheduler.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Provide an {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
19
View Source File : TaskUtils.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Utility methods for decorating tasks with error handling.
*
* <p><b>NOTE:</b> This clreplaced is intended for internal use by Spring's scheduler
* implementations. It is only public so that it may be accessed from impl clreplacedes
* within other packages. It is <i>not</i> intended for general use.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @since 3.0
*/
public abstract clreplaced TaskUtils {
/**
* An ErrorHandler strategy that will log the Exception but perform
* no further handling. This will suppress the error so that
* subsequent executions of the task will not be prevented.
*/
public static final ErrorHandler LOG_AND_SUPPRESS_ERROR_HANDLER = new LoggingErrorHandler();
/**
* An ErrorHandler strategy that will log at error level and then
* re-throw the Exception. Note: this will typically prevent subsequent
* execution of a scheduled task.
*/
public static final ErrorHandler LOG_AND_PROPAGATE_ERROR_HANDLER = new PropagatingErrorHandler();
/**
* Decorate the task for error handling. If the provided {@link ErrorHandler}
* is not {@code null}, it will be used. Otherwise, repeating tasks will have
* errors suppressed by default whereas one-shot tasks will have errors
* propagated by default since those errors may be expected through the
* returned {@link Future}. In both cases, the errors will be logged.
*/
public static DelegatingErrorHandlingRunnable decorateTaskWithErrorHandler(Runnable task, @Nullable ErrorHandler errorHandler, boolean isRepeatingTask) {
if (task instanceof DelegatingErrorHandlingRunnable) {
return (DelegatingErrorHandlingRunnable) task;
}
ErrorHandler eh = (errorHandler != null ? errorHandler : getDefaultErrorHandler(isRepeatingTask));
return new DelegatingErrorHandlingRunnable(task, eh);
}
/**
* Return the default {@link ErrorHandler} implementation based on the boolean
* value indicating whether the task will be repeating or not. For repeating tasks
* it will suppress errors, but for one-time tasks it will propagate. In both
* cases, the error will be logged.
*/
public static ErrorHandler getDefaultErrorHandler(boolean isRepeatingTask) {
return (isRepeatingTask ? LOG_AND_SUPPRESS_ERROR_HANDLER : LOG_AND_PROPAGATE_ERROR_HANDLER);
}
/**
* An {@link ErrorHandler} implementation that logs the Throwable at error
* level. It does not perform any additional error handling. This can be
* useful when suppression of errors is the intended behavior.
*/
private static clreplaced LoggingErrorHandler implements ErrorHandler {
private final Log logger = LogFactory.getLog(LoggingErrorHandler.clreplaced);
@Override
public void handleError(Throwable t) {
if (logger.isErrorEnabled()) {
logger.error("Unexpected error occurred in scheduled task.", t);
}
}
}
/**
* An {@link ErrorHandler} implementation that logs the Throwable at error
* level and then propagates it.
*/
private static clreplaced PropagatingErrorHandler extends LoggingErrorHandler {
@Override
public void handleError(Throwable t) {
super.handleError(t);
ReflectionUtils.rethrowRuntimeException(t);
}
}
}
19
View Source File : TaskUtils.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Decorate the task for error handling. If the provided {@link ErrorHandler}
* is not {@code null}, it will be used. Otherwise, repeating tasks will have
* errors suppressed by default whereas one-shot tasks will have errors
* propagated by default since those errors may be expected through the
* returned {@link Future}. In both cases, the errors will be logged.
*/
public static DelegatingErrorHandlingRunnable decorateTaskWithErrorHandler(Runnable task, @Nullable ErrorHandler errorHandler, boolean isRepeatingTask) {
if (task instanceof DelegatingErrorHandlingRunnable) {
return (DelegatingErrorHandlingRunnable) task;
}
ErrorHandler eh = (errorHandler != null ? errorHandler : getDefaultErrorHandler(isRepeatingTask));
return new DelegatingErrorHandlingRunnable(task, eh);
}
19
View Source File : DelegatingErrorHandlingRunnable.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Runnable wrapper that catches any exception or error thrown from its
* delegate Runnable and allows an {@link ErrorHandler} to handle it.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @since 3.0
*/
public clreplaced DelegatingErrorHandlingRunnable implements Runnable {
private final Runnable delegate;
private final ErrorHandler errorHandler;
/**
* Create a new DelegatingErrorHandlingRunnable.
* @param delegate the Runnable implementation to delegate to
* @param errorHandler the ErrorHandler for handling any exceptions
*/
public DelegatingErrorHandlingRunnable(Runnable delegate, ErrorHandler errorHandler) {
replacedert.notNull(delegate, "Delegate must not be null");
replacedert.notNull(errorHandler, "ErrorHandler must not be null");
this.delegate = delegate;
this.errorHandler = errorHandler;
}
@Override
public void run() {
try {
this.delegate.run();
} catch (UndeclaredThrowableException ex) {
this.errorHandler.handleError(ex.getUndeclaredThrowable());
} catch (Throwable ex) {
this.errorHandler.handleError(ex);
}
}
@Override
public String toString() {
return "DelegatingErrorHandlingRunnable for " + this.delegate;
}
}
19
View Source File : ThreadPoolTaskScheduler.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Implementation of Spring's {@link TaskScheduler} interface, wrapping
* a native {@link java.util.concurrent.ScheduledThreadPoolExecutor}.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @since 3.0
* @see #setPoolSize
* @see #setRemoveOnCancelPolicy
* @see #setThreadFactory
* @see #setErrorHandler
*/
@SuppressWarnings("serial")
public clreplaced ThreadPoolTaskScheduler extends ExecutorConfigurationSupport implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, TaskScheduler {
private volatile int poolSize = 1;
private volatile boolean removeOnCancelPolicy = false;
@Nullable
private volatile ErrorHandler errorHandler;
@Nullable
private ScheduledExecutorService scheduledExecutor;
// Underlying ScheduledFutureTask to user-level ListenableFuture handle, if any
private final Map<Object, ListenableFuture<?>> listenableFutureMap = new ConcurrentReferenceHashMap<>(16, ConcurrentReferenceHashMap.ReferenceType.WEAK);
/**
* Set the ScheduledExecutorService's pool size.
* Default is 1.
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
*/
public void setPoolSize(int poolSize) {
replacedert.isTrue(poolSize > 0, "'poolSize' must be 1 or higher");
this.poolSize = poolSize;
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setCorePoolSize(poolSize);
}
}
/**
* Set the remove-on-cancel mode on {@link ScheduledThreadPoolExecutor}.
* <p>Default is {@code false}. If set to {@code true}, the target executor will be
* switched into remove-on-cancel mode (if possible, with a soft fallback otherwise).
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
*/
public void setRemoveOnCancelPolicy(boolean removeOnCancelPolicy) {
this.removeOnCancelPolicy = removeOnCancelPolicy;
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(removeOnCancelPolicy);
} else if (removeOnCancelPolicy && this.scheduledExecutor != null) {
logger.debug("Could not apply remove-on-cancel policy - not a ScheduledThreadPoolExecutor");
}
}
/**
* Set a custom {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
@Override
protected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
this.scheduledExecutor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler);
if (this.removeOnCancelPolicy) {
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(true);
} else {
logger.debug("Could not apply remove-on-cancel policy - not a ScheduledThreadPoolExecutor");
}
}
return this.scheduledExecutor;
}
/**
* Create a new {@link ScheduledExecutorService} instance.
* <p>The default implementation creates a {@link ScheduledThreadPoolExecutor}.
* Can be overridden in subclreplacedes to provide custom {@link ScheduledExecutorService} instances.
* @param poolSize the specified pool size
* @param threadFactory the ThreadFactory to use
* @param rejectedExecutionHandler the RejectedExecutionHandler to use
* @return a new ScheduledExecutorService instance
* @see #afterPropertiesSet()
* @see java.util.concurrent.ScheduledThreadPoolExecutor
*/
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return new ScheduledThreadPoolExecutor(poolSize, threadFactory, rejectedExecutionHandler);
}
/**
* Return the underlying ScheduledExecutorService for native access.
* @return the underlying ScheduledExecutorService (never {@code null})
* @throws IllegalStateException if the ThreadPoolTaskScheduler hasn't been initialized yet
*/
public ScheduledExecutorService getScheduledExecutor() throws IllegalStateException {
replacedert.state(this.scheduledExecutor != null, "ThreadPoolTaskScheduler not initialized");
return this.scheduledExecutor;
}
/**
* Return the underlying ScheduledThreadPoolExecutor, if available.
* @return the underlying ScheduledExecutorService (never {@code null})
* @throws IllegalStateException if the ThreadPoolTaskScheduler hasn't been initialized yet
* or if the underlying ScheduledExecutorService isn't a ScheduledThreadPoolExecutor
* @see #getScheduledExecutor()
*/
public ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() throws IllegalStateException {
replacedert.state(this.scheduledExecutor instanceof ScheduledThreadPoolExecutor, "No ScheduledThreadPoolExecutor available");
return (ScheduledThreadPoolExecutor) this.scheduledExecutor;
}
/**
* Return the current pool size.
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
* @see #getScheduledThreadPoolExecutor()
* @see java.util.concurrent.ScheduledThreadPoolExecutor#getPoolSize()
*/
public int getPoolSize() {
if (this.scheduledExecutor == null) {
// Not initialized yet: replacedume initial pool size.
return this.poolSize;
}
return getScheduledThreadPoolExecutor().getPoolSize();
}
/**
* Return the current setting for the remove-on-cancel mode.
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
*/
public boolean isRemoveOnCancelPolicy() {
if (this.scheduledExecutor == null) {
// Not initialized yet: return our setting for the time being.
return this.removeOnCancelPolicy;
}
return getScheduledThreadPoolExecutor().getRemoveOnCancelPolicy();
}
/**
* Return the number of currently active threads.
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
* @see #getScheduledThreadPoolExecutor()
* @see java.util.concurrent.ScheduledThreadPoolExecutor#getActiveCount()
*/
public int getActiveCount() {
if (this.scheduledExecutor == null) {
// Not initialized yet: replacedume no active threads.
return 0;
}
return getScheduledThreadPoolExecutor().getActiveCount();
}
// SchedulingTaskExecutor implementation
@Override
public void execute(Runnable task) {
Executor executor = getScheduledExecutor();
try {
executor.execute(errorHandlingTask(task, false));
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public void execute(Runnable task, long startTimeout) {
execute(task);
}
@Override
public Future<?> submit(Runnable task) {
ExecutorService executor = getScheduledExecutor();
try {
return executor.submit(errorHandlingTask(task, false));
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public <T> Future<T> submit(Callable<T> task) {
ExecutorService executor = getScheduledExecutor();
try {
Callable<T> taskToUse = task;
ErrorHandler errorHandler = this.errorHandler;
if (errorHandler != null) {
taskToUse = new DelegatingErrorHandlingCallable<>(task, errorHandler);
}
return executor.submit(taskToUse);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
ExecutorService executor = getScheduledExecutor();
try {
ListenableFutureTask<Object> listenableFuture = new ListenableFutureTask<>(task, null);
executeAndTrack(executor, listenableFuture);
return listenableFuture;
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
ExecutorService executor = getScheduledExecutor();
try {
ListenableFutureTask<T> listenableFuture = new ListenableFutureTask<>(task);
executeAndTrack(executor, listenableFuture);
return listenableFuture;
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
private void executeAndTrack(ExecutorService executor, ListenableFutureTask<?> listenableFuture) {
Future<?> scheduledFuture = executor.submit(errorHandlingTask(listenableFuture, false));
this.listenableFutureMap.put(scheduledFuture, listenableFuture);
listenableFuture.addCallback(result -> this.listenableFutureMap.remove(scheduledFuture), ex -> this.listenableFutureMap.remove(scheduledFuture));
}
@Override
protected void cancelRemainingTask(Runnable task) {
super.cancelRemainingTask(task);
// Cancel replacedociated user-level ListenableFuture handle as well
ListenableFuture<?> listenableFuture = this.listenableFutureMap.get(task);
if (listenableFuture != null) {
listenableFuture.cancel(true);
}
}
// TaskScheduler implementation
@Override
@Nullable
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
ScheduledExecutorService executor = getScheduledExecutor();
try {
ErrorHandler errorHandler = this.errorHandler;
if (errorHandler == null) {
errorHandler = TaskUtils.getDefaultErrorHandler(true);
}
return new ReschedulingRunnable(task, trigger, executor, errorHandler).schedule();
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
ScheduledExecutorService executor = getScheduledExecutor();
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return executor.schedule(errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
ScheduledExecutorService executor = getScheduledExecutor();
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return executor.scheduleAtFixedRate(errorHandlingTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
ScheduledExecutorService executor = getScheduledExecutor();
try {
return executor.scheduleAtFixedRate(errorHandlingTask(task, true), 0, period, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
ScheduledExecutorService executor = getScheduledExecutor();
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
ScheduledExecutorService executor = getScheduledExecutor();
try {
return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), 0, delay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
private Runnable errorHandlingTask(Runnable task, boolean isRepeatingTask) {
return TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, isRepeatingTask);
}
private static clreplaced DelegatingErrorHandlingCallable<V> implements Callable<V> {
private final Callable<V> delegate;
private final ErrorHandler errorHandler;
public DelegatingErrorHandlingCallable(Callable<V> delegate, ErrorHandler errorHandler) {
this.delegate = delegate;
this.errorHandler = errorHandler;
}
@Override
@Nullable
public V call() throws Exception {
try {
return this.delegate.call();
} catch (Throwable ex) {
this.errorHandler.handleError(ex);
return null;
}
}
}
}
19
View Source File : ThreadPoolTaskScheduler.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Set a custom {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
19
View Source File : ConcurrentTaskScheduler.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Adapter that takes a {@code java.util.concurrent.ScheduledExecutorService} and
* exposes a Spring {@link org.springframework.scheduling.TaskScheduler} for it.
* Extends {@link ConcurrentTaskExecutor} in order to implement the
* {@link org.springframework.scheduling.SchedulingTaskExecutor} interface as well.
*
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService}
* in order to use it for trigger-based scheduling if possible, instead of Spring's
* local trigger management which ends up delegating to regular delay-based scheduling
* against the {@code java.util.concurrent.ScheduledExecutorService} API. For JSR-236 style
* lookup in a Java EE 7 environment, consider using {@link DefaultManagedTaskScheduler}.
*
* <p>Note that there is a pre-built {@link ThreadPoolTaskScheduler} that allows for
* defining a {@link java.util.concurrent.ScheduledThreadPoolExecutor} in bean style,
* exposing it as a Spring {@link org.springframework.scheduling.TaskScheduler} directly.
* This is a convenient alternative to a raw ScheduledThreadPoolExecutor definition with
* a separate definition of the present adapter clreplaced.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @since 3.0
* @see java.util.concurrent.ScheduledExecutorService
* @see java.util.concurrent.ScheduledThreadPoolExecutor
* @see java.util.concurrent.Executors
* @see DefaultManagedTaskScheduler
* @see ThreadPoolTaskScheduler
*/
public clreplaced ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements TaskScheduler {
@Nullable
private static Clreplaced<?> managedScheduledExecutorServiceClreplaced;
static {
try {
managedScheduledExecutorServiceClreplaced = ClreplacedUtils.forName("javax.enterprise.concurrent.ManagedScheduledExecutorService", ConcurrentTaskScheduler.clreplaced.getClreplacedLoader());
} catch (ClreplacedNotFoundException ex) {
// JSR-236 API not available...
managedScheduledExecutorServiceClreplaced = null;
}
}
private ScheduledExecutorService scheduledExecutor;
private boolean enterpriseConcurrentScheduler = false;
@Nullable
private ErrorHandler errorHandler;
/**
* Create a new ConcurrentTaskScheduler,
* using a single thread executor as default.
* @see java.util.concurrent.Executors#newSingleThreadScheduledExecutor()
*/
public ConcurrentTaskScheduler() {
super();
this.scheduledExecutor = initScheduledExecutor(null);
}
/**
* Create a new ConcurrentTaskScheduler, using the given
* {@link java.util.concurrent.ScheduledExecutorService} as shared delegate.
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService}
* in order to use it for trigger-based scheduling if possible,
* instead of Spring's local trigger management.
* @param scheduledExecutor the {@link java.util.concurrent.ScheduledExecutorService}
* to delegate to for {@link org.springframework.scheduling.SchedulingTaskExecutor}
* as well as {@link TaskScheduler} invocations
*/
public ConcurrentTaskScheduler(ScheduledExecutorService scheduledExecutor) {
super(scheduledExecutor);
this.scheduledExecutor = initScheduledExecutor(scheduledExecutor);
}
/**
* Create a new ConcurrentTaskScheduler, using the given {@link java.util.concurrent.Executor}
* and {@link java.util.concurrent.ScheduledExecutorService} as delegates.
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService}
* in order to use it for trigger-based scheduling if possible,
* instead of Spring's local trigger management.
* @param concurrentExecutor the {@link java.util.concurrent.Executor} to delegate to
* for {@link org.springframework.scheduling.SchedulingTaskExecutor} invocations
* @param scheduledExecutor the {@link java.util.concurrent.ScheduledExecutorService}
* to delegate to for {@link TaskScheduler} invocations
*/
public ConcurrentTaskScheduler(Executor concurrentExecutor, ScheduledExecutorService scheduledExecutor) {
super(concurrentExecutor);
this.scheduledExecutor = initScheduledExecutor(scheduledExecutor);
}
private ScheduledExecutorService initScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) {
if (scheduledExecutor != null) {
this.scheduledExecutor = scheduledExecutor;
this.enterpriseConcurrentScheduler = (managedScheduledExecutorServiceClreplaced != null && managedScheduledExecutorServiceClreplaced.isInstance(scheduledExecutor));
} else {
this.scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
this.enterpriseConcurrentScheduler = false;
}
return this.scheduledExecutor;
}
/**
* Specify the {@link java.util.concurrent.ScheduledExecutorService} to delegate to.
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService}
* in order to use it for trigger-based scheduling if possible,
* instead of Spring's local trigger management.
* <p>Note: This will only apply to {@link TaskScheduler} invocations.
* If you want the given executor to apply to
* {@link org.springframework.scheduling.SchedulingTaskExecutor} invocations
* as well, preplaced the same executor reference to {@link #setConcurrentExecutor}.
* @see #setConcurrentExecutor
*/
public void setScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) {
initScheduledExecutor(scheduledExecutor);
}
/**
* Provide an {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
replacedert.notNull(errorHandler, "ErrorHandler must not be null");
this.errorHandler = errorHandler;
}
@Override
@Nullable
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
try {
if (this.enterpriseConcurrentScheduler) {
return new EnterpriseConcurrentTriggerScheduler().schedule(decorateTask(task, true), trigger);
} else {
ErrorHandler errorHandler = (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true));
return new ReschedulingRunnable(task, trigger, this.scheduledExecutor, errorHandler).schedule();
}
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return this.scheduledExecutor.schedule(decorateTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return this.scheduledExecutor.scheduleAtFixedRate(decorateTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
try {
return this.scheduledExecutor.scheduleAtFixedRate(decorateTask(task, true), 0, period, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return this.scheduledExecutor.scheduleWithFixedDelay(decorateTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
try {
return this.scheduledExecutor.scheduleWithFixedDelay(decorateTask(task, true), 0, delay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
private Runnable decorateTask(Runnable task, boolean isRepeatingTask) {
Runnable result = TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, isRepeatingTask);
if (this.enterpriseConcurrentScheduler) {
result = ManagedTaskBuilder.buildManagedTask(result, task.toString());
}
return result;
}
/**
* Delegate that adapts a Spring Trigger to a JSR-236 Trigger.
* Separated into an inner clreplaced in order to avoid a hard dependency on the JSR-236 API.
*/
private clreplaced EnterpriseConcurrentTriggerScheduler {
public ScheduledFuture<?> schedule(Runnable task, final Trigger trigger) {
ManagedScheduledExecutorService executor = (ManagedScheduledExecutorService) scheduledExecutor;
return executor.schedule(task, new javax.enterprise.concurrent.Trigger() {
@Override
@Nullable
public Date getNextRunTime(@Nullable LastExecution le, Date taskScheduledTime) {
return (trigger.nextExecutionTime(le != null ? new SimpleTriggerContext(le.getScheduledStart(), le.getRunStart(), le.getRunEnd()) : new SimpleTriggerContext()));
}
@Override
public boolean skipRun(LastExecution lastExecution, Date scheduledRunTime) {
return false;
}
});
}
}
}
19
View Source File : ConcurrentTaskScheduler.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Provide an {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
replacedert.notNull(errorHandler, "ErrorHandler must not be null");
this.errorHandler = errorHandler;
}
19
View Source File : ConcurrentTaskScheduler.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
@Override
@Nullable
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
try {
if (this.enterpriseConcurrentScheduler) {
return new EnterpriseConcurrentTriggerScheduler().schedule(decorateTask(task, true), trigger);
} else {
ErrorHandler errorHandler = (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true));
return new ReschedulingRunnable(task, trigger, this.scheduledExecutor, errorHandler).schedule();
}
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
19
View Source File : SimpleApplicationEventMulticaster.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Simple implementation of the {@link ApplicationEventMulticaster} interface.
*
* <p>Multicasts all events to all registered listeners, leaving it up to
* the listeners to ignore events that they are not interested in.
* Listeners will usually perform corresponding {@code instanceof}
* checks on the preplaceded-in event object.
*
* <p>By default, all listeners are invoked in the calling thread.
* This allows the danger of a rogue listener blocking the entire application,
* but adds minimal overhead. Specify an alternative task executor to have
* listeners executed in different threads, for example from a thread pool.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Stephane Nicoll
* @see #setTaskExecutor
*/
public clreplaced SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
@Nullable
private ErrorHandler errorHandler;
/**
* Create a new SimpleApplicationEventMulticaster.
*/
public SimpleApplicationEventMulticaster() {
}
/**
* Create a new SimpleApplicationEventMulticaster for the given BeanFactory.
*/
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
/**
* Set a custom executor (typically a {@link org.springframework.core.task.TaskExecutor})
* to invoke each listener with.
* <p>Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor},
* executing all listeners synchronously in the calling thread.
* <p>Consider specifying an asynchronous task executor here to not block the
* caller until all listeners have been executed. However, note that asynchronous
* execution will not participate in the caller's thread context (clreplaced loader,
* transaction replacedociation) unless the TaskExecutor explicitly supports this.
* @see org.springframework.core.task.SyncTaskExecutor
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
*/
public void setTaskExecutor(@Nullable Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/**
* Return the current task executor for this multicaster.
*/
@Nullable
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
/**
* Set the {@link ErrorHandler} to invoke in case an exception is thrown
* from a listener.
* <p>Default is none, with a listener exception stopping the current
* multicast and getting propagated to the publisher of the current event.
* If a {@linkplain #setTaskExecutor task executor} is specified, each
* individual listener exception will get propagated to the executor but
* won't necessarily stop execution of other listeners.
* <p>Consider setting an {@link ErrorHandler} implementation that catches
* and logs exceptions (a la
* {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_SUPPRESS_ERROR_HANDLER})
* or an implementation that logs exceptions while nevertheless propagating them
* (e.g. {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_PROPAGATE_ERROR_HANDLER}).
* @since 4.1
*/
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Return the current error handler for this multicaster.
* @since 4.1
*/
@Nullable
protected ErrorHandler getErrorHandler() {
return this.errorHandler;
}
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// 遍历注册的消息监听器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
} else {
invokeListener(listener, event);
}
}
}
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
} catch (ClreplacedCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClreplacedCastMessage(msg, event.getClreplaced())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClreplaced());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
} else {
throw ex;
}
}
}
private boolean matchesClreplacedCastMessage(String clreplacedCastMessage, Clreplaced<?> eventClreplaced) {
// On Java 8, the message starts with the clreplaced name: "java.lang.String cannot be cast..."
if (clreplacedCastMessage.startsWith(eventClreplaced.getName())) {
return true;
}
// On Java 11, the message starts with "clreplaced ..." a.k.a. Clreplaced.toString()
if (clreplacedCastMessage.startsWith(eventClreplaced.toString())) {
return true;
}
// On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."
int moduleSeparatorIndex = clreplacedCastMessage.indexOf('/');
if (moduleSeparatorIndex != -1 && clreplacedCastMessage.startsWith(eventClreplaced.getName(), moduleSeparatorIndex + 1)) {
return true;
}
// replaceduming an unrelated clreplaced cast failure...
return false;
}
}
19
View Source File : SimpleApplicationEventMulticaster.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Set the {@link ErrorHandler} to invoke in case an exception is thrown
* from a listener.
* <p>Default is none, with a listener exception stopping the current
* multicast and getting propagated to the publisher of the current event.
* If a {@linkplain #setTaskExecutor task executor} is specified, each
* individual listener exception will get propagated to the executor but
* won't necessarily stop execution of other listeners.
* <p>Consider setting an {@link ErrorHandler} implementation that catches
* and logs exceptions (a la
* {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_SUPPRESS_ERROR_HANDLER})
* or an implementation that logs exceptions while nevertheless propagating them
* (e.g. {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_PROPAGATE_ERROR_HANDLER}).
* @since 4.1
*/
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
19
View Source File : JmsNamespaceHandlerTests.java
License : Apache License 2.0
Project Creator : SourceHot
License : Apache License 2.0
Project Creator : SourceHot
@Test
public void testErrorHandlers() {
ErrorHandler expected = this.context.getBean("testErrorHandler", ErrorHandler.clreplaced);
ErrorHandler errorHandler1 = getErrorHandler("listener1");
ErrorHandler errorHandler2 = getErrorHandler("listener2");
ErrorHandler defaultErrorHandler = getErrorHandler(DefaultMessageListenerContainer.clreplaced.getName() + "#0");
replacedertThat(errorHandler1).isSameAs(expected);
replacedertThat(errorHandler2).isSameAs(expected);
replacedertThat(defaultErrorHandler).isNull();
}
19
View Source File : AbstractMessageListenerContainer.java
License : Apache License 2.0
Project Creator : SourceHot
License : Apache License 2.0
Project Creator : SourceHot
/**
* Abstract base clreplaced for Spring message listener container implementations.
* Can either host a standard JMS {@link javax.jms.MessageListener} or Spring's
* {@link SessionAwareMessageListener} for actual message processing.
*
* <p>Usually holds a single JMS {@link Connection} that all listeners are supposed
* to be registered on, which is the standard JMS way of managing listener sessions.
* Can alternatively also be used with a fresh Connection per listener, for Java EE
* style XA-aware JMS messaging. The actual registration process is up to concrete
* subclreplacedes.
*
* <p><b>NOTE:</b> The default behavior of this message listener container is to
* <b>never</b> propagate an exception thrown by a message listener up to the JMS
* provider. Instead, it will log any such exception at the error level.
* This means that from the perspective of the attendant JMS provider no such
* listener will ever fail. However, if error handling is necessary, then
* any implementation of the {@link ErrorHandler} strategy may be provided to
* the {@link #setErrorHandler(ErrorHandler)} method. Note that JMSExceptions
* <b>will</b> be preplaceded to the ErrorHandler in addition to (but after) being
* preplaceded to an {@link ExceptionListener}, if one has been provided.
*
* <p>The listener container offers the following message acknowledgment options:
* <ul>
* <li>"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default):
* This mode is container-dependent: For {@link DefaultMessageListenerContainer},
* it means automatic message acknowledgment <i>before</i> listener execution, with
* no redelivery in case of an exception and no redelivery in case of other listener
* execution interruptions either. For {@link SimpleMessageListenerContainer},
* it means automatic message acknowledgment <i>after</i> listener execution, with
* no redelivery in case of a user exception thrown but potential redelivery in case
* of the JVM dying during listener execution. In order to consistently arrange for
* redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
* preferably - setting "sessionTransacted" to "true" instead.
* <li>"sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE":
* <i>Lazy</i> message acknowledgment during ({@link DefaultMessageListenerContainer})
* or shortly after ({@link SimpleMessageListenerContainer}) listener execution;
* no redelivery in case of a user exception thrown but potential redelivery in case
* of the JVM dying during listener execution. In order to consistently arrange for
* redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
* preferably - setting "sessionTransacted" to "true" instead.
* <li>"sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE":
* Automatic message acknowledgment <i>after</i> successful listener execution;
* best-effort redelivery in case of a user exception thrown as well as in case
* of other listener execution interruptions (such as the JVM dying).
* <li>"sessionTransacted" set to "true":
* Transactional acknowledgment after successful listener execution;
* <i>guaranteed redelivery</i> in case of a user exception thrown as well as
* in case of other listener execution interruptions (such as the JVM dying).
* </ul>
*
* <p>There are two solutions to the duplicate message processing problem:
* <ul>
* <li>Either add <i>duplicate message detection</i> to your listener, in the
* form of a business enreplacedy existence check or a protocol table check. This
* usually just needs to be done in case of the JMSRedelivered flag being
* set on the incoming message (otherwise just process straightforwardly).
* Note that with "sessionTransacted" set to "true", duplicate messages will
* only appear in case of the JVM dying at the most unfortunate point possible
* (i.e. after your business logic executed but before the JMS part got committed),
* so duplicate message detection is just there to cover a corner case.
* <li>Or wrap your <i>entire processing with an XA transaction</i>, covering the
* reception of the JMS message as well as the execution of the business logic in
* your message listener (including database operations etc). This is only
* supported by {@link DefaultMessageListenerContainer}, through specifying
* an external "transactionManager" (typically a
* {@link org.springframework.transaction.jta.JtaTransactionManager}, with
* a corresponding XA-aware JMS {@link javax.jms.ConnectionFactory} preplaceded in
* as "connectionFactory").
* </ul>
* Note that XA transaction coordination adds significant runtime overhead,
* so it might be feasible to avoid it unless absolutely necessary.
*
* <p><b>Recommendations:</b>
* <ul>
* <li>The general recommendation is to set "sessionTransacted" to "true",
* typically in combination with local database transactions triggered by the
* listener implementation, through Spring's standard transaction facilities.
* This will work nicely in Tomcat or in a standalone environment, often
* combined with custom duplicate message detection (if it is unacceptable
* to ever process the same message twice).
* <li>Alternatively, specify a
* {@link org.springframework.transaction.jta.JtaTransactionManager} as
* "transactionManager" for a fully XA-aware JMS provider - typically when
* running on a Java EE server, but also for other environments with a JTA
* transaction manager present. This will give full "exactly-once" guarantees
* without custom duplicate message checks, at the price of additional
* runtime processing overhead.
* </ul>
*
* <p>Note that the "sessionTransacted" flag is strongly recommended over
* {@link org.springframework.jms.connection.JmsTransactionManager}, provided
* that transactions do not need to be managed externally. As a consequence,
* set the transaction manager only if you are using JTA or if you need to
* synchronize with custom external transaction arrangements.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 2.0
* @see #setMessageListener
* @see javax.jms.MessageListener
* @see SessionAwareMessageListener
* @see #handleListenerException
* @see DefaultMessageListenerContainer
* @see SimpleMessageListenerContainer
* @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
*/
public abstract clreplaced AbstractMessageListenerContainer extends AbstractJmsListeningContainer implements MessageListenerContainer {
@Nullable
private volatile Object destination;
@Nullable
private volatile String messageSelector;
@Nullable
private volatile Object messageListener;
private boolean subscriptionDurable = false;
private boolean subscriptionShared = false;
@Nullable
private String subscriptionName;
@Nullable
private Boolean replyPubSubDomain;
@Nullable
private QosSettings replyQosSettings;
private boolean pubSubNoLocal = false;
@Nullable
private MessageConverter messageConverter;
@Nullable
private ExceptionListener exceptionListener;
@Nullable
private ErrorHandler errorHandler;
private boolean exposeListenerSession = true;
private boolean acceptMessagesWhileStopping = false;
/**
* Specify concurrency limits.
*/
public abstract void setConcurrency(String concurrency);
/**
* Set the destination to receive messages from.
* <p>Alternatively, specify a "destinationName", to be dynamically
* resolved via the {@link org.springframework.jms.support.destination.DestinationResolver}.
* <p>Note: The destination may be replaced at runtime, with the listener
* container picking up the new destination immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
* @see #setDestinationName(String)
*/
public void setDestination(@Nullable Destination destination) {
this.destination = destination;
if (destination instanceof Topic && !(destination instanceof Queue)) {
// Clearly a Topic: let's set the "pubSubDomain" flag accordingly.
setPubSubDomain(true);
}
}
/**
* Return the destination to receive messages from. Will be {@code null}
* if the configured destination is not an actual {@link Destination} type;
* c.f. {@link #setDestinationName(String) when the destination is a String}.
*/
@Nullable
public Destination getDestination() {
return (this.destination instanceof Destination ? (Destination) this.destination : null);
}
/**
* Set the name of the destination to receive messages from.
* <p>The specified name will be dynamically resolved via the configured
* {@link #setDestinationResolver destination resolver}.
* <p>Alternatively, specify a JMS {@link Destination} object as "destination".
* <p>Note: The destination may be replaced at runtime, with the listener
* container picking up the new destination immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
* @see #setDestination(javax.jms.Destination)
*/
public void setDestinationName(@Nullable String destinationName) {
this.destination = destinationName;
}
/**
* Return the name of the destination to receive messages from.
* Will be {@code null} if the configured destination is not a
* {@link String} type; c.f. {@link #setDestination(Destination) when
* it is an actual Destination}.
*/
@Nullable
public String getDestinationName() {
return (this.destination instanceof String ? (String) this.destination : null);
}
/**
* Return a descriptive String for this container's JMS destination
* (never {@code null}).
*/
protected String getDestinationDescription() {
Object destination = this.destination;
return (destination != null ? destination.toString() : "");
}
/**
* Set the JMS message selector expression (or {@code null} if none).
* Default is none.
* <p>See the JMS specification for a detailed definition of selector expressions.
* <p>Note: The message selector may be replaced at runtime, with the listener
* container picking up the new selector value immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
*/
public void setMessageSelector(@Nullable String messageSelector) {
this.messageSelector = messageSelector;
}
/**
* Return the JMS message selector expression (or {@code null} if none).
*/
@Nullable
public String getMessageSelector() {
return this.messageSelector;
}
/**
* Set the message listener implementation to register.
* This can be either a standard JMS {@link MessageListener} object
* or a Spring {@link SessionAwareMessageListener} object.
* <p>Note: The message listener may be replaced at runtime, with the listener
* container picking up the new listener object immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
* @throws IllegalArgumentException if the supplied listener is not a
* {@link MessageListener} or a {@link SessionAwareMessageListener}
* @see javax.jms.MessageListener
* @see SessionAwareMessageListener
*/
public void setMessageListener(@Nullable Object messageListener) {
checkMessageListener(messageListener);
this.messageListener = messageListener;
if (messageListener != null && this.subscriptionName == null) {
this.subscriptionName = getDefaultSubscriptionName(messageListener);
}
}
/**
* Return the message listener object to register.
*/
@Nullable
public Object getMessageListener() {
return this.messageListener;
}
/**
* Check the given message listener, throwing an exception
* if it does not correspond to a supported listener type.
* <p>By default, only a standard JMS {@link MessageListener} object or a
* Spring {@link SessionAwareMessageListener} object will be accepted.
* @param messageListener the message listener object to check
* @throws IllegalArgumentException if the supplied listener is not a
* {@link MessageListener} or a {@link SessionAwareMessageListener}
* @see javax.jms.MessageListener
* @see SessionAwareMessageListener
*/
protected void checkMessageListener(@Nullable Object messageListener) {
if (messageListener != null && !(messageListener instanceof MessageListener || messageListener instanceof SessionAwareMessageListener)) {
throw new IllegalArgumentException("Message listener needs to be of type [" + MessageListener.clreplaced.getName() + "] or [" + SessionAwareMessageListener.clreplaced.getName() + "]");
}
}
/**
* Determine the default subscription name for the given message listener.
* @param messageListener the message listener object to check
* @return the default subscription name
* @see SubscriptionNameProvider
*/
protected String getDefaultSubscriptionName(Object messageListener) {
if (messageListener instanceof SubscriptionNameProvider) {
return ((SubscriptionNameProvider) messageListener).getSubscriptionName();
} else {
return messageListener.getClreplaced().getName();
}
}
/**
* Set whether to make the subscription durable. The durable subscription name
* to be used can be specified through the "subscriptionName" property.
* <p>Default is "false". Set this to "true" to register a durable subscription,
* typically in combination with a "subscriptionName" value (unless
* your message listener clreplaced name is good enough as subscription name).
* <p>Only makes sense when listening to a topic (pub-sub domain),
* therefore this method switches the "pubSubDomain" flag as well.
* @see #setSubscriptionName
* @see #setPubSubDomain
*/
public void setSubscriptionDurable(boolean subscriptionDurable) {
this.subscriptionDurable = subscriptionDurable;
if (subscriptionDurable) {
setPubSubDomain(true);
}
}
/**
* Return whether to make the subscription durable.
*/
public boolean isSubscriptionDurable() {
return this.subscriptionDurable;
}
/**
* Set whether to make the subscription shared. The shared subscription name
* to be used can be specified through the "subscriptionName" property.
* <p>Default is "false". Set this to "true" to register a shared subscription,
* typically in combination with a "subscriptionName" value (unless
* your message listener clreplaced name is good enough as subscription name).
* Note that shared subscriptions may also be durable, so this flag can
* (and often will) be combined with "subscriptionDurable" as well.
* <p>Only makes sense when listening to a topic (pub-sub domain),
* therefore this method switches the "pubSubDomain" flag as well.
* <p><b>Requires a JMS 2.0 compatible message broker.</b>
* @since 4.1
* @see #setSubscriptionName
* @see #setSubscriptionDurable
* @see #setPubSubDomain
*/
public void setSubscriptionShared(boolean subscriptionShared) {
this.subscriptionShared = subscriptionShared;
if (subscriptionShared) {
setPubSubDomain(true);
}
}
/**
* Return whether to make the subscription shared.
* @since 4.1
*/
public boolean isSubscriptionShared() {
return this.subscriptionShared;
}
/**
* Set the name of a subscription to create. To be applied in case
* of a topic (pub-sub domain) with a shared or durable subscription.
* <p>The subscription name needs to be unique within this client's
* JMS client id. Default is the clreplaced name of the specified message listener.
* <p>Note: Only 1 concurrent consumer (which is the default of this
* message listener container) is allowed for each subscription,
* except for a shared subscription (which requires JMS 2.0).
* @since 4.1
* @see #setPubSubDomain
* @see #setSubscriptionDurable
* @see #setSubscriptionShared
* @see #setClientId
* @see #setMessageListener
*/
public void setSubscriptionName(@Nullable String subscriptionName) {
this.subscriptionName = subscriptionName;
}
/**
* Return the name of a subscription to create, if any.
* @since 4.1
*/
@Nullable
public String getSubscriptionName() {
return this.subscriptionName;
}
/**
* Set the name of a durable subscription to create. This method switches
* to pub-sub domain mode and activates subscription durability as well.
* <p>The durable subscription name needs to be unique within this client's
* JMS client id. Default is the clreplaced name of the specified message listener.
* <p>Note: Only 1 concurrent consumer (which is the default of this
* message listener container) is allowed for each durable subscription,
* except for a shared durable subscription (which requires JMS 2.0).
* @see #setPubSubDomain
* @see #setSubscriptionDurable
* @see #setSubscriptionShared
* @see #setClientId
* @see #setMessageListener
*/
public void setDurableSubscriptionName(@Nullable String durableSubscriptionName) {
this.subscriptionName = durableSubscriptionName;
this.subscriptionDurable = (durableSubscriptionName != null);
}
/**
* Return the name of a durable subscription to create, if any.
*/
@Nullable
public String getDurableSubscriptionName() {
return (this.subscriptionDurable ? this.subscriptionName : null);
}
/**
* Set whether to inhibit the delivery of messages published by its own connection.
* Default is "false".
* @since 4.1
* @see javax.jms.Session#createConsumer(javax.jms.Destination, String, boolean)
*/
public void setPubSubNoLocal(boolean pubSubNoLocal) {
this.pubSubNoLocal = pubSubNoLocal;
}
/**
* Return whether to inhibit the delivery of messages published by its own connection.
* @since 4.1
*/
public boolean isPubSubNoLocal() {
return this.pubSubNoLocal;
}
/**
* Configure the reply destination type. By default, the configured {@code pubSubDomain}
* value is used (see {@link #isPubSubDomain()}.
* <p>This setting primarily indicates what type of destination to resolve if dynamic
* destinations are enabled.
* @param replyPubSubDomain "true" for the Publish/Subscribe domain ({@link Topic Topics}),
* "false" for the Point-to-Point domain ({@link Queue Queues})
* @since 4.2
* @see #setDestinationResolver
*/
public void setReplyPubSubDomain(boolean replyPubSubDomain) {
this.replyPubSubDomain = replyPubSubDomain;
}
/**
* Return whether the Publish/Subscribe domain ({@link javax.jms.Topic Topics}) is used
* for replies. Otherwise, the Point-to-Point domain ({@link javax.jms.Queue Queues})
* is used.
* @since 4.2
*/
@Override
public boolean isReplyPubSubDomain() {
if (this.replyPubSubDomain != null) {
return this.replyPubSubDomain;
} else {
return isPubSubDomain();
}
}
/**
* Configure the {@link QosSettings} to use when sending a reply. Can be set to
* {@code null} to indicate that the broker's defaults should be used.
* @param replyQosSettings the QoS settings to use when sending a reply or {@code null}
* to use the default vas.
* @since 5.0
*/
public void setReplyQosSettings(@Nullable QosSettings replyQosSettings) {
this.replyQosSettings = replyQosSettings;
}
@Override
@Nullable
public QosSettings getReplyQosSettings() {
return this.replyQosSettings;
}
/**
* Set the {@link MessageConverter} strategy for converting JMS Messages.
* @since 4.1
*/
public void setMessageConverter(@Nullable MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
@Override
@Nullable
public MessageConverter getMessageConverter() {
return this.messageConverter;
}
/**
* Set the JMS ExceptionListener to notify in case of a JMSException thrown
* by the registered message listener or the invocation infrastructure.
*/
public void setExceptionListener(@Nullable ExceptionListener exceptionListener) {
this.exceptionListener = exceptionListener;
}
/**
* Return the JMS ExceptionListener to notify in case of a JMSException thrown
* by the registered message listener or the invocation infrastructure, if any.
*/
@Nullable
public ExceptionListener getExceptionListener() {
return this.exceptionListener;
}
/**
* Set the ErrorHandler to be invoked in case of any uncaught exceptions thrown
* while processing a Message.
* <p>By default, there will be <b>no</b> ErrorHandler so that error-level
* logging is the only result.
*/
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Return the ErrorHandler to be invoked in case of any uncaught exceptions thrown
* while processing a Message.
* @since 4.1
*/
@Nullable
public ErrorHandler getErrorHandler() {
return this.errorHandler;
}
/**
* Set whether to expose the listener JMS Session to a registered
* {@link SessionAwareMessageListener} as well as to
* {@link org.springframework.jms.core.JmsTemplate} calls.
* <p>Default is "true", reusing the listener's {@link Session}.
* Turn this off to expose a fresh JMS Session fetched from the same
* underlying JMS {@link Connection} instead, which might be necessary
* on some JMS providers.
* <p>Note that Sessions managed by an external transaction manager will
* always get exposed to {@link org.springframework.jms.core.JmsTemplate}
* calls. So in terms of JmsTemplate exposure, this setting only affects
* locally transacted Sessions.
* @see SessionAwareMessageListener
*/
public void setExposeListenerSession(boolean exposeListenerSession) {
this.exposeListenerSession = exposeListenerSession;
}
/**
* Return whether to expose the listener JMS {@link Session} to a
* registered {@link SessionAwareMessageListener}.
*/
public boolean isExposeListenerSession() {
return this.exposeListenerSession;
}
/**
* Set whether to accept received messages while the listener container
* in the process of stopping.
* <p>Default is "false", rejecting such messages through aborting the
* receive attempt. Switch this flag on to fully process such messages
* even in the stopping phase, with the drawback that even newly sent
* messages might still get processed (if coming in before all receive
* timeouts have expired).
* <p><b>NOTE:</b> Aborting receive attempts for such incoming messages
* might lead to the provider's retry count decreasing for the affected
* messages. If you have a high number of concurrent consumers, make sure
* that the number of retries is higher than the number of consumers,
* to be on the safe side for all potential stopping scenarios.
*/
public void setAcceptMessagesWhileStopping(boolean acceptMessagesWhileStopping) {
this.acceptMessagesWhileStopping = acceptMessagesWhileStopping;
}
/**
* Return whether to accept received messages while the listener container
* in the process of stopping.
*/
public boolean isAcceptMessagesWhileStopping() {
return this.acceptMessagesWhileStopping;
}
@Override
protected void validateConfiguration() {
if (this.destination == null) {
throw new IllegalArgumentException("Property 'destination' or 'destinationName' is required");
}
}
@Override
public void setupMessageListener(Object messageListener) {
setMessageListener(messageListener);
}
// -------------------------------------------------------------------------
// Template methods for listener execution
// -------------------------------------------------------------------------
/**
* Execute the specified listener,
* committing or rolling back the transaction afterwards (if necessary).
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @see #invokeListener
* @see #commitIfNecessary
* @see #rollbackOnExceptionIfNecessary
* @see #handleListenerException
*/
protected void executeListener(Session session, Message message) {
try {
doExecuteListener(session, message);
} catch (Throwable ex) {
handleListenerException(ex);
}
}
/**
* Execute the specified listener,
* committing or rolling back the transaction afterwards (if necessary).
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see #invokeListener
* @see #commitIfNecessary
* @see #rollbackOnExceptionIfNecessary
* @see #convertJmsAccessException
*/
protected void doExecuteListener(Session session, Message message) throws JMSException {
if (!isAcceptMessagesWhileStopping() && !isRunning()) {
if (logger.isWarnEnabled()) {
logger.warn("Rejecting received message because of the listener container " + "having been stopped in the meantime: " + message);
}
rollbackIfNecessary(session);
throw new MessageRejectedWhileStoppingException();
}
try {
invokeListener(session, message);
} catch (JMSException | RuntimeException | Error ex) {
rollbackOnExceptionIfNecessary(session, ex);
throw ex;
}
commitIfNecessary(session, message);
}
/**
* Invoke the specified listener: either as standard JMS MessageListener
* or (preferably) as Spring SessionAwareMessageListener.
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see #setMessageListener
*/
@SuppressWarnings("rawtypes")
protected void invokeListener(Session session, Message message) throws JMSException {
Object listener = getMessageListener();
if (listener instanceof SessionAwareMessageListener) {
doInvokeListener((SessionAwareMessageListener) listener, session, message);
} else if (listener instanceof MessageListener) {
doInvokeListener((MessageListener) listener, message);
} else if (listener != null) {
throw new IllegalArgumentException("Only MessageListener and SessionAwareMessageListener supported: " + listener);
} else {
throw new IllegalStateException("No message listener specified - see property 'messageListener'");
}
}
/**
* Invoke the specified listener as Spring SessionAwareMessageListener,
* exposing a new JMS Session (potentially with its own transaction)
* to the listener if demanded.
* @param listener the Spring SessionAwareMessageListener to invoke
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see SessionAwareMessageListener
* @see #setExposeListenerSession
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void doInvokeListener(SessionAwareMessageListener listener, Session session, Message message) throws JMSException {
Connection conToClose = null;
Session sessionToClose = null;
try {
Session sessionToUse = session;
if (!isExposeListenerSession()) {
// We need to expose a separate Session.
conToClose = createConnection();
sessionToClose = createSession(conToClose);
sessionToUse = sessionToClose;
}
// Actually invoke the message listener...
listener.onMessage(message, sessionToUse);
// Clean up specially exposed Session, if any.
if (sessionToUse != session) {
if (sessionToUse.getTransacted() && isSessionLocallyTransacted(sessionToUse)) {
// Transacted session created by this container -> commit.
JmsUtils.commitIfNecessary(sessionToUse);
}
}
} finally {
JmsUtils.closeSession(sessionToClose);
JmsUtils.closeConnection(conToClose);
}
}
/**
* Invoke the specified listener as standard JMS MessageListener.
* <p>Default implementation performs a plain invocation of the
* {@code onMessage} method.
* @param listener the JMS MessageListener to invoke
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see javax.jms.MessageListener#onMessage
*/
protected void doInvokeListener(MessageListener listener, Message message) throws JMSException {
listener.onMessage(message);
}
/**
* Perform a commit or message acknowledgement, as appropriate.
* @param session the JMS Session to commit
* @param message the Message to acknowledge
* @throws javax.jms.JMSException in case of commit failure
*/
protected void commitIfNecessary(Session session, @Nullable Message message) throws JMSException {
// Commit session or acknowledge message.
if (session.getTransacted()) {
// Commit necessary - but avoid commit call within a JTA transaction.
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> commit.
JmsUtils.commitIfNecessary(session);
}
} else if (message != null && isClientAcknowledge(session)) {
message.acknowledge();
}
}
/**
* Perform a rollback, if appropriate.
* @param session the JMS Session to rollback
* @throws javax.jms.JMSException in case of a rollback error
*/
protected void rollbackIfNecessary(Session session) throws JMSException {
if (session.getTransacted()) {
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> rollback.
JmsUtils.rollbackIfNecessary(session);
}
} else if (isClientAcknowledge(session)) {
session.recover();
}
}
/**
* Perform a rollback, handling rollback exceptions properly.
* @param session the JMS Session to rollback
* @param ex the thrown application exception or error
* @throws javax.jms.JMSException in case of a rollback error
*/
protected void rollbackOnExceptionIfNecessary(Session session, Throwable ex) throws JMSException {
try {
if (session.getTransacted()) {
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> rollback.
if (logger.isDebugEnabled()) {
logger.debug("Initiating transaction rollback on application exception", ex);
}
JmsUtils.rollbackIfNecessary(session);
}
} else if (isClientAcknowledge(session)) {
session.recover();
}
} catch (IllegalStateException ex2) {
logger.debug("Could not roll back because Session already closed", ex2);
} catch (JMSException | RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback error", ex);
throw ex2;
}
}
/**
* Check whether the given Session is locally transacted, that is, whether
* its transaction is managed by this listener container's Session handling
* and not by an external transaction coordinator.
* <p>Note: The Session's own transacted flag will already have been checked
* before. This method is about finding out whether the Session's transaction
* is local or externally coordinated.
* @param session the Session to check
* @return whether the given Session is locally transacted
* @see #isSessionTransacted()
* @see org.springframework.jms.connection.ConnectionFactoryUtils#isSessionTransactional
*/
protected boolean isSessionLocallyTransacted(Session session) {
return isSessionTransacted();
}
/**
* Create a JMS MessageConsumer for the given Session and Destination.
* <p>This implementation uses JMS 1.1 API.
* @param session the JMS Session to create a MessageConsumer for
* @param destination the JMS Destination to create a MessageConsumer for
* @return the new JMS MessageConsumer
* @throws javax.jms.JMSException if thrown by JMS API methods
*/
protected MessageConsumer createConsumer(Session session, Destination destination) throws JMSException {
if (isPubSubDomain() && destination instanceof Topic) {
if (isSubscriptionShared()) {
return (isSubscriptionDurable() ? session.createSharedDurableConsumer((Topic) destination, getSubscriptionName(), getMessageSelector()) : session.createSharedConsumer((Topic) destination, getSubscriptionName(), getMessageSelector()));
} else if (isSubscriptionDurable()) {
return session.createDurableSubscriber((Topic) destination, getSubscriptionName(), getMessageSelector(), isPubSubNoLocal());
} else {
// Only preplaced in the NoLocal flag in case of a Topic (pub-sub mode):
// Some JMS providers, such as WebSphere MQ 6.0, throw IllegalStateException
// in case of the NoLocal flag being specified for a Queue.
return session.createConsumer(destination, getMessageSelector(), isPubSubNoLocal());
}
} else {
return session.createConsumer(destination, getMessageSelector());
}
}
/**
* Handle the given exception that arose during listener execution.
* <p>The default implementation logs the exception at warn level,
* not propagating it to the JMS provider — replaceduming that all handling of
* acknowledgement and/or transactions is done by this listener container.
* This can be overridden in subclreplacedes.
* @param ex the exception to handle
*/
protected void handleListenerException(Throwable ex) {
if (ex instanceof MessageRejectedWhileStoppingException) {
// Internal exception - has been handled before.
return;
}
if (ex instanceof JMSException) {
invokeExceptionListener((JMSException) ex);
}
if (isActive()) {
// Regular case: failed while active.
// Invoke ErrorHandler if available.
invokeErrorHandler(ex);
} else {
// Rare case: listener thread failed after container shutdown.
// Log at debug level, to avoid spamming the shutdown log.
logger.debug("Listener exception after container shutdown", ex);
}
}
/**
* Invoke the registered JMS ExceptionListener, if any.
* @param ex the exception that arose during JMS processing
* @see #setExceptionListener
*/
protected void invokeExceptionListener(JMSException ex) {
ExceptionListener exceptionListener = getExceptionListener();
if (exceptionListener != null) {
exceptionListener.onException(ex);
}
}
/**
* Invoke the registered ErrorHandler, if any. Log at warn level otherwise.
* @param ex the uncaught error that arose during JMS processing.
* @see #setErrorHandler
*/
protected void invokeErrorHandler(Throwable ex) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
errorHandler.handleError(ex);
} else {
logger.warn("Execution of JMS message listener failed, and no ErrorHandler has been set.", ex);
}
}
/**
* Internal exception clreplaced that indicates a rejected message on shutdown.
* Used to trigger a rollback for an external transaction manager in that case.
*/
@SuppressWarnings("serial")
private static clreplaced MessageRejectedWhileStoppingException extends RuntimeException {
}
}
19
View Source File : TaskUtils.java
License : Apache License 2.0
Project Creator : SourceHot
License : Apache License 2.0
Project Creator : SourceHot
/**
* Utility methods for decorating tasks with error handling.
*
* <p><b>NOTE:</b> This clreplaced is intended for internal use by Spring's scheduler
* implementations. It is only public so that it may be accessed from impl clreplacedes
* within other packages. It is <i>not</i> intended for general use.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @since 3.0
*/
public abstract clreplaced TaskUtils {
/**
* An ErrorHandler strategy that will log the Exception but perform
* no further handling. This will suppress the error so that
* subsequent executions of the task will not be prevented.
*/
public static final ErrorHandler LOG_AND_SUPPRESS_ERROR_HANDLER = new LoggingErrorHandler();
/**
* An ErrorHandler strategy that will log at error level and then
* re-throw the Exception. Note: this will typically prevent subsequent
* execution of a scheduled task.
*/
public static final ErrorHandler LOG_AND_PROPAGATE_ERROR_HANDLER = new PropagatingErrorHandler();
/**
* Decorate the task for error handling. If the provided {@link ErrorHandler}
* is not {@code null}, it will be used. Otherwise, repeating tasks will have
* errors suppressed by default whereas one-shot tasks will have errors
* propagated by default since those errors may be expected through the
* returned {@link Future}. In both cases, the errors will be logged.
*/
public static DelegatingErrorHandlingRunnable decorateTaskWithErrorHandler(Runnable task, @Nullable ErrorHandler errorHandler, boolean isRepeatingTask) {
if (task instanceof DelegatingErrorHandlingRunnable) {
return (DelegatingErrorHandlingRunnable) task;
}
ErrorHandler eh = (errorHandler != null ? errorHandler : getDefaultErrorHandler(isRepeatingTask));
return new DelegatingErrorHandlingRunnable(task, eh);
}
/**
* Return the default {@link ErrorHandler} implementation based on the boolean
* value indicating whether the task will be repeating or not. For repeating tasks
* it will suppress errors, but for one-time tasks it will propagate. In both
* cases, the error will be logged.
*/
public static ErrorHandler getDefaultErrorHandler(boolean isRepeatingTask) {
return (isRepeatingTask ? LOG_AND_SUPPRESS_ERROR_HANDLER : LOG_AND_PROPAGATE_ERROR_HANDLER);
}
/**
* An {@link ErrorHandler} implementation that logs the Throwable at error
* level. It does not perform any additional error handling. This can be
* useful when suppression of errors is the intended behavior.
*/
private static clreplaced LoggingErrorHandler implements ErrorHandler {
private final Log logger = LogFactory.getLog(LoggingErrorHandler.clreplaced);
@Override
public void handleError(Throwable t) {
logger.error("Unexpected error occurred in scheduled task", t);
}
}
/**
* An {@link ErrorHandler} implementation that logs the Throwable at error
* level and then propagates it.
*/
private static clreplaced PropagatingErrorHandler extends LoggingErrorHandler {
@Override
public void handleError(Throwable t) {
super.handleError(t);
ReflectionUtils.rethrowRuntimeException(t);
}
}
}
19
View Source File : SimpleApplicationEventMulticaster.java
License : Apache License 2.0
Project Creator : SourceHot
License : Apache License 2.0
Project Creator : SourceHot
/**
* Simple implementation of the {@link ApplicationEventMulticaster} interface.
*
* <p>Multicasts all events to all registered listeners, leaving it up to
* the listeners to ignore events that they are not interested in.
* Listeners will usually perform corresponding {@code instanceof}
* checks on the preplaceded-in event object.
*
* <p>By default, all listeners are invoked in the calling thread.
* This allows the danger of a rogue listener blocking the entire application,
* but adds minimal overhead. Specify an alternative task executor to have
* listeners executed in different threads, for example from a thread pool.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Stephane Nicoll
* @see #setTaskExecutor
*/
public clreplaced SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
@Nullable
private ErrorHandler errorHandler;
/**
* Create a new SimpleApplicationEventMulticaster.
*/
public SimpleApplicationEventMulticaster() {
}
/**
* Create a new SimpleApplicationEventMulticaster for the given BeanFactory.
*/
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
/**
* Set a custom executor (typically a {@link org.springframework.core.task.TaskExecutor})
* to invoke each listener with.
* <p>Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor},
* executing all listeners synchronously in the calling thread.
* <p>Consider specifying an asynchronous task executor here to not block the
* caller until all listeners have been executed. However, note that asynchronous
* execution will not participate in the caller's thread context (clreplaced loader,
* transaction replacedociation) unless the TaskExecutor explicitly supports this.
* @see org.springframework.core.task.SyncTaskExecutor
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
*/
public void setTaskExecutor(@Nullable Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/**
* Return the current task executor for this multicaster.
*/
@Nullable
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
/**
* Set the {@link ErrorHandler} to invoke in case an exception is thrown
* from a listener.
* <p>Default is none, with a listener exception stopping the current
* multicast and getting propagated to the publisher of the current event.
* If a {@linkplain #setTaskExecutor task executor} is specified, each
* individual listener exception will get propagated to the executor but
* won't necessarily stop execution of other listeners.
* <p>Consider setting an {@link ErrorHandler} implementation that catches
* and logs exceptions (a la
* {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_SUPPRESS_ERROR_HANDLER})
* or an implementation that logs exceptions while nevertheless propagating them
* (e.g. {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_PROPAGATE_ERROR_HANDLER}).
* @since 4.1
*/
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Return the current error handler for this multicaster.
* @since 4.1
*/
@Nullable
protected ErrorHandler getErrorHandler() {
return this.errorHandler;
}
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
} else {
invokeListener(listener, event);
}
}
}
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
} catch (ClreplacedCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClreplacedCastMessage(msg, event.getClreplaced())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClreplaced());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
} else {
throw ex;
}
}
}
private boolean matchesClreplacedCastMessage(String clreplacedCastMessage, Clreplaced<?> eventClreplaced) {
// On Java 8, the message starts with the clreplaced name: "java.lang.String cannot be cast..."
if (clreplacedCastMessage.startsWith(eventClreplaced.getName())) {
return true;
}
// On Java 11, the message starts with "clreplaced ..." a.k.a. Clreplaced.toString()
if (clreplacedCastMessage.startsWith(eventClreplaced.toString())) {
return true;
}
// On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."
int moduleSeparatorIndex = clreplacedCastMessage.indexOf('/');
if (moduleSeparatorIndex != -1 && clreplacedCastMessage.startsWith(eventClreplaced.getName(), moduleSeparatorIndex + 1)) {
return true;
}
// replaceduming an unrelated clreplaced cast failure...
return false;
}
}
19
View Source File : EmbeddedZooKeeper.java
License : Apache License 2.0
Project Creator : smallFive55
License : Apache License 2.0
Project Creator : smallFive55
/**
* from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java
* <p>
* Helper clreplaced to start an embedded instance of standalone (non clustered) ZooKeeper.
* <p>
* NOTE: at least an external standalone server (if not an ensemble) are recommended, even for
* org.springframework.xd.dirt.server.singlenode.SingleNodeApplication
*
* @author Patrick Peralta
* @author Mark Fisher
* @author David Turanski
*/
public clreplaced EmbeddedZooKeeper implements SmartLifecycle {
/**
* Logger.
*/
private static final Logger logger = LoggerFactory.getLogger(EmbeddedZooKeeper.clreplaced);
/**
* ZooKeeper client port. This will be determined dynamically upon startup.
*/
private final int clientPort;
/**
* Whether to auto-start. Default is true.
*/
private boolean autoStartup = true;
/**
* Lifecycle phase. Default is 0.
*/
private int phase = 0;
/**
* Thread for running the ZooKeeper server.
*/
private volatile Thread zkServerThread;
/**
* ZooKeeper server.
*/
private volatile ZooKeeperServerMain zkServer;
/**
* {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread.
*/
private ErrorHandler errorHandler;
private boolean daemon = true;
/**
* Construct an EmbeddedZooKeeper with a random port.
*/
public EmbeddedZooKeeper() {
clientPort = SocketUtils.findAvailableTcpPort();
}
/**
* Construct an EmbeddedZooKeeper with the provided port.
*
* @param clientPort port for ZooKeeper server to bind to
*/
public EmbeddedZooKeeper(int clientPort, boolean daemon) {
this.clientPort = clientPort;
this.daemon = daemon;
}
/**
* Returns the port that clients should use to connect to this embedded server.
*
* @return dynamically determined client port
*/
public int getClientPort() {
return this.clientPort;
}
/**
* Specify whether to start automatically. Default is true.
*
* @param autoStartup whether to start automatically
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isAutoStartup() {
return this.autoStartup;
}
/**
* Specify the lifecycle phase for the embedded server.
*
* @param phase the lifecycle phase
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* {@inheritDoc}
*/
@Override
public int getPhase() {
return this.phase;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRunning() {
return (zkServerThread != null);
}
/**
* Start the ZooKeeper server in a background thread.
* <p>
* Register an error handler via {@link #setErrorHandler} in order to handle
* any exceptions thrown during startup or execution.
*/
@Override
public synchronized void start() {
if (zkServerThread == null) {
zkServerThread = new Thread(new ServerRunnable(), "ZooKeeper Server Starter");
zkServerThread.setDaemon(daemon);
zkServerThread.start();
}
}
/**
* Shutdown the ZooKeeper server.
*/
@Override
public synchronized void stop() {
if (zkServerThread != null) {
// The shutdown method is protected...thus this hack to invoke it.
// This will log an exception on shutdown; see
// https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.
try {
Method shutdown = ZooKeeperServerMain.clreplaced.getDeclaredMethod("shutdown");
shutdown.setAccessible(true);
shutdown.invoke(zkServer);
} catch (Exception e) {
throw new RuntimeException(e);
}
// It is expected that the thread will exit after
// the server is shutdown; this will block until
// the shutdown is complete.
try {
zkServerThread.join(5000);
zkServerThread = null;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.warn("Interrupted while waiting for embedded ZooKeeper to exit");
// abandoning zk thread
zkServerThread = null;
}
}
}
/**
* Stop the server if running and invoke the callback when complete.
*/
@Override
public void stop(Runnable callback) {
stop();
callback.run();
}
/**
* Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none
* is provided, only error-level logging will occur.
*
* @param errorHandler the {@link ErrorHandler} to be invoked
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Runnable implementation that starts the ZooKeeper server.
*/
private clreplaced ServerRunnable implements Runnable {
@Override
public void run() {
try {
Properties properties = new Properties();
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID());
file.deleteOnExit();
properties.setProperty("dataDir", file.getAbsolutePath());
properties.setProperty("clientPort", String.valueOf(clientPort));
QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
quorumPeerConfig.parseProperties(properties);
zkServer = new ZooKeeperServerMain();
ServerConfig configuration = new ServerConfig();
configuration.readFrom(quorumPeerConfig);
zkServer.runFromConfig(configuration);
} catch (Exception e) {
if (errorHandler != null) {
errorHandler.handleError(e);
} else {
logger.error("Exception running embedded ZooKeeper", e);
}
}
}
}
}
19
View Source File : EmbeddedZooKeeper.java
License : Apache License 2.0
Project Creator : smallFive55
License : Apache License 2.0
Project Creator : smallFive55
/**
* Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none
* is provided, only error-level logging will occur.
*
* @param errorHandler the {@link ErrorHandler} to be invoked
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
19
View Source File : ProxyWebSocketHandler.java
License : Apache License 2.0
Project Creator : mthizo247
License : Apache License 2.0
Project Creator : mthizo247
/**
* A {@link WebSocketHandlerDecorator} that adds web socket support to zuul reverse proxy.
*
* @author Ronald Mthombeni
* @author Salman Noor
*/
public clreplaced ProxyWebSocketHandler extends WebSocketHandlerDecorator {
private final Logger logger = LoggerFactory.getLogger(ProxyWebSocketHandler.clreplaced);
private final WebSocketHttpHeadersCallback headersCallback;
private final SimpMessagingTemplate messagingTemplate;
private final ProxyTargetResolver proxyTargetResolver;
private final ZuulWebSocketProperties zuulWebSocketProperties;
private final WebSocketStompClient stompClient;
private final Map<WebSocketSession, ProxyWebSocketConnectionManager> managers = new ConcurrentHashMap<>();
private ErrorHandler errorHandler;
public ProxyWebSocketHandler(WebSocketHandler delegate, WebSocketStompClient stompClient, WebSocketHttpHeadersCallback headersCallback, SimpMessagingTemplate messagingTemplate, ProxyTargetResolver proxyTargetResolver, ZuulWebSocketProperties zuulWebSocketProperties) {
super(delegate);
this.stompClient = stompClient;
this.headersCallback = headersCallback;
this.messagingTemplate = messagingTemplate;
this.proxyTargetResolver = proxyTargetResolver;
this.zuulWebSocketProperties = zuulWebSocketProperties;
}
public void errorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
private String getWebSocketServerPath(ZuulWebSocketProperties.WsBrokerage wsBrokerage, URI uri) {
String path = uri.toString();
if (path.contains(":")) {
path = UriComponentsBuilder.fromUriString(path).build().getPath();
}
for (String endPoint : wsBrokerage.getEndPoints()) {
if (PatternMatchUtils.simpleMatch(toPattern(endPoint), path + "/")) {
return endPoint;
}
}
return null;
}
private ZuulWebSocketProperties.WsBrokerage getWebSocketBrokarage(URI uri) {
String path = uri.toString();
if (path.contains(":")) {
path = UriComponentsBuilder.fromUriString(path).build().getPath();
}
for (Map.Entry<String, ZuulWebSocketProperties.WsBrokerage> entry : zuulWebSocketProperties.getBrokerages().entrySet()) {
ZuulWebSocketProperties.WsBrokerage wsBrokerage = entry.getValue();
if (wsBrokerage.isEnabled()) {
for (String endPoint : wsBrokerage.getEndPoints()) {
if (PatternMatchUtils.simpleMatch(toPattern(endPoint), path + "/")) {
return wsBrokerage;
}
}
}
}
return null;
}
private String toPattern(String path) {
path = path.startsWith("/") ? "**" + path : "**/" + path;
return path.endsWith("/") ? path + "**" : path + "/**";
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
disconnectFromProxiedTarget(session);
super.afterConnectionClosed(session, closeStatus);
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
super.handleMessage(session, message);
handleMessageFromClient(session, message);
}
private void handleMessageFromClient(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
boolean handled = false;
WebSocketMessageAccessor accessor = WebSocketMessageAccessor.create(message);
if (StompCommand.SEND.toString().equalsIgnoreCase(accessor.getCommand())) {
handled = true;
sendMessageToProxiedTarget(session, accessor);
}
if (StompCommand.SUBSCRIBE.toString().equalsIgnoreCase(accessor.getCommand())) {
handled = true;
subscribeToProxiedTarget(session, accessor);
}
if (StompCommand.UNSUBSCRIBE.toString().equalsIgnoreCase(accessor.getCommand())) {
handled = true;
unsubscribeFromProxiedTarget(session, accessor);
}
if (StompCommand.CONNECT.toString().equalsIgnoreCase(accessor.getCommand())) {
handled = true;
connectToProxiedTarget(session);
}
if (!handled) {
if (logger.isDebugEnabled()) {
logger.debug("STOMP COMMAND " + accessor.getCommand() + " was not explicitly handled");
}
}
}
private void connectToProxiedTarget(WebSocketSession session) {
URI sessionUri = session.getUri();
ZuulWebSocketProperties.WsBrokerage wsBrokerage = getWebSocketBrokarage(sessionUri);
replacedert.notNull(wsBrokerage, "wsBrokerage must not be null");
String path = getWebSocketServerPath(wsBrokerage, sessionUri);
replacedert.notNull(path, "Web socket uri path must be null");
URI routeTarget = proxyTargetResolver.resolveTarget(wsBrokerage);
replacedert.notNull(routeTarget, "routeTarget must not be null");
String uri = ServletUriComponentsBuilder.fromUri(routeTarget).path(path).replaceQuery(sessionUri.getQuery()).toUriString();
ProxyWebSocketConnectionManager connectionManager = new ProxyWebSocketConnectionManager(messagingTemplate, stompClient, session, headersCallback, uri);
connectionManager.errorHandler(this.errorHandler);
managers.put(session, connectionManager);
connectionManager.start();
}
private void disconnectFromProxiedTarget(WebSocketSession session) {
disconnectProxyManager(managers.remove(session));
}
private void disconnectProxyManager(ProxyWebSocketConnectionManager proxyManager) {
if (proxyManager != null) {
try {
proxyManager.disconnect();
} catch (Throwable ignored) {
// nothing
}
}
}
private void unsubscribeFromProxiedTarget(WebSocketSession session, WebSocketMessageAccessor accessor) {
ProxyWebSocketConnectionManager manager = managers.get(session);
if (manager != null) {
manager.unsubscribe(accessor.getDestination());
}
}
private void sendMessageToProxiedTarget(WebSocketSession session, WebSocketMessageAccessor accessor) {
ProxyWebSocketConnectionManager manager = managers.get(session);
manager.sendMessage(accessor.getDestination(), accessor.getPayload());
}
private void subscribeToProxiedTarget(WebSocketSession session, WebSocketMessageAccessor accessor) throws Exception {
ProxyWebSocketConnectionManager manager = managers.get(session);
manager.subscribe(accessor.getDestination());
}
}
19
View Source File : ProxyWebSocketHandler.java
License : Apache License 2.0
Project Creator : mthizo247
License : Apache License 2.0
Project Creator : mthizo247
public void errorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
19
View Source File : SimpleApplicationEventMulticaster.java
License : MIT License
Project Creator : mindcarver
License : MIT License
Project Creator : mindcarver
/**
* Simple implementation of the {@link ApplicationEventMulticaster} interface.
*
* <p>Multicasts all events to all registered listeners, leaving it up to
* the listeners to ignore events that they are not interested in.
* Listeners will usually perform corresponding {@code instanceof}
* checks on the preplaceded-in event object.
*
* <p>By default, all listeners are invoked in the calling thread.
* This allows the danger of a rogue listener blocking the entire application,
* but adds minimal overhead. Specify an alternative task executor to have
* listeners executed in different threads, for example from a thread pool.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Stephane Nicoll
* @see #setTaskExecutor
*/
public clreplaced SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
@Nullable
private ErrorHandler errorHandler;
/**
* Create a new SimpleApplicationEventMulticaster.
*/
public SimpleApplicationEventMulticaster() {
}
/**
* Create a new SimpleApplicationEventMulticaster for the given BeanFactory.
*/
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
/**
* Set a custom executor (typically a {@link org.springframework.core.task.TaskExecutor})
* to invoke each listener with.
* <p>Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor},
* executing all listeners synchronously in the calling thread.
* <p>Consider specifying an asynchronous task executor here to not block the
* caller until all listeners have been executed. However, note that asynchronous
* execution will not participate in the caller's thread context (clreplaced loader,
* transaction replacedociation) unless the TaskExecutor explicitly supports this.
* @see org.springframework.core.task.SyncTaskExecutor
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
*/
public void setTaskExecutor(@Nullable Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/**
* Return the current task executor for this multicaster.
*/
@Nullable
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
/**
* Set the {@link ErrorHandler} to invoke in case an exception is thrown
* from a listener.
* <p>Default is none, with a listener exception stopping the current
* multicast and getting propagated to the publisher of the current event.
* If a {@linkplain #setTaskExecutor task executor} is specified, each
* individual listener exception will get propagated to the executor but
* won't necessarily stop execution of other listeners.
* <p>Consider setting an {@link ErrorHandler} implementation that catches
* and logs exceptions (a la
* {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_SUPPRESS_ERROR_HANDLER})
* or an implementation that logs exceptions while nevertheless propagating them
* (e.g. {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_PROPAGATE_ERROR_HANDLER}).
* @since 4.1
*/
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Return the current error handler for this multicaster.
* @since 4.1
*/
@Nullable
protected ErrorHandler getErrorHandler() {
return this.errorHandler;
}
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
} else {
invokeListener(listener, event);
}
}
}
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
} catch (ClreplacedCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClreplacedCastMessage(msg, event.getClreplaced())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClreplaced());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
} else {
throw ex;
}
}
}
private boolean matchesClreplacedCastMessage(String clreplacedCastMessage, Clreplaced<?> eventClreplaced) {
// On Java 8, the message starts with the clreplaced name: "java.lang.String cannot be cast..."
if (clreplacedCastMessage.startsWith(eventClreplaced.getName())) {
return true;
}
// On Java 11, the message starts with "clreplaced ..." a.k.a. Clreplaced.toString()
if (clreplacedCastMessage.startsWith(eventClreplaced.toString())) {
return true;
}
// On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."
int moduleSeparatorIndex = clreplacedCastMessage.indexOf('/');
if (moduleSeparatorIndex != -1 && clreplacedCastMessage.startsWith(eventClreplaced.getName(), moduleSeparatorIndex + 1)) {
return true;
}
// replaceduming an unrelated clreplaced cast failure...
return false;
}
}
19
View Source File : SimpleMessageListenerContainerTests.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
@Test
public void testRegisteredErrorHandlerIsInvokedOnException() throws Exception {
final SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer();
Session session = mock(Session.clreplaced);
// Queue gets created in order to create MessageConsumer for that Destination...
given(session.createQueue(DESTINATION_NAME)).willReturn(QUEUE_DESTINATION);
// and then the MessageConsumer gets created...
// no MessageSelector...
given(session.createConsumer(QUEUE_DESTINATION, null)).willReturn(messageConsumer);
// an exception is thrown, so the rollback logic is being applied here...
given(session.getTransacted()).willReturn(false);
Connection connection = mock(Connection.clreplaced);
// session gets created in order to register MessageListener...
given(connection.createSession(this.container.isSessionTransacted(), this.container.getSessionAcknowledgeMode())).willReturn(session);
ConnectionFactory connectionFactory = mock(ConnectionFactory.clreplaced);
given(connectionFactory.createConnection()).willReturn(connection);
final IllegalStateException theException = new IllegalStateException("intentional test failure");
this.container.setConnectionFactory(connectionFactory);
this.container.setDestinationName(DESTINATION_NAME);
this.container.setMessageListener(new SessionAwareMessageListener<Message>() {
@Override
public void onMessage(Message message, Session session) throws JMSException {
throw theException;
}
});
ErrorHandler errorHandler = mock(ErrorHandler.clreplaced);
this.container.setErrorHandler(errorHandler);
this.container.afterPropertiesSet();
this.container.start();
// manually trigger an Exception with the above bad MessageListener...
Message message = mock(Message.clreplaced);
// a Throwable from a MessageListener MUST simply be swallowed...
messageConsumer.sendMessage(message);
verify(connection).setExceptionListener(this.container);
verify(connection).start();
verify(errorHandler).handleError(theException);
}
19
View Source File : AbstractMessageListenerContainer.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Abstract base clreplaced for Spring message listener container implementations.
* Can either host a standard JMS {@link javax.jms.MessageListener} or Spring's
* {@link SessionAwareMessageListener} for actual message processing.
*
* <p>Usually holds a single JMS {@link Connection} that all listeners are supposed
* to be registered on, which is the standard JMS way of managing listener sessions.
* Can alternatively also be used with a fresh Connection per listener, for Java EE
* style XA-aware JMS messaging. The actual registration process is up to concrete
* subclreplacedes.
*
* <p><b>NOTE:</b> The default behavior of this message listener container is to
* <b>never</b> propagate an exception thrown by a message listener up to the JMS
* provider. Instead, it will log any such exception at the error level.
* This means that from the perspective of the attendant JMS provider no such
* listener will ever fail. However, if error handling is necessary, then
* any implementation of the {@link ErrorHandler} strategy may be provided to
* the {@link #setErrorHandler(ErrorHandler)} method. Note that JMSExceptions
* <b>will</b> be preplaceded to the ErrorHandler in addition to (but after) being
* preplaceded to an {@link ExceptionListener}, if one has been provided.
*
* <p>The listener container offers the following message acknowledgment options:
* <ul>
* <li>"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default):
* This mode is container-dependent: For {@link DefaultMessageListenerContainer},
* it means automatic message acknowledgment <i>before</i> listener execution, with
* no redelivery in case of an exception and no redelivery in case of other listener
* execution interruptions either. For {@link SimpleMessageListenerContainer},
* it means automatic message acknowledgment <i>after</i> listener execution, with
* no redelivery in case of a user exception thrown but potential redelivery in case
* of the JVM dying during listener execution. In order to consistently arrange for
* redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
* preferably - setting "sessionTransacted" to "true" instead.
* <li>"sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE":
* <i>Lazy</i> message acknowledgment during ({@link DefaultMessageListenerContainer})
* or shortly after ({@link SimpleMessageListenerContainer}) listener execution;
* no redelivery in case of a user exception thrown but potential redelivery in case
* of the JVM dying during listener execution. In order to consistently arrange for
* redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
* preferably - setting "sessionTransacted" to "true" instead.
* <li>"sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE":
* Automatic message acknowledgment <i>after</i> successful listener execution;
* best-effort redelivery in case of a user exception thrown as well as in case
* of other listener execution interruptions (such as the JVM dying).
* <li>"sessionTransacted" set to "true":
* Transactional acknowledgment after successful listener execution;
* <i>guaranteed redelivery</i> in case of a user exception thrown as well as
* in case of other listener execution interruptions (such as the JVM dying).
* </ul>
*
* <p>There are two solutions to the duplicate message processing problem:
* <ul>
* <li>Either add <i>duplicate message detection</i> to your listener, in the
* form of a business enreplacedy existence check or a protocol table check. This
* usually just needs to be done in case of the JMSRedelivered flag being
* set on the incoming message (otherwise just process straightforwardly).
* Note that with "sessionTransacted" set to "true", duplicate messages will
* only appear in case of the JVM dying at the most unfortunate point possible
* (i.e. after your business logic executed but before the JMS part got committed),
* so duplicate message detection is just there to cover a corner case.
* <li>Or wrap your <i>entire processing with an XA transaction</i>, covering the
* reception of the JMS message as well as the execution of the business logic in
* your message listener (including database operations etc). This is only
* supported by {@link DefaultMessageListenerContainer}, through specifying
* an external "transactionManager" (typically a
* {@link org.springframework.transaction.jta.JtaTransactionManager}, with
* a corresponding XA-aware JMS {@link javax.jms.ConnectionFactory} preplaceded in
* as "connectionFactory").
* </ul>
* Note that XA transaction coordination adds significant runtime overhead,
* so it might be feasible to avoid it unless absolutely necessary.
*
* <p><b>Recommendations:</b>
* <ul>
* <li>The general recommendation is to set "sessionTransacted" to "true",
* typically in combination with local database transactions triggered by the
* listener implementation, through Spring's standard transaction facilities.
* This will work nicely in Tomcat or in a standalone environment, often
* combined with custom duplicate message detection (if it is unacceptable
* to ever process the same message twice).
* <li>Alternatively, specify a
* {@link org.springframework.transaction.jta.JtaTransactionManager} as
* "transactionManager" for a fully XA-aware JMS provider - typically when
* running on a Java EE server, but also for other environments with a JTA
* transaction manager present. This will give full "exactly-once" guarantees
* without custom duplicate message checks, at the price of additional
* runtime processing overhead.
* </ul>
*
* <p>Note that the "sessionTransacted" flag is strongly recommended over
* {@link org.springframework.jms.connection.JmsTransactionManager}, provided
* that transactions do not need to be managed externally. As a consequence,
* set the transaction manager only if you are using JTA or if you need to
* synchronize with custom external transaction arrangements.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 2.0
* @see #setMessageListener
* @see javax.jms.MessageListener
* @see SessionAwareMessageListener
* @see #handleListenerException
* @see DefaultMessageListenerContainer
* @see SimpleMessageListenerContainer
* @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
*/
public abstract clreplaced AbstractMessageListenerContainer extends AbstractJmsListeningContainer implements MessageListenerContainer {
/**
* The JMS 2.0 Session.createSharedConsumer method, if available
*/
private static final Method createSharedConsumerMethod = ClreplacedUtils.getMethodIfAvailable(Session.clreplaced, "createSharedConsumer", Topic.clreplaced, String.clreplaced, String.clreplaced);
/**
* The JMS 2.0 Session.createSharedDurableConsumer method, if available
*/
private static final Method createSharedDurableConsumerMethod = ClreplacedUtils.getMethodIfAvailable(Session.clreplaced, "createSharedDurableConsumer", Topic.clreplaced, String.clreplaced, String.clreplaced);
private volatile Object destination;
private volatile String messageSelector;
private volatile Object messageListener;
private boolean subscriptionDurable = false;
private boolean subscriptionShared = false;
private String subscriptionName;
private Boolean replyPubSubDomain;
private boolean pubSubNoLocal = false;
private MessageConverter messageConverter;
private ExceptionListener exceptionListener;
private ErrorHandler errorHandler;
private boolean exposeListenerSession = true;
private boolean acceptMessagesWhileStopping = false;
/**
* Specify concurrency limits.
*/
public abstract void setConcurrency(String concurrency);
/**
* Set the destination to receive messages from.
* <p>Alternatively, specify a "destinationName", to be dynamically
* resolved via the {@link org.springframework.jms.support.destination.DestinationResolver}.
* <p>Note: The destination may be replaced at runtime, with the listener
* container picking up the new destination immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
* @see #setDestinationName(String)
*/
public void setDestination(Destination destination) {
replacedert.notNull(destination, "'destination' must not be null");
this.destination = destination;
if (destination instanceof Topic && !(destination instanceof Queue)) {
// Clearly a Topic: let's set the "pubSubDomain" flag accordingly.
setPubSubDomain(true);
}
}
/**
* Return the destination to receive messages from. Will be {@code null}
* if the configured destination is not an actual {@link Destination} type;
* c.f. {@link #setDestinationName(String) when the destination is a String}.
*/
public Destination getDestination() {
return (this.destination instanceof Destination ? (Destination) this.destination : null);
}
/**
* Set the name of the destination to receive messages from.
* <p>The specified name will be dynamically resolved via the configured
* {@link #setDestinationResolver destination resolver}.
* <p>Alternatively, specify a JMS {@link Destination} object as "destination".
* <p>Note: The destination may be replaced at runtime, with the listener
* container picking up the new destination immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
* @param destinationName the desired destination (can be {@code null})
* @see #setDestination(javax.jms.Destination)
*/
public void setDestinationName(String destinationName) {
replacedert.notNull(destinationName, "'destinationName' must not be null");
this.destination = destinationName;
}
/**
* Return the name of the destination to receive messages from.
* Will be {@code null} if the configured destination is not a
* {@link String} type; c.f. {@link #setDestination(Destination) when
* it is an actual Destination}.
*/
public String getDestinationName() {
return (this.destination instanceof String ? (String) this.destination : null);
}
/**
* Return a descriptive String for this container's JMS destination
* (never {@code null}).
*/
protected String getDestinationDescription() {
return this.destination.toString();
}
/**
* Set the JMS message selector expression (or {@code null} if none).
* Default is none.
* <p>See the JMS specification for a detailed definition of selector expressions.
* <p>Note: The message selector may be replaced at runtime, with the listener
* container picking up the new selector value immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
*/
public void setMessageSelector(String messageSelector) {
this.messageSelector = messageSelector;
}
/**
* Return the JMS message selector expression (or {@code null} if none).
*/
public String getMessageSelector() {
return this.messageSelector;
}
/**
* Set the message listener implementation to register.
* This can be either a standard JMS {@link MessageListener} object
* or a Spring {@link SessionAwareMessageListener} object.
* <p>Note: The message listener may be replaced at runtime, with the listener
* container picking up the new listener object immediately (works e.g. with
* DefaultMessageListenerContainer, as long as the cache level is less than
* CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
* @throws IllegalArgumentException if the supplied listener is not a
* {@link MessageListener} or a {@link SessionAwareMessageListener}
* @see javax.jms.MessageListener
* @see SessionAwareMessageListener
*/
public void setMessageListener(Object messageListener) {
checkMessageListener(messageListener);
this.messageListener = messageListener;
if (this.subscriptionName == null) {
this.subscriptionName = getDefaultSubscriptionName(messageListener);
}
}
/**
* Return the message listener object to register.
*/
public Object getMessageListener() {
return this.messageListener;
}
/**
* Check the given message listener, throwing an exception
* if it does not correspond to a supported listener type.
* <p>By default, only a standard JMS {@link MessageListener} object or a
* Spring {@link SessionAwareMessageListener} object will be accepted.
* @param messageListener the message listener object to check
* @throws IllegalArgumentException if the supplied listener is not a
* {@link MessageListener} or a {@link SessionAwareMessageListener}
* @see javax.jms.MessageListener
* @see SessionAwareMessageListener
*/
protected void checkMessageListener(Object messageListener) {
if (!(messageListener instanceof MessageListener || messageListener instanceof SessionAwareMessageListener)) {
throw new IllegalArgumentException("Message listener needs to be of type [" + MessageListener.clreplaced.getName() + "] or [" + SessionAwareMessageListener.clreplaced.getName() + "]");
}
}
/**
* Determine the default subscription name for the given message listener.
* @param messageListener the message listener object to check
* @return the default subscription name
* @see SubscriptionNameProvider
*/
protected String getDefaultSubscriptionName(Object messageListener) {
if (messageListener instanceof SubscriptionNameProvider) {
return ((SubscriptionNameProvider) messageListener).getSubscriptionName();
} else {
return messageListener.getClreplaced().getName();
}
}
/**
* Set whether to make the subscription durable. The durable subscription name
* to be used can be specified through the "subscriptionName" property.
* <p>Default is "false". Set this to "true" to register a durable subscription,
* typically in combination with a "subscriptionName" value (unless
* your message listener clreplaced name is good enough as subscription name).
* <p>Only makes sense when listening to a topic (pub-sub domain),
* therefore this method switches the "pubSubDomain" flag as well.
* @see #setSubscriptionName
* @see #setPubSubDomain
*/
public void setSubscriptionDurable(boolean subscriptionDurable) {
this.subscriptionDurable = subscriptionDurable;
if (subscriptionDurable) {
setPubSubDomain(true);
}
}
/**
* Return whether to make the subscription durable.
*/
public boolean isSubscriptionDurable() {
return this.subscriptionDurable;
}
/**
* Set whether to make the subscription shared. The shared subscription name
* to be used can be specified through the "subscriptionName" property.
* <p>Default is "false". Set this to "true" to register a shared subscription,
* typically in combination with a "subscriptionName" value (unless
* your message listener clreplaced name is good enough as subscription name).
* Note that shared subscriptions may also be durable, so this flag can
* (and often will) be combined with "subscriptionDurable" as well.
* <p>Only makes sense when listening to a topic (pub-sub domain),
* therefore this method switches the "pubSubDomain" flag as well.
* <p><b>Requires a JMS 2.0 compatible message broker.</b>
* @since 4.1
* @see #setSubscriptionName
* @see #setSubscriptionDurable
* @see #setPubSubDomain
*/
public void setSubscriptionShared(boolean subscriptionShared) {
this.subscriptionShared = subscriptionShared;
if (subscriptionShared) {
setPubSubDomain(true);
}
}
/**
* Return whether to make the subscription shared.
* @since 4.1
*/
public boolean isSubscriptionShared() {
return this.subscriptionShared;
}
/**
* Set the name of a subscription to create. To be applied in case
* of a topic (pub-sub domain) with a shared or durable subscription.
* <p>The subscription name needs to be unique within this client's
* JMS client id. Default is the clreplaced name of the specified message listener.
* <p>Note: Only 1 concurrent consumer (which is the default of this
* message listener container) is allowed for each subscription,
* except for a shared subscription (which requires JMS 2.0).
* @since 4.1
* @see #setPubSubDomain
* @see #setSubscriptionDurable
* @see #setSubscriptionShared
* @see #setClientId
* @see #setMessageListener
*/
public void setSubscriptionName(String subscriptionName) {
this.subscriptionName = subscriptionName;
}
/**
* Return the name of a subscription to create, if any.
* @since 4.1
*/
public String getSubscriptionName() {
return this.subscriptionName;
}
/**
* Set the name of a durable subscription to create. This method switches
* to pub-sub domain mode and activates subscription durability as well.
* <p>The durable subscription name needs to be unique within this client's
* JMS client id. Default is the clreplaced name of the specified message listener.
* <p>Note: Only 1 concurrent consumer (which is the default of this
* message listener container) is allowed for each durable subscription,
* except for a shared durable subscription (which requires JMS 2.0).
* @see #setPubSubDomain
* @see #setSubscriptionDurable
* @see #setSubscriptionShared
* @see #setClientId
* @see #setMessageListener
*/
public void setDurableSubscriptionName(String durableSubscriptionName) {
this.subscriptionName = durableSubscriptionName;
this.subscriptionDurable = true;
}
/**
* Return the name of a durable subscription to create, if any.
*/
public String getDurableSubscriptionName() {
return (this.subscriptionDurable ? this.subscriptionName : null);
}
/**
* Set whether to inhibit the delivery of messages published by its own connection.
* Default is "false".
* @since 4.1
* @see javax.jms.Session#createConsumer(javax.jms.Destination, String, boolean)
*/
public void setPubSubNoLocal(boolean pubSubNoLocal) {
this.pubSubNoLocal = pubSubNoLocal;
}
/**
* Return whether to inhibit the delivery of messages published by its own connection.
* @since 4.1
*/
public boolean isPubSubNoLocal() {
return this.pubSubNoLocal;
}
/**
* Configure the reply destination type. By default, the configured {@code pubSubDomain}
* value is used (see {@link #isPubSubDomain()}.
* <p>This setting primarily indicates what type of destination to resolve if dynamic
* destinations are enabled.
* @param replyPubSubDomain "true" for the Publish/Subscribe domain ({@link Topic Topics}),
* "false" for the Point-to-Point domain ({@link Queue Queues})
* @since 4.2
* @see #setDestinationResolver
*/
public void setReplyPubSubDomain(boolean replyPubSubDomain) {
this.replyPubSubDomain = replyPubSubDomain;
}
/**
* Return whether the Publish/Subscribe domain ({@link javax.jms.Topic Topics}) is used
* for replies. Otherwise, the Point-to-Point domain ({@link javax.jms.Queue Queues})
* is used.
* @since 4.2
*/
@Override
public boolean isReplyPubSubDomain() {
if (this.replyPubSubDomain != null) {
return replyPubSubDomain;
} else {
return isPubSubDomain();
}
}
/**
* Set the {@link MessageConverter} strategy for converting JMS Messages.
* @since 4.1
*/
public void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
@Override
public MessageConverter getMessageConverter() {
return this.messageConverter;
}
/**
* Set the JMS ExceptionListener to notify in case of a JMSException thrown
* by the registered message listener or the invocation infrastructure.
*/
public void setExceptionListener(ExceptionListener exceptionListener) {
this.exceptionListener = exceptionListener;
}
/**
* Return the JMS ExceptionListener to notify in case of a JMSException thrown
* by the registered message listener or the invocation infrastructure, if any.
*/
public ExceptionListener getExceptionListener() {
return this.exceptionListener;
}
/**
* Set the ErrorHandler to be invoked in case of any uncaught exceptions thrown
* while processing a Message.
* <p>By default, there will be <b>no</b> ErrorHandler so that error-level
* logging is the only result.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Return the ErrorHandler to be invoked in case of any uncaught exceptions thrown
* while processing a Message.
* @since 4.1
*/
public ErrorHandler getErrorHandler() {
return this.errorHandler;
}
/**
* Set whether to expose the listener JMS Session to a registered
* {@link SessionAwareMessageListener} as well as to
* {@link org.springframework.jms.core.JmsTemplate} calls.
* <p>Default is "true", reusing the listener's {@link Session}.
* Turn this off to expose a fresh JMS Session fetched from the same
* underlying JMS {@link Connection} instead, which might be necessary
* on some JMS providers.
* <p>Note that Sessions managed by an external transaction manager will
* always get exposed to {@link org.springframework.jms.core.JmsTemplate}
* calls. So in terms of JmsTemplate exposure, this setting only affects
* locally transacted Sessions.
* @see SessionAwareMessageListener
*/
public void setExposeListenerSession(boolean exposeListenerSession) {
this.exposeListenerSession = exposeListenerSession;
}
/**
* Return whether to expose the listener JMS {@link Session} to a
* registered {@link SessionAwareMessageListener}.
*/
public boolean isExposeListenerSession() {
return this.exposeListenerSession;
}
/**
* Set whether to accept received messages while the listener container
* in the process of stopping.
* <p>Default is "false", rejecting such messages through aborting the
* receive attempt. Switch this flag on to fully process such messages
* even in the stopping phase, with the drawback that even newly sent
* messages might still get processed (if coming in before all receive
* timeouts have expired).
* <p><b>NOTE:</b> Aborting receive attempts for such incoming messages
* might lead to the provider's retry count decreasing for the affected
* messages. If you have a high number of concurrent consumers, make sure
* that the number of retries is higher than the number of consumers,
* to be on the safe side for all potential stopping scenarios.
*/
public void setAcceptMessagesWhileStopping(boolean acceptMessagesWhileStopping) {
this.acceptMessagesWhileStopping = acceptMessagesWhileStopping;
}
/**
* Return whether to accept received messages while the listener container
* in the process of stopping.
*/
public boolean isAcceptMessagesWhileStopping() {
return this.acceptMessagesWhileStopping;
}
@Override
protected void validateConfiguration() {
if (this.destination == null) {
throw new IllegalArgumentException("Property 'destination' or 'destinationName' is required");
}
}
@Override
public void setupMessageListener(Object messageListener) {
setMessageListener(messageListener);
}
// -------------------------------------------------------------------------
// Template methods for listener execution
// -------------------------------------------------------------------------
/**
* Execute the specified listener,
* committing or rolling back the transaction afterwards (if necessary).
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @see #invokeListener
* @see #commitIfNecessary
* @see #rollbackOnExceptionIfNecessary
* @see #handleListenerException
*/
protected void executeListener(Session session, Message message) {
try {
doExecuteListener(session, message);
} catch (Throwable ex) {
handleListenerException(ex);
}
}
/**
* Execute the specified listener,
* committing or rolling back the transaction afterwards (if necessary).
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see #invokeListener
* @see #commitIfNecessary
* @see #rollbackOnExceptionIfNecessary
* @see #convertJmsAccessException
*/
protected void doExecuteListener(Session session, Message message) throws JMSException {
if (!isAcceptMessagesWhileStopping() && !isRunning()) {
if (logger.isWarnEnabled()) {
logger.warn("Rejecting received message because of the listener container " + "having been stopped in the meantime: " + message);
}
rollbackIfNecessary(session);
throw new MessageRejectedWhileStoppingException();
}
try {
invokeListener(session, message);
} catch (JMSException ex) {
rollbackOnExceptionIfNecessary(session, ex);
throw ex;
} catch (RuntimeException ex) {
rollbackOnExceptionIfNecessary(session, ex);
throw ex;
} catch (Error err) {
rollbackOnExceptionIfNecessary(session, err);
throw err;
}
commitIfNecessary(session, message);
}
/**
* Invoke the specified listener: either as standard JMS MessageListener
* or (preferably) as Spring SessionAwareMessageListener.
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see #setMessageListener
*/
@SuppressWarnings("rawtypes")
protected void invokeListener(Session session, Message message) throws JMSException {
Object listener = getMessageListener();
if (listener instanceof SessionAwareMessageListener) {
doInvokeListener((SessionAwareMessageListener) listener, session, message);
} else if (listener instanceof MessageListener) {
doInvokeListener((MessageListener) listener, message);
} else if (listener != null) {
throw new IllegalArgumentException("Only MessageListener and SessionAwareMessageListener supported: " + listener);
} else {
throw new IllegalStateException("No message listener specified - see property 'messageListener'");
}
}
/**
* Invoke the specified listener as Spring SessionAwareMessageListener,
* exposing a new JMS Session (potentially with its own transaction)
* to the listener if demanded.
* @param listener the Spring SessionAwareMessageListener to invoke
* @param session the JMS Session to operate on
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see SessionAwareMessageListener
* @see #setExposeListenerSession
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void doInvokeListener(SessionAwareMessageListener listener, Session session, Message message) throws JMSException {
Connection conToClose = null;
Session sessionToClose = null;
try {
Session sessionToUse = session;
if (!isExposeListenerSession()) {
// We need to expose a separate Session.
conToClose = createConnection();
sessionToClose = createSession(conToClose);
sessionToUse = sessionToClose;
}
// Actually invoke the message listener...
listener.onMessage(message, sessionToUse);
// Clean up specially exposed Session, if any.
if (sessionToUse != session) {
if (sessionToUse.getTransacted() && isSessionLocallyTransacted(sessionToUse)) {
// Transacted session created by this container -> commit.
JmsUtils.commitIfNecessary(sessionToUse);
}
}
} finally {
JmsUtils.closeSession(sessionToClose);
JmsUtils.closeConnection(conToClose);
}
}
/**
* Invoke the specified listener as standard JMS MessageListener.
* <p>Default implementation performs a plain invocation of the
* {@code onMessage} method.
* @param listener the JMS MessageListener to invoke
* @param message the received JMS Message
* @throws JMSException if thrown by JMS API methods
* @see javax.jms.MessageListener#onMessage
*/
protected void doInvokeListener(MessageListener listener, Message message) throws JMSException {
listener.onMessage(message);
}
/**
* Perform a commit or message acknowledgement, as appropriate.
* @param session the JMS Session to commit
* @param message the Message to acknowledge
* @throws javax.jms.JMSException in case of commit failure
*/
protected void commitIfNecessary(Session session, Message message) throws JMSException {
// Commit session or acknowledge message.
if (session.getTransacted()) {
// Commit necessary - but avoid commit call within a JTA transaction.
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> commit.
JmsUtils.commitIfNecessary(session);
}
} else if (message != null && isClientAcknowledge(session)) {
message.acknowledge();
}
}
/**
* Perform a rollback, if appropriate.
* @param session the JMS Session to rollback
* @throws javax.jms.JMSException in case of a rollback error
*/
protected void rollbackIfNecessary(Session session) throws JMSException {
if (session.getTransacted()) {
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> rollback.
JmsUtils.rollbackIfNecessary(session);
}
} else if (isClientAcknowledge(session)) {
session.recover();
}
}
/**
* Perform a rollback, handling rollback exceptions properly.
* @param session the JMS Session to rollback
* @param ex the thrown application exception or error
* @throws javax.jms.JMSException in case of a rollback error
*/
protected void rollbackOnExceptionIfNecessary(Session session, Throwable ex) throws JMSException {
try {
if (session.getTransacted()) {
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this container -> rollback.
if (logger.isDebugEnabled()) {
logger.debug("Initiating transaction rollback on application exception", ex);
}
JmsUtils.rollbackIfNecessary(session);
}
} else if (isClientAcknowledge(session)) {
session.recover();
}
} catch (IllegalStateException ex2) {
logger.debug("Could not roll back because Session already closed", ex2);
} catch (JMSException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
} catch (RuntimeException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
} catch (Error err) {
logger.error("Application exception overridden by rollback error", ex);
throw err;
}
}
/**
* Check whether the given Session is locally transacted, that is, whether
* its transaction is managed by this listener container's Session handling
* and not by an external transaction coordinator.
* <p>Note: The Session's own transacted flag will already have been checked
* before. This method is about finding out whether the Session's transaction
* is local or externally coordinated.
* @param session the Session to check
* @return whether the given Session is locally transacted
* @see #isSessionTransacted()
* @see org.springframework.jms.connection.ConnectionFactoryUtils#isSessionTransactional
*/
protected boolean isSessionLocallyTransacted(Session session) {
return isSessionTransacted();
}
/**
* Create a JMS MessageConsumer for the given Session and Destination.
* <p>This implementation uses JMS 1.1 API.
* @param session the JMS Session to create a MessageConsumer for
* @param destination the JMS Destination to create a MessageConsumer for
* @return the new JMS MessageConsumer
* @throws javax.jms.JMSException if thrown by JMS API methods
*/
protected MessageConsumer createConsumer(Session session, Destination destination) throws JMSException {
if (isPubSubDomain() && destination instanceof Topic) {
if (isSubscriptionShared()) {
// createSharedConsumer((Topic) dest, subscription, selector);
// createSharedDurableConsumer((Topic) dest, subscription, selector);
Method method = (isSubscriptionDurable() ? createSharedDurableConsumerMethod : createSharedConsumerMethod);
try {
return (MessageConsumer) method.invoke(session, destination, getSubscriptionName(), getMessageSelector());
} catch (InvocationTargetException ex) {
if (ex.getTargetException() instanceof JMSException) {
throw (JMSException) ex.getTargetException();
}
ReflectionUtils.handleInvocationTargetException(ex);
return null;
} catch (IllegalAccessException ex) {
throw new IllegalStateException("Could not access JMS 2.0 API method: " + ex.getMessage());
}
} else if (isSubscriptionDurable()) {
return session.createDurableSubscriber((Topic) destination, getSubscriptionName(), getMessageSelector(), isPubSubNoLocal());
} else {
// Only preplaced in the NoLocal flag in case of a Topic (pub-sub mode):
// Some JMS providers, such as WebSphere MQ 6.0, throw IllegalStateException
// in case of the NoLocal flag being specified for a Queue.
return session.createConsumer(destination, getMessageSelector(), isPubSubNoLocal());
}
} else {
return session.createConsumer(destination, getMessageSelector());
}
}
/**
* Handle the given exception that arose during listener execution.
* <p>The default implementation logs the exception at warn level,
* not propagating it to the JMS provider — replaceduming that all handling of
* acknowledgement and/or transactions is done by this listener container.
* This can be overridden in subclreplacedes.
* @param ex the exception to handle
*/
protected void handleListenerException(Throwable ex) {
if (ex instanceof MessageRejectedWhileStoppingException) {
// Internal exception - has been handled before.
return;
}
if (ex instanceof JMSException) {
invokeExceptionListener((JMSException) ex);
}
if (isActive()) {
// Regular case: failed while active.
// Invoke ErrorHandler if available.
invokeErrorHandler(ex);
} else {
// Rare case: listener thread failed after container shutdown.
// Log at debug level, to avoid spamming the shutdown log.
logger.debug("Listener exception after container shutdown", ex);
}
}
/**
* Invoke the registered JMS ExceptionListener, if any.
* @param ex the exception that arose during JMS processing
* @see #setExceptionListener
*/
protected void invokeExceptionListener(JMSException ex) {
ExceptionListener exceptionListener = getExceptionListener();
if (exceptionListener != null) {
exceptionListener.onException(ex);
}
}
/**
* Invoke the registered ErrorHandler, if any. Log at warn level otherwise.
* @param ex the uncaught error that arose during JMS processing.
* @see #setErrorHandler
*/
protected void invokeErrorHandler(Throwable ex) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
errorHandler.handleError(ex);
} else {
logger.warn("Execution of JMS message listener failed, and no ErrorHandler has been set.", ex);
}
}
/**
* Internal exception clreplaced that indicates a rejected message on shutdown.
* Used to trigger a rollback for an external transaction manager in that case.
*/
@SuppressWarnings("serial")
private static clreplaced MessageRejectedWhileStoppingException extends RuntimeException {
}
}
19
View Source File : AbstractMessageListenerContainer.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Set the ErrorHandler to be invoked in case of any uncaught exceptions thrown
* while processing a Message.
* <p>By default, there will be <b>no</b> ErrorHandler so that error-level
* logging is the only result.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
19
View Source File : AbstractJmsListenerContainerFactory.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Base {@link JmsListenerContainerFactory} for Spring's base container implementation.
*
* @author Stephane Nicoll
* @since 4.1
* @see AbstractMessageListenerContainer
*/
public abstract clreplaced AbstractJmsListenerContainerFactory<C extends AbstractMessageListenerContainer> implements JmsListenerContainerFactory<C> {
protected final Log logger = LogFactory.getLog(getClreplaced());
private ConnectionFactory connectionFactory;
private DestinationResolver destinationResolver;
private ErrorHandler errorHandler;
private MessageConverter messageConverter;
private Boolean sessionTransacted;
private Integer sessionAcknowledgeMode;
private Boolean pubSubDomain;
private Boolean replyPubSubDomain;
private Boolean subscriptionDurable;
private Boolean subscriptionShared;
private String clientId;
private Integer phase;
private Boolean autoStartup;
/**
* @see AbstractMessageListenerContainer#setConnectionFactory(ConnectionFactory)
*/
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
/**
* @see AbstractMessageListenerContainer#setDestinationResolver(DestinationResolver)
*/
public void setDestinationResolver(DestinationResolver destinationResolver) {
this.destinationResolver = destinationResolver;
}
/**
* @see AbstractMessageListenerContainer#setErrorHandler(ErrorHandler)
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* @see AbstractMessageListenerContainer#setMessageConverter(MessageConverter)
*/
public void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
/**
* @see AbstractMessageListenerContainer#setSessionTransacted(boolean)
*/
public void setSessionTransacted(Boolean sessionTransacted) {
this.sessionTransacted = sessionTransacted;
}
/**
* @see AbstractMessageListenerContainer#setSessionAcknowledgeMode(int)
*/
public void setSessionAcknowledgeMode(Integer sessionAcknowledgeMode) {
this.sessionAcknowledgeMode = sessionAcknowledgeMode;
}
/**
* @see AbstractMessageListenerContainer#setPubSubDomain(boolean)
*/
public void setPubSubDomain(Boolean pubSubDomain) {
this.pubSubDomain = pubSubDomain;
}
/**
* @see AbstractMessageListenerContainer#setReplyPubSubDomain(boolean)
*/
public void setReplyPubSubDomain(Boolean replyPubSubDomain) {
this.replyPubSubDomain = replyPubSubDomain;
}
/**
* @see AbstractMessageListenerContainer#setSubscriptionDurable(boolean)
*/
public void setSubscriptionDurable(Boolean subscriptionDurable) {
this.subscriptionDurable = subscriptionDurable;
}
/**
* @see AbstractMessageListenerContainer#setSubscriptionShared(boolean)
*/
public void setSubscriptionShared(Boolean subscriptionShared) {
this.subscriptionShared = subscriptionShared;
}
/**
* @see AbstractMessageListenerContainer#setClientId(String)
*/
public void setClientId(String clientId) {
this.clientId = clientId;
}
/**
* @see AbstractMessageListenerContainer#setPhase(int)
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* @see AbstractMessageListenerContainer#setAutoStartup(boolean)
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
@Override
public C createListenerContainer(JmsListenerEndpoint endpoint) {
C instance = createContainerInstance();
if (this.connectionFactory != null) {
instance.setConnectionFactory(this.connectionFactory);
}
if (this.destinationResolver != null) {
instance.setDestinationResolver(this.destinationResolver);
}
if (this.errorHandler != null) {
instance.setErrorHandler(this.errorHandler);
}
if (this.messageConverter != null) {
instance.setMessageConverter(this.messageConverter);
}
if (this.sessionTransacted != null) {
instance.setSessionTransacted(this.sessionTransacted);
}
if (this.sessionAcknowledgeMode != null) {
instance.setSessionAcknowledgeMode(this.sessionAcknowledgeMode);
}
if (this.pubSubDomain != null) {
instance.setPubSubDomain(this.pubSubDomain);
}
if (this.replyPubSubDomain != null) {
instance.setReplyPubSubDomain(this.replyPubSubDomain);
}
if (this.subscriptionDurable != null) {
instance.setSubscriptionDurable(this.subscriptionDurable);
}
if (this.subscriptionShared != null) {
instance.setSubscriptionShared(this.subscriptionShared);
}
if (this.clientId != null) {
instance.setClientId(this.clientId);
}
if (this.phase != null) {
instance.setPhase(this.phase);
}
if (this.autoStartup != null) {
instance.setAutoStartup(this.autoStartup);
}
endpoint.setupListenerContainer(instance);
initializeContainer(instance);
return instance;
}
/**
* Create an empty container instance.
*/
protected abstract C createContainerInstance();
/**
* Further initialize the specified container.
* <p>Subclreplacedes can inherit from this method to apply extra
* configuration if necessary.
*/
protected void initializeContainer(C instance) {
}
}
19
View Source File : TimerManagerTaskScheduler.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Implementation of Spring's {@link TaskScheduler} interface, wrapping
* a CommonJ {@link commonj.timers.TimerManager}.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @since 3.0
*/
public clreplaced TimerManagerTaskScheduler extends TimerManagerAccessor implements TaskScheduler {
private volatile ErrorHandler errorHandler;
/**
* Provide an {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
@Override
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
return new ReschedulingTimerListener(errorHandlingTask(task, true), trigger).schedule();
}
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, false));
Timer timer = getTimerManager().schedule(futureTask, startTime);
futureTask.setTimer(timer);
return futureTask;
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
Timer timer = getTimerManager().scheduleAtFixedRate(futureTask, startTime, period);
futureTask.setTimer(timer);
return futureTask;
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
Timer timer = getTimerManager().scheduleAtFixedRate(futureTask, 0, period);
futureTask.setTimer(timer);
return futureTask;
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
Timer timer = getTimerManager().schedule(futureTask, startTime, delay);
futureTask.setTimer(timer);
return futureTask;
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
Timer timer = getTimerManager().schedule(futureTask, 0, delay);
futureTask.setTimer(timer);
return futureTask;
}
private Runnable errorHandlingTask(Runnable delegate, boolean isRepeatingTask) {
return TaskUtils.decorateTaskWithErrorHandler(delegate, this.errorHandler, isRepeatingTask);
}
/**
* ScheduledFuture adapter that wraps a CommonJ Timer.
*/
private static clreplaced TimerScheduledFuture extends FutureTask<Object> implements TimerListener, ScheduledFuture<Object> {
protected transient Timer timer;
protected transient boolean cancelled = false;
public TimerScheduledFuture(Runnable runnable) {
super(runnable, null);
}
public void setTimer(Timer timer) {
this.timer = timer;
}
@Override
public void timerExpired(Timer timer) {
runAndReset();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
boolean result = super.cancel(mayInterruptIfRunning);
this.timer.cancel();
this.cancelled = true;
return result;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(System.currentTimeMillis() - this.timer.getScheduledExecutionTime(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed other) {
if (this == other) {
return 0;
}
long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS);
return (diff == 0 ? 0 : ((diff < 0) ? -1 : 1));
}
}
/**
* ScheduledFuture adapter for trigger-based rescheduling.
*/
private clreplaced ReschedulingTimerListener extends TimerScheduledFuture {
private final Trigger trigger;
private final SimpleTriggerContext triggerContext = new SimpleTriggerContext();
private volatile Date scheduledExecutionTime;
public ReschedulingTimerListener(Runnable runnable, Trigger trigger) {
super(runnable);
this.trigger = trigger;
}
public ScheduledFuture<?> schedule() {
this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext);
if (this.scheduledExecutionTime == null) {
return null;
}
setTimer(getTimerManager().schedule(this, this.scheduledExecutionTime));
return this;
}
@Override
public void timerExpired(Timer timer) {
Date actualExecutionTime = new Date();
super.timerExpired(timer);
Date completionTime = new Date();
this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
if (!this.cancelled) {
schedule();
}
}
}
}
19
View Source File : TaskUtils.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Utility methods for decorating tasks with error handling.
*
* <p><b>NOTE:</b> This clreplaced is intended for internal use by Spring's scheduler
* implementations. It is only public so that it may be accessed from impl clreplacedes
* within other packages. It is <i>not</i> intended for general use.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @since 3.0
*/
public abstract clreplaced TaskUtils {
/**
* An ErrorHandler strategy that will log the Exception but perform
* no further handling. This will suppress the error so that
* subsequent executions of the task will not be prevented.
*/
public static final ErrorHandler LOG_AND_SUPPRESS_ERROR_HANDLER = new LoggingErrorHandler();
/**
* An ErrorHandler strategy that will log at error level and then
* re-throw the Exception. Note: this will typically prevent subsequent
* execution of a scheduled task.
*/
public static final ErrorHandler LOG_AND_PROPAGATE_ERROR_HANDLER = new PropagatingErrorHandler();
/**
* Decorate the task for error handling. If the provided {@link ErrorHandler}
* is not {@code null}, it will be used. Otherwise, repeating tasks will have
* errors suppressed by default whereas one-shot tasks will have errors
* propagated by default since those errors may be expected through the
* returned {@link Future}. In both cases, the errors will be logged.
*/
public static DelegatingErrorHandlingRunnable decorateTaskWithErrorHandler(Runnable task, ErrorHandler errorHandler, boolean isRepeatingTask) {
if (task instanceof DelegatingErrorHandlingRunnable) {
return (DelegatingErrorHandlingRunnable) task;
}
ErrorHandler eh = (errorHandler != null ? errorHandler : getDefaultErrorHandler(isRepeatingTask));
return new DelegatingErrorHandlingRunnable(task, eh);
}
/**
* Return the default {@link ErrorHandler} implementation based on the boolean
* value indicating whether the task will be repeating or not. For repeating tasks
* it will suppress errors, but for one-time tasks it will propagate. In both
* cases, the error will be logged.
*/
public static ErrorHandler getDefaultErrorHandler(boolean isRepeatingTask) {
return (isRepeatingTask ? LOG_AND_SUPPRESS_ERROR_HANDLER : LOG_AND_PROPAGATE_ERROR_HANDLER);
}
/**
* An {@link ErrorHandler} implementation that logs the Throwable at error
* level. It does not perform any additional error handling. This can be
* useful when suppression of errors is the intended behavior.
*/
private static clreplaced LoggingErrorHandler implements ErrorHandler {
private final Log logger = LogFactory.getLog(LoggingErrorHandler.clreplaced);
@Override
public void handleError(Throwable t) {
if (logger.isErrorEnabled()) {
logger.error("Unexpected error occurred in scheduled task.", t);
}
}
}
/**
* An {@link ErrorHandler} implementation that logs the Throwable at error
* level and then propagates it.
*/
private static clreplaced PropagatingErrorHandler extends LoggingErrorHandler {
@Override
public void handleError(Throwable t) {
super.handleError(t);
ReflectionUtils.rethrowRuntimeException(t);
}
}
}
19
View Source File : TaskUtils.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Decorate the task for error handling. If the provided {@link ErrorHandler}
* is not {@code null}, it will be used. Otherwise, repeating tasks will have
* errors suppressed by default whereas one-shot tasks will have errors
* propagated by default since those errors may be expected through the
* returned {@link Future}. In both cases, the errors will be logged.
*/
public static DelegatingErrorHandlingRunnable decorateTaskWithErrorHandler(Runnable task, ErrorHandler errorHandler, boolean isRepeatingTask) {
if (task instanceof DelegatingErrorHandlingRunnable) {
return (DelegatingErrorHandlingRunnable) task;
}
ErrorHandler eh = (errorHandler != null ? errorHandler : getDefaultErrorHandler(isRepeatingTask));
return new DelegatingErrorHandlingRunnable(task, eh);
}
19
View Source File : ThreadPoolTaskScheduler.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Implementation of Spring's {@link TaskScheduler} interface, wrapping
* a native {@link java.util.concurrent.ScheduledThreadPoolExecutor}.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @since 3.0
* @see #setPoolSize
* @see #setRemoveOnCancelPolicy
* @see #setThreadFactory
* @see #setErrorHandler
*/
@SuppressWarnings("serial")
public clreplaced ThreadPoolTaskScheduler extends ExecutorConfigurationSupport implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, TaskScheduler {
// ScheduledThreadPoolExecutor.setRemoveOnCancelPolicy(boolean) only available on JDK 7+
private static final boolean setRemoveOnCancelPolicyAvailable = ClreplacedUtils.hasMethod(ScheduledThreadPoolExecutor.clreplaced, "setRemoveOnCancelPolicy", boolean.clreplaced);
private volatile int poolSize = 1;
private volatile boolean removeOnCancelPolicy = false;
private volatile ScheduledExecutorService scheduledExecutor;
private volatile ErrorHandler errorHandler;
/**
* Set the ScheduledExecutorService's pool size.
* Default is 1.
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
*/
public void setPoolSize(int poolSize) {
replacedert.isTrue(poolSize > 0, "'poolSize' must be 1 or higher");
this.poolSize = poolSize;
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setCorePoolSize(poolSize);
}
}
/**
* Set the remove-on-cancel mode on {@link ScheduledThreadPoolExecutor} (JDK 7+).
* <p>Default is {@code false}. If set to {@code true}, the target executor will be
* switched into remove-on-cancel mode (if possible, with a soft fallback otherwise).
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
*/
@UsesJava7
public void setRemoveOnCancelPolicy(boolean removeOnCancelPolicy) {
this.removeOnCancelPolicy = removeOnCancelPolicy;
if (setRemoveOnCancelPolicyAvailable && this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(removeOnCancelPolicy);
} else if (removeOnCancelPolicy && this.scheduledExecutor != null) {
logger.info("Could not apply remove-on-cancel policy - not a Java 7+ ScheduledThreadPoolExecutor");
}
}
/**
* Set a custom {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
@UsesJava7
@Override
protected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
this.scheduledExecutor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler);
if (this.removeOnCancelPolicy) {
if (setRemoveOnCancelPolicyAvailable && this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(true);
} else {
logger.info("Could not apply remove-on-cancel policy - not a Java 7+ ScheduledThreadPoolExecutor");
}
}
return this.scheduledExecutor;
}
/**
* Create a new {@link ScheduledExecutorService} instance.
* <p>The default implementation creates a {@link ScheduledThreadPoolExecutor}.
* Can be overridden in subclreplacedes to provide custom {@link ScheduledExecutorService} instances.
* @param poolSize the specified pool size
* @param threadFactory the ThreadFactory to use
* @param rejectedExecutionHandler the RejectedExecutionHandler to use
* @return a new ScheduledExecutorService instance
* @see #afterPropertiesSet()
* @see java.util.concurrent.ScheduledThreadPoolExecutor
*/
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return new ScheduledThreadPoolExecutor(poolSize, threadFactory, rejectedExecutionHandler);
}
/**
* Return the underlying ScheduledExecutorService for native access.
* @return the underlying ScheduledExecutorService (never {@code null})
* @throws IllegalStateException if the ThreadPoolTaskScheduler hasn't been initialized yet
*/
public ScheduledExecutorService getScheduledExecutor() throws IllegalStateException {
replacedert.state(this.scheduledExecutor != null, "ThreadPoolTaskScheduler not initialized");
return this.scheduledExecutor;
}
/**
* Return the underlying ScheduledThreadPoolExecutor, if available.
* @return the underlying ScheduledExecutorService (never {@code null})
* @throws IllegalStateException if the ThreadPoolTaskScheduler hasn't been initialized yet
* or if the underlying ScheduledExecutorService isn't a ScheduledThreadPoolExecutor
* @see #getScheduledExecutor()
*/
public ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() throws IllegalStateException {
replacedert.state(this.scheduledExecutor instanceof ScheduledThreadPoolExecutor, "No ScheduledThreadPoolExecutor available");
return (ScheduledThreadPoolExecutor) this.scheduledExecutor;
}
/**
* Return the current pool size.
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
* @see #getScheduledThreadPoolExecutor()
* @see java.util.concurrent.ScheduledThreadPoolExecutor#getPoolSize()
*/
public int getPoolSize() {
if (this.scheduledExecutor == null) {
// Not initialized yet: replacedume initial pool size.
return this.poolSize;
}
return getScheduledThreadPoolExecutor().getPoolSize();
}
/**
* Return the current setting for the remove-on-cancel mode.
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
*/
@UsesJava7
public boolean isRemoveOnCancelPolicy() {
if (!setRemoveOnCancelPolicyAvailable) {
return false;
}
if (this.scheduledExecutor == null) {
// Not initialized yet: return our setting for the time being.
return this.removeOnCancelPolicy;
}
return getScheduledThreadPoolExecutor().getRemoveOnCancelPolicy();
}
/**
* Return the number of currently active threads.
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
* @see #getScheduledThreadPoolExecutor()
* @see java.util.concurrent.ScheduledThreadPoolExecutor#getActiveCount()
*/
public int getActiveCount() {
if (this.scheduledExecutor == null) {
// Not initialized yet: replacedume no active threads.
return 0;
}
return getScheduledThreadPoolExecutor().getActiveCount();
}
// SchedulingTaskExecutor implementation
@Override
public void execute(Runnable task) {
Executor executor = getScheduledExecutor();
try {
executor.execute(errorHandlingTask(task, false));
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public void execute(Runnable task, long startTimeout) {
execute(task);
}
@Override
public Future<?> submit(Runnable task) {
ExecutorService executor = getScheduledExecutor();
try {
return executor.submit(errorHandlingTask(task, false));
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public <T> Future<T> submit(Callable<T> task) {
ExecutorService executor = getScheduledExecutor();
try {
Callable<T> taskToUse = task;
if (this.errorHandler != null) {
taskToUse = new DelegatingErrorHandlingCallable<T>(task, this.errorHandler);
}
return executor.submit(taskToUse);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
ExecutorService executor = getScheduledExecutor();
try {
ListenableFutureTask<Object> future = new ListenableFutureTask<Object>(task, null);
executor.execute(errorHandlingTask(future, false));
return future;
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
ExecutorService executor = getScheduledExecutor();
try {
ListenableFutureTask<T> future = new ListenableFutureTask<T>(task);
executor.execute(errorHandlingTask(future, false));
return future;
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public boolean prefersShortLivedTasks() {
return true;
}
// TaskScheduler implementation
@Override
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
ScheduledExecutorService executor = getScheduledExecutor();
try {
ErrorHandler errorHandler = (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true));
return new ReschedulingRunnable(task, trigger, executor, errorHandler).schedule();
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
ScheduledExecutorService executor = getScheduledExecutor();
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return executor.schedule(errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
ScheduledExecutorService executor = getScheduledExecutor();
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return executor.scheduleAtFixedRate(errorHandlingTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
ScheduledExecutorService executor = getScheduledExecutor();
try {
return executor.scheduleAtFixedRate(errorHandlingTask(task, true), 0, period, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
ScheduledExecutorService executor = getScheduledExecutor();
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
ScheduledExecutorService executor = getScheduledExecutor();
try {
return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), 0, delay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
private Runnable errorHandlingTask(Runnable task, boolean isRepeatingTask) {
return TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, isRepeatingTask);
}
private static clreplaced DelegatingErrorHandlingCallable<V> implements Callable<V> {
private final Callable<V> delegate;
private final ErrorHandler errorHandler;
public DelegatingErrorHandlingCallable(Callable<V> delegate, ErrorHandler errorHandler) {
this.delegate = delegate;
this.errorHandler = errorHandler;
}
@Override
public V call() throws Exception {
try {
return this.delegate.call();
} catch (Throwable t) {
this.errorHandler.handleError(t);
return null;
}
}
}
}
19
View Source File : ConcurrentTaskScheduler.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Adapter that takes a {@code java.util.concurrent.ScheduledExecutorService} and
* exposes a Spring {@link org.springframework.scheduling.TaskScheduler} for it.
* Extends {@link ConcurrentTaskExecutor} in order to implement the
* {@link org.springframework.scheduling.SchedulingTaskExecutor} interface as well.
*
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService}
* in order to use it for trigger-based scheduling if possible, instead of Spring's
* local trigger management which ends up delegating to regular delay-based scheduling
* against the {@code java.util.concurrent.ScheduledExecutorService} API. For JSR-236 style
* lookup in a Java EE 7 environment, consider using {@link DefaultManagedTaskScheduler}.
*
* <p>Note that there is a pre-built {@link ThreadPoolTaskScheduler} that allows for
* defining a {@link java.util.concurrent.ScheduledThreadPoolExecutor} in bean style,
* exposing it as a Spring {@link org.springframework.scheduling.TaskScheduler} directly.
* This is a convenient alternative to a raw ScheduledThreadPoolExecutor definition with
* a separate definition of the present adapter clreplaced.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @since 3.0
* @see java.util.concurrent.ScheduledExecutorService
* @see java.util.concurrent.ScheduledThreadPoolExecutor
* @see java.util.concurrent.Executors
* @see DefaultManagedTaskScheduler
* @see ThreadPoolTaskScheduler
*/
public clreplaced ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements TaskScheduler {
private static Clreplaced<?> managedScheduledExecutorServiceClreplaced;
static {
try {
managedScheduledExecutorServiceClreplaced = ClreplacedUtils.forName("javax.enterprise.concurrent.ManagedScheduledExecutorService", ConcurrentTaskScheduler.clreplaced.getClreplacedLoader());
} catch (ClreplacedNotFoundException ex) {
// JSR-236 API not available...
managedScheduledExecutorServiceClreplaced = null;
}
}
private ScheduledExecutorService scheduledExecutor;
private boolean enterpriseConcurrentScheduler = false;
private ErrorHandler errorHandler;
/**
* Create a new ConcurrentTaskScheduler,
* using a single thread executor as default.
* @see java.util.concurrent.Executors#newSingleThreadScheduledExecutor()
*/
public ConcurrentTaskScheduler() {
super();
setScheduledExecutor(null);
}
/**
* Create a new ConcurrentTaskScheduler, using the given
* {@link java.util.concurrent.ScheduledExecutorService} as shared delegate.
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService}
* in order to use it for trigger-based scheduling if possible,
* instead of Spring's local trigger management.
* @param scheduledExecutor the {@link java.util.concurrent.ScheduledExecutorService}
* to delegate to for {@link org.springframework.scheduling.SchedulingTaskExecutor}
* as well as {@link TaskScheduler} invocations
*/
public ConcurrentTaskScheduler(ScheduledExecutorService scheduledExecutor) {
super(scheduledExecutor);
setScheduledExecutor(scheduledExecutor);
}
/**
* Create a new ConcurrentTaskScheduler, using the given {@link java.util.concurrent.Executor}
* and {@link java.util.concurrent.ScheduledExecutorService} as delegates.
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService}
* in order to use it for trigger-based scheduling if possible,
* instead of Spring's local trigger management.
* @param concurrentExecutor the {@link java.util.concurrent.Executor} to delegate to
* for {@link org.springframework.scheduling.SchedulingTaskExecutor} invocations
* @param scheduledExecutor the {@link java.util.concurrent.ScheduledExecutorService}
* to delegate to for {@link TaskScheduler} invocations
*/
public ConcurrentTaskScheduler(Executor concurrentExecutor, ScheduledExecutorService scheduledExecutor) {
super(concurrentExecutor);
setScheduledExecutor(scheduledExecutor);
}
/**
* Specify the {@link java.util.concurrent.ScheduledExecutorService} to delegate to.
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService}
* in order to use it for trigger-based scheduling if possible,
* instead of Spring's local trigger management.
* <p>Note: This will only apply to {@link TaskScheduler} invocations.
* If you want the given executor to apply to
* {@link org.springframework.scheduling.SchedulingTaskExecutor} invocations
* as well, preplaced the same executor reference to {@link #setConcurrentExecutor}.
* @see #setConcurrentExecutor
*/
public final void setScheduledExecutor(ScheduledExecutorService scheduledExecutor) {
if (scheduledExecutor != null) {
this.scheduledExecutor = scheduledExecutor;
this.enterpriseConcurrentScheduler = (managedScheduledExecutorServiceClreplaced != null && managedScheduledExecutorServiceClreplaced.isInstance(scheduledExecutor));
} else {
this.scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
this.enterpriseConcurrentScheduler = false;
}
}
/**
* Provide an {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
replacedert.notNull(errorHandler, "'errorHandler' must not be null");
this.errorHandler = errorHandler;
}
@Override
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
try {
if (this.enterpriseConcurrentScheduler) {
return new EnterpriseConcurrentTriggerScheduler().schedule(decorateTask(task, true), trigger);
} else {
ErrorHandler errorHandler = (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true));
return new ReschedulingRunnable(task, trigger, this.scheduledExecutor, errorHandler).schedule();
}
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return this.scheduledExecutor.schedule(decorateTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return this.scheduledExecutor.scheduleAtFixedRate(decorateTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
try {
return this.scheduledExecutor.scheduleAtFixedRate(decorateTask(task, true), 0, period, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
return this.scheduledExecutor.scheduleWithFixedDelay(decorateTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
try {
return this.scheduledExecutor.scheduleWithFixedDelay(decorateTask(task, true), 0, delay, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
private Runnable decorateTask(Runnable task, boolean isRepeatingTask) {
Runnable result = TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, isRepeatingTask);
if (this.enterpriseConcurrentScheduler) {
result = ManagedTaskBuilder.buildManagedTask(result, task.toString());
}
return result;
}
/**
* Delegate that adapts a Spring Trigger to a JSR-236 Trigger.
* Separated into an inner clreplaced in order to avoid a hard dependency on the JSR-236 API.
*/
private clreplaced EnterpriseConcurrentTriggerScheduler {
public ScheduledFuture<?> schedule(Runnable task, final Trigger trigger) {
ManagedScheduledExecutorService executor = (ManagedScheduledExecutorService) scheduledExecutor;
return executor.schedule(task, new javax.enterprise.concurrent.Trigger() {
@Override
public Date getNextRunTime(LastExecution le, Date taskScheduledTime) {
return trigger.nextExecutionTime(le != null ? new SimpleTriggerContext(le.getScheduledStart(), le.getRunStart(), le.getRunEnd()) : new SimpleTriggerContext());
}
@Override
public boolean skipRun(LastExecution lastExecution, Date scheduledRunTime) {
return false;
}
});
}
}
}
19
View Source File : ConcurrentTaskScheduler.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
@Override
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
try {
if (this.enterpriseConcurrentScheduler) {
return new EnterpriseConcurrentTriggerScheduler().schedule(decorateTask(task, true), trigger);
} else {
ErrorHandler errorHandler = (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true));
return new ReschedulingRunnable(task, trigger, this.scheduledExecutor, errorHandler).schedule();
}
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
}
}
19
View Source File : ConcurrentTaskScheduler.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Provide an {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
replacedert.notNull(errorHandler, "'errorHandler' must not be null");
this.errorHandler = errorHandler;
}
19
View Source File : SimpleApplicationEventMulticaster.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Simple implementation of the {@link ApplicationEventMulticaster} interface.
*
* <p>Multicasts all events to all registered listeners, leaving it up to
* the listeners to ignore events that they are not interested in.
* Listeners will usually perform corresponding {@code instanceof}
* checks on the preplaceded-in event object.
*
* <p>By default, all listeners are invoked in the calling thread.
* This allows the danger of a rogue listener blocking the entire application,
* but adds minimal overhead. Specify an alternative task executor to have
* listeners executed in different threads, for example from a thread pool.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Stephane Nicoll
* @see #setTaskExecutor
*/
public clreplaced SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
private Executor taskExecutor;
private ErrorHandler errorHandler;
/**
* Create a new SimpleApplicationEventMulticaster.
*/
public SimpleApplicationEventMulticaster() {
}
/**
* Create a new SimpleApplicationEventMulticaster for the given BeanFactory.
*/
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
/**
* Set a custom executor (typically a {@link org.springframework.core.task.TaskExecutor})
* to invoke each listener with.
* <p>Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor},
* executing all listeners synchronously in the calling thread.
* <p>Consider specifying an asynchronous task executor here to not block the
* caller until all listeners have been executed. However, note that asynchronous
* execution will not participate in the caller's thread context (clreplaced loader,
* transaction replacedociation) unless the TaskExecutor explicitly supports this.
* @see org.springframework.core.task.SyncTaskExecutor
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
*/
public void setTaskExecutor(Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/**
* Return the current task executor for this multicaster.
*/
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
/**
* Set the {@link ErrorHandler} to invoke in case an exception is thrown
* from a listener.
* <p>Default is none, with a listener exception stopping the current
* multicast and getting propagated to the publisher of the current event.
* If a {@linkplain #setTaskExecutor task executor} is specified, each
* individual listener exception will get propagated to the executor but
* won't necessarily stop execution of other listeners.
* <p>Consider setting an {@link ErrorHandler} implementation that catches
* and logs exceptions (a la
* {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_SUPPRESS_ERROR_HANDLER})
* or an implementation that logs exceptions while nevertheless propagating them
* (e.g. {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_PROPAGATE_ERROR_HANDLER}).
* @since 4.1
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Return the current error handler for this multicaster.
* @since 4.1
*/
protected ErrorHandler getErrorHandler() {
return this.errorHandler;
}
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
} else {
invokeListener(listener, event);
}
}
}
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
listener.onApplicationEvent(event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
listener.onApplicationEvent(event);
}
}
}
19
View Source File : SimpleApplicationEventMulticaster.java
License : Apache License 2.0
Project Creator : langtianya
License : Apache License 2.0
Project Creator : langtianya
/**
* Set the {@link ErrorHandler} to invoke in case an exception is thrown
* from a listener.
* <p>Default is none, with a listener exception stopping the current
* multicast and getting propagated to the publisher of the current event.
* If a {@linkplain #setTaskExecutor task executor} is specified, each
* individual listener exception will get propagated to the executor but
* won't necessarily stop execution of other listeners.
* <p>Consider setting an {@link ErrorHandler} implementation that catches
* and logs exceptions (a la
* {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_SUPPRESS_ERROR_HANDLER})
* or an implementation that logs exceptions while nevertheless propagating them
* (e.g. {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_PROPAGATE_ERROR_HANDLER}).
* @since 4.1
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
19
View Source File : EmbeddedZooKeeper.java
License : Apache License 2.0
Project Creator : hengyunabc
License : Apache License 2.0
Project Creator : hengyunabc
/**
* from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java
*
* Helper clreplaced to start an embedded instance of standalone (non clustered) ZooKeeper.
*
* NOTE: at least an external standalone server (if not an ensemble) are recommended, even for
* {@link org.springframework.xd.dirt.server.singlenode.SingleNodeApplication}
*
* @author Patrick Peralta
* @author Mark Fisher
* @author David Turanski
*/
public clreplaced EmbeddedZooKeeper implements SmartLifecycle {
/**
* Logger.
*/
private static final Logger logger = LoggerFactory.getLogger(EmbeddedZooKeeper.clreplaced);
/**
* ZooKeeper client port. This will be determined dynamically upon startup.
*/
private final int clientPort;
/**
* Whether to auto-start. Default is true.
*/
private boolean autoStartup = true;
/**
* Lifecycle phase. Default is 0.
*/
private int phase = 0;
/**
* Thread for running the ZooKeeper server.
*/
private volatile Thread zkServerThread;
/**
* ZooKeeper server.
*/
private volatile ZooKeeperServerMain zkServer;
/**
* {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread.
*/
private ErrorHandler errorHandler;
private boolean daemon = true;
/**
* Construct an EmbeddedZooKeeper with a random port.
*/
public EmbeddedZooKeeper() {
clientPort = SocketUtils.findAvailableTcpPort();
}
/**
* Construct an EmbeddedZooKeeper with the provided port.
*
* @param clientPort port for ZooKeeper server to bind to
*/
public EmbeddedZooKeeper(int clientPort, boolean daemon) {
this.clientPort = clientPort;
this.daemon = daemon;
}
/**
* Returns the port that clients should use to connect to this embedded server.
*
* @return dynamically determined client port
*/
public int getClientPort() {
return this.clientPort;
}
/**
* Specify whether to start automatically. Default is true.
*
* @param autoStartup whether to start automatically
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isAutoStartup() {
return this.autoStartup;
}
/**
* Specify the lifecycle phase for the embedded server.
*
* @param phase the lifecycle phase
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* {@inheritDoc}
*/
@Override
public int getPhase() {
return this.phase;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRunning() {
return (zkServerThread != null);
}
/**
* Start the ZooKeeper server in a background thread.
* <p>
* Register an error handler via {@link #setErrorHandler} in order to handle
* any exceptions thrown during startup or execution.
*/
@Override
public synchronized void start() {
if (zkServerThread == null) {
zkServerThread = new Thread(new ServerRunnable(), "ZooKeeper Server Starter");
zkServerThread.setDaemon(daemon);
zkServerThread.start();
}
}
/**
* Shutdown the ZooKeeper server.
*/
@Override
public synchronized void stop() {
if (zkServerThread != null) {
// The shutdown method is protected...thus this hack to invoke it.
// This will log an exception on shutdown; see
// https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.
try {
Method shutdown = ZooKeeperServerMain.clreplaced.getDeclaredMethod("shutdown");
shutdown.setAccessible(true);
shutdown.invoke(zkServer);
} catch (Exception e) {
throw new RuntimeException(e);
}
// It is expected that the thread will exit after
// the server is shutdown; this will block until
// the shutdown is complete.
try {
zkServerThread.join(5000);
zkServerThread = null;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.warn("Interrupted while waiting for embedded ZooKeeper to exit");
// abandoning zk thread
zkServerThread = null;
}
}
}
/**
* Stop the server if running and invoke the callback when complete.
*/
@Override
public void stop(Runnable callback) {
stop();
callback.run();
}
/**
* Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none
* is provided, only error-level logging will occur.
*
* @param errorHandler the {@link ErrorHandler} to be invoked
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Runnable implementation that starts the ZooKeeper server.
*/
private clreplaced ServerRunnable implements Runnable {
@Override
public void run() {
try {
Properties properties = new Properties();
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID());
file.deleteOnExit();
properties.setProperty("dataDir", file.getAbsolutePath());
properties.setProperty("clientPort", String.valueOf(clientPort));
QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
quorumPeerConfig.parseProperties(properties);
zkServer = new ZooKeeperServerMain();
ServerConfig configuration = new ServerConfig();
configuration.readFrom(quorumPeerConfig);
zkServer.runFromConfig(configuration);
} catch (Exception e) {
if (errorHandler != null) {
errorHandler.handleError(e);
} else {
logger.error("Exception running embedded ZooKeeper", e);
}
}
}
}
}
19
View Source File : EmbeddedZooKeeper.java
License : Apache License 2.0
Project Creator : apache
License : Apache License 2.0
Project Creator : apache
/**
* from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java
* <p>
* Helper clreplaced to start an embedded instance of standalone (non clustered) ZooKeeper.
* <p>
* NOTE: at least an external standalone server (if not an ensemble) are recommended, even for
* {@link org.springframework.xd.dirt.server.singlenode.SingleNodeApplication}
*
* @author Patrick Peralta
* @author Mark Fisher
* @author David Turanski
*/
public clreplaced EmbeddedZooKeeper implements SmartLifecycle {
/**
* Logger.
*/
private static final Logger logger = LoggerFactory.getLogger(EmbeddedZooKeeper.clreplaced);
/**
* ZooKeeper client port. This will be determined dynamically upon startup.
*/
private final int clientPort;
/**
* Whether to auto-start. Default is true.
*/
private boolean autoStartup = true;
/**
* Lifecycle phase. Default is 0.
*/
private int phase = 0;
/**
* Thread for running the ZooKeeper server.
*/
private volatile Thread zkServerThread;
/**
* ZooKeeper server.
*/
private volatile ZooKeeperServerMain zkServer;
/**
* {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread.
*/
private ErrorHandler errorHandler;
private boolean daemon = true;
/**
* Construct an EmbeddedZooKeeper with a random port.
*/
public EmbeddedZooKeeper() {
clientPort = SocketUtils.findAvailableTcpPort();
}
/**
* Construct an EmbeddedZooKeeper with the provided port.
*
* @param clientPort port for ZooKeeper server to bind to
*/
public EmbeddedZooKeeper(int clientPort, boolean daemon) {
this.clientPort = clientPort;
this.daemon = daemon;
}
/**
* Returns the port that clients should use to connect to this embedded server.
*
* @return dynamically determined client port
*/
public int getClientPort() {
return this.clientPort;
}
/**
* Specify whether to start automatically. Default is true.
*
* @param autoStartup whether to start automatically
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isAutoStartup() {
return this.autoStartup;
}
/**
* Specify the lifecycle phase for the embedded server.
*
* @param phase the lifecycle phase
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* {@inheritDoc}
*/
@Override
public int getPhase() {
return this.phase;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRunning() {
return (zkServerThread != null);
}
/**
* Start the ZooKeeper server in a background thread.
* <p>
* Register an error handler via {@link #setErrorHandler} in order to handle
* any exceptions thrown during startup or execution.
*/
@Override
public synchronized void start() {
if (zkServerThread == null) {
zkServerThread = new Thread(new ServerRunnable(), "ZooKeeper Server Starter");
zkServerThread.setDaemon(daemon);
zkServerThread.start();
}
}
/**
* Shutdown the ZooKeeper server.
*/
@Override
public synchronized void stop() {
if (zkServerThread != null) {
// The shutdown method is protected...thus this hack to invoke it.
// This will log an exception on shutdown; see
// https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.
try {
Method shutdown = ZooKeeperServerMain.clreplaced.getDeclaredMethod("shutdown");
shutdown.setAccessible(true);
shutdown.invoke(zkServer);
} catch (Exception e) {
throw new RuntimeException(e);
}
// It is expected that the thread will exit after
// the server is shutdown; this will block until
// the shutdown is complete.
try {
zkServerThread.join(5000);
zkServerThread = null;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.warn("Interrupted while waiting for embedded ZooKeeper to exit");
// abandoning zk thread
zkServerThread = null;
}
}
}
/**
* Stop the server if running and invoke the callback when complete.
*/
@Override
public void stop(Runnable callback) {
stop();
callback.run();
}
/**
* Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none
* is provided, only error-level logging will occur.
*
* @param errorHandler the {@link ErrorHandler} to be invoked
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Runnable implementation that starts the ZooKeeper server.
*/
private clreplaced ServerRunnable implements Runnable {
@Override
public void run() {
try {
Properties properties = new Properties();
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID());
file.deleteOnExit();
properties.setProperty("dataDir", file.getAbsolutePath());
properties.setProperty("clientPort", String.valueOf(clientPort));
QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
quorumPeerConfig.parseProperties(properties);
zkServer = new ZooKeeperServerMain();
ServerConfig configuration = new ServerConfig();
configuration.readFrom(quorumPeerConfig);
zkServer.runFromConfig(configuration);
} catch (Exception e) {
if (errorHandler != null) {
errorHandler.handleError(e);
} else {
logger.error("Exception running embedded ZooKeeper", e);
}
}
}
}
}
19
View Source File : EmbeddedZooKeeper.java
License : Apache License 2.0
Project Creator : apache
License : Apache License 2.0
Project Creator : apache
/**
* from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java
* <p>
* Helper clreplaced to start an embedded instance of standalone (non clustered) ZooKeeper.
* <p>
* NOTE: at least an external standalone server (if not an ensemble) are recommended, even for
* {@link org.springframework.xd.dirt.server.singlenode.SingleNodeApplication}
*
* @author Patrick Peralta
* @author Mark Fisher
* @author David Turanski
*/
public clreplaced EmbeddedZooKeeper implements SmartLifecycle {
/**
* Logger.
*/
private static final Logger logger = LoggerFactory.getLogger(EmbeddedZooKeeper.clreplaced);
/**
* ZooKeeper client port. This will be determined dynamically upon startup.
*/
private final int clientPort;
/**
* Whether to auto-start. Default is true.
*/
private boolean autoStartup = true;
/**
* Lifecycle phase. Default is 0.
*/
private int phase = 0;
/**
* Thread for running the ZooKeeper server.
*/
private volatile Thread zkServerThread;
/**
* ZooKeeper server.
*/
private volatile ZooKeeperServerMain zkServer;
/**
* {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread.
*/
private ErrorHandler errorHandler;
private boolean daemon = true;
/**
* Construct an EmbeddedZooKeeper with a random port.
*/
public EmbeddedZooKeeper() {
clientPort = SocketUtils.findAvailableTcpPort();
}
/**
* Construct an EmbeddedZooKeeper with the provided port.
*
* @param clientPort port for ZooKeeper server to bind to
*/
public EmbeddedZooKeeper(int clientPort, boolean daemon) {
this.clientPort = clientPort;
this.daemon = daemon;
}
/**
* Returns the port that clients should use to connect to this embedded server.
*
* @return dynamically determined client port
*/
public int getClientPort() {
return this.clientPort;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isAutoStartup() {
return this.autoStartup;
}
/**
* Specify whether to start automatically. Default is true.
*
* @param autoStartup whether to start automatically
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
/**
* {@inheritDoc}
*/
@Override
public int getPhase() {
return this.phase;
}
/**
* Specify the lifecycle phase for the embedded server.
*
* @param phase the lifecycle phase
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRunning() {
return (zkServerThread != null);
}
/**
* Start the ZooKeeper server in a background thread.
* <p>
* Register an error handler via {@link #setErrorHandler} in order to handle
* any exceptions thrown during startup or execution.
*/
@Override
public synchronized void start() {
if (zkServerThread == null) {
zkServerThread = new Thread(new ServerRunnable(), "ZooKeeper Server Starter");
zkServerThread.setDaemon(daemon);
zkServerThread.start();
}
}
/**
* Shutdown the ZooKeeper server.
*/
@Override
public synchronized void stop() {
if (zkServerThread != null) {
// The shutdown method is protected...thus this hack to invoke it.
// This will log an exception on shutdown; see
// https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.
try {
Method shutdown = ZooKeeperServerMain.clreplaced.getDeclaredMethod("shutdown");
shutdown.setAccessible(true);
shutdown.invoke(zkServer);
} catch (Exception e) {
throw new RuntimeException(e);
}
// It is expected that the thread will exit after
// the server is shutdown; this will block until
// the shutdown is complete.
try {
zkServerThread.join(5000);
zkServerThread = null;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.warn("Interrupted while waiting for embedded ZooKeeper to exit");
// abandoning zk thread
zkServerThread = null;
}
}
}
/**
* Stop the server if running and invoke the callback when complete.
*/
@Override
public void stop(Runnable callback) {
stop();
callback.run();
}
/**
* Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none
* is provided, only error-level logging will occur.
*
* @param errorHandler the {@link ErrorHandler} to be invoked
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Runnable implementation that starts the ZooKeeper server.
*/
private clreplaced ServerRunnable implements Runnable {
@Override
public void run() {
try {
Properties properties = new Properties();
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID());
file.deleteOnExit();
properties.setProperty("dataDir", file.getAbsolutePath());
properties.setProperty("clientPort", String.valueOf(clientPort));
QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
quorumPeerConfig.parseProperties(properties);
zkServer = new ZooKeeperServerMain();
ServerConfig configuration = new ServerConfig();
configuration.readFrom(quorumPeerConfig);
zkServer.runFromConfig(configuration);
} catch (Exception e) {
if (errorHandler != null) {
errorHandler.handleError(e);
} else {
logger.error("Exception running embedded ZooKeeper", e);
}
}
}
}
}
19
View Source File : SpringRabbitMQComponentConfiguration.java
License : Apache License 2.0
Project Creator : apache
License : Apache License 2.0
Project Creator : apache
/**
* Send and receive messages from RabbitMQ using Spring RabbitMQ client.
*
* Generated by camel-package-maven-plugin - do not edit this file!
*/
@Generated("org.apache.camel.springboot.maven.SpringBootAutoConfigurationMojo")
@ConfigurationProperties(prefix = "camel.component.spring-rabbitmq")
public clreplaced SpringRabbitMQComponentConfiguration extends ComponentConfigurationPropertiesCommon {
/**
* Whether to enable auto configuration of the spring-rabbitmq component.
* This is enabled by default.
*/
private Boolean enabled;
/**
* Optional AMQP Admin service to use for auto declaring elements (queues,
* exchanges, bindings). The option is a
* org.springframework.amqp.core.AmqpAdmin type.
*/
private AmqpAdmin amqpAdmin;
/**
* The connection factory to be use. A connection factory must be configured
* either on the component or endpoint. The option is a
* org.springframework.amqp.rabbit.connection.ConnectionFactory type.
*/
private ConnectionFactory connectionFactory;
/**
* Specifies whether to test the connection on startup. This ensures that
* when Camel starts that all the JMS consumers have a valid connection to
* the JMS broker. If a connection cannot be granted then Camel throws an
* exception on startup. This ensures that Camel is not started with failed
* connections. The JMS producers is tested as well.
*/
private Boolean testConnectionOnStartup = false;
/**
* Specifies whether the consumer should auto declare binding between
* exchange, queue and routing key when starting. Enabling this can be good
* for development to make it easy to standup exchanges, queues and bindings
* on the broker.
*/
private Boolean autoDeclare = false;
/**
* Specifies whether the consumer container should auto-startup.
*/
private Boolean autoStartup = true;
/**
* Allows for bridging the consumer to the Camel routing Error Handler,
* which mean any exceptions occurred while the consumer is trying to pickup
* incoming messages, or the likes, will now be processed as a message and
* handled by the routing Error Handler. By default the consumer will use
* the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that
* will be logged at WARN or ERROR level and ignored.
*/
private Boolean bridgeErrorHandler = false;
/**
* The name of the dead letter exchange
*/
private String deadLetterExchange;
/**
* The type of the dead letter exchange
*/
private String deadLetterExchangeType = "direct";
/**
* The name of the dead letter queue
*/
private String deadLetterQueue;
/**
* The routing key for the dead letter exchange
*/
private String deadLetterRoutingKey;
/**
* How many times a Rabbitmq consumer will retry the same message if Camel
* failed to process the message
*/
private Integer maximumRetryAttempts = 5;
/**
* Whether a Rabbitmq consumer should reject the message without requeuing.
* This enables failed messages to be sent to a Dead Letter Exchange/Queue,
* if the broker is so configured.
*/
private Boolean rejectAndDontRequeue = true;
/**
* Delay in msec a Rabbitmq consumer will wait before redelivering a message
* that Camel failed to process
*/
private Integer retryDelay = 1000;
/**
* The number of consumers
*/
private Integer concurrentConsumers = 1;
/**
* To use a custom ErrorHandler for handling exceptions from the message
* listener (consumer). The option is a
* org.springframework.util.ErrorHandler type.
*/
private ErrorHandler errorHandler;
/**
* To use a custom factory for creating and configuring ListenerContainer to
* be used by the consumer for receiving messages. The option is a
* org.apache.camel.component.springrabbit.ListenerContainerFactory type.
*/
private ListenerContainerFactory listenerContainerFactory;
/**
* The maximum number of consumers (available only with SMLC)
*/
private Integer maxConcurrentConsumers;
/**
* The type of the MessageListenerContainer
*/
private String messageListenerContainerType = "DMLC";
/**
* Tell the broker how many messages to send to each consumer in a single
* request. Often this can be set quite high to improve throughput.
*/
private Integer prefetchCount = 250;
/**
* Custom retry configuration to use. If this is configured then the other
* settings such as maximumRetryAttempts for retry are not in use. The
* option is a
* org.springframework.retry.interceptor.RetryOperationsInterceptor type.
*/
private RetryOperationsInterceptor retry;
/**
* The time to wait for workers in milliseconds after the container is
* stopped. If any workers are active when the shutdown signal comes they
* will be allowed to finish processing as long as they can finish within
* this timeout. The option is a long type.
*/
private Long shutdownTimeout = 5000L;
/**
* Whether the producer should be started lazy (on the first message). By
* starting lazy you can use this to allow CamelContext and routes to
* startup in situations where a producer may otherwise fail during starting
* and cause the route to fail being started. By deferring this startup to
* be lazy then the startup failure can be handled during routing messages
* via Camel's routing error handlers. Beware that when the first message is
* processed then creating and starting the producer may take a little time
* and prolong the total processing time of the processing.
*/
private Boolean lazyStartProducer = false;
/**
* Specify the timeout in milliseconds to be used when waiting for a reply
* message when doing request/reply messaging. The default value is 5
* seconds. A negative value indicates an indefinite timeout. The option is
* a long type.
*/
private Long replyTimeout = 5000L;
/**
* Whether autowiring is enabled. This is used for automatic autowiring
* options (the option must be marked as autowired) by looking up in the
* registry to find if there is a single instance of matching type, which
* then gets configured on the component. This can be used for automatic
* configuring JDBC data sources, JMS connection factories, AWS Clients,
* etc.
*/
private Boolean autowiredEnabled = true;
/**
* Switch on ignore exceptions such as mismatched properties when declaring
*/
private Boolean ignoreDeclarationExceptions = false;
/**
* To use a custom MessageConverter so you can be in control how to map
* to/from a org.springframework.amqp.core.Message. The option is a
* org.springframework.amqp.support.converter.MessageConverter type.
*/
private MessageConverter messageConverter;
/**
* To use a custom MessagePropertiesConverter so you can be in control how
* to map to/from a org.springframework.amqp.core.MessageProperties. The
* option is a
* org.apache.camel.component.springrabbit.MessagePropertiesConverter type.
*/
private MessagePropertiesConverter messagePropertiesConverter;
/**
* To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter
* header to and from Camel message. The option is a
* org.apache.camel.spi.HeaderFilterStrategy type.
*/
private HeaderFilterStrategy headerFilterStrategy;
public AmqpAdmin getAmqpAdmin() {
return amqpAdmin;
}
public void setAmqpAdmin(AmqpAdmin amqpAdmin) {
this.amqpAdmin = amqpAdmin;
}
public ConnectionFactory getConnectionFactory() {
return connectionFactory;
}
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public Boolean getTestConnectionOnStartup() {
return testConnectionOnStartup;
}
public void setTestConnectionOnStartup(Boolean testConnectionOnStartup) {
this.testConnectionOnStartup = testConnectionOnStartup;
}
public Boolean getAutoDeclare() {
return autoDeclare;
}
public void setAutoDeclare(Boolean autoDeclare) {
this.autoDeclare = autoDeclare;
}
public Boolean getAutoStartup() {
return autoStartup;
}
public void setAutoStartup(Boolean autoStartup) {
this.autoStartup = autoStartup;
}
public Boolean getBridgeErrorHandler() {
return bridgeErrorHandler;
}
public void setBridgeErrorHandler(Boolean bridgeErrorHandler) {
this.bridgeErrorHandler = bridgeErrorHandler;
}
public String getDeadLetterExchange() {
return deadLetterExchange;
}
public void setDeadLetterExchange(String deadLetterExchange) {
this.deadLetterExchange = deadLetterExchange;
}
public String getDeadLetterExchangeType() {
return deadLetterExchangeType;
}
public void setDeadLetterExchangeType(String deadLetterExchangeType) {
this.deadLetterExchangeType = deadLetterExchangeType;
}
public String getDeadLetterQueue() {
return deadLetterQueue;
}
public void setDeadLetterQueue(String deadLetterQueue) {
this.deadLetterQueue = deadLetterQueue;
}
public String getDeadLetterRoutingKey() {
return deadLetterRoutingKey;
}
public void setDeadLetterRoutingKey(String deadLetterRoutingKey) {
this.deadLetterRoutingKey = deadLetterRoutingKey;
}
public Integer getMaximumRetryAttempts() {
return maximumRetryAttempts;
}
public void setMaximumRetryAttempts(Integer maximumRetryAttempts) {
this.maximumRetryAttempts = maximumRetryAttempts;
}
public Boolean getRejectAndDontRequeue() {
return rejectAndDontRequeue;
}
public void setRejectAndDontRequeue(Boolean rejectAndDontRequeue) {
this.rejectAndDontRequeue = rejectAndDontRequeue;
}
public Integer getRetryDelay() {
return retryDelay;
}
public void setRetryDelay(Integer retryDelay) {
this.retryDelay = retryDelay;
}
public Integer getConcurrentConsumers() {
return concurrentConsumers;
}
public void setConcurrentConsumers(Integer concurrentConsumers) {
this.concurrentConsumers = concurrentConsumers;
}
public ErrorHandler getErrorHandler() {
return errorHandler;
}
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
public ListenerContainerFactory getListenerContainerFactory() {
return listenerContainerFactory;
}
public void setListenerContainerFactory(ListenerContainerFactory listenerContainerFactory) {
this.listenerContainerFactory = listenerContainerFactory;
}
public Integer getMaxConcurrentConsumers() {
return maxConcurrentConsumers;
}
public void setMaxConcurrentConsumers(Integer maxConcurrentConsumers) {
this.maxConcurrentConsumers = maxConcurrentConsumers;
}
public String getMessageListenerContainerType() {
return messageListenerContainerType;
}
public void setMessageListenerContainerType(String messageListenerContainerType) {
this.messageListenerContainerType = messageListenerContainerType;
}
public Integer getPrefetchCount() {
return prefetchCount;
}
public void setPrefetchCount(Integer prefetchCount) {
this.prefetchCount = prefetchCount;
}
public RetryOperationsInterceptor getRetry() {
return retry;
}
public void setRetry(RetryOperationsInterceptor retry) {
this.retry = retry;
}
public Long getShutdownTimeout() {
return shutdownTimeout;
}
public void setShutdownTimeout(Long shutdownTimeout) {
this.shutdownTimeout = shutdownTimeout;
}
public Boolean getLazyStartProducer() {
return lazyStartProducer;
}
public void setLazyStartProducer(Boolean lazyStartProducer) {
this.lazyStartProducer = lazyStartProducer;
}
public Long getReplyTimeout() {
return replyTimeout;
}
public void setReplyTimeout(Long replyTimeout) {
this.replyTimeout = replyTimeout;
}
public Boolean getAutowiredEnabled() {
return autowiredEnabled;
}
public void setAutowiredEnabled(Boolean autowiredEnabled) {
this.autowiredEnabled = autowiredEnabled;
}
public Boolean getIgnoreDeclarationExceptions() {
return ignoreDeclarationExceptions;
}
public void setIgnoreDeclarationExceptions(Boolean ignoreDeclarationExceptions) {
this.ignoreDeclarationExceptions = ignoreDeclarationExceptions;
}
public MessageConverter getMessageConverter() {
return messageConverter;
}
public void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
public MessagePropertiesConverter getMessagePropertiesConverter() {
return messagePropertiesConverter;
}
public void setMessagePropertiesConverter(MessagePropertiesConverter messagePropertiesConverter) {
this.messagePropertiesConverter = messagePropertiesConverter;
}
public HeaderFilterStrategy getHeaderFilterStrategy() {
return headerFilterStrategy;
}
public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) {
this.headerFilterStrategy = headerFilterStrategy;
}
}
19
View Source File : SpringRabbitMQComponentConfiguration.java
License : Apache License 2.0
Project Creator : apache
License : Apache License 2.0
Project Creator : apache
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
18
View Source File : ThreadPoolTaskScheduler.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
@Override
public <T> Future<T> submit(Callable<T> task) {
ExecutorService executor = getScheduledExecutor();
try {
Callable<T> taskToUse = task;
ErrorHandler errorHandler = this.errorHandler;
if (errorHandler != null) {
taskToUse = new DelegatingErrorHandlingCallable<>(task, errorHandler);
}
return executor.submit(taskToUse);
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
18
View Source File : ThreadPoolTaskScheduler.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
// TaskScheduler implementation
@Override
@Nullable
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
ScheduledExecutorService executor = getScheduledExecutor();
try {
ErrorHandler errorHandler = this.errorHandler;
if (errorHandler == null) {
errorHandler = TaskUtils.getDefaultErrorHandler(true);
}
return new ReschedulingRunnable(task, trigger, executor, errorHandler).schedule();
} catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
18
View Source File : SimpleApplicationEventMulticaster.java
License : MIT License
Project Creator : Vip-Augus
License : MIT License
Project Creator : Vip-Augus
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
doInvokeListener(listener, event);
}
}
18
View Source File : TracedThreadPoolTaskSchedulerTest.java
License : Apache License 2.0
Project Creator : opentracing-contrib
License : Apache License 2.0
Project Creator : opentracing-contrib
@Test
public void setErrorHandler() {
final ErrorHandler errorHandler = mock(ErrorHandler.clreplaced);
scheduler.setErrorHandler(errorHandler);
verify(delegate).setErrorHandler(errorHandler);
}
18
View Source File : TracedThreadPoolTaskScheduler.java
License : Apache License 2.0
Project Creator : opentracing-contrib
License : Apache License 2.0
Project Creator : opentracing-contrib
@Override
public void setErrorHandler(ErrorHandler errorHandler) {
delegate.setErrorHandler(errorHandler);
}
See More Examples