Red Hat Training
A Red Hat training course is available for Red Hat Fuse
第69章 HL7
HL7 コンポーネント
このコンポーネントは以下をサポートします。
- HL7 MLLP codec ( Mina)
- Camel 2.15 以降の Netty4 の HL7 MLLP コーデック
- HAPI および文字列間の 型コンバーター
- HAPI ライブラリーを使用した HL7 DataFormat
- さらに使いやすいため、105章MINA2 - 非推奨 コンポーネントと統合されています。
Maven ユーザーは、このコンポーネントの
pom.xml に以下の依存関係を追加する必要があります。
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-hl7</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>Camel on EAP デプロイメント
このコンポーネントは、Red Hat JBoss Enterprise Application Platform (JBoss EAP) コンテナー上で簡素化されたデプロイメントモデルを提供する Camel on EAP (Wildfly Camel) フレームワークによってサポートされます。このモデルの詳細は、Deploying into a Web Server の Apache Camel on JBoss EAP の章を参照してください。
HL7 MLLP プロトコル
HL7 は、テキストベースの TCP ソケットベースのプロトコルである HL7 MLLP プロトコルでよく使用されます。このコンポーネントには、MLLP プロトコルに準拠する Mina および Netty4 Codec が同梱されるため、TCP トランスポート層で HL7 リクエストを受け入れる HL7 リスナーを簡単に公開できます。
HL7 リスナーサービスを公開するには、
camel-mina2 または camel-netty4 コンポーネントが HL7MLLPCodec (mina2)または HL7MLLPNettyDecoder/HL7MLLPNettyEncoder (Netty4)とともに使用されます。
HL7 MLLP コーデックには、以下のオプションがあります。
| 名前 | デフォルト値 | 説明 |
|---|---|---|
startByte
|
0x0b
|
HL7 ペイロードにまたがる開始バイト。 |
endByte1
|
0x1c
|
HL7 ペイロードにまたがる最初のエンドバイト。 |
endByte2
|
0x0d
|
HL7 ペイロードにまたがる 2 番目の終了バイト。 |
charset
|
JVM のデフォルト | codec に使用するエンコーディング( 文字セット名)。指定しない場合、Camel は JVM のデフォルト Charset を 使用します。 |
produceString
|
true
|
Camel 2.14.1: true の場合、コーデックは定義された charset を使用して文字列を作成します。false の場合、コーデックはプレーンなバイトアレイをルートに送信し、HL7 Data Format が HL7 メッセージコンテンツから実際の文字セットを決定できるようにします。
|
convertLFtoCR
|
false
|
は、\n を \r (0x0d、13 進数)に変換します。HL7 は、セグメントターミネーターとして \r を使用します。HAPI ライブラリーには \r を使用する必要があります。
|
Mina を使用した HL7 リスナーの公開
Spring XML ファイルでは、ポート 8888 で TCP を使用して HL7 要求をリッスンするように Mina2 エンドポイントを設定します。
<endpoint id="hl7MinaListener" uri="mina2:tcp://localhost:8888?sync=true&codec=#hl7codec"/>
sync=true は、このリスナーが同期されているため、呼び出し元に HL7 応答を返すことを示します。HL7 コーデックが codec=#hl7codec で設定されている。
hl7codec は Spring Bean ID であるため、mygreatcodecforhl7 または任意の名前を付けることができます。codec も Spring XML ファイルで設定されます。
<bean id="hl7codec" class="org.apache.camel.component.hl7.HL7MLLPCodec">
<property name="charset" value="iso-8859-1"/>
</bean>
この Java DSL の例が示すように、エンドポイント hl7MinaListener はルートでコンシューマーとして使用できます。
from("hl7MinaListener").beanRef("patientLookupService");
これは、HL7 をリッスンし、HL7 という名前のサービスにルーティングする非常に単純 なルートです。これは Spring Bean ID で、以下のように Spring XML で設定されます。
<bean id="patientLookupService" class="com.mycompany.healthcare.service.PatientLookupService"/>
Camel のもう 1 つの強力な機能は、以下のように Camel に関連付けられていない POJO クラスにビジネスロジックを持つことができることです。
import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.v24.segment.QRD;
public class PatientLookupService {
public Message lookupPatient(Message input) throws HL7Exception {
QRD qrd = (QRD)input.get("QRD");
String patientId = qrd.getWhoSubjectFilter(0).getIDNumber().getValue();
// find patient data based on the patient id and create a HL7 model object with the response
Message response = ... create and set response data
return response
}
このクラスは Camel からではなく HAPI ライブラリーからのインポートのみを使用することに注意してください。
Netty を使用した HL7 リスナーの公開(Camel 2.15 以降から利用可能)
Spring XML ファイルでは、ポート 8888 で TCP を使用して HL7 リクエストをリッスンするように Netty4 エンドポイントを設定します。
<endpoint id="hl7NettyListener" uri="netty4:tcp://localhost:8888?sync=true&encoder=#hl7encoder&decoder=#hl7decoder"/>
sync=true このリスナーが同期されているため、呼び出し元に HL7 応答を返すことを示します。HL7 コーデックは、encoder=#hl7encoder および decoder=#hl7decoder で設定されます。hl7encoder および hl7decoder は Bean ID のみであるため、名前が異なる可能性があることに注意してください。Bean は Spring XML ファイルで設定できます。
<bean id="hl7decoder" class="org.apache.camel.component.hl7.HL7MLLPNettyDecoderFactory"/> <bean id="hl7encoder" class="org.apache.camel.component.hl7.HL7MLLPNettyEncoderFactory"/>
この Java DSL の例が示すように、
hl7NettyListener エンドポイントはコンシューマーとしてルートで使用できます。
from("hl7NettyListener").beanRef("patientLookupService");java.lang.String または byte[] を使用した HL7 モデル
HL7 MLLP コーデックは、プレーン
String をデータ形式として使用します。Camel は Type Converter を使用して文字列を HAPI HL7 モデルオブジェクトに変換しますが、データを独自に解析する場合は、プレーン String オブジェクトを使用できます。
Camel 2.14.1 の時点で、
produceString プロパティーを false に設定すると、Mina および Netty コーデックの両方がプレーン byte[] をデータ形式として使用することもできます。Type Converter は、byte[] を HAPI HL7 モデルオブジェクトとの間で変換することもできます。
HAPI を使用した HL7v2 モデル
HL7v2 モデルは、HAPI ライブラリーの Java オブジェクトを使用します。このライブラリーを使用すると、HL7v2 で主に使用される EDI 形式(ER7)からエンコードおよびデコードできます。
以下の例は、リフォルト ID
0101701234 で発行者を検索するリクエストです。
MSH|^~\\&|MYSENDER|MYRECEIVER|MYAPPLICATION||200612211200||QRY^A19|1234|P|2.4 QRD|200612211200|R|I|GetPatient|||1^RD|0101701234|DEM||
HL7 モデルを使用すると、
ca.uhn.hl7v2.model.Message オブジェクトを使用して作業できます。 たとえば、音声 ID を取得することができます。
Message msg = exchange.getIn().getBody(Message.class);
QRD qrd = (QRD)msg.get("QRD");
String patientId = qrd.getWhoSubjectFilter(0).getIDNumber().getValue(); // 0101701234byte[], String またはその他の単純なオブジェクト形式を使用する必要がないため、HL7 リスナーと組み合わせると便利です。HAPI HL7v2 モデルオブジェクトのみを使用できます。事前にメッセージタイプが分かっている場合は、よりタイプセーフになります。
QRY_A19 msg = exchange.getIn().getBody(QRY_A19.class); String patientId = msg.getQRD().getWhoSubjectFilter(0).getIDNumber().getValue();
HL7 DataFormat
HL7 コンポーネントには、HL7 モデルオブジェクトのマーシャリングまたはアンマーシャリングに使用できる HL7 データフォーマットが同梱されています。
marshal= メッセージからバイトストリームへ(HL7 MLLP コーデックを使用して応答する場合に使用できます)unmarshal= バイトストリームからメッセージへ(HL7 MLLP からストリームデータを受信する場合に使用できます)
データフォーマットを使用するには、インスタンスをインスタンス化し、ルートビルダーで
marshal または unmarshal 操作を呼び出します。
DataFormat hl7 = new HL7DataFormat();
...
from("direct:hl7in").marshal(hl7).to("jms:queue:hl7out");
上記の例では、HL7 は HAPI Message オブジェクトからバイトストリームにマーシャリングされ、JMS キューに配置されます。以下の例は、逆になります。
DataFormat hl7 = new HL7DataFormat();
...
from("jms:queue:hl7out").unmarshal(hl7).to("patientLookupService");
ここでは、プロキシールックアップサービスに渡される HAPI Message オブジェクトにバイトストリームをアンマーシャリングします。
注記
HAPI 2.0 (Camel 2.11 で使用される)の時点で、HL7v2 モデルクラスは完全にシリアライズ可能です。そのため、HL7v2 メッセージを JMS キューに直接配置できます(例:
marshal() を呼び出しずに)、キューから直接再度読み取ることができます(例: unmarshal()を呼び出さずに)。
重要
Camel 2.11 の時点で、
unmarshal は \n から \r に変換してセグメント区切り文字を自動的に修正しません。この変換が必要な場合は、org.apache.camel.component.hl7.HL7#convertLFToCR で便利な Expression が提供されます。
重要
Camel 2.14.1 の時点で、
marshal および unmarshal の両方が MSH-18 フィールドで提供された charset を評価します。このフィールドが空の場合、デフォルトでは、対応する Camel charset プロパティー/ヘッダーに含まれる charset が想定されます。HL7DataFormat クラスから継承する際に guessCharsetName メソッドを上書きすると、このデフォルトの動作を変更することもできます。
Camel には、よく知られているデータ形式用の簡略化された構文があります。
HL7DataFormat オブジェクトのインスタンスを作成する必要はありません。
from("direct:hl7in").marshal().hl7().to("jms:queue:hl7out");
from("jms:queue:hl7out").unmarshal().hl7().to("patientLookupService");メッセージヘッダー
unmarshal 操作は、MSH セグメントから以下のフィールドを Camel メッセージのヘッダーとして追加します。
| キー | MSH フィールド | 例 |
|---|---|---|
CamelHL7SendingApplication
|
MSH-3
|
MYSERVER
|
CamelHL7SendingFacility
|
MSH-4
|
MYSERVERAPP
|
CamelHL7ReceivingApplication
|
MSH-5
|
MYCLIENT
|
CamelHL7ReceivingFacility
|
MSH-6
|
MYCLIENTAPP
|
CamelHL7Timestamp
|
MSH-7
|
20071231235900
|
CamelHL7Security
|
MSH-8
|
null
|
CamelHL7MessageType
|
MSH-9-1
|
ADT
|
CamelHL7TriggerEvent
|
MSH-9-2
|
A01
|
CamelHL7MessageControl
|
MSH-10
|
1234
|
CamelHL7ProcessingId
|
MSH-11
|
P
|
CamelHL7VersionId
|
MSH-12
|
2.4
|
CamelHL7Context
|
-
|
Camel 2.14: メッセージの解析に使用された
HapiContext が含まれます。
|
CamelHL7Charset
|
MSH-18
|
Camel 2.14.1: Unicode UTF-8
|
CamelHL7Context 以外のヘッダーはすべて String 型です。ヘッダー値がない場合、その値は null になります。
オプション
HL7 データ形式は以下のオプションをサポートします。
| オプション | デフォルト | 説明 |
|---|---|---|
validate
|
true
|
デフォルトの検証ルールを使用して HAPI Parser がメッセージを検証するかどうか。parser オプションまたは hapiContext オプションを使用して、目的の HAPI ValidationContext で初期化することが推奨されます。 |
parser
|
ca.uhn.hl7v2.parser.GenericParser
|
使用されるカスタムパーサー。タイプ ca.uhn.hl7v2.parser.Parser である必要があります。GenericParser では、XML でエンコードされた HL7v2 メッセージの解析も許可されることに注意してください。 |
hapiContext
|
ca.uhn.hl7v2.DefaultHapiContext
|
Camel 2.14: カスタムパーサー、カスタム ValidationContext などを定義できるカスタム HAPI コンテキスト。これにより、HL7 の解析およびレンダリングプロセスを完全に制御できます。
|
Dependencies
Camel ルートで HL7 を使用するには、上記の camel-hl7 の依存関係を追加して、このデータ形式を実装する必要があります。
HAPI ライブラリーは、HL7v2 メッセージバージョンごとに 1 つずつ、ベースライブラリー と複数の構造ライブラリーに分割されました。
デフォルトでは、
camel-hl7 は HAPI ベースライブラリー のみを参照します。アプリケーションは、構造ライブラリー自体を含めます。たとえば、アプリケーションが HL7v2 メッセージバージョン 2.4 および 2.5 で機能する場合は、以下の依存関係を追加する必要があります。
<dependency>
<groupId>ca.uhn.hapi</groupId>
<artifactId>hapi-structures-v24</artifactId>
<version>2.2</version>
<!-- use the same version as your hapi-base version -->
</dependency>
<dependency>
<groupId>ca.uhn.hapi</groupId>
<artifactId>hapi-structures-v25</artifactId>
<version>2.2</version>
<!-- use the same version as your hapi-base version -->
</dependency>
または、ベースライブラリーを含む OSGi バンドル、すべての構造ライブラリーおよび必要な依存関係(バンドルクラスパス上)は、中央の Maven リポジトリー からダウンロードできます。
<dependency>
<groupId>ca.uhn.hapi</groupId>
<artifactId>hapi-osgi-base</artifactId>
<version>2.2</version>
</dependency>
Terser 言語
HAPI は、一般的に使用される場所の仕様構文を使用してフィールドへのアクセスを提供する Terser クラスを提供します。Terser 言語を使用すると、この構文を使用してメッセージから値を抽出し、フィルターリング、コンテンツベースのルーティングなどの式および述語として使用できます。
例:
import static org.apache.camel.component.hl7.HL7.terser;
...
// extract patient ID from field QRD-8 in the QRY_A19 message above and put into message header
from("direct:test1")
.setHeader("PATIENT_ID",terser("QRD-8(0)-1"))
.to("mock:test1");
// continue processing if extracted field equals a message header
from("direct:test2")
.filter(terser("QRD-8(0)-1").isEqualTo(header("PATIENT_ID"))
.to("mock:test2");HL7 検証述語
多くの場合、HL7v2 メッセージを解析し、別のステップで HAPI ValidationContext に対して検証することが推奨されます。
例:
import static org.apache.camel.component.hl7.HL7.messageConformsTo;
import ca.uhn.hl7v2.validation.impl.DefaultValidation;
...
// Use standard or define your own validation rules
ValidationContext defaultContext = new DefaultValidation();
// Throws PredicateValidationException if message does not validate
from("direct:test1").validate(messageConformsTo(defaultContext)).to("mock:test1");HapiContext (Camel 2.14)を使用した HL7 検証述語
HAPI コンテキストは常に ValidationContext (または ValidationRuleBuilder)で設定されているため、検証ルールに間接的にアクセスできます。さらに、HL7DataFormat のマーシャリングを解除すると、
CamelHL7Context header で設定された HAPI コンテキストが転送され、このコンテキストの検証ルールを簡単に再利用できます。
import static org.apache.camel.component.hl7.HL7.messageConformsTo;
import static org.apache.camel.component.hl7.HL7.messageConforms
...
HapiContext hapiContext = new DefaultHapiContext();
hapiContext.getParserConfiguration().setValidating(false); // don't validate during parsing
// customize HapiContext some more ... e.g. enforce that PID-8 in ADT_A01 messages of version 2.4 is not empty
ValidationRuleBuilder builder = new ValidationRuleBuilder() {
@Override
protected void configure() {
forVersion(Version.V24)
.message("ADT", "A01")
.terser("PID-8", not(empty()));
}
};
hapiContext.setValidationRuleBuilder(builder);
HL7DataFormat hl7 = new HL7DataFormat();
hl7.setHapiContext(hapiContext);
from("direct:test1")
.unmarshal(hl7) // uses the GenericParser returned from the HapiContext
.validate(messageConforms()) // uses the validation rules returned from the HapiContext
// equivalent with .validate(messageConformsTo(hapiContext))
// route continues from hereHL7 確認式
HL7v2 処理の一般的なタスクは、たとえば検証結果に基づいて、受信 HL7v2 メッセージへの応答として確認応答メッセージを生成することです。
ack 式は、この処理を非常に重要に達成できます。
import static org.apache.camel.component.hl7.HL7.messageConformsTo;
import static org.apache.camel.component.hl7.HL7.ack;
import ca.uhn.hl7v2.validation.impl.DefaultValidation;
...
// Use standard or define your own validation rules
ValidationContext defaultContext = new DefaultValidation();
from("direct:test1")
.onException(Exception.class)
.handled(true)
.transform(ack()) // auto-generates negative ack because of exception in Exchange
.end()
.validate(messageConformsTo(defaultContext))
// do something meaningful here
...
// acknowledgement
.transform(ack())追加のサンプル
以下の例では、プレーンの
String HL7 リクエストが応答を返す HL7 リスナーに送信されます。
String line1 = "MSH|^~\\&|MYSENDER|MYRECEIVER|MYAPPLICATION||200612211200||QRY^A19|1234|P|2.4";
String line2 = "QRD|200612211200|R|I|GetPatient|||1^RD|0101701234|DEM||";
StringBuilder in = new StringBuilder();
in.append(line1);
in.append("\n");
in.append(line2);
String out = (String)template.requestBody("mina2:tcp://127.0.0.1:8888?sync=true&codec=#hl7codec", in.toString());
次の例では、HL7 リスナーからの HL7 リクエストはビジネスロジックにルーティングされ、これはレジストリーに登録されているプレーン POJO として hl7service として実装されます。
public class MyHL7BusinessLogic {
// This is a plain POJO that has NO imports whatsoever on Apache Camel.
// its a plain POJO only importing the HAPI library so we can much easier work with the HL7 format.
public Message handleA19(Message msg) throws Exception {
// here you can have your business logic for A19 messages
assertTrue(msg instanceof QRY_A19);
// just return the same dummy response
return createADR19Message();
}
public Message handleA01(Message msg) throws Exception {
// here you can have your business logic for A01 messages
assertTrue(msg instanceof ADT_A01);
// just return the same dummy response
return createADT01Message();
}
}
その後、
RouteBuilder を使用する Camel ルートは以下のようになります。
DataFormat hl7 = new HL7DataFormat();
// we setup or HL7 listener on port 8888 (using the hl7codec) and in sync mode so we can return a response
from("mina2:tcp://127.0.0.1:8888?sync=true&codec=#hl7codec")
// we use the HL7 data format to unmarshal from HL7 stream to the HAPI Message model
// this ensures that the camel message has been enriched with hl7 specific headers to
// make the routing much easier (see below)
.unmarshal(hl7)
// using choice as the content base router
.choice()
// where we choose that A19 queries invoke the handleA19 method on our hl7service bean
.when(header("CamelHL7TriggerEvent").isEqualTo("A19"))
.beanRef("hl7service", "handleA19")
.to("mock:a19")
// and A01 should invoke the handleA01 method on our hl7service bean
.when(header("CamelHL7TriggerEvent").isEqualTo("A01")).to("mock:a01")
.beanRef("hl7service", "handleA01")
.to("mock:a19")
// other types should go to mock:unknown
.otherwise()
.to("mock:unknown")
// end choice block
.end()
// marshal response back
.marshal(hl7);
HL7 DataFormat を使用すると、Camel メッセージヘッダーに MSH セグメントからのフィールドが入力されることに注意してください。ヘッダーは、上記の例のように、フィルターリングまたはコンテンツベースのルーティングに特に便利です。