Show page source of スタンドアロン版Camelの例 #78083

[[PageOutline]]

「ファイルを一方のフォルダから他方のフォルダにコピーする」サンプルを例にとり、色々な方法でやってみます。

[[Thumb(model.png, size=large, caption=送信元フォルダにあるファイルを送信先にコピーする)]]

= (その1)Javaで作成 =

以下のようなモデルをJavaで作成してみます。

[[Thumb(fileToFileJava.png, size=large, caption=Java版]]

Javaで書くと以下のようになります。

{{{ code java
public class Main {
	public static void main(String args[]) throws Exception {
		File inboxDirectory = new File("/home/knoppix/Desktop/inbox");
		File outboxDirectory = new File("/home/knoppix/Desktop/outbox");
		outboxDirectory.mkdir();
		File[] files = inboxDirectory.listFiles();
		for (File source : files) {
			//出力ファイル名の拡張子を日付に変える
			Date date = new Date();
			SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd'-'HH'.'mm'.'ss");

			String[] strArray = source.getName().split("\\.");
			String destFileName ="";
			for(int i=0; i<strArray.length-1;i++){
				destFileName +=destFileName.concat(strArray[i]);
			}
			destFileName += destFileName.concat("." + sdf1.format(date));
			
			File dest = new File(outboxDirectory.getPath() + File.separator
					+ destFileName);
			copyFile(source, dest);
		}
	}

	private static void copyFile(File source, File dest) throws IOException {
		OutputStream out = new FileOutputStream(dest);
		byte[] buffer = new byte[(int) source.length()];
		FileInputStream in = new FileInputStream(source);
		
		in.read(buffer);
		try {
			out.write(buffer);
			System.out.println("Copy from " +source.getAbsolutePath() + " To " + dest.getAbsoluteFile());
		} finally {
			out.close();
			in.close();
		}
	}
}
}}}

Javaで処理を記述した場合、後述するCamelを使う場合に比べ下記の問題があります。

 * フォルダが変更になったり、送信先が増えたり、プロトコルが変わったり(例えばFTP送信に変更)と、要件の変更/追加に伴いコードが読みにくくなる
 * プログラム起動時に送信元フォルダにあったファイルだけが処理される。このため1日に複数回送信元フォルダにファイルが置かれる場合、cron等を使って定期的にプログラムを起動する必要がある
 * エラーに対する処理が貧弱(というかない!)。またエラー以外にも様々なパターンを考慮したコードを追加する必要がある。
   * 例えばフォルダがない場合、同一ファイルが存在する場合、途中でシステムダウンした場合…などでも問題なく動作するようにする必要がる

[[BR]]

= (その2)Camelで作成 =

続いてCamelを使って同じことをやってみます。ここではCamelのルーティング言語の一つであるJavaDSLを利用します。

[[Thumb(fileToFileCamel.png, size=large, caption=Camel版(JavaDSLでルーティングを記述)]]

Camelの場合、「Aをする→Bをする→Cをする…」といったように、処理の流れをルートとして記述します。

つまり今回のようなファイルのコピー処理は「ファイルを取得する→ファイル名の拡張子を変更する→ファイルを出力する」というルートになりますが、Camelの便利な機能の一つとして「ファイルを出力する」機能の中でファイルの拡張子を変更できるので、今回はこれを使って実現します。

結局Camelでのルーティングは「ファイルを取得する→ファイル名を変えてファイルを出力する」というルーティング処理になります。

== メイン ==

最初にメインコードを記述します。ここでやっていることのメイン処理は以下になります。

 1. !CamelContextを生成。!CamelContextとは、ランタイム時に必要となる器みたいなものです
 1. ルーティングのインスタンスを生成
 1. !CamelContextにルーティングのインスタンスをセット
 1. !CamelContextを開始
 1. 一定時間で停止

{{{ code java
import org.apache.camel.impl.DefaultCamelContext;

public class Main {
	public static void main(String args[]) throws Exception {
		// 1:最初にCamelContextを作成する
		CamelContext context = new DefaultCamelContext();
		RouteBuilder routeBuilder = new FileToFileRoute();
		context.addRoutes(routeBuilder);

		// 2:作成したCamelContextを開始し、60秒後に停止
		context.start();
		Thread.sleep(60000);
		context.stop();
	}
}
}}}

==  処理(ルーティング) ==

ルーティング部分はRouteBuilderを拡張し、実際の処理をルートとして記述します。

{{{
public class FileToFileRoute extends RouteBuilder {
	
	@Override
	public void configure() throws Exception {
		from("file:/home/knoppix/Desktop/inbox?noop=true&delay=5000")   //noop=true:処理後、
                                                                                //ファイルの削除をしない
		        .to("file:/home/knoppix/Desktop/outbox?fileName=${file:name.noext}.${date:now:yyyyMMdd-HH:mm:ss}");
	}
}
}}}


[[BR]]

= (その3)Camel+Springで作成 =

ルーティングの記述はSpringでも記述できます。Springを使うことでトランザクションマネージャに参加が可能になります。それではルーティング部分をSpringDSLで記述してみます。

[[Thumb(fileToFileCamelSpring.png, size=large, caption=Camel+Spring版]]

{{{ code java
public class Main {
	public static void main(String args[]) throws Exception {
		// ${CLASSPATH}/META-INF/spring/*.xmlファイルを探して実行する
		// ルーティングは${CLASSPATH}/META-INF/spring/myRoute.xmlで定義している
		System.out.println("デスクトップのinbox内ファイルを置くとoutboxにコピーされます。");
		System.out.println("DEBUGログはmylog.logを参照してください");
		System.out.println("Ctrl-Cで終了してください。");
		org.apache.camel.spring.Main.main(args);
	}
}
}}}

クラスパスの通ったディレクトに"META-INF/spring"ディレクトリを作成し、そこにルーティング用のXMLファイルを置く。名前は任意でよい。

{{{ code html
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">

<!-- Camel Contextのコンフィギュレーション -->
	<camelContext xmlns="http://camel.apache.org/schema/spring">
		<route id="route_ファイル読み込んだ後に書込み">
			<from uri="file:/home/knoppix/Desktop/inbox?noop=true&amp;delay=5000" />
			<to uri="file:/home/knoppix/Desktop/outbox?fileName=${file:name.noext}.${date:now:yyyyMMdd-HH:mm:ss}" />
		</route>
	</camelContext>
</beans>
}}}

上記3つの例で示したように、同じことをやるのに様々な実現方法があります。CamelやCamel+Springでの記述は最初は分かりにくく感じるかもしれませんが、処理をルートとして記述する、という考え方なので、ルートの間に別の処理を挿入して機能の拡張が簡単にできます。また今回はファイルの読み書きにFileコンポーネントという部品を使いましたが、コンポーネントには多数のオプションがあり、役に立ちそうなオプションをコンポーネントにどんどん追加できます。