Apache Camelで外部プロパティファイルを扱う

# はじめに

Apache Camelで使用する各種プロパティを外部ファイルから使用する方法を紹介します。
Apache CamelでのFile、FTP等の様々なコンポーネントには多くのオプションがあります。プロダクションや開発環境等の環境に応じてオプション値を変えるために、外部プロパティファイルを通常使用します。

# 外部プロパティファイルを使用する

外部プロパティファイルを使用した簡単なサンプルを作成してみます。
まず、以下のようにPropertiesComponentクラスのインスタンスを生成し、setLocationメソッドでプロパティファイルを指定します。

```java
	static PropertiesComponent createPropertiesComponent() {
		PropertiesComponent component = new PropertiesComponent();
		component.setLocation("classpath:myapp.properties");
		return component;
	}
```

以下では、クラスパス中のmyapp.propertiesファイルを指定しています。

> component.setLocation("classpath:myapp.properties");

ファイルパスの場合は、以下のように指定します。

> component.setLocation("file:myapp.properties");

myapp.propertiesファイルを使用する、mainメソッドは以下のように記載します。

```java
	public static void main(String[] args) {
		try {
			CamelContext context = new DefaultCamelContext();
			context.addComponent("properties", createPropertiesComponent());
			context.addRoutes(createRouteBuilder());

			context.start();
			Thread.sleep(5000);
			context.stop();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
```

以下の1行では、createPropertiesComponentメソッドで生成したPropertiesComponentインスタンスをCamelContextに追加しています。
これによりCamelContext内でプロパティを扱うことができるようになります。

```java
context.addComponent("properties", createPropertiesComponent());
```

実際のプロパティの使用例が以下になります。
Camelプロパティの値は、{{key}}の形式を使用して、PropertyPlaceholder内でキー名を指定することによって取得できます。
ルートを作成するJava DSL中で、"{{input_dir}}", "{{output_dir}}"のようにプロパティのキーを指定します。

```java
	static RouteBuilder createRouteBuilder() {
        return new RouteBuilder() {
			public void configure() throws Exception {
				from("file:{{input_dir}}?noop=true").to("file:{{output_dir}}");
			}
        };
    }
```

実際のプロパティファイルは以下のように定義されています。

```src/main/resources/myapp.properties
input_dir=data/input
output_dir=data/output
```

CamelではSpringを利用して外部プロパティファイルを使用することもできますが、Propertyコンポーネントを使用することで、Springがなくても利用できます。


## XML DSLの場合

Spring XML DSLを使用する場合は、以下のようにIDがpropertiesのSpring beanを定義します。

```xml
	<bean id="properties"
		class="org.apache.camel.component.properties.PropertiesComponent">
		<property name="location"
			value="classpath:myapp.properties" />
	</bean>
```

この例では、"classpath:myapp.properties"のプロパティファイルを読み込むように設定されています。
このプロパティを利用するrouteの例は以下のようになります。
"{{}}"でくくられた箇所で各プロパティを読み込んでいます。

```xml
	<camelContext
		xmlns="http://camel.apache.org/schema/spring">
		<route>
			<from uri="file:{{input_dir}}?noop=true" />
			<to uri="file:{{output_dir}}" />
		</route>
	</camelContext>
```


## プロセッサ内でプロパティを利用する

プロセッサ内でプロパティを利用する場合、resolvePropertyPlaceholdersメソッド、またはPropertyInjectアノテーションを使用します。

```java
public class TestProcessor implements Processor {

	private Logger logger = LoggerFactory.getLogger(TestProcessor.class);

    @PropertyInject("greeting")
    private String greeting;

	@Override
	public void process(Exchange exchange) throws Exception {
		String testStr = exchange.getContext().resolvePropertyPlaceholders("{{test_str}}");
		logger.info("TestProcessor testStr = {}", testStr);
		logger.info("TestProcessor greeting = {}", greeting);
	}
}

```

resolvePropertyPlaceholdersメソッドでプロパティファイルのtest_strプロパティの値を取得しています。
また、PropertyInjectアノテーションを使用し、プロパティファイルのgreetingプロパティの値をgreeting変数にインジェクションしています。


# BridgePropertyPlaceholderConfigurerを利用する

PropertiesComponentを使用した方法では、CamelContext内でしかプロパティを扱うことができませんでした。Spring内でプロパティを扱いたい場合は、BridgePropertyPlaceholderConfigurerを使用します。

```xml
	<bean id="bridgePropertyPlaceholder" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer">
		<property name="location" value="classpath:myapp.properties"/>
	</bean>
```


なお、BridgePropertyPlaceholderConfigurerは、Springのproperty-placeholderとは一緒に使用できません。


# JVM引数を利用する

外部プロパティファイルではありませんが、JVM引数の値を使用することもできます。
この場合、PropertyPlaceholderは使用せず、JVM引数を以下のように設定します。

```
-Dinput_dir=data/input -Doutput_dir=data/output
```

プログラム中からプロパティを利用するためには、{{sys:プロパティ名}}で指定します。
以下はJVM引数を利用する例です。

```java
				from("file:{{sys:input_dir}}?noop=true").to("file:{{sys:output_dir}}");
```

実際には個々のプロパティをJVM引数に指定するのは大変なので、このような利用方法はせず、以下のように環境ごとにプロパティファイルを切り替える場合に使用することになります。

```java
component.setLocation("file:${propertiesFile}/myapp.properties");
```

※{{sys:propertiesFile}}ではうまくいかなかったので、${propertiesFile}とした。なぜうまくいかなかったのかは不明。

```
-DpropertiesFile=production
```

このコードでは、${propertiesFile}をJVM引数し環境ごとにJVM引数を変えることで、ローカル開発環境、staging環境、production環境で設定ファイルを切り替えることができるようになります。


# 環境変数を利用する

Camelでは、${env:環境変数名}で、環境変数の値を取得することができます。

```java
		component.setLocation("file:${env:propertiesFile}/myapp.properties");
```



# 参考

- [Using PropertyPlaceholder](https://camel.apache.org/manual/latest/using-propertyplaceholder.html)