/*
* Copyright 2002-2016 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.endpoint;
import java.lang.reflect.Method;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.Lifecycle;
import org.springframework.integration.core.MessageSource;
import org.springframework.messaging.MessagingException;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* A {@link MessageSource} implementation that invokes a no-argument method so
* that its return value may be sent to a channel.
*
* @author Mark Fisher
* @author Gary Russell
* @author Artem Bilan
*/
public class MethodInvokingMessageSource extends AbstractMessageSource<Object>
implements InitializingBean, Lifecycle {
private volatile Object object;
private volatile Method method;
private volatile String methodName;
private volatile boolean initialized;
private final Object initializationMonitor = new Object();
public void setObject(Object object) {
Assert.notNull(object, "'object' must not be null");
this.object = object;
}
public void setMethod(Method method) {
Assert.notNull(method, "'method' must not be null");
this.method = method;
}
public void setMethodName(String methodName) {
Assert.notNull(methodName, "'methodName' must not be null");
this.methodName = methodName;
}
@Override
public String getComponentType() {
return "inbound-channel-adapter";
}
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
synchronized (this.initializationMonitor) {
if (this.initialized) {
return;
}
Assert.notNull(this.object, "object is required");
Assert.isTrue(this.method != null || this.methodName != null, "method or methodName is required");
if (this.method == null) {
this.method = ReflectionUtils.findMethod(this.object.getClass(), this.methodName);
Assert.notNull(this.method, "no such method '" + this.methodName
+ "' is available on " + this.object.getClass());
}
Assert.isTrue(!void.class.equals(this.method.getReturnType()),
"invalid MessageSource method '" + this.method.getName() + "', a non-void return is required");
this.method.setAccessible(true);
this.initialized = true;
}
}
@Override
public void start() {
if (this.object instanceof Lifecycle) {
((Lifecycle) this.object).start();
}
}
@Override
public void stop() {
if (this.object instanceof Lifecycle) {
((Lifecycle) this.object).stop();
}
}
@Override
public boolean isRunning() {
return !(this.object instanceof Lifecycle) || ((Lifecycle) this.object).isRunning();
}
@Override
protected Object doReceive() {
try {
if (!this.initialized) {
this.afterPropertiesSet();
}
return ReflectionUtils.invokeMethod(this.method, this.object);
}
catch (Exception e) {
throw new MessagingException("Failed to invoke method", e);
}
}
}