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

Reply via email to