Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

INT-2935: Improve AELMP performance #750

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,38 +1,36 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Copyright 2002-2013 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.gemfire.inbound;
package org.springframework.integration.endpoint;

import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.integration.endpoint.MessageProducerSupport;

/**
* A {@link MessageProducerSupport} sub-class that provides {@linkplain #payloadExpression}
* evaluation with result as a payload for Message to send.
*
* @author David Turanski
* @author Artem Bilan
* @since 2.1
*
*/
abstract class SpelMessageProducerSupport extends MessageProducerSupport {

private volatile Expression payloadExpression;
public abstract class ExpressionMessageProducerSupport extends MessageProducerSupport {

private final SpelExpressionParser parser = new SpelExpressionParser();


@Override
protected void onInit(){
super.onInit();
}

private volatile Expression payloadExpression;

public void setPayloadExpression(String payloadExpression) {
if (payloadExpression == null) {
this.payloadExpression = null;
Expand All @@ -41,14 +39,13 @@ public void setPayloadExpression(String payloadExpression) {
this.payloadExpression = this.parser.parseExpression(payloadExpression);
}
}
protected Object evaluationResult(Object payload){

protected Object evaluatePayloadExpression(Object payload){
Object evaluationResult = payload;
if (payloadExpression != null) {
evaluationResult = payloadExpression.getValue(payload);
}
return evaluationResult;
}


}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2013 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.
Expand All @@ -16,85 +16,111 @@

package org.springframework.integration.event.inbound;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.integration.Message;
import org.springframework.integration.endpoint.MessageProducerSupport;
import org.springframework.integration.endpoint.ExpressionMessageProducerSupport;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
* An inbound Channel Adapter that passes Spring {@link ApplicationEvent ApplicationEvents} within messages.
* An inbound Channel Adapter that implements {@link ApplicationListener} and
* passes Spring {@link ApplicationEvent ApplicationEvents} within messages.
* If a {@link #setPayloadExpression(String) 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
* @see ApplicationEventMulticaster
* @see ExpressionMessageProducerSupport
*/
public class ApplicationEventListeningMessageProducer extends MessageProducerSupport implements ApplicationListener<ApplicationEvent> {
public class ApplicationEventListeningMessageProducer extends ExpressionMessageProducerSupport implements SmartApplicationListener {

private final Set<Class<? extends ApplicationEvent>> eventTypes = new CopyOnWriteArraySet<Class<? extends ApplicationEvent>>();
private volatile Set<Class<? extends ApplicationEvent>> eventTypes;

private volatile Expression payloadExpression;
private ApplicationEventMulticaster applicationEventMulticaster;

private volatile boolean active;

private final SpelExpressionParser parser = new SpelExpressionParser();


/**
* 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 additional this method re-register current instance as a {@link ApplicationListener}
* in the {@link ApplicationEventMulticaster} to clear listeners cache and get a fresh cache entry
* on next appropriate {@link ApplicationEvent}.
*
* @see ApplicationEventMulticaster#addApplicationListener
* @see #supportsEventType
*/
@SuppressWarnings("unchecked")
public void setEventTypes(Class<? extends ApplicationEvent>[] eventTypes) {
Assert.notEmpty(eventTypes, "at least one event type is required");
synchronized (this.eventTypes) {
this.eventTypes.clear();
this.eventTypes.addAll(CollectionUtils.arrayToList(eventTypes));
}
}
public void setEventTypes(Class<? extends ApplicationEvent>... eventTypes) {
Set<Class<? extends ApplicationEvent>> eventSet = new HashSet<Class<? extends ApplicationEvent>>(CollectionUtils.arrayToList(eventTypes));
eventSet.remove(null);
this.eventTypes = (eventSet.size() > 0 ? eventSet : null);

/**
* Provide an expression to be evaluated against the received ApplicationEvent
* instance (the "root object") in order to create the Message payload. If none
* is provided, the ApplicationEvent itself will be used as the payload.
*/
public void setPayloadExpression(String payloadExpression) {
if (payloadExpression == null) {
this.payloadExpression = null;
}
else {
this.payloadExpression = this.parser.parseExpression(payloadExpression);
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(this);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last comment 😄 (I hope!)

I wonder if we should detect eventTypes.length == 1 && eventTypes[0] == null and reset the field to null in that case? (just like if we had never set an event type list).

Of course, they can always set it to ApplicationEvent to get all events.

Also, aside from the only element being null, maybe an Assert.noNullElements() ??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gery, it's very serious catch:

adapter.setEventTypes((Class<? extends ApplicationEvent>) null);

ends up with NPE now.
So, will be fixed soon.

}

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.");
}

public void onApplicationEvent(ApplicationEvent event) {
if (this.active || event instanceof ApplicationContextEvent) {
if (CollectionUtils.isEmpty(this.eventTypes)) {
this.sendEventAsMessage(event);
return;
if (event.getSource() instanceof Message<?>) {
this.sendMessage((Message<?>) event.getSource());
}
for (Class<? extends ApplicationEvent> eventType : this.eventTypes) {
if (eventType.isAssignableFrom(event.getClass())) {
this.sendEventAsMessage(event);
return;
}
else {
Object payload = this.evaluatePayloadExpression(event);
this.sendMessage(MessageBuilder.withPayload(payload).build());
}
}
}

public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
if (this.eventTypes == null) {
return true;
}
for (Class<? extends ApplicationEvent> type : this.eventTypes) {
if (type.isAssignableFrom(eventType)) {
return true;
}
}
return false;
}

public boolean supportsSourceType(Class<?> sourceType) {
return true;
}

public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}

@Override
protected void doStart() {
this.active = true;
Expand All @@ -105,14 +131,5 @@ protected void doStop() {
this.active = false;
}

private void sendEventAsMessage(ApplicationEvent event) {
if (event.getSource() instanceof Message<?>) {
this.sendMessage((Message<?>) event.getSource());
}
else {
Object payload = (this.payloadExpression != null) ? this.payloadExpression.getValue(event) : event;
this.sendMessage(MessageBuilder.withPayload(payload).build());
}
}

}

4 changes: 2 additions & 2 deletions spring-integration-event/src/test/java/log4j.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ log4j.rootCategory=WARN, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%c{1}: %m%n
log4j.appender.stdout.layout.ConversionPattern=%c{1}: (%t) %m%n

log4j.category.org.springframework.integration=WARN
log4j.category.org.springframework.integration.file=WARN
log4j.category.org.springframework.integration.event=INFO
Loading