2

Using Mule Enterprise Standalone 3.1.2 I'm instrumenting attributes of the org.mule.routing.UntilSuccessful via a subclass. My subclass is used as a custom router.

<flow name="Queue Handler" processingStrategy="synchronous">
    <inbound-endpoint ref="Some.Queue">
        <vm:transaction action="ALWAYS_BEGIN"/>
    </inbound-endpoint>

    <custom-router class="com.company.product.mule.UntilSuccessfulSubclass">
        <flow-ref name="SomeFlow" />

        <spring:property name="objectStore" ref="SomeObjectStore" />
        <spring:property name="maxRetries" value="${maxRetries}" />
        <spring:property name="secondsBetweenRetries" value="${secondsBetweenRetries}" />
        <spring:property name="deadLetterQueue" ref="Cancel.Queue" />
        <spring:property name="maxThreads" value="${maxThreads}" />
        <spring:property name="maxBufferSize" value="${maxBufferSize}" />
        <spring:property name="threadTTL" value="${threadTTL}" />
    </custom-router>
</flow>

Currently I'm instrumenting the exposure via @ManagedAttribute on the getters and setters of my subclass of UntilSuccessful.

Looking at the Mule core xsd it doesn't appear that I have the option to pass in a bean instead of a class.

I'd prefer to use Spring's MBeanExporter functionality because this would allow me to avoid changing my class file by adding annotations and, more annoyingly, by having to override superclass methods just so I can instrument the JMX exposure.

eebbesen
  • 5,070
  • 8
  • 48
  • 70

2 Answers2

2

No word from MuleSoft as to when/whether the enhancement request will go through. However, MuleSoft's support team did provide a workaround:

  • Create interface that defines methods you want to expose in JMX
  • Implement interface in UntilSuccessfulSubclass
  • Include the following method in initialise():

    private void registerMBean()
    {
        final JmxSupportFactory jmxSupportFactory = AutoDiscoveryJmxSupportFactory.getInstance();
        final JmxSupport jmxSupport = jmxSupportFactory.getJmxSupport();
        final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
    
        final String rawName = getName() + "(" + getType() + ")";
        final String name = jmxSupport.escape(rawName);
        final String jmxName = String.format("%s:%s%s", jmxSupport.getDomainName(muleContext, !muleContext.getConfiguration().isContainerMode()), "type=ODM,name=", name);
        try
        {
            final ObjectName on = jmxSupport.getObjectName(jmxName);
            final ClassloaderSwitchingMBeanWrapper mBean = new ClassloaderSwitchingMBeanWrapper(this, UntilSuccessfulMBean.class, muleContext.getExecutionClassLoader());
            logger.debug("Registering custom router with name: " + on);
            mBeanServer.registerMBean(mBean, on);
        }
        catch (final Exception e)
        {
            logger.error(e.getMessage());
        }
    }
    

This approach does not require any change to the original Mule config file (partially referenced in my original post).

One downside to this approach is that my MBean has to appear in the Mule. directory in JMX instead of grouped with all of my other MBeans outside of that context, but it gets the job done. I don't have the points to spend on digging into Mule's JMX packages but it may be possible.

eebbesen
  • 5,070
  • 8
  • 48
  • 70
0

Currently Mule prevents using Spring beans directly as custom message processors, routers, ... which IMO is an oversight: since you're an EE user, you may want to open a ticket requesting an improvement for this.

Here is what you currently have to do to configure an UntilSuccessful message processor with Spring. I'm sure you can apply this to your own sub-class.

<spring:beans>
    <spring:bean id="untilSuccessful" class="org.mule.routing.UntilSuccessful">
        <spring:property name="routes">
            <util:list>
                <spring:ref bean="flowToProcess" />
            </util:list>
        </spring:property>
        <spring:property name="objectStore" ref="someObjectStore" />
        <spring:property name="maxRetries" value="5" />
        <spring:property name="secondsBetweenRetries" value="30" />
    </spring:bean>
</spring:beans>

<flow name="test">
    <vm:inbound-endpoint path="test.in"
        exchange-pattern="one-way" />

    <custom-processor class="com.myComp.MessageProcessorDelegate">
        <spring:property name="delegate" ref="untilSuccessful" />
    </custom-processor>
</flow>


package com.myComp;

import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.processor.MessageProcessor;
import org.mule.processor.AbstractInterceptingMessageProcessor;

public class MessageProcessorDelegate extends AbstractInterceptingMessageProcessor
{
    private MessageProcessor delegate;

    public MuleEvent process(final MuleEvent event) throws MuleException
    {
        return delegate.process(event);
    }

    public void setDelegate(final MessageProcessor delegate)
    {
        this.delegate = delegate;
    }
}
David Dossot
  • 33,403
  • 4
  • 38
  • 72
  • Any suggestions for troubleshooting `This MuleWorkManager 'UntilSuccessful' is stopped` error? I'm actually implementing this as a custom router which may be why my modifications based on the processor recommendation above is somewhat different. My first thought was that Mule was 'starting' the processor delegate and not the delegate itself, but changing process to the following yielded the same message: `return this.process(event);` – eebbesen Jun 10 '13 at 17:10
  • The delegate is here only to prevent Mule to start until successful twice, which happens if you reference to it directly using a `` construct. I'm not sure about the "stopped" problem you're encountering though, especially as `custom-router` and `custom-processor` are basically the same behind the scene. Maybe open a new question with your code, config and stacktrace? – David Dossot Jun 10 '13 at 17:51
  • Turns out `initialise()` for the flow was not being called. When I override the `MessageRouterDelegate` to call `initialise()` on my `UntilRouter` subclass I get an error due to excessive initialization. I may open another question but I want to do some more reading prior to that -- I may just implement a 'settings delegate' singleton to give JMX visibility to the settings and call it a day. – eebbesen Jun 10 '13 at 18:36
  • Did you open a request for improvement to allow Spring beans to be used as custom routers, etc... ? As an EE customer, your request would have weight and the CE user would be eternally grateful :P – David Dossot Jun 10 '13 at 18:44