/* * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.integration.event.inbound; import java.util.HashSet; import java.util.Set; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.PayloadApplicationEvent; import org.springframework.context.event.ApplicationEventMulticaster; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextStoppedEvent; import org.springframework.context.event.GenericApplicationListener; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.core.Ordered; import org.springframework.core.ResolvableType; import org.springframework.integration.endpoint.ExpressionMessageProducerSupport; import org.springframework.messaging.Message; import org.springframework.util.Assert; /** * An inbound Channel Adapter that implements {@link ApplicationListener} and * passes Spring {@link ApplicationEvent ApplicationEvents} within messages. * If a {@link #setPayloadExpression payloadExpression} is provided, it will be evaluated against * the ApplicationEvent instance to create the Message payload. Otherwise, the event itself will be the payload. * * @author Mark Fisher * @author Artem Bilan * @author Gary Russell * @see ApplicationEventMulticaster * @see ExpressionMessageProducerSupport */ public class ApplicationEventListeningMessageProducer extends ExpressionMessageProducerSupport implements GenericApplicationListener { private volatile Set<ResolvableType> eventTypes; private ApplicationEventMulticaster applicationEventMulticaster; private volatile boolean active; private volatile long stoppedAt; public ApplicationEventListeningMessageProducer() { setPhase(Integer.MAX_VALUE / 2 - 1000); } /** * Set the list of event types (classes that extend ApplicationEvent) that * this adapter should send to the message channel. By default, all event * types will be sent. * In addition, this method re-registers the current instance as a {@link ApplicationListener} * with the {@link ApplicationEventMulticaster} which clears the listener cache. The cache will be * refreshed on the next appropriate {@link ApplicationEvent}. * * @param eventTypes The event types. * @see ApplicationEventMulticaster#addApplicationListener * @see #supportsEventType */ public final void setEventTypes(Class<?>... eventTypes) { Assert.notNull(eventTypes, "'eventTypes' must not be null"); Set<ResolvableType> eventSet = new HashSet<ResolvableType>(eventTypes.length); for (Class<?> eventType : eventTypes) { if (eventType != null) { eventSet.add(ResolvableType.forClass(eventType)); } } this.eventTypes = (eventSet.size() > 0 ? eventSet : null); if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.addApplicationListener(this); } } @Override public String getComponentType() { return "event:inbound-channel-adapter"; } @Override protected void onInit() { super.onInit(); this.applicationEventMulticaster = this.getBeanFactory() .getBean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); Assert.notNull(this.applicationEventMulticaster, "To use ApplicationListeners the 'applicationEventMulticaster' " + "bean must be supplied within ApplicationContext."); } @Override public void onApplicationEvent(ApplicationEvent event) { if (this.active || ((event instanceof ContextStoppedEvent || event instanceof ContextClosedEvent) && this.stoppedRecently())) { if (event.getSource() instanceof Message<?>) { this.sendMessage((Message<?>) event.getSource()); } else { Message<?> message = null; Object result = extractObjectToSend(event); if (result instanceof Message) { message = (Message<?>) result; } else { message = this.getMessageBuilderFactory().withPayload(result).build(); } this.sendMessage(message); } } } private Object extractObjectToSend(Object root) { if (root instanceof PayloadApplicationEvent) { return ((PayloadApplicationEvent<?>) root).getPayload(); } return evaluatePayloadExpression(root); } private boolean stoppedRecently() { return this.stoppedAt > System.currentTimeMillis() - 5000; } @Override public boolean supportsEventType(ResolvableType eventType) { if (this.eventTypes == null) { return true; } for (ResolvableType type : this.eventTypes) { if (type.isAssignableFrom(eventType)) { return true; } } if (eventType.getRawClass() != null && PayloadApplicationEvent.class.isAssignableFrom(eventType.getRawClass())) { if (eventType.hasUnresolvableGenerics()) { return true; } ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric(); for (ResolvableType type : this.eventTypes) { if (type.isAssignableFrom(payloadType)) { return true; } } } return false; } @Override public boolean supportsSourceType(Class<?> sourceType) { return true; } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } @Override protected void doStart() { this.active = true; } @Override protected void doStop() { this.stoppedAt = System.currentTimeMillis(); this.active = false; } }