Reputation: 2242
I have a set of beans that implement an interface. I want to multicast an incoming message to an explicit (sub)set of these beans using a method from this interface. The method call will result in a List<Object>
for each bean. I want to aggregate all the lists into one big list and pass that on to the next route.
My first approach was to create a route for each bean that passes the result to the aggregation route. However I think I lose the type-safety that I tried to enforce with the interface. (In other words, I cannot prevent other people from adding beans to the multicast that do not implement the interface. I believe this could lead to an error in my aggregation strategy at runtime (e.g. body is not a list).)
The Interface:
public interface Reporter {
List<Object> report();
}
An example of the routes I created for each bean that implements the interface:
<route>
<from uri="direct:bean1"/>
<bean ref="reporterOfSomething" method="report"/>
<to uri="seda:aggregate"/>
</route>
My current approach is to create a list bean with a value-type attribute referencing the Reporter interface and adding the implementing beans to this list. This way I have my types checked by the scheme validation, not just when the route is called. However I couldn't figure out how to multicast the incoming message to each bean in the list.
<util:list id="reporters" value-type="Reporter"><!-- i.e. the interface -->
<ref bean="reporterOfSomething"/>
<ref bean="reporterOfSomethingElse"/>
</util:list>
So I have the feeling that I'm either overcomplicating things or just not using the right constructs.
How can I call all these beans and have some form of type-safety (e.g. Intellij complains that I violate the scheme when I pass a bean of the wrong type or the application could crash during startup or some other way that will cause a compile/scheme/initialization error)?
Upvotes: 2
Views: 1428
Reputation: 7646
Define a processor that iterates over the reporting beans and aggregates the results of the single reporter beans:
public class ReporterProcessor implements Processor {
private List<Reporter> reporters;
@Override
public void process(final Exchange exchange) throws Exception {
List<Object> aggregatedList = new ArrayList<>();
for (final ReporterBean reporter : reporters) {
aggregatedList.add(reporter.report(exchange));
}
exchange.getIn().setBody(aggregatedList);
}
public void setReporters(final List<Reporter> reporters) {
this.reporters = reporters;
}
}
Camel route definition:
<util:list id="reporterList" value-type="Reporter"> <!-- i.e. the interface -->
<ref bean="reporterOfSomething"/>
<ref bean="reporterOfSomethingElse"/>
</util:list>
<bean id="reporterProcessor" class="ReporterProcessor">
<property name="reporters" ref="reporterList" />
</bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:bean1"/>
<process ref="reporterProcessor"/>
<to uri="seda:aggregate"/>
</route>
</camelContext>
That way, all the results of the single reporter beans are aggregated and passed to seda:aggregate
.
Upvotes: 1
Reputation: 1519
Upvotes: 0
Reputation: 3497
Maybe you can use an observer pattern, like described at Wikipedia: http://en.wikipedia.org/wiki/Observer_pattern
It is designed for passing messages around. Otherwise you also can have a look at CompleteableFuture which can send messages (a)synchronously on completion.
Upvotes: 0