Apache Camel 2.x → 3.0 マイグレーションガイド(camel-core 編)

Red Hatエンジニアリングの佐藤匡剛です。昨年12月の赤帽エンジニアAdvent Calendarの記事で、Camel 3へのマイグレーションガイドの紹介記事を年明けに書くと宣言していましたが、ようやく書きました。

今回紹介する本家のガイドは、こちらです。

Apache Camel 2.x to 3.0 Migration Guide - Apache Camel

このガイドは長いので、このブログでは2つの記事(camel-core編、コンポーネント編)に分けてお送りします。コンポーネント編はこちらです。

rheb.hatenablog.com

今回は、camel-core編です。

Javaのバージョン

Camel 3が正式にサポートするのはJava 11です。当面はJava 8もベストエフォートでサポートを続けますが、いずれどこかの段階でドロップされます。

JAXB

Java 11でJAXBを使うには、Maven dependencyの明示的な追加が必要です。XML DSLでJAXBを使っていたり、camel-jaxbコンポーネントを使っている場合は、これらのdependencypom.xmlに追加します。

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.3.0.1</version>
</dependency>

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.3.2</version>
</dependency>

ランタイム/プラットフォーム

Spring Boot StarterのGroup ID変更

Spring Boot StarterのMaven groupIdorg.apache.camelからorg.apache.camel.springbootに変更されました。

Camel 2.x:

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-component-starter</artifactId>
</dependency>

Camel 3.0:

<dependency>
  <groupId>org.apache.camel.springboot</groupId>
  <artifactId>camel-component-starter</artifactId>
</dependency>

Mainクラス

CamelのMainクラス(Camelアプリケーションをスタンドアロンで実行するためのユーティリティクラス)が含まれるJARが、camel-coreからcamel-mainに変わりました。Mainクラスを使っている方は、camel-mainpom.xmlへの追加が必要です。

camel-coreのモジュール化

camel-core

Camel 3の大きな変更の1つがcamel-coreのモジュール化です。camel-coreは、以下のJARに細分化されました。後方互換性のために、これらを1つにまとめたcamel-coreは引き続き提供されていますが、マイクロサービス化のためにアプリケーションをスリムダウンしたい方は必要なdependencyだけをピックアップして使えます。

  • camel-api
  • camel-base
  • camel-caffeine-lrucache
  • camel-cloud
  • camel-core
  • camel-jaxp
  • camel-main
  • camel-management-api
  • camel-management
  • camel-support
  • camel-util
  • camel-util-json

コアコンポーネント

さらに、camel-coreに含まれていた下記のコアコンポーネントも、通常のコンポーネントと同様に外だしされました。それぞれ、使いたいコンポーネントをピックアップして使う形になります。

  • camel-attachments
  • camel-bean
  • camel-browse
  • camel-controlbus
  • camel-dataformat
  • camel-dataset
  • camel-direct
  • camel-directvm
  • camel-file
  • camel-language
  • camel-log
  • camel-mock
  • camel-ref
  • camel-rest
  • camel-saga
  • camel-scheduler
  • camel-seda
  • camel-stub
  • camel-timer
  • camel-validator
  • camel-vm
  • camel-xpath
  • camel-xslt
  • camel-xslt-saxon
  • camel-zip-deflater

CamelContext

複数CamelContextの非サポート

元々アプリケーションのデプロイメント毎に複数のCamelContextを定義する方法は、推奨されてもおらず100%完全な実装でもなかったのですが、Camel 3ではデプロイメント毎に1つのCamelContextのみサポート、ということが明示化されました。

それに伴い、複数のCamelContextを扱うために提供されていたAPIはごっそり削除されました。@EndpointInject@Produce@ConsumeなどのCamelアノテーションにあったcontext属性は削除されました。

Mainクラスの複数CamelContext非サポート

camel-core、camel-spring、camel-cdiのMainクラスでも、同様に1つのCamelContextのみ対応するための変更が加えられています。具体的には、getCamelContextMap()メソッドが削除され、getCamelContext()メソッドだけになりました。

CamelContextのグローバルオプション

Camel 2.xでdeprecatedだったCamelContextgetProperties()は削除されました。代わりに、getGlobalOptions()を使います。

Java:

context.getGlobalOptions().put("CamelJacksonEnableTypeConverter", "true");
context.getGlobalOptions().put("CamelJacksonTypeConverterToPojo", "true");

XML:

<globalOptions>
  <globalOption key="CamelJacksonEnableTypeConverter" value="true"/>
  <globalOption key="CamelJacksonTypeConverterToPojo" value="true"/>
</globalOptions>

ExtendedCamelContext

CamelContextのAPIが一般ユーザ向けに整理され、高度なユースケース向けのAPIやSPIはExtendedCamelContextに移されました。ExtendedCamelContextには以下のようにしてアクセスします。

ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class);

ModelCamelContext

ModelCamelContextにあったloadRouteDefinitions()loadRestDefinitions()のメソッドは、他のメソッドと名前を揃えるためにaddRouteDefinitions()addRestDefinitions()になりました。ローダ関連のメソッドはModelHelperユーティリティクラスに見つかります。

ModelCamelContextにアクセスしたいときは、以下のようにします。

ModelCamelContext mcc = camelContext.adapt(ModelCamelContext.class);

CatalogCamelContext

CamelContextに定義されていたカタログ関連のメソッドは、CatalogCamelContextインタフェースに移動しました。以下のようにして使います。

CatalogCamelContext ccc = context.adapt(CatalogCamelContext.class);

CamelContextによるルートの制御

CamelContextにあったstartRoute()stopRoute()suspendRoute()resumeRoute()getRouteStatus()とその他関連するメソッドはRouteControllerクラスに移されました。以下のようにアクセスします。

context.getRouteController().startRoute("myRoute");

Message API

MessageのgetOut()

MessageクラスのhasOut()getOut()メソッドはdeprecateになりました。代わりにシンプルにgetMessage()を使います。メッセージのINとOUTというコンセプトは廃止になりました。これらは、JBIやSOAPといった古い仕様から採用されたものですが、実際はそれほど有用でなかったためです。

それに伴い、他の部分でもIN、OUTのコンセプトに基づいた要素は削除されています。Beanパラメータバインディングの@OutHeadersアノテーションは削除され、代わりに@Headersを使います。

MessageのFault API

MessageクラスのFault APIも削除されました。SOAPのFaultメッセージにしか使われていなかったためです。handleFaultオプションも削除されています。

SOAPを扱うcamel-cxf、camel-spring-wsコンポーネントでは、それぞれ独自にFaultメッセージを実装していて、handleFaultの有効化をコンポーネント/エンドポイントのオプションとして設定する必要があります。

MessageのAttachments API

javax.activationのAttachments APIは、Messageクラスからcamel-attachmentsのorg.apache.camel.attachment.AttachmentMessageクラスに移動しました。

使い方は、以下のとおりです。

AttachmentMessage am = exchange.getMessage(AttachmentMessage.class);
am.addAttachment("myAtt", new DataHandler(...));

ルート/エンドポイント

consumer.プレフィクスの付いたエンドポイントオプションの削除

consumer.プレフィクスの付いたエンドポイントオプションは廃止されました。今後は、consumer.プレフィクスを付けずにそのままオプションを指定します。

例)consumer.delay=5000delay=5000

POJOアノテーション

@Consume@Produce@EndpointInjectref属性は削除されました。代わりに、value属性にrefコンポーネントを使い、以下のようにします(valueは省略可能なことに注意)。

@Consume("ref:myName")

上記にuri属性を使うこともできますが、uri属性自体もdeprecatedになっていて、代わりにvalue属性を使う必要があります。そのため、全般に、@Consume(uri = "jms:cheese")ではなく@Consume("jms:cheese")を使います。

複数インプットのあるルート

Camel 2.xでは、実はルートは2つ以上のインプットを持つことが(部分的に)できたのですが、ほとんど使われていませんでした。Camel 3では、この機能を削除し、明示的に1つのルートで1つのインプットしか受け付けないようにしました。

ルートポリシー

org.apache.camel.support.RoutePolicySupportクラスはcamel-supportに移りました。メソッドstartConsumer()stopConsumer()の戻り値はbooleanからvoidに変更されました(元々trueしか返していなかったため)。

org.apache.camel.impl.ThrottlingInflightRoutePolicyクラスはorg.apache.camel.throttling.ThrottlingInflightRoutePolicyにパッケージが変わりました。

XML DSLのマイグレーション

XML DSLのタグに細かな修正が入っています。

  • カスタムロードバランサーEIPのタグが<custom>から<customLoadBalancer>に変更された
  • XML Securityデータフォーマットで<secureXML>タグのkeyOrTrustStoreParametersId属性がkeyOrTrustStoreParametersRefに名前変更された
  • <zipFile>データフォーマットが<zipfile>に名前変更された

その他の変更

  • RestEndpointクラスのbindingMode向けのgetter/setterメソッドは、camel-apiのorg.apache.camel.spi.RestConfiguration.RestBindingMode型を使う形に変更されました。setterメソッドに関しては、String型を使うバージョンも残されてます。

  • RouteBuilderクラスのincludeRoutes()メソッドは削除されました。このメソッドはCamel 2.xの頃からdeprecatedでした。

その他のAPI

非推奨API、コンポーネントの削除

Camel 2.xで既にdeprecatedになっていたAPIやコンポーネントは、Camel 3で全部削除されました。

検査例外 vs 非検査例外

Camelのほとんどの例外クラスは非検査例外(RuntimeExceptionのサブクラス)になりました。

また、ServiceおよびSuspendableServiceのライフサイクルメソッドstart()stop()suspend()resume()も検査例外を投げないようになりました。

FactoryFinderクラスのAPIは、検査例外FactoryNotFoundExceptionClassNotFoundException等をスローする代わりに、Optional型を返すように変更されました。

HelperとSupport

HelperおよびSupportのクラスの変更は以下の通りです。

  • org.apache.camel.util.AsyncProcessorHelper (camel-core) → org.apache.camel.support.AsyncProcessorHelper (camel-support)

  • org.apache.camel.util.AsyncProcessorConverterHelper (camel-core) → org.apache.camel.support.AsyncProcessorConverterHelper (camel-support)

  • org.apache.camel.util.CamelContextHelper (camel-core) → org.apache.camel.support.CamelContextHelper (camel-support)

  • org.apache.camel.util.EndpointHelper (camel-core) → org.apache.camel.support.EndpointHelper (camel-support)

  • org.apache.camel.util.EventHelper (camel-core) → org.apache.camel.support.EventHelper (camel-support)

  • org.apache.camel.util.ExchangeHelper (camel-core) → org.apache.camel.support.ExchangeHelper (camel-support)

  • org.apache.camel.util.GZIPHelper (camel-core) → org.apache.camel.support.GZIPHelper (camel-support)

  • org.apache.camel.util.JsonSchemaHelper (camel-core) → org.apache.camel.support.JsonSchemaHelper (camel-support)

  • org.apache.camel.util.MessageHelper (camel-core) → org.apache.camel.support.MessageHelper (camel-support)

  • org.apache.camel.util.ObjectHelper (camel-core) → org.apache.camel.support.ObjectHelper (camel-support) & org.apache.camel.util.ObjectHelper (camel-util)

    • camel-apiに依存したメソッドはcamel-supportに、それ以外はcamel-utilに移動
  • org.apache.camel.util.PlatformHelper (camel-core) → org.apache.camel.support.PlatformHelper (camel-support)

  • org.apache.camel.util.PredicateAssertHelper (camel-core) → org.apache.camel.support.PredicateAssertHelper (camel-support)

  • org.apache.camel.util.ResolverHelper (camel-core) → org.apache.camel.support.ResolverHelper (camel-support)

  • org.apache.camel.util.ResourceHelper (camel-core) → org.apache.camel.support.ResourceHelper (camel-support)

  • org.apache.camel.spi.RestProducerFactoryHelper (camel-core) → org.apache.camel.support.RestProducerFactoryHelper (camel-support)

  • org.apache.camel.util.ServiceHelper (camel-core) → org.apache.camel.support.service.ServiceHelper (camel-api)

  • org.apache.camel.util.UnitOfWorkHelper (camel-core) → org.apache.camel.support.UnitOfWorkHelper (camel-support)

  • org.apache.camel.processor.loadbalancer.SimpleLoadBalancerSupportは削除されました。代わりにorg.apache.camel.processor.loadbalancer.LoadBalancerSupportを使います。

冪等リポジトリ

冪等リポジトリ(IdempotentRepository)クラスも以下のように場所が移動しています。

  • org.apache.camel.processor.idempotent.FileIdempotentRepository (camel-core) → org.apache.camel.support.processor.idempotent.FileIdempotentRepository (camel-support)

  • org.apache.camel.processor.idempotent.MemoryIdempotentRepository (camel-core) → org.apache.camel.support.processor.idempotent.MemoryIdempotentRepository (camel-support)

アグリゲーション

XsltAggregationStrategyクラスは以下のように場所が移動しています。

  • org.apache.camel.builder.XsltAggregationStrategy (camel-core) → org.apache.camel.component.xslt.XsltAggregationStrategy (camel-xslt)

org.apache.camel.builder.AggregationStrategiesクラスのxslt()メソッドは削除されました。代わりにcamel-xsltのXsltAggregationStrategyを直接使います。

Aggregate EIPのgroupExchanges()オプションを使った場合でも、アウトプットがExchange.GROUPED_EXCHANGEに格納されることはなくなりました。これは、既にCamel 2.13以降deprecatedになっていた挙動でした。

JSSE

org.apache.camel.util.jsseパッケージのクラスは、org.apache.camel.support.jsseパッケージに移りました。

フォールバック型コンバータ

@FallbackConverterは削除されました。代わりに@Converter(fallback = true)を使います。さらに、@Converter(generateLoader = true)とすることでCamelが型コンバータをより高速にロードするためのコードを自動生成できるようになりました。

レジストリ

SimpleRegistryクラスがorg.apache.camel.implパッケージからorg.apache.camel.supportパッケージに移動しました。ただし、今後はorg.apache.camel.support.DefaultRegistryを代わりに使うべきです。さらに、SimpleRegistryまたはDefaultRegistryにエントリを追加するのに、put()メソッドでなくbind()メソッドを使ってください。

CompositeRegistryPropertyPlaceholderDelegateRegistryクラスは共に削除されました。代わりにDefaultRegistryを使います。

アノテーション

アノテーション関連の細かな変更は以下のとおりです。

  • org.apache.camel.Constantアノテーションは削除されました。代わりに@Simpleを使います。

  • org.apache.camel.InvokeOnHeader / org.apache.camel.InvokeOnHeadersorg.apache.camel.spi.InvokeOnHeader / org.apache.camel.spi.InvokeOnHeaders

その他の変更

その他、細かな修正を列挙します。(まだ未分類な変更項目が多いので、後で別のセクションに振り分けるかもしれません。)

  • breadcrumbの使用はデフォルトでtrueからfalseに変更されました。

  • CamelContextがまだ起動していない段階で、ProducerTemplateConsumerTemplateを使おうとすると失敗するようになりました。

  • org.apache.camel.implパッケージにあったクラスの大部分は、camel-baseのorg.apache.camel.impl.engineパッケージに移されました。

  • org.apache.camel.util.jndi.JNDIContext (camel-core) → org.apache.camel.support.jndi.JNDIContext (camel-support)

  • org.apache.camel.ThreadPoolRejectedPolicyorg.apache.camel.util.concurrent.ThreadPoolRejectedPolicy

  • org.apache.camel.processor.validation.PredicateValidationExceptionorg.apache.camel.support.processor.validation.PredicateValidationException

  • org.apache.camel.util.toolbox.AggregationStrategiesorg.apache.camel.builder.AggregationStrategies

  • org.apache.camel.processor.aggregate.AggregationStrategyorg.apache.camel.AggregationStrategy

  • org.apache.camel.management.JmxSystemPropertyKeysorg.apache.camel.api.management.JmxSystemPropertyKeys

  • org.apache.camel.builder.xml.XPathBuilderorg.apache.camel.language.xpath.XPathBuilder (camel-xpath)

  • org.apache.camel.builder.xml.InvalidXPathExpressionorg.apache.camel.language.xpath.InvalidXPathException (camel-xpath)

  • org.apache.camel.converter.stream.OutputStreamBuilderorg.apache.camel.support.builder.OutputStreamBuilder

  • camel-coreのAPI全般にわたって次のtypoを直しました:chipercipher

  • ReloadStrategySupportFileWatcherReloadStrategyクラスは削除されました。

  • MessageHistoryFactoryインタフェースにメッセージをフィルタまたはコピーするオプションが追加され、APIに細かな変更がありました。

  • TypeConverterAwareインタフェースは削除されました。代わりに、型コンバータメソッドへのパラメータとしてExchangeを使います。

  • ComponentDataFormatインタフェースは、Serviceインタフェースを継承するようになりました。コンポーネントやデータフォーマットにもそれらのライフサイクルを管理するサービスコントラクトがあるためです。デフォルトのベースクラスは既にそれらのインタフェースを実装しています。

  • コンポーネント共通のresolvePropertyPlaceholdersオプションは削除されました。プロパティプレースホルダーの機能はCamel Main、Camel Spring Boot等で既にサポートされています。

EIP

XML DSLの<setHeader><setProperty>

<setHeader>headerName属性、<setProperty>propertyName属性は、単にnameに名前変更しました。

Camel 2.x:

<setHeader headerName="foo"><simple>Hello ${body}</simple></setHeader>

Camel 3.0:

<setHeader name="foo"><simple>Hello ${body}</simple></setHeader>

XML DSLの<aggregate>

Aggregate EIPで、相関サイズ/タイムアウト(correlation size/timeout)を表現する条件式(expression)のタグ名が変更されました。XML上の名前衝突を避けるための措置です。

Camel 2.x:

<completionSize>
  <header>mySize</header>
</completionSize>

Camel 3.0:

<completionSizeExpression>
  <header>mySize</header>
</completionSizeExpression>

<completionTimeout>も同様に<completionTimeoutExpression>となります。

Hystrix EIP

元々あったHystrix EIPは、より一般的なCircuit Breaker EIPに変更され、他の実装をプラグインできるようになりました。

Java DSL、XML DSLでそれぞれ以下のように書き換える必要があります。

  • .hysterix().circuitBreaker()
  • <hystrix><circuitBreaker>

テスト

camel-test

camel-testを使っていて、これまでテスト用のBeanを登録するためにcreateRegistry()メソッドをオーバーライドしてJndiRegistryクラスをインスタンス生成していた場合、このテクニックはもう必要なくなりました。代わりに、CamelContextからRegistry APIを取得してbind()メソッドを使うのが推奨の方法になります。

context.getRegistry().bind("myId", myBean);

adviceWith

adviceWithを使ったテストは以下のように書き換える必要があります。

Camel 2.x:

context.getRouteDefinition("start").adviceWith(camelContext, new AdviceWithRouteBuilder() {
  ...
}

Camel 3.0:

ModelCamelContext mcc = camelContext.adapt(ModelCamelContext.class);
RouteReifier.adviceWith(mcc.getRouteDefinition("start"), mcc, new AdviceWithRouteBuilder() {
  ...
}

AdviceWithRouteBuilderとラムダを使うともっと簡単に書けます。

AdviceWithRouteBuilder.adviceWith(context, "myRoute", a -> {
  a.replaceFromWith("direct:start");
}

管理/監視

トレーシング

Camelルーティングの詳細なログを出力するTracer機能の実装が、書き換えられました。新しいTracerでは、ログは org.apache.camel.Tracingロガー名で出力されます。

JMXでは、 BacklogTracerはデフォルトで無効になりました。有効にするには、CamelContextbacklogTracing=trueをセットします。

JMXイベント

org.apache.camel.management.eventパッケージにあったすべてのイベントクラスは、org.apache.camel.spi.CamelEventクラス内にサブクラスとして定義されるようになりました。例えば、CamelContextの開始イベントはCamelEvent.CamelContextStartedEventになります。

EIP、コンポーネント等の参照用JMX APIの削除

EIPやコンポーネント、エンドポイント等を検索し、そのメタ情報を得るためのJMX APIは削除されました。これらのAPIはアプリケーション実行時にはあまり意味がなく、同じ情報は開発時にはcamel-catalogから得られるためです。関連するCamelのKarafコマンドも同様に削除されました。

カスタムコンポーネント/言語

カスタムコンポーネント

カスタムコンポーネントは、今後はcamel-coreではなくcamel-supportのみに依存するように実装すべきです。

DefaultComponentDefaultEndpointなど、camel-coreにあったカスタムコンポーネントの開発に必要なクラスは、org.apache.camel.implパッケージのからcamel-supportのorg.apache.camel.supportパッケージに移されました。

同様に、camel-coreのorg.apache.camel.util.componentパッケージにあった全てのクラスもcamel-supportのorg.apache.camel.support.componentパッケージに移されました。

カスタム言語

@LaunguageAnnotationアノテーションは、org.apache.camel.languageパッケージからorg.apache.camel.support.languageパッケージへ移されました。

言語

Simple言語からのOUT Messageの削除

OUT Messageのコンセプトが廃止されたのに伴い、Simple言語からも${out.body}といった用法が削除されました。

Simple言語の開始/終了トークン

これまでSimple言語の開始/終了を表すトークンを変更できたのですが、誰も使っていなかったので最適化のために廃止されました。今後は、デフォルトの${xxx}または$simple{xxx}のみが使用可能です。

Simple言語のproperty

Camel 2.xでSimple言語のpropertyはdeprecatedになっていましたが、Camel 3では削除されました。代わりにexchangePropertyを使います。

Terser言語 → HL7 Terser言語

Terser言語は、terserhl7terserに名前変更されました。

アノテーション

言語関連のアノテーションの変更は以下のとおりです。

  • org.apache.camel.language.XPathorg.apache.camel.language.xpath.XPath (camel-xpath)

  • org.apache.camel.language.Beanorg.apache.camel.language.bean.Bean (camel-bean)

  • org.apache.camel.language.Simpleorg.apache.camel.language.simple.Simple

  • org.apache.camel.language.SpELorg.apache.camel.language.spel.SpEL (camel-spring)

Camel Mavenプラグイン

camel-maven-pluginが2つに分割されました。

  • camel-maven-plugin
  • camel-report-maven-plugin

1つめのcamel-maven-pluginがrunゴールを持っていて、Camelアプリケーションを素早くスタンドアロン実行できるためのものです。

2つめのcamel-report-maven-pluginはvaludateroute-coverageゴールを持っていて、Camelプロジェクトのバリデーションやカバレッジのレポートを出力するためのものです。

既知の問題

内部のルーティングエンジンをリファクタリングした影響で、MDCロギングとbreadcrumb IDの扱いに一定の状況下で問題が見つかっています。この問題は、camel-zipkinコンポーネントにも影響しています。

最後に

本家のガイドは構成がカオスなので、意味のある構成を見つけ出して再構成するのに一番苦労しました。(その分、本家ガイドよりもこちらの方が参照しやすくなっているはず!)もし気が向いたら、本家ガイドにもこの記事の構成を反映させるかもしれません。

次回は、マイグレーションガイドのコンポーネント編を書く予定です。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。