Components

Component 是一个容易混淆的名词,可能使用EndpointFactory会更合适,因为Component是创建Endpoint实力的工厂类。例如如果一个Camel应用使用了几个JMS 队列,那么这个应用首先需要创建一个叫JmsComponent(实现了Component接口)的实例,然后应用会调用这个JMSComponent对象的createEndpoint()方法来创建一个JmsEndpoint对象(这个对象实现了Endpoint接口)。事实上,应用代码并没直接调用Component.createEndoint() 方法,而是CamelContext对象通过找到对应的Component对象(我马上会在后续的文章中介绍),并调用createEndpoint() 方法来实现的。

myCamelContext.getEndpoint("pop3://john.smith@mailserv.example.com?password=myPassword");

在getEndpoint()中使用的参数就是URI。这个URI的前缀(: 之前的那部分内容)描述了一个组件的名字,CamelContext对象内部维护着一个组件名字与Component对象的映射表。对于上面给定的URI例子来说,CamelContext对象会根据pop3前缀找到MailComponent类,然后CamelContext对会调用MailComponent的createEndpoint("pop3://john.smith@mailserv.example.com?password=myPassword") 方法。在createEndpoint()方法中, 将把URI分割成一段段小的参数,这些小参数将被用来设置生成的Endpoint对象。

在上一段中, 我提到的CamelContext对象维护了一个组件名到Component对象的映射表。但这个映射表是如何产生的呢?这里可以在通过代码调用CamelContext.addComponent(String componentName, Component component)来实现。 下面的例子就是展示了如何给一个MailComponent对象注册上三个不同的名字。
Component mailComponent = new org.apache.camel.component.mail.MailComponent();
myCamelContext.addComponent("pop3", mailComponent);
myCamelContext.addComponent("imap", mailComponent);
myCamelContext.addComponent("smtp", mailComponent);

第二个方法也是最常用的方法,就是通过CamelContext对象来实现一个懒初始化。这个方法依赖于一套Camel内部的定义Component发现规则, 开发者只要在实现Component接口的时候按照这一规则设置,就可以保证CamelContext能够正常发现这一Component。这里我们假设你所写的Class名字为 com.example.myproject.FooComponent, 并且你想让Camel自动将这个component和"foo”这个名字相对应。为了做到这一点,你需要先写一个叫做"META-INF/services/org/apache/camel/component/foo" 属性文件, 注意这个文件没有".properties"作为后缀名,在这个属性文件中只有一个class的条目,而这个条目的只就是你所写的类的全名。如下所示

META-INF/services/org/apache/camel/component/foo
class=com.example.myproject.FooComponent

如果你还想让Camel将上面的类和”bar” 这个名字联系起来,那你需要在同样的目录下在创建一个相同内容叫bar的文件。一旦完成了这些配置, 你可以把 com.example.myproject.FooComponent class和这些配置文件一同打成一个jar 包,然后把这个jar包放你的CLASSPATH中。这样Camel就会通过分析这些属性文件的class 项目,通过使用reflectionAPI创建这个指定的类的实例。

正如我在Endpoint中说描述的, Camel提供了对多种通信协议一个开箱即用的支持。这种支持是建立在实现了Component接口的类以及让CamelContext对象自动建立映射关系的配置文件基础之上的。

在这一节的开始, 我使用的这个例子来调用CamelContext.getEndpoint()。
myCamelContext.getEndpoint("pop3://john.smith@mailserv.example.com?password=myPassword");

在最开始举这个例子的时候,我说这个getEndpoint()方法的参数是一个URI。我这么说是因为Camel的在线问答以及Camel的源代码就把这个参数声明为一个URI。在现实生活中,这个参数是按照URL来定义的。这是因为Camel会从参数中通过一个简单的算法查找第一:来分析出组件名。为了了解其中的奥妙,大家可以回想一下我在前面 URL,URI,URN和IRI是什么中谈到的 一个URI可以是URL或者URN。 现在让我们来看一下下面的getEndpoint()调用。
myCamelContext.getEndpoint("pop3:...");
myCamelContext.getEndpoint("jms:...");
myCamelContext.getEndpoint("urn:foo:...");
myCamelContext.getEndpoint("urn:bar:...");

Camel会先找出这些component的标识,例如 "pop3", "jms", "urn" 和 "urn"。如果"urn:foo" 和"urn:bar" 能够别用来识别component,或者是使用"foo" 和"bar" (这一可以跳过这个"urn:"前缀)。所以在实际的编程中,大家更喜欢使用URL来制定一个Endpoint(使用":..."来描述的字符串)而不是用一个URN( 使用"urn::..."来描述的字符串)。正因为我们没有安全按照URN的规定的参数来调用getEndpoint() 方法, 所以这个方法的参数更像一个URL而不是一个URI。

 

===========================

1.component.createEndpoint()

2.if it's in from(...) clause, then call endpoint.createConsumer()

  2.1 consumer will call doStart(),

  2.2 create message and exchange, set exchange.in,then call processor to process this exchange.

  you can create several exchange, each exchange mean one process.

 3.if it's in to(...), then call endpoint.createProducer()

  3.1producer call process(), then you can process this exchange, set this exchange.out, then it will be processed

 

Component

public class MemoryComponent extends DefaultComponent{
 @Override
  //memory:myMemory?param=value
  //remaining = myMemory
  protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
   System.out.println("createEndpoint(String uri, String remaining, Map<String, Object> parameters)");
   MemoryEndpoint endpoint = new MemoryEndpoint(uri, this);
   return endpoint;
  }}

Endpoint

public class MemoryEndpoint extends DefaultEndpoint{
 public MemoryEndpoint() {
   super();
   System.out.println("MemoryEndpoint()");
  } public MemoryEndpoint(String endpointUri, Component component) {
   super(endpointUri, component);
   System.out.println("MemoryEndpoint(String endpointUri, Component component)");
  } @Override
  public Consumer createConsumer(Processor processor) throws Exception {
   System.out.println("createConsumer(Processor processor)");
   Consumer memConsumer = new MemoryConsumer(this,processor);
   return memConsumer;
  } @Override
  public Producer createProducer() throws Exception {
   System.out.println("createProducer()");
   Producer memProducer = new MemoryProducer(this);
   return memProducer;
  } @Override
  public boolean isSingleton() {
   System.out.println("isSingleton()");
   return false;
  }}

Producer

public class MemoryProducer extends DefaultProducer{
 public MemoryProducer(Endpoint endpoint) {
   super(endpoint);
   System.out.println("MemoryProducer(Endpoint endpoint)");
  } @Override
  public void process(Exchange exchange) throws Exception {
   System.out.println("process(Exchange exchange)");
   Object body = exchange.getIn().getBody();
   System.out.println("add to queue:" + (String)body);
   exchange.getOut().setBody("producer-" + (String)body);
   StaticQueue.producerQueue.add("producer-" + (String)body);
  }}

 

Consumer

public class MemoryConsumer extends DefaultConsumer {
 public MemoryConsumer(Endpoint endpoint, Processor processor) {
   super(endpoint, processor);
   System.out.println("MemoryConsumer(Endpoint endpoint, Processor processor)");
  } @Override
  protected void doStart() throws Exception {
   super.doStart();
   
   System.out.println("doStart()");
   for (String str : StaticQueue.consumerQueue) {
    Exchange ex = this.getEndpoint().createExchange();
    Message msg = new DefaultMessage();
    msg.setBody(str);
    ex.setIn(msg);
    getProcessor().process(ex);
   }
  } @Override
  protected void doStop() throws Exception {
   super.doStop();
   System.out.println("doStop()");
   
  }}

Processor

public class MemoryProcessor implements Processor {
 @Override
  public void process(Exchange exchange) throws Exception {
   System.out.println("MemoryProcessor-process(Exchange exchange)");
   Message in = exchange.getIn();
   System.out.println("in:" +in.getBody());
   Message out = exchange.getOut();
   System.out.println("out:" +out.getBody());
   
   //self defined processor need to transmit the msg from in to out, //to("memory:mymemory").process(processor)
  out.setBody(in.getBody() + " out processed");
   
   //in.setBody(in.getBody() + " in processed");
   
  }}

 

Test

public class Test {
 /**
   * @param args
   * @throws Exception 
   */
  public static void main(String[] args) throws Exception {
   if ( System.getProperty("log4j.configuration") != null )
    PropertyConfigurator.configure(System.getProperty("log4j.configuration"));
   else 
    BasicConfigurator.configure();
   
   // TODO Auto-generated method stub
   Component memoryCom = new MemoryComponent();
   CamelContext context = new DefaultCamelContext();
   context.addComponent("memory", memoryCom);
   
   
   Component streamCom = new StreamComponent();
   context.addComponent("in", streamCom);
   context.addComponent("out", streamCom);
   
   context.addRoutes(new MemoryRouteBuilder());
   context.start();
   
   Runtime.getRuntime().addShutdownHook(new Thread(){
    @Override
    public void run() {
     System.out.println("queues:");
     for (String str : StaticQueue.producerQueue) {
      System.out.println("queue:"+str);
     }
    }
    
   });
  }}
 class MemoryRouteBuilder extends RouteBuilder {
  /** * A main() so we can easily run these routing rules in our IDE */
   /** * Lets configure the Camel routing rules using Java code... */
  public void configure() {
   //producer
 //  from("timer://myTimer?period=2000").setBody().simple("myTimertest1").
 //  to("memory:mymemory");
   
   //consumer
   MemoryProcessor processor = new MemoryProcessor();
   //from("memory:mymemory").to("file://C://test");
   //from("memory:mymemory").to("memory:mymemory").to("file://C://test");
   from("memory:mymemory").to("memory:mymemory").process(processor).to("file://test");
     //to("log:out");
   //  to("stream:out");
   
   //from("stream:in?promptMessage=Enter&promptDelay=5000").to("stream:out");
  }
 }class StaticQueue  {
  public static Queue<String> consumerQueue = new LinkedBlockingQueue<String>();
  public static Queue<String> producerQueue = new LinkedBlockingQueue<String>();
  static {
   consumerQueue.add("consumer-1");
   consumerQueue.add("consumer-2");
  }
  
 }