Hi, all. I was talking about this on the users list, but I found out about
the dev list, so I wanted to share this question with fellow camel
devs/contributors.
I am adding JMX reporting and control to my dynamic router eip component
(not the original dynamic router that you can use with the DSL in core). I
have two services that I annotated with camel-management annotations:
For JMX control (things removed for brevity):
@Converter(generateBulkLoader = true)
@ManagedResource(description = "Dynamic Router control operations service")
public class DynamicRouterControlService extends ServiceSupport {
private final CamelContext camelContext;
private final DynamicRouterFilterService filterService;
public DynamicRouterControlService(CamelContext camelContext,
DynamicRouterFilterService
filterService) {
this.camelContext = camelContext;
this.filterService = filterService;
}
@ManagedOperation(description = "Subscribe for dynamic routing
with a predicate expression")
public String subscribeWithPredicateExpression(
String subscribeChannel,
String subscriptionId,
String destinationUri,
int priority,
String predicate,
String expressionLanguage,
boolean update) {
return filterService.addFilterForChannel(subscriptionId, priority,
obtainPredicateFromExpression(camelContext, predicate,
expressionLanguage),
destinationUri, subscribeChannel, update);
}
@ManagedOperation(description = "Subscribe for dynamic routing
with the name of a predicate bean in the registry")
public String subscribeWithPredicateBean(
String subscribeChannel,
String subscriptionId,
String destinationUri,
int priority,
String predicateBean,
boolean update) {
return filterService.addFilterForChannel(subscriptionId, priority,
obtainPredicateFromBeanName(predicateBean, camelContext),
destinationUri, subscribeChannel, update);
}
@ManagedOperation(description = "Subscribe for dynamic routing
with a predicate instance")
public String subscribeWithPredicateInstance(
String subscribeChannel,
String subscriptionId,
String destinationUri,
int priority,
Object predicate,
boolean update) {
return filterService.addFilterForChannel(subscriptionId,
priority, obtainPredicateFromInstance(predicate),
destinationUri, subscribeChannel, update);
}
@ManagedOperation(description = "Unsubscribe for dynamic routing
on a channel by subscription ID")
public boolean removeSubscription(
String subscribeChannel,
String subscriptionId) {
return filterService.removeFilterById(subscriptionId, subscribeChannel);
}
@Override
public void start() {
// no-op
}
@Override
public void stop() {
// no-op
}
}
For reporting/monitoring (things removed for brevity):
@ManagedResource(description = "Dynamic Router filter service")
public class DynamicRouterFilterService extends ServiceSupport {
private final Map<String,
ConcurrentSkipListSet<PrioritizedFilter>> filterMap = new
ConcurrentHashMap<>();
private final Map<String, List<PrioritizedFilterStatistics>>
filterStatisticsMap = new ConcurrentHashMap<>();
private final Supplier<PrioritizedFilterFactory> filterFactorySupplier;
public DynamicRouterFilterService(final
Supplier<PrioritizedFilterFactory> filterFactorySupplier) {
this.filterFactorySupplier = filterFactorySupplier;
LOG.debug("Created Dynamic Router component");
}
@ManagedAttribute(description = "Get the list of filters for the
specified dynamic router channel")
public Collection<PrioritizedFilter> getFiltersForChannel(final
String channel) {
return List.copyOf(filterMap.get(channel));
}
@ManagedAttribute(description = "Get the map of filters for all
dynamic router channels")
public Map<String, ConcurrentSkipListSet<PrioritizedFilter>>
getFilterMap() {
return Map.copyOf(filterMap);
}
@ManagedAttribute(description = "Get the set of filter statistics
for the specified dynamic router channel")
public List<PrioritizedFilterStatistics>
getStatisticsForChannel(final String channel) {
return List.copyOf(filterStatisticsMap.get(channel));
}
@ManagedAttribute(description = "Get the map of statistics for all
dynamic router channels")
public Map<String, List<PrioritizedFilterStatistics>>
getFilterStatisticsMap() {
return Map.copyOf(filterStatisticsMap);
}
@Override
public void start() {
// no-op
}
@Override
public void stop() {
// no-op
}
}
I want to write a test that verifies that camel is registering these. I
have added camel-management to my pom in the "test" scope. I originally
tried to use a test annotated with @CamelSpringTest, but I could not it to
work, and when I tried to get the ManagementAgent, it was always null. So
I switched to a normal test that extends CamelTestSupport, and now I can at
least get the agent and the MBeanServer. Here is my test class:
class DynamicRouterManagementIT extends CamelTestSupport {
@Override
protected boolean useJmx() {
return true;
}
@Test
void testExpectedMbeansExist() throws MalformedObjectNameException {
MBeanServer mBeanServer =
context.getManagementStrategy().getManagementAgent().getMBeanServer();
String names = mBeanServer.queryNames(null, null).stream()
.map(ObjectName::getCanonicalName)
.filter(name -> name.contains("ynamic"))
.collect(Collectors.joining("\n"));
System.err.println("MBean names:\n" + names);
}
@Override
protected RoutesBuilder createRouteBuilder() {
return new RouteBuilder() {
@Override
public void configure() {
from("direct:subscribe").to("dynamic-router-control:subscribe");
from("direct:command").to("dynamic-router:test");
}
};
}
}
The output does not show either of the two @ManagedResource classes. Here
is the output:
MBean names:
>
> org.apache.camel:context=camel-1,name="dynamic-router-control",type=components
> org.apache.camel:context=camel-1,name="dynamic-router",type=components
>
> org.apache.camel:context=camel-1,name="dynamic-router-control://subscribe",type=endpoints
>
> org.apache.camel:context=camel-1,name=DynamicRouterProducer(0x511505e7),type=producers
>
> org.apache.camel:context=camel-1,name=DynamicRouterControlProducer(0x70abf9b0),type=producers
>
> org.apache.camel:context=camel-1,name="dynamic-router://test",type=endpoints
Why don't I see the MBeans that I expect for the classes that I included
above?
Thanks,
Steve