package org.oddjob.beanbus.mega;
import java.lang.reflect.Method;
import java.util.Collection;
import org.oddjob.arooa.ArooaAnnotations;
import org.oddjob.arooa.ArooaBeanDescriptor;
import org.oddjob.arooa.ArooaSession;
import org.oddjob.arooa.ComponentTrinity;
import org.oddjob.arooa.deploy.ArooaAnnotationsUtil;
import org.oddjob.arooa.reflect.ArooaPropertyException;
import org.oddjob.arooa.reflect.PropertyAccessor;
import org.oddjob.arooa.registry.ComponentPool;
import org.oddjob.beanbus.Destination;
import org.oddjob.beanbus.Outbound;
/**
* A collection of different {@link OutboundStrategy}s that are applied to
* a component to see if it can be adapted to an {@link Outbound}.
*
* @author rob
*
*/
public class OutboundStrategies implements OutboundStrategy {
@Override
public <T> Outbound<T> outboundFor(Object component,
ArooaSession session) {
Outbound<T> outbound =
isOutboundAlreadyStrategy().outboundFor(
component, session);
if (outbound == null) {
outbound = hasDestinationAnnotationStrategy().outboundFor(
component, session);
}
return outbound;
}
/**
* Provides a strategy that checks to see if the component is a
* {@link Outbound} already.
*
* @return
*/
public OutboundStrategy isOutboundAlreadyStrategy() {
return new OutboundStrategy() {
@SuppressWarnings("unchecked")
@Override
public <T> Outbound<T> outboundFor(Object component,
ArooaSession session) {
if (component instanceof Outbound) {
return ((Outbound<T>) component);
}
else {
return null;
}
}
};
}
/**
* Provides a strategy base on the {@link Destination} annotation.
*
* @return
*/
public OutboundStrategy hasDestinationAnnotationStrategy() {
return new OutboundStrategy() {
@Override
public <T> Outbound<T> outboundFor(Object component,
ArooaSession session) {
// The component may be a proxy so we have to find
// the wrapped component.
ComponentPool componentPool = session.getComponentPool();
ComponentTrinity trinity = componentPool.trinityFor(
component);
final Object realComponent = trinity.getTheComponent();
final PropertyAccessor accessor =
session.getTools().getPropertyAccessor();
ArooaBeanDescriptor beanDescriptor =
session.getArooaDescriptor().getBeanDescriptor(
accessor.getClassName(realComponent),
accessor);
ArooaAnnotations annotations =
beanDescriptor.getAnnotations();
final Method setToMethod = annotations.methodFor(Destination.class.getName());
if (setToMethod != null) {
return new Outbound<T>() {
@Override
public void setTo(Collection<? super T> destination) {
try {
setToMethod.invoke(realComponent, destination);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
}
final String property = new ArooaAnnotationsUtil(
annotations).findSingleAnnotatedProperty(
Destination.class.getName());
if (property != null) {
return new Outbound<T>() {
@Override
public void setTo(Collection<? super T> destination) {
try {
accessor.setProperty(realComponent,
property, destination);
} catch (ArooaPropertyException e) {
throw e;
} catch (RuntimeException e) {
throw e;
}
}
};
}
return null;
}
};
}
}