46.3. 生成されたコンポーネントサブプロジェクト

概要

新しいコンポーネントのビルド用の Maven サブプロジェクトは camel-api-example/camel-api-example-component プロジェクトディレクトリーの下にあります。このセクションでは、生成されたサンプルコードの詳細と、その動作を説明します。

コンポーネント POM での Java API の提供

Java API はコンポーネント POM の依存関係として提供される必要があります。たとえば、サンプル Java API は、以下のようにコンポーネント POM ファイルの依存関係 camel-api-example-component/pom.xml として定義されます。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  ...
  <dependencies>
    ...
    <dependency>
      <groupId>org.jboss.fuse.example</groupId>
      <artifactId>camel-api-example-api</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
    ...
  </dependencies>
  ...
</project>

コンポーネント POM での Javadoc メタデータの提供

Java API のすべてのまたは一部に Javadoc メタデータを使用している場合は、コンポーネント POM の依存関係として Javadoc を指定する必要があります。この依存関係に関して注意することが 2 つあります。

  • Javadoc の Maven コーディネートは Java API の Maven コーディネートとほぼ同じですが、以下のように classifier 要素も指定する必要があります。

    <classifier>javadoc</classifier>
  • 以下のように、provided スコープを持つよう Javadoc を宣言する必要があります。

    <scope>provided</scope>

たとえば、コンポーネント POM では、Javadoc 依存関係は以下のように定義されます。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  ...
  <dependencies>
    ...
    <!-- Component API javadoc in provided scope to read API signatures -->
    <dependency>
      <groupId>org.jboss.fuse.example</groupId>
      <artifactId>camel-api-example-api</artifactId>
      <version>1.0-SNAPSHOT</version>
      <classifier>javadoc</classifier>
      <scope>provided</scope>
    </dependency>
    ...
  </dependencies>
  ...
</project>

サンプルファイル Hello のファイルメタデータの定義

ExampleFileHello のメタデータは署名ファイルで提供されます。通常、このファイルは手動で作成する必要がありますが、メソッド署名のリスト (各行に 1 つずつ) で設定される非常にシンプルな形式です。このサンプルコードは camel-api-example-component/signatures ディレクトリーに以下の内容を含む署名ファイル file-sig-api.txt を提供します。

public String sayHi();
public String greetMe(String name);
public String greetUs(String name1, String name2);

署名ファイル形式の詳細は、「署名ファイルメタデータ」 を参照してください。

API マッピングの設定

API コンポーネントフレームワークの主な機能の 1 つは、API マッピング を実行するコードを自動的に生成することです。つまり、エンドポイント URI を Java API のメソッド呼び出しにマッピングするスタブコードを生成します。API マッピングへの基本的な入力は、Java API、Javadoc メタデータ、署名ファイルのメタデータなどです。

API マッピングを実行するコンポーネントは、コンポーネント POM で設定された camel-api-component-maven-plugin Maven プラグインです。コンポーネント POM からの以下の抜粋は、camel-api-component-maven-plugin プラグインの設定方法を示しています。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  ...
  <build>
    <defaultGoal>install</defaultGoal>

    <plugins>
      ...
      <!-- generate Component source and test source -->
      <plugin>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-api-component-maven-plugin</artifactId>
        <executions>
          <execution>
            <id>generate-test-component-classes</id>
            <goals>
              <goal>fromApis</goal>
            </goals>
            <configuration>
              <apis>
                <api>
                  <apiName>hello-file</apiName>
                  <proxyClass>org.jboss.fuse.example.api.ExampleFileHello</proxyClass>
                  <fromSignatureFile>signatures/file-sig-api.txt</fromSignatureFile>
                </api>
                <api>
                  <apiName>hello-javadoc</apiName>
                  <proxyClass>org.jboss.fuse.example.api.ExampleJavadocHello</proxyClass>
                  <fromJavadoc/>
                </api>
              </apis>
            </configuration>
          </execution>
        </executions>
      </plugin>
      ...
    </plugins>
    ...
  </build>
  ...
</project>

プラグインは、Java API のクラスを設定するための単一の apis 子要素が含まれる configuration 要素によって設定されます。各 API クラスは以下のように api 要素によって設定されます。

apiName

API name は、API クラスの短縮名で、エンドポイント URI の endpoint-prefix として使用されます。

注記

API が単一の Java クラスのみで設定される場合は、apiName 要素を空のままにすることができます。これにより、endpoint-prefix は冗長になります。その後、「単一 API クラスの URI 形式」 に示す形式を使用して、エンドポイント URI を指定できます。

proxyClass
このプロキシークラスの要素は、API クラスの完全修飾名を指定します。
fromJavadoc
API クラスに Javadoc メタデータが付随する場合、それを示すために fromJavadoc 要素を含める必要があります。provided 依存関係として、Javadoc 自体も Maven ファイルで指定する必要があります (「コンポーネント POM での Javadoc メタデータの提供」を参照)。
fromSignatureFile

API クラスに署名ファイルのメタデータが付随する場合、これを示すために fromSignatureFile 要素を含める必要があります。この要素の内容で署名ファイルの場所を指定します。

注記

署名ファイルは、実行時ではなくビルド時にのみ必要であるため、Maven によってビルドされた最終パッケージには含まれません

生成されたコンポーネントの実装

API コンポーネントは、camel-api-example-component/src/main/java ディレクトリー下において以下のコアクラス (Camel コンポーネントすべてに実装する必要がある) から設定されます。

ExampleComponent
コンポーネント自体を表します。このクラスは、エンドポイントインスタンスのファクトリーとして機能します (例: ExampleEndpoint のインスタンス) 。
ExampleEndpoint
エンドポイント URI を表します。このクラスは、コンシューマーエンドポイント (例: ExampleConsumer) のファクトリーとして機能し、またプロデューサーエンドポイント (例: ExampleProducer) のファクトリーとして機能します。
ExampleConsumer
エンドポイント URI で指定された場所からメッセージを消費できるコンシューマーエンドポイントの具象インスタンスを表します。
ExampleProducer
プロデューサーエンドポイントの具象インスタンスを表します。これは、エンドポイント URI で指定された場所にメッセージを送信できます。
ExampleConfiguration

エンドポイント URI オプションを定義するために使用できます。この設定クラスによって定義される URI オプションは特定の API クラスには関連付けられません。つまり、これらの URI オプションを API クラスまたはメソッドのいずれかと組み合わせることができます。これは、たとえば、リモートサービスへの接続にユーザー名およびパスワードの認証情報を宣言する必要がある場合などに役立ちます。ExampleConfiguration クラスの主な目的は、API クラスまたは API インターフェイスを実装するクラスに必要なパラメーターの値を提供することです。たとえば、これらはコンストラクターパラメーターや、ファクトリーメソッドまたはクラスのパラメーター値になります。

このクラスで URI オプション option を実装するために必要なのは、アクセッサーメソッドのペア getOption and setOption を実装することだけです。コンポーネントフレームワークはエンドポイント URI を自動的に解析し、実行時にオプション値を挿入します。

ExampleComponent クラス

生成された ExampleComponent クラスは、以下のように定義されます。

// Java
package org.jboss.fuse.example;

import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.util.component.AbstractApiComponent;

import org.jboss.fuse.example.internal.ExampleApiCollection;
import org.jboss.fuse.example.internal.ExampleApiName;

/**
 * Represents the component that manages {@link ExampleEndpoint}.
 */
@UriEndpoint(scheme = "example", consumerClass = ExampleConsumer.class, consumerPrefix = "consumer")
public class ExampleComponent extends AbstractApiComponent<ExampleApiName, ExampleConfiguration, ExampleApiCollection> {

    public ExampleComponent() {
        super(ExampleEndpoint.class, ExampleApiName.class, ExampleApiCollection.getCollection());
    }

    public ExampleComponent(CamelContext context) {
        super(context, ExampleEndpoint.class, ExampleApiName.class, ExampleApiCollection.getCollection());
    }

    @Override
    protected ExampleApiName getApiName(String apiNameStr) throws IllegalArgumentException {
        return ExampleApiName.fromValue(apiNameStr);
    }

    @Override
    protected Endpoint createEndpoint(String uri, String methodName, ExampleApiName apiName,
                                      ExampleConfiguration endpointConfiguration) {
        return new ExampleEndpoint(uri, this, apiName, methodName, endpointConfiguration);
    }
}

このクラスの重要なメソッドは createEndpoint で、これは新しいエンドポイントインスタンスを作成します。通常、コンポーネントクラスのデフォルトコードを変更する必要はありません。ただし、このコンポーネントのライフサイクルと同じオブジェクトが存在する場合は、これらのオブジェクトをコンポーネントクラスから利用できるようにすることができます (例: メソッドを追加してこれらのオブジェクトを作成、これらのオブジェクトをコンポーネントに注入)。

ExampleEndpoint クラス

生成された ExampleEndpoint クラスは以下のように定義されます。

// Java
package org.jboss.fuse.example;

import java.util.Map;

import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.util.component.AbstractApiEndpoint;
import org.apache.camel.util.component.ApiMethod;
import org.apache.camel.util.component.ApiMethodPropertiesHelper;

import org.jboss.fuse.example.api.ExampleFileHello;
import org.jboss.fuse.example.api.ExampleJavadocHello;
import org.jboss.fuse.example.internal.ExampleApiCollection;
import org.jboss.fuse.example.internal.ExampleApiName;
import org.jboss.fuse.example.internal.ExampleConstants;
import org.jboss.fuse.example.internal.ExamplePropertiesHelper;

/**
 * Represents a Example endpoint.
 */
@UriEndpoint(scheme = "example", consumerClass = ExampleConsumer.class, consumerPrefix = "consumer")
public class ExampleEndpoint extends AbstractApiEndpoint<ExampleApiName, ExampleConfiguration> {

    // TODO create and manage API proxy
    private Object apiProxy;

    public ExampleEndpoint(String uri, ExampleComponent component,
                         ExampleApiName apiName, String methodName, ExampleConfiguration endpointConfiguration) {
        super(uri, component, apiName, methodName, ExampleApiCollection.getCollection().getHelper(apiName), endpointConfiguration);

    }

    public Producer createProducer() throws Exception {
        return new ExampleProducer(this);
    }

    public Consumer createConsumer(Processor processor) throws Exception {
        // make sure inBody is not set for consumers
        if (inBody != null) {
            throw new IllegalArgumentException("Option inBody is not supported for consumer endpoint");
        }
        final ExampleConsumer consumer = new ExampleConsumer(this, processor);
        // also set consumer.* properties
        configureConsumer(consumer);
        return consumer;
    }

    @Override
    protected ApiMethodPropertiesHelper<ExampleConfiguration> getPropertiesHelper() {
        return ExamplePropertiesHelper.getHelper();
    }

    protected String getThreadProfileName() {
        return ExampleConstants.THREAD_PROFILE_NAME;
    }

    @Override
    protected void afterConfigureProperties() {
        // TODO create API proxy, set connection properties, etc.
        switch (apiName) {
            case HELLO_FILE:
                apiProxy = new ExampleFileHello();
                break;
            case HELLO_JAVADOC:
                apiProxy = new ExampleJavadocHello();
                break;
            default:
                throw new IllegalArgumentException("Invalid API name " + apiName);
        }
    }

    @Override
    public Object getApiProxy(ApiMethod method, Map<String, Object> args) {
        return apiProxy;
    }
}

API コンポーネントフレームワークのコンテキストでは、エンドポイントクラスによって実行される主なステップの 1 つは、API プロキシー を作成することです。API プロキシーは、ターゲット Java API からのインスタンスで、メソッドがエンドポイントによって呼び出されます。通常、Java API は多くのクラスで設定されるため、URI に表示される endpoint-prefix を基にして、適切な API クラスを選択する必要があります (URI の一般形式は scheme://endpoint-prefix/endpoint であることに留意してください)。

ExampleConsumer クラス

生成された ExampleConsumer クラスは以下のように定義されます。

// Java
package org.jboss.fuse.example;

import org.apache.camel.Processor;
import org.apache.camel.util.component.AbstractApiConsumer;

import org.jboss.fuse.example.internal.ExampleApiName;

/**
 * The Example consumer.
 */
public class ExampleConsumer extends AbstractApiConsumer<ExampleApiName, ExampleConfiguration> {

    public ExampleConsumer(ExampleEndpoint endpoint, Processor processor) {
        super(endpoint, processor);
    }

}

ExampleProducer クラス

生成された ExampleProducer クラスは以下のように定義されます。

// Java
package org.jboss.fuse.example;

import org.apache.camel.util.component.AbstractApiProducer;

import org.jboss.fuse.example.internal.ExampleApiName;
import org.jboss.fuse.example.internal.ExamplePropertiesHelper;

/**
 * The Example producer.
 */
public class ExampleProducer extends AbstractApiProducer<ExampleApiName, ExampleConfiguration> {

    public ExampleProducer(ExampleEndpoint endpoint) {
        super(endpoint, ExamplePropertiesHelper.getHelper());
    }
}

ExampleConfiguration クラス

生成された ExampleConfiguration クラスは以下のように定義されます。

// Java
package org.jboss.fuse.example;

import org.apache.camel.spi.UriParams;

/**
 * Component configuration for Example component.
 */
@UriParams
public class ExampleConfiguration {

    // TODO add component configuration properties
}

このクラスに URI オプション option を追加するには、適切なタイプのフィールドを定義し、対応するアクセッサーメソッド (getOption および setOption) のペアを実装します。コンポーネントフレームワークはエンドポイント URI を自動的に解析し、実行時にオプション値を挿入します。

注記

このクラスは、すべての API メソッドと組み合わせることができる 一般的な URI オプションを定義するために使用されます。特定の API メソッドに関連する URI オプションを定義するには、API コンポーネント Maven プラグインに 追加のオプション を設定します。詳細は、「追加オプション」 を参照してください。

URI 形式

API コンポーネント URI の一般的な形式を取ります。

scheme://endpoint-prefix/endpoint?Option1=Value1&...&OptionN=ValueN

通常、URI は Java API の特定のメソッド呼び出しにマッピングされます。たとえば、API メソッド ExampleJavadocHello.greetMe("Jane Doe") を呼び出す場合、以下のように URI が作成されます。

scheme
Maven archetype でコードを生成した時に指定される API コンポーネントスキーム。この場合、スキームは example です。
endpoint-prefix

camel-api-component-maven-plugin Maven プラグイン設定で定義される API クラスにマップする API 名。ExampleJavadocHello クラスの場合、関連する設定は以下のとおりです。

<configuration>
  <apis>
    <api>
      <apiName>hello-javadoc</apiName>
      <proxyClass>org.jboss.fuse.example.api.ExampleJavadocHello</proxyClass>
      <fromJavadoc/>
    </api>
    ...
  </apis>
</configuration>

これは、必要な endpoint-prefixhello-javadoc であることを示しています。

エンドポイント
endpoint は、メソッド名 greetMe にマップします。
Option1=Value1
URI オプションはメソッドパラメーターを指定します。greetMe(String name) メソッドは、name=Jane%20Doe として指定できる単一のパラメーター name を取ります。オプションのデフォルト値を定義する場合は、interceptProperties メソッドを上書きしてこれを行うことができます (「プログラミングモデル」 を参照)。

URI の一部をまとめると、以下の URI で ExampleJavadocHello.greetMe("Jane Doe") を呼び出しできることがわかります。

example://hello-javadoc/greetMe?name=Jane%20Doe

デフォルトのコンポーネントインスタンス

example URI スキームをデフォルトのコンポーネントインスタンスにマッピングするために、Maven archetype は camel-api-example-component サブプロジェクトに以下のファイルを作成します。

src/main/resources/META-INF/services/org/apache/camel/component/example

このリソースファイルは、Camel コアが example URI スキームに関連付けられたコンポーネントを特定できるようにします。ルートで example:// URI を使用するたびに、Camel はクラスパスを検索し、対応する example リソースファイルを探します。この example ファイルには、以下のコンテンツが含まれます。

class=org.jboss.fuse.example.ExampleComponent

これにより、Camel コアは ExampleComponent コンポーネントのデフォルトインスタンスを作成できます。このファイルを編集する必要があるのは、コンポーネントクラスの名前をリファクタリングする場合のみです。