Contact Us 1-800-596-4880

Extend the Runtime Manager Agent for Hybrid

Where possible, we changed noninclusive terms to align with our company value of Equality. We maintained certain terms to avoid any effect on customer implementations.

You can extend the Anypoint Runtime Manager agent, including implementing a complete service, external message handler, and internal message hander using a method to revert a string.

Runtime Manager Agent Extensible Component

The Runtime Manager agent contains the following extensible components:

  • Services

  • External message handlers

  • Internal message handlers

Runtime Manager Agent Custom Component Structure

A Runtime Manager agent custom component should comply with the following structure:

  • /lib contains component dependencies

  • /classes contain compiled classes

A custom component should also be compiled with Java 1.7, components compiled with higher versions will not be loaded by the agent.

For this example, in order to acquire the libraries necessary to extend the agent, add the following dependencies to your pom.xml:

<properties>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <mule.agent.version>1.6.4-mule-3.x</mule.agent.version>
    <jersey.core.version>2.11</jersey.core.version>
    <commons.lang.version>2.4</commons.lang.version>
</properties>

<dependencies>
        <dependency>
            <groupId>com.mulesoft.agent</groupId>
            <artifactId>mule-agent-api</artifactId>
            <version>${mule.agent.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>${jersey.core.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <scope>provided</scope>
            <version>${commons.lang.version}</version>
        </dependency>
</dependencies>

<repositories>
    <repository>
        <id>mulesoft-ci-releases</id>
        <name>ci releases</name>
        <url>https://repository-master.mulesoft.org/nexus/content/repositories/releases-ee/<url>
    </repository>
</repositories>

<build>
    <plugins>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

Contact MuleSoft Support for access to this repository:

https://repository-master.mulesoft.org/nexus/content/repositories/releases-ee/

The corresponding JAR should be added under the lib folder within the mule-agent plugin, which is contained in the plugins folder of the Mule instance. For example, $MULE_HOME/plugins/mule-agent/lib/<component name>.jar.

Add a New Service

To add a new service, implement the MuleAgentService interface.

Considerations for custom services:

  • The service can execute any internal handler registered in the Runtime Manager agent environment, by using the @Inject annotation.

  • You don’t have to follow the Runtime Manager agent architecture in order to create a new service.

Write Your Service

Implement MuleAgentService

@Named("my.company.service")
@Singleton
public class MyService implements MuleAgentService
{

    @Inject
    private Map<String, InternalMessageHandler<List<T>>> handlers;

    @Override
    public java.util.List<com.mulesoft.agent.handlers.InternalMessageHandler> getInternalHandlers()
    {
        // TODO: return List of Internal Handlers
    }

    @Override
    public void enable(boolean state) throws AgentEnableOperationException {
        // TODO: enable the Service
    }

    @Override
    public boolean isEnabled() {
        // TODO: return Service status
    }
}

To add your new service, just drop the JAR containing your classes in the lib folder within the mule-agent plugin folder (for example, in $MULE_HOME/mule-agent/lib).

Revert String Service Example

As explained above, this document uses a simple example to explain how to write a full extension to revert a string. The first step is to add a service for this purpose.

@Named("com.company.service.reverse")
@Singleton
public class ReverseService implements MuleAgentService
{

    @Inject
    List<InternalMessageHandler<String>> messageHandlerList;

    @Override
    public List<InternalMessageHandler> getInternalHandlers()
    {
        return new ArrayList<InternalMessageHandler>(messageHandlerList);
    }

    @Override
    public void enable(boolean b) throws AgentEnableOperationException
    {

    }

    @Override
    public boolean isEnabled()
    {
        return true;
    }

    public String getConvertedString(String origString)
    {
        String reverted = StringUtils.reverse(origString);
        for (InternalMessageHandler<String> internalMessageHandler : messageHandlerList)
        {
            internalMessageHandler.handle(reverted);
        }

        return reverted;
    }
}

Add a New External Message Handler

To add a new external message handler, you have to implement the Runtime Manager agent Reverse String External Message Handler interface.

Considerations for custom external message handlers:

  • The external message handler will be injected into a transport

  • The external message handler must be thread-safe

  • An external message handler is executed by a transport and cannot interact with Mule. Only Services can interact with Mule

Write Your External Message Handler

REST

@Named("my.external.handler")
@Path("somePath")
@Singleton
public class MyRequestHandler implements ExternalMessageHandler
{
    @Inject
    private MuleService muleServiceInTheAPIModule;

    @Override
    public void enable(boolean state) throws AgentEnableOperationException {
        // TODO: enable the Handler
    }

    @Override
    public boolean isEnabled() {
        // TODO: return Handler status
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Component> someRequest()
    {

    }
}

WebSockets

@Named("TYPE_OF_MESSAGE_THAT_MUST_DISPATCH")
@Singleton
public class MyRequestHandler implements ExternalMessageHandler
{
    @Inject
    private MuleService muleServiceInTheAPIModule;

    @Override
    public void enable(boolean state) throws AgentEnableOperationException {
        // TODO: enable the Handler
    }

    @Override
    public boolean isEnabled() {
        // TODO: return Handler status
    }

}

To add your new external message handler, just drop the JAR containing your classes under the lib folder within the mule-agent plugin folder (for example, in $MULE_HOME/mule-agent/lib).

Reverse String External Message Handler

Following the Reverse String example, the External Handler is shown below.

@Named("com.company.externalhandler.reverse")
@Path("revert")
@Singleton
public class ReverseExternalHandler implements ExternalMessageHandler
{

    @Inject
    private ReverseService reverseService;

    @Override
    public void enable(boolean b) throws AgentEnableOperationException
    {

    }

    @Override
    public boolean isEnabled()
    {
        return true;
    }

    @GET
    public String getReversedString(@QueryParam("string") String string)
    {
        return reverseService.getConvertedString(string);
    }
}

The above code exposes a resource under <your REST transport host>/mule/revert.

Add a New Internal Message Handler

To add a new internal message handler, you have to implement the Internal Message Handler interface.

Considerations for custom internal message handlers:

  • The internal message handler will be injected into a service based on the message types it handles

  • The internal message handler must be thread-safe

  • An internal message handler is executed by a service and cannot interact with Mule. Only Services can interact with Mule

Write Your Internal Message Handler

@Named("my.company.internal.handler")
@Singleton
public class MyInternalMessageHandler<T> implements InternalMessageHandler<T>{

    boolean handle(T t){
          // TODO handle message
    }

    @Override
    public void enable(boolean state) throws AgentEnableOperationException {
        // TODO: enable the Handler
    }

    @Override
    public boolean isEnabled() {
        // TODO: return Handler status
    }
}

To add your new internal message handler, just drop the jar containing your classes under the lib folder within the mule-agent plugin folder (for example, in $MULE_HOME/mule-agent/lib).

Reverse String Internal Message Handler

The code below shows an internal message handler for the reverse string example.

@Named("com.mulesoft.agent.test.extension.internalHandler")
@Singleton
public class ReverseInternalHandler extends BufferedHandler<String>
{

    @Configurable("true")
    protected boolean enabled;

    @Configurable
    public String host;

    @Configurable
    public String port;

    @Inject
    public ReverseInternalHandler()
    {
        super();
    }

    @Override
    protected boolean canHandle(String t)
    {
        return true;
    }

    @Override
protected boolean flush(Collection<String> ts)
    {
        String tempDir = System.getProperty("java.io.tmpdir");
        File revertedStringFile = new File(tempDir, "revertedString.txt");

        FileOutputStream fos = null;

        BufferedWriter bw = null;

        try
        {
            fos = new FileOutputStream(revertedStringFile);

            bw = new BufferedWriter(new OutputStreamWriter(fos));

            for (String string : ts)
            {
                bw.write(string);
                bw.newLine();
            }
        }
        catch (IOException e)
        {
            System.out.println("Error writing reversed string");
            return false;
        } finally {
          if (bw != null){
            try {
                bw.close();
            } catch(IOException x) {

            }
          }
          if (fos != null){
            try{
                fos.close();
            } catch(IOException x) {

            }
          }
        }
        return true;
    }
    @PostConfigure
    public void postConfigure()
    {
    }

    @Override
    public void enable(boolean b) throws AgentEnableOperationException
    {
      enabled = b;
    }

    @Override
    public boolean isEnabled()
    {
        return enabled;
    }
}

This internal message handler writes the message processed by the service to a file called revertedString.txt.

Runtime Manager Agent API Interfaces

Mule Service

**
 * <p>
 * Implementations of this interface provides new functionality to the Runtime Manager agent. These services handle data from
 * Mule and interact with Mule.
 * </p>
 *
 * @see com.mulesoft.agent.handlers.ExternalMessageHandler , InternalMessageHandler
 * @since 1.0
 */
public interface MuleAgentService extends Switcher
{

    public List<InternalMessageHandler> getInternalHandlers();

}

External Message Handler

/**
 * <p>
 * Gets  messages coming from an external system and executes {@link com.mulesoft.agent.services.MuleAgentService} based
 * the request.
 * </p>
 * <p>
 * This is just a marker interface for the communication layer to recognize the interface as a External message receiver
 * </p>
 *
 * @since 1.0
 */
public interface ExternalMessageHandler extends Switcher
{

}

Internal Message Handler

/**
 * <p>
 * Internal messages come generally from mule side. {@link InternalMessageHandler} are use to handle those messages depending on,
 * for example, the transport.
 * </p>
 *
 * @param <Rq> is the type of the message it must handle
 * @since 1.0
 */
public interface InternalMessageHandler<Rq> extends Switcher
{

    /**
     * <p>
     * Process an internal message
     * </p>
     *
     * @param message The message to be processed
     * @return true if the message could be processed
     */
    boolean handle(@NotNull Rq message);

}

Switcher

/**
 * <p>
 * All the classes implementing this interface will be able to enable/disable themselves
 * </p>
 *
 * @since 1.0
 */
public interface Switcher
{
    /**
     * <p>
     * Turn the feature on, the class will be behave as expected
     * <br/>
     * If the feature is being disabled, any resources it has allocated should be freed and taken again when it is reenabled
     * </p>
     * @param state true if enabled, false otherwise
     * @throws AgentEnableOperationException if the end state is not the requested one
     */
    void enable(boolean state) throws AgentEnableOperationException;

    /**
     * <p>
     * Check the state of the class
     * </p>
     *
     * @return true if it is on, false otherwise
     */
    boolean isEnabled();

}