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

(その1)Javaで作成

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

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

  1. public class Main {
  2. public static void main(String args[]) throws Exception {
  3. File inboxDirectory = new File("/home/knoppix/Desktop/inbox");
  4. File outboxDirectory = new File("/home/knoppix/Desktop/outbox");
  5. outboxDirectory.mkdir();
  6. File[] files = inboxDirectory.listFiles();
  7. for (File source : files) {
  8. //出力ファイル名の拡張子を日付に変える
  9. Date date = new Date();
  10. SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd'-'HH'.'mm'.'ss");
  11. String[] strArray = source.getName().split("\\.");
  12. String destFileName ="";
  13. for(int i=0; i<strArray.length-1;i++){
  14. destFileName +=destFileName.concat(strArray[i]);
  15. }
  16. destFileName += destFileName.concat("." + sdf1.format(date));
  17. File dest = new File(outboxDirectory.getPath() + File.separator
  18. + destFileName);
  19. copyFile(source, dest);
  20. }
  21. }
  22. private static void copyFile(File source, File dest) throws IOException {
  23. OutputStream out = new FileOutputStream(dest);
  24. byte[] buffer = new byte[(int) source.length()];
  25. FileInputStream in = new FileInputStream(source);
  26. in.read(buffer);
  27. try {
  28. out.write(buffer);
  29. System.out.println("Copy from " +source.getAbsolutePath() + " To " + dest.getAbsoluteFile());
  30. } finally {
  31. out.close();
  32. in.close();
  33. }
  34. }
  35. }

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

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


(その2)Camelで作成

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

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

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

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

メイン

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

  1. CamelContextを生成。CamelContextとは、ランタイム時に必要となる器みたいなものです
  2. ルーティングのインスタンスを生成
  3. CamelContextにルーティングのインスタンスをセット
  4. CamelContextを開始
  5. 一定時間で停止
  1. import org.apache.camel.impl.DefaultCamelContext;
  2. public class Main {
  3. public static void main(String args[]) throws Exception {
  4. // 1:最初にCamelContextを作成する
  5. CamelContext context = new DefaultCamelContext();
  6. RouteBuilder routeBuilder = new FileToFileRoute();
  7. context.addRoutes(routeBuilder);
  8. // 2:作成したCamelContextを開始し、60秒後に停止
  9. context.start();
  10. Thread.sleep(60000);
  11. context.stop();
  12. }
  13. }

処理(ルーティング)

ルーティング部分は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}");
	}
}


(その3)Camel+Springで作成

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

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

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

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  6. http://camel.apache.org/schema/spring
  7. http://camel.apache.org/schema/spring/camel-spring.xsd">
  8. <!-- Camel Contextのコンフィギュレーション -->
  9. <camelContext xmlns="http://camel.apache.org/schema/spring">
  10. <route id="route_ファイル読み込んだ後に書込み">
  11. <from uri="file:/home/knoppix/Desktop/inbox?noop=true&amp;delay=5000" />
  12. <to uri="file:/home/knoppix/Desktop/outbox?fileName=${file:name.noext}.${date:now:yyyyMMdd-HH:mm:ss}" />
  13. </route>
  14. </camelContext>
  15. </beans>

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