I have an update if anyone can provide some insight. I have been debugging through the stack when I call camelContext.addService(instance), and I see why my @ManagedResource class is not getting picked up. As a quick indirectly related side point, this makes me wonder why my other @ManagedResource class *is* getting picked up! But, first things first. The Introspector class is looking to see if there is an MBean interface for the ManagedService class that is being inspected. The name of the interface that is being passed into Introspector.implementsMBean() is org.apache.camel.api.management.mbean.ManagedServiceMBean, and that seems like it should satisfy the requirements. For the comparison, the "clName" value that is passed in is org.apache.camel.management.mbean.ManagedService, and it took me several minutes of staring before I realized that the "api" part is missing from the package name. The method adds "MBean" to that name, then the two string values are compared. Naturally, they do not match, so this is never registered as an MBean. In the Zulip chat, I posted a screenshot of the values, and the debugger showing that the comparison has failed, and fallen through to the "else" block. You can see my comment here: https://camel.zulipchat.com/#narrow/stream/257298-camel/topic/JMX.20with.20ManagedResource.20and.20ManagedAttribute.20problem/near/411505238 if you want a visual representation of what I just tried to explain. I don't know how I could be causing this, or if there's any way that I can do something different that will allow the comparison to pass. Please let me know if anyone can offer any insight here.
Thank you, Steve On Thu, Jan 4, 2024 at 4:16 PM Steve973 <steve...@gmail.com> wrote: > Thank you. This helped get me much further in this effort. The thing > that I am having problems with, now, is that when I annotate the class > with @ManagedResource, and then include @ManagedAttribute to methods, it > will not show up as an MBean. If I remove the @ManagedResource annotation > from the class, I can get it as an MBean, but I cannot see any of the > things I designated as @ManagedAttribute when I get the service and get its > attributes. Do you have any ideas about why this could be happening? > > Thanks, > Steve > > On Wed, Jan 3, 2024 at 5:32 AM Claus Ibsen <claus.ib...@gmail.com> wrote: > >> It needs to be added as a service. >> >> in the producer you can do something ala >> >> doStart >> >> ControlService cs = new XXXX >> context.addService(cs); >> >> And remove the service in doStop >> >> See for example SendProcessor, or do a >> >> git grep "addService(" >> >> And look in the code for other examples >> >> >> On Wed, Jan 3, 2024 at 10:57 AM Steve973 <steve...@gmail.com> wrote: >> >> > An instance is created in the control producer. How should it be >> created >> > in order to be managed? >> > >> > On Wed, Jan 3, 2024, 3:59 AM Claus Ibsen <claus.ib...@gmail.com> wrote: >> > >> > > Hi >> > > >> > > You should not overwrite start and stop methods. But implement >> doStart / >> > > doStop if you need any logic. >> > > >> > > And how do you create DynamicRouterControlService in the first place >> > > >> > > On Tue, Jan 2, 2024 at 11:40 PM Steve973 <steve...@gmail.com> wrote: >> > > >> > > > 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 >> > > > >> > > >> > > >> > > -- >> > > Claus Ibsen >> > > ----------------- >> > > @davsclaus >> > > Camel in Action 2: https://www.manning.com/ibsen2 >> > > >> > >> >> >> -- >> Claus Ibsen >> ----------------- >> @davsclaus >> Camel in Action 2: https://www.manning.com/ibsen2 >> >