# mulesoft Mule Sdk - Full Documentation # DataSense サポートの追加 DataSense は、モジュール内のエンティティの型メタデータを表示する Mule サービスです。 この機能は省略可能ですが、モジュールを使いやすくするために、モジュールで DataSense を使用することを強くお勧めします。 このドキュメントでは、エンドユーザーの視点から見たコネクタのアーキテクチャと DataSense の概念について読者が精通していることを前提としています。 ## [](#component-metadata)コンポーネントのメタデータとは? インテグレーション開発者は、1 つのコンポーネントの出力を別のコンポーネントの入力に接続できるようにデータを変換するために、特定のコンポーネント (操作、ソースなど) の入力データ型と出力データ型の決定に多くの時間を費やします。この作業では、各コンポーネントの API ドキュメントを参照して必要なパラメーターを見つけなければなりません。このプロセスは非効率的で、間違いを犯しやすく、ときにはストレスも溜まります。 DataSense は、これらのコンポーネントが提供するメタデータを使用して、必要な情報をすべて自動的に解決してデザイン時にエンドユーザーに提供してくれるので、開発を大幅にスピードアップすることができます。 この機能は、既知の型のパラメーターが取ることのできる値を絞り込むための[値プロバイダー](https://docs.mulesoft.com/jp/mule-sdk/1.1/value-providers)とは異なり、この機能ではパラメーター値の範囲を検出できない動的型を見つけるためのものです。 ここで言う「型」とは、要素の `MetadataType` を意味します。`MetadataType` は、特定の要素の種類や構造を表します。たとえば、基本的な文字列や数字の要素であれば `StringType` や `NumberType`、コレクションなら `ArrayType`、ネストされた要素を持つ複雑な構造 (POJO や JSON オブジェクト) であれば `ObjectType`、型が未知で、他の使用可能などのタイプでもよい要素であれば `AnyType` になります。 [「DataWeave の型」](#4.1@mule-runtime::dataweave-types.adoc)を参照してください。 ### [](#静的メタデータ)静的メタデータ 静的メタデータとは、コンパイル時に既知で、コネクタの JAR ファイルにある型から使用できるメタデータです。単純な Java 型は、開発者がモデルで定義したカスタム POJO と同じように、この静的メタデータに属します。重要な点は、構造が明確に分かっていて、他のパラメーターに依存せずに調査できるということです。 ### [](#動的メタデータ)動的メタデータ 動的メタデータとは、コンパイル時に型が未知のメタデータです。動的メタデータは、コネクタの設定に基づいてデザイン時に解決する必要があります。このメタデータには、さまざまなケースでいろいろな使い方があります。たとえば、型そのものは既知でも構造がサービス設定に依存するケース (例: システムのアカウントにユーザーがカスタマイズできる項目があるため、ユーザーのログイン情報に基づいてその構造を毎回検出しなければならない場合) や、すべてが動的であるため、記述されている構造が設定済みパラメーターに大きく依存するケース (例: 記述されている構造がサービス操作のペイロードであり、ユーザーの Sandbox に基づいたサービス定義にも依存する場合) があります。 動的メタデータを解決するには、現在のコンポーネント設定に従って必要な型構造を取得する方法を知っているメタデータリゾルバーに要素を関連付ける必要があります。詳細は「[メタデータリゾルバー](#metadata_resolvers)」を参照してください。 ### [](#入力メタデータ)入力メタデータ 入力メタデータは、コンポーネントのパラメーターのタイプを解決します。各パラメーターは、同じコンポーネントの他のパラメーターが公開している種類のメタデータから分離された静的または動的メタデータを提供します。 動的メタデータのパラメーターは操作とソースでのみ使用できます。設定と接続のパラメーターは常に静的メタデータとなります。 ### [](#出力メタデータ)出力メタデータ コンポーネントの出力は、メタデータの静的または動的な解決にバインドされます。たとえば、`void` 操作は、操作の出力が `VoidType` であることを示す静的メタデータを持ち、リモートサービスから `User` プロファイルをフェッチする操作は `User` タイプを動的に記述できます。 [構造](https://docs.mulesoft.com/jp/mule-sdk/1.1/module-structure)についての説明にあるように、操作の出力結果には、ペイロードのデータと返されるメッセージの属性が含まれます。これらの属性の構造は、ペイロードの構造と同じくらい重要です。それぞれのメタデータを独立して記述することで、エンドユーザーにとっては使いやすくなります。ただし、一部のコンポーネントは属性を生成しないため、属性の動的メタデータの記述は常に任意で行います。 特定の戻り値のデータ型では、強制的にメタデータが動的に記述されます。これはエンドユーザーの使い勝手を向上させるための要件であり、型の記述が汎用的過ぎると使いづらくなるためです。 ## [](#実装の概要)実装の概要 動的 DataSense サポートを実装するには、まず、特定の要素で提供するメタデータの型を定義します。型を定義したら、アノテーションと異なるメタデータリゾルバーのカスタム実装の組み合わせ (例: `@MetadataKeyId(BucketKeysResolver.class)`) を活用できます。どの組み合わせを使用するかはユースケースによって異なります。 以降のセクションでは、上記のケースの実装について説明します。 ### [](#メタデータキーパラメーター)メタデータキーパラメーター 動的メタデータ構造を記述するには、どの型を表現するのかを知る必要があります。この型の参照を定義するには、記述する型の ID を含む `@MetadataKeyId` パラメーターを操作で指定します。 たとえば、汎用レコードを Amazon S3 に保存する操作があるとして、サポートされる各型の構造 (`Account` や `Organization` など) を記述しておけば、デザインしやすくなります。この場合は、操作のパラメーターの 1 つに ID として `Account` または `Organization` を含む型の参照を定義します。このパラメーターは、バケットに保存するレコードの Account 構造または Organization 構造 (エンドユーザーが使うと決めた方) を記述します。 `@MetadataKeyId` パラメーターは常に必要というわけではなく、設定に応じて動的に変化する構造が (複数ではなく) 1 つしかない場合などには不要です。たとえば、接続用のログイン情報がシステム管理者用であるかどうかによって構造が変化する `User` エンティティなどです。 MetadataKey パラメーターを含める目的は、出力のメタデータと、キーが定義されているコンポーネントの入力を解決するためのパラメーター値を使用することです。そのため、入力、出力、または属性の MetadataResolver が存在しない場合には、MetadataKey を定義しないでください。SDK バージョン 1.3 以降では、MetadataKey パラメーターを持ちながらも出力リゾルバーや入力リゾルバーを持たないコンポーネントがコネクタに含まれていると、コンパイルに失敗します。 ### [](#metadata_resolvers)メタデータリゾルバー DataSense の動的要素を取得する場合は、メタデータリゾルバーを実装します。リゾルバーには多くの種類があり、それぞれ機能とユースケース (後述) が異なりますが、中心となる以下の概念は同じです。 - カテゴリ名: 異なるメタデータリゾルバーが連携するように関連付けるグループの名前です。 - リゾルバー名: 特定のメタデータリゾルバーを一意に識別する名前です。異なるリゾルバーが同じ `category` に属することはできますが、リゾルバー名は_異なっている必要があります_。 - メタデータコンテキスト: メタデータフェッチ呼び出し中に使用するすべての設定要素と接続要素へのアクセスと、`TypeLoader` や `TypeBuilder` などのユーティリティコンポーネントを提供します。動的型を作成する場合は、コンテキストによって提供される実装を常に使用することが重要です。 # DevKit 移行ツール DevKit 移行ツール (DMT) は、Mule 3.x で動作する DevKit で作成されたコネクタから、Mule 4 SDK と互換性のあるプロジェクトへの移行を支援します。 Anypoint Connector DevKit は、Mule 4 とは互換性がありません。Mule 3 用の独自の DevKit プロジェクトを開発した場合、それを Mule 4 アプリケーションで使用するには、新しい SDK に移行する必要があります。 ## [](#互換性ルール)互換性ルール コネクタを移行するときは、互換性ルールに注意してください。 - 移行は最新の DevKit バージョン (3.8.0 以降) でのみ保証される。 - 最新の検証が適用されないコネクタ、または非推奨コンポーネントやアノテーションを使用するコネクタは、移行中に問題が発生した場合に考慮されない。 - 一部の概念は Mule 4 には存在しない。このツールは、サポートされていないコンポーネントの影響を受ける部分は移行しません。また、MuleSoft が SDK に適用するベストプラクティスに従っていないコードを移行する可能性があります。 - DataSense モデルなど、Mule 4 では一部の機能が大きく異なります。 次の機能は移行されません。 - インバウンド/アウトバウンドメッセージプロパティ - Mule メッセージ/イベントを直接操作する機能 - 変数を変更または照会する機能 移行後、サポートされなくなった機能に対するモジュールのコードまたは動作の変更が必要な可能性があります。 ## [](#devkit-connector-の移行)DevKit Connector の移行 DMT はプロジェクトを移行し、自動的に面倒な作業を 実行します。ただし、移行結果を確認して調整する必要があります。 **プロジェクトを適切に機能させるためには、手動の作業が必要です**。 DMT は次の作業を自動的に実行します。 - 現在のコネクタコードを他の Java ライブラリと同様にラップする、新しい SDK 拡張モデルと互換性のある新しいソースコードを生成する - コードの責務をテスト済みのコネクタコードに委任する - 生成されたコード内のインラインコメントでエラーをマークし、エラーを解決するための次の手順が説明されたドキュメントを示す ## [](#dmt-の実行)DMT の実行 DMT を実行するには、コネクタ `pom.xml` を調整し、コマンドラインからコネクタを作成します。 1. コネクタの `pom.xml` ファイルを開き、`parent` アーティファクトを検索します。 ```xml org.mule.tools.devkit mule-devkit-parent 3.9.4 ``` 2. `groupId`、`artifactId`、`version` の値を変更します。 ```xml org.mule.tools.dmt mule-dmt 1.0.0 ``` 3. `parent` が変更されたため、IDE またはコマンドラインからコネクタを作成します。 mvn clean package テストクラスは SDK を使用してコンパイルされないため、実行、移行、コピーは行われません。移行した プロジェクトでテストクラスを保持する場合は、プロパティ `-DexcludeTests=false` を使用してコネクタを作成します。 mvn clean package -DexcludeTests=false プロセスが完了したら、`Build Success` メッセージが表示されます。 生成された拡張プロジェクトは、`_{rootdir}/target/generated-sources/extension_` フォルダー内に置かれます。  ## [](#サポートされているコンポーネント)サポートされているコンポーネント DevKit Connector の次の要素は、新しい拡張表現に移植されています。 - プロセッサー すべてのプロセッサーは、すべて同じクラス内の操作に移行されます。 プロセッサーのパラメーターは、操作パラメーターに反映される必要があり、 セットアップする必要がある古いコネクタに存在する設定または挿入された 項目としての要素もパラメーターとして渡される必要があります。 拡張操作についての詳細は、[「SDK 操作ドキュメントリファレンス」](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)を参照してください。 - ソース ポーリングソースとトリガーによるソースの両方が新しいソースクラスに移行されます。 デフォルトでは、ソースのコードはコンパイルおよび実行されますが、生成されたソースクラスにコメントが追加されるため、最近移行したコネクタの操作性を改善できます。 拡張ソースについての詳細は、[「SDK ソースドキュメントリファレンス」](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)を参照してください。 - 接続戦略 @Configuration と @ConnectionManagement の両方の戦略が移行されます。 接続についての詳細は、[「SDK での接続」](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)を参照してください。 - 設定 @Configuration 戦略は CachedConnectionProvider に移行されます。これは、その接続が停止されるまで、すべての操作に対して 1 つの接続インスタンスを提供します。 - 接続管理 @ConnectionManagement 戦略は PoolingConnectionProvider に移行されるため、生成された 接続はプールされます。接続のキャッシュは維持されるため、将来の要求で必要になったときに再利用できます。 @ConnectionManagement 接続メソッドが「Single Instance」としてマークされている場合、@Configuration 戦略が移行されるときに、それが CachedConnectionProvider に移行されます。 次の要素もサポートされています。 - [ページ設定された操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/object-streaming) - [メタデータ](https://docs.mulesoft.com/jp/mule-sdk/1.1/metadata) (メタデータオブジェクトは移行されません。MetadataTypes への手動移行が必要です) - [OAuth 接続戦略](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections) - [表示アノテーション](https://docs.mulesoft.com/jp/mule-sdk/1.1/parameter-layout) - [OnException ハンドラー](https://docs.mulesoft.com/jp/mule-sdk/1.1/errors) # HTTP ベースのコネクタ HTTP 要求を発行するか、または HTTP エンドポイントを公開することによってリモートシステムにアクセスするコネクタでは、特別に考慮すべき点がいくつかあります。 ## [](#mule-http-クライアントの使用)Mule HTTP クライアントの使用 HTTP 要求の実行には Mule HTTP クライアントを使用する**必要があります**。他の HTTP クライアント (Jersey クライアント、Apache HTTP クライアント、Jetty、Netty など) を Mule HTTP クライアントの代わりに使用す**べきではありません**。 このルールの唯一の例外は、Mule HTTP クライアントで再現するのが非常に困難な付加価値を持つクライアントライブラリが、すでにリモートシステムベンダーから提供されている場合です。 たとえば、Amazon AWS Connector は、カスタムメッセージ署名を必要とする HTTP API を消費することで機能します。Amazon では、この署名を行うためのロジックをカプセル化したクライアントライブラリを提供しています。 一方、利便性を高めるために HTTP クライアントをラップする以外は何もしないクライアントライブラリ (Google クライアントなど) は、このルールの例外とはなりません。 - HTTP クライアントライフサイクルの処理 HTTP クライアントのライフサイクルは、HttpClient クラスを作成する ConnectionProvider クラスの責任です。 - キャッシュされた接続プロバイダーの使用 HttpClient クラスを作成するすべての ConnectionProvider クラスは、CachedConnectionProvider インターフェースを実装する**必要があります**。 このルールは、接続プロバイダーが生成する接続オブジェクトにも影響します。以前に説明した「接続オブジェクトは内部クライアントを公開しては (内部クライアントであっては) **ならない**」というルールにより、提供される接続オブジェクトは、その状態の一部として HTTP クライアントを含む必要があり、スレッドセーフである**必要があります**。 - Startable および Stoppable 接続プロバイダーの使用 接続プロバイダーは、Startable インターフェースと Stoppable インターフェースも提供する**必要があります**。HttpClient は、start() フェーズで作成および開始される**必要があり**、stop() フェーズで終了される**必要があります**。 ライフサイクルの例: ```java public class HttpConnectionProvider implements CachedConnectionProvider, Startable, Stoppable { @Inject private HttpService httpService; @Parameter private TlsContextFactory tlsContext; @Override public void start() throws MuleException { initialiseIfNeeded(tlsContext); httpClient = httpService.getClientFactory().create(getHttpClientConfiguration()); httpClient.start(); } @Override public void stop() throws MuleException { if (httpClient != null) { httpClient.stop(); } } // rest of the implementation removed for example simplicity } ``` - HTTP クライアント名の設定 各 ConnectionProvider で作成された HttpClient には、その ConnectionProvider を所有する設定の名前に基づいた (あるいは単純に一致する) 名前を付ける**必要があります**。 これは、パフォーマンスのトラブルシューティングにおいて非常に重要です。各 HttpClient は、I/O に使用するセレクタースレッドを作成します。これらのスレッドには、クライアント名にちなんだ名前が付けられます。これらのスレッドに意味のある名前を付けることで、パフォーマンスの問題を診断しやすくなります。 所有する設定の名前は @RefName アノテーションを使用して取得できます。 そのやり方の例を次に示します。 ```java public class HttpConnectionProvider implements CachedConnectionProvider, Startable, Stoppable { @Inject private HttpService httpService; @RefName private String configName @Override public void start() throws MuleException { httpClient = httpService.getClientFactory(). create(new HttpClientConfiguration.Builder() .setName(configName) .build()); httpClient.start(); } // rest of implementation removed for example simplicity } ``` - 操作での非ブロック I/O の活用 HttpClient は、非ブロック I/O を使用して要求を実行できます。操作は、この機能を活用し、さらに非ブロックとして定義される**必要があります**。 - 要素を参照しない HttpService では、個別の 要素に関連付けられている HttpClient を取得できます。この機能は、コネクタで使用するために用意されているわけではありません。コネクタでは、この機能を使用しては**なりません**。 HttpClient インスタンスを必要とするすべてのコネクタは、自分で作成して管理する**必要があります**。 - HTTP プロキシ設定の提供 HTTP クライアントインスタンスを使用するコネクタは、HTTP Connector と同様にプロキシを設定する機能を提供する必要があります。プロキシ設定を使用する一般的な理由には、セキュリティ、メンテナンス、プロキシキャッシュなどがあります。多くの組織では、ファイアウォールの背後で作業する場合にもプロキシ設定が必要です。 次のコードスニペットは、HTTP 要求コネクタの OAuth エンドポイントなどでプロキシを設定する方法を示しています。 このグローバルプロキシ設定を参照として使用します。 クライアントログイン情報許可種別を設定する場合は、次のスニペットを使用します。 認証コード許可種別を設定する場合は、次のスニペットを使用します。 ; ; ; `proxyConfig` 種別を使用する場合、次のように、接続プロバイダーで接続がプロキシを参照するように `@Parameter` アノテーションを含める必要があります。 ```java @Parameter @Optional @Placement(tab = "Proxy", order = 1) private MyConnectorProxyConfiguration proxyConfig; ``` HTTP クライアントでプロキシ設定も定義する必要があります。 ```java .setProxyConfig(connectionParams.getProxyConfig()) ``` 詳細は、HTTP Connector がプロキシを処理する方法に関する [Java コード](https://github.com/mulesoft/mule-http-connector/blob/9914ce6aa6ceb3aa16a5b821289f15b9c6af6acc/src/main/java/org/mule/extension/http/api/request/proxy/DefaultProxyConfig.java)を参照してください。 ## [](#http-インバウンドエンドポイントの公開)HTTP インバウンドエンドポイントの公開 一部のコネクタでは、自身の HTTP インバウンドエンドポイントを公開する必要があります。 そのためには、コネクタで外部 要素を参照して HttpServer インスタンスを取得する**必要があります**。コネクタ自身でサービスを作成しては**なりません**。 これは次のようにして実現する**必要があります**。 - リスナー設定を正しく参照する 接続プロバイダーは、listenerConfig という文字列パラメーターを公開する**必要があります**。このパラメーターは、文字列型で、式を受け入れず、@ConfigReference アノテーションを使用して自身が 要素を参照することを示す**必要があります**。 次に例を示します。 ```java @Parameter @Expression(NOT_SUPPORTED) @ConfigReference(name = "LISTENER_CONFIG", namespace = "HTTP") private String listenerConfig; ``` - RequestHandler の追加 上の listenerConfig パラメーターを使用して、一致する HttpServer インスタンスを次のように取得できます。 ```java HttpServer httpServer; try { httpServer = httpService.getServerFactory().lookup(listenerConfig); } catch (ServerNotFoundException e) { throw new IllegalArgumentException( format("Connector configuration '%s' refers to an with name '%s', " + "but such element doesn't exist", configName, listenerConfigName), e); } ``` 取得した HttpServer で org.mule.runtime.http.api.server.HttpServer#addRequestHandler(java.lang.String, org.mule.runtime.http.api.server.RequestHandler) メソッドを使用して、新しい RequestHandler を追加できます。 コネクタは、このメソッドの Javadocs で定義されているコントラクトに慎重に準拠する**必要があります**。最も重要な点として、このメソッドを呼び出すと RequestHandlerManager インスタンスが返されます。これらのインスタンスは、start() と stop() という 2 つの重要なメソッドを公開するため、コネクタ側で保持する**必要があります**。 インバウンドエンドポイントは、RequestHandlerManager で start() メソッドを呼び出すまでは実際には機能しません。また、RequestHandlerManager で stop() メソッドを呼び出すまで、このエンドポイントは機能し続けます。 そのため、カスタムエンドポイントを所有するコンポーネントが停止した場合は、RequestHandlerManager も停止する**必要があります**。そうしないと、コネクタでメモリリークが発生します。 ### [](#タイムアウトを設定可能にする)タイムアウトを設定可能にする コネクタは、HTTP 要求のタイムアウトを制御するパラメーターを公開する**必要があります**。 これは、期間パラメーターの処理方法と、タイムアウトパラメーターを設定で上書きできるようにする方法に関する前述のルールと一貫した方法で行う**必要があります**。 ## [](#https-セキュリティ)HTTPS セキュリティ コネクタは、可能な限り HTTPS スキームをサポートしている**必要があり**、推奨されるオプションとして考慮する**必要があります**。 - リモートシステムで HTTPS しかサポートしていない場合は、コネクタ側で必要な TlsContextFactory パラメーターを用意する**必要があります**。 - リモートシステムで HTTP と HTTPS の両方のスキームをサポートしている場合は、コネクタで両方のオプションをサポートする必要がありますが、HTTP が使用されたときには警告をログに記録する**必要があります**。 ## [](#関連情報)関連情報 - [MuleSoft ヘルプセンター](https://help.mulesoft.com) - [Mule SDK 開発のベストプラクティス](https://docs.mulesoft.com/mule-sdk/latest/best-practices) # Java 用 Mule SDK 入門 最初の Mule SDK プロジェクトはわずか数ステップで作成できます。 - 必要なソフトウェアをインストールする。 - Maven でプロジェクトを生成して調べる。 - IDE をセットアップする。 - 生成したプロジェクトを構築する。 - コネクタまたはモジュールを開発する。 - Anypoint Studio でコネクタまたはモジュールを実行する。 SDK には、新しいプロジェクトを作成するための Maven プラグインと Maven アーキタイプが用意されています。アーキタイプは、新しいプロジェクトが一貫した構造を持ち、推奨されるプラクティスを採用していて、実験的に使用できる要素がプロジェクトに含まれることを保証する、プロジェクトのテンプレートです。 ## [](#setup)必須ソフトウェアのインストール ローカル環境に以下のツールをインストールして、正しく動作することを確認します。 - Java コードをコンパイルして構築するための Java Development Kit 8 (JDK 8)。 サポートされる Java SDK の最上位バージョンは JDK 11 ですが、JDK 11 はアプリケーションの実行にのみ使用できます。Java SDK でのコンパイルは JDK 8 で行う必要があります。 - プロジェクトの構築を管理するための Apache Maven 3.3.9 以降。 ## [](#setup_ide)Maven プラグインを使用したプロジェクトの生成 `generate` コマンドを実行して、Maven アーキタイプをベースとした拡張プロジェクトを作成します。 mvn org.mule.extensions:mule-extensions-archetype-maven-plugin:1.2.0:generate 必須項目値を入力するように求められた後に、新しいプロジェクトが生成されます。 ## [](#生成されたプロジェクトの探索)生成されたプロジェクトの探索 生成されたプロジェクトには、基本の Mule [モジュール構造](https://docs.mulesoft.com/jp/mule-sdk/1.1/module-structure)にいくつかの基本クラス、ダミー実装、そして生成されたモジュールを使用する実行中のテストが 2 つ含まれています。 このプロジェクトは Maven プロジェクトであるため、Maven が構築を実行するために使用するすべての情報と設定の詳細が格納された `pom.xml` ファイルが入っています。この生成された POM ファイルは、すべての Mule モジュールプロジェクトの共通設定とデフォルトがすべて入った、モジュールの親 POM から継承しています。 ```xml org.mule.extensions mule-modules-parent 1.1.3 ``` ## [](#ide-のセットアップ)IDE のセットアップ SDK が機能するためには、コマンドラインパラメーターの `-parameters` を Java コンパイラーに渡す必要があります。 ### [](#intellij-での開発)IntelliJ での開発 IntelliJ を使用している場合は、次の手順を実行します。 1. `Preferences > Build, Execution, Deployment > Compiler > Java Compiler` に移動します。 2. `-parameters` を `Additional command line parameters` セクションに追加します。  ## [](#プロジェクトの構築)プロジェクトの構築 プロジェクトが生成されたら、プロジェクトを構築します。 mvn clean install このコマンドは、プロジェクトをコンパイルし、テストを実行して、プロジェクトをローカル Maven リポジトリにインストールします。 ## [](#カスタムモジュールコードの開発)カスタムモジュールコードの開発 `@Extension` アノテーションが付加されたクラスを探して、[モジュール構造](https://docs.mulesoft.com/jp/mule-sdk/1.1/module-structure)とモジュールに追加できる各要素を調べてください。これらの要素は、コネクタの変更に使用します。 ## [](#set-custom-icon)コネクタへのカスタムアイコンの追加 コネクタアイコンは .svg 形式のファイルです。コネクタのアイコンをカスタマイズするには、カスタムアイコンが含まれる `icon.svg` ファイルをコネクタツリーのルートにある `icon` フォルダーの下に追加します。 次の画像はアイコンのフォルダー構造の例を示しています。  カスタムアイコンをコネクタに追加したら、アイコンは Anypoint Exchange と Anypoint Studio に表示されます。 ## [](#コネクタの-studio-への追加)コネクタの Studio への追加 コネクタが動作するようになったら、Anypoint Studio で試してみましょう。 Mule アプリケーションの `pom.xml` ファイルを開いて、`` にコネクタの `groupId`、`artifactId`、および `version` を指定してコネクタを追加します。 例: 連動関係 ```xml ... ... org.mule.connector mule-connector 1.0.0 mule-plugin ... ... ``` Java 用 SDK ではバージョンごとに異なる機能が用意されています。「SDK バージョンの選択」を参照して、コネクタに適切なバージョンを選択してください。 # Mule SDK Java 用 Mule SDK または XML を使用して、Mule アプリケーションにインストールできる新しいモジュールを作成することで、Mule 4 Runtime を拡張できます。モジュールの例としては、HTTP などのコネクタや、検証モジュールなどのカスタム機能を備えたモジュールがあります。 SDK は、以下の機能を持つ API を提供します。 - 以前の DevKit と比べて Mule モジュールの開発をスピードアップする。 - モジュールを Mule Runtime の内部から分離する。 - Mule コンポーネントと他のモジュール (クラウドコネクタなど) との一貫性を保証する。 高度で機能が豊富な Java Mule SDK と、アウトバウンド操作のみを提供し、再帰的なコールはサポートしないシンプルな XML SDK のどちらでも使用できます。 ## [](#devkit-との違い)DevKit との違い Java 用 Mule SDK は、DevKit を Mule 4 でさらに発展させたツールです。Devkit の代わりとして、Mule Runtime を拡張するための正規の方法が提供されています。DevKit は、Mule 4 では使用できません。 SDK はアノテーション付き Java クラスという同じ概念の上に成立していますが、内部の動作は異なります。 - SDK はコードジェネレーターではありません。構築されたモジュールには、生成されたコードは含まれません (XSD スキーマすら含まれません)。モジュールは、明確に定義された _Extensions API_ を通して Mule Runtime とのインタラクションを行います。ただし、API の詳細は SDK フレームワークが処理するため、これらについて学習する必要はありません。 - SDK は DevKit より強力で、より多くの機能をサポートします。 - トランザクション - Request-Response (要求-応答) メッセージソース - 動的設定 - ルーター - 非ブロック操作 - クラスローディング分離 - 強化されたランタイムサービスとの相互運用性 ## [](#関連情報)関連情報 - [DevKit から SDK への移行ツール](https://docs.mulesoft.com/jp/mule-sdk/1.1/dmt) - [Java 用 Mule SDK](https://docs.mulesoft.com/jp/mule-sdk/1.1/getting-started) - [XML SDK](https://docs.mulesoft.com/jp/mule-sdk/1.1/xml-sdk) # Mule SDK での関数の寄稿 DataWeave は、Mule 4 の主要な式言語であり、Mule SDK もそれに準拠しています。そのため、Mule [操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)をコーディングするのと同じように、モジュールのコードから DataWeave に関数を寄稿することができます。カスタム関数を使用することで、新しい方法でコードが再利用できるようになり、単一モジュール内で機能が追加され、宣言方法に関するオーバーヘッドも Mule 操作と比較して非常に少なくて済みます。 ## [](#関数の宣言)関数の宣言 Extension レベルで `@ExpressionFunctions` アノテーションを使用することで、DataWeave 関数を表す公開メソッドを含むクラスを参照できます。このメソッドのコードは、名前を識別子として DataWeave スクリプトから直接実行されます。 ```java @Extension(name = "Docs") @ExpressionFunctions(DocsFunction.class) public class DocsModule { } ``` この例は、`DocsFunction` クラスで次のメソッドを定義しています。 ```java public Object xpath(@Optional(defaultValue = PAYLOAD) InputStream item, String expression){ try { return xPathFactory.newXPath().evaluate(expression, documentBuilder.parse(item)); } catch (Exception e) { return null; } } ``` この `xpath` 関数は、DataWeave スクリプト内から使用して、_モジュールの名前空間内で_参照できます。 次の例では XML を読み取って、新しい `xpath` 関数を使用して XPath 検索条件を設定しています。 ```xml 35]/title")]"/> ``` 上記の簡素化された例の実際の実装は、 [XPathFunction.java](https://github.com/mulesoft/mule-xml-module/blob/1.3.3/src/main/java/org/mule/module/xml/internal/xpath/XPathFunction.java) を参照してください。 ## [](#制限-設定と接続には非対応)制限: 設定と接続には非対応 定義上、関数は特定の[設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)や[接続](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)に依存したり、それらを受け取ったりすることはできません。 # Mule SDK のバリデーター バリデーターとは、メッセージを変更することなく Mule メッセージを検証する操作です。バリデーターでは次の効果をもたらすことができます。 - バリデーターで課された条件が満たされた場合、フローは続行し、Mule メッセージは変更されません。 - バリデーターで課された条件が満たされない場合、エラーがスローされます。 ## [](#バリデーターの要件は)バリデーターの要件は? バリデーターになるには、操作は次の要件を満たす必要があります。 - `@Validator` アノテーションによって到達される必要があります。クラスレベルまたはメソッドレベルで割り当てることができます。`@Validator` アノテーションをクラスレベルで使用すると、すべての公開メソッドがバリデーターとしてマークされます。 - `void` を返す必要があります。 - `MULE:VALIDATION` (またはこの拡張) である 1 つ以上のエラーをスローする必要があります。検証に失敗した場合、バリデーターは Mule 検証エラーまたはその子をスローする必要があります。 `@Validator` アノテーション付きのメソッドはステレオタイプ `ValidatorStereotype` に属します。コンポーネントは 2 つのステレオタイプを持つことができないため、複数のステレオタイプをメソッドに割り当てることはできません。 バリデーターは、操作と同じ UX を共有します。Studio で使用するモジュールを追加すると、バリデーターがパレットに表示されます。バリデーターをフローに追加すると、そのパラメーターは操作の場合と同様に割り当てられます。 ## [](#バリデーターの作成方法)バリデーターの作成方法 次の例では、単純なバリデーターを作成する方法を示します。これは、`balance` という名前の単純な拡張機能を作成します。 ```java @Operations({BalanceOperations.class}) @Extension(name = "balance") @ErrorTypes(BalanceError.class) public class BalanceExtension { } ``` 以下の `BalanceOperations` クラスは、`@Validator` アノテーションが付加された検証メソッドを追加します。このメソッドは、汎用的な検証エラー種別から取得するエラー種別をスローします。`BalanceOperations` クラスに `@Validator` アノテーションを付加することもできますが、これを行うと、その中の他の操作がバリデーターとしてフラグ付けされます。 ```java public class BalanceOperations { @Validator @Throws(BalanceErrorsProvider.class) public void hasSufficientFunds(Integer balance, Integer price) throws Exception { if (price > balance){ throw new ModuleException(BalanceError.INSUFFICIENT_FUNDS, new IllegalArgumentException("There is not enough money to make the transaction")); } } } ``` 次の例では、検証が失敗した場合にスローするエラーを作成します。これには検証の失敗に応じた名前が付いています。 ```java public enum BalanceError implements ErrorTypeDefinition { INSUFFICIENT_FUNDS(MuleErrors.VALIDATION); private ErrorTypeDefinition extends Enum>> parent; BalanceError(ErrorTypeDefinition extends Enum>> parent) { this.parent = parent; } @Override public Optional>> getParent() { return Optional.ofNullable(parent); } } ``` バリデーターのメソッドには、検証がスローできるすべてのエラー種別を認識する `ErrorTypeProvider` が必要です。この例では、メソッドがスローできるエラーの種別は **BALANCE:INSUFFICIENT\_FUNDS** のみであることを指定する `ErrorTypeProvider` を作成します。 ```java public class BalanceErrorsProvider implements ErrorTypeProvider { @Override public Set getErrorTypes() { HashSet errors = new HashSet<>(); errors.add(BalanceError.INSUFFICIENT_FUNDS); return errors; } } ``` ## [](#バリデーターの使用方法)バリデーターの使用方法 上記で作成したバリデーターをフローで使用するとします。構文は操作の場合と同じです。`balance` と `price` は必須パラメーターのため、これらを割り当てる必要があります。この場合、変数 `price` と `balance` の値を使用して検証が実行されますが、ここでは任意の式を使用できます。 ```xml ``` ## [](#バリデーターおよびallスコープ)バリデーターおよび「all」スコープ バリデーターはステレオタイプ `ValidatorStereotype` のため、検証モジュールから `all` スコープでバリデーターを使用できます。 次の例では、検証モジュールからバリデーターを使用します。また、これは、値が実際に正であるかどうかを検証する、`isPositive` という名前のバリデーターを持つ数値拡張があることを想定します。 ```xml ``` この例では、空の文字列ではない `buyerName` 変数があることを確認します。その後、`price` と `balance` の両方の変数に正の値が含まれていることを確認します。最後にバリデーターを使用して口座に十分な残高があるかどうかを確認します。 # Mule SDK を使用したスコープの作成 スコープは[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)と似ていますが、これらの実行には、他の子[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)の実行が含まれます。つまり、スコープは基本的に 1 つの `Chain` コンポーネントおよび `CompletionCallback` と共に 1 つ以上の引数 (単純な[パラメーター](https://docs.mulesoft.com/jp/mule-sdk/1.1/parameters)) を受け取る操作です。 `Chain` は、スコープ内で宣言し、抽象化して実行する子[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)を表します。 ## [](#スコープの宣言)スコープの宣言 このデコレーターの例では、スコープの基本構造がわかります。これには、実行される `Chain` と、スコープの実行が完了すると呼び出される `CompletionCallback` があります。 _(yes, すべてのスコープは[非ブロック操作として宣言されます。](https://docs.mulesoft.com/jp/mule-sdk/1.1/non-blocking-operations))_: ```java @Extension(name = "Docs") @Operations(LogDecorator.class) public class DocsModule { } ``` ```java public void logDecorator(Chain operations, CompletionCallback callback) { LOGGER.debug("Invoking child operations") operations.process( result -> { LOGGER.debug(result.getOutput()); callback.success(result); }, (error, previous) -> { LOGGER.error(error.getMessage()); callback.error(error); }); } ``` もちろん、[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)の `Chain` を受け取る場合、何らかの方法でそれらを実行する必要があります。それが `process(successCallback, errorCallback)` で実行される内容です。 この例では、これを使用して、非ブロック形式で `Chain` を実行し、成功またはエラーの場合に結果をリスンします。ここでは、`Chain` の_すべて_の[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)の実行が成功すると、その実行結果を使用して `successCallback` がコールされます。_いずれかの_子[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)の実行中にエラーが発生すると、エラーと最後の成功結果の両方を引数として `errorCallback` がコールされます。 Mule アプリケーションでスコープを使用する例を次に示します。 ```xml ``` これにより、`LOGGER` の呼び出しでラップされた `http:request` 子操作が実行されます。 他のスコープやルーターが含まれるスコープ内で任意の数の[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)を実行できます。 ## [](#パラメーターの追加)パラメーターの追加 スコープは、他の単純な `@Parameters` および `@ParameterGroups` を受け取ることができます。スコープは子要素として宣言される_複雑な_パラメーターを受け取ることができないため、これらは_単純_です。たとえば、デコレーターのログレベルをカスタマイズする場合、それをパラメーターとして受け取ることができるようになります。 ```java public void logDecorator(@Optional(defaultValue="true") boolean debug, Chain operations, CompletionCallback callback) { if (debug){ LOGGER.debug("Invoking child operations") } operations.process( result -> { Object message = result.getOutput(); if (debug){ LOGGER.debug(message); } else { LOGGER.info(message); } callback.success(result); }, (error, previous) -> { LOGGER.error(error.getMessage()); callback.error(error); }); } ``` スコープの API の変更は最小限です。 ```xml ``` デフォルトでは、コンテナスコープで受信したメッセージを使用して `Chain` が実行されますが、`process` メソッドの他の定義を使用すると、スコープのユーザーは、`Chain` の実行に使用されるペイロードや属性をカスタマイズできます。 ## [](#ステレオタイプの使用)ステレオタイプの使用 `Stereotypes` を使用すると、`Chain` 内に存在できる[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)を制限できます。これにより、その用途の一貫性を確保できます。特定の `Stereotypes` のある[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)のみをスコープ内で宣言できます。 ```java public void assertAll(@AllowedStereotypes(AssertionStereotype.class) Chain assertions, @Optional boolean failOnError, CompletionCallback callback) { assertions.process( result -> { callback.success(Result.builder().output(true).build()); }, (error, previous) -> { if (failOnError){ callback.error(error); } else { callback.success(Result.builder().output(false).build()); } }); } ``` ```xml ``` ## [](#設定と接続には非対応)設定と接続には非対応 スコープには、[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)とは異なる制限があります。定義上、スコープは特定の[設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)や[接続](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)に依存したり、それらを受け取ったりすることはできません。 ## [](#1-つの-chain-のみ)1 つの Chain のみ `Chain` コンポーネントはスコープの定義のキーであるため、1 つの `Chain` 引数_のみ_が含まれている_必要_があります。 ## [](#常に非ブロック)常に非ブロック すべてのスコープは、それらの結果を伝えるために `CompletionCallback` を受け取る `void` メソッドとして定義されている必要があります。つまり、すべてのスコープはデフォルトで非ブロックになります。 [「非ブロック操作」](https://docs.mulesoft.com/jp/mule-sdk/1.1/non-blocking-operations)を参照してください。 # Mule SDK を使用したメッセージソースの作成 操作は、メッセージを処理して結果を生成するコンポーネントです。メッセージソースは、Mule Runtime で処理する新しいメッセージを受信または生成するコンポーネントです。 メッセージソースの例: - HTTP リスナー - ファイルウォッチャー - ユーザーが以前にサブスクライブしたキューからメッセージを取得する JMS/AMQP リスナー - Salesforce ストリーミング API ## [](#操作とメッセージソースの類似点)操作とメッセージソースの類似点 操作とメッセージソースには、以下が含まれます。 - パラメーター - 戻り値のデータ型 - 名前と説明 - 再接続機能 ## [](#操作とメッセージソースの相違点)操作とメッセージソースの相違点 操作 メッセージソース 操作はメッセージを処理します。 ソースはメッセージを作成してフローにプッシュします。 操作のライフサイクルは、含まれているフローに関連付けられています。 メッセージソースは、含まれているフローとは独立して開始および停止できます。 操作のパラメーターには、式を受け入れるオプションが含まれます (デフォルト)。 ソースには、式を受け入れることができるパラメーターと受け入れることができないパラメーターの明確な定義があります。式を受け入れることができるのは、応答の生成に含まれるパラメーターのみです。 操作にはライフサイクルを設定できますが、そのパラメーター値は使用できないか、必要ありません。 メッセージソースには、start() および stop() フェーズが必要です。パラメーター値へのアクセス権が必要になる場合もあります。 操作が実行されるたびに接続が取得されます。 メッセージソースが開始されるたび、または再接続の発生時に接続が取得されます。 ## [](#mule-sdk-を介したメッセージソースの実装)Mule SDK を介したメッセージソースの実装 メッセージソースの実装方法を定義する場合、上記の相違点により、操作で定義されているモデルと 100% 一貫性を確保することは困難です。 ソースは、2 つの汎用型 (生成されるイベントペイロードの型と属性の型に対応) を取る `Source` クラスを拡張する場合に必要になります。 ```java @Alias("listener") @EmitsResponse public class HttpListener extends Source {} ``` @Alias アノテーションを使用すると、名前を強制できます。使用しない場合、SDK によって名前が推定されます。 ## [](#次のステップ)次のステップ - [メッセージソースのパラメーターの定義](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-parameters) # Mule SDK を使用したルーターの作成 概念上、ルーターは多くの実行可能なルートと一連のパラメーター (1 つルートまたはすべてのルートの実行を処理するパラメーター、あるいはどのルートの実行も処理しないパラメーター) を受け取ることができる[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)です。 複数の実行パスの候補を受け取る場合、ルートを使用する必要があります。ルートのパラメーターを使用すると、含まれているプロセッサーを実行する必要があるかどうかを判断できます。ステレオタイプは、含まれているチェーンのステレオタイプを定義するためにルートの宣言で使用できます。要素の DSL コンテンツには、パラメーター化された[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)が含まれないため、ルートでは複雑なパラメーターをインラインで定義できません。 ## [](#ルートの定義)ルートの定義 まず、`Route` 基本クラスを拡張して、モジュールで 1 つ以上のルートを宣言する必要があります。 ```java public class WhenRoute extends Route { @Parameter @Optional private boolean shouldExecute; public boolean shouldExecute() { return shouldExecute; } } ``` ## [](#ルーターの宣言)ルーターの宣言 次に、いずれかのモジュールの[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)として、ルーターメソッドを宣言します。`RouterCompletionCallback` と共に 1 つ以上の `Route` 実装を受け取る操作は、ルーターとして登録されます。 ```java @Extension(name = "Docs") @Operations(ChoiceRouter.class) public class DocsModule { } ``` `ChoiceRouter` クラスは、次のメソッドを定義します。 ```java public void choice(WhenRoute when, @Optional OtherwiseRoute otherwise, RouterCompletionCallback callback) { if (when.shouldExecute()) { when.getChain().process(callback::success, (error, previous) -> callback.error(error)); } else if (otherwise != null && otherwise.shouldExecute()) { otherwise.getChain().process(callback::success, (e, r) -> callback.error(e)); } else { callback.success(Result.builder().build()); } } ``` 上記では、ルーターの宣言方法と、設定に基づいてどのようにルートが実行されるのかがわかります。ルートの実行は、各ルート自体がスコープであるかのようにチェーンを介して行われます。 ルーターを使用するには、ルーターパラメーターを設定して、その独自のパラメーターで各ルート宣言を追加します。 ```xml ``` これにより、`payload` が null でないたびに `when` ルートに含まれている `http:request` 操作が実行されます。null の `payload` が到達すると、代替の `otherwise` が実行されます。 ## [](#void-ルーター)Void ルーター **バージョン 1.1 以降で使用可能** 実行の終了時に実行前と同じイベントやメッセージを残すルーターを作成することが必要になる場合もあります。この種のルーターは、Void ルーターと呼ばれます。 Void ルーターを実装するには、メソッドに `RouterCompletionCallback` ではなく `VoidCompletionCallback` 型の引数が必要です。このコールバックは、以前と同じように (`success` および `error` メソッドで) 使用します。ただし、このケースでは `success` でどのパラメーターも受け取りません。 ## [](#制限)制限 次の制限が適用されます。 ### [](#設定と接続には非対応)設定と接続には非対応 ルーターには、[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)とは異なる制限があります。定義上、ルーターは特定の設定や接続に依存したり、それらを受け取ったりすることはできません。 ### [](#常に非ブロック)常に非ブロック すべてのルーターは、その結果を伝えるために `RouterCompletionCallback` を受け取る `void` メソッドとして定義されている必要があります。つまり、すべてのルーターはデフォルトで非ブロックになります。 # Mule SDK 開発のベストプラクティス このドキュメントの目的は、Mule Runtime Engine (Mule) の機能を最大限に活用し、MuleSoft の UX と品質のガイドラインに沿ってモジュールやコネクタを開発するためのベストプラクティスを Mule SDK のユーザーに提供することです。 ## [](#用語)用語 このドキュメントでは次の用語を使用します。 Connector (コネクタ) 外部システムとの接続を確立するモジュール。コネクタはモジュールです。 大きな文字列 サイズが 4 KB を超える文字列。 Module (モジュール) Mule SDK で開発し、Mule 4 の機能を拡張するプラグイン。 Mule 言語 XML ベースのドメイン特有言語 (DSL) で、Mule アプリケーションの開発で使用し、操作の内部でモジュールを呼び出します。 「しなければなりません」/「してはなりません」 「しなければなりません」/「してはなりません」は厳密なルールを意味します。つまり、ベストプラクティスに準拠するためには、「する必要がある」と指示されているすべてのプラクティスを実践しなければなりません。 「するべきです」/「するべきではありません」 「するべきです」/「するべきではありません」は、推奨されるルールではあるものの、場合によっては省略することも可能で、省略した場合でもベストプラクティスには準拠できることを意味します。 対象システム:: コネクタがアクセスするリソース。 ユーザー 「ユーザー」は、Mule SDK (モジュールを開発するためのシステム) のユーザーではなく、開発されたモジュールを消費するエンドユーザーを指します。すべてのベストプラクティスは、エンドユーザーのエクスペリエンスを改善することを最終的な目的としています。 ## [](#mulesoft-のコーディングプラクティス)MuleSoft のコーディングプラクティス SDK を使用して新しいモジュールやコネクタを作成する場合は、API、ライブラリ、または機能の断片を Mule が理解できるコンポーネントに単純にラップするというアプローチを採る**べきではありません**。 その代わりに「Mule というプログラミング言語を拡張する」というアプローチを採る**べきです**。 C プログラミング言語や自分の Java フレームワークで新しいライブラリを作成する場合であれば、ライブラリを消費する C または Java の開発者が、ライブラリに一貫性があってエコシステム特有のすべてのルールやガイドラインに準拠していることを実感できるように、ライブラリの API、構文、セマンティクスを設計するでしょう。これを怠ると、一貫性や明確さが期待通りではなくなり、ライブラリのユーザーを失望させることになります。 カスタム Mule モジュールやコネクタの開発でも同じことが言えます。モジュールやコネクタは、単に Mule ブリッジを作成することで開発するのではなく、一貫性があり、使いやすく、他の要素と相互に関連性を持つ方法で機能を追加する、Mule 言語の拡張として開発する必要があります。 ## [](#関連情報)関連情報 - [MuleSoft ヘルプセンター](https://help.mulesoft.com) # Mule サービスインジェクション ## [](#mule-サービスの使用)Mule サービスの使用 モジュールを実装する際には、Mule が提供するいくつかのサービスの使用が必要となる場合があります。これらのサービスとしては、`ObjectStoreManager`、`LockFactory`、`HttpService` などがあります。 サービスを使用するには、`MuleContext` のレジストリから取得する必要はありません。単に `@Inject` アノテーションを使用してコンポーネント (操作、ソース、設定など) に挿入するだけです。 レジストリのサービスをコンポーネントに挿入するシンプルな例を示します。 例: @Inject アノテーションの使用 ```java public class ObjectStoreOperations { // ... @Inject private ObjectStoreManager runtimeObjectStoreManager; // ... @Throws(StoreErrorTypeProvider.class) public void store(String key, @Content TypedValue value, @Optional @ParameterDsl(allowInlineDefinition = false) ObjectStore objectStore) { ObjectStore os = objectStore == null ? runtimeObjectStoreManager.getDefaultPartition() : objectStore; os.store(key, value); } // ... } ``` 一般的な Mule サービスをいくつか紹介します。 - `LockFactory`: 共有データにアクセスするために同期が必要なすべての Mule コンポーネントは、このインターフェースのデフォルト実装からロックを使用して同期する必要があります。`LockFactory` の詳細は、[「分散ロッキング」](https://docs.mulesoft.com/jp/mule-runtime/4.4/distributed-locking)を参照してください。 - `ExpressionManager`: XML、Java、スクリプト、アノテーションなど、Mule 設定に組み込まれた式を評価するためのユニバーサルアクセスを提供します。 - `TransformationService`: 値を別の指定された型に変換するためのサービスです。 - `HttpService`: HTTP のサーバー実装とクライアント実装の両方を提供します。コネクタで HTTP 接続を使用する場合は、このサービスの使用を試行する必要があります。 - `SchedulerService`: Mule Runtime に存在する異なるスケジューラーとスレッドプールへのアクセスを提供し、タスクをスケジュールできるようにします。 - `SoapService`: SOAP サービスをコンシュームする SOAP クライアントを作成するサービスです。 - `ObjectStoreManager`: `ObjectStore` インスタンスの作成と管理を担当するマネージャーです。 # MuleSoft Connector 認定プログラムのガイドラインについて このドキュメントは、Mule 4 のコネクタ認定に関連します。Mule 3 の認定については、[DevKit ドキュメント](#3.9@connector-devkit::connector-certification-program-guidelines.adoc)を参照してください。 MuleSoft のコネクタ認定プログラムでは、MuleSoft の認定を受けられる状態のエンタープライズグレードコネクタを作成するステップを順を追って説明します。認定されると、コネクタは Anypoint Exchange を介して顧客と開発者が検索および使用できるようになります。 ## [](#開始する前に)開始する前に 認定プログラムに着手する前に、次の事項を検討し、これらの要件を順守できることを確認します。 - コネクタは最新かつ安全な状態に保ち、少なくとも年 1 回は再認定を受ける必要がある。 - コネクタは、エンタープライズバージョンの MuleSoft ソフトウェアまたは MuleSoft サービス用に作成および配布する必要がある。 - コネクタのすべてのトランザクションは、MuleSoft を介してではなく顧客とパートナー間で行われる必要がある。 - コネクタは完全に機能し、本番対応のエンタープライズグレードのアプリケーションおよびプロトコルコネクタである必要がある。つまり、Mule を外部システムと接続するコネクタである必要があります。 - コードは、継続的インテグレーション環境にデプロイできる状態になっている必要があります。コードは、非公開リポジトリをインポートすることなしにコマンドラインからコンパイルできる必要があります。ログイン情報は個別に提供され、コンパイル時に設定できる必要があります。さらに、認定にはコネクタの Sandbox ログイン情報が必要です。 - コネクタは、オープンソースまたは自分が所有するサードパーティライブラリのみを使用する必要がある。サードパーティの配布不可能なライブラリは使用できません。 - Anypoint Exchange に同様のコネクタがすでに存在する場合でも、既存のコネクタよりも優れた追加機能があれば、そのコネクタを送信可能。 ## [](#サポートの提供)サポートの提供 パートナーまたは開発者は、Anypoint Exchange の各コネクタに対して完全なサポートを提供する必要があります。MuleSoft が受け取ったサポートの問い合わせについて、MuleSoft は商業的に合理的なレベルの Tier 1 の電話、Web ベースやメールによるサポートを顧客に直接提供します。MuleSoft は、市販の MuleSoft 製品に関連する問題を解決します。パートナーコネクタに固有の問題は、パートナーにエスカレートされます。 - パートナーは、1 営業日以内に MuleSoft からエスカレートされたすべてのサポート問い合わせに応答する。 - パートナーは、5 営業日以内に顧客の技術サポートの問題を解決するために最善を尽くす。 ## [](#コネクタの価格設定)コネクタの価格設定 パートナーまたは開発者は、コネクタを無料または有料で使用可能にするかどうかを決定する独自の裁量権を持ちます。ただし、Anypoint Studio 内ではすべてのコネクタを無料で使用できるようにする必要があります。必須ではありませんが、設計やデプロイメント用のコネクタのトライアルを顧客に提供することをお勧めします。 詳細は、下記の「[カスタムモジュールライセンス](#see_also)」リンクを参照してください。 カテゴリ 詳細 無料 コネクタは、顧客が Anypoint Exchange を介してダウンロードして無料で使用できます。 有料 有料コネクタは、Anypoint Studio での設計時に Mule アプリケーションで使用できます。デプロイメントでは、コネクタはライセンスがないと実行できません。顧客はパートナーから直接コネクタを購入する必要があり、MuleSoft が提供する生成されたライセンスキーを使用して、有料コネクタの使用を管理する必要があります。コネクタの価格設定は、パートナーによって決定されます。 ## [](#ライセンス条件)ライセンス条件 `LICENSE.md` のライセンス規約の前に次の法的規約を追加します。 **MuleSoft 認定コネクタについて** MuleSoft 認定コネクタは、MuleSoft のパートナーおよび開発者コミュニティによって開発されています。これらのコネクタは、MuleSoft によってレビューおよび認定されています。必要に応じて <コネクタ名> Connector を購入したり、その支援やサポートを受けたりするには、直接 _<パートナー名>_ (_連絡先情報_) にお問い合わせください。MuleSoft は、MuleSoft 認定コネクタのサポートの一切の義務を放棄します。 コネクタをインストールすると、お客様は、MuleSoft がお客様の連絡先情報をこのコネクタの開発者と共有して、お客様がコネクタに関する詳細情報を開発者から直接受信できるようにすることに同意したことになります。 _独自のライセンス規約。_ ## [](#コンプライアンスのエクスポート)コンプライアンスのエクスポート 米国の法律で認められている場合を除き、MuleSoft から受け取った「MuleSoft の機密情報」や「MuleSoft ドキュメント」またはお客様の資料 (「パートナードキュメント」や「パートナーコネクタ」を含むがこれに限定されない) を使用することや、輸出または再輸出することはできません。特に、例外なく、「MuleSoft の機密情報」、「MuleSoft ドキュメント」およびお客様の資料は、次のいずれの者に対しても、輸出または再輸出を行うことができません。(a) 米国の通商禁止国 (b) 米国財務省の特別指定国リストまたは米国商務省の拒否人名リスト上の一切の者。 お客様は、上記国家に住居を定めていないこと、あるいは上記リストに該当するものではないことを表明および保証するものとします。また、お客様は、お客様が米国の法律で禁止されている目的で「MuleSoft の機密情報」や「MuleSoft ドキュメント」およびお客様の資料を使用または再輸出しないことに同意していただいたものとし、当該目的には核、化学兵器もしくは生物兵器の開発、設計、製造または生産を含みますがこれらに限定されません。 Anypoint Exchange を介したユーザーへの資料の提供が、関連管轄区域における技術の輸出入に関するあらゆる規制に準拠していることを確認する責任は、お客様が単独で負うものとします。(大文字で表記された用語は、認定コネクタパートナー契約と同じ定義を持つものとします)。 ## [](#開発および認定)開発および認定 開発するコネクタについて MuleSoft に通知し、[MuleSoft](mailto:isv@mulesoft.com) に連絡して認定を受けます。MuleSoft から詳細情報についての連絡があります。 ## [](#see_also)関連情報 - [コネクタ認証の技術ガイドライン](https://docs.mulesoft.com/jp/mule-sdk/1.1/certification-guidelines-for-connectors) - [カスタムモジュールライセンス](https://docs.mulesoft.com/jp/mule-sdk/1.1/license#custom-module-license) - [MuleSoft フォーラム](https://forums.mulesoft.com) - [MuleSoft へのお問い合わせ](mailto:isv@mulesoft.com) # Null Safe ユーザーがパラメーターの値を指定していないときでも `@Parameter` をインスタンス化する必要がある場合があります。次に例を示します。 ```java @Parameter @Optional private List numbers; ``` `numbers` をコードで操作する場合は、`NullPointerException` を発生させないようにするために、どこかで `numbers == null` のチェックが必要です。 SDK は `null` の代わりに空のリストを提供する `@NullSafe` などのアノテーションの使用をサポートしています。これを使用すると、SDK は値が指定されていない場合には自動的に値を作成します。 次の [サンプルコード](https://github.com/mulesoft/mule-http-connector/blob/master/src/main/java/org/mule/extension/http/internal/request/RequestSettings.java)は、`List` インターフェースに `@NullSafe` を使用します。 `@NullSafe` アノテーションにはいろいろな種類があります。`List` インターフェースや `Map` インターフェースと一緒に使用すると、`@NullSafe` はこれらのコレクションのデフォルト実装を作成します。 次の例では、POJO を null safe 型としています。 ```java @Parameter @Optional @NullSafe private Foo foo; ``` ご推察のとおり、SDK は `Foo` をインスタンス化して、`foo` パラメーターに割り当てることで、手動での null チェックを不要にします。 `@NullSafe` を POJO で使用する場合は、POJO 内で宣言するすべてのパラメーターを_省略可能_とする必要があります。SDK は、必須パラメーターのデフォルト値を作成できません。そのため、`@NullSafe` を使用して必須パラメーターを自動的にインスタンス化することは無意味です。 パラメーターの型を使用する代わりに、特定のクラスをインスタンス化するように `@NullSafe` を設定することもできます。これは、パラメーターの型をインスタンス化できない場合 (抽象クラスやインターフェースなど) に便利です。 インスタンス化するクラスは、アノテーションで `defaultImplementingType` 属性を設定することで指定します。次に例を示します。 ```java @Parameter @Optional @NullSafe(defaultImplementingType = Foo.class) private AbstractFoo foo; ``` # OAuth OAuth 2.0 は、業界標準の認証プロトコルです。OAuth 2.0 は、クライアント開発者の手間を簡素化することに主眼を置いており、Web アプリケーション、デスクトップアプリケーション、携帯電話、家庭用機器のそれぞれに特化した認証フローを提供しています。OAuth 2.0 プロトコルの詳細は、 [https://oauth.net/2/](https://oauth.net/2/) を参照してください。 SDK は、OAuth 対応モジュールの開発をサポートしており、これらのモジュールでは OAuth プロトコルで認証される接続を確立できます。これにより、エンドユーザーに対しては OAuth プロトコルの複雑さのほとんどが隠されるため、OAuth の学習を不要にしています。 SDK による OAuth のサポートは以下に制限されます。 - OAuth バージョン 2 のみ - [認証コード許可](https://docs.mulesoft.com/mule-sdk/latest/authorization-code)種別 - [クライアントログイン情報](https://docs.mulesoft.com/mule-sdk/latest/client-credentials)許可種別 (バージョン 1.3 以降で使用可能) # OAuth 対応コネクタまたはモジュールでの OAuth ダンスの実行 モジュールを使用するための最後のステップは、OAuth ダンスのトリガーです。 [「OAuth 対応コネクタまたはモジュールの設定」](https://docs.mulesoft.com/jp/mule-sdk/1.1/oauth-configuring)で説明されている `authorizePath` パラメーターは、ブラウザーにヒットして OAuth ダンスを開始するために必要な、自動的に作成される HTTP エンドポイントのパスをエンドユーザーが設定するために使用します。 ヒント: SDK でサポートされる認証コード許可種別は、Web ブラウザーでのユーザーの操作を必要とします。 ## [](#multi-tenancy)Multi-Tenancy OAuth にとってのマルチテナントとは、OAuth ダンスを複数回実行できて、それぞれ取得したトークンを異なるリソースオーナー ID に関連付ける機能を意味します。 エンドユーザーは、ダンスの開始時にトークンに割り当てる `resourceOwnerId` を指定する必要があります。たとえば、`authorizePath` を `/authorize` に設定し、ユーザー `sdk_demo` に対してダンスを実行する場合は、次の HTTP パスにヒットする必要があります: `/authorize?resourceOwnerId=sdk_demo`。 ダンスが完了したら、そのユーザー用に取得されたアクセストークンを使用して操作を実行します。それには、モジュール設定の `resourceOwnerId` パラメーターで式を使用します。以下に完全な例を示します。 ```xml (1) (2) ``` 1resourceOwnerId パラメーターが式に設定されます。OAuth で保護された操作を実行するたびに、この式が評価され、その値に関連付けられているトークンが使用されます。2認証エンドポイント authorizePath が設定されます。 ### [](#アクセストークンの無効化)アクセストークンの無効化 マルチテナントでは、特定の `resourceOwnerId` のアクセストークンを無効化できます。トークンを無効化すると、関連付けられているトークン情報が削除されます。 アクセストークンを無効化できるように、SDK はすべての OAuth 対応コネクタまたはモジュールに `unauthorize` という操作を自動的に追加します。上記の例の場合、取得したトークンを無効化するには、次のいずれかのステートメントを使用します。 ```xml ``` ## [](#次のステップ)次のステップ [期限切れのアクセストークンの処理](https://docs.mulesoft.com/jp/mule-sdk/1.1/oauth-token-expiration) # OAuth 対応コネクタまたはモジュールの設定 ユーザーが OAuth 対応コネクタやモジュールをどのように使用できるかも重要です。SDK は OAuth プロトコルの複雑さを可能な限り隠しますが、OAuth ダンスなどは隠せません。この問題に対して SDK は、すべての OAuth Module の使用方法を標準化して、ユーザーエクスペリエンスを簡素化することに努めています。 このセクションでは、ユーザーがモジュールを使用するための手順について説明します。 ## [](#合成パラメーター)合成パラメーター 接続プロバイダーで明示的に定義されているすべての設定に加えて、SDK はいくつかのパラメーターを追加して、適切な動作を挿入します。 パラメーター名 必須 式 デフォルト値 説明 resourceOwnerId いいえ SUPPORTED なし ユーザーは、関連付けられているアクセストークンと更新トークンを所有するテナントの ID を指定することでマルチテナントをサポートできます。認証ダンスを実行すると、この値によって取得されているトークンの ID が提供されます。コンポーネントで新しい接続が必要な場合は、使用するデフォルトのオーナー ID として使用されます。 consumerKey はい NOT_SUPPORTED なし サービスプロバイダーに登録されている OAuth consumerKey。 consumerSecret はい NOT_SUPPORTED なし サービスプロバイダーに登録されている OAuth consumerSecret。 authorizationUrl いいえ NOT_SUPPORTED `@AuthorizationCode アノテーションで提供されている値。 サービスプロバイダーの認証 URL。 accessTokenUrl いいえ NOT_SUPPORTED @AuthorizationCode アノテーションで提供されている値。 サービスプロバイダーのアクセストークン URL。 state いいえ REQUIRED なし OAuth ダンスの開始時に送信し、トークンコールバックによってサービスプロバイダーから返される文字列値。ダンスの開始とトークンのコールバックを相関させるために使用します。この属性の最も一般的なユースケースはマルチテナントです。 scope いいえ NOT_SUPPORTED @AuthorizationCode アノテーションで提供されている値。 OAuth ダンス時に要求する OAuth スコープ。指定しない場合、デフォルトのアノテーションの範囲になります。 listenerConfig はい NOT_SUPPORTED なし アクセストークンコールバックエンドポイントをキャッチするリスナーの作成に使用する <http:listener-config /> への参照。 callbackPath はい NOT_SUPPORTED なし アクセストークンコールバックエンドポイントのパス。 authorizePath はい NOT_SUPPORTED なし OAuth ダンスをトリガーするローカル HTTP エンドポイントのパス。 externalCallbackUrl いいえ NOT_SUPPORTED なし コールバックエンドポイントがプロキシの背後にあるか、直接 URL 以外でアクセスする必要がある場合、このパラメーターを使用して OAuth プロバイダーに、コールバックへのアクセスに使用すべき URL を指示します。 resourceOwnerId YES SUPPORTED なし 各コンポーネントが他を参照しない場合に使用する必要がある resourceOwnerId。 objectStore いいえ NOT_SUPPORTED なし 各リソースオーナー ID のデータの保存に使用するオブジェクトストアへの参照。指定しない場合、Runtime は自動的にデフォルトのオブジェクトストアをプロビジョニングします。 before いいえ NOT_SUPPORTED なし OAuth ダンスを開始する直前に実行するフローの名前 (事前フローを参照)。 after いいえ NOT_SUPPORTED なし accessToken が受信された直後に実行するフローの名前 (事後フローを参照)。 ## [](#式の使用について)式の使用について 上記の表には、式を受け入れる多くの合成パラメーターが示されています。式を使用することで、通常のパラメーターで式を使用するのと同じ効果が得られ、動的なパラメーター設定を可能にします。 ## [](#oauth-接続-dsl)OAuth 接続 DSL 生成される DSL は次のようになります。 ```xml ``` - 他のすべてのプロバイダーと同様に、通常パラメーターと OAuth パラメーターはすべて接続プロバイダーレベルで示されています。 - 認証コード許可種別に関連したパラメーター (`consumerKey`、`consumerSecret`、`authorizationUrl`、`accessTokenUrl`、`localAuthorizationHost`、`localAuthorizationPort`、`localAuthorizationPath`、`before`、`after`、`scope`、`defaultResourceOwnerId`) は、`` という子要素に配置されます。 - コールバックに関連したパラメーターは、`` という子要素に配置されます。 - オブジェクトストアに関連したパラメーターは、`` という子要素に配置されます。 ## [](#ダンス前後のカスタムロジック)ダンス前後のカスタムロジック OAuth ダンスを開始する直前やダンスが完了した直後に、エンドユーザーが何らかのランダムロジックを実行する必要が生じることがよくあります。たとえば、指定されたオーナー ID が正常にオンボードされたことを外部システムに通知したり、活動ログを保存したり、といったユースケースです。 認証プロセスは、自動的に作成されるエンドポイントをヒットすることでトリガーされるため、`` 子要素には `before` パラメーターと `after` パラメーターがあります。 これらの省略可能なパラメーターは、OAuth ダンスの前または後に呼び出す `` の名前を指定します。 ### [](#before_flow)事前フロー 事前フローは、OAuth ダンスが開始される直前に実行されます。フローに送信されるイベントのペイロードは、`AuthorizationCodeRequest` のインスタンスであり、次のような不変の POJO となります。 ```java public interface AuthCodeRequest { /** * @return The id of the user being authenticated */ String getResourceOwnerId(); /** * @return The scopes that were requested */ Optional getScopes(); /** * @return The OAuth state that was sent */ Optional getState(); /** * @return The external callback url that the user configured or {@link Optional#empty()} if none was provided */ Optional getExternalCallbackUrl(); } ``` ユーザーは、必要に応じてカスタムロジックをこのフローで自由に実行できます。特に、フロー変数を設定するのに便利です (「[事後フロー](#after_flow)」参照)。 ### [](#after_flow)事後フロー 事後フローは、アクセストークンを受け取って格納した直後に実行されます。このフローは、事前フローの結果に相当するイベント (事前フローが定義されていない場合は空のイベント) で実行されますが、ペイロードは `ConnectionProvider` に挿入されたのと同じ `AuthorizationCodeState` オブジェクトに置換されます。ただし、設定されている変数はそのまま残ります (事前フローが定義されていない場合は空になる)。 ## [](#カスタム-objectstore-の設定)カスタム ObjectStore の設定 取得したアクセストークンは `ObjectStore` に保存されます。デフォルトでは、SDK はトークンをアプリケーションのデフォルトストアに保存しますが、ユーザーは次のようにカスタムオブジェクトストアを定義することもできます。 ```xml (2) ``` 1カスタムストアを定義します。2モジュールの設定からそのストアを参照します。 ## [](#次のステップ)次のステップ [OAuth 対応コネクタまたはモジュールでの OAuth ダンスの実行](https://docs.mulesoft.com/jp/mule-sdk/1.1/oauth-dance) # Result オブジェクト `Result` オブジェクトは、コンポーネントの実行結果を表します。このオブジェクトは、コンポーネントがメッセージペイロードに値を設定して戻す必要があるケースだけではなく、メッセージ属性や MIME タイプを指定するケースでも使用されます。 クラスには、ペイロードに格納される値の型と、返されるメッセージ属性の型の 2 つの汎用型があります。 ファイルコネクタの `read` 操作を大幅に簡素化した例を示します。この操作は、ペイロードをファイルの内容を含む `InputStream` に設定します。また、属性をファイル名、サイズ、タイムスタンプ、権限などの情報が入った `FileAttributes` オブジェクトに設定します。 ```java public Result read(String path) { (1) InputStream content = getContent(path); FileAttributes attributes = getAttributes(path); return Result.builder() (2) .output(content) (3) .attributes(attributes) (4) .build(); (5) } ``` 1操作は Result<InputStream, FileAttributes> を返します。これは、操作が InputStream をペイロードとして、FileAttributes を属性として返すことを Runtime に通知します。2結果値を取得すると、Result.builder() を使用して新しいインスタンスを作成します。この値は厳密に型指定されているため、ビルダーを作成する際には汎用型を指定する必要があります。3ビルダーの output(Object) メソッドは、ペイロードの設定に使用します。4attributes(Object) は、属性の設定に使用します。5例では、build() メソッドをコールして、作成された Result を返しています。 ## [](#mime-タイプの設定)MIME タイプの設定 `Result` オブジェクトを使用して出力の MIME タイプを設定できます。前述の例を少し変えて、操作でファイルの最適な MIME タイプをファイル拡張子から推定します。 ```java public Result read(String path) { InputStream content = getContent(path); FileAttributes attributes = getAttributes(path); MediaType guessedMediaType = MediaType.ANY; if (path.endsWith(".json")) { guessedMediaType = MediaType.APPLICATION_JSON; } else if (path.endsWith("*.xml")) { guessedMediaType = MediaType.APPLICATION_XML; } else if (path.endsWith("*.bin")) { guessedMediaType = MediaType.BINARY; } return Result.builder() .output(content) .attributes(attributes) .mediaType(guessedMediaType) .build(); } ``` 上記の例では、MediaType クラスは @MediaType アノテーション付きではなく、Mule API の org.mule.runtime.api.metadata.MediaType となっています。 ## [](#void-属性)void 属性 ペイロードと MIME タイプを設定し、属性は設定しない場合、void 型を使用します。次に例を示します。 ```java public Result read(String path) { InputStream content = getContent(path); return Result.builder() .output(content) .mediaType(bestGuessMediaType(path)) .build(); } ``` # SDK コンポーネントおよび操作のトラブルシューティング - Mule 4 以下のトラブルシューティング機能は、Mule SDK 1.4 以降で使用できます。 Java SDK のトラブルシューティングを行うために、ログ記録 (冗長ログを含む) を有効にする方法と、一般的なエラーメッセージの解釈について学習します。 ## [](#ログ記録)ログ記録 ログを使用して、次の SDK コンポーネントのトラブルシューティングを行います。 コンポーネント名 ログ機能 ソース ライフサイクルの開始時と終了時など、ソースライフサイクルに関する情報をログに記録します。 エラーと再接続の場合、ログには発生した例外に関連付けられた完全なスタック追跡が表示されます。 クラスター環境の場合、ログにはソース状況情報が表示されます。これは、それがプライマリソースであるかどうかを示します。 ポーリング入力元 ソースによって承認および拒否された項目に関する情報をログに記録します。 拒否の場合、ログには拒否の原因に関する情報が含まれます。 ポーリング入力元のウォーターマーク処理 ポーリング入力元に対するウォーターマーク処理に関する情報をログに記録します。 このプロセスは低レベルのロジックを使用するため、デバッグまたはトラブルシューティングが必要な場合にのみトレースログを有効にします。 プーリング接続プロバイダー プーリング接続プロバイダーの接続管理に関する情報をログに記録します。 このログには、接続プールの状況情報、およびプールが接続を取得して返すタイミングを示す接続処理が表示されます。 ## [](#冗長ログ)冗長ログ 冗長ログを使用して SDK コンポーネントのトラブルシューティングを行い、状況または動作に関する情報を取得します。 アプリケーションのパフォーマンスに大きく影響するため、冗長ログはテストやトラブルシューティングでのみ使用してください。 Anypoint Studio、または CloudHub API を使用している場合は Anypoint Runtime Manager で、冗長ログを有効にします。 どちらの場合も、アプリケーションのログファイルに情報が記録されます。 ### [](#anypoint-studio-での冗長ログの有効化)Anypoint Studio での冗長ログの有効化 次の手順では、Anypoint Studio を使用して冗長ログを有効にする方法について説明します。 1. Anypoint Studio にアクセスし、**\[Package Explorer\]** ビューに移動します。 2. アプリケーションのプロジェクト名を開きます。 3. `src/main/resources` パスフォルダーを開きます。 4. フォルダー内の `log4j2.xml` ファイルを開きます。  5. `` タグ内に `` タグを追加します。 ```xml ... ... ``` コンポーネントの完全修飾名を指定するための参照として、次の表を使用してください。 名前 完全修飾名 ログレベル 接続元 org.mule.runtime.module.extension.internal.runtime.source.ExtensionMessageSource DEBUG ポーリング入力元 org.mule.runtime.module.extension.internal.runtime.source.poll.PollingSourceWrapper DEBUG ポーリング入力元のウォーターマーク処理 org.mule.runtime.module.extension.internal.runtime.source.poll.PollingSourceWrapper TRACE プーリング接続プロバイダー org.mule.runtime.core.internal.connection.PoolingConnectionHandler org.mule.runtime.core.internal.connection.PoolingConnectionManagementStrategy DEBUG 次の例は、完全修飾名を `log4j2.xml` ファイルに追加し、ソースの冗長ログを有効にする方法を示しています。 ```xml ... ``` ### [](#anypoint-runtime-manager-での冗長ログの有効化)Anypoint Runtime Manager での冗長ログの有効化 次の手順では、Anypoint Runtime Manager を使用して冗長ログを有効にする方法について説明します。 1. Anypoint Runtime Manager にアクセスします。 2. 目的のアプリケーションを選択します。 3. 左側のペインで、**\[Settings (設定)\]** に移動します。 4. **\[Logging (ログ)\]** タブに移動します。  5. コンポーネントの完全修飾名とログレベル (DEBUG または TRACE) を追加します。 コンポーネントの完全修飾名を指定する方法が示されている表を参照してください。 6. **\[Apply Changes (変更を適用)\]** をクリックします。 ## [](#ログの例)ログの例 次の例は、SDK コンポーネントで想定されるログを示しています。 - [ソースログの例](#source-logging-example) - [ポーリングソースログの例](#polling-source-logging-example) - [ポーリングソースウォーターマークログの例](#polling-source-watermarking-logging-example) - [プーリング接続プロバイダーログの例](#pooling-connection-provider-logging-example) 以下の例は、FTP サーバーのファイルをリストする FTP Connector ソースと処理したファイルの名前を記録するロガーで構成される Mule アプリケーションからのログです。  ### [](#source-logging-example)ソースログの例 次の例は、ソースのログを示しています。 ```none org.mule.runtime.module.extension.internal.runtime.source.ExtensionMessageSource: Message source 'listener' on flow 'ftp-troubleshooting-examples' threw exception. Attempting to reconnect... org.mule.runtime.module.extension.internal.runtime.source.ExtensionMessageSource: Message source 'listener' on flow 'ftp-troubleshooting-examples' successfully reconnected org.mule.runtime.module.extension.internal.runtime.source.ExtensionMessageSource: Message source 'listener' on flow 'ftp-troubleshooting-examples' could not be reconnected. Will be shutdown. org.mule.runtime.module.extension.internal.runtime.source.ExtensionMessageSource: Message source 'listener' on flow 'ftp-troubleshooting-examples' is stopping ``` ### [](#polling-source-logging-example)ポーリングソースログの例 次の例は、ポーリングソースのログを示しています。 ```none org.mule.runtime.module.extension.internal.runtime.source.poll.PollingSourceWrapper: Item with id:[/ftp-example.json] is accepted org.mule.runtime.module.extension.internal.runtime.source.poll.PollingSourceWrapper: Item with id:[/ftp-example.json] is rejected with status:[FILTERED_BY_WATERMARK] ``` ### [](#polling-source-watermarking-logging-example)ポーリングソースウォーターマークログの例 次の例は、ポーリングソースウォーターマークのログを示しています。 ```none org.mule.runtime.module.extension.internal.runtime.source.poll.PollingSourceWrapper: A new watermark maximum has been found when processing item with id /ftp-example.json for source in flow ftp-troubleshooting-examples ``` ### [](#pooling-connection-provider-logging-example)プーリング接続プロバイダーログの例 次の例は、プーリング接続プロバイダーのログを示しています。 ```none org.mule.runtime.core.internal.connection.PoolingConnectionManagementStrategy: Acquiring connection org.mule.extension.ftp.internal.connection.FtpFileSystem@1a0c776f from the pool FTP_Config-5e20b7d9-417d-4307-ab4c-9ef3e7ae4d9b org.mule.runtime.core.internal.connection.PoolingConnectionManagementStrategy: Status for pool FTP_Config-5e20b7d9-417d-4307-ab4c-9ef3e7ae4d9b: 1 connections are active out of 5 max active limit, 0 connections are idle out of 5 max idle limit ``` ## [](#エラー-cannot-find-org-mule-sdk-api-classes-org-mule-sdk-api-クラスが見つかりません)エラー: Cannot Find org.mule.sdk.api Classes (org.mule.sdk.api クラスが見つかりません) モジュールの親 POM のバージョン 1.4.0 を使用すると、Java SDK によって `Cannot access XYZ class file: XYZ not found` または `Cannot find symbol: method someMethod() location: variable someVar of type XYZ` (この XYZ は `org.mule.sdk.api` パッケージのクラス) などのエラーがスローされます。 ```xml org.mule.extensions mule-modules-parent 1.4.0 ``` 次に例を示します。 \[ERROR\] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project : Compilation failure: cannot access org.mule.sdk.api.runtime.streaming.StreamingHelper \[ERROR\] class file for org.mule.sdk.api.runtime.streaming.StreamingHelper not found cannot find symbol \[ERROR\] symbol: method resolveCursors(java.util.HashMap,boolean) \[ERROR\] location: variable streamingHelper of type org.mule.runtime.extension.api.runtime.streaming.StreamingHelper `org.mule.sdk.api` パッケージは実験的機能であり、現在まだ開発中です。非実験的機能のドキュメントページで明示的に指示されない限り、このパッケージは使用しないでください。このパッケージは実験的であるため、MuleSoft ではこのパッケージで定義されたクラスに対するサポート、または後方互換性を保証いたしません。 `org.mule.sdk.api` パッケージのクラスやインターフェースがすべての Mule バージョンで認識されるとは限らない点にも注意が必要です。より正確には、`org.mule.sdk.api` のどのクラスも Mule バージョン 4.4 以前では認識されず、そのすべてのコンポーネントが Mule 4.4 以降でサポートされるとは限りません。 このエラーを修正するには、`org.mule.sdk.api` パッケージの使用を避け、代わりに `org.mule.runtime.extension.api` パッケージの同等のクラスまたはアノテーションを使用してください。 # SDK バージョンの選択 開発者は、特定の製品で使用可能な最新バージョンを使用する傾向にあります。これは Mule SDK の場合には適用しないでください。Mule モジュールを拡張するために使用する SDK のバージョンを選択するときは、次の操作を実行します。 - 必要な機能を特定する。 - 必要な機能が含まれる最下位のバージョンを選択する。 次のセクションでこの理由を説明します。 ## [](#extensions-api)Extensions API SDK を使用して開発している場合、実際には API (Extensions API) を使用しています。いずれかの SDK アノテーションで項目またはメソッドにアノテーションを付加するとき、またはインターフェースを実装するときは常に、この Extensions API の一部を使用していることになります。配布するモジュールにはコードのみが含まれます。モジュールと Mule Runtime の内部をブリッジするコードは含まれません。このギャップは、`Extensions API` によって Runtime でブリッジされます。 ## [](#最小-mule-バージョン)最小 Mule バージョン Mule Runtime の各バージョンは、`Extensions API` の 1 つの特定バージョンとその前のすべてのバージョンのサポートが含まれて配布されます。 たとえば、次の両方が該当するとします。 - Mule `4.1` には SDK バージョン `1.1` が付属する。 - Mule `4.2` には SDK バージョン `1.2` が付属する。 Mule `4.2` は、SDK バージョン `1.2`、`1.1`、および `1.0` で開発されたモジュールを完全にサポートします。Mule `4.3` で SDK 1.3 が導入された場合、`1.2` や `1.1` などもサポートされます。 この概念は次の両方に適用されます。 - どの Mule Runtime バージョンも以前にリリースされたすべての SDK バージョンをサポートしているため、Mule `4.1` で機能するモジュールはすべての Mule 4.x (`x >= 1`) で機能する。 - モジュールが SDK `1.2` を使用して作成された場合、その SDK バージョンをサポートするランタイムでのみ機能する。この例の場合、このモジュールは Mule `4.1` では機能しません。 ## [](#必要な機能の特定)必要な機能の特定 使用可能な最新の SDK バージョンの使用は、モジュールと互換性があるのは最新の Mule Runtime のみになるため、避けてください。代わりに、次のように、必要なすべての機能を含む最も古いバージョンを使用します。 - 接続と基本的な DataSense のみを必要とする単純なコネクタを作成している場合、バージョン `1.0` を使用する。 - `PollingSource` インターフェースも使用する必要がある場合、`PollingSource` のサポートが導入された SDK 1.1 を使用する。その機能をサポートするランタイムのみがモジュールを実行できます。 SDK の新機能については、ドキュメントにそれが導入されたバージョンが記載されています。特定のバージョンが指定されていない場合、その機能は最初のバージョンから存在しています。 お勧めする方法は、バージョン 1.0.0 を使用してすべてのプロジェクトを開始し、特定の機能が必要になったときにのみ、バージョンをアップグレードすることです。 これらのガイドラインに従うことで、モジュールはより多くの Mule Runtime バージョンとの互換性が保たれるため、より多くのユーザーがモジュールを使用できるようになります。新しいバージョンの機能が不要な場合、新しいバージョンを使用する理由はありません。 ## [](#sdk-にバグがある場合は)SDK にバグがある場合は? `Extensions API` は API であり、その実装は Mule Runtime 内にあるため、ほとんどの SDK 関連のバグ修正は新しい SDK バージョンではなく、Mule Runtime のパッチリリースおよびサービスパックでリリースされます。 問題が API 定義内にある一部のコーナーケースでは、SDK のパッチリリースが使用可能になります (`1.1.2` など)。常により高いバージョンのバグ修正を選択する必要があります。たとえば、`1.0.0` と `1.0.4` がある場合、`1.0.4` を選択します。 上記のバージョン番号は、既存のバージョンまたはパッチを表すとは限らない例として使用されていることに注意してください。 ## [](#バージョンの変更)バージョンの変更 SDK の `version` は、モジュールの `pom.xml` ファイルの `parent` 要素内で指定されます。 ```xml org.mule.extensions mule-modules-parent 1.0.0 ``` 別のバージョンに変更するには、単に親バージョンを変更します。 # TLS 設定 TLS 設定のサポートをモジュールに追加する方法は簡単です。次の例のように、種別 `TlsContextFactory` の [パラメーター](https://docs.mulesoft.com/jp/mule-sdk/1.1/parameters)を宣言するだけです。 ```java @Parameter @Optional private TlsContextFactory tlsContextFactory; ``` 上記の例では、次の XML 設定のサポートが自動的に生成されます。 ```xml ``` TLS コンテキストをアプリケーションのグローバル要素として定義することもできるため、使用する必要がある任意の場所でその名前を使用して TLS コンテキストを参照できます。 TLS の必要性をユーザーに表示しない場合 (内部的にサービスに安全に接続する必要がある場合など)、そのビルダーを使用して独自の `TlsContextFactory` を作成できます。 ```java private final TlsContextFactory tlsContextFactory = TlsContextFactory.builder() .trustStorePath("tls/trustStore") .trustStorePassword("mulepassword") .build() ``` このビルダーでは、`TlsContextFactory` のデフォルトインスタンスを作成することもできます。 ```java private final TlsContextFactory defaultTlsContextFactory = TlsContextFactory.builder().buildDefault(); ``` `TlsContextFactory` が使用可能になると (パラメーターとして使用可能か、そのビルダーを介して取得されたかに関係なく)、次の例のように初期化する必要があります。 ```java if (tlsContextFactory instanceof Initialisable) { ((Initialisable) tlsContextFactory).initialise(); } ``` 次に、これを使用して `SSLContext`、`SSLSocketFactory`、または `SSLServerSocketFactory` を取得できます。また、有効になった TLS プロトコルと暗号化スイートを取得することもでき、これを使用して、以下の例のように、TLS/SSL を使用するほとんどの Java コンポーネントをセットアップできます。 [FTPSClient](https://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPSClient.html) をセットアップするには、 [SSLContext](https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLContext.html) を取得し、次にそのプロトコルと暗号化スイートを設定します。 ```java SSLContext sslContext = tlsContextFactory.createSslContext(); String[] enabledProtocols = tlsContextFactory.getEnabledProtocols(); String[] enabledCiphers = tlsContextFactory.getEnabledCipherSuites(); FTPSClient client = new FTPSClient(sslContext); client.setEnabledProtocols(enabledProtocols); client.setEnabledCipherSuites(enabledCiphers); ``` [SSLSocketFactory](https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLSocketFactory.html) を取得して、独自の [ソケット](https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html)を作成することもできます。 ```java SSLSocketFactory sslSocketFactory = tlsContextFactory.createSocketFactory(); Socket socket = sslSocketFactory.create(); ``` [ServerSocket](https://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html) を作成するには、[SSLServerSocketFactory](https://docs.oracle.com/javase/8/docs/api/index.html?javax/net/ssl/SSLServerSocketFactory.html) を取得することもできます。 ```java SSLServerSocketFactory sslServerSocketFactory = tlsContextFactory.createServerSocketFactory(); ServerSocket socket = sslServerSocketFactory.createServerSocket(); ``` TLS コンテキストと、すべての使用可能なパラメーターを正しく設定するには、[「キーストアとトラストストアを使用した TLS の設定」](#4.1@mule-runtime::tls-configuration.adoc)を参照してください。 # Transactions SDK では、Mule フロー内でトランザクションへの結合と新規トランザクションの作成を行うコネクタを作成できます。これには、1 つの単位として機能する、ソースと操作の実行が含まれます。つまり、フロー内で問題が発生した場合、トランザクションに参加しているすべてのコンポーネントが 1 つの単位としてその実行をロールバックします。一部だけで部分的な完了とならないようにトランザクション内のすべての操作がロールバックされます。 ## [](#コネクタへのトランザクションの実装)コネクタへのトランザクションの実装 Mule のトランザクションサポートは、キーにより識別されるトランザクションリソースに基づいて機能します。SDK はこの同じ概念、すなわち接続の抽象化を再利用し、コンポーネントの接続をトランザクションのキーとして使用するという概念を踏襲します。 `ConnectionProvider` が `TransactionalConnection` インターフェースのインスタンスを生成するため、トランザクションを持つには拡張機能に `ConnectionProvider` が必要です。 ### [](#transactionalconnection-インターフェース)TransactionalConnection インターフェース コネクタでトランザクションを有効にするには、接続プロバイダー ([`ConnectionProvider`](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)) が必要です。この接続プロバイダーが、`TransactionalConnection` インターフェースを実装する接続を提供します。 接続では、トランザクションの開始と結果を伝達するために使用する `TransactionalConnection` メソッドを実装する必要があります。 ```java public class TXConnectionProvider implements ConnectionProvider { ... } ``` ```java public class TxConnection implements TransactionalConnection { @Override public void begin() throws TransactionException { //logic to begin a transaction } @Override public void commit() throws TransactionException { //logic to commit a transaction } @Override public void rollback() throws TransactionException { //logic to rollback a transaction } } ``` このインターフェースを実装するには、次のメソッドを実装する必要があります。 Method (メソッド) 説明 begin() トランザクションを開始する必要がある場合、このメソッドをコールします。 commit() トランザクションが正しく終了し、トランザクションをコミットする必要がある場合、これをコールします。 rollback() トランザクションがエラーで終了し、トランザクションをロールバックする必要がある場合、これをコールします。 ### [](#操作でのトランザクション)操作でのトランザクション 操作をトランザクションの下で動作させるには、`@Connection` パラメーターがトランザクション対応の接続、つまり `TransactionalConnection` を実装する接続である必要があります。 #### [](#トランザクションのアクション)トランザクションのアクション 操作がトランザクション型の場合、`transactionalAction` という名前の合成パラメーターが操作に自動的に追加されます。このパラメーターは、次の値を取る可能性がある Enum (列挙) 型です。 アクション名 説明 ALWAYS_JOIN コネクタは常に既存のトランザクションに結合します。トランザクションがないか、現在のトランザクションに現在の操作との互換性がない場合、操作の実行は失敗します。 JOIN_IF_POSSIBLE (デフォルト) トランザクションを使用できる場合、そのトランザクションを使用します。それ以外の場合、処理を続行します。 NOT_SUPPORTED 操作は、実行中のトランザクションの外側で実行されます。 ```xml ``` ##### [](#操作コード内の操作のトランザクションアクション)操作コード内の操作のトランザクションアクション 場合によって、Mule アプリケーション内で `transactionalAction` がどの操作レベルで設定されているかを把握することが必要になる場合があります。これを行うには、使用された値を挿入するように `OperationTransactionalAction` 型のパラメーターを設定することができます。 ```java public void work(@Connection TxConnection connection, OperationTransactionalAction action) { // } ``` #### [](#操作のトランザクションの使用方法)操作のトランザクションの使用方法 操作はトランザクションを開始できません。トランザクションは[メッセージソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)によって開始できます。また、操作は、新しいトランザクションを開始する `` スコープの内側に入っている必要があります。 トランザクション型操作を実行する前に、Mule は現在のトランザクションに、バインドされたキーがあるかどうかを確認します。 - バインドされたキーがすでにある場合 (以前の操作またはソースによりすでに登録されているため)、Mule は、現在の操作との互換性があるかどうかを確認します。互換性がある場合、操作は、バインドされた接続を使用します。 それ以外の場合、実行フローが失敗し、現在の操作が互換性のないトランザクションに入ろうとしたことが示されます。 - バインドされたキーがない場合、操作の接続がキーとしてバインドされ、`TransactionalConnection.begin()` が実行されて、現在の操作のトランザクションを開始する必要があることが通知されます。 トランザクションスコープ (つまり、`` スコープ、またはトランザクションが[メッセージソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)により初期化されている場合はフロー全体) の実行の最後で、トランザクションが正しく終了している場合、Mule は `TransactionalConnection.commit()` をコールします。エラーが発生している場合は、`TransactionalConnection.rollback()` を実行します。 接続がトランザクションに結合すると、プロバイダーの接続管理戦略が上書きされます。つまり、接続の戦略に関係なく、トランザクションのスコープ内のすべての一致する操作で同じ接続が使用されます。 この動作は CachedConnectionProvider の概念に完全に一致するわけではありません。同じ接続が、異なるトランザクションに同時に結合できるためです。そのため、同じ接続内で異なるトランザクションを同時に管理する方法をユーザーが認識しておく必要があります。 トランザクションと共に CachedConnectionProviders を使用することは極力お勧めしません。 ### [](#ソースでのトランザクション)ソースでのトランザクション 操作をトランザクションの下で動作させるには、`@Connection` パラメーターが、トランザクション互換性のある接続を提供できる `ConnectionProvider` である必要があります。 #### [](#トランザクションのアクション-2)トランザクションのアクション ##### [](#ソースのトランザクションアクション)ソースのトランザクションアクション メッセージソースがトランザクションの場合、`transactionalAction` という名前の合成パラメーターが自動的に追加されます。このパラメーターは、次の値を取る可能性がある Enum (列挙) 型です。 Table 1. ソースのトランザクションアクション アクション名 説明 ALWAYS BEGIN (常に開始) 呼び出しごとに新しいトランザクションが必ず作成されます。 NONE (なし) (デフォルト) ソースはトランザクションを開始せず、フロー内で開かれているトランザクションに参加しません。 ##### [](#操作コード内のソースのトランザクションアクション)操作コード内のソースのトランザクションアクション 場合によって、Mule アプリケーション内で `transactionalAction` がどのソースレベルで設定されているかを把握することが必要になる場合があります。この場合、使用された値を挿入するように `SourceTransactionalAction` 型のパラメーターを定義することができます。次に例を示します。 ソースへの SourceTransactionalAction の挿入 ```java public class TransactionalSource extends Source { @Connection private ConnectionProvider connection; @Parameter private SourceTransactionalAction action; // rest of the code } ``` このトピックの詳細は、[ソーストランザクション](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-transactions)についての説明を参照してください。 ### [](#xa-トランザクション)XA トランザクション XA トランザクションは同様の方法でサポートされます。唯一の違いは、プロバイダーが `TransactionalConnection` の代わりに `XATransactionalConnection` を返すことです。これは、`XAResource` を返すことができる接続です。 # XML SDK XML SDK は、より高度な Java ベースの Mule SDK に代わるものです。XML SDK を使用して、Mule アプリケーションを作成する方法と同様にカスタムモジュールを作成します。 実際にモジュール内で既存の Mule コンポーネントを使用できます。このフレームワークでは、モジュールの主要部分 (``、``、`` 要素など) を囲む XML 要素としていくつかの構文的なイディオムを追加するだけです。たとえば、次のスニペットでは `Hello XML SDK` 内で 1 つの操作を定義します。 ```xml ``` 他のコンポーネントの使用方法と同じ方法で、Mule SDK コンポーネントを Mule フローで使用します。この例では、操作 `` で定義されているとおりに、フロー `"random-flow"` の実行によりペイロードが `"Hello World!"` に設定されます。 ```xml ``` XML SDK は強く型付けされているため、すべての操作の定義済みパラメーターのデータ型は、入力および出力の両方で静的に設定されます。 ## [](#必須ソフトウェアのインストール)必須ソフトウェアのインストール ローカル環境に以下のツールをインストールして、正しく動作することを確認します。 - Java コードをコンパイルして構築するための Java Development Kit 8 (JDK 8)。 サポートされる XML SDK の最上位バージョンは JDK 11 ですが、JDK 11 はアプリケーションの実行にのみ使用できます。XML SDK でのコンパイルは JDK 8 で行う必要があります。 - プロジェクトの構築を管理するための Apache Maven 3.3.9 以降。 ## [](#xml-sdk-の基礎)XML SDK の基礎 XML SDK コンポーネントは、その動作と、Runtime がコンポーネントとやり取りする方法を示す主要な要素で構成されます。 - 操作 - プロパティ - 囲んでいるモジュール ### [](#操作)操作 `` 要素は一連の入力パラメーターと 1 つの出力を定義します。関数と同様に、入力パラメーターがあり、(本文に記述されている) アクションを実行し、1 つの出力があります。関数と異なり、操作に値が保存されている場合や、操作で外部ソースを参照する場合、操作の動作は変わる可能性があります。 - 入力パラメーター (``): 操作をコールするときに入力する型を宣言します。 このパラメーターは、`` スコープ内のメッセージプロセッサーがアクセスできる唯一のデータです。 - 本文 (``): 実行するコンポーネントのチェーンを定義します。フローに似ています。 - 出力 (``): XML SDK Module の出力データ型を宣言します。これは、`` で処理された後のペイロードの型です。 - エラー: `` 内で XML SDK が発生させる (またはマップする) ことができるエラー種別を宣言します。 次の XML SDK Module では、2 つの数値をパラメーターとして取得し、それらを合計する 1 つの操作を実行します。 ```xml ... ``` XML SDK Module を Mule アプリケーションで使用するには、XML SDK Module を Mule フローに追加するだけです。次に例を示します。 ```xml ``` Table 1. <parameter> の属性 名前 使用 デフォルト値 説明 name 必須 なし <parameter> の名前 defaultValue 省略可能 なし 別の値を提供しない場合、<operation> はデフォルト値を使用します。 use 必須 AUTO 可能な値: REQUIRED: パラメーターが存在する必要があります。パラメーターに defaultValue がある場合、これを REQUIRED にすることはできません。 OPTIONAL: パラメーターは必須ではありません。 AUTO: defaultValue がない場合、ランタイム時にデフォルトの REQUIRED になります。それ以外の場合、OPTIONAL としてマークされます。 type 必須 なし <parameter> のデータ型を定義します。string、boolean、datetime、date、number、time などのプリミティブ型を使用できます。また、カタログで定義された任意の型に依存することもできます。 password 省略可能 false UI 内では <parameter> を **** でマークします。 role 必須 behavior 現在の <parameter> に対して生成された XSD を変更する特定のパラメーターに対する定義済みのロールのセット。 behavior は属性を表示します。 CONTENT は、子要素として DataWeave のサポートがあることを意味します。 PRIMARY は CONTENT のように機能しますが、デフォルトではペイロードにマップします。 ロールについての詳細を参照してください。 summary 省略可能 なし 簡単なツールチップを <parameter> に追加します。 example 省略可能 なし このパラメーターのデータ型の短い例を追加します。 displayName 省略可能 なし UI 表示ラベルを提供します。displayName がない場合、デフォルト値は、name 属性のハイフン付きバージョンになります。 order 省略可能 なし 各要素を UI に表示する順序を定義します。 tab 省略可能 なし UI 内で <parameter> が属する必要があるグループ (またはタブ) を定義します。 visibility 省略可能 PUBLIC バージョン 1.2 以降で使用可能 次のように、操作の表示を PUBLIC (誰でも表示して使用可能) または PRIVATE (現在のモジュールのみにアクセス可能で、外部からは表示不可能) とマークします。 <operation name="example" visibility="PRIVATE"> <parameters> <parameter name="errorTopic" type="string" /> doc:description 省略可能 なし <parameter> のドキュメント。 Table 2. <output> の属性 名前 使用 デフォルト値 説明 type 省略可能 出力ペイロードのデータ型。要素を削除して、これを void に設定することができます。これにより、動作にペイロードの変更が伴う場合でも、<operation> が Mule イベントを変更することが回避されます。 `` 要素を使用する場合、属性型の定義は `` 要素によってサポートされます。 Table 3. <output-attributes> の属性 名前 使用 デフォルト値 説明 type 省略可能 出力属性のデータ型。要素を削除して、これを void に設定することができます。これにより、動作にペイロードの変更が伴う場合でも、<operation> が Mule イベントを変更することが回避されます。 両方の出力 (`` と ``) は、制御が呼び出し元に戻った時に作成される `MuleMessage` の一部になります。 Table 4. <error> の属性 名前 使用 デフォルト値 説明 type 必須 <body> 内でスロー (または再マップ) するエラーコードの型。Mule エラーの概念を参照してください。 ### [](#プロパティ)プロパティ `` は、XML SDK コンポーネントのエンドユーザーにより定義された項目を対象とします。これは、これを使用する Mule プロジェクト全体のグローバル設定として機能します。 プロパティは、操作により公開されるパラメーターに似ていますが、特定の操作ではなく、プロジェクト内の XML SDK コンポーネントのすべてのインスタンスに影響するレベルで機能します。操作のパラメーターと同様に、プロパティは、通常は、デフォルト値を持つ単純型です。 XML SDK Module のエンドユーザーが混乱しないように、エンドユーザーが編集する必要があると思われるプロパティのみを公開します。たとえば、エンドユーザーが変更できないまたは変更してはならない内部値は公開しないでください。 次の XML SDK Module は要求を [GitHub API V3](https://developer.github.com/v3/users/#get-the-authenticated-user) に送信し、認証済みユーザーを取得します。 ```xml ``` この例では、次のようにモジュール内で定義されている `` を参照します。 - グローバル要素内で `request-config` の値として。 - 操作内で `http-request` 内の `config-ref` 属性に対する値として。 次の Mule アプリケーションは XML SDK Module を使用します。`github` プレフィックス (`github:get-user` など) はモジュールの `name` から派生します。 ```xml ``` `"test-github-flow"` の実行のたびに、認証済みユーザーの GitHub 情報が返されます。 ```json { "login": "fernandezlautaro", "id": 4719511, "avatar_url": "https://avatars1.githubusercontent.com/u/4719511?v=3", "gravatar_id": "", "url": "https://api.github.com/users/fernandezlautaro", ... } ``` ログイン情報が正しくない場合、GitHub から次のエラー応答が返されます。 ```json { "message": "Requires authentication", "documentation_url": "https://developer.github.com/v3" } ``` Table 5. <property> 属性 名前 使用 デフォルト値 説明 name 必須 なし <property> の名前。 defaultValue 省略可能 なし 別の値を提供しない場合、<property> はデフォルト値を使用します。 use 必須 AUTO 可能な値: REQUIRED: プロパティが存在する必要があります。パラメーターに defaultValue がある場合、これを REQUIRED にすることはできません。 OPTIONAL: プロパティは必須ではありません。 AUTO: defaultValue がない場合、ランタイム時にデフォルトの REQUIRED になります。それ以外の場合、OPTIONAL としてマークされます。 type 必須 なし <property> のデータ型を定義します。string、boolean、datetime、date、number、time などのプリミティブ型を使用できます。また、カタログで定義された任意の型に依存することもできます。 password 省略可能 false 入力時に UI 内のプロパティの値が非表示になります (**** が使用されます)。 summary 省略可能 なし 簡単なツールチップを <property> に追加します。 example optional なし このプロパティのデータ型の短い例を追加します。 displayName 省略可能 なし UI 表示ラベルを提供します。displayName がない場合、デフォルト値は、name 属性のハイフン付きバージョンになります。 order 省略可能 なし 各要素を UI に表示する順序を定義します。 tab 省略可能 なし UI 内で <property> が属する必要があるグループ (またはタブ) を定義します。 doc:description 省略可能 なし <property> のドキュメント。 XML SDK を使用して行われた拡張では、暗黙的な設定はサポートされません。つまり、拡張で定義されたすべてのプロパティが省略可能であっても、すべての操作には設定が必要です。そのパラメーターの値を指定せずに設定を作成できるため、デフォルト値を使用できます。 ### [](#module-モジュール)Module (モジュール) `` 要素は XML SDK Module のルートです。これには、モジュールに属するすべてのプロパティと操作が含まれます。 Table 6. <module> 属性 名前 使用 デフォルト値 説明 name 必須 なし <module> の名前。 vendor 省略可能 "MuleSoft" XML SDK Module のベンダー。 prefix 省略可能 なし スキーマを生成するときに使用するモジュールのプレフィックス。空の場合、モジュールでは name 属性のハイフン付きバージョンが使用されます。プレフィックス属性を参照してください。 namespace 省略可能 なし スキーマの生成時にモジュールで使用する名前空間。それ以外の場合、デフォルトは http://www.mulesoft.org/schema/mule/<prefix> です (<prefix> は prefix 属性値)。 doc:description 省略可能 なし <module> のドキュメント。 XML SDK スキーマを Mule アプリケーションにインポートするには、`namespace` 属性を使用します。XML スキーマは動的に生成されます。`namespace`、`prefix`、および `name` 属性がどのように連携するかを次の表で示します。 Table 7. <module> で name、prefix、および namespace を提供する 提供された値 生成された値 name="hello with spaces" name="hello with spaces" prefix="hello-prefix" prefix="hello-prefix" namespace="http://www.mulesoft.org/schema/a/different/path/mule/hello" namespace="http://www.mulesoft.org/schema/a/different/path/mule/hello" 生成されたスキーマの場所: `http://www.mulesoft.org/schema/a/different/path/mule/hello/current/mule-hello-prefix.xsd` Table 8. <module> で name と prefix を提供する 提供された値 生成された値 name="hello with spaces" name="hello with spaces" prefix="hello-prefix" prefix="hello-prefix" なし namespace=http://www.mulesoft.org/schema/mule/hello-prefix 生成されたスキーマの場所: `http://www.mulesoft.org/schema/mule/hello-prefix/current/mule-hello-prefix.xsd` Table 9. <module> で name のみを提供する 提供された値 生成された値 name="hello with spaces" name="hello with spaces" なし prefix="hello-with-spaces" なし namespace=http://www.mulesoft.org/schema/mule/hello-with-spaces 生成されたスキーマの場所は `http://www.mulesoft.org/schema/mule/hello-with-spaces/current/mule-hello-with-spaces.xsd` です。 ### [](#prefix-attribute)プレフィックス属性 `prefix` 属性は、スキーマを生成するときに使用するモジュールのプレフィックスです。 空の場合、モジュールでは XML SDK `name` 属性のハイフン付きバージョンが使用されます。 `prefix` 属性の値は、リソースファイルを含むフォルダーの名前と相関関係があります。そのため、この値を設定するかどうかは、リソースフォルダーの名前に影響します。カスタム名でプレフィックスを設定する場合は、カスタムプレフィックス名と一致するようにリソースフォルダーの名前を変更する必要があります。 次のモジュールには `name` 属性 `name="hello with spaces"` のみがあります。つまり、その `prefix` は `hello-with-spaces` として動的に生成され、その `namespace` は `http://www.mulesoft.org/schema/mule/hello-with-spaces/current/mule-hello-with-spaces.xsd` として動的に生成されます。また、Mule アプリケーションには該当の値に一致する参照をポイントするスキーマの場所 (`schemaLocation`) が必要であることも意味します。 ```xml ``` 上記のこの `hello with spaces` モジュールを Mule アプリケーションで使用できます。次に例を示します。 ```xml ``` ## [](#xml-sdk-プロジェクトの作成およびテスト)XML SDK プロジェクトの作成およびテスト XML SDK Module を作成する手順は、次のとおりです。 1. MuleSoft リポジトリを自分の Maven (`mvn`) 設定ファイルに追加します。 ```text Mule true mulesoft-releases MuleSoft Repository http://repository.mulesoft.org/releases/ default ``` 2. Maven (`mvn`) を使用して、次のコマンドを実行します。 ```text mvn archetype:generate \ -DarchetypeGroupId=org.mule.extensions \ -DarchetypeArtifactId=mule-extensions-xml-archetype \ -DarchetypeVersion=1.2.0 \ -DgroupId=org.mule.extension \ -DartifactId=hello-mule-extension \ -DmuleConnectorName=Hello ``` 上記のコネクタ名は Hello のため、モジュールの名前空間は、prefix 属性で設定されているように module-hello に自動的に設定されます。 3. 値が正しいかどうかを示すように要求するメッセージが表示されたら、`enter` を押して続行します。 Maven アーキタイプでは、XML SDK Module の最小限のコードと、それを実行するための機能テストを含むスタブプロジェクトが作成されます。このプロジェクトの構造は次のようになります。 ```text ➜ hello-mule-extension tree . . ├── pom.xml └── src ├── main │ └── resources │ └── org │ └── mule │ └── yourdomain │ └── module-Hello.xml (1) └── test └── munit └── assertion-munit-test.xml (2) 8 directories, 3 files ``` (1) `hello-mule-extension/src/main/resources/org/mule/yourdomain/module-Hello.xml`: XML SDK ルート要素を定義します。 (2) `hello-mule-extension/src/test/munit/assertion-munit-test.xml`: XML SDK 操作をコールするアサーション操作。 4. `/hello-mule-extension` 内で `mvn clean install` を実行し、`Hello XML SDK` モジュール用のプラグインを作成します。 このコマンドでは、親プロジェクトに加えてその子プロジェクトもインストールされます。また、モジュールで定義された操作の MUnit を介してスイートも実行されます。 ```text ➜ hello-mule-extension mvn clean install ... .. . ================================================================================== Number of tests run: 2 - Failed: 0 - Errors: 0 - Skipped: 0 - Time elapsed: 2246ms ================================================================================== [INFO] ==================================================================================== [INFO] MUnit Run Summary - Product: MULE, Version: 4.1.1 [INFO] ==================================================================================== [INFO] >> assertion-munit-test.xml test result: Tests: 2, Errors: 0, Failures: 0, Skipped: 0 [INFO] [INFO] ==================================================================================== [INFO] > Tests: 2 [INFO] > Errors: 0 [INFO] > Failures: 0 [INFO] > Skipped: 0 [INFO] ==================================================================================== .... ... .. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 39.166 s [INFO] Finished at: 2017-06-14T22:07:42-03:00 [INFO] Final Memory: 61M/928M [INFO] ------------------------------------------------------------------------ ➜ hello-smart-connector ``` (3) このコネクタをテストのためにローカルの Maven リポジトリからプロジェクトに追加する場合、次の連動関係を追加します。 org.mule.extension hello-mule-extension 1.0.0-SNAPSHOT mule-plugin \+ これで、このコネクタを Studio パレットから使用できるようになりました。 + ## [](#set-custom-icon)コネクタへのカスタムアイコンの追加 コネクタアイコンは .svg 形式のファイルです。コネクタのアイコンをカスタマイズするには、カスタムアイコンが含まれる `icon.svg` ファイルをコネクタツリーのルートにある `icon` フォルダーの下に追加します。 次の画像はアイコンのフォルダー構造の例を示しています。  カスタムアイコンをコネクタに追加したら、アイコンは Anypoint Exchange と Anypoint Studio に表示されます。 ## [](#xml-sdk-module-からの-mule-プラグインのコンシューム)XML SDK Module からの Mule プラグインのコンシューム XML SDK Module 内から Mule プラグインをコンシュームする手順は、次のとおりです。 1. 連動関係を XML SDK Module の POM ファイルに追加します。 たとえば、XML SDK Module で HTTP Connector と OAuth Module を使用するには、POM に次の連動関係を含める必要があります。 ```xml org.mule.connectors mule-http-connector 1.2.1 mule-plugin compile org.mule.modules mule-oauth-module 1.1.2 mule-plugin compile ``` 2. スキーマの場所を `` ルート要素に追加します。次に例を示します。 ```xml ... ``` ## [](#操作の再利用)操作の再利用 場合によって、繰り返されるメッセージプロセッサーが操作に含まれることがあります。このメッセージプロセッサーが新しい操作でカプセル化され、他の場所からコールされている場合、このメッセージプロセッサーに依存できます。 操作に循環連動関係がない場合、`` で定義された各 `` を_同じ_ `` 内で再利用できます。 たとえば、挿入や更新を実行する前に `` で入力パラメーターを検証するとします。次の例では、検証が操作 `validate-and-insert` および `validate-and-update` 内で繰り返されています。 ```xml INSERT INTO PLANET(NAME) VALUES (:name) #[{ 'name' : vars.name }] update PLANET set NAME= :newName where NAME=':originalName' #[{'originalName' : vars.originalName, 'newName' : vars.newName}] ``` 前述の例のこのプロセスを簡素化するには、他の操作からコールする `validate` 操作を追加することができます。次に例を示します。 ```xml ``` `` 内から他の操作をコンシュームする手順は、次のとおりです。 1. XML 名前空間の `xmlns:tns` 属性と `schemaLocation` の新しい値を `` に追加します。 値は現在のモジュールの対象の名前空間をマップする必要があります。 2. 操作の名前の前に `tns` プレフィックスを付けて操作をコールします。完全なモジュールは次のようになります。 ```xml INSERT INTO PLANET(NAME) VALUES (:name) #[{ 'name' : vars.name }] update PLANET set NAME= :newName where NAME=':originalName' #[{'originalName' : vars.originalName, 'newName' : vars.newName}] ``` `config-ref` は_同じ_モジュールへの参照であるために含まれていません。つまり、すべてのグローバルインスタンスが操作間で共有されることを意味します。 ## [](#操作内の操作の再利用)操作内の操作の再利用 `use=CONTENT` [コンテンツパラメーター](https://docs.mulesoft.com/jp/mule-sdk/1.1/content-parameters)を使用して別の操作内の操作を再利用するには、内部タグ名の `use=CONTENT` パラメーターを参照します。 `use=CONTENT` を使用してその `requiredParameter` パラメーターを定義する `shared-operation` 操作があるとします。 別の操作 `sample-operation` は、次のように独自の定義内で `shared-operation` を再利用します。 ```xml #[vars.required-Parameter] ``` パラメーターである requiredParameter はキャメルケースの命名規則を使用していますが、参照である vars.required-Parameter はケバブケースの命名規則を使用しています。パラメーターや操作に名前を付けるときは、ケバブケースの命名規則を使用してプロジェクトの一貫性を維持します。XML SDK の制限事項を参照してください。 `requiredParameter` 値は、`sample-operation` の内部タグとして参照される必要があります。 それ以外の場合、プロジェクトは `Attribute 'required-parameter' is not allowed to appear in element 'tns:shared-operation'.` などのビルドエラーをスローします。 コネクタの XML 定義は、内部タグとして `use=CONTENT` を使用して設定されたパラメーターを生成します。`content` というパラメーターが内部タグ `` として `use=CONTENT` に設定されている [File Connector](https://docs.mulesoft.com/jp/mule-sdk/1.1/content-parameters#content-param) を参照してください。 ## [](#テスト接続の提供)テスト接続の提供 設計時には、グローバル要素の属性に間違った値 (間違ったユーザー名やパスワード、不適切な URL など) が提供された場合にフィードバックを提供すると便利です。このフィードバックを提供するには、接続テストをサポートするグローバル要素をモジュールに組み込む必要があります。 たとえば、`file:connection` 要素をモジュールに組み込むことで、XML SDK Module `` で File Connector からの接続テスト機能を使用できます。デフォルトでは、モジュールはファイル設定から接続テスト機能を取得し、サポートします。 ```xml ``` 接続テストは、UI から、`fileConfig` でカプセル化されたグローバル要素に委任されます。 テスト接続を提供する 2 つ以上のグローバル要素がモジュールに含まれる場合、使用するグローバル要素を `xmlns:connection="true"` 属性でマークしていないと、モジュールを作成したときにエラーが発生します。次に例を示します。 ```xml ``` xmlns:connection="true" を使用して複数のグローバル要素をマークすると、1 つしか許容されないため、コンパイルに失敗します。 ## [](#エラーの処理)エラーの処理 場合によって、`` 内の操作により、そのままの形で伝播すべきでないエラーコードがスローされることがあります。この場合、エンドユーザーにとってわかりやすいものにコードを再マップする必要があります。また、問題が `` 内の条件に関連する場合があります。 前者の場合、XML SDK は[エラーマッピング](#4.1@mule-runtime::mule-error-concept.adoc#about-error-mappings)を使用します。後者の場合、[Raise Error コンポーネント](#4.1@mule-runtime::raise-error-component-reference.adoc)が使用されます。 次の例は、2 つの数値を除算する操作でエラーマッピングを実行します。 ```xml ... ``` 除数 `numberB` がゼロの場合、`div` 操作は `MULE:EXPRESSION` ランタイムエラーになりますが、エラーの詳細が十分に説明されていません。 より詳細なエラーを作成するには、エラーマッピングを使用して、`div` 操作で `MATH-XML-SDK:DIVISION_BY_ZERO` エラーを生成することができます。次に例を示します。 ```xml ... ``` 式 `#[vars.numberA / vars.numberB]` の評価の前に検証を実行することで、同じエラーを生成できます。式が失敗した場合、`MATH-XML-SDK:DIVISION_BY_ZERO` エラーが発生します。次に例を示します。 ```xml ... ``` ## [](#xml_sdk_catalog)XML SDK カタログ `` と `` の標準データ型はプリミティブ型 (`string`、`boolean`、`number`、`date`、`datetime`、`localdatetime`、`time`、`localtime`、`timezone`、`binary`、`any`、`regex`) です。 プリミティブ型よりも複雑な構造の型を定義するには、モジュールに挿入するデータ型のカタログを作成します。この例では、次のコンテンツのカタログファイル (`hello-smart-connector/smart-connector/src/main/resources/module-Hello-catalog.xml`) を作成します。 ```xml ``` このカタログファイルは XSD および JSON スキーマファイルを参照します。 - `person-schema.xsd`。次のコンテンツが含まれます。 ```xml ``` - `person-schema.json`。次のコンテンツが含まれます。 ```json { "type": "object", "properties": { "age": { "type": "integer" }, "name": { "type": "string" }, "lastname": { "type": "string" } }, "additionalProperties": false } ``` `tree hello-smart-connector/smart-connector` フォルダーの構造は次のようになります。 ```text ➜ ~ tree hello-smart-connector/smart-connector hello-smart-connector/smart-connector ├── pom.xml └── src └── main └── resources ├── module-Hello-catalog.xml ├── module-Hello.xml ├── person-schema.json └── person-schema.xsd ``` スキーマの準備ができたら、関連付けられたカタログ (`PersonXsdType` および `PersonJsonType`) を参照することで、定義された型を使用します。次に例を示します。 ```xml ... ``` JSON スキーマの `type` 属性の値が、そのスキーマ (`PersonJsonType`) を含むカタログの名前になっています。ただし、XML スキーマの場合、`type` 属性の値では 2 つのコロン `::` と qname (修飾名) 参照が `Person` 要素に付加されます (`PersonXsdType::{http://uri}Person`)。 JSON から XML への DataWeave 変換 (`` 内で示されている) を実行するには、モジュールで必須スキーマ (`mule-ee.xsd`) を見つけることができるように次の連動関係を POM ファイルに追加する必要があります。 ```xml com.mulesoft.mule.runtime.modules mule-module-spring-config-ee ${mule.version} provided ``` 上記の[例](#example)の操作を Mule アプリケーションで使用するには、値を操作に提供する必要があります。次に例を示します。 ```xml ``` プリミティブ型ではない値をパラメーター化すると、定義済みの `` で値を `role="CONTENT"` として宣言できるため、`` 内で追加のプロセッサーを使用して操作をコールする必要がなくなります。この例の `person-xml-to-json` 操作でこの属性を `content` パラメーターに追加します。 ```xml ... ... ``` 上記の[例](#example2)の操作を Mule アプリケーションで使用するには、値を操作に提供する必要があります。次に例を示します。 ```xml .. ``` ## [](#xml-sdk-module-の稼働サンプル)XML SDK Module の稼働サンプル [https://github.com/mulesoft-labs/smart-connectors-integration-tests](https://github.com/mulesoft-labs/smart-connectors-integration-tests) には、次のディレクトリが含まれます。 - `apps-using-smart-connectors`: XML SDK Module を使用する Mule アプリケーション。 - `smart-connectors`: DataWeave、HTTP Connector、File Connector、Validation Module などを組み込む XML SDK Module。 このいくつかの例を以下のサブセクションで説明します。 ### [](#module-using-core)例: コアコンポーネントの使用 この例では、Set Payload (`mule:set-payload`) などのコアコンポーネントを組み込みます。 GitHub の場所: [smart-connectors/smart-connector-using-core](https://github.com/mulesoft-labs/smart-connectors-integration-tests/tree/master/smart-connectors/smart-connector-using-core) ```xml ``` ### [](#例-json-カスタム型の使用)例: JSON カスタム型の使用 この例では JSON 型を組み込みます。 GitHub の場所: [smart-connectors/smart-connector-using-custom-types-json](https://github.com/mulesoft-labs/smart-connectors-integration-tests/tree/master/smart-connectors/smart-connector-using-custom-types-json) ```xml ``` カタログ ```xml ``` スキーマ ```json { "type": "object", "properties": { "number": { "type": "number" }, "street_name": { "type": "string" }, "street_type": { "type": "string", "enum": [ "Street", "Avenue", "Boulevard" ] } }, "additionalProperties": false } ``` ### [](#例-カスタム-xml-型の使用)例: カスタム XML 型の使用 この例ではカスタム XML 型を組み込みます。 GitHub の場所: [smart-connectors/smart-connector-using-custom-types-xsd](https://github.com/mulesoft-labs/smart-connectors-integration-tests/tree/master/smart-connectors/smart-connector-using-custom-types-xsd) ```xml ``` カタログ ```xml ``` スキーマ 1 ```xml A user with all the information ``` ### [](#例-リソースのエクスポート)例: リソースのエクスポート この例では、リソースがコネクタと共にエクスポートされてパッケージ化されるように、リソースをプロジェクトに追加する方法を説明します。 GitHub の場所: [smart-connectors/smart-connector-exporting-resources](https://github.com/mulesoft-labs/smart-connectors-integration-tests/tree/master/smart-connectors/smart-connector-exporting-resources) 目的はリソースをエクスポートして主要な Mule アプリケーションで使用できるようにすることです。このため、モジュールファイル `module-exporting-resources.xml` に機能は含まれません。 module-exporting-resources.xml ```xml ``` 次のリソースファイルがエクスポートされます。 myMappings.dwl ```text %dw 2.0 /****************************************************************************************************************************** NOTICE: This file, `dwModule.dwl`, must be referenced in the META-INF/mule-artifact/mule-artifact.json file to properly export the resource so that the the functions being consumed (`five()`, `echo(String)`, `toUpper(Person)`, `toUpper(Array): Array = persons map toUpper($) ``` リソースファイルは、モジュールの名前 ([メインモジュールファイル](#module-exporting-resources)で定義) にちなんだ名前が付けられた新しいフォルダー内に配置する**必要**があります。 この例では、モジュールの名前は `module-exporting-resources` のため、フォルダーの名前は `module_exporting_resources` である必要があります。ハイフンはアンダースコアに置き換えられます。 この新しいフォルダーまたはそのサブフォルダーに含まれるすべてのファイルが XML SDK により自動的にエクスポートされます。 この例では、フォルダー構造は次のようになります。 ```text smart-connector-exporting-resources ├── pom.xml └── src └── main └── resources ├── module-exporting-resources.xml └── module_exporting_resources └── weirdFolder └── myMappings.dwl ``` 最終的に、エクスポートされたファイルを Mule フローで使用できます。この最初の例は、エクスポートされたファイルで定義されている dataweave 関数を使用する方法を示しています。 ```xml ``` この 2 番目の例は、たとえば、 [Parse Template](https://docs.mulesoft.com/mule-runtime/4.3/parse-template-reference) コンポーネントで使用される場所を介してファイルにアクセスする方法を示しています。 ```xml ``` ### [](#例-dataweave-の使用)例: DataWeave の使用 この例では、Transform (`ee:transform`) コンポーネントを使用して DataWeave を組み込みます。 GitHub の場所: [smart-connectors/smart-connector-using-dw](https://github.com/mulesoft-labs/smart-connectors-integration-tests/tree/master/smart-connectors/smart-connector-using-dw) ```xml ``` ### [](#例-file-connector-の使用)例: File Connector の使用 場所 `[smart-connectors/smart-connector-using-file](https://github.com/mulesoft-labs/smart-connectors-integration-tests/tree/master/smart-connectors/smart-connector-using-file)`: File Connector により異なる (`file:list` など) ```xml ``` ### [](#http-connector-の使用)HTTP Connector の使用 この例では、HTTP 要求 (`http:requester`) を使用して HTTP Connector を組み込みます。 GitHub の場所: [smart-connectors/smart-connector-using-http](https://github.com/mulesoft-labs/smart-connectors-integration-tests/tree/master/smart-connectors/smart-connector-using-http) ```xml ``` ### [](#例-別の-xml-sdk-の使用)例: 別の XML SDK の使用 この例は、XML SDK Module `module-using-core` (「[例: コアコンポーネントの使用](#module-using-core)」を参照) を使用する 1 つの XML SDK Module (`module-using-smart-connector`) を示しています。 GitHub の場所: [smart-connectors/smart-connector-using-smart-connector](https://github.com/mulesoft-labs/smart-connectors-integration-tests/tree/master/smart-connectors/smart-connector-using-smart-connector) ```xml ``` ### [](#validation-module-の使用)Validation Module の使用 この例では、Validation Module、具体的には `validation:is-email` を使用します。 GitHub の場所: [smart-connectors/smart-connector-using-validation](https://github.com/mulesoft-labs/smart-connectors-integration-tests/tree/master/smart-connectors/smart-connector-using-validation) ```xml ``` ## [](#xml-sdk-limitations)XML SDK の制限事項 現在、SDK には次の制限事項があります。 - XML SDK では、ソース (`` など) やルーターではなくアウトバウンド操作のみが提供されます。 - 操作では、再帰的コールはサポートされません。 - `name` や `config-ref` は予約済みのキーワードであるため、操作ではこれらの名前のパラメーターを使用できません。 - ケバブケースの命名規則を使用すると、名前値の変換時に単語間にハイフンが挿入されるため、XML SDK プロジェクトでパラメーターや操作に名前を付けるときにケバブケースの命名規則を使用すると、XML タグの生成中にエラーが生じることがありません。 # エラー処理 ## [](#エラー種別の定義)エラー種別の定義 モジュールでは、予想されるすべてのビジネス関連の条件や技術的な条件に対してエラー種別を定義して、ユーザーが明確に処理できるようにする**必要があります**。 次のような条件では、一致するエラー種別を定義す**べきです**。 - ID で参照されたエンティティが存在しない - 口座に残高がない - ユーザーが認証されていない - ユーザーが特定のアクションを実行するための権限を持っていない - リモートシステムの容量が一杯である 次のような条件では、一致するエラー種別を定義す**べきではありません**。 - ネットワークエラー - 予期しないサーバーエラー - 未知のエラー ## [](#エラー階層の使用)エラー階層の使用 Mule 4 のエラー種別では、階層の概念をサポートしています。つまり、エラーは単体で定義することも、同じモジュールで定義されている別の ErrorType や、汎用 Mule エラーとして定義されている ErrorType の子として定義することもできます。 Mule 4 のエラー処理を活用することで、汎用エラーハンドラーを再利用して、一般的な問題に一貫した方法で取り組むことができます。たとえば、複数のコネクタを同じフローで使用し、接続の問題が発生した時点で特定のアラートをトリガーするフローがあるとします。そのフローのすべてのコネクタが、すべての接続の問題の親エラーとして MuleErrors.CONNECTIVITY を使用していれば、アラートのトリガー処理は簡単に定義できます。 内部のモジュールでも、同じ種類の内部関係を持つエラー種別を定義しているモジュールであれば、同じことが言えます。 WebSockets Connector の例を示します。 ```java public enum WsError implements ErrorTypeDefinition { CONNECTIVITY(MuleErrors.CONNECTIVITY), CLIENT_SECURITY(MuleErrors.CLIENT_SECURITY), SERVER_SECURITY(MuleErrors.SERVER_SECURITY), BASIC_AUTHENTICATION(SERVER_SECURITY), UNAUTHORIZED(CLIENT_SECURITY), FORBIDDEN(CLIENT_SECURITY), NOT_FOUND, SERVICE_UNAVAILABLE, NO_SUCH_SOCKET, INVALID_SOCKET_ID, NON_UNIQUE_SOCKET_ID, REMOTELY_CLOSED, INTERNAL_SERVER_ERROR; private ErrorTypeDefinition extends Enum>> parent; WsError(ErrorTypeDefinition extends Enum>> parent) { this.parent = parent; } WsError() {} @Override public Optional>> getParent() { return Optional.ofNullable(parent); } } ``` この例からは以下が見て取れます。 - 親を使用してエラー種別を定義している - CONNECTIVITY エラーで Mule のエラーを拡張している - CLIENT\_SECURITY エラーと SERVER\_SECURITY エラーを定義している - BASIC\_AUTHENTICATION、FORBIDDEN、UNAUTHORIZED エラーで CLIENT\_SECURITY と SERVER\_SECURITY を拡張している - 他のドメイン特有のエラーが単体で存在している ## [](#モジュール例外の正しい使い方)モジュール例外の正しい使い方 ModuleException クラス (またはそのカスタムサブクラス) は、エラーが 定義されている ErrorType と一致した場合にのみスローされる**必要があります**。一致する ErrorType を持たない予期しないエラーや処理不能なエラーは、通常の例外としてスローされる**必要があります**。 ## [](#エラー種別を定義し過ぎない)エラー種別を定義し過ぎない よくあるアンチパターンとして、「ビジネスエラーごとに 1 つのエラー種別」という概念に基づいて「すべてのエラー詳細に個別のエラー種別」を定義してしまうことがあります。たとえば、INVALID\_EMAIL、INVALID\_ID、INVALID\_NAME、INVALID\_CARD のようにエラー種別を作り続けてしまい、エラー種別が爆発的に増えた結果、せっかくの機能が使えなくなってしまいます。 モジュールでは、同様のセマンティクスを持つエラー種別をまとめて、その代わりに例外メッセージを活用する**必要があります**。上の例では、INVALID\_DATA という 1 つの ErrorType のみを定義す**べき**であり、問題がどこにあったのか (クレジットカード、顧客名など) を例外メッセージの追加コンテキストで示します。 このルールは「エラーは処理可能でなければならない」という以前の概念と密接に関連しています。ID が不正であるというメッセージとメールアドレスが不正であるというメッセージを別々に受け取りたいユーザーはいないからです (Java で同じような経験を何度したことか考えてみましょう)。 ## [](#例外やエラー種別は公開しない)例外やエラー種別は公開しない モジュールで定義した Exception、ErrorTypeDefinition、ErrorTypeProvider クラスを API の一部としてエクスポートしては**なりません**。 ## [](#関連情報)関連情報 - [MuleSoft ヘルプセンター](https://help.mulesoft.com) - [Mule SDK 開発のベストプラクティス](https://docs.mulesoft.com/mule-sdk/latest/best-practices) # エラー定義 Mule では、エラーとは、何か問題が発生したことを伝達し、意味のある情報を提供することで、ユーザーがスローされたエラーの種類に応じて修正措置を取ることができるようにする方法です。 詳細は、[「エラー処理について」](#4.1@mule-runtime::error-handling.adoc)を参照してください。 ## [](#モジュールエラーの定義)モジュールエラーの定義 最初のステップは、モジュールによってスローされる可能性があるすべてのエラーを定義することです。これを行うには、`ErrorTypeDefinition` インターフェースを実装する `enum` を定義します。 この `enum` で定義された各値はエラーとみなされます。 ```java public enum SimpleError implements ErrorTypeDefinition { INVALID_PARAMETER, TIME_OUT, NOT_ALLOWED } ``` ### [](#エラー階層)エラー階層 モジュールエラーは、同じモジュールのエラー (同じ `enum` の値) または Mule エラーからのみ継承できます。Mule エラーは、 `org.mule.runtime.extension.api.error.MuleErrors` で定義されます。 親エラーを定義していないエラーは、自動的に `MULE:ANY` から継承されます。 ```java public enum HierarchalError implements ErrorTypeDefinition { INVALID_PARAMETER, TIME_OUT, NOT_ALLOWED, ILLEGAL_ACTION(NOT_ALLOWED), BAD_CREDENTIALS(MuleErrors.CONNECTIVITY); private ErrorTypeDefinition extends Enum>> parent; HierarchalError(ErrorTypeDefinition extends Enum>> parent) { this.parent = parent; } HierarchalError() { } @Override public Optional>> getParent() { return Optional.ofNullable(parent); } } ``` ### [](#モジュールのエラーの登録)モジュールのエラーの登録 `@Extension` アノテーションが付加されたクラスは、モジュールが処理するエラーを示すために `@ErrorTypes` のアノテーションが付加されている必要があります。このアノテーションは、定義されたエラーを含む `ErrorTypeDefinition` `enum` を参照します。 ```java @Extension(name = "Foo") @ErrorTypes(HierarchalError.class) @Xml(prefix = "test-connector") public class FooExtension { // Content } ``` ## [](#スローされる可能性があるエラーの指定)スローされる可能性があるエラーの指定 モジュールで発生する可能性があるすべてのエラーを宣言したら、それらをスロー する可能性がある操作にエラーをバインドする情報を提供する必要があります。 これを行うには、`ErrorTypeProvider` を実装する必要があります。これは、操作によってスロー される可能性があるエラーを伝達するクラスです。 ```java public class ExecuteErrorsProvider implements ErrorTypeProvider { @Override public Set getErrorTypes() { HashSet errors = new HashSet<>(); errors.add(HierarchalErrors.INVALID_PARAMETER); errors.add(HierarchalErrors.BAD_CREDENTIALS); errors.add(HierarchalErrors.ILLEGAL_ACTION); return errors; } } ``` `ErrorTypeProvider` を定義したら、それを適切な操作にバインドする 必要があります。次のように、操作レベルで `@Throws` アノテーションを使用してバインドします。 ```java @Throws(ExecuteErrorsProvider.class) public void execute(){ // operation body } ``` Studio または Flow Designer で、`@Throws` アノテーションが付加された操作は、その操作がスローする可能性があるエラーについてのヒントをユーザーに提供します。  XML は次のようになります。 ```xml ``` ## [](#エラーのスロー)エラーのスロー エラーは、特定のエラーにバインドされている Java 例外の Mule 表現です。 エラーと例外の間に静的なバインドはありません。エラーを伝達 するには、操作が `org.mule.runtime.extension.api.exception.ModuleException` または このクラスの子例外をスローし、コンストラクター内でスローする目的の `ErrorTypeDefinition` を示す必要があります。 ```java @Throws(ExecuteErrorsProvider.class) public void execute(){ try { throw new IllegalStateException(); } catch (IllegalStateException e){ throw new ModuleException(HierarchalErrors.ILLEGAL_ACTION, e); } } ``` また、このロジックを新しい例外クラス内にラップすることをお勧めします。 ```java public final class IllegalActionException extends ModuleException { public IllegalActionException(Exception cause) { super(HierarchalErrors.ILLEGAL_ACTION, cause); } } ``` 操作の ErrorTypeProvider で宣言されていないエラーをスローすると、 予期せぬエラーの例外が発生します。操作で宣言されていないエラーをスローすることはできません。 # オブジェクトストリーミング (ページネーション) オブジェクトストリーミングは、未加工のバイトストリームではなく Java オブジェクトをストリーミングするという点を除いては[バイナリストリーミング](https://docs.mulesoft.com/jp/mule-sdk/1.1/binary-streaming)と同じです。 Devkit (Mule 3) に精通しているなら、自動ページネーション機能の進化形と考えればわかりやすいでしょう。Devkit との違いは、Mule SDK では反復可能アクセス、ランダムアクセス、同時アクセスをサポートしているという点です。 データベースコネクタの Select 操作を大幅に簡素化したオブジェクトストリーミングの使用例を示します。 ```java public PagingProvider> list(@Text String sql) { (1) return new PagingProvider>() { private ResultSet resultSet; @Override public List> getPage(DbConnection connection) { (2) if (resultSet == null) { resultSet = executeQuery(connection, sql); (3) } return extractPageFrom(resultSet); } @Override public java.util.Optional getTotalResults(DbConnection connection) { return java.util.Optional.empty(); (4) } @Override public void close(DbConnection connection) throws MuleException { resultSet.close(); (5) } } } ``` 1 このメソッドの署名について 2 点注意すべきことがあります。 メソッドは PagingDelegate オブジェクトを返します。PagingDelegate は 2 つの汎用型を必要とします。1 つ目はデリゲート関数が次ページ以降を取得するために使用する接続の種別で、2 つ目はページ内の要素の種別です。 List 操作はパラメーターを受け取ります。ただし、接続オブジェクトは受け取りません。ページングされた操作は接続を受け取ることができないためです。代わりに、Runtime によって PagingProvider に渡される接続を常に使用する必要があります。 そのため、この署名は DbConnection オブジェクトを使用したページのクエリ結果を返し、ストリームの各項目は結果の各行を表す Map<String, Object> となります。 2 getPage() は次のページをフェッチして返します。このメソッドは、ページをフェッチするために使用する接続を受け取ります。ストリームが終わったら、このメソッドは次を行う必要があります。 3 操作のロジックによって、最初のページを取得するロジックか、次のページを取得するロジックが必要な場合があります。 4 オブジェクトストリーミングの別の機能として、ストリーム内の実際のオブジェクト数を通知することができます。これには getTotalResults() メソッドを実装する必要があります。ただし、すべての API がこのメソッドをサポートしているわけではありません。たとえば、SalesforceAPI はこのメソッドをサポートしていますが JDBC (データベースコネクタを駆動する API) はサポートしていません。そのため、このメソッドは Java Optional クラス (この場合は空のクラス) を返します。ページネーション操作のユーザーは、#[payload.size] のような式によってこの値を取得できます。 5 最後に、ストリーム内のオブジェクトが無くなったら close() メソッドが呼び出されます。このメソッドは接続を終了するものではありません。接続の終了は SDK が自動的に行います。このメソッドは、このページングデリゲート関数が持っている可能性のあるリソースを解放するものです。たとえば、このケースでは、ページングデリゲート関数は、各ページ値を抽出する元となる ResultSet を持っています。この ResultSet を解放する必要があります。 ## [](#スティッキー接続)スティッキー接続 デフォルトでは、`getPage()` が受け取る接続が呼び出しごとに同じであるという保証はありません。それで別に問題はありません。ほとんどの API (特に Rest API) では、_問題ではない_だけではなく、機能の 1 つでもあります。ただし、他のケース (データベースなど) では、**同じ**接続を使用して、すべてのページを取得する**必要があります**。これは Devkit では不可能でした。 Mule SDK ではスティッキー接続が追加されており、`getPage()` メソッドが常に同じトランザクションで呼び出されるように Runtime で保証しなければならないことを指示します。次に例を示します。 ```java public PagingProvider> list(String sql) { return new PagingProvider>() { private ResultSet resultSet; @Override public List> getPage(DbConnection connection) { ... } @Override public java.util.Optional getTotalResults(DbConnection connection) { ... } @Override public void close(DbConnection connection) throws MuleException { ... } @Override public boolean useStickyConnections() { return true; } } } ``` ## [](#ストリーミングの設定)ストリーミングの設定 バイナリストリーミングと同様に、自動ページング操作は ``、``、および `` を介してストリーミング設定を自動的に取得します。これらの要素の詳細については、[バイナリストリーミング](https://docs.mulesoft.com/jp/mule-sdk/1.1/binary-streaming)についての説明を参照してください。上記の Select 操作の例でカスタムファイルストアストリーミングを設定すると次のようになります。 ```xml ``` # カスタム静的メタデータ **バージョン 1.1 以降で使用可能** 静的メタデータを使用して、コンパイル時に既知であり、コネクタの jar 内の型から使用できるメタデータを参照します。単純な Java 型は、モデルの中で開発者が定義したカスタム POJO であり、この静的メタデータの一部でもあります。静的として該当する部分は、他のパラメーターに依存することなく、構造が十分に知られていること、または構造を調査できることです。 静的メタデータが動的よりも優れている点は、静的メタデータは変化しないためにその構造を再計算する必要がないことです。つまり、アプリケーションを開発するときにすでに解決していることです。 単純な Java 型または POJO を戻り値またはパラメーターの型として使用する場合、SDK は要素に適した静的型を作成しますが、型が Java オブジェクト (Json スキーマ、XSD など) として定義されていない場合、ユーザーは使用する型の構造を正確に把握し、SDK が提供するカスタム静的メタデータ機能を使用する必要があります。 ## [](#xml-型および-json-型)XML 型および JSON 型 特定の構造 (スキーマ) に従う JSON 型または XML 型のパラメーターが操作で要求される場合があります。 適切な XSD または JSON スキーマを使用して、これを DataSense に伝えることができます。 これは InputStream および String の Java 型パラメーターでのみ機能します。 ### [](#json-型)JSON 型 JSON 型の構造を決定するには、JSON スキーマを提供する必要があります。 - `@OutputJsonType` ```java @OutputJsonType(schema = "person-schema.json") public Result retrievePerson() { // ... } ``` - `@AttributesJsonType` ```java @AttributesJsonType(schema = "resolution-attributes-schema.json") public Result getSolution() { // ... } ``` - @`InputJsonType` ```java public void addPerson(@InputJsonType(schema = "person-schema.json") InputStream person) { // ... } ``` ### [](#xml-型)XML 型 XML の構造を決定するには、XSD ファイルと、読み込む要素を参照するために使用する修飾名を提供する必要があります。 - `@OutputXmlType` ```java @OutputXmlType(schema = "order.xsd", qname = "shiporder") public Result retrieveOrder() { // ... } ``` - `@AttributesXmlType` ```java @AttributesXmlType(schema = "order-attributes.xsd", qname = "attributes") public Result getOrderStatistics() { // ... } ``` - `@InputXmlType` ```java public void createOrder(@InputXmlType(schema = "order.xsd", qname = "shiporder") InputStream order) { // ... } ``` ## [](#静的型リゾルバー)静的型リゾルバー 入力パラメーター、出力ペイロード、または出力属性のカスタム静的メタデータを解決する方法はよく似ています。次の例を参照してください。 各例のリゾルバーは、`StaticResolver` を実装する抽象クラスを拡張します。 `getStaticMetadata` は、メタデータを解決するために実装する必要があるメソッドです。 ### [](#inputstatictyperesolver)InputStaticTypeResolver 操作の入力パラメーターでカスタム静的メタデータの解決方法を使用するには、パラメーターに `@TypeResolver` アノテーションを付加し、アノテーションの値を `InputStaticTypeResolver` にする必要があります。 これは `InputStaticTypeResolver` の例であり、メソッド `getStaticMetadata` を実装する必要があります。 ```java public class JsonPersonInputStaticTypeResolver extends InputStaticTypeResolver { @Override public MetadataType getStaticMetadata() { ObjectTypeBuilder object = BaseTypeBuilder.create(MetadataFormat.JSON).objectType(); object.id("json-object"); object.addField().key("name").value().stringType(); object.addField().key("last-name").value().stringType(); return object.build(); } } ``` ### [](#outputstatictyperesolver)OutputStaticTypeResolver 操作の出力ペイロードでカスタム静的メタデータの解決方法を使用するには、メソッドに `@OutputResolver` アノテーションを付加し、アノテーションの出力値を `OutputStaticTypeResolver` にする必要があります。 これは `OutputStaticTypeResolver` の例であり、メソッド `getStaticMetadata` を実装する必要があります。 ```java public class CsvOutputStaticTypeResolver extends OutputStaticTypeResolver { @Override public MetadataType getStaticMetadata() { return BaseTypeBuilder.create(MetadataFormat.CSV).objectType().id("csv-object").build(); } } ``` ### [](#attributesstatictyperesolver)AttributesStaticTypeResolver 操作の出力属性でカスタム静的メタデータの解決方法を使用するには、メソッドに `@OutputResolver` アノテーションを付加し、アノテーションの属性値を `OutputStaticTypeResolver` にする必要があります。 これは `AttributesStaticTypeResolver` の例であり、メソッド `getStaticMetadata` を実装する必要があります。 ```java public class CsvAttributesStaticTypeResolver extends AttributesStaticTypeResolver { @Override public MetadataType getStaticMetadata() { ObjectTypeBuilder object = BaseTypeBuilder.create(MetadataFormat.CSV).objectType(); object.addField().key("location").value().stringType(); object.addField().key("size").value().numberType(); return object.build(); } } ``` # クライアントログイン情報 バージョン 1.3 以降で使用できます。 認証コード許可タイプは、ユーザーの代理で動作するアプリケーションの認証に主眼を置いていますが、クライアントログイン情報許可タイプは、自身のために動作するアプリケーションの認証に主眼を置いています。この許可は、人間の介入を必要としないため、マシン間の通信に適しています。 ## [](#クライアントログイン情報対応コネクタの開発)クライアントログイン情報対応コネクタの開発 クライアントログイン情報のサポートは、`@ClientCredentials` アノテーションを使用して `ConnectionProvider` レベルで追加できます。 Salesforce 用 Anypoint Connector (Salesforce Connector) 用の `ConnectionProvider` を極端に簡素化した例を示します。 ```java @ClientCredentials(tokenUrl = "https://login.salesforce.com/services/oauth2/authorize") public class SalesforceOAuthConnectionProvider implements ConnectionProvider { @Parameter @Optional(defaultValue = "34.0") private Double apiVersion; /** * Tailors the login page to the user's device type. */ @OAuthParameter private String display; /** * Avoid interacting with the user */ @OAuthParameter @Optional(defaultValue = "false") private boolean immediate; /** * Specifies how the authorization server prompts the user for reauthentication and reapproval */ @OAuthParameter @Optional(defaultValue = "true") private boolean prompt; @OAuthCallbackValue(expression = "#[payload.instance_url]") private String instanceId; @OAuthCallbackValue(expression = "#[payload.id]") private String userId; private AuthorizationCodeState state; @Override public SalesforceClient connect() throws ConnectionException { if (state.getAccessToken() == null) { throw new SalesforceException(MessageFormat.format(COULD_NOT_EXTRACT_FIELD, "accessToken")); } if (instanceId == null) { throw new SalesforceException(MessageFormat.format(COULD_NOT_EXTRACT_FIELD, "instanceId")); } return new SalesforceClient(state.getAccessToken(), instanceId, apiVersion); } public void disconnect(SalesforceClient connection) { connection.close(); } @Override public ConnectionValidationResult validate(SalesforceClient connection) { return success(); } } ``` SDK の他の接続と同様に、クラスは `ConnectionProvider` を実装しています。オブジェクトによって認証された操作は、プロバイダーが返す `SalesforceClient` オブジェクトを処理します。このデザインアプローチの重要な点は、コネクタは基本認証を使用する `ConnectionProvider` を別に定義することもできるため、使用する認証方法と操作が切り離され、すべての操作の互換性が保証されるということです。 ### [](#clientcredentials)@ClientCredentials このアノテーションは、この接続プロバイダーがクライアントログイン情報許可種別を使用した OAuth ダンスを必要とすることを示します。このアノテーションには以下の属性があります。 ```java public @interface ClientCredentials { /** * @return The Url of the endpoint which provides the access tokens */ String tokenUrl(); /** * @return Expression to be used on the response of {@link #tokenUrl()} to extract the access token */ String accessTokenExpr() default "#[payload.access_token]"; /** * @return Expression to be used on the response of {@link #tokenUrl()} to extract the access token expiration */ String expirationExpr() default "#[payload.expires_in]"; /** * @return The default set of scopes to be requested, as a comma separated list. Empty string means no default scopes. */ String defaultScopes() default ""; /** * Allows to customize the placement that the client credentials will have in the request. * * @return the selected {@link CredentialsPlacement}. Defaults to {@link CredentialsPlacement#BASIC_AUTH_HEADER} */ CredentialsPlacement credentialsPlacement() default BASIC_AUTH_HEADER; } ``` ### [](#接続管理戦略)接続管理戦略 `@ClientCredentials` の例のプロバイダーは、ConnectionProvider インターフェースの特殊化を実装していないため、OAuth メカニズムを他の接続管理戦略と組み合わせることができます。使用するインターフェース (PoolingConnectionProvider、CachedConnectionProvider、ConnectionProvider など) によって、接続オブジェクトをプールまたはキャッシュしたり、毎回新しく作り直したりすることができます。接続管理の詳細については、接続性のリファレンスについての説明を参照してください。 このシナリオで特殊化されていない (たとえば、PollingConnectionProvider や CachedConnectionProvider ではない) ConnectionProvider インターフェースを使用する際のセマンティクスに注意してください。通常の「非 OAuth」接続プロバイダーでは、特殊化されていないインターフェースを使用することは、コンポーネントが接続を必要とするたびに新しい接続が作成され、コンポーネントの終了時に破棄されることを意味します。これは OAuth のケースにも当てはまりますが、OAuth ダンスが再び実行されるという意味ではありません。OAuth でも新しい接続オブジェクトが作成されますが、同じアクセストークンが有効である間は再利用されます。 ### [](#通常のパラメーターと-oauth-パラメーターの違い)通常のパラメーターと OAuth パラメーターの違い この ConnectionProvider は、他のすべての接続プロバイダーと同様にパラメーターを持ちます。ただし、通常のパラメーターと `@OAuthParameter` では概念が異なりますので注意してください。 OAuthParameter は、OAuth ダンスの実行中にカスタムパラメーターとして使用されます。たとえば、接続プロバイダーが `apiVersion` パラメーターを使用して SalesforceClient を作成する場合、即時パラメーターは、実際にはサービスプロバイダーへの OAuth 要求で送信されます。 モジュールの視点から見ると、OAuth パラメーターもユーザーが値を提供するパラメーターの 1 つに過ぎません。これらのパラメーターには、`@Optional`、`@Expression`、および従来の `@Parameter` アノテーションで使用できる他のすべてのアノテーションを組み合わせることができます。DSL では、通常のパラメーターと OAuth パラメーターは一緒に表示されます。モジュールのエンドユーザーには違いが一切分かりません。 ## [](#requestalias-パラメーター)requestAlias パラメーター 一部のカスタム OAuth パラメーターには、Java ではサポートされない文字が含まれています (例: `Api-Key`)。`-` は項目名には使用できないため、@OAuthParameter アノテーションには `requestAlias` という省略可能なパラメーターがあります。 ```java @OAuthParameter(requestAlias = "api-key") private String apiKey; ``` ### [](#oauthcallbackvalue-アノテーション)@OAuthCallbackValue アノテーション サービスプロバイダーが OAuth コールバックで返す応答からは、コールバック値が抽出されます。ほとんどのサービスプロバイダーは標準項目 (アクセストークンや更新トークン、期限切れ情報など) のみを返しますが、一部のサービスプロバイダーは追加項目 (Salesforce の場合はユーザー ID やインスタンス ID など) も返します。 このアノテーションには、応答に適用して値を抽出するための式が含まれています。抽出された値は、接続プロバイダーが使用する項目に割り当てられます。connect()、validate()、または disconnect() メソッドを呼び出すと、項目が設定されて使用可能になります。 ### [](#clientcredentialsstate)@ClientCredentialsState `@ClientCredentials` アノテーションが付加されたすべての ConnectionProvider は、ClientCredentialsState 型の項目を 1 つ (だけ) 持っている_必要があります_。 この項目は、OAuth ダンスの結果に関する情報を含む、シンプルな不変の POJO です。この POJO には以下の情報が含まれます。 ```java public interface ClientCredentialsState { /** * @return The obtained access token */ String getAccessToken(); /** * @return The access token's expiration. The actual format of it depends on the OAuth provider */ Optional getExpiresIn(); } ``` プロバイダーは、このオブジェクトを介して accessToken や OAuth ダンス中に取得した他の標準情報にアクセスします。元の Salesforce の例を見直せば、connect() メソッドがこの POJO を利用してクライアントを作成していることがわかります。 ## [](#クライアントログイン情報コネクタの設定)クライアントログイン情報コネクタの設定 ユーザーが OAuth 対応コネクタやモジュールをどのように使用できるかも重要です。SDK は OAuth プロトコルの複雑さを可能な限り隠しますが、OAuth ダンスなどは隠せません。この問題に対して SDK は、すべての OAuth Module の使用方法を標準化して、ユーザーエクスペリエンスを簡素化することに努めています。 このセクションでは、ユーザーがモジュールを使用するための手順について説明します。 ### [](#合成パラメーター)合成パラメーター ConnectionProvider で明示的に定義されているすべての設定に加えて、SDK はいくつかのパラメーターを追加して、適切な動作を挿入します。 パラメーター名 必須 式 デフォルト値 説明 clientId はい SUPPORTED なし サービスプロバイダーに登録されている OAuth clientId 値。 clientSecret はい NOT_SUPPORTED なし サービスプロバイダーに登録されている OAuth clientSecret 値。 tokenUrl いいえ SUPPORTED @ClientCredentials アノテーションで提供されている値。 サービスプロバイダーのトークンエンドポイント URL。 scopes いいえ SUPPORTED @ClientCredentials アノテーションで提供されている値。 OAuth ダンス時に要求する OAuth スコープ。指定されていない場合、デフォルトとしてアノテーション内のスコープが使用されます。 objectStore いいえ NOT_SUPPORTED なし 各リソースオーナー ID のデータを保存する ObjectStore への参照。指定しない場合、Runtime は自動的にデフォルトのオブジェクトストアをプロビジョニングします。 ### [](#式の使用について)式の使用について 合成パラメーターの表には、式を受け入れる多くの合成パラメーターが示されています。式を使用することで、通常のパラメーターで式を使用するのと同じ効果が得られ、動的なパラメーター設定を可能にします。 ### [](#oauth-接続-dsl)OAuth 接続 DSL 生成される DSL の例を示します。 ```java ``` 他のすべてのプロバイダーの場合と同様に、通常パラメーターと OAuth パラメーターはすべて接続プロバイダーレベルで示されています。 クライアントログイン情報許可種別に関連したパラメーターは、 という子要素に配置されます。 ObjectStore に関連したパラメーターは、 という子要素に配置されます。 ### [](#カスタム-objectstore-の設定)カスタム ObjectStore の設定 取得したアクセストークンはオブジェクトストアに保存されます。デフォルトでは、SDK はトークンをアプリケーションのデフォルトストアに保存しますが、ユーザーは次の例に示すようにカスタムオブジェクトストアを定義することもできます。 ```java ``` ## [](#期限切れになったクライアントログイン情報アクセストークンの更新)期限切れになったクライアントログイン情報アクセストークンの更新 ほとんどのアクセストークンには有効期限が設定されており、通常は発行から 30 ~ 60 分です。そのため、ほとんどのプロバイダーでは更新トークンも提供しており、OAuth ダンスを再び実行しなくても済むようにしていますが、これはプロバイダーによって厳格に適用される標準ではありません。 SDK が期限切れのトークンを自動的に検出して新しいトークンを取得できるようにするような標準は適用されていません。通信方法は API ごとに異なるため、次のような `AccessTokenExpiredException` 例外が存在します。 ```java public void someOperation(@Connection SalesforceRestClient client) { Response response = client.performSomeOperation(); if (response.getStatusCode() == 401) { throw new AccessTokenExpiredException(); } } ``` この例では、架空の REST クライアントを使用して操作を実行しています。 - この REST クライアントは、`@ClientCredentials` アノテーションが付加された ConnectionProvider で作成されたものと想定されています。 - このクライアントは操作を実行して、HTTP コールの情報が格納されたレスポンスオブジェクトを受け取ります。 - この例では、状況コードの 401 (`UNAUTHORIZED`) はトークンの期限切れであると想定しています。 - また、AccessTokenExpiredException をスローしています。 SDK がこの例外を検出すると、自動的に更新ダンスを実行して、新しいアクセストークンで操作を再試行します。 前述したように、アクセストークンの期限切れの通知方法は API ごとに異なります。例外をスローする API もありますし、カスタムメッセージを出力する API もあります。リモート API を調べて、最適な対応を決定してください。 ### [](#アクセストークンの無効化)アクセストークンの無効化 マルチテナントでは、特定の resourceOwnerId を持つアクセストークンを無効化して、関連付けられているトークン情報を削除することができます。 アクセストークンを無効化できるように、SDK はすべての OAuth 対応コネクタまたはモジュールに `unauthorize` という操作を自動的に追加します。次の例では、取得したトークンをこのように無効化できます。 ```java ``` この操作では、サービスプロバイダー側のトークンは無効化されません。Mule のキャッシュとオブジェクトストアからサービスプロバイダーが削除されます。 # クラスローディング分離について Mule 4 のクラスローディングスキーマは、ランタイム、アプリケーション、モジュールを互いに分離します。それぞれは (クラスではなく) パッケージを指定し、API の一部としてエクスポートして、これらのパッケージを可視化します。 Mule 3 のクラスローディングの問題: - モジュールが互いに分離されなかった。 - モジュールが Mule Runtime から分離されなかった。 - モジュールが Mule アプリケーションから分離されなかった。 Mule 3 では、一部のライブラリを使用するモジュールが、同じライブラリの別のバージョンを使用する他のモジュール、アプリケーション、またはランタイムと競合することがありました。この競合によってクラスローディングの問題が発生し、`ClassNotFoundException` や `NoSuchMethodException` など、トラブルシューティングの困難な混乱を招くエラーメッセージが表示されることがありました。 ## [](#モジュールのクラスローディング分離)モジュールのクラスローディング分離 クラスローディングは、クラスではなくパッケージによって自動的に絞り込まれるため、どのパッケージをエクスポートして Mule アプリケーションに対して可視化するかを、モジュールが指定する必要があります。 エクスポートするパッケージを判断するために、SDK は各設定、接続、コンポーネントの戻り値と入力種別を調べてそれらのパッケージを取得します。そのため、_エクスポートしない_クラスがエクスポートされるパッケージから除外されていることを確認する必要があります。エクスポートされるクラスは、エクスポートしないクラスとパッケージを共有していない必要があります。 次のパッケージ階層をお勧めします (MuleSoft モジュールで内部的に使用)。 org.mule.module \\--> .api.\* \\--> .internal.\* - `.api.*` には、Mule アプリケーションによってエクスポートされ表示されるすべてのクラス (戻り値のデータ型、サブタイプ、入力種別、接続インターフェース) が含まれる。 - `.internal.*` には、モジュールの特定の動作に使用されるすべてのクラス (アノテーション付きのクラス、`Connection` および `Operation` 実装と内部クラス) が含まれる。 ### [](#エクスポートされたパッケージと戻り値のデータ型の把握)エクスポートされたパッケージと戻り値のデータ型の把握 MuleSoft では、エクスポートされた**すべての**クラスがモジュールに属することを推奨しています。 ライブラリの衝突により、モジュールと他のモジュール、アプリケーション連動関係、さらにはランタイムとの互換性がなくなるという問題を回避するため、以下が_強く推奨_されます。 - モジュールが使用しているライブラリに属するクラスからは_絶対に_オブジェクトを戻したり受け取ったりしないこと。 次のセクションのシナリオを検討してください。 #### [](#1-つ目のシナリオ-同じパッケージをエクスポートする)1 つ目のシナリオ: 同じパッケージをエクスポートする このシナリオでは、操作が非常に異なる 2 つのモジュールを使用します。どちらも同じライブラリ (GSON) を使用して JSON を解析し、`JsonObject` クラスのインスタンスを_返します_。片方は GSON バージョン `1.1`、他方は GSON バージョン `2.3` を使用します。`JsonObject` クラスは、両方のバージョンとして同じパッケージに含まれていますが、各バージョンの実装が異なるため、クラス間の互換性がなくなります。 この例では、`JsonObject` クラスを操作の戻り値のデータ型として公開しています。 最初のモジュール操作 ```java public JsonObject getEmployee(@Connection EmployeesServiceConnection connection, String id) { return new JsonObject(connection.getById(id)); } ``` 2 番目のモジュール操作 ```java public JsonObject getAllProducts(@Connection ProductsServiceConnection connection) { return new JsonObject(connection.getProdsJson()); } ``` Mule アプリケーションをデプロイしてから、同じパッケージをエクスポートする 2 つのモジュールを使用しようとすると、2 つのモジュールが同じパッケージをエクスポートできないため、Mule はエラーとなります。 #### [](#2-つ目のシナリオ-同じクラスの異なるバージョンの-2-つのインスタンスを戻す)2 つ目のシナリオ: 同じクラスの異なるバージョンの 2 つのインスタンスを戻す 前述の例を少し変えて、操作が _GSON_ パッケージをエクスポートしないものとします。その代わりに `java.lang.Object` を戻します。 最初のモジュール操作 ```java public Object getEmployee() { // Here JsonObject is from GSON 1.1 return new JsonObject(); } ``` 2 番目のモジュール操作 ```java public Object getAllProducts() { // Here JsonObject is from GSON 2.3 return new JsonObject(); } ``` アプリケーションで両方のモジュールを使用すると、両方のクラスの完全修飾名がまったく同じであるため、2 つのバージョンのうち片方だけが読み込まれます。完全修飾名の衝突によって、パッケージの_読み込まれなかったほうの_バージョンを必要とするモジュールは、異なる動作を起こして `ClassCastException` や `NoSuchMethodException` などのエラーが発生しやすくなります。 ### [](#export-アノテーション)@Export アノテーション SDK によって自動的にエクスポートされないクラスをモジュールがエクスポートする必要があるという、極めて厄介なケースや複雑なケースでは、`@Export` アノテーションを使用できます。 `@Export` アノテーションは、エクスポートするクラスの配列を受け取ります。 同じパッケージのすべてのクラスをエクスポートクラスとしてエクスポートしない限り、特定のクラスだけをエクスポートすることはできません。 # コーディングの原則 以下の原則は、モジュールまたはコネクタのすべてのコンポーネントに適用されます。これらは、すべての操作、配信元、設定、接続プロバイダー、関数に適用されます。 ## [](#コネクタは配信先システムを正確に反映する必要がある)コネクタは配信先システムを正確に反映する必要がある Anypoint Platform のコンテキストで言えば、コネクタの目的は配信先システムを Mule 言語に翻訳することです。コネクタは、高レベルの抽象表現を追加したり、特定のビジネスユースケースを実装する操作を含めたりしては**なりません**。 たとえば、請求書を作成し、請求書に項目を追加して、請求書を送信するためのリソースを持つ請求 API があるとします。このような API のコネクタは、これらのリソースのそれぞれに対して操作を 1 つずつ含む**必要があります**が、3 つのコールを 1 つに組み合わせる操作を含んでは**なりません**。 例外としては自動ページング操作があり、ページング効果を実現するために、単一の Mule 操作からの出力の処理において、複数のコールを実行します。 ## [](#プロトコルを混在させない)プロトコルを混在させない 1 つのコネクタは、同時に 1 種類のプロトコルにのみ接続する**必要があります**。たとえば、1 つの外部システムが REST API、SOAP API、そして OData API を公開するとします。 これらは同じ外部システムにアクセスしていますが、Anypoint Platform では 3 つの異なる API が存在することになります。そのため、1 つのコネクタで 3 種類のプロトコルを処理するのではなく、それぞれの API に対して別々のコネクタを用意する**必要があります**。 ## [](#エクスポートされたモジュール-java-api)エクスポートされたモジュール Java API このセクションを読む前に、Mule SDK の[「クラスローディング分離」](https://docs.mulesoft.com/mule-sdk/latest/isolation)を参照してください。 モジュールは、モジュールで定義されたパッケージのみをエクスポートする**必要があります**。連動関係ライブラリからのパッケージをエクスポートしては**なりません**。 ### [](#java-パッケージ)Java パッケージ モジュールは JDK からのパッケージをエクスポートせずにコンシュームするだけであるため、これらのパッケージは扱いが異なります。Mule は、使用するモジュールで使用できるすべての Java パッケージを自動的にエクスポートします。 ですが、モジュールは、そのモジュールと互換性のある Mule バージョンでサポートされているすべての JDK で使用できる Java パッケージのみを使用する**必要があります**。com.sun などのベンダー固有のパッケージを使用しては**なりません**。 ### [](#java-11-との互換性)Java 11 との互換性 Mule 4.2.0 からは JDK 11 もサポートされるようになりました。そのため、ネイティブ Java API に依存しているモジュールでは、必要な API が Java の新しいモジュール型アーキテクチャ (Java 9 で初めて登場した [Project Jigsaw](https://openjdk.java.net/projects/jigsaw/)) で使用できない場合があるという事実を考慮する**必要があります**。 たとえば、モジュールが Java トランザクション API (JTA) を必要とする場合、そのモジュールは pom.xml ファイルで次の依存関係を宣言する**必要があります**。 ```xml javax.transaction javax.transaction-api 1.2 ``` Java Mail API を使用する場合は次のように宣言します。 ```xml javax.mail javax.mail-api 1.6.2 ``` ### [](#スレッドセーフなデザイン)スレッドセーフなデザイン Mule は、同時性の高いワークロード向けにデザインされたリアクティブ実行エンジンです。そのため、すべてのコンポーネントは、最小限の競合で同時実行をサポートするように常にデザインする**必要があります**。 [スレッドセーフ](https://en.wikipedia.org/wiki/Thread_safety)は、同時実行を扱い慣れた Java 開発者にとっては基本的な概念です。SDK のユーザーも、この概念に慣れておくことが期待されます。 ## [](#不変のペイロードと属性オブジェクトを使用する)不変のペイロードと属性オブジェクトを使用する ペイロードまたはメッセージ属性として使用されるすべての出力データ型は、不変のオブジェクトである**必要があります**。 ## [](#コンテンツパラメーターの正しい使い方)コンテンツパラメーターの正しい使い方 @Content パラメーターは、MuleSoft [「コンテンツパラメーター」](https://docs.mulesoft.com/mule-sdk/latest/content-parameters)ドキュメントに従って正しく使用してください。 ## [](#フロー変数にはアクセスしない)フロー変数にはアクセスしない Mule 4 では、変数にはエンドユーザーのみがアクセスできます。モジュールから直接フロー変数にアクセスす**べきではありません**。 SDK にはフロー変数にアクセスするための API は用意されていませんが、省略可能なパラメーターを利用することでこの制約を破ることができます。次に例を示します。 ```java @Optional(defaultValue = "#[vars.foo]") String foo @Optional(defaultValue = "#[vars]") Map> vars ``` ただし、これらのステートメント (およびモジュール内から vars にアクセスする他の手段) は禁止されています。モジュールで必要とされるすべての情報は、パラメーターで明確に提供する**べきです**。変数に値を割り当てるかどうかはエンドユーザーが決めることです。 このルールに違反すると、位置の独立性にも違反することになります。 ## [](#メッセージ属性をパラメーターとして使用しない)メッセージ属性をパラメーターとして使用しない コンポーネントでは、属性オブジェクトが同じモジュールの一部として定義されている場合であっても、メッセージ属性としても使用される種別のパラメーターを定義す**べきではありません**。 たとえば、コネクタに LocalFileAttributes クラスを出力属性として使用する操作がある場合、次の定義は不正です。 ```java public void checkAccess(@Content LocalFileAttributes attributes) { doCheckAccess(attributes); } ``` その代わりに、実際に必要な属性クラスからの情報を反映したパラメーターを追加してください。 ```java public void checkAccess(String path) { ... } ``` ## [](#正しいエンコードを使用する)正しいエンコードを使用する 複数のエンコードを受け入れるシステムに接続する場合は、使用するエンコードを[設定の上書き](https://docs.mulesoft.com/mule-sdk/latest/config-override)によって設定可能にする**必要があります**。つまり、使用するエンコードを設定レベルだけではなく、エンコードを必要とする各コンポーネント (操作、配信元、関数など) でもパラメーター化可能とす**べきです**。 設定レベルでは、エンコードパラメーターのデフォルトを、@DefaultEncoding アノテーションで取得できる Mule のデフォルトエンコードとする**必要があります**。 次に例を示します。 ```java public class MyConfig implements Initialisable { @DefaultEncoding private String defaultEncoding; @Parameter @Optional private String encoding; public void initialise() throws InitialisationException { if (encoding == null) { encoding = defaultEncoding; } } public String getEncoding() { return encoding; } } ``` ## [](#期間パラメーター)期間パラメーター 多くのモジュールでは、タイムアウトやキャッシュエビクションといった期間を設定する必要があります。 期間は、2 つのパラメーターの組み合わせとして表現する**必要があります**。 - Timeout サフィックスの付いた int (整数) スカラーパラメーター - スカラーを限定する java.util.concurrent.TimeUnit パラメーター このパラメーターの名前は、対応するスカラーと完全に同じ名前に TimeUnit サフィックスを付けたものである**必要があります**。TimeUnit パラメーターのデフォルトは SECONDS にす**べきです**。 次に例を示します。 ```java /** * The socket connection timeout value. This attribute works in tandem with {@link #connectionTimeoutUnit}. */ @Parameter @Optional(defaultValue = "5") @Placement(tab = ADVANCED_TAB, order = 1) @Summary("Socket connection timeout value") private int connectionTimeout; /** * A {@link TimeUnit} that qualifies the {@link #connectionTimeout} */ @Parameter @Optional(defaultValue = "SECONDS") @Placement(tab = ADVANCED_TAB, order = 2) @Summary("Time unit to be used in the Timeout configurations") private TimeUnit connectionTimeoutUnit; ``` ## [](#タイムアウトには設定可能な設定の上書きが必須)タイムアウトには設定可能な設定の上書きが必須 タイムアウトの影響を受ける操作を実行するすべてのコンポーネントでは、パラメーターの[設定の上書き](https://docs.mulesoft.com/mule-sdk/latest/config-override)によってタイムアウトを設定できるようにする**必要があります**。 これらのタイムアウトは、期間パラメーターとして表現する**必要があります**。 ## [](#プライマリコンテンツのみのデフォルトをペイロードにすべき)プライマリコンテンツのみのデフォルトをペイロードにすべき プライマリコンテンツ以外のパラメーターのデフォルトをペイロードにす**べきではありません**。つまり、以下の定義を使用す**べきではありません**。 ```java @Optional(defaultValue = "#[payload]") ``` ## [](#日付パラメーターと時刻パラメーターの処理)日付パラメーターと時刻パラメーターの処理 日付と時刻のパラメーターは、java.time.LocalDate 種別、java.time.LocalDateTime、または java.time.ZonedDateTime 種別を使用して実装する**必要があります**。java.util.Date や java.util.Calendar は使用しないでください。 ## [](#エンドツーエンドのエクスペリエンスの確認)エンドツーエンドのエクスペリエンスの確認 モジュールをパブリッシュする前に、Anypoint Studio と Anypoint Design Center でモジュールをテストします。使い勝手とエクスペリエンスが優れていることを確認してください。正常に機能しても使い勝手が悪ければ、そのモジュールは不完全です。 以下を確認する**必要があります**。 - すべての入力パラメーターと出力値について DataSense が正しく解決される。 - 各コンポーネントのパラメーターの[レイアウト](https://docs.mulesoft.com/jp/mule-sdk/1.1/parameter-layout)が正しい。 - 表示ラベルや説明にタイプミスがない。 - モジュールの主なユースケースを使用するアプリケーションをユーザーが簡単にビルドできる。 ## [](#pojo-はできるだけ使用しない)POJO はできるだけ使用しない SDK では、入力パラメーターと出力データ型のどちらでも POJO を使用できます。ですが、これらの使用はお勧めできません。すべてのモジュールでは、JSON または XML を使用するように工夫す**べき**です。動的データ型の場合は、Java マップも使用できます。 このルールは、POJO を使用するユースケースが存在しない、あるいはすべての構造を JSON または Java マップに変換する必要があるという意味ではありません。このルールは単に、他のコンポーネントとの相互運用性が高く、逐次化の問題を回避できるデータ形式を使用した方がよいという意味です。 たとえば、Mule アプリケーションで活用するための Java 税金ライブラリを組織で開発したとします。このライブラリが POJO を返す場合は、このライブラリをラップする SDK モジュールをビルドし、その税金モジュールが POJO を受け入れて POJO を生成することになっても問題はありません。 一方、JSON を返す税金 API を利用する場合には、税金コネクタはその JSON を POJO に変換するのではなく、API と同じ JSON を返す**べきです**。 ## [](#pojo-の公開)POJO の公開 公開されるすべての POJO は (出力データ型、入力パラメーター、メッセージ属性として使用されるため) DataWeave に準拠する**必要があります**。つまり、@Parameter アノテーションが付けられた各項目に対して、デフォルトのコンストラクターと getter メソッドが必要です。 ## [](#ユーザーに-java-型を意識させてはならない)ユーザーに Java 型を意識させてはならない ユーザーは、モジュールを実装するために使用されている Java 型を知らなくてもモジュールを使用できる**必要があります**。 たとえば、次の変換を考えてみましょう。 ```json { name: "Pedro", address: { x: 11, y: 12 } } as com.foo.Person ``` このモジュールは、このような明確な変換が必要ないような方法で定義される**必要があります**。これを実現するには次のような方法があります。 - POJO を使用して個人を表現しない (推奨) - com.foo.Person を DataWeave に準拠した具体的なクラスにする - 入力パラメーターとして使用する場合は、抽象型やインターフェースを使用するのではなく、com.foo.Person を明確に参照する ## [](#ペイロードと属性は逐次化可能でなければならない)ペイロードと属性は逐次化可能でなければならない 操作またはメッセージ配信元から返されるメッセージ属性オブジェクトは、Java で逐次化可能である**必要があります**。そうでなければ、ObjectStore、VM キュー、またはクラスターモードの Mule では使用できません。 ## [](#mulecontext-にはアクセスしない)MuleContext にはアクセスしない MuleContext は非推奨であるため、どのモジュールやコネクタからもアクセスしては**なりません**。 ほとんどの場合、モジュールが MuleContext にアクセスする理由は特定の Runtime サービスを取得するためです。次に例を示します。 ```java muleContext.getRegistry().lookupByType(ObjectStoreManager.class) ``` その代わりに、@Inject を使用してこれらのサービスを取得します。 ```java public class MyComponent { @Inject ObjectStoreManager osm; } ``` ## [](#slf4j-によるログ)SLF4J によるログ すべてのログは、SLF4J API を使用して記録する**必要があります**。 この API との連動関係は MuleSoft が提供する親 pom ファイルで定義されているため、モジュールでは連動関係を定義しては**なりません**。 ## [](#すべてのロガーは静的でなければならない)すべてのロガーは静的でなければならない ロガーの作成にはリソースを大量に消費します。そのため、すべてのロガーは、非公開、静的、そして最終版である**必要があります**。 次に例を示します。 ```java public class Operation { private static final Logger LOGGER = LoggerFactory.getLogger(Operation.class); ... } ``` ## [](#静的状態を避ける)静的状態を避ける すべてのモジュールクラスは、静的状態を含んでいては**なりません**。例外は、ロガーと Serializable クラスの serialVersionUID のみです。 ## [](#sdk-バージョンの選択)SDK バージョンの選択 通常、開発者は特定の製品で使用可能な最新バージョンを使用する傾向にあります。これは SDK の場合には適用す**べきではありません**。Mule を拡張するには、次の手順を実行します。 - 必要な機能を特定する。 - 必要な機能が含まれる下位バージョンを選択します。 適切な SDK バージョンの選択についての詳細は、[「SDK バージョンの選択」](https://docs.mulesoft.com/mule-sdk/latest/choosing-version)を参照してください。 ## [](#ボックス入力のブールは使用しない)ボックス入力のブールは使用しない ブールパラメーターは、ネイティブブール型である**必要があります**。ボックス入力のブールはパラメーターの型としては使用できません。 すべてのブールパラメーターは省略可能とみなされ、デフォルトは false である**必要があります**。@Optional アノテーションを使用して、ブールパラメーターのデフォルトを変更できますが、必須パラメーターにすることはできません。 ## [](#リストパラメーターでは複数形の名前を使用する)リストパラメーターでは複数形の名前を使用する Java コレクション、マップ、配列、または何らかの配列 (JSON 配列など) を表す他の型として実装されているすべてのパラメーターには、複数形の名前を付ける**必要があります**。 ## [](#semver-versioning-の使用)Semver Versioning の使用 モジュールは、 [Semantic Versioning](https://semver.org/) 標準を使用してバージョン設定する**必要があります**。 ## [](#厳格なキャメルケースの使用)厳格なキャメルケースの使用 モジュールのソースコード全体では、キャメルケースを正しく適用する**必要があります**。そうしないと SDK が XML DSL の生成やレイアウトの処理を正しく行えなくなります。 ## [](#関連情報)関連情報 - [MuleSoft ヘルプセンター](https://help.mulesoft.com) - [Mule SDK 開発のベストプラクティス](https://docs.mulesoft.com/mule-sdk/latest/best-practices) # コネクタの再接続 SDK と Mule には標準の再接続戦略が用意されており、接続に使用するすべてのコネクタに適用されます。このサポートは汎用であるため、再接続ルールの設定と調整はどのコネクタでも同じです。 HTTP リクエスターでは、再試行のための再接続戦略は使用されません。詳細は、HTTP Request 設定リファレンス を参照してください。 ## [](#sdk-が再接続のトリガーのタイミングを知る方法)SDK が再接続のトリガーのタイミングを知る方法 SDK と Mule は再接続エンジンを備えていますが、再接続を行うとき、接続が切断されたとき、新しい接続が必要なときは、コネクタから通知されます。 ## [](#接続エラーとは)接続エラーとは? 既存の接続が機能しなくなり、コネクタがビジネスロジックの実行を継続できなくなると、再接続メカニズムによって新しい有効な接続を確立できます。これらのエラーは、接続エラーと呼ばれます。 エラーが接続エラーなのか他のエラーなのかを見極めることが非常に重要です。いくつかの例を示します。 ### [](#接続エラーの例)接続エラーの例 - Connection Timeout (接続タイムアウト) - ログイン情報が無効 - トークンの期限切れ ### [](#接続エラー以外のエラーの例)接続エラー以外のエラーの例 - HTTP 要求時に必要な HTTP クエリパラメーターがない - ファイルのコピー時にディレクトリが存在しない - スラックに null メッセージをパブリッシュした - データベースクエリの実行時の構文エラー ## [](#再接続のトリガー方法)再接続のトリガー方法 再接続において最も重要なことは、接続エラーが発生して再接続が必要な場合に、通知が正しく行えるということです。エラーの通知方法は、エラーが検出されたコンポーネントによって異なります。 以下のセクションでは、コネクタの各コンポーネントでの再接続のトリガー方法について説明します。 ### [](#接続プロバイダー)接続プロバイダー #### [](#接続の作成)接続の作成 接続プロバイダーは、接続に最初に関わります。接続プロバイダーが接続を作成できない理由にはいくつかありますが、接続エラーが発生した瞬間に接続プロバイダーは接続エラーを通知して、再接続をトリガーすることができます。つまり、接続を再び作成しようと試みます。 `connect()` メソッドが接続を作成しようとしたときにエラーを検出して再接続が必要になった場合は、[`ConnectionException()`](#connection-exception) をスローします。 ```java @Override public Connection connect() throws ConnectionException { Connection connection; try { connection = new Connection(); } catch (Exception e) { throw new ConnectionException("Error occurred trying to connect.", e); } return connection; } ``` #### [](#接続の検証)接続の検証 接続がまだ有効であることを確認するため、SDK は稼働中の接続をいつでも取得して、接続を作成した接続プロバイダーに対して検証できます。 接続を検証するため、`validate(Connection)` が呼び出され、接続プロバイダーが接続が有効かどうかをチェックします。 接続プロバイダーが接続が有効でなくなっていることを検出すると、[接続検証結果](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections#connection-validation-result)にエラー結果の `ConnectionValidationResult.failure(Cause, Exception)` を格納します。これによって現在の接続が切断されて無効化され、可能であれば再び作成されます。 例: 接続の検証 ```java @Override public ConnectionValidationResult validate(Connection connection) { if(connection.isValid()){ return ConnectionValidationResult.success(); } else { return ConnectionValidationResult.failure("Connection Problem", new RuntimeException()); } } ``` ### [](#操作)操作 操作が失敗する理由は、無効なパラメーター値や予期せぬエラーなどさまざまです。また、接続エラーに起因する場合もあります。エラーの原因が接続エラーであることを示すため、[`ConnectionException()`](#connection-exception) がスローされます。この例外により、**再接続がトリガーされ、操作が再び実行されます**。 #### [](#操作の例)操作の例 例 ```java public void operationTriggersReconnection(@Connection Connection connection, boolean connectionException){ if(connectionException){ throw new ConnectionException("Connection Error"); (1) } else { throw new RuntimeException(); (2) } } ``` 1ConnectionException がスローされると、使用されていた接続が無効化されます。 接続プロバイダーは新しい接続を作成しようと試み、接続が可能になると、操作が再び実行されます。2他の例外もスローされている場合は、エラーはビジネスエラーと見なされ、接続は無効化されず、操作も再実行されません。 ### [](#ソース)ソース [ソースは自分自身の接続を作成する責任を持つ](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-config-connection#obtaining-a-connection)ため、ソースによる再接続のトリガーは操作とは少し異なります。正常に作成された接続がその後切断されると、ソースは接続エラーとして [`ConnectionException(Exception, Connection)`](#connection-exception) をスローします。 ソースには[起動中](#starting-source)と[実行中](#running-source)の 2 つのフェーズがあります。それぞれの段階では、接続エラーの通知方法が異なります。 接続エラーを ConnectionException で通知しないと、再接続メカニズムが正しく機能しません。 #### [](#starting-source)起動中のソース `onStart()` メソッドが実行されるときに、ソースは起動中のソースフェーズにあります。 接続エラーは、`onConnectionException()` メソッドを使用して `SourceCallback` で通知する必要があります。ソースは停止し、再接続を試みます。 例 ```java @Override public void onStart(SourceCallback sourceCallback) throws MuleException { Connection connection = connectionProvider.connect(); try { connection.startStreaming(); } catch(Exception e){ sourceCallback.onConnectionException(new ConnectionException(e, connection)); } } ``` #### [](#running-source)実行中のソース `onStart()` メソッドが正常に完了してソースが正常に起動すると、残りのロジックが他のスレッドで実行されます。 他のスレッドでの実行中は、SDK は `throw` ステートメントで通知されたエラーを検出することはできません。そのため、`onConnectionException()` を使用して `SourceCallback` でエラーを通知する必要があります。 例 ```java @Connection ConnectionProvider connectionProvider; @Inject SchedulerService schedulerService; private Scheduler scheduler; @Override public void onStart(SourceCallback sourceCallback) throws MuleException { Connection connection = connectionProvider.connect(); scheduler = schedulerService.ioScheduler(); (1) scheduler.execute(() -> { while (true) { try { connection.receiveMessage(); } catch (Exception e){ sourceCallback.onConnectionException(new ConnectionException(e, connection)); (2) } } }); } ``` 1新しいスレッドでソースロジックを実行するためのスケジューラーを作成します。2置換すべきエラー接続を含む ConnectionException を SourceCallback に渡します。 #### [](#操作内からの再試行ポリシーテンプレートへのアクセス)操作内からの再試行ポリシーテンプレートへのアクセス バージョン 1.3 以降で使用できます。 操作用に設定されている `RetryPolicyTemplate` オブジェクトに操作自身がアクセスする必要のある高度なケースがあります。たとえば、再試行を独立して処理する既存のライブラリを操作で使用している場合や、再接続なしで再試行を適用する必要のあるユースケースなどです。 これらのケースをサポートするには、有効な `RetryPolicyTemplate` インスタンスを操作パラメーターとして追加して使用するように操作から要求します。次の WebSockets 用 Anypoint Connector (WebSockets Connector) の例を見てください。 ```java public void send(String socketId, @Content TypedValue content, @Connection WebSocketConnection conn, CompletionCallback callback, RetryPolicyTemplate retryPolicyTemplate) { } ``` retryPolicyTemplate 引数は操作パラメーターには変換されず、実行時に実効値と共に挿入されます。 この機能は、高度なシナリオのみを意図しています。通常は、ConnectionException をスローして、再接続と再試行を Mule に自動的に実行させます。この機能は、絶対に必要な場合にのみ使用してください。 ## [](#connection-exception)接続例外 `ConnectionException` は以下のプロパティで構築できます。 - **Message**: 現在のエラーを説明した文字列です。 - **Cause**: 指定した場合、Throwable は現在のエラーの原因を示します。 - [**ErrorType**](https://docs.mulesoft.com/jp/mule-sdk/1.1/errors): 指定した場合、ErrorType は現在のエラーを説明します。 - **Connection**: 指定した場合、Object は接続エラーを表します。切断と破棄に使用されます。 ### [](#関連情報)関連情報 - [ソースの設定と接続](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-config-connection) - [ソースライフサイクル](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-lifecycle) - [モジュールのエラー](https://docs.mulesoft.com/jp/mule-sdk/1.1/errors) # コネクタ認定の技術ガイドライン 1. _「Mule SDK の使用開始」_の次のセクションを使用して、開発環境をセットアップします。 - [開発環境のセットアップ](https://docs.mulesoft.com/jp/mule-sdk/1.1/getting-started#setup) - [IDE のセットアップ](https://docs.mulesoft.com/jp/mule-sdk/1.1/getting-started#setup_ide) 2. コネクタを作成または移行します。 - パートナーまたは開発者の場合、Mule 4 Connector を作成する。 1. 次のコマンドを実行します。 `mvn org.mule.extensions:mule-extensions-archetype-maven-plugin:generate` 2. コンソールから設定を完了します。 - 拡張の名前 (`cookbook` など) を指定する。 - `groupId` の要求を受け取ったら、デフォルトを受け入れる。 - _独自の_拡張の `artifactId` (`cookbook-connector` など) を指定する。 - 拡張のバージョンを指定する。 これが最初のコネクタの場合、`1.0.0` を使用します。そうでない場合、最後のコネクタからメジャーバージョンを作成します。たとえば、Mule 3 での AS/400 Connector の最新バージョンは `v1.0.2` です。Mule 4 の場合、コネクタバージョンは `v2.0.0` です。 - 拡張のメインパッケージの要求を受け取ったら、デフォルトを受け入れる。 - 既存の Mule 3 Connector を Mule 4 に移行する場合、移行ツールを使用する。 1. Devkit `version` を次のように変更します。 org.mule.tools.dmt mule-dmt 1.0.0 `0.9.0` は移行ツールのベータバージョンです。詳細は、「[FAQ](#question_1)」を参照してください。 2. `mvn clean package -Dmaven.test.skip` コマンドを使用します。 生成された Mule 4 拡張が対象フォルダーに表示されます。 3. コネクタの一部を自動移行できないことを示すエラーが移行ツールで報告された場合、続行する前にこれらのエラーを解決します。 3. `pom.xml` ファイルを更新します。 - 次の `` 設定を見つける。 org.mule.extensions mule-modules-parent 1.0.0 - 設定を次のように変更する。 org.mule.connectors mule-certified-parent 1.1.0 4. 次のいずれかのアノテーションセットを `Extension.java` に追加します。 - MuleSoft 認定コネクタ (無料) の場合: 例: Azure Storage のアノテーション ```annotations @Extension(name = “Azure Storage”, category = CERTIFIED, vendor = “Whishworks") @RequiresEnterpriseLicense(allowEvaluationLicense = true) ``` - MuleSoft 認定コネクタ (追加料金) の場合: 例: SAP Hybris のアノテーション ```annotations @Extension(name = “SAP Hybris”, category = CERTIFIED, vendor = “Admios") @RequiresEnterpriseLicense @RequiresEntitlement(name = “sap-hybris-connector") ``` 5. コネクタアイコンを設定します。[「コネクタへのカスタムアイコンの追加」](https://docs.mulesoft.com/jp/mule-sdk/1.1/getting-started#set-custom-icon)を参照してください。 6. `demo` のフォルダーを追加します。 7. ルートフォルダーに `License.md` がまだない場合は追加します。 ```text About MuleSoft Certified Connectors MuleSoft Certified Connectors are developed by MuleSoft’s partners and developer community. These connectors have been reviewed and certified by MuleSoft. To purchase the [Connector Name] Connector or to receive assistance or support for it, contact [Partner Name] directly at [Contact Information]. MuleSoft disclaims any support obligation for MuleSoft Certified Connectors. By installing this connector, you consent to MuleSoft sharing your contact information with the developer of this connector so that you can receive more information about it directly from the developer. Your license terms ``` [Mule SDK ドキュメント](https://docs.mulesoft.com/jp/mule-sdk/1.1/)に従って、操作を作成したりコネクタに追加したりできます。 上記の手順を完了したら、コネクタの構造は Mule 4 の準備が整っています。 8. [「モジュールのテスト」](https://docs.mulesoft.com/jp/mule-sdk/1.1/testing)に従って、コネクタのユニット、機能、およびインテグレーションテストケースを追加します。 コネクタには少なくとも 65% のテストカバー率が必要です。 9. コネクタを Connectivity Assets Manager に追加します。 Connectivity Assets Manager の既存のアカウントを使用できます。アカウントがない場合は、MuleSoft にお問い合わせください。 ## [](#faq)FAQ **DevKit を Mule 4 SDK に移行するためのキットやツールはありますか?** - はい。移行ツールは、2018 年第 2 四半期にその GA で使用可能になります。それまではベータバージョンを使用できます。 org.mule.tools.dmt mule-dmt 1.0.0 **サンプル SDK Connector プロジェクトの場所は?** - このガイドで説明されている手順で、コネクタプロジェクトの構造を作成できます。Cookbook Connector が更新されるまでは、Slack Connector を例として使用できます。 [mulesoft/slack-connector](https://github.com/mulesoft/mule4-slack-connector) を参照してください。 **プロジェクトを Studio 7 にインポートする方法と、それをテストして Studio に追加する方法は?** - コネクタプロジェクトを Studio 7 にインポートする機能は、現時点では使用できません。 次のコマンドを使用して Studio 7 にコネクタをインストールし、Studio 7 で使用するコネクタを作成できます。 `mvn clean install` 詳細な手順は、「[インストール例](#local_install)」を参照してください。 **Anypoint Design Center でコネクタを使用可能にする方法は?** - Design Center でコネクタをテストするには、Exchange で組織にコネクタをパブリッシュします。 完了したら、次のような `pom.xml` が表示されます。 4.0.0 org.mule.extension cookbook-connector 1.0.0 mule-extension Cookbook Extension 次の手順に従います。 1. Anypoint Platform アカウントを作成します。 このアカウントは、Connectivity Assets Manager で使用するアカウントとは異なる必要があります。 2. `private-exchange` サーバー ID を含むローカル Maven `settings.xml` ファイルに Anypoint ログイン情報を追加します。 3. コネクタ内の `groupid` の名前をビジネスグループ ID に変更します。 4. ビジネスグループ ID を含む次の Maven `deploy` コマンドを実行します。 ```text mvn clean deploy -DaltDeploymentRepository=private-exchange::default::https://maven.anypoint.mulesoft.com/api/v1/organizations//maven ``` **モジュールはオンプレミスや Runtime Manager ではなく Studio から実行されていることを認識できますか? または関連する懸念事項はありますか?** 背景: コネクタに対象 AS/400 サーバーのシリアル番号に基づくカスタムライセンスコードがある場合、接続が確立されるときにライセンスチェックが動的に実行されます。MuleSoft では、顧客はライセンスがなくても Studio 内でコネクタを評価できます。ただし、オンプレミスまたは Runtime Manager で実行している場合、コネクタは機能しません。 回答: - カスタムライセンスコードは、Runtime Manager では適用されません。Mule 4 SDK でネイティブにサポートされているライセンス検証を使用することをお勧めします。詳細は、[「モジュールライセンス」](https://docs.mulesoft.com/jp/mule-sdk/1.1/license)を参照してください。 - `xxxExtension.java` で、Mule 4 SDK のライセンス検証を使用するために次のアノテーションを追加します。この例では、Admios によって作成された SAP Hybris Connector を使用しています。 例: MuleSoft 認定コネクタ (追加料金) ```text @RequiresEnterpriseLicense @RequiresEntitlement(name = “sap-hybris-connector") ``` ## [](#installation_example)インストール例 この例は、FAQ 「[プロジェクトを Studio 7 にインポートする方法と、それをテストして Studio に追加する方法は?](#question_3)」を補足するものです。 次のコマンドを使用して Studio 7 にコネクタをインストールし、Studio 7 で使用するコネクタを作成できます。 1. `mvn clean install` を実行します。 この例は、ローカル Maven リポジトリへの `cookbook` Connector のインストールを示しています。 ```console [INFO] No primary artifact to install, installing attached artifacts instead. [INFO] Installing /Users/me/Downloads/mule4SampleConnector/cookbook-connector/pom.xml to /Users/me/.m2/repository/org/mule/extension/cookbook-connector/1.0.0/cookbook-connector-1.0.0.pom [INFO] Installing /Users/me/Downloads/mule4SampleConnector/cookbook-connector/target/temporal-extension-model.json to /Users/me/.m2/repository/org/mule/extension/cookbook-connector/1.0.0/cookbook-connector-1.0.0-extension-model-4.0.0.json [INFO] Installing /Users/me/Downloads/mule4SampleConnector/cookbook-connector/target/cookbook-connector-1.0.0-mule-plugin.jar to /Users/me/.m2/repository/org/mule/extension/cookbook-connector/1.0.0/cookbook-connector-1.0.0-mule-plugin.jar [NOTE] --- [INFO] BUILD SUCCESS [NOTE] --- [INFO] Total time: 35.057 s [INFO] Finished at: 2018-01-11T17:10:50-08:00 [INFO] Final Memory: 49M/476M [NOTE] --- ``` 2. Studio 7 で Mule プロジェクトを作成し、Studio 7 でこのプロジェクトの `pom.xml` を開きます。  3. コネクタの連動関係設定 (``) を `pom.xml` に追加します。 たとえば、次の `` では、Studio 7 がローカル Maven リポジトリにインストールされた `cookbook-connector` を検索できます。 org.mule.extension cookbook-connector 1.0.0 mule-plugin パレットにコネクタが表示されます。次の例は、Studio パレットの Cookbook Connector を示しています。  ## [](#関連情報)関連情報 [Intro to Anypoint Design Center - Flow Designer](https://www.mulesoft.com/webinars/api/intro-to-anypoint-design-center-flow-designer) (Anypoint Design Center の概要 - Flow Designer) [Mule Runtime について](#4.1@mule-runtime::index.adoc) [Mule SDK](https://docs.mulesoft.com/jp/mule-sdk/1.1/) [Mule 4 SDK](https://youtu.be/qdOXKj8V9Lc) (動画) [Connector/DevKit/SDK フォーラム](https://forums.mulesoft.com/spaces/14/anypoint-connectors.html) [ベストプラクティス](https://docs.mulesoft.com/jp/mule-sdk/1.1/best-practices) [Slack Connector](https://github.com/mulesoft/mule4-slack-connector) [HTTP Connector](https://github.com/mulesoft/mule-http-connector/tree/1.2.0) [Database Connector](https://github.com/mulesoft/mule-db-connector/tree/1.3.1) [DevKit 移行ツール](https://docs.mulesoft.com/jp/mule-sdk/1.1/dmt) # コンテキスト情報インジェクション 操作またはソースが処理されるコンテキストに関する情報を取得するため、操作またはソースにパラメーターを追加できます。パラメーターは UI には表示されませんが、SDK によってランタイムに挿入されます。 ## [](#コンポーネントの場所)コンポーネントの場所 操作を実行したりソースを使用したりするときに、主にログ記録の目的で、コンポーネントの場所に関するコンテキストが必要になる場合があります。これを実現するため、`ComponentLocation` をパラメーターとして定義し、それを挿入できます。 次の例は、ソースを開始するときにコンポーネントの場所をログに記録する方法を示しています。 ```java @Alias("listener") public class HttpListener extends Source { private static final Logger LOGGER = getLogger(HttpListener.class); @Connection private ConnectionProvider serverProvider; private ComponentLocation location; @Parameter private String path; private HttpServer server; @Override public void onStart(SourceCallback sourceCallback) throws MuleException { server = serverProvider.connect(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Starting HTTP Listener %s on path %s", location.getLocation(), path); } server.listen(path); } // ... } ``` 次の例は、操作 (ソースなし) のコンテキストでコンポーネントの場所をログに記録する方法を示しています。 ```java //ComponentLocation is added as a parameter when used in an operation public String sayHi(String person, String q, ComponentLocation location) { // ... System.out.println("Location: " + location.getLocation()); // ... } ``` ## [](#イベントの追跡)イベントの追跡 **バージョン 1.1 以降で使用可能** ログを使用してイベントを追跡できるようにするには、操作およびソースコールバックで `CorrelationInfo` パラメーターを使用します。この相関関係情報により、処理されるイベントのイベント ID と相関関係 ID が提供されます。 `CorrelationInfo` パラメーターを操作メソッドまたはソースコールバックに追加する必要があるだけです。インスタンスには、メソッドまたはコールバックが実行するイベント情報が入力されます。 次の簡単な例は、`CorrelationInfo` の使用方法を示しています。 ```java public class ObjectStoreOperations { private static final Logger LOGGER = getLogger(ObjectStoreOperations.class); // ... @Throws(StoreErrorTypeProvider.class) public void store(String key, @Content TypedValue value, ObjectStore objectStore, CorrelationInfo correlationInfo) { objectStore.store(key, value); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Object stored with key: %s .The event id is: %s", key, correlationInfo.getEventId()); } } // ... } ``` # コンテンツパラメーター 次の操作 (疑似コード) を考えてみます。 ```xml ``` 操作を構成するパラメーターは、多くの場合異なる役割を果たします。 ## [](#動作パラメーター)動作パラメーター これらのパラメーターは、操作の動作方法を決定する設定を管理します。上記の例では、`overwrite` パラメーターは、ファイルがすでに存在する場合に実行するアクションを設定します。`path` パラメーターは、コンテンツの書き込み先を示します。両方のパラメーターは操作を構成しますが、これは Write 操作であるため、 書き込まれるデータの主な概念を表すものではありません。 一部の操作は、次のように動作パラメーターによって排他的に形成されます。 ```xml ``` この操作はコンテンツを取得しないため、両方のパラメーターが動作パラメーターです。コンテンツはコピーされるファイル内にあります。 ## [](#content-param)コンテンツパラメーター 上記の動作パラメーターの説明を考慮すると、コンテンツパラメーターの定義は明確です。上記の `file:write` の例では、コンテンツは `@Content` パラメーターです。 コンテンツパラメーターには、次の特性があります。 - 式を受け入れる必要がある。SUPPORTS\_EXPRESSIONS と EXPRESSION\_REQUIRED の両方がサポートされていますが、`@Expression(NOT_SUPPORTED)` が使用されている場合はコンパイルに失敗します。 - 各コンテンツパラメーターは、コンテンツを生成するために独自の DataWeave スクリプトを埋め込むことができる。 - コンテンツパラメーターは、埋め込まれた DataWeave スクリプトを有効にするため、常にテキスト要素として DSL に変換される。 今回はコンテンツパラメーターを使用して、もう一度 `file:write` 操作を考えてみます。この操作をフローで使用し、メッセージペイロードは XML として保存する JSON であるとします。 ```xml ``` モジュールのコードでは、`content` パラメーターは `@Content` アノテーションでマークされます。 ```java public void write(String path, @Content InputStream content) { // write code } ``` ## [](#primary_content_parameter)プライマリコンテンツパラメーター 場合によっては、次のように操作に多数のコンテンツパラメーターがあります。 ```xml #[body..] #[uri-params …] #[you get the picture..] ``` ご覧のとおり、必要なだけのコンテンツパラメーターを設定できます。つまり、`@Content` アノテーションを複数のメソッド引数で使用できます。 ただし、その場合でも `body` パラメーターは他のパラメーターよりも重要です。ヘッダーも HTTP 要求で送信されるコンテンツの一部ですが、それらのヘッダーは送信される本文を補完するものです。そのため、操作に複数のコンテンツパラメーターがある場合、`@Content(primary = true)` を使用してその 1 つをプライマリコンテンツとしてマークする必要があります。 プライマリコンテンツパラメーターは、通常のコンテンツパラメーターと同じ特性のすべてに加えて、次の特性があります。 - 自動的に省略可能になる。 - デフォルトで自動的に `#[payload]` に設定される。 これら 2 つの機能は、ランタイムによって自動的にパラメーターに追加されます。 コンテンツパラメーターが 1 つのみだった file:write の例に戻りましょう。これはプライマリですか? YES。操作のコンテンツパラメーターが 1 つのみの場合、SDK は自動的にそれをプライマリと見なします。つまり、file:write 操作のコンテンツパラメーターは自動的に省略可能になり、デフォルトで #[payload] に設定されます。これは、モジュール間の一貫性を強化するために役立ちます。 ## [](#プライマリコンテンツのデフォルトの変更)プライマリコンテンツのデフォルトの変更 プライマリコンテンツをデフォルトでペイロード以外の何かに設定する必要がある極端な状況があります。これは、操作のコンテンツパラメーターが 1 つのみで、そのパラメーターが常に必要とは限らない場合に発生しがちです。たとえば、Database Connector を考えてみます。選択クエリの入力パラメーターはプライマリコンテンツですが、すべてのクエリに入力パラメーターが必要なわけではありません。そのため、実際のデフォルトは空のマップにする必要があります。 これを行うには、`@Content` アノテーションと `@Optional` アノテーションを組み合わせます。たとえば、次の例はデフォルトを空のマップに設定しています。 ```java public List select(@Text String sql, @Optional(defaultValue="#[{}]") @Content Map inputParameters) { // select } ``` コンテンツパラメーターを省略可能として、デフォルトなしで設定することもできます。 ```java public List select(@Text String sql, @Optional @Content Map inputParameters) { // select } ``` 最後に、次のように `@Content` アノテーションを `@NullSafe` と組み合わせることができます。 ```java public List select(@Text String sql, @Optional @NullSafe @Content Map inputParameters) { // select } ``` 最初と 3 番目の例は同等です。ただし、モジュールのユーザーの操作性が向上するため、@NullSafe オプションをお勧めします。#[{}] を明示的なデフォルトとして設定すると、経験の浅い Mule ユーザーは混乱する可能性があります。 ## [](#パラメーターグループへのコンテンツパラメーターの埋め込み)パラメーターグループへのコンテンツパラメーターの埋め込み 上記の [`http:request`](#primary_content_parameter) 操作のコンテンツパラメーターは、`request-builder` という要素に含まれています。使いやすさの理由から、コネクタの作成者はすべての要求関連の属性をそれを囲むオブジェクトでグループ化することを選択しました。これは、SDK によって 次の方法でサポートされています。 ```java public void request(String path, @ParameterGroup(showInDsl=true) HttpRequestBuilder requestBuilder) { // request } ``` ご覧のとおり、ここにはコンテンツパラメーターはありません。ただし、`HttpRequestBuilder` クラス内を見ると、`@Content` アノテーションがあります。 ```java public class HttpRequestBuilder { @Parameter @Content(primary = true) private InputStream body; @Parameter @Content @NullSafe private Map uriParams; @Parameter @Content @NullSafe private Map uriParams; } ``` サンプル要求操作の HttpRequestBuilder 引数から @ParameterGroup アノテーションを削除すると、コンパイルエラーになります。@Content は複合型には使用できません。 # サンプルデータ サンプルデータにより、操作とソースで生成する出力の例を提供できます。これらの例は、コネクションレスの例からの接続または出力形式を介して、ライブシステムから取得された情報を表示します。 サンプルデータは、Mule 4.4.0 以降でサポートされています。ただし、Mule バージョンに関係なく、すべての Anypoint Connector でこの機能を使用できます。 サンプルデータを使用して、次の作業を行うことができます。 - SDK API を実装する - 操作パラメーターを使用して例を提供する - 設定と接続を使用して例を提供する ## [](#sdk-api)SDK API SDK API を使用して、サンプルデータを提供したり、エラーを通知したり、コンポーネントを拡張したります。 ### [](#sampledataresolver)SampleDataResolver この API を実装して、実際の本番シナリオでコンポーネントが出力するデータを表すサンプルデータを使用し、操作とメッセージソースを拡張します。 実装には次の作業が必要です。 - デフォルトのコンストラクターを提供する。 - Result オブジェクトを返すペイロード属性とメッセージ属性の両方のサンプルを提供する。 汎用データ型は、拡張コンポーネントの戻り値のデータ型と常に一致します。動的なデータ型を返すコンポーネントの場合、各実装は正しい動的なデータ型のインスタンスを返します。操作が属性を返さない場合は、Result を使用します。 - サンプルデータの取得によって、対象システムに重大な副次的影響が発生しないことを保証する。 - 大きなオブジェクトやデータストリームを返すためには使用しない。データは、小さなワーカーインスタンスのメモリ内に収まる必要があります。 実装は、パラメーター、設定、および接続にアクセスし、`@Parameter`、`@Config`、および `@Connection` パラメーターを介してサンプルデータを生成できます。 コネクタの場合、ハードコードされた値を返す代わりに、接続先のシステムから実際のデータを返す実装が最も価値があります。 次の例は、SampleDataResolver API を示しています。 ```java /** * [...] * * @param the generic type of the output value * @param the generic type of the message attributes * @since 1.4 */ @MinMuleVersion("4.4") public interface SampleDataProvider { /** * An ID that identifies each implementation of this interface. It must be unique among implementations in the same * extension. Subsequent invocations must always return the same fixed value. * * @return the resolver's id */ String getId(); /** * Obtains and returns the sample information. * * @return a {@link Result} object * @throws SampleDataException if the sample cannot be obtained */ Result getSample() throws SampleDataException; } ``` ストリーミングは次の場合はサポートされていません。 - InputStream 値を返す操作またはソース。 リゾルバーは、ByteArrayInputStream 値や、getSample() メソッドを返す前にデータストリーム全体をすでに取得している他のオフライン実装など、接続を必要としない実装を常に返します。これは、基盤となる接続が閉じられた後でも InputStream 値は完全にコンシューマブルであるためです。一時バッファファイルも使用しないでください。 - ストリーミングとみなされるため PagingProvider 値を返す操作。以前の箇条書きで説明されている制限が適用されます。このような場合、代わりに同じ項目型の List 値が返されます。 ### [](#sampledataexception)SampleDataException このクラスはサンプルデータの取得中にエラーを通知するため、ランタイムはそれに応じてエラーを処理できます。必要に応じて、このクラスで説明される定義済みの失敗コードメッセージを使用します。 次の例は、SampleDataException クラスを示しています。 ```java /** * {@link Exception} to indicate that an error occurred fetching sample data through a {@link SampleDataProvider}. * * @since 1.4.0 */ public class SampleDataException extends MuleException { /** * Signals an unexpected exception */ public final static String UNKNOWN = "UNKNOWN"; /** * Indicates that the {@link SampleDataProvider} didn't return any information */ public final static String NO_DATA_AVAILABLE = "NO_DATA_AVAILABLE"; /** * Indicates that a connection couldn't be established */ public final static String CONNECTION_FAILURE = "CONNECTION_FAILURE"; /** * Indicates that Sample Data resolution was attempted on a {@link Location} that doesn't exist */ public final static String INVALID_LOCATION = "INVALID_LOCATION"; /** * Indicates that the Sample Data resolution was attempted but the underlying {@link SampleDataProvider} has required parameters * that weren't supplied */ public final static String MISSING_REQUIRED_PARAMETERS = "MISSING_REQUIRED_PARAMETERS"; /** * Indicates that Sample Data resolution was attempted on a component that doesn't support that capability */ public final static String NOT_SUPPORTED = "NOT_SUPPORTED"; /** * Indicates that Sample Data resolution was attempted on an unregistered Extension */ public final static String INVALID_TARGET_EXTENSION = "INVALID_TARGET_EXTENSION"; private final String failureCode; public SampleDataException(String message, String failureCode) { super(createStaticMessage(message)); this.failureCode = failureCode; } public SampleDataException(String message, String failureCode, Throwable cause) { super(createStaticMessage(message), cause); this.failureCode = failureCode; } public SampleDataException(I18nMessage message, String failureCode) { super(message); this.failureCode = failureCode; } public SampleDataException(I18nMessage message, String failureCode, Throwable cause) { super(message, cause); this.failureCode = failureCode; } /** * @return The failure code of the error that produced the error */ public String getFailureCode() { return failureCode; } } ``` ### [](#sampledata)@SampleData このアノテーションは、リゾルバーを拡張コンポーネントに関連付けます。ソースではデータ型レベル、操作ではメソッドレベルで適用されます。 次の例は、`@SampleData` アノテーションを示しています。 ```java /** * Associates a {@link Source} class or operation method with a {@link SampleDataProvider}. * * @since 1.4.0 * @see SampleDataProvider */ @Target({TYPE, METHOD}) @Retention(RUNTIME) @Documented public @interface SampleData { /** * @return the associated {@link SampleDataProvider} */ Class extends SampleDataProvider> value(); /** * @return bindings between parameters in the {@link SampleData#value()} to extraction expressions. */ Binding[] bindings() default {}; } ``` ## [](#サンプルデータの例)サンプルデータの例 操作、または設定と接続を使用してサンプルデータを取得します。 ### [](#直接操作を使用したサンプルデータの取得)直接操作を使用したサンプルデータの取得 この例を使用して、接続を使用せずに操作を使用して静的サンプルデータを提供します。 JSON 形式で情報を取得する操作を含む新しい GitHub Connector があるとします。ただし、限られた数またはコストのかかる API コールの 1 つをコンシュームするサンプルデータを提供している間は API コールをコンシュームしたくないため、操作を直接実装します。 次の例は、`@SampleData` アノテーションを介してプロバイダーが接続された操作の定義を示しています。 ```java @SampleData(JsonSampleDataProvider.class) public Result getUserInfo(String username, @Connection GitHubConnection connection) { // operation code... } ``` 次の例は、以前に示された実装を使用してパラメーターを挿入するサンプルデータプロバイダー実装を示しています。 `@Parameter` アノテーションの名前とデータ型は、操作のパラメーター (`username`) と同じです。 ```java public class JsonSampleDataProvider implements SampleDataProvider { private static JsonObject sampleJson = new JsonObject(); public JsonSampleDataProvider() { sampleJson.add("company", "Mulesoft"); sampleJson.add("email", "maxmule2007@mulesoft.com"); sampleJson.add("repositories", new JsonArray("mule-api", "data-weave-2")); } @Parameter private String username; @Override public Result getSample() throws SampleDataException { sampleJson.addFirst("username", username); String body = sampleJson.getBody(); return Result.builder() .output(new ByteArrayInputStream(body.getBytes())) .mediaType(MediaType.APPLICATION_JSON) .length(body.length()) .build(); } @Override public String getId() { return "jsonResolver"; } } ``` `username` パラメーターの値が `John Doe` だとします。プロバイダーは次の JSON を返します。 ```json5 { "username": "John Doe", "company": "Mulesoft", "email": "maxmule2007@mulesoft.com", "repositories": ["mule-api", "data-weave-2"] } ``` ### [](#設定値と接続を使用したサンプルデータの取得)設定値と接続を使用したサンプルデータの取得 この例を使用して、パラメーターと設定値に従い、同時に接続も必要とする動的なサンプルデータを提供します。 次の条件を満たす操作とソースの両方を含む新しい GitHub Connector があるとします。 - 取得するエンティティのデータ型を制御する **objectType** パラメーター (`pullRequest`、`issue`、`commit` などの値を使用可能) がある。 - 結果を絞り込む省略可能な **status** パラメーターがある - GitHub API の接続を使用する - Result オブジェクトを返す 次の例は、操作定義を示しています。 ```java @SampleData(ObjectSampleDataProvider.class) public Result getObject(String objectType, @Optional String status, String anotherParameter, @Connection GitHubConnection connection, @Config GitHubConfig config) { // operation code... } ``` 次の例は、ソース定義を示しています。 ```java @SampleData(ObjectSampleDataProvider.class) public class OnNewThingTrigger extends Source { @Parameter private String objectType; @Parameter @Optional private String status; @Parameter private String extraParameter; @Config private GitHubConfig config; @Connection private ConnectionProvider connection; // source code... } ``` 次の例は、両方のケースに対応する SampleDataProvider 実装を示しています。**objectType** パラメーターと **status** パラメーター、および接続と設定を使用します。 ```java public class ObjectSampleDataProvider implements SampleDataProvider { @Parameter private String objectType; @Parameter @Optional private String status; @Connection private GitHubConnection connection; @Config private GitHubConfig config; @Override public Result getSample() throws SampleDataException { String query = "objectType=" + objectType; if (status != null) { query += "; status=" + status; } query += ";organization=" + config.getOrganization(); List jsonDocs = connection.query(query); if (jsonDocs.isEmpty()) { throw new SampleDataException("No data available", NO_DATA_AVAILABLE); } GitHubObject sample = jsonDocs.get(0); String body = sample.getBody(); return Result.builder() .output(new ByteArrayInputStream(body.getBytes())) .mediaType(MediaType.APPLICATION_JSON) .length(body.length()) .attributes(sample.getMetadata()) .attributesMediaType(MediaType.APPLICATION_JAVA) .build(); } @Override public String getId() { return "objectResolver"; } } ``` 両方のコンポーネントには、サンプルデータプロバイダーと同じデータ型の署名があります。これらはリゾルバーで必要な同じパラメーターを定義しますが、それぞれにリゾルバーでは不要な独自のパラメーターがあります。リゾルバーは、値プロバイダーと同じ方法でパラメーター、接続、および設定にアクセスします。 使用可能なデータがない場合、リゾルバーは定義済みの失敗コードで `SampleDataException` エラーをスローします。 ## [](#oauth-トークンの更新)OAuth トークンの更新 操作またはソースで OAuth 接続を使用している場合は、 [操作またはソース](https://docs.mulesoft.com/mule-sdk/1.1/oauth-token-expiration)で実行する場合と同様に、getSample() メソッド内で `AccessTokenExpiredException` エラーをスローして、プロバイダーでトークンの更新をトリガーします。 次の例は、トークンの更新を示しています。 ```java public class RefreshedOAuthSampleDataProvider implements SampleDataProvider { public static final String SAMPLE_PAYLOAD_VALUE = "Sample payload!"; public static final String SAMPLE_ATTRIBUTES_VALUE = "Sample Attributes!"; @Connection private TestOAuthConnection testOAuthConnection; @Override public String getId() { return "OAuth sample data"; } @Override public Result getSample() throws SampleDataException { if (!testOAuthConnection.getState().getAccessToken().contains("refresh")) { throw new AccessTokenExpiredException(); } return builder() .output(SAMPLE_PAYLOAD_VALUE) .attributes(SAMPLE_ATTRIBUTES_VALUE) .build(); } } ``` ## [](#別名および機能パラメーター)別名および機能パラメーター 値プロバイダーを解決するのと同じ方法でパラメーターを解決できます。 パラメーターの一部として機能パラメーターを定義するのと同様に、別名を定義できます。 ## [](#エラー条件)エラー条件 コンパイル中に、一連の検証によりサンプルデータプロバイダーが前述の制限の一部に準拠していることがチェックされます。 - 出力と属性のデータ型のチェック SDK は、出力と属性のデータ型が 汎用タプルで宣言されたものと一致するコンポーネントにプロバイダーが適用されていることを検証します。そうでない場合、検証エラーがスローされます。 - パラメーターの使用状況チェック SDK は、サンプルデータプロバイダーでパラメーターが使用される場合、関連コンポーネントでもそれがパラメーターとして宣言されていることを検証し、両方の宣言でパラメーターのデータ型が同じであることもチェックします。そうでない場合、検証エラーがスローされます。 - 接続と設定の使用状況チェック SDK は、サンプルデータプロバイダーで接続または設定が使用されている場合、関連コンポーネントでもそれらが使用されていることを検証します。そうでない場合、検証エラーがスローされます。 - インスタンス化チェック SDK は、各プロバイダーがインスタンス化可能であることを検証します。これは必須の条件です。そうでない場合、検証エラーがスローされます。 - void なし サンプルデータプロバイダーを void 操作に配置することはできません。そうでない場合、検証エラーがスローされます。 - ストリーミング ストリーミングはサポートされませんが、これは強制されていません。 拡張開発者は、ベストプラクティスに従って契約を遵守する必要があります。 # ステレオタイプ ステレオタイプはコンポーネントを緩やかに分類する方法です。コンポーネントにステレオタイプを割り当てると、コンポーネントは特定の戻り値のデータ型や構造を持つものではなくなります。代わりに、同じステレオタイプの他のコンポーネントと共通するものがコンポーネントに保持されていることが示されます。ステレオタイプを割り当てて、パラメーターがそのステレオタイプに属するようにすることができます。 ## [](#stereotype-アノテーション)Stereotype アノテーション コンポーネントにステレオタイプを割り当てるには、`@Stereotype` アノテーションを `StereotypeDefinition` クラスと共に使用する必要があります。 `@Stereotype` アノテーションは次のレベルで使用できます。 - メソッドレベル。特定の操作に影響します。 - クラスレベル。このクラスで定義されているすべての操作にステレオタイプを割り当てます。 コンポーネントは 1 つのステレオタイプにのみ属することができます。つまり、コンポーネントで `@Stereotype` アノテーションが使用されている場合、そのコンポーネントに他のアノテーションでステレオタイプを割り当てることはできません。 たとえば、操作でメッセージを変更せず、何らかの検証のみを実行することを示すために使用する `@Validator` アノテーションでは、ステレオタイプが操作に自動的に割り当てられます。 次の例では、操作で `@Stereotype` を使用しています。 ```java @Stereotype(JenkinsStereotypeDefinition.class) public final class CommonJenkinsOperations { public void triggerBuild(String name, Map arguments) throws Exception { // ... } public void createJobs(String name, Map arguments) throws Exception { // ... } public Result ActiveJobs() throws Exception { // ... } } ``` この場合、クラス `CommonJenkinsOperations` のすべての操作が、`JenkinsStereotypeDefinition` で定義されたステレオタイプになります。 ## [](#stereotypedefinition)StereotypeDefinition このインターフェースは、ステレオタイプ名、名前空間、親を提供します。デフォルトでは、名前空間は拡張機能の名前空間に割り当てられます。 ステレオタイプには階層があります。指定しない限り、デフォルトでは、ステレオタイプは別のステレオタイプから拡張されません。 次の例は、`StereotypeDefinition` の定義方法を示しています。 ```java public final class JenkinsStereotypeDefinition extends MuleStereotypeDefinition { (1) @Override public String getName() { return "JENKINS_OPERATION"; } @Override public Optional getParent() { return Optional.of(PROCESSOR_DEFINITION); (2) } } ``` 1JenkinsStereotypeDefinition クラスは、PROCESSOR_DEFINITION などの複数の StereotypeDefinition を認識している StereotypeDefinition から拡張されます。2MuleStereotypeDefinition でこの StereotypeDefinition の親として定義されている StereotypeDefinition である PROCESSOR_DEFINITION を選択します。 ## [](#パラメーターでの-allowedstereotypes-アノテーション)パラメーターでの AllowedStereotypes アノテーション このアノテーションは、パラメーターで受け入れられる各 `StereotypeDefinition` を識別します。このアノテーションの値は、`StereotypeDefinition` の単一値または配列です。これは、種別 `Chain` または `Route` のパラメーターにのみ割り当てることができます。 次の例では、特定のステレオタイプをパラメーターとして適用します。 ```java public class JenkinsScope { private static final Logger logger = getLogger(JenkinsScope.class); public void jenkinsGroupExecution(@AllowedStereotypes(JenkinsStereotypeDefinition.class) Chain operations, CompletionCallback callback) throws Exception { LOGGER.debug("Invoking Jenkins Operations.") operations.process( result -> { // Log information about the execution of the operations callback.success(result); }, (error, previous) -> { LOGGER.error(error.getMessage()); callback.error(error); }); } } ``` 受信する `Chain` には、`JenkinsStereotypeDefinition` クラスで定義されたステレオタイプを持つ操作のみを含めることができます。 ## [](#設定リファレンス)設定リファレンス 各設定には自動的に割り当てられた一意のステレオタイプがあります。このステレオタイプには次の特性があります。 - 名前と名前空間の両方が大文字で構成され、単語はアンダースコアで区切られます。 - 名前空間は拡張機能の名前空間です。たとえば、HTTP Connector では「HTTP」、JMS Connector では「JMS」になります。 - 名前は設定の名前です。たとえば、「requestConfig」設定のステレオタイプ名は「REQUEST\_CONFIG」になります。 このデフォルトのステレオタイプは、`@Stereotype` アノテーションを使用して上書きできます。 このステレオタイプを使用すると、`@ConfigReference` アノテーションを使用して、`String` パラメーターを設定の特定の種別の名前に制限できます。このアノテーションでは、設定のステレオタイプの名前と名前空間が必要です。 この機能の使用例を次に示します。 HttpService を使用する拡張機能を開発します。これを使用するのに HttpRequesterConfig が必要です。これで、拡張クライアントを使用すると、HttpService は実際の設定を使用します。 たとえば、HTTP Connector でこの `HttpRequesterConfig` を宣言したとします。 ```java @Configuration(name = "requestConfig") @ConnectionProviders(HttpRequesterProvider.class) @Operations({HttpRequestOperations.class}) public class HttpRequesterConfig { // Parameters and getters for the Configuration } ``` Web サービスコンシューマーコネクタは次のように定義されています。 ```java @ErrorTypes(SoapErrors.class) @Operations(ConsumeOperation.class) @ConnectionProviders(SoapClientConnectionProvider.class) (1) @SubTypeMapping(baseType = CustomTransportConfiguration.class, subTypes = CustomHttpTransportConfiguration.class) @Extension(name = "Web Service Consumer") @Xml(prefix = "wsc") public class WebServiceConsumer { } ``` 1この ConnectionProvider は、@ConfigReference アノテーションを使用するパラメーターを保持します。このコネクタでは設定が宣言されていないため、デフォルトの config が使用されます。 次は、ConnectionProvider の宣言の一部を示しています。 ```java public class SoapClientConnectionProvider implements CachedConnectionProvider { // ... @Inject private HttpService httpService; // ... @Placement(tab = "Transport") @Parameter @Optional @Expression(NOT_SUPPORTED) @DisplayName("Transport Configuration") private CustomTransportConfiguration customTransportConfiguration; // ... } ``` 次は、`@ConfigReference` アノテーションが使用されている場所を示しています。 ```java @Alias("http-transport-configuration") public class CustomHttpTransportConfiguration implements CustomTransportConfiguration { @ConfigReference(namespace = "HTTP", name = "REQUEST_CONFIG") (1) @Parameter private String requesterConfig; @Override public MessageDispatcher buildDispatcher(ExtensionsClient client) { return new HttpConfigBasedMessageDispatcher(requesterConfig, client); (2) } @Override public TransportResourceLocator resourceLocator(ExtensionsClient client) { return new HttpResourceLocator(requesterConfig, client); (2) } } ``` 1文字列パラメーター requesterConfig は HttpRequesterConfig の名前の値を使用する必要があります。2設定の名前は ExtensionsClient と共に使用されます。 # ストリーミング Mule 4 では、ストリーミングによって、自動的および透過的な反復可能ストリームが可能になります (詳細は、以下の「ストリーミングについて」を参照)。 ストリーミングには次の 2 種類があります。 - [バイナリストリーミング](https://docs.mulesoft.com/jp/mule-sdk/1.1/binary-streaming) - [オブジェクトストリーミング](https://docs.mulesoft.com/jp/mule-sdk/1.1/object-streaming) ## [](#関連情報)関連情報 [ストリーミングについて](#4.1@mule-runtime::streaming-about.adoc#repeatable_streams) # スレッドと非同期処理 ほとんどのモジュールではスレッドセーフなデザインを心掛けるという点を除いては、同時実行の問題を抱える**べきではありません**。 ただし、モジュールがタスクを非同期に実行したり、繰り返し発生するタスクをスケジュールしたりする必要のあるユースケースもあります。このセクションでは、そのためのベストプラクティスについて詳しく説明します。 このセクションの説明では、「Scheduler」は org.mule.runtime.api.scheduler.Scheduler クラスのインスタンスを指します。 非同期処理と非ブロック I/O を混同しないでください。これらは同じではありません。 ## [](#モジュールで-threads-や-executors-を作成しない)モジュールで Threads や Executors を作成しない モジュールが自身の Threads、Executors、または ExecutorServices を作成しては**なりません**。すべての非同期タスクは、Mule の SchedulerService から Scheduler を取得して実行する**必要があります**。 SchedulerService API については、その Javadocs で詳細に説明されています。記載されているコントラクトに留意して、正しく使用してください。 ### [](#連動関係によって作成されるスレッド)連動関係によって作成されるスレッド モジュールが外部配信元と連動しなければ自身のスレッドを作成できない場合があります。次に例を示します。 - ブローカーライブラリと連動して自身のコンシューマー Threads を作成する JMS Connector - 自身の I/O セレクター Threads を生成するクライアントライブラリ - 自身の Threads を生成する JDBC ドライバー これらのケースには回避策がないため、ルールの例外だと言えます。ただし、次の条件を満足する**必要があります**。 - 他に実行可能な代替手段がなく、Threads の制御下に留まることだけを目的として自身の JMS ブローカーを作成することがないこと - これらのライブラリによって作成された Threads には意味のある名前を付ける**必要がある** 一部のライブラリでは、Executors のインスタンスを渡して、Threads が提供されていない場合はフォールバックして自身の Threads を作成することができます。このような場合には、使用するメソッドで Executors を渡す**べきです**。詳細は次のカスタム Scheduler のセクションを参照してください。 ## [](#配信元ではポーリングに-scheduler-を使用しない)配信元ではポーリングに Scheduler を使用しない 配信元では、ポーリングの目的で Scheduler を作成しては**なりません**。その代わりに PollingSource クラスを拡張してください。 ## [](#scheduler-ライフサイクルの管理)Scheduler ライフサイクルの管理 Mule のほとんどのコンポーネントと同じように、Scheduler にはライフサイクルがあり、慎重に管理する**必要があります**。 - 正しい Scheduler 種別の選択 Scheduler サービスでは、3 種類の Scheduler を提供しています。 - CPU Light (CPU 負荷小) これらの Scheduler は、CPU をそれほど消費せずに短時間で完了する非同期タスクに使用す**べきです**。非ブロック I/O を実行するタスクにも使用できます。たとえば、単純な検証、簡単な計算、I/O を実行せずに 10 ms 前後で完了するあらゆるロジックなどです。 - CPU Intensive (CPU 負荷大) 大量の CPU リソースを使用するタスク向けです。I/O 操作や長時間のブロック (I/O スレッドが I/O の実行中に保持したロックを待機する場合など) は、ここで実行す**べきです**。たとえば、暗号化、高負荷の返還、リソースを大量に消費する検証、I/O を実行せずに大量の CPU リソースを 20 ms 以上に渡って使用するあらゆるロジックなどです。 - IO Scheduler (I/O スケジューラー) FTP サイトへの書き込みやリレーショナルデータベースへのアクセスといったブロック I/O 操作向けです。 これらの Scheduler に送信するタスクは、各 Scheduler が処理対象とする種別の作業に準拠している**必要があります**。これらの Scheduler は、Mule 4 [実行エンジン](https://docs.mulesoft.com/mule-runtime/latest/execution-engine)が使用するメインスレッドプールのスライスです 。 各 Scheduler のワークプロファイルに準拠しないと、Mule から最適なパフォーマンスを引き出すことはできません。 - カスタム Scheduler 3 つの Scheduler 種別のいずれにも完全には適合しない Scheduler があります。カスタム Scheduler は以下のケースで使用す**べきです**。 - 一定したレートで繰り返し実行されるタスク (PollingSource の一部とす**べきではない**)。例 (一部): - キャッシュ期限タスク - リソースリリースタスク - I/O セレクター - キューコンシューマー - 自身のスレッドプールを必要とするタスク - 上記の条件のいずれとも完全には一致しない混成プロファイルを持つタスク - Scheduler には意味のある名前を付ける SchedulerService で取得するすべての Scheduler には、以下を反映した意味のある名前を付ける**必要があります**。 - Scheduler を作成したモジュールの名前 - Scheduler を作成したコンポーネントの設定オブジェクトの名前またはフロー内での位置 - Scheduler の目的 - 所有コンポーネントの定義 自身の Scheduler を管理する上で重要な側面は、どのコンポーネントが Scheduler を所有す**べきか**を定義することです。 - Scheduler を配信元で使用する場合は、その配信元の一部として Scheduler を定義する**必要があります**。 - Scheduler を接続リリース関連のリソースで使用する場合は、ConnectionProvider が Scheduler を所有す**べきです**。 - Scheduler がどのコンポーネントにも特有ではないタスクを実行したり、多くのコンポーネントが異なるコンポーネントからタスクを受け取ったりする場合には、設定オブジェクトが Scheduler を所有す**べきです**。 所有コンポーネントは、ライフサイクルを意識したものである**必要があります**。つまり、次のいずれかを行う**必要があります**。 - Initialisable および Disposable インターフェースを実装する - Startable および Stoppable インターフェースを実装する - Scheduler を操作レベルでは作成しない Scheduler を操作クラス内で作成しては**なりません**。操作で Scheduler を使用する必要がある場合は、Scheduler を設定要素レベルで作成して、すべての操作で共有する**必要があります**。 - Scheduler はできる限り共有する モジュールは、Scheduler を必要なだけ作成すべきですが、できるだけ少なく抑える**べきです**。別々のコンポーネントがそれぞれ Scheduler を所有したほうが良いユースケースもありますが、できる限りコンポーネント間で Scheduler を共有して再利用する**必要があります**。 - すべての Scheduler が停止することを保証する 作成されたすべての Scheduler が最後に stop() メソッドを呼び出すことを保証する**必要があります**。このメソッドの呼び出しは、Scheduler を所有するコンポーネントのライフサイクルと連携させる**べきです**。たとえば、Scheduler が設定要素によって所有される場合、そのコンポーネントは Stoppable インターフェースを実装して、自身の stop() コールの一環としてこのインターフェースを呼び出す**べきです**。配信元は、onStop() メソッドでこの処理を行う**べきです** (以下同じように続きます)。 ## [](#scheduler-のライフサイクルの例)Scheduler のライフサイクルの例 次の配信元が所有する Scheduler の例は、すべてのライフサイクルの概念を反映しています。 ```java public class ExampleSourceScheduler extends Source { @Inject private SchedulerService schedulerService; @Inject private SchedulerConfig schedulerConfig; private ComponentLocation location; private Scheduler scheduler; @Override public void onStart(SourceCallback sourceCallback) throws MuleException { scheduler = schedulerService.customScheduler(schedulerConfig .withMaxConcurrentTasks(numberOfConsumers) .withName("vm-listener-flow " + location.getRootContainerName()) .withWaitAllowed(true) .withShutdownTimeout(5, SECONDS)); } @Override public void onStop() { if (scheduler != null) { scheduler.stop(); } } } ``` ## [](#関連情報)関連情報 - [MuleSoft ヘルプセンター](https://help.mulesoft.com) - [Mule SDK 開発のベストプラクティス](https://docs.mulesoft.com/mule-sdk/latest/best-practices) # セキュリティ モジュールは、すべての標準的なセキュリティのベストプラクティスに準拠する**必要があります**。 特に、以下について特に考慮す**べきです**。 - XXE 攻撃から保護してください。 - 信用されていない配信元からの情報は常に検疫してください。 - ローカルファイルシステムからファイルを読み取るときは、ホスト環境のシークレットにアクセスしたり、パス走査を有効にしたりしないでください。 - 可能であれば CSRF トークンを使用してください。 - データベースに対してクエリを実行するときは、PreparedStatement クラスを正しく使用して SQL インジェクション攻撃を回避してください。 ## [](#関連情報)関連情報 - [MuleSoft ヘルプセンター](https://help.mulesoft.com) - [Mule SDK 開発のベストプラクティス](https://docs.mulesoft.com/mule-sdk/latest/best-practices) # セキュリティ 作成するコネクタの接続先サービスは、ユーザーの代わりにアプリケーションで通信するために、多くの場合、何らかのセキュリティを適用します。 SDK には、コネクタのユーザーが接続を保護するための方法が 2 つ用意されています。 - [TLS の追加](https://docs.mulesoft.com/jp/mule-sdk/1.1/tls) - [OAuth 認証の追加](https://docs.mulesoft.com/jp/mule-sdk/1.1/oauth) # トランザクションメッセージソース 操作と同様に、メッセージソースではトランザクションがサポートされています。メッセージソースの例としては、JMS や VM Connector リスナーがあります。どちらのリスナーも、キューからメッセージを取得してフローにプッシュします。メッセージ処理が成功すると、トランザクションがコミットされます。失敗すると、トランザクションがロールバックされ、メッセージがキューに戻ります。 操作と同様に、メッセージソースはトランザクションになるように `TransactionalConnection` インターフェースを実装する接続種別で動作する必要があります。接続で `XATransactionalConnection` が実装されている場合、XA トランザクションも自動的にサポートされます。 例: トランザクションメッセージソース ```java public class TransactionalSource extends Source { @Connection private ConnectionProvider connectionProvider; .... } ``` ## [](#メッセージソースのトランザクションアクション)メッセージソースのトランザクションアクション メッセージソースがトランザクションの場合、`transactionalAction` という名前の合成パラメーターが自動的に追加されます。そのパラメーターは、次の値を取ることができる `enum` 型です。 - ALWAYS\_BEGIN: 呼び出しごとに新しいトランザクションが作成されます。 - NONE: ソースがトランザクションを開始せずに、フローで開いているトランザクションに参加しないことを示します。 ## [](#メッセージソースのトランザクション種別)メッセージソースのトランザクション種別 ソースで XA トランザクションがサポートされている場合、`transactionType` パラメーターが追加されます。このパラメーターは、次の値を取ることができます。 - LOCAL: 通常のトランザクションを開始します。 - XA: 代わりに XA トランザクションを開始します。 ## [](#トランザクションの処理)トランザクションの処理 SDK では、トランザクションは接続を介してモデル化されます。そのため、トランザクションごとに異なる接続インスタンスが必要になります。これは、メッセージソースでは並列性がサポートされている必要がありますが、同じ接続で異なる 2 つのトランザクションを同時に提供できないためです。 そのため、SDK ドキュメントの他の場所で使用されている HTTP リスナーサンプルとは異なるモデルが必要になります。そこで、VM Connector の `` を使用する次の簡略化された例を考えてみましょう。 ```java public VMListener extends Source { @Connection private ConnectionProvider sessionProvider; @Override public void onStart(SourceCallback sourceCallback) throws MuleException { while(notStopped()) { QueueSession session = sessionProvider.connect(); (1) CallbackContext ctx = callback.createContext(); (2) TransactionHandle status = ctx.bindConnection(session); (3) try { callback.handle(session.poll(), ctx); (4) } catch (Exception e) { status.rollback(); } } } @OnSuccess public void onSuccess(SourceCallbackContext context) { handleSuccess(context.getConnection()); (5) } @OnError public void onError(SourceCallbackContext context, Error error) { handleError(context, error); } } ``` 1複数の接続が取得されます。2接続ごとに新しいCallbackContext が作成されます。3作成された SourceCallbackContext の bindConnection() メソッドを介して各接続がコンテキストに登録されます。4コンテキストが handle メソッドに渡されます。5接続は後で SourceCallbackContext.getConnection() メソッドを介してすべての onSuccess、onError、onTerminate methods で使用できるようになります。 接続はコンテキストにバインドされているため、Runtime は必要に応じて自動的に接続を終了します。接続がトランザクションで、ソースもトランザクションになるように設定されている場合、`bindConnection()` メソッドをコールすると、その接続で自動的にトランザクションが開始されます。また、接続がトランザクションの場合、Runtime は `onSuccess()` メソッドの後に自動的にトランザクションをコミットしたり、`onError()` メソッドの後にロールバックしたりします。 このケースでは、トランザクションはキューからメッセージをポーリングする前に開始する必要があります。接続の取得直後に bindConnection() をコールすることをお勧めします。 ## [](#カスタムトランザクション処理)カスタムトランザクション処理 コネクタによっては、カスタムトランザクション処理を提供することが必要になる場合があります。たとえば、エラーの場合にエラー応答をパブリッシュしたいとします。この場合、ロールバックされると応答が宛先に到達しなくなるため、トランザクションをコミットする必要があります。 例: カスタムトランザクション処理 ```java @OnError public void onError(SourceCallbackContext context, Error error) { ctx.getConnection().publish(buildErrorResponse(error)); (1) ctx.getTransactionHandle().commit(); (2) } ``` 1onSuccess() および onError() メソッドを実行するとき、接続はまだオープン状態です。2コンテキストには、手動でトランザクションを操作できる TransactionHandle が設定されています。トランザクションを手動で解決する場合、Runtime でそのことが考慮され、後で自動的に解決されなくなります。最も一般的なユースケースでは、この作業を行う必要はありません。 # バイナリストリーミング バイナリストリーミングのユースケースでは、ストリームは、何を表すかに関係なく一般的な方法で処理されるバイトの集まりです。たとえば、HTTP 要求の応答、FTP サーバーでのファイルの取得と書き込みなどがあります。 SDK は、Java `InputStream` クラスを使用してこの抽象化をサポートします。 ## [](#操作でのバイナリストリーミング)操作でのバイナリストリーミング 操作は、ストリームパラメーターを受け取るか、ストリームを返すか、またはその両方を行うことができます。 ファイルコネクタの Write 操作は、ストリームに対して行う操作の例です。 ```java public class FileOperations { public void write(@Content InputStream content, String path) { // do the writing } } ``` `InputStream` 型のパラメーターがある場合、SDK は Mule のストリーミング機能を使用するために必要なすべてのサポートを提供します。上記の例の `content` パラメーターは、常にストリームの先頭を指す反復可能なストリームに割り当てられ、それが true であるかどうかに関係なく、ストリームが初めて読み取られるかのように処理します。 もう一つの可能性は、Read 操作のように、代わりにバイナリストリームを_返す_操作です。 ```java public class FileOperations { public InputStream read(String path) { // do the reading } } ``` `InputStream` を返す場合、SDK はそのストリームを反復可能にするために必要なすべてのマジックを自動的に追加します。 ## [](#ストリーミングの設定)ストリーミングの設定 ``、``、`` などの要素を許可することで、SDK はストリーミングの動作方法を設定するためのサポートを自動的に追加します。上記の Read の例でカスタムファイルストアストリーミングを設定する例を次に示します。 ```xml ``` ## [](#既存のファイルからのストリーミング)既存のファイルからのストリーミング バージョン 1.3 以降で使用できます。 `` 戦略を使用すると、メモリ内のバッファに入り切らない情報が一時的にファイルに格納されます。いくつかのケースでは、この戦略を効率的に使用できず、I/O 要件とディスクスペース要件が最適ではなくなります。 最も一般的なケースは次のとおりです。 シナリオ 1 ファイルの内容を返す操作またはソースを構築する場合です。開発しているコンポーネントは、ファイルを開いて、ファイルの内容を含む InputStream を返します。ファイルのサイズがメモリバッファより大きいと、 はストリームの内容で一時的なファイルの構築を開始します。このファイルは、すでに開いている元のファイルと内容がまったく同じ複製となります。 シナリオ 2 シナリオ 1 のバリエーションとして、操作またはソースが InputStream を取得してから、それを_返す前に_事前処理する必要がある場合です。元のストリームはまだフローにプッシュされていないため、まだ繰り返し可能ではありません。そのためソースは、元のストリームを処理している間は処理済みの内容を一時的なファイルに格納することで、自身でバッファ処理を実装する必要があります。事前処理が完了したら、ソースはファイルの内容をプッシュして、シナリオ 1 に戻ります。 これら 2 つのシナリオから、自身で新しいファイルを作成する繰り返し可能なストリーミングフレームワークを使用するのではなく、同じ内容がすでに元のファイルにあるわけですから、その既存ファイルの内容から繰り返し可能なストリームを取得すべきであることは明白です。 これらのシナリオでは `ImmutableFileRepeatableInputStream` クラスを使用します。このクラスは、標準クラスの `java.io.FileInputStream` と似ていますが、Mule Runtime Engine (Mule) が新しいバッファファイルを作成するのを防止し、既存のファイルを使用するように指示します。 たとえば、このクラスは次のような操作で使用できます。 ```java @MediaType(value = ANY, strict = false) public InputStream read(String path) { File file = new File(path); if (!file.exists()) { // throw ModuleException } return new ImmutableFileRepeatableInputStream(file); } ``` このような性質のファイルを処理する場合には、削除するタイミングを理解することが重要です。ユースケースによっては、自分で作成したコードでファイルを作成する必要になります。単純なケースでは、ストリームを閉じるときにファイルを削除できます。ストリームを閉じるときにファイルを削除する場合は、次の便利なコンストラクターを使用すれば、ストリームを閉じるときに自動的にファイルを削除するように Mule に指示できます。 `new ImmutableFileRepeatableInputStream(file, true);` この機能を使用するには、ファイルが不変である必要があります。つまり、ImmutableFileRepeatableInputStream インスタンスが作成された後は、少なくとも ImmutableFileRepeatableInputStream が閉じるまでは、ファイルの内容を変更することはできません。フローの読み取り中にファイルの内容が変更されてしまうと、不整合やダーティリード、またはその他の競合が発生することがあります。 ## [](#関連情報)関連情報 - [ストリーミング](https://docs.mulesoft.com/jp/mule-sdk/1.1/streaming) - [反復可能ストリーム](#4.1@mule-runtime::streaming-about.adoc#repeatable_streams) # パラメーター パラメーターとは、特定のコンポーネントに属する設定可能な引数です。 [設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)、[コンポーネント](https://docs.mulesoft.com/jp/mule-sdk/1.1/module-structure#components)、そして[接続プロバイダー](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)は、それぞれパラメーターで設定できるため、_パラメーター化可能_であると言います。 パラメーターは、コンポーネントが適切に機能するために必要な情報を提供します。各パラメーターには以下の情報が含まれます。 - パラメーターが持つことのできる値の種類を制限する型。 - パラメーターを一意に識別する名前。 簡単な例を次に示します。 ```java @Parameter private String foo; ``` パラメーターは、対象とするコンポーネントの種類により、クラスの項目またはメソッドの引数として定義できます。 たとえば、[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)パラメーターは、操作を宣言するメソッドの引数と同じように定義します。`@Parameter` アノテーションを付加する必要はありません。 次の `foo` の例を見てください。 ```java public void method(String foo){} ``` ## [](#複雑な型の使用)複雑な型の使用 次の例では、文字列や整数のような単純な型ではない複雑なパラメーターを使用しています。 ```java @Parameter @Optional private Options options; ``` `Options` は POJO オブジェクトで、次のように定義されます。 ```java public class Options { @Parameter public String color; @Parameter @Optional public String mode; public String getColor(){ return color; } public void setColor(String color){ this.color = color; } public String getMode(){ return mode; } public void setMode(String mode){ this.mode = mode; } } ``` この例について、以下の点に注意してください。 - `Options` パラメーター全体が省略可能なパラメーターとして使用されるため、使用する場合は `Options` 内のすべての必須パラメーターが設定されていることを確認する必要があります。 - `Options` を設定しないと、値は `null` になります (この動作を変更する方法については「[NullSafe](https://docs.mulesoft.com/jp/mule-sdk/1.1/null-safe)」を参照してください)。 - `Options` パラメーターは、Java Bean プロパティである必要があります (つまり、項目名と一致する setter と getter が必要です)。 ### [](#複雑な型の-dsl)複雑な型の DSL 複雑な型は、通常のパラメーターから分離する必要があります。複雑な型のすべての属性を要素特有のパラメーターとマージしても意味がありません。 そのため、複雑な型では子定義が作成されます。次の例は、[設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)の複雑な `Options` 型を示しています。 ```xml ``` `module:options` は `name` および `someConfigAttribute` パラメーターから分離されています。 ## [](#修飾子)修飾子 パラメーターは柔軟にカスタマイズできます。このセクションでは、パラメーターを定義する際に使用してパラメーターの動作や制限を指定する、いくつかの修飾子について説明します。 ### [](#式のサポート)式のサポート `ExpressionSupport` は、設定値が DataWeave 式である場合のパラメーターの動作を指定します。 3 つの値があります。 - `REQUIRED`: パラメーターは、式のみを受け入れます。 - `SUPPORTED` (デフォルト): パラメーターは、式と単純な値の両方を受け入れます。 - `NOT_SUPPORTED`: パラメーターは、静的な値を要求します。式は受け入れません。 これらの値は `@Expression` アノテーションを付加するだけで設定できます。 ```java @Parameter @Expression(SUPPORTED) private String foo; ``` 上記の例では、`foo` という名前の `String` 型のパラメーターを定義しており、静的な値 (例: `"bar"`) または式 (例: `"\#[vars.foo]"`) の両方を受け入れます。 ### [](#選択可能)選択可能 パラメーターには必須と省略可能の 2 種類があります。 パラメーターには、実行しようとしている操作にとって非常に重要な情報、つまり、それを設定しなければ処理を続行できないような情報 (HTTP 要求でのホスト名など) を指定するものがあります。一方で、それがなくても処理を実行できる、あるいはデフォルト値 (HTTP リスナーのポート 80 など) が使用されるような情報を指定するパラメーターもあります。 `@Optional` アノテーションを付加しない限り、パラメーターは必須となります。次に例を示します。 ```java @Parameter @Optional(defaultValue="80") private Integer port; ``` 省略可能なパラメーターにはデフォルト値を設定できます。 `@Optional` は `String` 値のみを受け入れますが、SDK はパラメーターの型に合わせて自動的に値を変換します。また、パラメーターが式をサポートしている場合は、デフォルト値として式を使用することもできます。 ### [](#alias-の使用)@Alias の使用 各パラメーターは、定義時に項目で指定された名前を持ちます。この名前は `@Alias` アノテーションで上書きできます。 ```java @Parameter @Optional @Alias("class") private String clazz; ``` `@Alias` を使用することで、Java の予約語 (`class` など) をパラメーター名に使用できます。項目名に予約語を使用することはできません。 ### [](#パラメーター-dsl-のカスタマイズ)パラメーター DSL のカスタマイズ `@ParameterDsl` アノテーションを使用して、DSL でのパラメーターの表示と動作をカスタマイズできます。 このアノテーションは、生成される XML DSL の構文とセマンティクスに関連したディレクティブを設定し、モデル内の任意のパラメーターに適用できます。 `@ParameterDsl` アノテーションには設定可能な要素が 2 つあります。 - `allowInlineDefinition`: 関連付けられているパラメーターが子要素などのインライン定義をサポートするかどうかを指定します。 複雑な型のパラメーターの DSL をカスタマイズする場合、特に、無効な項目 (`name` など) を持つためにインライン定義を回避する必要がある場合や、構造が複雑過ぎてインラインで表現する意味がない場合などに使用します。 たとえば、[設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)で `Options` 型を使用して、`@ParameterDsl(allowInlineDefinition=false)` でパラメーターを宣言した場合は、子要素を定義できなくなります。 ```xml ``` - `allowReferences`: 関連付けられているパラメーターが `String` を受け取る際にレジストリ参照をサポートするかどうかを指定します。 このアノテーションにより、パラメーターの型だけでは参照サポートを自動設定するのに十分な情報を提供できない場合に、設定時のパラメーターの動作を制御できます。 たとえば、JMS Connector で、レジストリからオブジェクトを `ConsumerType` 設定としてユーザーが挿入することを回避させる場合には、参照をサポートしないと宣言します。 ```java @Parameter @Optional @Expression(NOT_SUPPORTED) @ParameterDsl(allowReferences = false) private ConsumerType consumerType; ``` ## [](#groups)パラメーターグループ `@ParameterGroup` アノテーションは、特別なリレーションを共有しているためにまとめた方が便利なパラメーターをグループ化します。 このようなパラメーターは、どのように見極めたらよいでしょうか? 常に**一緒に移動する**パラメーターは、`@ParameterGroup` でグループ化した方がよいでしょう。 また、`@ParameterGroup` を使用することで、グループ内のすべてのパラメーターが同じボックスにまとめられ、グループに属さない他のパラメーターとは別に表示されるため、UI 表示でも便利です。次に例を示します。  上記の画像を見ると、`Connection` グループには 4 つのパラメーターがあり、そのグループには属さないパラメーター (`Soap Version` など) もあります。このように、目的ごとにパラメーターを分けることができます。 このパラメーターグループの簡単な定義例を示します。 ```java public class ConnectionProperties { @Parameter public String host; @Parameter @Optional(defaultValue="80") public Integer port; public String getHost(){ return host; } public void setHost(String host){ this.host = host; } public Integer getPort(){ return port; } public void setPort(Integer port){ this.port = port; } } ``` 上記の例は次のように使用できます。 ```java @ParameterGroup("Connection") private ConnectionProperties properties; ``` `"Connection"` は `@ParameterGroup` の名前であり、UI に表示される名前です。 `@ParameterGroup` プロパティを定義するクラスは、`properties` という名前のパラメーターを持ちません。 代わりに、`ConnectionProperties` の内部で定義されているパラメーターを持ちます。 - `host` という必須パラメーター。 - `port` という省略可能なパラメーター。 つまり、パラメーターグループを定義するクラスは、これらの追加パラメーターによって拡張され、`ConnectionProperties` 内で定義されているパラメーターと、クラスで宣言されている他のすべてのパラメーターを持つことになります。 `@ParameterGroup` アノテーションが付加された各項目は、Java Bean プロパティである必要があります (つまり、項目名と一致する setter と getter が必要です)。 ## [](#pojo-とパラメーターグループの違い)POJO とパラメーターグループの違い `@ParameterGroup` は、それを宣言したコンポーネント内で定義するのではなく、DSL で子要素として記述できるように設定できます。 たとえば、次のような操作を考えてください。 ```java public void execute(@ParameterGroup ConnectionProperties properties) { ... } ``` 上記の操作用の DSL は次のようになります。 ```xml ``` ただし、`@ParameterGroup(showInDsl=true)` を使用してパラメーターグループを設定すると、DSL は次のようになります。 ```xml ``` POJO `@Parameter` を定義しても同じ DSL が得られるため、どのような状況において `@ParameterGroup` アノテーション付きの POJO ではなく POJO を使用すべきなのか迷うかも知れません。 これらの 2 つの概念には微妙な違いがあります。型を全体として捉えて、その型が提供する構造が重要である場合は、必ず POJO を使用してください。 たとえば、`ConnectionProperties` (上記) は、常に一緒に設定される 2 つのパラメーターを一緒に扱っています。この場合、これらのパラメーターはモジュールのドメインでエンティティを表現しません。`@ParameterGroup` は、関連するパラメーターを一緒に扱って UI で一緒に表示するための便利な手段にすぎません。 上記で定義されている `Options` POJO は、オブジェクトのパラメーターだけではなくオブジェクト自身も重要です。たとえば、各オブジェクトはそれ自身で意味があるため (オブジェクト指向プログラミングのように) `Options` のリストを定義することは有効です。一方、モジュールのドメインでは特定の意味を持たず、パラメーターを一緒に表示するためだけにクラスを使用する場合には、パラメーターグループを使用した方がよいでしょう。 ## [](#パラメーターの型の制限)パラメーターの型の制限 `org.mule.runtime.core.api.source.scheduler.Scheduler` 型または `org.mule.runtime.api.scheduler.SchedulingStrategy` 型のパラメーターまたは POJO は追加できません。 # パラメーター DSL のカスタマイズ コンポーネントパラメーターのいくつかの側面をカスタマイズしたり制限したりすることで、ユーザーエクスペリエンスを最大限に高めることができます。たとえば、関係のないパラメーターを隠すことで UI が見やすくなります。 ## [](#参照または値としての文字列の受け取り)参照または値としての文字列の受け取り 次のような操作があるとします。 ```java public void send(@Connection MyConnection connection, Object value) { connection.doSend(value); } ``` これは次のように呼び出します。 ```xml ``` デフォルトでは、Mule は `requestPayload` がグローバルリストや POJO などのレジストリ内のオブジェクトへの参照であると見なします。Extension クラスで実際に `requestPayload` 文字列を受け取りたい場合は、`@ParameterDsl` アノテーションを使用して操作の宣言を変更します。 ```java public void send(@Connection MyConnection connection, @ParameterDsl(allowReferences = false) Object value) { connection.doSend(value); } ``` この変更によって参照の使用が明示的に無効化されるため、操作は文字列値を受け取ります。 ## [](#複雑な型の使い方の定義)複雑な型の使い方の定義 すべてのモジュールは、モジュール API に準拠した POJO を公開できます。 ```java // This is the POJO declaration public class Door { @Parameter private boolean isLocked; @Parameter private String color; } // This is the configuration public class HouseConfig { @Parameter private Door mainDoor; } ``` このようなパラメーターがある場合は、`Door` が DSL でどのように使用されるかをモジュール開発者が設定する必要があります。その目的のために `@TypeDsl` アノテーションが用意されており、これによって 2 つの重要な設定が可能になります。 - `allowInlineDefinition`: POJO (この例では `Door`) をパラメーターとして使用する要素において、その POJO をインラインで宣言できるかどうかを定義します。 `true` であれば、次のように宣言できます。 ```xml (1) (2) ``` 1config はパラメーターのコンテナとして宣言されています。2Door は (config 内で) インラインで定義されています。 - `allowTopLevelDefinition`: POJO (この例では `Door`) をアプリケーションの最上位要素として宣言できるかどうかを定義します。 `true` であれば、次のように宣言できます。 ```xml (1) (2) ``` 1Door はアプリケーションのグローバル要素として宣言されています。2config は別に宣言され、door-ref 属性と共にグローバル要素 Door を名前で参照しています。 # パラメーター UI のカスタマイズ SDK は、UI と UX の多くの側面をカスタマイズするためのアノテーションのセットを提供しています。 ## [](#displayname)@DisplayName UI で使用する要素や項目のカスタム表示ラベルを指定します。 ## [](#example)@Example パラメーターで使用できる値の簡単な例を添えておくと便利な場合があります。 ```java @Parameter @Example("0.0.0.0") private String port; ``` このパラメーターは次のように表示されます。  ## [](#summary)@Summary `@Summary` は、パラメーターの目的の短い説明です。 たとえば、この説明は Design Center でパラメーターにカーソルを置くと表示される説明などに使用できます。 ```java @Parameter @Optional(defaultValue = "SECONDS") @Summary("Time unit to be used in the Connection Timeout") private TimeUnit connectionTimeoutUnit; ``` このパラメーターは次のように表示されます。  ## [](#placement)@Placement このアノテーションは、以下の設定を可能にします。 - グループ内でパラメーターが定義される相対的な順序。値は相対的に扱われ、順序 `10` の要素は順序 `25` の要素より上になります。 - パラメーターを視覚的にグループ化するタブ。この属性は、パラメーターを表示するタブの名前を指定します。デフォルトは「General」で、名前は指定されません。同じタブに複数のパラメーターや項目を表示するには、同じタブの値を指定してください。 次の例では、`foo` と `bar` が `Advanced` という名前の同じタブにグループ化され、`foobar` はデフォルトタブの唯一のパラメーターとなります。 ```java @Parameter @Placement(order = 1, tab="Advanced") private String foo; @Parameter @Placement(order = 2, tab="Advanced") private String bar; @Parameter private String foobar; ``` `foo` パラメーターと `bar` パラメーターは新しい `"Advanced"` タブに次のように表示されます。  ## [](#text)@Text パラメーターが UI で複数行の入力をサポートするように指示します。このアノテーションは DSL にも影響し、アノテーション付きのパラメーターを、テキストを要素のコンテンツとした子要素とします。 このアノテーションは、`String` 型のパラメーターでのみ使用できます。 例 ```java @Parameter @Optional @Text @DisplayName("SQL Query Text") private String sql; ``` Design Center では `@Text` は次のように表示されます。  `@Text` は、パラメーターを含む要素の DSL にも影響します。このアノテーションを使用すると、`CDATA` コンテンツを受け入れる子要素が作成されます。たとえば、次のような操作があるとします。 ```java public void execute(String message) { ... } ``` この操作の DSL は次のようになります。 ```xml ``` 次の例では、`message` 操作に `@Text` アノテーションを付加しています。 ```java public void execute(@Text String message) { ... } ``` 対応する DSL は次のようになります。 ```xml ``` ## [](#path)@Path パラメーターをファイルまたはディレクトリへのパスとしてマークします。このパラメーターは、UI ではファイルピッカー項目として表示されます。 このアノテーションは、`String` 型のパラメーターでのみ使用できます。 このアノテーションは以下の情報を提供します。 - `type`: パスの対象がディレクトリ、ファイル、またはその両方のいずれであるか。 - `acceptsUrls`: @Path パラメーターで URL をサポートするかどうか。 - `acceptedFileExtensions`: パラメーターが処理できる拡張子のリスト。 次の例では、リモートリソースを含む、拡張子が `.txt` のファイルを受け入れます。 ```java @Parameter @Path(type = FILE, acceptedFileExtensions = "txt", acceptsUrls = true) private String resourcePath; ``` ## [](#password)@Password UI から入力されたパラメーター値をマスクするように指示します。 このアノテーションは、`String` 型のパラメーターでのみ使用できます。  Figure 1. UI での例 ## [](#すべての統合)すべての統合 上記のアノテーションを組み合わせた例を示します。 ```java @Parameter @Placement(order = 3, tab="Additional information") @Example("My name is Max the Mule and I love MuleSoft!") @DisplayName("User biography") @Summary("Information related to the user\'s life") @Text private String biography; ``` ## [](#classvalue)@ClassValue **バージョン 1.1 以降で使用可能** パラメーターがクラス名への参照であることを指示します。 このアノテーションは、`String` 型のパラメーターでのみ使用できます。 パラメーターがクラスであることをツールに示すだけでなく、参照可能なクラスの制約も指定できます。割り当てられた値が特定のクラスまたはインターフェースを拡張または実装 (`extendsOrImplements`) する必要があることを示すことができます。 使用する JDBC ドライバーのクラス名をエンドユーザーが指定する必要のあるデータベースコネクタの例を次に示します。 ```java @Parameter @ClassValue(extendsOrImplements = "java.sql.Driver") private String driverClassName; ``` # パラメーターの定義 パラメーターを適切に定義することは、コンポーネントの使い勝手を良くするために重要です。優れた機能を提供するコンポーネントであっても、簡単かつ直感的に設定できなければ、ユーザーはコンポーネントの力を引き出すことができません。 JSON および XML パラメーターの処理 一部の操作は、JSON または XML ドキュメント形式の値を想定したパラメーターを公開しています。 - Java 型 JSON および XML パラメーターは、InputStream の形式で渡される**必要があります**。これらのデータ型を表す通常の Java 型 (Reader、Sax オブジェクト、Document、Node、JsonNode など) は使用できません。 - DataSense による解決 想定されるスキーマに準拠したドキュメントとしてこれらのパラメーターが提供されることを保証するため、ユーザーはツールのサポートを必要とします。したがって、これらのパラメーターでは、想定されるスキーマが明確に定義されている**必要があります**。 - 静的 DataSense スキーマが固定されて既知であることがあります。スキーマが既知で静的である場合は、動的な DataSense リゾルバーで問題を解決しては**なりません**。コネクタは、次のいずれかの方法でスキーマを指定する**必要があります**。 - @InputJsonType アノテーション モジュールのリソースの一部である JSON スキーマを参照することで想定されるデータ型を定義できるようにします。 ```java public void createPerson(@InputJsonType(schema = "person-schema.json") @Content InputStream person) { ... } ``` - @InputXmlType アノテーション @InputJsonType と同様ですが、XML スキーマを参照します。 ```java public void createOrder(@InputXmlType(schema = "order.xsd", qname = "shiporder") @Content InputStream order) { ... } ``` - InputStaticTypeResolver 他の方法として、InputStaticTypeResolver を使用して、型をプログラムで定義することもできます。 ```java public void createOrder(@TypeResolver(OrderTypeResolver.class) @Content InputStream order) { ... } ``` [静的 DataSense の処理に関する詳細](https://docs.mulesoft.com/mule-sdk/latest/static-metadata)。 - 動的 DataSense スキーマが動的である場合は、動的リゾルバーが必要です。これを行うには、InputTypeResolver インターフェースを実装します。 重要なルールは、ユーザーが準拠できる特定のスキーマにモジュールが解決される**必要がある**という点です。動的リゾルバーは、汎用の型である Any を返すことはできません。 ```java public void createOrder(@TypeResolver(DynamicOrderTypeResolver.class) @Content InputStream order) { ... } ``` ## [](#動的-java-型パラメーター)動的 Java 型パラメーター コネクタが動的なデータ型を処理することは非常に一般的です。たとえば、Salesforce、NetSuite、SAP などのサービスでは、ユーザーがカスタマイズできる基本構造を持つコアエンティティ (Person、Order など) のセットを定義します。 他のサービス (OData サービスなど) では、さらに複雑で完全なカスタムデータ型セットを定義できます。 これらの動的データ型を使用するすべてのパラメーターには、現在の設定で使用する実際の型定義を提供する @TypeResolver が関連付けられている**必要があります**。 上のセクションでは、JSON や XML ドキュメントとして渡されるパラメーターでは @TypeResolver が必要だということを説明しました。Map やカスタム POJO などの Java 型として表されるパラメーターにも同じルールが適用されます。どの Java クラスを使用して表現されるかには関係なく、他のすべての動的データ型に対しては、慎重に定義された複雑な TypeResolver が存在する**必要があります**。 ## [](#ストリーミング)ストリーミング ストリーミングは、Mule 4 の主要な側面の 1 つです。ストリーミングを活用できるように操作を定義することが重要です。 - byte\[\] 配列パラメーターは使用しない byte\[\] 型のパラメーターを使用しては**なりません**。代わりに InputStream を使用してください。Mule は、すべての byte\[\] パラメーター値を自動的に InputStream に変換します。 - 大きな文字列パラメーターは使用しない 文字列パラメーターそのものは問題ありませんが、サイズが 4 KB を超えた場合にどのような問題を起きるかを常に考えてください。それを超える可能性がある場合は、パラメーターは文字列ではなく InputStream として定義し、InputTypeResolver を使用して予想されるメディア種別のメタデータを提供する**必要があります**。 ## [](#layout)レイアウト MuleSoft のレイアウトメカニズムは、グループとタブという 2 つの構成概念から成り立っています。 グループやタブは自由に定義できますが、標準的な名前が用意されています。 デフォルトグループ: - General (一般) - Advanced (詳細) - Connection (接続) デフォルトタブ: - Default (デフォルト) - Advanced (詳細) - Security (セキュリティ) - Connection (接続) パラメーターがこれらのカテゴリに適合しない場合は、新しいカテゴリを定義できます。その場合は、その判断について拡張機能の設計仕様に明確に記述する必要があります。 - 必須パラメーター 必須パラメーターは、常にデフォルトのグループとタブに存在する**必要があり**、生成される UI では最初に表示される**必要があります**。 必須パラメーターは、エンドユーザーが一目でわかるようにメインのグループとタブに配置する**必要があります**。 - 省略可能なパラメーター 省略可能なパラメーターはメインビューには配置する**べきではありません**。これは、平均的なユーザーであればほとんどの場合は設定しないようなパラメーターでビューを溢れさせないようにするためです。 例外: - 設定が必須ではなく、省略可能であっても、使用する頻度が非常に高いパラメーターもあります。 - デフォルト値が用意されているために省略可能であっても、コンポーネントの動作にとって重要なパラメーターもあります (例: http:request 操作の method パラメーター)。 - デフォルト値 デフォルト値として式を使用する**べきではありません**。たとえば、イベントにアクセスする式 (`[vars]`、`[attributes]`、`[payload]` など)、動的な値を取得する式 (`[now()]` など)、デフォルトの空の構造を作成する式 (`#[[]]` など) があります。 - @NullSafe Null 値の代わりに空のインスタンスを自動的に提供することで Null 値が回避されるように、Collection 型または Map 型の省略可能なパラメーターには @NullSafe アノテーションを付ける**必要があります**。 - セキュリティパラメーター セキュリティパラメーターについて述べる場合は、実際のセキュリティパラメーターと接続パラメーターを区別することが重要です。たとえば、ユーザー名とパスワードはアクセス制御に使用するため、セキュリティパラメーターとして考えることができます。しかし現実的には、これらを第一に考えなければ接続を確立することは不可能であるため、必須の接続パラメーターであるとも言えます。 - そのため、省略可能なセキュリティパラメーター (tlsContext やハッシュアルゴリズムなど) は、必須としない場合には \[Security (セキュリティ)\] タブに配置する**必要があります**。 - 必須のセキュリティパラメーターは、他の必須パラメーターと同じように \[General (一般)\] タブに配置する**必要があります**。 - パラメーターの順序 前述のように、必須パラメーターは最初に表示する**必要があります**が、ではどの順序で並べる**べき**でしょうか? 省略可能なパラメーターについても同様です。必須パラメーターの後に並べるのは分かっていますが、どの順序で並べればよいのでしょうか? パラメーターの順序に関する考慮事項: - 強力かつ既知の関連性ランキングがある 一部のパラメーターが他と比べて関連性の高いことが分かっているケースがあります。関連性の根拠としては、使用される頻度やコネクタの特定ドメインとの関連性などがあります。たとえば、http:listener の場合は、他に必須パラメーターがあったとしても、path が最も関連性の高いパラメーターとなります。省略可能なパラメーターにも同じことが言えます。たとえば、allowed-methods パラメーターは、キープアライブ設定よりも関連性は高くなります。 このケースで問題となるのは、関連性が主観によって変わってしまう可能性があることです。関連性については人によって意見が分かれることもありますし、操作を呼び出すユーザーが単に間違っていることもあります。これらの場合には、拡張機能の設計ドキュメントで関連性の順序とその理由を明確に記述する**必要があります**。レビュー担当者にも、その順序について異議を唱える機会を与える**必要があります**。 - メタデータキーの順序: このシナリオは操作にのみ適用されます。操作のメタデータキーが階層化されている場合、メタデータキーと一致するパラメーターも同じ順序に並べる**べきです**。 - 使用や関連性のランキングがない - 混在 強力な関連性を持つパラメーターグループまたはサブグループと、そうではないグループ (詳細やセキュリティなど) が混在する場合があります。 関連性が明確ではない場合には、アルファベット順に並べる**べきです**。 - Parameter Types (パラメーターの型) Java ベースのコネクタを扱う場合は、コネクタが外部ライブラリからの型を公開しては**なりません**。 たとえば、MongoDB ライブラリを使用して MongoDB Connector を作成する場合、クエリの結果は BSON オブジェクトとして表されます。この結果は、次の理由から、操作の出力または入力になることはありません。 - コネクタが、コネクタ開発者によって管理されていない実装と結合される。 - 型を DataWeave からコンシュームまたは作成することが困難あるいは不可能である。 - 内部ライブラリがアプリケーションクラスローダーで共有され、クラスの競合が発生する可能性がある。 ## [](#パラメーターのヒント)パラメーターのヒント - @Example 省略可能なパラメーターでデフォルトを指定しない場合は、@Example アノテーションを使用して有効な値の例を提示す**べきです**。これによって設定す**べき**データの種類と構造について確信が持てるようになるため、Mule 開発者の UX が向上します。 これは単純型のパラメーターにのみ適用されます。POJO、リスト、マップは含まれません。 - 表示名 SDK と Studio は、パラメーターの名前を UI に表示されている名前に変換しようと最大限の努力を試みますが、それだけでは不十分な場合があります。コネクタの DSL では意味を持つ名前であっても、UI では意味を持たない場合 (そしてその逆の場合) があります。この場合は @DisplayName 機能を使用する**べきです**。 拡張機能で使用するパラメーター名は DSL (XML) と表示名でも使用されるため、コネクタのリリース後は、下位互換性を維持するため、この名前は変更できません。下位互換性に影響せずに UI に表示される名前を変更するには、@DisplayName アノテーションも使用できます。最後に、Java や Mule DSL とは異なり、@DisplayName では空白スペースも使用できます。 - 式のサポート デフォルトでは、パラメーターで式を使用できます。このデフォルトを変更す**べき**ケースもあります。 設定や接続プロバイダーのパラメーターで式をサポートすることが無意味な場合は、式のサポートを無効にしてください。たとえば、HTTP リスナーを配置するポート番号を指定する場合などです。Mule がメッセージを処理するたびにインバウンドリスナーのポートが変更されてはいけません。 どのユースケースでも固定値を取らないパラメーターでは、式の使用を必須としてください。たとえば、アグリゲーターのグループ ID を指定する場合などです。 - 概要 すべてのパラメーターには、パラメーターの目的とセマンティクスを説明する Javadoc があります。場合によっては説明が非常に長くなることがあります。このような場合には、@Summary アノテーションを使用して 1 行だけの説明を提供するとよいでしょう。概要なので、意味や目的がすべて記述されていなくても問題ありません。これは 1 行だけの短い説明であり、UI ではツールチップとして使用できます。 - 設定の上書き 設定オブジェクトでコネクタにグローバルに影響す**べき**パラメーターを定義する場合があります。ですが、一部のコンポーネントでは、そのパラメーターを上書きする必要がある場合もあります。 文字セットのエンコードが良い例です。File Connector で、設定レベルで使用するエンコードを定義したとします。一方、アプリケーションの特定のフローでのみ (別のフローでは設定されているエンコードを使用するとしても) 異なるエンコードを使用す**べき**場合があります。この場合には、@ConfigOverride アノテーションを使用する**必要があります**。これは (設定されているデフォルトを上書きする部分を手動でチェックする場合と比較して) コードを簡素化できるだけではありません。@ConfigOverride は、自動的に上書きを行えるだけではなく、このパラメーターが設定パラメーターを上書きしていることを Studio やフローの設計者に知らせる役割も果たし、UI を同じように表示させることができます。 [設定の上書きの詳細な説明](https://docs.mulesoft.com/mule-sdk/latest/config-override)。 - ピースを組み合わせる ヒントの相互作用の例を次に示します。 ```java @Parameter @Optional @Summary("The sender 'From' address. If not provided, it defaults to the address specified in the config") @Example("example@company.com") private String fromAddress; ``` ## [](#列挙と値プロバイダー)列挙と値プロバイダー 特定のパラメーターを事前定義済みの値のリストとしてユーザーに表示するユースケースがあります。 このリストは、固定されている場合、つまり選択できる値がすでにコンパイル時に定義されていて変更できない場合があります。たとえば、SFTP プロキシのプロトコルです。可能な値は HTTP、SOCKS4、SOCKS5 のみです。このリストは固定され、いかなる状況においても変更されることはありません。 このような場合は、モジュールで [Java 列挙型](https://docs.mulesoft.com/mule-sdk/latest/value-providers#java_enum)をパラメーターの型として使用する**必要があります**。列挙は、選択可能な値をすべてリストし、SDK は設計時に自動的に適切なリストを生成します。 一方、選択できる値が動的であり、他の条件によって変更される場合があります。 たとえば、Slack Connector では、メッセージを異なるチャネルに送信できます。使用できるチャネルは、ログインしているユーザーによって異なります。そのため、リストは動的です。 カスタム値など、既知ではない (動的な) 値を含めるには、代わりに[値プロバイダー](https://docs.mulesoft.com/mule-sdk/latest/value-providers#value_providers)を使用する**べきです**。 列挙を使用する状況 - 値のセットが既知である場合 - 値のセットが制限されている場合 - 値のセットがコンテキストに連動しない場合 - 値のセットがクローズドである場合 - POJO 内でコンボが必要な場合 (値プロバイダーは POJO 内では使用できません) 値プロバイダーを使用する状況 - 値が既知ではない場合 - 値のセットが接続、設定、または他のパラメーターのコンテキストに連動している場合 - 値のセットがオープンであり、コネクタがいくつかの値を提案できるうえ、他の値も有効である場合 - 値のセットが動的である場合 ## [](#排他的パラメーター)排他的パラメーター パラメーター値が無効である場合も、モジュールは起動時または実行時に失敗す**べきではありません**。たとえば、Scripting Module は、インラインで指定されたスクリプトまたはファイルから参照されたスクリプトを実行します。このモジュールは、2 つのパラメーターを持ちます。1 つはインラインオプションの script、もう 1 つは scriptFile です。ユーザーは一度にどちらか片方のみを使用できるため、両方とも省略可能であるとも言えます。 優れたユーザーエクスペリエンスを実現するため、UI は次の場合にユーザーにヒントを提供するように設計する**べきです**。 - 同時に 2 つのパラメーターが指定された場合 - パラメーターが 1 つも指定されなかった場合 このようなユースケースでは、設計時に優れたエクスペリエンスを保証するように、[排他的で省略可能な](https://docs.mulesoft.com/mule-sdk/latest/exclusive-optionals)機能を活用す**べきです**。 ## [](#pojo-パラメーターの使用)POJO パラメーターの使用 POJO 型のパラメーターの定義が必要になる場合があります。シナリオによって、この方法が推奨される場合と推奨されない場合があります。 - パラメーターのグループ化での POJO の使用 POJO パラメーターを使用するケースの一例は、複数のコンポーネント (操作やソース) に対して同じパラメーターセットを常に繰り返す場合です。Java のグッドプラクティスは、これらのパラメーターを 1 つの再利用可能なクラスにまとめることです。 たとえば、すべてのグループベースのアグリゲーターが共通のパラメーターセットを必要とする Aggregators Module を考えてください。次の例では、GroupBasedAggregatorParameterGroup クラスを作成しています。 ```java public class GroupBasedAggregatorParameterGroup extends TimeoutContainingAggregatorParameterGroup { /** * An expression that determines the aggregation group unique ID. * This ID determines which events *must* be aggregated together. */ @Parameter @Expression(REQUIRED) @Optional(defaultValue = "#[correlationId]") private String groupId; /** * The size of the expected group to aggregate. All messages with * the same correlation ID *must* have the same groupSize. * If not, only the first message groupSize is considered and * a warning is logged. */ @Parameter @Expression(SUPPORTED) @Optional private Integer groupSize; /** * The time to remember a group ID once it was completed or timed out. * 0 means, don't remember, -1 remember forever */ @Parameter @Expression(NOT_SUPPORTED) @Optional(defaultValue = "180") private int evictionTime; /** * The unit for the evictionTime attribute */ @Parameter @Expression(NOT_SUPPORTED) @Optional(defaultValue = "SECONDS") private TimeUnit evictionTimeUnit; } ``` このオブジェクトは次のように使用します。 ```java @Alias("groupBasedAggregator") @Throws(GroupBasedAggregatorErrorProvider.class) public void aggregateByGroup( GroupBasedAggregatorParameterGroup aggregatorParameters, @Alias("incrementalAggregation") @Optional IncrementalAggregationRoute incrementalAggregationRoute, @Alias("aggregationComplete") AggregationCompleteRoute onAggregationCompleteRoute, RouterCompletionCallback completionCallback) throws ModuleException { // impl... } ``` このアプローチにはいくつかの問題があります。 - GroupBasedAggregatoParameterGroup オブジェクトはモジュールの型カタログで複雑な型を定義しますが、この型はモジュールのドメインモデルに対して実際のセマンティックな意味を持ちません。 この型は、モジュールの作成に使用したプログラミング言語のグッドプラクティスに基づいて作成された便宜上の内部型に過ぎません。そのため、この型をカタログに含める意味はありません。 - 型がカタログに記載されているため、モジュールの API の一部となります。 したがって、この型を変更したり、他の型に置き換えたりすると、下位互換性の問題が発生します。 - 複雑なオブジェクトは、Studio や Flow Designer で優れたユーザーエクスペリエンスを実現するのに不向きです。 これらの問題はすべて 1 つの根本原因に起因しています。モジュールの構造は、使用するプログラミング言語の微妙な違いを反映したり、その影響を受けたりする**べきではありません** (ここで XML SDK を使用していればこの問題は発生しなかったことに注意してください)。 生成されるモジュールで副作用を生むことなく POJO でパラメーターをまとめるには、@ParameterGroup アノテーションを使用してください。 ```java public void aggregateByGroup( @ParameterGroup( name = "Aggregator config") GroupBasedAggregatorParameterGroup aggregatorParameters, @Alias("incrementalAggregation") @Optional IncrementalAggregationRoute incrementalAggregationRoute, @Alias("aggregationComplete") AggregationCompleteRoute onAggregationCompleteRoute, RouterCompletionCallback completionCallback) throws ModuleException { // implemented as privileged operation in GroupBasedAggregatorOperationsExecutor } ``` このアノテーションは、メソッドの引数としてインラインで指定されたかのように、POJO を開いて中のパラメーターを公開します。ユーザーや型カタログの観点からは GroupBasedAggregatoParameterGroup は存在せず、単に操作で複数の文字列パラメーターが定義されているようにしか見えません。ただし、それでも開発者は Java POJO を活用する必要があります。 - Mule DSL での子要素の適用 POJO パラメーターの別のユースケースは、Mule DSL で特定のパラメーターを子要素として表示する場合です。たとえば、次の Email Connector の例を見てください。 ```xml Email Content ``` は、content パラメーターと contentType パラメーターを含む POJO です。Email Connector は非常に複雑であるため、Mule DSL では本文を子要素として表示することで読みやすさを改善できます。 この目的で POJO を使用する場合でも、上の例と同じ問題が発生しますが、ここでも @ParameterGroup アノテーションを使用することで解決できます。 ```java @Summary("Sends an email message") @Throws(SendErrorTypeProvider.class) public void send(@Connection SenderConnection connection, @Config SMTPConfiguration configuration, @Placement(order = 1) @ParameterGroup(name = "Settings") EmailSettings settings, @Placement(order = 2) @ParameterGroup(name = "Body", showInDsl = true) EmailBody body, @Placement(order = 3) @ParameterGroup(name = "Attachments") AttachmentsGroup attachments) { ``` 例を見ると分かるように、@ParameterGroup アノテーションには showInDsl 属性があり、内部パラメーターを子要素として表示するように DSL に指示できます。 - グローバル要素の定義 もう 1 つのユースケースは、別のコンポーネントから参照される (設定ではなく) グローバル要素の定義です。 たとえば、File Connector にはマッチャーという概念があります。マッチャーは、ファイルを処理す**べき**か無視すべきかを決定するために使用されるルールのセットです。マッチャーは、 操作で、またはコネクタで定義されている任意のメッセージソースで使用できます。 異なるフローで完全に同じマッチャーが必要になることもあるため、グローバルマッチャーを定義して後で参照するための機能がコネクタに用意されています。次に例を示します。 ```xml ``` これらの場合には、@ParameterGroup アノテーションを使用せずにマッチャーパラメーターを POJO として定義する意味があります。このケースでは、実装の詳細ではなく機能のコアピースであるため、マッチャーの概念をコネクタの型カタログに含めても問題はありません。 ただし、1 つだけ注意すべき点があります。マッチャーを実装するクラスがグローバル要素として使用されるということを宣言する必要があります。 ```java @Alias("matcher") @TypeDsl(allowTopLevelDefinition = true) public class LocalFileMatcher { /** * Files created before this date are rejected. */ @Parameter @Summary("Files created before this date are rejected.") @Optional private LocalDateTime createdSince; /** * Files created after this date are rejected */ @Parameter @Summary("Files created after this date are rejected") @Optional private LocalDateTime createdUntil; ... } ``` - DSL の意思決定 まとめとして、POJO とパラメーターグループの使用方法を決定するプロセスを支援するシンプル名フローチャートを示します。  - `equals` メソッドと `hashCode` メソッドの実装 [動的設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/static-dynamic-configs#Dynamic-Configuration-Lifecycle)が正しく機能するためには、POJO パラメーターまたはパラメーターグループで使用する Java クラスで `equals` メソッドと `hashCode` メソッドを実装する必要があります。 既存の設定で POJO パラメーターが使用されていない場合でも、将来のランタイム機能がこれらのメソッドに依存する可能性があるため、設定には `equals` メソッドと `hashCode` メソッドが必要です。次の Database Connector のクラスの例には、`equals` メソッドと `hashcode` メソッドが実装される様子が示されています。 ```java /** * Pooling configuration for JDBC Data Sources capable of pooling connections * * @since 1.0 */ @Alias("pooling-profile") public class DbPoolingProfile implements DatabasePoolingProfile { /** * Maximum number of connections a pool maintains at any given time */ @Parameter @Optional(defaultValue = "5") @Placement(order = 1) @Expression(NOT_SUPPORTED) private int maxPoolSize = 5; /** * Minimum number of connections a pool maintains at any given time */ @Parameter @Optional(defaultValue = "0") @Placement(order = 2) @Expression(NOT_SUPPORTED) private int minPoolSize = 0; /** * Determines how many connections at a time to try to acquire when the pool is exhausted */ @Parameter @Optional(defaultValue = "1") @Placement(order = 3) @Expression(NOT_SUPPORTED) private int acquireIncrement = 1; /** * Determines how many statements are cached per pooled connection. Setting this to zero will disable statement caching */ @Parameter @Optional(defaultValue = "5") @Placement(order = 4) @Expression(NOT_SUPPORTED) private int preparedStatementCacheSize = 5; /** * The amount of time a client trying to obtain a connection waits for it to be acquired when the pool is * exhausted. Zero (default) means wait indefinitely */ @Parameter @Optional(defaultValue = "0") @Placement(order = 5) @Expression(NOT_SUPPORTED) private int maxWait = 0; /** * A {@link TimeUnit} which qualifies the {@link #maxWait}. */ @Parameter @Optional(defaultValue = "SECONDS") @Placement(order = 6) @Expression(NOT_SUPPORTED) private TimeUnit maxWaitUnit; /** * Determines how many seconds a Connection can remain pooled but unused before being discarded. * Zero means idle connections never expire. */ @Parameter @Optional(defaultValue = "0") @Placement(order = 7) @Expression(NOT_SUPPORTED) private int maxIdleTime; @Parameter @Optional @Placement(tab = ADVANCED_TAB, order = 8) @Expression(NOT_SUPPORTED) @Summary("Additional properties used to configure pooling profile.") private Map additionalProperties = emptyMap(); //getters... @Override public int hashCode() { return Objects.hash(minPoolSize, maxPoolSize, acquireIncrement, preparedStatementCacheSize, maxWaitUnit, maxWait); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof DbPoolingProfile)) { return false; } DbPoolingProfile that = (DbPoolingProfile) obj; return maxPoolSize == that.maxPoolSize && minPoolSize == that.minPoolSize && acquireIncrement == that.acquireIncrement && preparedStatementCacheSize == that.preparedStatementCacheSize && maxWait == that.maxWait && maxWaitUnit == that.maxWaitUnit; } } ``` ## [](#パラメーターの型の制限)パラメーターの型の制限 `org.mule.runtime.core.api.source.scheduler.Scheduler` 型または `org.mule.runtime.api.scheduler.SchedulingStrategy` 型のパラメーターまたは POJO は追加できません。Mule Runtime Engine と SDK は、ポーリングソースなどにこれらの型のパラメーターを追加します。 ## [](#関連情報)関連情報 - [MuleSoft ヘルプセンター](https://help.mulesoft.com) - [Mule SDK 開発のベストプラクティス](https://docs.mulesoft.com/mule-sdk/latest/best-practices) # フロー出力の取得とメッセージソースからの応答の送信 ソースの主要なプロパティの 1 つは、応答が生成されるかどうかを示します。 応答を生成しないソースの例: - ファイルリスナー - Salesforce ストリーミング API - Scheduler 要素 - 非同期プッシュ通知をリスンするソース 応答を生成するソース: - TCP サーバー - HTTP サーバー - JMS サーバー このように、この分類はあまり確定的ではありません。次に例を示します。 - HTTP サーバーでは応答の送信がサポートされているが、ユーザーが送信しないように選択できる。 - JMS リスナーがメッセージを応答キューに送信して応答するかどうかは、メッセージヘッダーによって異なる。 ソースが応答を送信できて、メッセージが正常に処理されても、ソースが応答を送信しない場合があります。応答の送信プロセスがスキップされる可能性のあるロジックまたは設定状況があります。 ソースが応答を生成できることを指定するには、`@EmitsResponse` アノテーションを付加する必要があります。 これにより、ソースにそれを行う機能があることが Runtime やツールに通知されます。 ただし、SDK も Runtime も次の作業を行わない点に注意してください。 - 応答を生成するソースが実際に応答を生成するかどうかを検証する。 - ソースが応答を生成することを宣言していなくても、ソースが応答を送信しないようにする。 ## [](#コールバックパラメーター)コールバックパラメーター ソースで生成されたメッセージの処理がフローで完了するたびに、フローで生成された応答をソースで取得することが必要になる場合があります。これは、_コールバックメソッド_を介して行われます。 コールバックメソッドは、ソースを所有するフローで生成された応答を利用するために使用されます。これを行うには、`@OnSuccess`、`@OnError`、`@OnTerminate` アノテーションを付加してメソッドを宣言します。これらのメソッドは操作と同じように宣言されます。ただし、これらのメソッドは応答をリスンしますが、応答を変更することはできないため void にする必要があります。 これらのコールバックメソッドの各パラメーターは、操作と同じように評価されます (自動変換を含む)。ただし、これらのコールバックはメッセージを処理する Runtime に応じて実行されるため、コールバックは式を受け入れることができます (デフォルト)。 ソースが応答を生成しない場合でも、リソースの解放、ログ、監査などでコールバックメソッドが必要になることがあります。 ## [](#正常出力のリスン)正常出力のリスン ソースでは `@OnSuccess` アノテーションが付加されたメソッドを宣言できます。こうすることで、フローでメッセージが正常に処理された (エラーがスローされなかったか、すべて適切に処理された) 場合にメソッドが実行されます。 このメソッドには、ソースパラメーターとして処理される引数を設定できます。コネクタのユーザーは、通常のパラメーターとコールバックパラメーターを区別できません (区別する必要がありません)。この用途では、どちらでも問題ありません。ツール (Studio や Flow Designer) により、式を受け入れるパラメーターと受け入れないパラメーターがユーザーに通知されます。ユーザーは、他に何も心配する必要はありません。 別の重要な考慮事項は、ソースがメッセージをフローにプッシュした後のメッセージ処理が非同期であるということです。そのため、`@OnSuccess` メソッドも非同期で呼び出されます。 簡略化された HTTP Connector の例を次に示します。 ```java @EmitsResponse (1) public class HttpListener extends Source { @Override public void onStart(SourceCallback sourceCallback) throws MuleException { httpServer = serverProvider.connect(); httpServer.listen(path).onRequest(request -> { SourceCallbackContext ctx = sourceCallback.createContext(); (2) ctx.setVariable("responseContext", new HttpResponseContext(request.getResponseSender())); (3) Result result = requestToResult(request); sourceCallback.handle(result, ctx); (4) }); } @OnSuccess public void onSuccess(@Content String responseBody, @Optional String responseStatusCode, SourceCallbackContext callbackContext) (5) throws Exception { if (hasResponse(responseStatusCode)) { (6) HttpResponseContext responseContext = callbackContext.getVariable("responseContext"); (7) responseContext.sendResponse(responseBody, statusCode); (8) } } } ``` 1この例では、この HttpListener が応答を送信する可能性があるため、@EmitsResponse アノテーションをソースに付加します。2@OnSuccess メソッドは非同期 (多くの場合は並列) で呼び出されるため、状態をコールバックメソッドに伝える必要があります。より正確に言えば、応答する実際の要求に関連する何らかの参照を提供する必要があります。それを行うために、この例では SourceCallback を使用して新しい SourceCallbackContext を作成しています。3この例では、HttpResponseContext を保持するコンテキストに変数を追加します。これは、応答の送信方法を認識しているコネクタで定義されたカスタムオブジェクトです。4この例では、Result オブジェクトと新しく作成されたコンテキストを使用して、SourceCallback でメッセージを生成およびプッシュします。5コールバックメソッドには、2 つのパラメーター (送信される応答の本文に対応する @Content と応答の HTTP 状況コードに対応する @Optional) があります。SourceCallbackContext 型の 3 番目の引数もあります。これはパラメーターではありませんが、handle() メソッドに渡された同じコンテキストを復元するように SDK に指示する手段です。6HTTP プロトコルでは応答が送信されない場合もあるため、この例では、応答の状況コードで応答を送信することが要求されているのかどうかをチェックします。7応答が必要な場合、この例では最初にコンテキストに設定された応答コンテキストを復元します。8応答が送信されます。 ## [](#エラー出力のリスン)エラー出力のリスン `@OnSuccess` と同様に、`@OnError` はフローで未処理のエラーがスローされたときに実行されます。次に例を示します。 ```java @OnError public void onError(@Optional @DisplayName(ERROR_RESPONSE_SETTINGS) @NullSafe HttpListenerErrorResponseBuilder errorResponseBuilder, SourceCallbackContext callbackContext, Error error) { } ``` このケースのメソッドは、成功の例と非常に似ています。また、パラメーターとコールバックコンテキストを受け取って、エラー応答をリクエスターに送り返します。さらに、エラーオブジェクトを受け取ることもできます。これは、取得した失敗に関する情報が含まれる Mule エラーオブジェクトです。 Error オブジェクトは、Java java.lang.Error オブジェクトではなく、SDK org.mule.runtime.api.message.Error です。 ## [](#コンテンツパラメーター)コンテンツパラメーター コールバックは、操作と同様にコンテンツパラメーターを受け入れます。HTTP Connector の場合、`HttpListenerResponseBuilder` でこれらが使用されます。これにより、DataWeave を使用して、フローの結果をコネクタで返す形式に変換できます。コンテンツやプライマリコンテンツのすべての概念は、関連する制限にも適用されます。 ## [](#onterminate)OnTerminate ソースで `@OnSuccess` または `@OnError` メソッドを提供する必要はありません。ソースでは、必要なメソッドを宣言できますが、まったく宣言しないこともできます。ただし、これらの 1 つ以上が定義されている場合、`@OnTerminate` メソッドも定義する必要があります。 `@OnSuccess` または `@OnError` は失敗する可能性があるため、このメソッドが必要になります。これらのいずれかで例外がスローされると、応答を待機してリモートシステムがハングしたり、リソースが漏洩したり、監査ログが不完全なままになったりします。 `onTerminate` メソッドの例を次に示します。 ```java public void onTerminate(SourceResult sourceResult) { Boolean sendingResponse = (Boolean) sourceResult.getSourceCallbackContext().getVariable(RESPONSE_SEND_ATTEMPT).orElse(false); if (FALSE.equals(sendingResponse)) { sourceResult .getInvocationError() .ifPresent(error -> sendErrorResponse(new HttpListenerErrorResponseBuilder(), sourceResult.getSourceCallbackContext(), error, null)); } } ``` メソッドは、`onSuccess` または `onError` メソッドで発生した可能性のある省略可能なエラーと、関連する `SourceCallbackContext` が含まれる `SourceResult` オブジェクトを受け取ります。 上記の例では、メソッドはエラーが見つかった場合に汎用エラー応答を送信します。 ## [](#次のステップ)次のステップ - [メッセージソースからの非同期応答の送信](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-async-response) # ポーリング入力元 **バージョン 1.1 以降で使用可能** ポーリング入力元は、外部アクションによってトリガーされるのではなく、指定された `scheduling strategy` に従って定期的に項目をポーリングして、羃等性とウォーターマークを自動的に処理します。毎回のポーリングアクションでは、多くの項目を、それぞれを単一のメッセージとしてフローにディスパッチできます。 ## [](#ポーリング入力元の作成)ポーリング入力元の作成 ポーリング入力元を作成するには、通常の入力元と同じように、Extension クラスで `Source` クラスを `@Sources` アノテーションに付加します。クラス `Source` を拡張するのではなく、入力元をポーリング入力元として動作させるためには、クラスを `PollingSource` から拡張する必要があります。 `PollingSource` から拡張する場合は、`poll` メソッドと `onRejectedItem` メソッドを実装する必要があります。 - `poll` はディスパッチするアイテムを取得し、`accept` メソッドを使用してそれらのアイテムを `pollContext` で渡します。 - ディスパッチした項目のいずれかが (ウォーターマーク、羃等性、あるいはサーバーの過負荷の問題などによって) 拒否された場合は、`onRejectedItem` がコールされます。このメソッドは、`PollItem` の結果セットに関連付けられているすべてのリソースを解放します。 FTP Connector のディレクトリリスナー実装でこれらのメソッドを宣言した例を示します。 ```java public class FtpDirectoryListener extends PollingSource { // ... @Override public void poll(PollContext pollContext) { // ... } @Override public void onRejectedItem(Result result, SourceCallbackContext callbackContext) { // ... } // ... } ``` ## [](#poll-メソッドの実装)poll メソッドの実装 このメソッドは、ディスパッチする項目をすべて収集して、1 つずつ処理します。 `PollContext` からの `accept` メソッドは、ポーリングされた項目をフローにディスパッチします。このメソッドは、`Consumer` をパラメーターとして受け取ります。 次の例では、フローにディスパッチするメッセージを設定しています。 ```java public class FtpDirectoryListener extends PollingSource { // ... @Override public void poll(PollContext pollContext) { if(pollContext.isSourceStopping()){ (1) return; } List attributesList = listFilesAttributes(); for (FtpFileAttributes attributes : attributesList) { if(pollContext.isSourceStopping()){ (1) break; } pollContext.accept(item -> { (2) Result result = read(attributes.getPath()); item.setResult(result); (3) }); } } // ... } ``` 1pollContext は、入力元が停止中であるかどうかの情報を提供します。これは、時間を要するタスクの前には必ず考慮しなければなりません。2accept はフローに項目をディスパッチします。3setResult は、ディスパッチしたメッセージを設定します。 ### [](#羃等性)羃等性 羃等性により、項目が 2 回ポーリングされることを防止できます。SDK は、他のスレッドやクラスターノードが同じ ID の項目を処理していないことを保証することで、処理の羃等性を実現します。同じ ID を持つ 2 つの項目が同時に処理されることはありません。処理中の項目と同じ ID を持つ項目をノードがポーリングすると、その項目は削除され、`onRejectedItem` メソッドがコールされます。 ```java public class FtpDirectoryListener extends PollingSource { // ... @Override public void poll(PollContext pollContext) { if(pollContext.isSourceStopping()){ return; } List attributesList = listFilesAttributes(); for (FtpFileAttributes attributes : attributesList) { if(pollContext.isSourceStopping()){ break; } pollContext.accept(item -> { Result result = read(attributes.getPath()); item.setResult(result); item.setId(attributes.getPath()); (1) }); } } // ... } ``` 1setId は、羃等性に使用する ID を設定します。 ### [](#ウォーターマーク)ウォーターマーク コールのたびに新しいデータを古いデータから手動で分割することなく、新しいデータのみを入手したい場合には、データの増分入力元をポーリングする際にウォーターマークを使用します。 項目のウォーターマークに増分値を設定することで、新しい項目のウォーターマーク値が現在のウォーターマーク値よりも小さい場合は、ほかのすべてのポーリングでその項目が削除されて `onRejectedItem` がコールされます。上記の例では、ファイルのタイムスタンプをウォーターマーク値として使用しています。 SDK はどの条件でウォーターマークを比較するのでしょうか? 使用するウォーターマークが `Comparable` を実装するのであれば、値の自然順序が使用されます。この場合は、条件を設定する必要はありません。 ```java public class FtpDirectoryListener extends PollingSource { // ... @Parameter @Optional(defaultValue = "false") private boolean watermarkEnabled = false; (1) // ... @Override public void poll(PollContext pollContext) { if(pollContext.isSourceStopping()){ return; } List attributesList = listFilesAttributes(); for (FtpFileAttributes attributes : attributesList) { if(pollContext.isSourceStopping()){ break; } pollContext.accept(item -> { Result result = read(attributes.getPath()); item.setResult(result); item.setId(attributes.getPath()); if (watermarkEnabled) { (1) item.setWatermark(attributes.getTimestamp()); (2) } }); } } // ... } ``` 1通常は、ウォーターマークを使用するかどうかをユーザーに決めさせるのがベストプラクティスです。2setWatermark は、ファイルのタイムスタンプをウォーターマークとして設定します。 ウォーターマーク値が `Comparable` を実装しない場合や、自然順序以外の条件を使用する場合はどうしたらよいでしょうか? この場合は、`setWatermarkComparator` メソッドをコールして、`Comparator` を `PollContext` に設定します。 ポーリングが完了する前にウォーターマークの更新が設定されていない場合、ラッチを追加すれば、2 回の反復でウォーターマークが更新されることがありません。 ### [](#pollitemstatus)PollItemStatus `accept` メソッドをコールすると `PollItemStatus` が返されます。これは、列挙値であり、以下の値を取ることができます。 - ACCEPTED: 項目が受け入れられ、実行用にスケジュールされました。 - FILTERED\_BY\_WATERMARK: ウォーターマークが有効化されており、それによって除外されたため、項目が拒否されました。 - ALREADY\_IN\_PROCESS: 羃等性が有効化されており、別のスレッドまたはノードですでに同じ項目が処理されているため、項目が拒否されました。 - SOURCE\_STOPPING: 入力元が停止信号を受信したため、項目が拒否されました。 これを使用して、ポーリングで返された各項目の状況をログに記録できます。 ```java public class FtpDirectoryListener extends PollingSource { // ... @Parameter @Optional(defaultValue = "false") private boolean watermarkEnabled = false; // ... @Override public void poll(PollContext pollContext) { if(pollContext.isSourceStopping()){ return; } List attributesList = listFilesAttributes(); for (FtpFileAttributes attributes : attributesList) { if(pollContext.isSourceStopping()){ break; } PollItemStatus status = pollContext.accept(item -> { (1) Result result = read(attributes.getPath()); item.setResult(result); item.setId(attributes.getPath()); if (watermarkEnabled) { item.setWatermark(attributes.getTimestamp()); } }); if(!status.equals(PollItemStatus.ACCEPTED)){ LOGGER.debug("Item rejected with code: " + status.name()); } } } // ... } ``` 1ログに記録されている PollItemStatus を後で取得します。 ### [](#入力元のコールバックコンテキストの取得)入力元のコールバックコンテキストの取得 コールバックメソッドで使用するデータを保存する必要がある場合は、`item` によって `SourceCallbackContext` を取得できます。 次の例では、コンテキストを取得してそのデータを保存しています。 ```java public class FtpDirectoryListener extends PollingSource { // ... @Parameter @Optional(defaultValue = "false") private boolean watermarkEnabled = false; // ... @Override public void poll(PollContext pollContext) { if(pollContext.isSourceStopping()){ return; } List attributesList = listFilesAttributes(); for (FtpFileAttributes attributes : attributesList) { if(pollContext.isSourceStopping()){ break; } PollItemStatus status = pollContext.accept(item -> { SourceCallbackContext context = item.getSourceCallbackContext(); (1) context.addVariable("attributes", attributes); (2) Result result = read(attributes.getPath()); item.setResult(result); item.setId(attributes.getPath()); if (watermarkEnabled) { item.setWatermark(attributes.getTimestamp()); } }); if(!status.equals(PollItemStatus.ACCEPTED)){ LOGGER.debug("Item rejected with code: " + status.name()); } } } // ... } ``` 1item からコンテキストを取得します。2データを SourceCallbackContextに保存します。 ## [](#onrejecteditem-メソッドの実装)OnRejectedItem メソッドの実装 このメソッドは、ディスパッチされた項目のいずれかが拒否されるとコールされます。このメソッドは、`PollItem` の結果セットに関連付けられているすべてのリソースを解放します。 次の例は、このメソッドの実装方法を示しています。 ```java public class FtpDirectoryListener extends PollingSource { // ... @Override public void onRejectedItem(Result result, SourceCallbackContext callbackContext) { closeFileStream(result); } // ... } ``` ## [](#フローでのポーリング入力元の使用方法)フローでのポーリング入力元の使用方法 SDK は、`scheduling strategy` パラメーターを自動的に入力元に追加し、ポーリングの実行を処理する戦略 (`fixed-frequency` など) をユーザーが指定できるようにします。Runtime は、指定された戦略に従って `poll` メソッドの実行を自動的にスケジュールします。 ポーリング入力元を使用する FTP ディレクトリリスナーの例を示します。 ```xml ``` # メタデータキーパラメーター 動的メタデータ構造を記述するには、どの型を表現するのかを知る必要があります。この型の参照を定義するには、記述する型 (Account など) の ID を含む `@MetadataKeyId` パラメーターを操作で指定します。この ID は、そのパラメーターで定義されているメタデータリゾルバーに渡されます。 たとえば、汎用レコードをリモートシステムに保存する操作があるとして、サポートされる型として `Account` や `Organization` を記述しておけば、デザインしやすくなります。この場合は、操作のパラメーターの 1 つに ID として `Account` または `Organization` を含む型の参照を定義します。 このパラメーターは、バケットに保存するレコードの Account 構造または Organization 構造 (エンドユーザーが使うと決めた方) を記述します。 ## [](#メタデータキーのリストの提供)メタデータキーのリストの提供 動的メタデータを解決する最も一般的なケースでは、解決される可能性のある各型を特定するキーの動的セットを用意します。エンドユーザーが設計時にコネクタを設定する際には、操作を選択してから、動的に入力されるキーをセットから選択すると、そのキーがメタデータ解決の `MetadataKeyId` になります。 動的キーの解決を実装するには、まず `TypeKeysResolver` を宣言します。 ```java public class RecordKeysResolver implements TypeKeysResolver { @Override public String getCategoryName() { return "Records"; } @Override public Set getKeys(MetadataContext context) throws MetadataResolvingException, ConnectionException { // First we need to obtain the key IDs that will be used. // This is where you'd normally use `context.getConfig()` // or `context.getConnection()` to obtain the entity id's // from a remote service, for this demo the keys will be fixed List keyIds = Arrays.asList("Author_id", "BookList_id", "Book_id"); HashSet keys = new HashSet<>(); for (String id: keyIds){ // For each possible if, we create a new MetadataKey with that ID MetadataKeyBuilder builder = MetadataKeyBuilder.newKey(id); // Then, we add a DisplayName to that MetadataKey, // this will be the name shown in the UI builder.withDisplayName(StringUtils.removeEnd(id, "_id")); //finally, add the key to the Set of known MetadataKeys keys.add(builder.build()); } return keys; } } ``` 上の例では、MetadataKey の動的セットを作成するのに必要なすべての要素が定義されています。実装するメソッドは `getKeys` で、利用可能なすべてのキーをユーザーに出力します。 `Author_id` などの `id` 要素は内部で使用され、表現したい構造に対してすべてのリゾルバーにおいて一意である必要があります。`displayName` は、ユーザーに表示するキーの名前であるため、わかりやすく読みやすい名前にしてください。 リゾルバーを定義したら、クラス定義レベルでその `keysResolver` 値を使用して `@MetadataScope` アノテーションを追加し、キーであるパラメーターに `@MetadataKeyId` アノテーションを付けることで、リゾルバーを操作またはソースとして使用できます。すべてのメタデータリゾルバーは、操作またはソースの同じカテゴリに属している必要があります。 ```java @MetadataScope(keysResolver = RecordKeysResolver.class) public class OperationWithMetadataKey { public void create(@MetadataKeyId String type, @Config MyConfig config){ //... } } ``` ```java @MetadataScope(keysResolver = RecordKeysResolver.class) public class DocsMetadataSource extends Source, Void> { @MetadataKeyId @Parameter public String type; //... } ``` 前の例は、ソースのメタデータキーをサポートする唯一の方法です。ソースを定義するときに、@MetadataKeyId アノテーションでリゾルバーを設定しないでください。 操作クラス定義レベルで `@MetadataScope` アノテーションを設定すると、そのすべての操作でメタデータが提供され、スコープからリゾルバーを継承するため、すべての操作に `@MetadataKeyId` アノテーションが付いたパラメーターが必要であることを示します。 1 つの操作に対してキーリゾルバーを設定することもできます。 ```java public class MyOperations { public void operationWithMetadataKey(@MetadataKeyId(RecordKeysResolver.class) String type, @Config MyConfig config){ //... } public void plainOperation(@Config MyConfig config){ //... } } ``` さらに、操作クラス定義レベルで `@MetadataScope` アノテーションがある場合は、パラメーターに `@MetadataKeyId` アノテーションの値を設定し、1 つの操作に対してスコープレベルで定義されたリゾルバーを上書きできます。 ```java @MetadataScope(keysResolver = ClassLevelResolver.class) public class MyOperations { public void operation(@MetadataKeyId String type, @Config MyConfig config){ // This operation will use the ClassLevelResolver } public void operationWithAnotherResolver(@MetadataKeyId(OverridingResolver.class) String type, @Config MyConfig config){ // This operation will use the OverridingResolver } } ``` 前の 2 つの例 (パラメーターレベルでのリゾルバーの設定、およびスコープから継承されたリゾルバーの上書き) は、操作を定義するときにのみ動作します。これらの機能はソースでは使用できません。 ## [](#ユーザー定義の-metadatakey)ユーザー定義の MetadataKey ユーザー定義の `MetadataKey` は、エンドユーザーが自由に提供できるキーであり、潜在的な要素のリストでは定義されません。 たとえば、クエリでは非常によくあるケースですが、エンドユーザーが実行したいクエリ全体を `MetadataKey` として使用します。 ユーザー定義の `MetadataKey` を宣言するには、パラメーターアノテーション、またはクラス定義で存在する場合は `@MetadataScope` アノテーションに対して `TypesKeyResolver` を指定せずに、パラメーターに `@MetadataKeyId` アノテーションを付けます。 ```java public class MyOperations { public void query(@MetadataKeyId String query){ //... } } ``` ## [](#省略可能な-metadatakey-パラメーター)省略可能な MetadataKey パラメーター バージョン 1.3 以降で使用できます。 `MetadataKey` パラメーターは、他のパラメーターと同じように `@Optional` アノテーションを付けて省略可能にすることができます。 ```java public void query(@MetadataKeyId @Optional String query){ //... } ``` 省略可能な MetadataKey パラメーターに値が割り当てられていない場合は、`null` を `MetadataKey` 値としてメタデータコールが行われます。そのため、この `MetadataKey` パラメーターに関連付けられているすべての `MetadataResolver` パラメーターは、Null 値を受け取ることができるようにしておく必要があります。 # メッセージソースからの非同期応答の送信 ソースは、非同期で応答を送信できます。非同期ソースの主なユースケースは次のとおりです。 - 応答操作が非ブロックである。 - 応答操作はブロックだが、それを開始したスレッドとは別のスレッド (通常、`OnSuccess` または `OnError` アノテーションが付加されたメソッドを実行するスレッド) で非同期で実行される。 - ソースは、個別のスレッドで応答ストリームをコンシュームする必要のある非同期監査を実行する。 このようなケースでは、次のようになります。 - Runtime は応答が非同期であることを認識する必要がある。認識していない場合、応答を生成するスレッドと、応答を取得するメッセージに関連付けられているリソースを解放しようとする Runtime 間で競合状況が発生します。 - `OnSuccess` または `OnError` アノテーションが付加されたメソッドに `SourceCompletionCallback` 型の引数が含まれている必要がある。これにより、ソースが非同期であることが Runtime に通知されます。 Runtime は、`success()` または `error(Throwable)` メソッドが呼び出されるまで関連付けられているイベントを完了しません。これは非常に強いコントラクトです。ソースが適切に Runtime に通知せずに `SourceCompletionCallback` を要求すると、最終的に Runtime 全体がフリーズする可能性があります。 例を挙げます。 ```java @OnSuccess public void onSuccess(@Content String response, SourceCompletionCallback callback) { asyncResponder.sendResponse(response, new ResponderCallback() { void onSuccess() { callback.success(); } void onFailure(Throwable t) { callback.error(t); } };) } ``` ## [](#次のステップ)次のステップ [トランザクションメッセージソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-transactions) # メッセージソースからフローへのメッセージのプッシュ フローの情報を生成したら、ソースは `SourceCallback` を使用してフローにその情報を送信します。最小限の HTTP リスナーの例に戻ります。 ```java public class HttpListener extends Source { @Override public void onStart(SourceCallback sourceCallback) throws MuleException { httpServer = serverProvider.connect(); (1) server.listen(path).onRequest(request -> { (2) Result result = requestToResult(request); (3) sourceCallback.handle(result); (4) }); } } ``` 1この例では、ConnectionProvider を使用して HttpServer を取得します。一般的な接続プロバイダーの場合、適切なホストとポートを使用してすでにサーバーが設定されています。2リモートクライアントが HTTP 要求をサーバーにプッシュし、HttpServer コンポーネントが各要求のソースを通知します。次に、ソースが SourceCallback を使用してメッセージをフローにプッシュします。3メッセージは、操作が複雑な出力を伝えるために使用する同じ Result オブジェクトを利用して表されます。詳細は、Result オブジェクトについての説明を参照してください。4この例では、SourceCallback の handle(Result) メソッドを使用してメッセージを渡します。 ## [](#スレッドモデル)スレッドモデル `handle(Result)` メソッドを介して `Result` オブジェクトが `SourceCallback` に渡されると、メソッドを呼び出すスレッドとは異なるスレッドでメッセージ処理が非同期で実行されます。 次のステップでは、フロー処理の結果をキャッチし、必要に応じて応答を送信する方法について説明します。 ## [](#次のステップ)次のステップ - [フロー出力の取得とメッセージソースからの応答の送信](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-response) # メッセージソースでの設定および接続の取得 ## [](#設定オブジェクトの取得)設定オブジェクトの取得 操作と同様に、ソースはその動作に関するパラメーターを取得するために設定を参照できます。そのような設定を取得するには、項目に `@Config` アノテーション (操作引数で使用されるアノテーションと同じ) を付加する必要があります。 ```java public class HttpListener extends Source { @Config private HttpListenerConfig config; } ``` ## [](#接続の取得)接続の取得 ソースで接続が必要な場合 (スケジューラーを実装していなければ 99% のコネクタで必要)、接続を取得する必要があります。操作と同様に、`@Connection` アノテーションが使用されますが、主に次の 2 つの点が異なります。 - メソッド引数ではなく項目で使用される。 - 接続オブジェクトではなく `ConnectionProvider` が挿入される。 ```java public class HttpListener extends Source { @Config private HttpListenerConfig config; @Connection private ConnectionProvider serverProvider; @Parameter @Optional(defaultValue = "/") private String path; private HttpServer httpServer; @Override public void onStart(SourceCallback sourceCallback) throws MuleException { httpServer = serverProvider.connect(); (1) httpServer.listen(path).onRequest(request -> { (2) processRequest(request, sourceCallback); (3) }); } @Override public void onStop() { if (httpServer != null) { (4) serverProvider.disconnect(httpServer); (5) } } } ``` 1この例では、ConnectionProvider を使用して HttpServer を取得しています。一般的な接続プロバイダーの場合、適切なホストとポートを使用してすでにサーバーが設定されています。2リモートクライアントが HTTP 要求をサーバーにプッシュし、HttpServer コンポーネントが各要求のソースを通知します。次に、ソースが SourceCallback を使用してメッセージをフローにプッシュします。3ソースは processRequest メソッドを定義して、HTTP 要求を、フローにプッシュできるメッセージに変換する必要があります。その方法については、このドキュメントで後述しますが、例を単純化するために、これが機能すると想定できます。4onStop() メソッドは、リソース (このケースでは HttpServer) を解放します。サーバーが作成される前に onStart() メソッドが失敗した場合に備えて null をチェックします。5この例では、ConnectionProvider の disconnect() メソッドを使用してサーバーを解放します。 上記の例は疑似コードです。例が明確かつ簡潔になるように、実際の HTTP Connector を大幅に簡略化しています。 ## [](#次のステップ)次のステップ - [メッセージソースからフローへのメッセージのプッシュ](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-push-message) # メッセージソースのパラメーターの定義 パラメーターは、`Source` クラスの項目として定義されます。操作を定義するときにすべての機能とアノテーション (`@NullSafe`、`@ParameterGroup`、`@TypeResolver` など) を使用できます。次に例を示します。 ```java @EmitsResponse public class HttpListener extends Source { @Config private HttpListenerConfig config; @Parameter @Optional(defaultValue = "/") private String path; @Parameter private Integer port; /** * Comma separated list of allowed HTTP methods by this listener. */ @Parameter @Optional @Placement(tab = Placement.ADVANCED_TAB) @Summary("Comma separated list of methods. Leave empty to allow all.") @Example("GET, POST") private String allowedMethods; } ``` これは設定の定義方法と似ていますが、これらのどのパラメーターでも式を受け入れないという点が異なります。式のサポートが必要な `@Expression` アノテーションを使用するとエラーになります。 ## [](#次のステップ)次のステップ - [メッセージソースのライフサイクル](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-lifecycle) # メッセージソースのライフサイクル ライフサイクルが所有フローに関連付けられている場合、操作とは異なり、ソースは Runtime Manager で個別に開始または停止できます。 これをサポートするために、`Source` クラスでは、`onStart()` および `onStop()` メソッドを実装する必要があります。 ## [](#onstart)onStart VM Connector の次の例は、`onStart()` メソッドを示しています。 ```java @Override public void onStart(SourceCallback sourceCallback) throws MuleException { } ``` このメソッドでは、メッセージを生成できるように必要なすべてのリソース (スレッド、スケジューラー、接続など) を初期化する必要があります。これを実行しようとしているときに例外またはエラー状況が見つかった場合、次の作業を行う必要があります。 - 割り当てなかったリソースを解放する。 - わかりやすいメッセージと共に例外をスローする。 ソースを開始できない場合、そのソースが含まれるアプリケーションは開始できません。 この時点で @Parameter アノテーションで定義されているすべてのソースパラメーター値が解決されて使用できるようになります。 ### [](#sourcecallback)SourceCallback メソッドは SourceCallback オブジェクトを受信します。`SourceCallback` は、ソースの機能のほぼすべての側面に関わるため、ソースの最も重要な部分と言えます。`SourceCallback` の用途や役割についての詳細は、このドキュメントを読み進めていくなかで確認できますが、簡単に言うと `SourceCallback` は Runtime と通信するためにソースで使用されるものです。この用途を次に示します。 - メッセージをフローにプッシュする。 - 接続の問題を伝えて、再接続をトリガーする。 - ソースのプッシュフェーズ間の状態を応答処理部分に渡す。 `SourceCallback` はこのように重要な役割を担っているため、指定されたインスタンスが常に使用できることが非常に重要です。ソースの複雑さやコードの編成によっては、メソッド引数として保持するだけでこれを実現できる場合があります。より複雑なソースでは、インスタンス項目でその参照を保持することが必要になる可能性もあります。これを行う場合、`onStop()` メソッドの実行時に参照がクリアされていることを確認する必要があります。 ## [](#onstop)onStop このメソッドは、ソースによるメッセージの生成を停止するために Runtime によって呼び出されます。**このメソッドは失敗しないようにする必要があります**。停止プロセス中に見つかった例外は、ソースによって記録され、適切に処理される必要がありますが、このメソッドの呼び出した後、ソースは次の作業を行う (次の状態になっている) 必要があります。 - メッセージの生成を停止する。 - 割り当てられたリソースを解放する。 - 再起動できる状態になっている。 ## [](#次のステップ)次のステップ - [メッセージソースでの設定および接続の取得](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-config-connection) # モジュールのテスト テストにより、コードの一部が正しく動作することが確認できます。モジュールをテストすることは、単にビジネスロジックに応じてテストケースを作成するだけにとどまりません。モジュールと Mule 間でインタラクションのテストを何度も実行し、Mule エコシステムとの互換性を確保する必要があります。 モジュールのテスト方法についての詳細は、以下の一連の記事を参照してください。これらの記事では、モジュールをテストするためのステップごとの手順が紹介されています。また、モジュールのテストケースの基本と、モジュールからの簡単な操作の実行方法についても説明されています。 - [最初のテストケースの作成](https://docs.mulesoft.com/jp/mule-sdk/1.1/testing-writing-your-first-test-case) ([FlowRunner](https://docs.mulesoft.com/jp/mule-sdk/1.1/testing-writing-your-first-test-case#testing-flowrunner) を使用) # モジュールのライセンス SDK で作成されたモジュールは、3 種類のライセンスのいずれかを持ち、ライセンスによってアプリケーションの実行要件が異なります。 ## [](#community-module)Community Module すべてのモジュールのデフォルトであり、Community Module を使用するアプリケーションは、すべての Mule Runtime で特に要件なしで実行できます。 ## [](#enterprise-module)Enterprise Module Enterprise Module を使用しているアプリケーションは、Mule EE Runtimes でしか実行できないため、モジュールのユーザーは MuleSoft Enterprise ライセンスが必要です。モジュールを EE 専用として宣言するのは非常に簡単です。単に `@RequiresEnterpriseLicense` アノテーションを付加するだけです。 ```java @Extension(name = "enterprise") @RequiresEnterpriseLicense public class EnterpriseConnector { } ``` デフォルトでは、`RequiresEnterpriseLicense` はユーザーに完全な MuleSoft Enterprise ライセンスを求めますが、Runtime の評価ライセンスでも実行できるように宣言することもできます。これは、`RequiresEnterpriseLicense` アノテーションで `allowEvaluationLicense` フラグを使用して設定します。 ```java @Extension(name = "enterprise") @RequiresEnterpriseLicense(allowEvaluationLicense = true) public class EnterpriseConnector { } ``` ## [](#カスタムモジュールライセンス)カスタムモジュールライセンス MuleSoft Certified Connector は、専用のカスタムライセンスを作成するための_認定ライセンス生成キー_を MuleSoft に要求できます。これにより、Certified Connector を使用するユーザーは、モジュールを開発したパートナーからカスタムライセンスを入手できます。 MuleSoft Certified Connector を構築したパートナーは、顧客がコネクタを使用して Mule アプリケーションを構築し、デザイン時にテストできる機会を提供できます。顧客がコネクタを使用して Mule アプリケーションをデプロイしようとすると、パートナーのカスタムライセンスが求められます。 ### [](#コネクタ用のライセンス生成キーの取得)コネクタ用のライセンス生成キーの取得 開発したコネクタの認定を MuleSoft に申請する前に、Certified Connector パートナー候補は次の手順を実行する必要があります。 1. MuleSoft がパートナー用のキーとキーストアを生成するために必要な以下の情報を用意します。 - 会社名 (ベンダー名) - 連絡先メール - 連絡メッセージ - Connector Name (コネクタ名) 2. MuleSoft にキーとキーストアを要求します。 1. 公開 `.key` は、コネクタに保存してあるファイルです。 2. ライセンスを生成するパートナーとしての自分用の `.jks` キーストア。 ## [](#コネクタコードの調整と公開キーの保存)コネクタコードの調整と公開キーの保存 キーとキーストアを取得したら、次の操作を実行します。 1. パートナーは、要求されたすべての属性に `@RequiresEntitlement` アノテーションを適用して値を入力することで、コネクタのプロジェクトコードを調整します。 - `name` はコネクタ名でなければなりません。 - `vendor` 属性は、`.key` サフィックスの前の部分でなければなりません。たとえば、MuleSoft が `prov-name.key` というベンダーキーを生成した場合、パートナーは `prov-name` をベンダーとして入力します。 ```java @Extension(name="connector-name", vendor="prov-name") @RequiresEntitlement(name="connector-name") public class LicensedConnector { ... } ``` - MuleSoft が提供した `.key` ファイルをコネクタのプロジェクトディレクトリの `src/main/resources` または `src/main/resources/license` 内に置きます。 ### [](#サンプルパートナーコネクタ)サンプルパートナーコネクタ サンプルコネクタをダウンロードして Studio にインポートすることで、ライセンス管理アノテーションがコネクタコードでどのように設定されるかを確認できます。顧客の `.key` ライセンスファイルは `src/main/resources` に格納されている必要があります。 ## [](#ライセンスファイルの生成)ライセンスファイルの生成 MuleSoft のパートナーは、`.jks` ファイルとライセンス生成プラグインを使用して、コネクタの顧客に送信するライセンスを生成します。 コマンドラインから、`.jks` ファイルが格納されているディレクトリで、`vendor.keystore` に自分の `.jks` ファイルへのパスを指定して、次のコマンドを実行します。 mvn org.mule.tools.devkit:mule-devkit-license:license -Dvendor.keystore=betaprovider-license-demo.jks 必要に応じて、上のコマンドに -Ddays.to.expire=<days-until-this-license-expires> を付加することで、ライセンスの有効期限を指定することもできます。顧客の名前をライセンスに追加するには、-Dclient=<client-name> を追加します。 ライセンスが正常に作成されると、出力は次のように表示されます。 \[INFO\] Scanning for projects... \[NOTE\] \[INFO\] ------------------------------------------------------------------------ \[INFO\] Building Maven Stub Project (No POM) 1 \[INFO\] ------------------------------------------------------------------------ \[NOTE\] \[INFO\] --- mule-devkit-license:license (default-cli) @ standalone-pom --- \* Enter the name of the client whom will receive this license: Bob \* Enter the name of the provider of the Entitlement as it appears in the @RequiresEntitlement annotation: betaprovider \* Enter the name of the Entitlement as it appears in the @RequiresEntitlement annotation: lic-demo \* Enter the name of the Connector as it appears in the @Connector "name" attribute: license-demo \* Enter keystore password: \[INFO\] ------------------------------------------------------------------------ \[INFO\] BUILD SUCCESS \[INFO\] ------------------------------------------------------------------------ \[INFO\] Total time: 18.151s \[INFO\] Finished at: Thu Dec 10 09:34:41 ART 2015 \[INFO\] Final Memory: 6M/287M \[NOTE\] ## [](#ライセンス付きコネクタを含む-mule-アプリケーションの開発)ライセンス付きコネクタを含む Mule アプリケーションの開発 コネクタライセンスが正常に機能しているかどうかを確認するには、ライセンス (`.lic` ファイル) が Mule アプリケーションや Mule サーバーからアクセスできる必要があります。 ### [](#mule-アプリケーション内のライセンスファイル)Mule アプリケーション内のライセンスファイル コネクタのライセンスを購入した顧客は、パートナーまたはベンダーから提供された `.lic` ファイルを以下のディレクトリに格納できます。 - (Studio で開発した) アプリケーションの `src/main/resources`。 - アプリケーションがすでに展開されてサーバーにデプロイされている場合は `app/classes`。 ### [](#mule-サーバー内のライセンスファイル)Mule サーバー内のライセンスファイル ライセンスをアプリケーションに格納する代わりに、Mule サーバーの `conf/` フォルダーに格納することができます。 複数のアプリケーションで同じライセンスが必要な場合は、Mule サーバーにライセンスを保存することをお勧めします。 # モジュールモデルの学習 Mule モジュールの構築は、`@Extension` アノテーション付きのクラスから開始します。このクラスは、すべてのモジュール機能と、機能に関連するすべての要素をエクスポートするために使用します。 このクラスは、公開された非抽象クラスである必要があります。@Extension アノテーションは、インターフェース、抽象クラス、公開/保護クラス、または型付きクラス (汎用型) では使用できません。 ```java @Extension(name = "basic") public class BasicModule { } ``` `@Extension` アノテーションを使用する場合は、モジュールにわかりやすく簡潔な名前を付ける必要があります。モジュール名に、`extension`、`module`、または `connector` は使用できません。これらの文字列を含めても、SDK によって削除されます。必要に応じて、属性 `vendor` と属性 `category` を指定できます ([「ライセンス」](https://docs.mulesoft.com/jp/mule-sdk/1.1/license)を参照)。 空のモジュールを作成したら、モジュールに要素を追加できます。  Figure 1. 基本のモジュール構造 概要レベルでは以下の要素があります。 - [コンポーネント](#コンポーネント) - [操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations) - [ソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources) - [関数](https://docs.mulesoft.com/jp/mule-sdk/1.1/functions) - [ルーター](https://docs.mulesoft.com/jp/mule-sdk/1.1/routers) - [スコープ](https://docs.mulesoft.com/jp/mule-sdk/1.1/scopes) - [接続プロバイダー](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections) - [設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs) - [パラメーター](https://docs.mulesoft.com/jp/mule-sdk/1.1/parameters) ## [](#コンポーネント)コンポーネント コンポーネントは、モジュール機能の鍵となります。モジュールは、与えられたパラメーターセットに基づいて実行され、フローでメッセージを生成または変更します。 モジュールの最も一般的なコンポーネントはソースと操作です。 - [操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)は、受信したメッセージを処理して結果を生成するコンポーネントです。 - [ソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)は、Mule Runtime が処理するメッセージを受信するか、新しいメッセージを生成するコンポーネントです。 ## [](#設定)設定 設定は、モジュールの動作に影響する設定可能なパラメーターのセットです。 通常、[ソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)と[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)は、動作を決定する設定のパラメーターに依存します。ただし、一部は設定なしでも機能します。 モジュールの設定を宣言するための要件はなく、いくつでも必要なだけ宣言できます。設定が異なればパラメーターセットも異なり、その設定を使用した場合にしか使用できない[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)や [ソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)を指定する場合もあります。 ## [](#接続プロバイダー)接続プロバイダー [接続プロバイダー](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)は、[設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)から作成される接続の処理を担当する Module 要素です。ロジックとパラメーター化処理を一元管理して、特定種別の接続のプロビジョニングおよびリリースを行います。 [設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)、[ソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)、および[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)と同じように、接続プロバイダーを実行するためには、通常は接続に依存します。接続は必須ではありませんが、普通は使用されます。[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)と[ソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)で使用する接続は、[接続プロバイダー](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)が提供します。 [接続プロバイダー](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)は[設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)にバインドされています。[設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)には、[接続プロバイダー](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)が 1 つも定義されないか、1 つだけ定義されるか、あるいは異なる種別の接続を作成する複数の接続プロバイダーが定義される場合があります。たとえば、HTTPS 接続と (非セキュア) HTTP 接続用に別々の `ConnectionProvider` が定義されます。 ## [](#パラメーター)パラメーター `Parameters` は、モジュールモデルの最も細かい要素であり、[操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)、[ソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)、[設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)、および[接続プロバイダー](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)のすべての要素で使用されます。 パラメーターは、実行する要素の値を受け入れる設定可能な要素を表すか、または設定された値を保持します。 ## [](#他の要素)他の要素 モジュールには、その他にも [ルーター](https://docs.mulesoft.com/jp/mule-sdk/1.1/routers)、[スコープ](https://docs.mulesoft.com/jp/mule-sdk/1.1/scopes)、[関数](https://docs.mulesoft.com/jp/mule-sdk/1.1/functions)、[エラー](https://docs.mulesoft.com/jp/mule-sdk/1.1/errors)などの要素があります。ここで説明した要素は、ほとんどのモジュールで使用する可能性があるコア要素です。 # モジュール接続フレームワーク 接続モジュール (コネクタ) は、最も一般的なモジュールです。Mule フローと外部リソース間の接続を提供します。 接続フレームワークの `ConnectionProvider` でこれらの接続を設定して、Mule Runtime Engine が処理する接続を作成、切断、および説明します。 接続を使用する方法についての詳細は、[接続の使用](#use-connections)を参照してください。 ## [](#接続プロバイダーの宣言)接続プロバイダーの宣言 新しい `ConnectionProvider` を宣言するには、`ConnectionProvider` インターフェースを実装する新しいクラスを作成する必要があります。`ConnectionProvider` インターフェースは、`ConnectionProvider` が処理するインスタンスのクラスを示す 1 つの型引数を受け取る型付けされたインターフェースです。 この例は、`ConnectionProvider` インターフェースを実装する `MyConnectionProvider` クラスを宣言します。 ```java public class MyConnectionProvider implements ConnectionProvider { @Parameter private String password; public MyConnection connect() throws ConnectionException { return new MyConnection(password); } public void disconnect(MyConnection connection) { connection.invalidate(); } public ConnectionValidationResult validate(MyConnection connection) { return connection.isValid() ? ConnectionValidationResult.success() : ConnectionValidationResult.failure("Connection is not valid", new InvalidConnectionException()); } } ``` 定義された各 ConnectionProvider は、インスタンス化可能で公開されており、デフォルトのコンストラクターがある必要があります。 接続へのアクセスを必要とする他のコンポーネント (操作やソースなど) は、`MyConnection` クラスのインスタンスを介して接続へのアクセスを取得します。 上記の例には、`@Parameter` とメソッド `connect()`、`disconnect()`、および `validate()` が含まれます。次のセクションでそれぞれについて説明します。 ### [](#接続プロバイダーパラメーター)接続プロバイダーパラメーター その他の `Module` 要素と同様に、`ConnectionProvider` には `@Parameters` を使用できます。 各 `ConnectionProvider` の `@Parameters` は、`connect()` メソッドで、実際の接続をインスタンス化するために必要な設定可能な要素である必要があります。 複数の操作で必要な一般的な @Parameters は、ConnectionProvider には含まれていない必要があります。それは設定 @Parameter で一般的なケースです。「@Parameter セクション」を参照してください。 ### [](#_connections_connect)Connect `connect()` メソッドは、設定されたすべてのパラメーターを使用して実際の接続をインスタンス化します。返される接続はすぐに使用可能であると期待されることを知ることが**非常に重要**です。 返される**接続**は、インターフェースやコントラクトを実装する必要はありません。ソケット接続を参照するとは限りません。単なるクライアントやそれと同様の何かである可能性があります。 ### [](#disconnect)Disconnect `disconnect(Connection)` メソッドは、ライブ接続を受信して破棄し、割り当てられたすべてのリソースを解放します。 ### [](#validate)Validate [上記](#_connections_connect)のように、`ConnectionProvider` の `connect()` メソッドは有効で完全に機能する接続を返す**必要があります**。接続はアイドル状態中に古くなる可能性があるため、`ConnectionProvider` には `validate(Connection)` メソッドが用意されています。このメソッドは、使用する前に接続を確認するために呼び出されます。 検証に失敗した場合、接続は無効になり、新しい接続が取得されます。 #### [](#接続検証結果)接続検証結果 `validate(Connection)` メソッドは、`ConnectionValidationResult` 型のオブジェクトを返します。これは `ConnectionValidationResult.success()` と `ConnectionValidationResult.failure()` の 2 つの型のいずれかになります。 `failure()` が返されると、説明メッセージと失敗 `Exception` (接続が無効な理由を提供) が新しい `failure()` に提供されます。必要に応じて、[エラー処理](https://docs.mulesoft.com/jp/mule-sdk/1.1/errors)機能を追加するために `ErrorType` を指定できます。 - `failure(String, Exception)` - `failure(String, ErrorType, Exception)` ## [](#接続プロバイダーの追加)接続プロバイダーの追加 各 `ConnectionProvider` は、0、1 つ、または複数の `ConnectionProvider` を持つことができる接続にバインドされます。 `ConnectionProvider` の実装をモジュール設定に追加するには、`@ConnectionProviders` アノテーションを使用する必要があります。このアノテーションは、`Module` が定義する各 `ConnectionProvider` を宣言します。`@Extension` または `@Configuration` レベルで使用できます。 拡張に複数の `ConnectionProvider` が含まれる場合、`@Alias` を使用してそれぞれに意味のある名前を付ける必要があります。慣例により、その接続プロバイダーの名前については、指定された名前に `` `-connection `` サフィックスが追加されます。 `@Extension` レベルで宣言された `ConnectionProvider` の例: ```java @Extension(name="xyz") @Operations(Operations.class) @ConnectionProviders(MyConnectionProvider.class) public class MyModule { @Parameter private String someParameter; public String getSomeParameter() { return someParameter; } } ``` サンプル `MyConnectionProvider` を使用したこの設定の XML の例: ```xml ``` ## [](#接続管理)接続管理 `ConnectionProvider` のいくつかの接続管理戦略を 指定できます。 ### [](#プーリング戦略)プーリング戦略 接続はプールされます。接続のキャッシュは維持されるため、将来の要求で必要になったときに再利用できます。 これは、接続の作成にコストがかかる場合や、接続インスタンスへの同時アクセスがサポートされていない場合に役立ちます。 このプーリング戦略では、プーリングプロファイル設定が自動的に接続に追加されます。次の表に、**\[Use default connection pool configuration (デフォルトの接続プール設定を使用)\]** 種別のプーリングプロファイルのデフォルト値を示します。 名前 デフォルト値 Max Active (最大アクティブ) 5 Max Idle (最大アイドル) 5 Max Wait (最大待機) 5 Exhausted Action (枯渇アクション) GROW Initialisation Policy (初期化ポリシー) INITIALIZE_ONE Min Eviction Millis (最小除去時間) 1800000 Eviction Check Interval Millis (除去確認間隔) -1 プーリング接続管理を有効にするには、`PoolingConnectionProvider` インターフェースを実装します。 詳細は、[「Pooling Profiles (プーリングプロファイル)」](https://docs.mulesoft.com/mule-runtime/latest/tuning-pooling-profiles)を参照してください。 ### [](#キャッシュ戦略)キャッシュ戦略 設定インスタンスごとに、1 つの特定の設定が常に同じ接続を取得するように、接続が確立されてキャッシュされます。設定自体が停止されるまで、接続は維持されます。 キャッシュ接続管理を有効にするには、`CachedConnectionProvider` インターフェースを実装します。 詳細は、[「Caching (キャッシュ)」](https://docs.mulesoft.com/mule-runtime/latest/tuning-caching)を参照してください。 ### [](#戦略なし)戦略なし ランタイムでは、プーリングの場合のような追加インフラストラクチャは追加されません。 `ConnectionProvider` が接続処理動作の全体を提供します。接続が必要な操作は、接続が必要になるたびに `connect()` メソッドをコールし、操作が完了したら接続を破棄します。 `ConnectionProvider` インターフェースを実装することは、戦略がないことを意味します。 ## [](#use-connections)接続の使用 操作とソースでの接続の使用は大きく異なります。次を参照してください。 - [操作での接続の使用](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations#_using_connections) - [ソースでの接続の使用](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources-config-connection) # 他のモジュールからの型のインポート すべてのモジュールは、モジュールの API の一部である型のセットを宣言できます。この型のセットは、元のモジュールの名前空間の定義を維持したままで、他のモジュールにインポートできます。 他のモジュールからの型のインポートは、多くの場合で役に立ちます。一例を挙げます。 - 特定の認証方法など、型内にバンドルされたロジックを再利用する。 - 同じプロパティの設定用に同じ API をユーザーに公開する。たとえば、同じパラメーターを同じ順序で、同じ記述で設定する場合は、異なるモジュールで同じ型を使用することで実現できます。 モジュールの型は 3 ステップで再利用できます。 1. `pom.xml` 内の連動関係を、API を使用する `mule-plugin` に追加します。 ```xml org.mule.connectors mule-sockets-connector (1) ${muleSocketsConnectorVersion} mule-plugin (2) ``` 1型が宣言されているモジュール2mule-plugin 分類子を忘れずに連動関係に追加すること 2. インポートする型を参照している Extension クラスで `@Import` を宣言します。 ```java @Extension(name = "HTTP") @Import(type = TcpClientSocketProperties.class) @Import(type = TcpServerSocketProperties.class) public class HttpConnector { } ``` 3. パラメーター宣言で型を使用します。 ```java @Alias("request") public class HttpRequesterProvider implements CachedConnectionProvider { @Parameter private TcpClientSocketProperties clientSocketProperties; } ``` これによって DSL 宣言がどのように変わるかに注意してください。拡張 (この例では `http`) が別の名前空間 (この例では `sockets`) で宣言されたパラメーターを受け取ることができるようになりました。 ```xml ``` # 値プロバイダー コネクタを開発する場合、エンドユーザーが値セットからパラメーターを選択できるようにすることができます。これにより、ユーザーは何を設定するかを容易に知ることができ、開発者は設定される値が正しいことに確信が持てます。 [Java 列挙](#java_enum)をパラメーターとして使用して、この機能を既知の値に対して提供できます。SDK が列挙からすべての値を自動的に取得するため、値を UI のコンボセレクターとして提供できます。 カスタム値など、既知ではない値を含めるには、代わりに[値プロバイダー](#value_providers)を使用する必要があります。 パラメーターの動的データ型を検出する[メタデータ](https://docs.mulesoft.com/jp/mule-sdk/1.1/metadata)とは異なり、この機能はパラメーターで指定できる値を提供するように設計されています。 ## [](#java_enum)Java 列挙 次のロールを使用してコンテンツをパブリッシュできるコンテンツパブリッシュサービス用のコネクタを開発しているとします。 - `ADMIN` - `READER` - `WRITER` これらのロールを提供するには、次のように、`UserRole` 列挙を作成して `publishAs` 操作のパラメーターとして公開します。 例: 既知のロールを定義する Java 列挙 ```java public enum UserRole { ADMIN, READER, WRITER } ``` 次の例の操作メソッドでは、ユーザーは特定の `UserRole` を使用してコンテンツをパブリッシュできます。 ```java public void publishAs(@Content Object content, UserRole roleEnum){ System.out.println("Publishing " + content + " with Role: " + roleEnum); } ``` このソリューションは容易であり効果的ですが、いくつかの制限事項と問題があります。 - カスタム値をサポートしない。パラメーターが列挙に基づくため、カスタム値を定義できません。たとえば、カスタムロールを使用して接続先のサービスを設定できる場合、コネクタの機能が制限されるため、`UserRole` 列挙を引き続き使用することはできません。 - 値が静的に定義される。接続や設定に応じて値を変更することはできません。 - Java 列挙の命名に制限がある。列挙値を数字または特殊文字で始めることはできません。 カスタムロールが必要で、既知のユーザーロールのドロップダウンリストも使用する必要がある場合は、[値プロバイダー](#value_providers)を使用して、動的値と既知の値に対応できます。 ## [](#value_providers)値プロバイダー 値プロバイダーは、コネクタのあらゆるコンポーネント ([操作](https://docs.mulesoft.com/jp/mule-sdk/1.1/operations)、[ソース](https://docs.mulesoft.com/jp/mule-sdk/1.1/sources)、[設定](https://docs.mulesoft.com/jp/mule-sdk/1.1/configs)、[接続プロバイダー](https://docs.mulesoft.com/jp/mule-sdk/1.1/connections)、スコープなど) 内のあらゆるパラメーターに値を動的かつスマートな方法で提供するためのメカニズムです。 ### [](#StaticUserRoleValueProvider)値プロバイダーを実装する方法 次の例では、上記の列挙ソリューションと同じ動作が生成されますが、値の開集合のメリットがあります。これはカスタム値をサポートします。 1. `ValueProvider` を実装する Java クラスを作成します。 このインターフェースを実装する場合、[値](#value-structure)のセットを返す `resolve()` メソッドを実装する必要があります。 ```java public class StaticUserRoleValueProvider implements ValueProvider { @Override public Set resolve() { return ValueBuilder.getValuesFor("ADMIN", "READER", "WRITER"); } } ``` 2. 動的値を必要とするパラメーターを `@OfValues()` アノテーションでマークします。 `@OfValues` には、パラメーターにバインドされる `ValueProvider` 実装が必要です。 たとえば、次の操作メソッド `publishAs` にはこのようなバインディングが含まれています。 ```java public void publishAs(@Content Object content, @OfValues(StaticUserRoleValueProvider.class) String userRole){ (1) System.out.println("Publishing " + content + " with Role: " + userRole); } ``` 3. これを Studio または Design Center で使用して、値の取得を開始できるようになりました。  ### [](#接続または設定を使用した値プロバイダー)接続または設定を使用した値プロバイダー 値プロバイダーは接続および設定を受け取ることができます。これにより、現在の接続および設定に基づいて値を解決できます。 接続および設定パラメーターに配置されている値プロバイダーに接続および設定を挿入することはできません。 #### [](#接続または設定の受け取り)接続または設定の受け取り `@Connection` および `@Config` アノテーションを使用して、値プロバイダー内での接続および設定の使用を宣言します。これらのアノテーションを使用する値プロバイダーが正常に機能するには、設定または接続が_有効である_ことが必要です。SDK では、接続と設定が有効でない限り、解決ロジックは実行されません。 ```java public class ConnectedValueProvider implements ValueProvider { @Connection ServiceConnection connection; @Config ServiceConfig config; @Override public Set resolve() throws ValueResolvingException { //Do whatever is required with the connection or config List result = connection.retrieveInfo(); return ValueBuilder.getValuesFor(result); } } ``` 挿入する接続と設定の型は、値プロバイダーを参照する操作またはソースで定義された型と互換性がある必要があります。 ### [](#例-2-接続された値プロバイダーのユースケース)例 2: 接続された値プロバイダーのユースケース 上記のロールの例では、サービスでカスタムロールを定義できましたが、コネクタがそれらのロールを伝達することはできませんでした。 稼働中の接続を介して値を解決するように値プロバイダーを実装すると、使用可能なロールをフェッチし、値プロバイダーを介してロールを伝達できるようになります。 ```java public class UserRoleValueProvider implements ValueProvider { @Connection ServiceConnection connection; @Override public Set resolve() throws ValueResolvingException { return ValueBuilder.getValuesFor(connection.getAvailableRoles()); } } ``` ### [](#他のパラメーターに依存する値プロバイダー)他のパラメーターに依存する値プロバイダー 接続と設定を挿入することに加えて、値プロバイダーは、_同じコンテキスト_の他のパラメーターに依存することができます。SDK では、必須パラメーターが設定されるまで、値プロバイダーの解決ロジックは実行されません。 「_同じコンテキスト_」とは、値プロバイダーをコンポーネントで使用する場合、そのコンポーネントに必須パラメーターが存在する必要があることを意味します。たとえば、パラメーター `dynamicParam` 内で値プロバイダーを使用する設定 `FancyConfig` でパラメーター `aConfigParam` の値を必要とする場合、`aConfigParam` が `FancyConfig` 設定に存在する必要があります。 必須パラメーターで式を使用すると、アクティブなイベントなしでは式を解決できないために値プロバイダーの実行が無効になる場合があります。 #### [](#必須パラメーターの宣言)必須パラメーターの宣言 コネクタや設定の場合と同様に、`@Parameter` アノテーションを使用して、解決ロジックの実行に必要なパラメーターを宣言します。次の例の `String requiredParam` など、必須パラメーターと**同じ型と名前**の値プロバイダーの項目でアノテーションを使用します。 外部パラメーターの例: 2 つのパラメーターを宣言する操作 (1 つは値プロバイダーを使用) ```java public void operationWithValueProvider(String requiredParam, @OfValues(ValueProviderWithRequiredParams.class) String dynamicParam){ } ``` 外部パラメーターの例: `requiredParam` パラメーターを必要とする値プロバイダー ```java public class ValueProviderWithRequiredParams implements ValueProvider { @Parameter String requiredParam; @Override public Set resolve() { return ValuesBuilder.getValuesFor(param); } } ``` ##### [](#必須パラメーターが設定されていない場合)必須パラメーターが設定されていない場合 コンポーネントで必須として定義されたパラメーターをエンドユーザーが設定しない場合、値プロバイダーは実行されません。ただし、パラメーターが省略可能として定義されている場合、値プロバイダーは `Null` 値を使用して実行されるため、null に対応する処理が必要です。 ##### [](#例-3-コンテキストパラメーターを使用する値プロバイダー)例 3: コンテキストパラメーターを使用する値プロバイダー 日と月の日付ピッカーが必要なケースを考えてみます。 2 つの列挙を使用すればこれを容易に表すことができますが、すべての月の日数が同じであるわけではありません。そのため、この表現で、ユーザーが無効な日付を設定できるようにします。 この問題を修正する手順は、次のとおりです。 1. 日付ピッカーを公開する操作を定義します。 この操作は 2 つのパラメーターを受け取ります。使用可能なすべての月を静的に伝達する `monthEnum` と、月の日付を伝達するために使用する `day` です。 Publish On Date (パブリッシュ日) 操作 ```java public void publishOnDate(Month monthEnum, @OfValues(DayValueProvider.class) String day) { } ``` 2. `Month` 列挙を定義します。 `Month` は、使用可能なすべての月を含み、各月の日数を特定します。 MonthEnum 列挙 ```java public enum Month { JANUARY(31), FEBRUARY(28), MARCH(31), APRIL(30), MAY(31), JUNE(30), JULY(31), AUGUST(31), SEPTEMBER(30), OCTOBER(31), NOVEMBER(30), DECEMBER(31); private int dayCount; MonthEnum(int i) { dayCount = i; } public int getDayCount() { return dayCount; } } ``` 3. 選択された月をコンシュームする値プロバイダーを作成します。 選択された月に応じて、値プロバイダーは、その月で使用可能なすべての日を動的に提供します。`DayValueProvider` は、動作するには `monthEnum` が必要であることを示します。 ```java public class DayValueProvider implements ValueProvider { @Parameter Month monthEnum; (1) @Override public Set resolve() { return ValueBuilder.getValuesFor(getNumbersFrom(1, monthEnum.getDayCount()) .stream() .map(num -> String.format("%02d", num))); } List getNumbersFrom(int init, int end){ List numbers = new ArrayList<>(end - init); for (int i = init; i <= end; i++) { numbers.add(i); } return numbers; } } ``` 4. 結果は次のようになります。 次のアニメーションで示されているように、`Day` セレクターは、`Month enum` パラメーターの値に基づいて動的に入力されます。  #### [](#value-structure)値構造 値プロバイダーは値のセットを返します。`Value` は、次のプロパティで構成される単純な構造です。 - `id` : この値の一意の識別子。これは必須です。 - `displayName`: UI に表示される名前。これは省略可能です。デフォルトでは、ID が表示名として使用されます。 #### [](#値の作成方法)値の作成方法 `ValueBuilder` を使用して値を作成するための独自の方法があります。 ```java ValueBuilder adminValueBuilder = ValueBuilder.newValue("ADMIN_USR_ROLE"); (1) adminValueBuilder.withDisplayName("Admin"); (2) Value adminValue = newValue.build(); (3) ``` 1Value の ID を使用して ValueBuilder を作成する必要があります。2必要に応じて、表示名を使用して値を強化することができます。3Value インスタンスを返すためのビルダーを作成します。 ## [](#valuebuilder-ユーティリティ)ValueBuilder ユーティリティ `ValueBuilder` は、特定のケースで値の作成を容易にするユーティリティを提供します。 Values に変換する必要がある値を含む `List`、`String[]`、`Stream`、または `Map` がある場合、この変換を行う最も簡単な方法は、`getValuesFor()` を使用することです。 ```java // Array Case Set arrayCase = ValueBuilder.getValuesFor("Admin", "Writer"); // List Case List valueList = new ArrayList<>(); valueList.add("Admin"); valueList.add("Writer"); Set listCase = ValueBuilder.getValuesFor(valueList); // Stream Case Set streamCase = ValueBuilder.getValuesFor(valueList.stream()); // Map Case // The Key will be considered as ID and the Value as Display Name Map valueMap = new HashMap<>(); valueMap.put("ADMIN_USR_ROLE", "Admin"); valueMap.put("WRITER_USR_ROLE") "Writer"); Set mapCase = ValueBuilder.getValuesFor(valueMap); ``` # 入力メタデータ 入力メタデータとは、コンポーネントのパラメーター型の解決を意味します。 各パラメーターは、同じコンポーネントの他のパラメーターが公開している種類のメタデータとは分離された静的または動的メタデータを提供します。 動的メタデータのパラメーターは操作でのみ使用できます。ソース、設定、および接続のパラメーターは常に静的メタデータとなります。 ## [](#inputtyperesolver-の宣言)InputTypeResolver の宣言 `InputTypeResolver` 実装は、`MetadataContext` が提供する情報に基づいて、また、最も重要な点として `MetadataKey` を使用してアプリケーション開発者が必要とする `MetadataType` を特定することによって、`MetadataType` の解決要求を処理します。`MetadataType` の詳細は、[「コンポーネントのメタデータとは?」](https://docs.mulesoft.com/jp/mule-sdk/1.1/metadata#component-metadata)を参照してください。 ```java public class InputEntityResolver implements InputTypeResolver { @Override public String getCategoryName() { return "DocEntities"; } @Override public MetadataType getInputMetadata(MetadataContext context, String key) throws MetadataResolvingException, ConnectionException { final ObjectTypeBuilder objectBuilder = context.getTypeBuilder().objectType(); switch (key) { case "Author_id": objectBuilder.addField().key("name").value().numberType(); objectBuilder.addField().key("lastName").value().stringType(); break; case "BookList_id": objectBuilder.addField().key("genre").value().stringType(); objectBuilder.addField().key("bookIds").value().arrayType().of().stringType(); break; case "Book_id": objectBuilder.addField().key("title").value().stringType(); objectBuilder.addField().key("ISBN").value().numberType(); break; default: throw new MetadataResolvingException("Unknown key:" + key, INVALID_METADATA_KEY); } return objectBuilder.build(); } } ``` 上述の例では、`typeBuilder` を取得するために `MetadataContext` のみを使用していますが、提供されている設定要素や接続要素を使用することもできます。 たとえば、接続要素を使用して外部サービスからメタデータをフェッチしたり、スキーマのような設定要素に含まれる静的リソースにアクセスしたりできます。 ## [](#inputtyperesolver-の使用)InputTypeResolver の使用 `TypesKeysResolver` と `InputTypeResolver` を使用することで、操作とソースに入力 DataSense サポートを追加できます。 `InputTypeResolver` と特定の `TypesKeysResolver` を一緒に使用する場合の主な制限は、`TypesKeysResolver` で提供される `MetadataKey` が `InputTypeResolver` によって `MetadataType` に解決できるようにするため、どちらも同じ `category` に属している必要があるという点です。 ```java public class DemoOperation { public void create(@Connection MyConnection connection, @MetadataKeyId(EntityKeysResolver.class) String type, @TypeResolver(InputEntityResolver.class) Map entity){ // Code that handles the creation based on the "type" of the "entity" if ("Account_id".equals(type)){ //... } else { //... } } } ``` 各パラメーターは専用の `TypeResolver` を持ち、それぞれが任意の `InputEntityResolver` を使用します。つまり、両方が同じリゾルバーを使用することもでき、結果として 2 つのパラメーターで同じ MetadataType を記述したり、同じ `MetadataKeyId` を使用して 2 つの異なる `MetadataType` (各パラメーターに 1 つずつ) を記述したりすることができます。 たとえば、2 つのパラメーターで同じリゾルバーを使用することで、エンティティをマージできます。 ```java public void merge(@MetadataKeyId(EntityKeysResolver.class) String type, @TypeResolver(InputEntityResolver.class) Map first, @TypeResolver(InputEntityResolver.class) Map second){ // Code that handles the merge based on the "type" of the "entity" if ("BookList_id".equals(type)){ ((List)first.get("bookIds")).addAll((List) second.get("bookIds")); } else { //... } } ``` あるいは、各エンティティ用に 2 つの異なる `MetadataType` を定義する必要があっても、常に同じ (1 回だけ解決される) `MetadataKeyId` にバインドされるため、すべて同じ `category` に属するようになります。 ```java public void crete(@MetadataKeyId(EntityKeysResolver.class) String type, @TypeResolver(ItemTypeResolver.class) Map item, @TypeResolver(ContainerTypeResolver.class) Map container){ // Code that handles the item based on the "type" of the "entity" if ("developer".equals(type)){ createDeveloperInTeam(item, container); } else { //... } } ``` ## [](#ユーザー定義の-metadatakey-を持つ入力メタデータ)ユーザー定義の MetadataKey を持つ入力メタデータ 前のセクションでは、`MetadataKeyId` パラメーターが `TypeKeysResolver` を宣言していない場合に、アプリケーション開発者が操作の設定時に任意のキーを定義できることを示しました。 このセクションでは、`MetadataKeyId` を `TypeKeysResolver` なしで使用して、パラメーターで設定されている値を使用して Database Connector で `queryParameters` の入力 MetadataType を解決する簡単な例を示します。 ```java public List> select(@MetadataKeyId String sql, @TypeResolver(DbInputMetadataResolver.class) Map queryParameters, @Config DbConnector connector){ //... } ``` ```java public class DbInputMetadataResolver implements InputTypeResolver { @Override public String getCategoryName() { return "DbCategory"; } @Override public MetadataType getInputMetadata(MetadataContext context, String query) throws MetadataResolvingException, ConnectionException { // The MetadataKey is the `query` parameter, we have to parse it to resolve // all the Metadata of its parameters QueryTemplate queryTemplate = parseQuery(query); List inputParams = queryTemplate.getInputParams(); if (inputParams.size() == 0) { // No input metadata when no input parameters return context.getTypeBuilder().nullType().build(); } PreparedStatement statement = getStatement(context, queryTemplate); return getInputMetadataUsingStatementMetadata(statement, inputParams); } } ``` ## [](#metadatakey-を使用しない動的入力メタデータの解決)MetadataKey を使用しない動的入力メタデータの解決 未知の構造を持つエンティティが複数存在することは希で、通常は、たとえばアプリケーション開発者が Sandbox に接続するために使用しているログイン情報に依存するような、動的 MetadataType が 1 つだけ存在します。この場合は、同じ `Organization` エンティティでも、アカウントによって異なるプロパティとなる場合があります。 `KeyLess` InputMetadata の解決を宣言するには、`MetadataKeyId` パラメーターを省略して、`MetadataKey` に依存せずに `TypeResolver` を使用します。 ```java public void createOrg(@TypeResolver(OrganizationTypeResolver.class) Map organization){ //... } ``` ```java public class OrganizationTypeResolver implements InputTypeResolver { @Override public String getCategoryName() { return "Organization"; } @Override public MetadataType getInputMetadata(MetadataContext context, Object key) throws MetadataResolvingException, ConnectionException { // The `key` parameter will be `null` if the fetch is performed // as a `KeyLess` Metadata resolution. We'll just ignore it. DemoConnection connection = context.getConnection() .orElseThrow(() -> new MetadataResolvingException("A connection is required to resolve Metadata but none was provided", FailureCode.INVALID_CONFIGURATION)); String schema = connection.getClient().describeOrganization(); return new JsonTypeLoader(schema).load("http://demo.org") .orElseThrow(() -> new MetadataResolvingException("No Metadata is available for the Organization", FailureCode.NO_DYNAMIC_TYPE_AVAILABLE)); } } ``` # 最初のテストケースの作成 このセクションでは、モジュールの操作をテストするための、ステップごとの手順について説明します。また、実行する必要があるテストケースの基本について説明します。 ## [](#1-つ目の概念)1 つ目の概念 モジュールのすべてのテストケースに以下の基本項目が含まれている必要があります。 - テストケースクラス: テストロジックを含む Java クラス。フローを実行し、結果についてアサーションを実行します。 - Mule アプリケーション XML: テストするモジュールを使用する Mule アプリケーション。 このドキュメントは、Mule 拡張アーキタイプを使用して生成されたモジュールプロジェクトに基づきます ([最初の SDK プロジェクトの作成](https://docs.mulesoft.com/jp/mule-sdk/1.1/getting-started#generating-a-project-using-the-maven-archetype-directly))。 この例を使用してモジュールのテスト方法を学習し、親の連動関係については上記のドキュメントを参照します。このドキュメントには、テストケースの構築に必要なすべての連動関係が記載されています。 ## [](#1-テストケースクラスの作成)1.テストケースクラスの作成 テストケースクラスは、`MuleArtifactFunctionalTestCase` から継承される必要があります。これで、Mule アプリケーション内でのモジュールのテストが可能になります。 ```java public class BasicOperationsTestCase extends MuleArtifactFunctionalTestCase { } ``` ## [](#2-mule-アプリケーションの記述)2.Mule アプリケーションの記述 モジュールをテストするには、そのモジュールを使用する Mule アプリケーションを実行し、フローを実行して、実行結果についてアサーションを実行します。 Mule アプリケーション XML は、モジュールプロジェクトの `src/test/resources` フォルダー内に配置する必要があります。 ```xml ```  ヒント: Mule アプリケーションの記述は、Anypoint Studio で Mule アプリケーションを作成し、生成された XML をコピーしてモジュールプロジェクト内に貼り付けることで簡単にできます。 ## [](#3-テストケースへの-mule-アプリケーションのインポート)3.テストケースへの Mule アプリケーションのインポート テストケースクラスと Mule アプリケーション XML を作成したら、その 2 つのコンポーネントをバインドし、テストケースを実行する Mule アプリケーションを識別します。これを行うには、`getConfigFile()` メソッドを上書きし、Mule アプリケーション XML の相対パスを含む `String` を返します。 設定ファイルのパスは、module-project/src/test/resources フォルダーを基準とする相対パスです。たとえば、XML ファイルが module-project/src/test/resources/test-connector-mule-app.xml に配置されている場合、getConfigFile() メソッドは test-connector-mule-app.xml を返します。 ```java public class ModuleTestCase extends MuleArtifactFunctionalTestCase { @Override protected String getConfigFile() { return "test-connector-mule-app.xml"; } } ``` ## [](#4-最初のテストケースの作成)4.最初のテストケースの作成 このフェーズでは、モジュールテストケースの作成を開始するためのすべてをセットアップします。最初のテストでは、フローを実行し、出力を取得して、それに対してアサーションを実行する簡単な操作をテストするように記述します。 ### [](#testing-flowrunner)4.1 フローの実行 `flowRunner("flowName")` ユーティリティメソッドを使用して、`FlowRunner` (フローを実行できるユーティリティ) のインスタンスを作成します。パラメーターで識別されたフローを実行するように `FlowRunner` インスタンスを設定します。 次に `FlowRunner` インスタンスで `run()` を実行します。次に例を示します。 ```java Event event = flowRunner("sayHiFlow").run(); ``` フローを実行すると、`payload`、`attributes`、`vars` と、フローの実行に関して使用可能なすべての情報を含む `Event` が返されます。 フローからストリームが返された場合は、keepStreamsOpen() メソッドをコールして、ランタイムによるストリームの終了 (フローの終了時の正常な動作です) を防止してください。keepStreamsOpen() メソッドをコールしないと、ストリームをコンシュームしようとしたときに CursorProviderAlreadyClosedException エラーが返されます。次の例は、keepStreamsOpen() メソッドのコール方法を示しています。 Event event = flowRunner("streamFlow").keepStreamsOpen().run(); ### [](#4-2-ペイロード値の取得)4.2 ペイロード値の取得 フローを実行したら、`event` 変数にフローの実行結果が含まれます。ペイロードの値を取得し、必要なアサーションを実行するには、この変数が必要です。 ```java Object payloadValue = event.getMessage() .getPayload() .getValue(); assertThat(payloadValue, is("Hello Mariano Gonzales!!!")) ``` ### [](#4-3-まとめ)4.3 まとめ 次の例は、前述のテストケース手順をまとめたものです。 ```java @Test public void executeSayHiOperation() throws Exception { Event sayHiFlow = flowRunner("sayHiFlow").run(); (1) String payloadValue = ((String) sayHiFlow .getMessage() .getPayload() .getValue()); (2) assertThat(payloadValue, is("Hello Mariano Gonzales!!!")); (3) } ``` 1sayHiFlow フローを実行します。2ペイロード値を取得します。3値に対してアサーションを実行します。 # 出力 MediaType の適用 [`Result` オブジェクト](https://docs.mulesoft.com/jp/mule-sdk/1.1/result-object)により、出力の `mimeType` を設定できます。ただし、この設定は省略可能です (SDK 開発者には、`mimeType` の設定は求められていません)。 一方で、操作の出力 `mimeType` が必須である次のようなケースもあります。 - 操作が `String` を返す場合。 - 操作が `InputStream` を返す場合。 この制限は任意ではありません。Mule 4 は DataWeave を式言語として使用するため、ユーザーはデータの形式を気にする必要はありません。気にする必要があるのは、構造のみです。ただし、DataWeave が Mule メッセージで伝達されるすべての値のメディア種別を判断できればよいのです。 SDK は、DataWeave が自動的に必要な情報を得られるように作業の大半を処理しますが、操作で `String` などの汎用型が返された場合は、データが JSON なのか、XML なのか、あるいはプレーンテキスト形式なのかを知ることは不可能です。`InputStream` が返された場合も同様で、JSON、XML、または CSV ストリーム、あるいはバイナリ情報の可能性もあります。いずれのケースでも、開発者はデザイン時にこの情報を SDK に対して指定する必要があります。 そのために `@MediaType` アノテーションが用意されています。`String` または `InputStream` を返すすべてのソースと操作は、MediaType を `**/**` に指定してある場合でも、このアノテーションを使用する必要があります。 たとえば、顧客に関する情報を返す操作を開発しているとします。また、この操作は XML 形式で情報を返すものとします。この場合は、次のように定義できます。 ```java @MediaType(MediaType.APPLICATION_XML) public String getCustomerInfo(String customerId) { return fetchCustomerXml(customerId); } ``` また、ビデオを `mp4` 形式で返すビデオストリーミングモジュールを開発している場合なら、次のようになります。 ```java @MediaType("video/mp4") public InputStream getVideo(String videoId) { return getVideoStream(videoId); } ``` @MediaType アノテーションは、最も一般的なメディア種別に対して定数セットを定義しています。ただし、ビデオメディア種別の例に示されているように、必要なカスタム mediaType を使用することもできます。 ## [](#strict-false-メディア種別)strict = false メディア種別 上記の例では、操作は指定されている以外のメディア種別を返すことはできません。しかし、_最も可能性の高い_メディア種別しか分からない場合や、`mediaType` を特定できない場合もあります。このようなケースに備えて、`@MediaType` アノテーションには `strict = false` オプションが用意されています。 ### [](#可変メディア種別)可変メディア種別 顧客情報を取得する操作の例に戻り、接続先のサービスがデフォルトでは XML を返し、さらに、異なる形式を使用するように特定のアカウントを設定することもできるとします。また、そのメディア種別を事前に知ることはできないとします。この場合は、次のように定義できます。 ```java @MediaType(value = MediaType.APPLICATION_XML, strict = false) public String getCustomerInfo(String customerId) { return fetchCustomerXml(customerId); } ``` `strict` パラメーターを `false` に設定すると、`outputMimeType` パラメーターが自動的に操作に追加されます。このパラメーターにより、モジュールのユーザーは `mimeType` を手動で上書きできます。そのため、自分のアカウントを知っていて、JSON を使用するように設定されているユーザーであれば、次のように指定できます。 ```xml ``` ### [](#不明なメディア種別)不明なメディア種別 HTTP 要求のケースを考えてみましょう。取得されるメディア種別はヒットするエンドポイントによって変わります。取得するメディア種別が不明であるため、`ANY` (`**/**`) を使用します。 ```java @MediaType(value = "*/*", strict = false) public InputStream request(String path) { return httpClient.request(path); } ``` ここでも、`strict = false` 属性によって、ユーザーはエンドポイントに応じて `mimeType` を手動で設定できます。 ```xml ``` 自動的に追加される outputMimeType パラメーターは省略可能であり、デフォルト値はありません。ユーザーは、このパラメーターを空白のままにしておけます。その場合、SDK はアノテーションで設定されているメディア種別を使用します。 # 出力メタデータ 出力メタデータは、コンポーネントの結果の型を解決します。各コンポーネントは、ペイロードと属性の静的メタデータまたは動的メタデータを互いに分離して提供できます。 ## [](#outputtyperesolver-と-attributestyperesolver-の宣言)OutputTypeResolver と AttributesTypeResolver の宣言 `OutputTypeResolver` 実装と `AttributesTypeResolver` 実装は、`MetadataContext` が提供する情報に基づいて、また、最も重要な点として `MetadataKey` を使用してエンドユーザー (Mule アプリケーションの作成者) が必要とする `MetadataType` を特定することによって、`MetadataType` の解決要求を処理します。`MetadataType` の詳細は、[「コンポーネントのメタデータとは?」](https://docs.mulesoft.com/jp/mule-sdk/1.1/metadata#component-metadata)を参照してください。 `OutputTypeResolver` インターフェースと `AttributesTypeResolver` インターフェースは、汎用 `T` でパラメーター化され、`MetadataKeyId` パラメーターの型と一致する必要があります。この例では、最も一般的な `MetadataKeyId` 型である `String` を汎用型として使用しています。(他のドキュメントもこの汎用型を参照し、`String` 以外に変更する必要がある場合に型を詳細に定義しています。) ```java public class OutputEntityResolver implements OutputTypeResolver, AttributesTypeResolver { @Override public String getCategoryName() { return "Records"; } @Override public String getResolverName() { return "OutputEntityResolver"; } @Override public MetadataType getOutputType(MetadataContext context, String key) throws MetadataResolvingException, ConnectionException { switch (key) { case "Author_id": return context.getTypeLoader().load(AuthorResult.class); case "BookList_id": return context.getTypeLoader().load(BookListResult.class); case "Book_id": return context.getTypeLoader().load(BookResult.class); default: throw new MetadataResolvingException("Unknown key:" + key, INVALID_METADATA_KEY); } } @Override public MetadataType getAttributesType(MetadataContext context, String key) throws MetadataResolvingException, ConnectionException { if ("Book_id".equals(key)){ return context.getTypeLoader().load(BookAttributes.class); } // Only Books have Attributes information return context.getTypeBuilder().nullType().build(); } } ``` 上記の例では、`typeLoader` を取得するために `MetadataContext` のみを使用して Java クラスに基づいて MetadataType を記述していますが、提供されている設定要素や接続要素を使用することもできます。 ## [](#outputtyperesolver-の使用)OutputTypeResolver の使用 `TypeKeysResolver` と `OutputTypeResolver` を使用することで、操作とソースに出力 DataSense サポートを追加できます。`OutputTypeResolver` と特定の `TypeKeysResolver` を一緒に使用する場合の主な制限は、`TypeKeysResolver` で提供される `MetadataKey` が `OutputTypeResolver` によって `MetadataType` に解決できるようにするため、どちらも同じ `category` に属している必要があるという点です。 ### [](#結果ペイロードへの-datasense-の追加)結果ペイロードへの DataSense の追加 ```java public class FetchOperations { @OutputResolver(output = OutputEntityResolver.class) public Map get(@Connection MyConnection connection, @MetadataKeyId(EntityKeysResolver.class) String entityKind){ return connection.getClient().fetch(entityKind); } } ``` 上記の例では、フェッチされる `entityKind` に基づいて出力の MetadataType を動的に解決しているため、`EntityKeysResolver` が提供する `Author_id` で `entityKind` を設定してある場合は、その `MetadataKey` で `OutputEntityResolver` が呼び出され、`get` 操作の出力は `AuthorResult` ObjectType に解決されます。 ソースは、同じ出力型解決を使用して、フローにディスパッチされるオブジェクトの MetadataType を記述することができます。宣言は同様です。 ```java @MetadataScope(keysResolver = EntityKeysResolver.class, outputResolver = OutputEntityResolver.class) public class ListenerSource extends Source, Void> { @MetadataKeyId @Parameter public String type; @Connection private ConnectionProvider connection; @Override public void onStart(SourceCallback, Void> sourceCallback) throws MuleException { //... } @Override public void onStop() { //... } } ``` ソースと操作では、出力型の解決のライフサイクルは同じです。まず `MetadataKeyId` を設定してから、そのキーで `OutputTypeResolver` を呼び出して、結果のエンティティの MetadataType を解決します。 ### [](#結果属性用の-datasense-の追加)結果属性用の DataSense の追加 動的メタデータの解決では、コンポーネントの完全な出力がペイロードだけではなく `Result` であることを考慮します。 操作またはソースの出力に動的な属性構造がある場合は、`AttributesTypeResolver` (`OutputTypeResolver.java` の例で実装済み) を宣言してから、操作またはソースの宣言にリゾルバーへの参照を追加することで、MetadataType を解決することができます。 次の例では、`Book` エンティティを、それぞれが独自の構造を持つ本のコンテンツと属性に分割します。この分割により、エンドユーザーは操作の結果をより効果的に理解して使用できます。つまり、データ (ペイロードに格納される本のコンテンツ) とペイロードを特徴付けるメタデータ (本の属性) に分けて考えることができます。 ```java public class FetchOperationsWithAttributes { @OutputResolver(output = OutputEntityResolver.class, attributes = OutputEntityResolver.class) public Result get(@Connection MyConnection connection, @MetadataKeyId(EntityKeysResolver.class) String entityKind){ if ("Book_id".equals(entityKind)){ Book book = (Book)connection.getClient().fetch(entityKind); return Result.builder() .output(book.content()) .attributes(book.attributes()) .build(); } return return Result.builder() .output(connection.getClient().fetch(entityKind)) .build(); } } ``` ソースには、ペイロードで使用したのと同じような宣言がありますが、`attributesResolver` 参照が追加されています。 ```java @MetadataScope(keysResolver = EntityKeysResolver.class, outputResolver = OutputEntityResolver.class, attributesResolver = OutputEntityResolver.class) public class ListenerSource extends Source, Object> { @MetadataKeyId @Parameter public String type; //... } ``` ## [](#ユーザー定義の-metadatakey-を持つ出力メタデータ)ユーザー定義の MetadataKey を持つ出力メタデータ ユーザー定義の MetadataKey のケースは、コンポーネントの出力にも適用されます。 クエリの場合は、解決される可能性のある MetadataKey のセットを事前に定義することができません。その代わりに、出力の型または構造を特徴付けるパラメーターとその値があります。 たとえば、Database Connector には `select` 操作があります。その出力は、クエリ対象のエンティティによって異なります。 ```java @OutputResolver(output = SelectMetadataResolver.class) public List> select(@MetadataKeyId String sql, @Config DbConnector connector){ // ... } ``` `SelectMetadataResolver` は次のように宣言されています。 ```java public class SelectMetadataResolver extends BaseDbMetadataResolver implements OutputTypeResolver { @Override public String getCategoryName() { return "DbCategory"; } @Override public String getResolverName() { return "SelectResolver"; } @Override public MetadataType getOutputType(MetadataContext context, String query) throws MetadataResolvingException, ConnectionException { if (isEmpty(query)) { throw new MetadataResolvingException("No Metadata available for an empty query", FailureCode.INVALID_METADATA_KEY); } ResultSetMetaData statementMetaData = getStatementMetadata(context, parseQuery(query)); if (statementMetaData == null) { throw new MetadataResolvingException(format("Driver did not return metadata for the provided SQL: [%s]", query), FailureCode.INVALID_METADATA_KEY); } ObjectTypeBuilder record = context.getTypeBuilder().objectType(); Map recordModels = resolveRecordModels(statementMetaData); recordModels.entrySet() .forEach(e -> record.addField().key(e.getKey()).value(e.getValue())); return record.build(); } } ``` ## [](#メタデータの自動ラップのリスト)メタデータの自動ラップのリスト `select` の例では、操作から `List` が返されています。SELECT クエリの結果は複数のレコードエントリであるため当然ですが、`SelectMetadataResolver` は `getOutputType` メソッドで ArrayType を記述していません。その代わりに、返された MetadataType は単一の `record` 構造を表しています。 これは何故でしょうか。 すでにお分かりかも知れませんが、操作は ArrayType (リスト、PagingProvider など) を返すため、配列の `generic` 型のみを記述するだけで済みます。OutputTypeResolver と AttributesTypeResolver は常に、_コレクション_型自身ではなく_コレクションの要素_の MetadataType を解決します。これにより、MetadataType リゾルバーの再利用性が高まり、必要なコードを減らすことができます。 解決された属性は、操作の `List` 出力の属性_ではなく_、コレクションの_要素_の属性_でもある_ことを考慮してください。 ## [](#metadatakey-を使用しない動的出力メタデータの解決)MetadataKey を使用しない動的出力メタデータの解決 入力と同様、コンポーネントの設定または接続に依存する動的型として、操作の出力は特定の `MetadataKey` がなくても解決できます。この場合も、キーレスリゾルバーを宣言するには、`MetadataKeyId` パラメーターを省略して、TypeResolvers の MetadataKey を無視してください。 ```java public class UserTypeResolver implements OutputTypeResolver, AttributesTypeResolver { @Override public String getCategoryName() { return "User"; } @Override public MetadataType getOutputType(MetadataContext context, Object key) throws MetadataResolvingException, ConnectionException { // The `key` parameter will be `null` if the fetch is performed // as a `KeyLess` Metadata resolution. We'll just ignore it. String schema = getUserSchema(context); return new JsonTypeLoader(schema).load("http://demo.user") .orElseThrow(() -> new MetadataResolvingException("No Metadata is available for the User", FailureCode.NO_DYNAMIC_TYPE_AVAILABLE)); } @Override public MetadataType getAttributesType(MetadataContext context, Object key) throws MetadataResolvingException, ConnectionException { // The `key` parameter will be `null` if the fetch is performed // as a `KeyLess` Metadata resolution. We'll just ignore it. String schema = getUserSchema(context); return new JsonTypeLoader(schema).load("http://demo.attributes") .orElseThrow(() -> new MetadataResolvingException("No Metadata is available for the User Attributes", FailureCode.NO_DYNAMIC_TYPE_AVAILABLE)); } private String getUserSchema(MetadataContext context) throws MetadataResolvingException, ConnectionException { return context.getConnection() .orElseThrow(() -> new MetadataResolvingException("A connection is required to resolve Metadata but none was provided", FailureCode.INVALID_CONFIGURATION)) .describeUser(); } } ``` ```java public class UserOperations { @OutputResolver(output = UserTypeResolver.class, attributes=UserTypeResolver.class) public Result, Object> getUser(@Connection DemoConnection connection){ User user = connection.getUser(); return Result., Object>.builder() .output(user.personalInfo()) .attributes(user.accountInfo()) .build(). } } ``` # 動的設定 設定パラメーターで式の使用が必要になることは特別なことではありません。一般的なユースケースを次に示します。 - マルチテナント: 有効なユーザーに応じて、ログイン情報またはその他の設定が変わる場合があります。 - 動的エンドポイント: 転送されるメッセージに応じて、異なる宛先が使用されます。 - 動的設定: たとえば、メッセージの宛先に応じて、タイムアウトが変わる場合があります。 ## [](#静的設定)静的設定 設定のパラメーターに式が割り当てられていない場合 (パラメーターで式がサポートされている場合でも)、その設定は静的です。次に例を示します。 例: 静的設定 ```xml
操作はメッセージを処理します。
ソースはメッセージを作成してフローにプッシュします。
操作のライフサイクルは、含まれているフローに関連付けられています。
メッセージソースは、含まれているフローとは独立して開始および停止できます。
操作のパラメーターには、式を受け入れるオプションが含まれます (デフォルト)。
ソースには、式を受け入れることができるパラメーターと受け入れることができないパラメーターの明確な定義があります。式を受け入れることができるのは、応答の生成に含まれるパラメーターのみです。
操作にはライフサイクルを設定できますが、そのパラメーター値は使用できないか、必要ありません。
メッセージソースには、start() および stop() フェーズが必要です。パラメーター値へのアクセス権が必要になる場合もあります。
start()
stop()
操作が実行されるたびに接続が取得されます。
メッセージソースが開始されるたび、または再接続の発生時に接続が取得されます。
@Alias
無料
コネクタは、顧客が Anypoint Exchange を介してダウンロードして無料で使用できます。
有料
有料コネクタは、Anypoint Studio での設計時に Mule アプリケーションで使用できます。デプロイメントでは、コネクタはライセンスがないと実行できません。顧客はパートナーから直接コネクタを購入する必要があり、MuleSoft が提供する生成されたライセンスキーを使用して、有料コネクタの使用を管理する必要があります。コネクタの価格設定は、パートナーによって決定されます。
resourceOwnerId
authorizePath
いいえ
SUPPORTED
なし
ユーザーは、関連付けられているアクセストークンと更新トークンを所有するテナントの ID を指定することでマルチテナントをサポートできます。認証ダンスを実行すると、この値によって取得されているトークンの ID が提供されます。コンポーネントで新しい接続が必要な場合は、使用するデフォルトのオーナー ID として使用されます。
consumerKey
はい
NOT_SUPPORTED
サービスプロバイダーに登録されている OAuth consumerKey。
consumerSecret
サービスプロバイダーに登録されている OAuth consumerSecret。
authorizationUrl
`@AuthorizationCode アノテーションで提供されている値。
`@AuthorizationCode
サービスプロバイダーの認証 URL。
accessTokenUrl
@AuthorizationCode アノテーションで提供されている値。
@AuthorizationCode
サービスプロバイダーのアクセストークン URL。
state
REQUIRED
OAuth ダンスの開始時に送信し、トークンコールバックによってサービスプロバイダーから返される文字列値。ダンスの開始とトークンのコールバックを相関させるために使用します。この属性の最も一般的なユースケースはマルチテナントです。
scope
OAuth ダンス時に要求する OAuth スコープ。指定しない場合、デフォルトのアノテーションの範囲になります。
listenerConfig
アクセストークンコールバックエンドポイントをキャッチするリスナーの作成に使用する <http:listener-config /> への参照。
<http:listener-config />
callbackPath
アクセストークンコールバックエンドポイントのパス。
OAuth ダンスをトリガーするローカル HTTP エンドポイントのパス。
externalCallbackUrl
コールバックエンドポイントがプロキシの背後にあるか、直接 URL 以外でアクセスする必要がある場合、このパラメーターを使用して OAuth プロバイダーに、コールバックへのアクセスに使用すべき URL を指示します。
YES
各コンポーネントが他を参照しない場合に使用する必要がある resourceOwnerId。
objectStore
各リソースオーナー ID のデータの保存に使用するオブジェクトストアへの参照。指定しない場合、Runtime は自動的にデフォルトのオブジェクトストアをプロビジョニングします。
before
OAuth ダンスを開始する直前に実行するフローの名前 (事前フローを参照)。
after
accessToken が受信された直後に実行するフローの名前 (事後フローを参照)。
accessToken
Result<InputStream, FileAttributes>
InputStream
FileAttributes
Result.builder()
output(Object)
attributes(Object)
build()
Result
MediaType
@MediaType
org.mule.runtime.api.metadata.MediaType
ソース
ライフサイクルの開始時と終了時など、ソースライフサイクルに関する情報をログに記録します。 エラーと再接続の場合、ログには発生した例外に関連付けられた完全なスタック追跡が表示されます。 クラスター環境の場合、ログにはソース状況情報が表示されます。これは、それがプライマリソースであるかどうかを示します。
ポーリング入力元
ソースによって承認および拒否された項目に関する情報をログに記録します。 拒否の場合、ログには拒否の原因に関する情報が含まれます。
ポーリング入力元のウォーターマーク処理
ポーリング入力元に対するウォーターマーク処理に関する情報をログに記録します。 このプロセスは低レベルのロジックを使用するため、デバッグまたはトラブルシューティングが必要な場合にのみトレースログを有効にします。
プーリング接続プロバイダー
プーリング接続プロバイダーの接続管理に関する情報をログに記録します。 このログには、接続プールの状況情報、およびプールが接続を取得して返すタイミングを示す接続処理が表示されます。
接続元
org.mule.runtime.module.extension.internal.runtime.source.ExtensionMessageSource
DEBUG
org.mule.runtime.module.extension.internal.runtime.source.poll.PollingSourceWrapper
TRACE
org.mule.runtime.core.internal.connection.PoolingConnectionHandler org.mule.runtime.core.internal.connection.PoolingConnectionManagementStrategy
org.mule.runtime.core.internal.connection.PoolingConnectionHandler
org.mule.runtime.core.internal.connection.PoolingConnectionManagementStrategy
1.0.0
begin()
begin()
トランザクションを開始する必要がある場合、このメソッドをコールします。
commit()
commit()
トランザクションが正しく終了し、トランザクションをコミットする必要がある場合、これをコールします。
rollback()
rollback()
トランザクションがエラーで終了し、トランザクションをロールバックする必要がある場合、これをコールします。
ALWAYS_JOIN
コネクタは常に既存のトランザクションに結合します。トランザクションがないか、現在のトランザクションに現在の操作との互換性がない場合、操作の実行は失敗します。
JOIN_IF_POSSIBLE (デフォルト)
トランザクションを使用できる場合、そのトランザクションを使用します。それ以外の場合、処理を続行します。
NOT_SUPPORTED
操作は、実行中のトランザクションの外側で実行されます。
CachedConnectionProvider
CachedConnectionProviders
ALWAYS BEGIN (常に開始)
呼び出しごとに新しいトランザクションが必ず作成されます。
NONE (なし) (デフォルト)
ソースはトランザクションを開始せず、フロー内で開かれているトランザクションに参加しません。
name
必須
<parameter> の名前
<parameter>
defaultValue
省略可能
別の値を提供しない場合、<operation> はデフォルト値を使用します。
<operation>
use
AUTO
可能な値:
REQUIRED: パラメーターが存在する必要があります。パラメーターに defaultValue がある場合、これを REQUIRED にすることはできません。
OPTIONAL: パラメーターは必須ではありません。
OPTIONAL
AUTO: defaultValue がない場合、ランタイム時にデフォルトの REQUIRED になります。それ以外の場合、OPTIONAL としてマークされます。
type
<parameter> のデータ型を定義します。string、boolean、datetime、date、number、time などのプリミティブ型を使用できます。また、カタログで定義された任意の型に依存することもできます。
string
boolean
datetime
date
number
time
password
false
UI 内では <parameter> を **** でマークします。
****
role
behavior
現在の <parameter> に対して生成された XSD を変更する特定のパラメーターに対する定義済みのロールのセット。
behavior は属性を表示します。
CONTENT は、子要素として DataWeave のサポートがあることを意味します。
CONTENT
PRIMARY は CONTENT のように機能しますが、デフォルトではペイロードにマップします。
PRIMARY
ロールについての詳細を参照してください。
summary
簡単なツールチップを <parameter> に追加します。
example
このパラメーターのデータ型の短い例を追加します。
displayName
UI 表示ラベルを提供します。displayName がない場合、デフォルト値は、name 属性のハイフン付きバージョンになります。
order
各要素を UI に表示する順序を定義します。
tab
UI 内で <parameter> が属する必要があるグループ (またはタブ) を定義します。
visibility
PUBLIC
バージョン 1.2 以降で使用可能
次のように、操作の表示を PUBLIC (誰でも表示して使用可能) または PRIVATE (現在のモジュールのみにアクセス可能で、外部からは表示不可能) とマークします。
PRIVATE
<operation name="example" visibility="PRIVATE"> <parameters> <parameter name="errorTopic" type="string" />
doc:description
<parameter> のドキュメント。
出力ペイロードのデータ型。要素を削除して、これを void に設定することができます。これにより、動作にペイロードの変更が伴う場合でも、<operation> が Mule イベントを変更することが回避されます。
void
出力属性のデータ型。要素を削除して、これを void に設定することができます。これにより、動作にペイロードの変更が伴う場合でも、<operation> が Mule イベントを変更することが回避されます。
<body> 内でスロー (または再マップ) するエラーコードの型。Mule エラーの概念を参照してください。
<body>
<property> の名前。
<property>
別の値を提供しない場合、<property> はデフォルト値を使用します。
REQUIRED: プロパティが存在する必要があります。パラメーターに defaultValue がある場合、これを REQUIRED にすることはできません。
OPTIONAL: プロパティは必須ではありません。
<property> のデータ型を定義します。string、boolean、datetime、date、number、time などのプリミティブ型を使用できます。また、カタログで定義された任意の型に依存することもできます。
入力時に UI 内のプロパティの値が非表示になります (**** が使用されます)。
簡単なツールチップを <property> に追加します。
optional
このプロパティのデータ型の短い例を追加します。
UI 内で <property> が属する必要があるグループ (またはタブ) を定義します。
<property> のドキュメント。
<module> の名前。
<module>
vendor
"MuleSoft"
XML SDK Module のベンダー。
prefix
スキーマを生成するときに使用するモジュールのプレフィックス。空の場合、モジュールでは name 属性のハイフン付きバージョンが使用されます。プレフィックス属性を参照してください。
namespace
スキーマの生成時にモジュールで使用する名前空間。それ以外の場合、デフォルトは http://www.mulesoft.org/schema/mule/<prefix> です (<prefix> は prefix 属性値)。
http://www.mulesoft.org/schema/mule/<prefix>
<prefix>
<module> のドキュメント。
name="hello with spaces"
name="hello with spaces"
prefix="hello-prefix"
namespace="http://www.mulesoft.org/schema/a/different/path/mule/hello"
namespace=http://www.mulesoft.org/schema/mule/hello-prefix
prefix="hello-with-spaces"
namespace=http://www.mulesoft.org/schema/mule/hello-with-spaces
Hello
module-hello
xmlns:connection="true"
ErrorTypeProvider
メソッドは PagingDelegate オブジェクトを返します。PagingDelegate は 2 つの汎用型を必要とします。1 つ目はデリゲート関数が次ページ以降を取得するために使用する接続の種別で、2 つ目はページ内の要素の種別です。
PagingDelegate
List 操作はパラメーターを受け取ります。ただし、接続オブジェクトは受け取りません。ページングされた操作は接続を受け取ることができないためです。代わりに、Runtime によって PagingProvider に渡される接続を常に使用する必要があります。
PagingProvider
そのため、この署名は DbConnection オブジェクトを使用したページのクエリ結果を返し、ストリームの各項目は結果の各行を表す Map<String, Object> となります。
DbConnection
Map<String, Object>
getPage()
getTotalResults()
Optional
#[payload.size]
close()
ResultSet
String
clientId
サービスプロバイダーに登録されている OAuth clientId 値。
clientSecret
サービスプロバイダーに登録されている OAuth clientSecret 値。
tokenUrl
@ClientCredentials アノテーションで提供されている値。
@ClientCredentials
サービスプロバイダーのトークンエンドポイント URL。
scopes
OAuth ダンス時に要求する OAuth スコープ。指定されていない場合、デフォルトとしてアノテーション内のスコープが使用されます。
各リソースオーナー ID のデータを保存する ObjectStore への参照。指定しない場合、Runtime は自動的にデフォルトのオブジェクトストアをプロビジョニングします。
ConnectionException
SourceCallback
file:write
#[payload]
@NullSafe
#[{}]
HttpRequestBuilder
@ParameterGroup
@Content
JenkinsStereotypeDefinition
PROCESSOR_DEFINITION
StereotypeDefinition
MuleStereotypeDefinition
@ConfigReference
config
requesterConfig
HttpRequesterConfig
ExtensionsClient
CallbackContext
SourceCallbackContext
bindConnection()
handle
SourceCallbackContext.getConnection()
onSuccess
onError
onTerminate methods
onSuccess()
onError()
TransactionHandle
ImmutableFileRepeatableInputStream
Door
door-ref
HttpListener
@EmitsResponse
@OnSuccess
HttpResponseContext
handle()
Error
java.lang.Error
org.mule.runtime.api.message.Error
pollContext
accept
setResult
setId
setWatermark
PollItemStatus
item
@MetadataKeyId
HttpServer
handle(Result)
ConnectionProvider
processRequest
onStop()
onStart()
disconnect()
@Parameter
-Ddays.to.expire=<days-until-this-license-expires>
-Dclient=<client-name>
@Extension
@Parameters
Max Active (最大アクティブ)
5
Max Idle (最大アイドル)
Max Wait (最大待機)
Exhausted Action (枯渇アクション)
GROW
Initialisation Policy (初期化ポリシー)
INITIALIZE_ONE
Min Eviction Millis (最小除去時間)
1800000
Eviction Check Interval Millis (除去確認間隔)
-1
mule-plugin
Value
ValueBuilder
module-project/src/test/resources
module-project/src/test/resources/test-connector-mule-app.xml
getConfigFile()
test-connector-mule-app.xml
フローからストリームが返された場合は、keepStreamsOpen() メソッドをコールして、ランタイムによるストリームの終了 (フローの終了時の正常な動作です) を防止してください。keepStreamsOpen() メソッドをコールしないと、ストリームをコンシュームしようとしたときに CursorProviderAlreadyClosedException エラーが返されます。次の例は、keepStreamsOpen() メソッドのコール方法を示しています。
CursorProviderAlreadyClosedException
Event event = flowRunner("streamFlow").keepStreamsOpen().run();
sayHiFlow
mediaType
outputMimeType