Apache Camel - Transforming Data

點擊查看原文 Apache Camel - Transforming Data

集成工具是屬于構造企業(yè)服務總線 ESB 的基礎终息,勢必會處理不同組件不同格式的消息逗鸣,那么數據轉換也就是繼承工具包括 Camel 的關鍵特性。

數據轉換(Data Transformation)可以分為兩種類型:

  • 數據格式轉換 Data format transformation - 消息體的數據格式從一種轉換成另外一種帘饶,例如CSV格式轉換成XML格式
  • 數據類型轉換 Data type transformation - 消息體的數據類型從一種轉換成另外一種哑诊,例如 java.lang.String 轉換成 javax.jms.TextMessage

Camel 對數據格式和數據類型的轉換有幾種方式:

  • Data formats - XML, JSON ...
  • Expression - Languages
  • Java - Processor, Bean, Content Enricher
  • Templates - XSLT, Apache Velocity ...

Data formats

Data formats 在 Camel 里以可插拔的轉換器形式存在。每個 data format 實現了接口 org.apache.camel.spi.DataFormat 并包含兩個方法:

  • marshal - 把一個 Message 編譯成常見的數據格式及刻,例如編譯java對象成 XML, CSV, Json 等
  • unmarshal - 反編譯镀裤,把常見數據格式轉換成 Message

Data formats 可以用在 Java DSL 和 XML DSL 中:

  • 用在 Java DSL 中
from("file://rider/csvfiles")
 .unmarshal().csv()
 .split(body()).to("activemq:queue.csv.record");
  • 用在 XML DSL 中
<route>
 <from uri="file://rider/csvfiles"/>
 <unmarshal><csv/></unmarshal>
 <split>
   <simple>body</simple>
   <to uri="activemq:queue.csv.record"/>
 </split>
</route>

Camel 支持的 Data formats 完整列表參見 Apache Camel > Documentation > Architecture > Data formats.

XML Json

企業(yè)集成開發(fā)中常用的兩種數據格式 XML 和 Json,經常需要相互轉換缴饭。camel-xmljson組件是用來做 XML 和 Json 之間轉換的暑劝。

  • marshalling => converting from XML to JSON
  • un-marshaling => converting from JSON to XML.

添加此組件依賴包:

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-xmljson</artifactId>
  <version>x.x.x</version>
  <!-- Use the same version as camel-core, but remember that this component is only available from Camel 2.10 -->
</dependency>

<!-- And also XOM must be included. XOM cannot be included by default due to an incompatible
license with ASF; so add this manually -->
<dependency>
  <groupId>xom</groupId>
  <artifactId>xom</artifactId>
  <version>1.2.5</version>
</dependency>

在 Java DSL 中使用此 Data format:

// From XML to JSON - inline dataformat
from("direct:marshalInline")
  .marshal().xmljson()
  .to("mock:jsonInline");

// From JSON to XML - inline dataformat
from("direct:unmarshalInline")
  .unmarshal().xmljson()
  .to("mock:xmlInline");

更多設置參見Apache Camel > Documentation > Architecture > Data Format > XmlJson

Expression

Expressions and Predicates (expressions that evaluate to true or false) can then be used to create the various Enterprise Integration Patterns in the DSL or Xml Configuration like the Recipient List.

To support dynamic rules Camel supports pluggable Expression strategies using a variety of different Languages.

表達式 Expression 是使用不同的語言 Languages 書寫,常用的語言例如:Simple Language, XPath, Scripting Languages, Constant 等等颗搂。

例如 Simple Language 書寫的表達式: Hello ${body} 担猛,也可以用作斷言如 ${body} == 'Camel', ${header.zip} between '30000..39999'

通常表達式會作為獲取 Message Body Header Properties 值的方式丢氢,斷言會作為 Route 判斷的依據傅联。

Transform

Transform 是 Camel route DSL 中的一個方法,它接受一個 Expression 作為參數疚察,執(zhí)行表達式的結果作為轉換后的 Message Body 蒸走。Transform 可以用在 Java DSL 和 XML DSL 中,例如在 Java DSL 中使用 Transform 與 Simple language:

from("direct:start")
  .transform().simple("Hello ${body}!")
    .to("mock:result");

如果是使用 JavaScript 語言的表達式:

from("direct:start")
  .transform().javaScript("'Hello ' + request.body + '!'")
    .to("mock:result");

Java

如果 Camel 提供的 Data formats 和 Expression 不能滿足你所需要的邏輯書寫的話貌嫡,你可以還需要寫一些 Java 邏輯比驻。
可以編寫 Java 邏輯的方式有幾種:

  • Processor
  • Beans
  • Content Enricher

Processor

The Camel Processor is an interface defined in org.apache.camel.Processor with a
single method:
public void process(Exchange exchange) throws Exception;

它可以任意處理傳入的 Exchange 對象该溯。

from("direct:start")
 .process(new Processor() {
  public void process(Exchange exchange) throws Exception {
    exchange.getIn().setBody("Hello " + exchange.getIn().getBody() + "!");
  }
 })
 .to("mock:result");

Beans

Camel 使用了類似于 Spring Framework POJO 的輕量級 Bean 管理容器。Camel 的 Bean 管理注冊表(registry)是一個 Service Provider Interface (SPI)嫁艇,它實現了接口 org.apache.camel.spi.Registry朗伶。常見的實現有:

  • SimpleRegistry - A simple implementation to be used when unit testing or running Camel in the Google App engine, where only a limited number of JDK classes are available.
  • JndiRegistry - An implementation that uses an existing Java Naming and Directory Interface (JNDI) registry to look up beans.
  • ApplicationContextRegistry - An implementation that works with Spring to look up beans in the Spring ApplicationContext. This implementation is automatically used when you’re using Camel in a Spring environment.
  • OsgiServiceRegistry - An implementation capable of looking up beans in the OSGi service reference registry. This implementation is automatically used when using Camel in an OSGi environment.

在 Java DSL 中使用 Bean,指定 Bean 的標識和想要調用的方法名稱:

public void configure() throws Exception {
  from("direct:hello").beanRef("helloBean", "hello");
}

也可以只指定 Bean 的 Class步咪,Camel 會在 startup 時初始化 Bean论皆,并在調用時根據 Message Body data type 去匹配方法的參數類型并決定實際調用哪個方法:

public void configure() throws Exception {
  from("direct:hello").bean(HelloBean.class);
}

Camel 調用 Bean 時還支持很多 Camel annotations

public String orderStatus(@Body Integer orderId, @Headers Map headers) {
  Integer customerId = (Integer) headers.get("customerId");
  String customerType = (String) headers.get("customerType");
  ...
}

和 Camel language annotations

public Document handleIncomingOrder( @Body Document xml,
  @XPath("/order/@customerId") int customerId,
  @Bean(ref = "guid", method="generate") int orderId );

Content Enricher

Content Enricher 模式是一種 Message Transformation 模式。

Image: DataEnricher

它分為 Poll enrich 和 Enrich 兩種方式猾漫。

Pollenrich

from("quartz://report?cron=0+0+6+*+*+?")
 .to("http://riders.com/orders/cmd=received")
 .process(new OrderToCSVProcessor())
 .pollEnrich("ftp://riders.com/orders/?username=rider&password=secret",
   new AggregationStrategy() {
    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
      if (newExchange == null) {
        return oldExchange;
      }
      String http = oldExchange.getIn().getBody(String.class);
      String ftp = newExchange.getIn().getBody(String.class);
      String body = http + "\n" + ftp;
      oldExchange.getIn().setBody(body);
      return oldExchange;
    }
  })
  .to("file://riders/orders");

Enrich

Templates

對于更高級的數據轉換我們還可以使用 Template 技術点晴,如 XSLT, Apache Velocity, FreeMarker 等。

XSLT

XSLT (Extensible Stylesheet Language Transformations) ) is a language for transforming XML documents into other XML documents or other formats such as HTML for web pages, plain text or XSL Formatting Objects, which may subsequently be converted to other formats, such as PDF, PostScript and PNG.[2] XSLT 1.0 is widely supported in modern web browsers.

XSLT 是一個 Camel 組件悯周,所以使用其 endpoint uri:

from("file://rider/inbox")
 .to("xslt://camelinaction/transform.xsl")
 .to("activemq:queue:transformed")

Velocity

Apache Velocity is a Java-based template engine that provides a template language to reference objects defined in Java code. It aims to ensure clean separation between the presentation tier and business tiers in a Web application (the model–view–controller design pattern).

Camel Type Converters

Camel 有一套數據類型轉換系統(tǒng)粒督,當 Camel 遇到 From Type 和 To Type 不同時,會去 Type Converters 注冊系統(tǒng)查找相應的 Converter 禽翼,如果存在相應的 Converter 則使用其轉換數據類型屠橄,否則會報出異常。

自定義的 Converter 如下:

@Converter
public final class PurchaseOrderConverter {

    @Converter
    public static PurchaseOrder toPurchaseOrder(byte[] data, Exchange exchange) {
        TypeConverter converter = exchange.getContext().getTypeConverter();
        String s = converter.convertTo(String.class, data);
        if (s == null || s.length() < 30) {
            throw new IllegalArgumentException("data is invalid");
        }
        s = s.replaceAll("##START##", "");
        s = s.replaceAll("##END##", "");
        String name = s.substring(0, 9).trim();
        String s2 = s.substring(10, 19).trim();
        BigDecimal price = new BigDecimal(s2);
        price.setScale(2);
        String s3 = s.substring(20).trim();
        Integer amount = converter.convertTo(Integer.class, s3);
        return new PurchaseOrder(name, price, amount);
    }
}

本文相關代碼完整項目 Github

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末闰挡,一起剝皮案震驚了整個濱河市锐墙,隨后出現的幾起案子,更是在濱河造成了極大的恐慌长酗,老刑警劉巖溪北,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異夺脾,居然都是意外死亡之拨,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門咧叭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚀乔,“玉大人,你說我怎么就攤上這事菲茬〖酰” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵生均,是天一觀的道長。 經常有香客問我腥刹,道長马胧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任衔峰,我火速辦了婚禮佩脊,結果婚禮上蛙粘,老公的妹妹穿的比我還像新娘。我一直安慰自己威彰,他們只是感情好出牧,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著歇盼,像睡著了一般舔痕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上豹缀,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天伯复,我揣著相機與錄音,去河邊找鬼邢笙。 笑死啸如,一個胖子當著我的面吹牛,可吹牛的內容都是我干的氮惯。 我是一名探鬼主播叮雳,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼妇汗!你這毒婦竟也來了帘不?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤铛纬,失蹤者是張志新(化名)和其女友劉穎厌均,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體告唆,經...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡棺弊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了擒悬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片模她。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖懂牧,靈堂內的尸體忽然破棺而出侈净,到底是詐尸還是另有隱情,我是刑警寧澤僧凤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布畜侦,位于F島的核電站,受9級特大地震影響躯保,放射性物質發(fā)生泄漏旋膳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一途事、第九天 我趴在偏房一處隱蔽的房頂上張望验懊。 院中可真熱鬧擅羞,春花似錦、人聲如沸义图。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽碱工。三九已至娃承,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間痛垛,已是汗流浹背草慧。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留匙头,地道東北人漫谷。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像蹂析,于是被迫代替她去往敵國和親舔示。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內容