在xml的汪洋中遨游之mule篇

mule号称开源ESB的最好实现,研究mule也有段时间了, 在“浩如烟海”的xml配置中,保持清醒的头脑确实不容易。
 作为学习笔记之一,记录一下一个mule简单应用的实现。

需求:给指定的email地址发送邮件.
 一:基本实现:
 1: 实现命令行输入发送email:
 为了能在命令行接受输入, 需要配置一个输入输出连接器:

     <stdio:connector name="SystemStreamConnector"
        promptMessage="Please enter email content(email address, contents): " messageDelayTime="1000" />
 


2:配置一个UMO,把输入的内容放入一个队列:

        <service name="contentUMO">
            <!-- any number of endpoints can be added to an inbound router -->
            <inbound>
                <stdio:inbound-endpoint system="IN" />
            </inbound>
            <outbound>
                <pass-through-router>
                    <vm:outbound-endpoint path="content" />
                </pass-through-router>
            </outbound>
        </service>
 


        outbound节点的配置, 把输入的内容(String) 路由到一个叫“content”的queue中, 此queue为jvm中的内存队列。
3:配置一个UMO,实现发送email:

<service name="EmailBridge">
            <inbound>
                <vm:inbound-endpoint path="content" />
            </inbound>
            <outbound>
                <pass-through-router>
                    <smtps:outbound-endpoint user="lcllcl987"
                        password="yourpassword" host="smtp.gmail.com"
                        transformer-refs="ContentToEmail StringToMimeMessage"
                        connector-ref="emailConnector" from="[email protected]"
                        subject="test for mule email bridge!" />
                </pass-through-router>
            </outbound>
        </service>

        
        其中inbound的配置为contentUMO的outbound, contentUMO和EmailBridge这个两个UMO通过名称为“content”的queue连接起来, 实现通讯。EmailBridge接收到输入后, 会依次通过ContentToEmail, StringToMimeMessage两个transformer进行内容的转换。
        BTW:为了在mule中使用smtp, 需要在xml的namespace中声明:

xmlns:smtps="http://www.mulesource.org/schema/mule/smtps/2.1"
 

        mule有很多对于具体协议的transport实现,每一个transport的实现作为一个jar包存在(比如mule-transport-email-2.1.2.jar), 在jar中的META-INF/spring.schemas文件中, 写明了xsd文件的对应关系, META-INF/sping.handers配置了相关命名空间的handle class, 可以据此在mule的配置文件中声明命名空间.
        完整的mule配置文件如下:

        <?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesource.org/schema/mule/core/2.1"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:spring="http://www.springframework.org/schema/beans"
    xmlns:stdio="http://www.mulesource.org/schema/mule/stdio/2.1"
    xmlns:vm="http://www.mulesource.org/schema/mule/vm/2.1"
    xmlns:smtps="http://www.mulesource.org/schema/mule/smtps/2.1"
    xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.mulesource.org/schema/mule/core/2.1 http://www.mulesource.org/schema/mule/core/2.1/mule.xsd
       http://www.mulesource.org/schema/mule/stdio/2.1 http://www.mulesource.org/schema/mule/stdio/2.1/mule-stdio.xsd
       http://www.mulesource.org/schema/mule/vm/2.1 http://www.mulesource.org/schema/mule/vm/2.1/mule-vm.xsd
       http://www.mulesource.org/schema/mule/smtps/2.1 http://www.mulesource.org/schema/mule/smtps/2.1/mule-smtps.xsd">

    <description>
        This is a simple component example that demostrates how to send
        a e-mail
    </description>
    <stdio:connector name="SystemStreamConnector"
        promptMessage="Please enter email content(email address, contents): " messageDelayTime="1000" />

    <!-- This configures an extra setting if you're using GMail's SMTP -->
    <custom-connector name="emailConnector"
        class="co.mule.mail.SmtpConnector" />

    <custom-transformer name="ContentToEmail"
        class="co.mule.mail.ContentToEmailTransformer" />
    <custom-transformer name="StringToMimeMessage"
        class="org.mule.transport.email.transformers.StringToEmailMessage" />

    <!--
        The Mule model initialises and manages your UMO components
    -->
    <model name="myEmail">
        <!--
            A Mule service defines all the necessary information about how your components will
            interact with the framework, other components in the system and external sources.
            Please refer to the Configuration Guide for a full description of all the parameters.
        -->
        <service name="contentUMO">
            <!-- any number of endpoints can be added to an inbound router -->
            <inbound>
                <stdio:inbound-endpoint system="IN" />
            </inbound>
            <outbound>
                <pass-through-router>
                    <vm:outbound-endpoint path="content" />
                </pass-through-router>
            </outbound>
        </service>
        <service name="EmailBridge">
            <inbound>
                <vm:inbound-endpoint path="content" />
            </inbound>
            <outbound>
                <pass-through-router>
                    <smtps:outbound-endpoint user="lcllcl987"
                        password="yourpassword" host="smtp.gmail.com"
                        transformer-refs="ContentToEmail StringToMimeMessage"
                        connector-ref="emailConnector" from="[email protected]"
                        subject="test for mule email bridge!" />
                </pass-through-router>
            </outbound>
        </service>
    </model>
</mule>
 


相关class如下:
自定义消息转换器:

public class ContentToEmailTransformer extends AbstractTransformer
{
    @Override
    protected Object doTransform(Object src, String encoding) throws TransformerException
    {
        String body =  (String)src;
        String[] msg = body.split(",");
        String email = msg[0];
        String content = msg[1];
       
        RequestContext.getEventContext().getMessage().setProperty(
                      MailProperties.TO_ADDRESSES_PROPERTY, email);
        System.out.println("Sent email to " + email +  " ,content: " + content);
        return content;
    }
}

 
自定义smtp连接器(smtp connector):

public class SmtpConnector extends org.mule.transport.email.SmtpsConnector
{

    @Override
    protected void extendPropertiesForSession(Properties global, Properties local, URLName url) {
        super.extendPropertiesForSession(global, local, url);

        local.setProperty("mail.smtp.starttls.enable", "true");
        local.setProperty("mail.smtp.auth", "true");
        local.setProperty("mail.smtps.starttls.enable", "true");
        local.setProperty("mail.smtps.auth", "true");
    }
}
 


运行此程序, 根据提示, 在命令行输入:

Please enter email content(email address, contents):
[email protected], I come from Wuhan city!

 check你的邮箱, 收到email.

二: 升级:增加一个component.
修改UMO:EmailBridge配置, 增加一个component:

        <service name="EmailBridge">
            <inbound>
                <vm:inbound-endpoint path="content" />
            </inbound>
            <component class="co.mule.mail.EmailComponent"/>
            <outbound>
                <pass-through-router>
                    <smtps:outbound-endpoint user="lcllcl987"
                        password="yourpassword" host="smtp.gmail.com"
                        transformer-refs="emailModelToString StringToMimeMessage"
                        connector-ref="emailConnector" from="[email protected]"
                        subject="test for mule email bridge!" />
                </pass-through-router>
            </outbound>
        </service>

 

    注意到增加了一个component, 接受命令行的输入(String), 产生一个EmailModel的对象.之后,这个EmailModel对象进入outbound, 并经过
emailModelToString, StringToMimeMessag的处理, 最后发送出去.
其中emailModelToString是新添加的一个自定义transformer:

    <custom-transformer name="emailModelToString"
        class="co.mule.mail.EmailModelToString" />

 
相关class如下:
EmailModel.java:

package co.mule.mail;

public class EmailModel
{
    private String address;
    private String content;
   
    public EmailModel(String address, String content)
    {
        this.address = address;
        this.content = content;
    }
    public String getAddress()
    {
        return address;
    }
    public void setAddress(String address)
    {
        this.address = address;
    }
    public String getContent()
    {
        return content;
    }
    public void setContent(String content)
    {
        this.content = content;
    }
    @Override
    public String toString()
    {
        // TODO Auto-generated method stub
        return "address=" + address + ", content=" + content;
    }
}
 

EmailComponent.java
需要说明的是:
mule默认采用方法参数类型匹配策略, 所以, 如果有String类型的输入, foo方法自动调用, 也可以详细指定调用哪个方法,比如以下配置明确指定调用component的foo方法:

            <component class="co.mule.mail.EmailComponent">
                <method-entry-point-resolver>
                    <include-entry-point method="foo"/>
                </method-entry-point-resolver>
            </component>

 

package co.mule.mail;

import org.mule.RequestContext;
import org.mule.transport.email.MailProperties;

public class EmailComponent
{
    public Object foo(String input)
    {
        String[] msg = input.split(",");
        String address = msg[0];
        String content = msg[1];
        EmailModel email = new EmailModel(address, content);
        System.out.println("create email model: " + email);
        RequestContext.getEventContext().getMessage().setProperty(
                MailProperties.TO_ADDRESSES_PROPERTY, email.getAddress());
        return new EmailModel(address, content);
    }
}
 


EmailModelToString.java

package co.mule.mail;

import org.mule.api.transformer.TransformerException;
import org.mule.transformer.AbstractTransformer;

public class EmailModelToString extends AbstractTransformer
{
    public EmailModelToString()
    {
        super();
        this.registerSourceType(EmailModel.class);
        this.setReturnClass(String.class);
    }
   

    @Override
    protected Object doTransform(Object src, String encoding)
            throws TransformerException {
        EmailModel emailModel = (EmailModel)src;
        return emailModel.toString();
    }

}

 


三:继续升级:不满足于在命令行输入, 需要在浏览器输入, 也就是发布一个http接口。
修改contentUMO如下:

        <service name="contentUMO">
            <!-- any number of endpoints can be added to an inbound router -->
            <inbound>
                <!-- Incoming HTTP requests -->
                <inbound-endpoint address="http://localhost:9999"
                    transformer-refs="HttpRequestToString"
                    synchronous="true" />
            </inbound>
            <outbound>
                <pass-through-router>
                    <vm:outbound-endpoint path="content" />
                </pass-through-router>
            </outbound>
        </service>
 


        通过http请求得到输入参数, 经过HttpRequestToString的转换, 放入“content” queue, 为了和content中的数据格式匹配,在浏览器中按如下方式输入:
        http://localhost:[email protected],hello
        新增了一个class:
HttpRequestToString.java

package co.mule.mail;

import org.mule.api.transformer.TransformerException;
import org.mule.transformer.AbstractTransformer;
import org.mule.util.IOUtils;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

public class HttpRequestToString extends AbstractTransformer
{
    private static final String EMAIL_REQUEST_PARAMETER = "email=";
   
    public HttpRequestToString()
    {
        super();
        this.registerSourceType(String.class);
        this.setReturnClass(String.class);
    }

    public Object doTransform(Object src, String encoding) throws TransformerException
    {
        return extractEmailValue(extractRequestQuery(convertRequestToString(src, encoding)));
    }
   
    private String convertRequestToString(Object src, String encoding)
    {

        return src.toString();
    }
   
    private String extractRequestQuery(String request)
    {
        String requestQuery = null;
       
        if (request != null && request.length() > 0 && request.indexOf('?') != -1)
        {
            requestQuery = request.substring(request.indexOf('?') + 1).trim();
        }

        return requestQuery;
    }
   
    private String extractEmailValue(String requestQuery) throws TransformerException
    {
        String emailValue = null;
       
        if (requestQuery != null && requestQuery.length() > 0)
        {
            int nameParameterPos = requestQuery.indexOf(EMAIL_REQUEST_PARAMETER);
            if (nameParameterPos != -1)
            {
                int nextParameterValuePos = requestQuery.indexOf('&');
                if (nextParameterValuePos == -1 || nextParameterValuePos < nameParameterPos)
                {
                    nextParameterValuePos = requestQuery.length();
                }

                emailValue = requestQuery.substring(nameParameterPos + EMAIL_REQUEST_PARAMETER.length(), nextParameterValuePos);
            }
           
            if (emailValue != null && emailValue.length() > 0)
            {
                try
                {
                    emailValue = URLDecoder.decode(emailValue, "UTF-8");
                }
                catch (UnsupportedEncodingException uee)
                {
                    logger.error(uee.getMessage());
                }
            }
        }

        if (emailValue == null)
        {
            emailValue = "";
        }
       
        return emailValue;
    }
}
 

使用心得:除了xml,还是xml. 如果没有图形化的配置工具, 使用起来还是很麻烦的。对于mule的开发, 主要做component和transfer的开发.至于其他好处, 有待进一步学习。

你可能感兴趣的:(spring,jvm,xml,浏览器,Gmail)