Статьи

Hello Camel: автоматическая передача файлов

Apache Camel описан на его
главной веб-странице (и в
Руководстве пользователя Camel ) как «универсальная инфраструктура интеграции с открытым исходным кодом, основанная на известных корпоративных шаблонах интеграции». Инфраструктура Camel основана на книге
Enterprise Integration Patterns и предоставляет
реализации шаблонов, описанных в
этой книге . Я смотрю на пример типа «Hello World» с использованием Camel в этом посте.

Веб — страница и пользователи Camel Руководство также ссылаются на StackOverflow нити , что именно является Apache Camel? это включает в себя несколько хороших описаний Apache Camel. Дэвид Ньюкомб описал Верблюда там:


Apache Camel — это технология обмена сообщениями с возможностью маршрутизации.
Он объединяет начальную и конечную точки обмена сообщениями, позволяя передавать сообщения из разных источников в разные места назначения. Например: JMS-> JSON, HTTP-> JMS или воронка FTP-> JMS, HTTP-> JMS, JMS => JSON.

В этой статье я рассмотрю простое использование Camel, которое не требует использования JMS-провайдера или даже FTP или HTTP. Простота примера упрощает использование Camel. В этом примере Camel используется для автоматической передачи файлов из указанного каталога в другой указанный каталог. Три случая будут продемонстрированы.

В первом случае файлы, помещенные в каталог «input», автоматически копируются в каталог «output», не затрагивая исходные файлы. Во втором случае файлы, помещенные в каталог «input», автоматически копируются в каталог «output», а затем файлы в каталоге «input» сохраняются в специальном подкаталоге «.camel» в каталоге «input». В третьем случае файлы удаляются из каталога «input» при копировании в каталог «output» (фактически, операция «move»). Все три случая реализованы с почти одинаковым кодом. Единственное различие между ними заключается в единственной строке, указывающей, как Camel должен обрабатывать передачу файлов.

В следующем листинге кода показан базовый код, необходимый для использования Camel для автоматического копирования файлов, помещенных во входной каталог, в другой выходной каталог с Camel.

/**
 * Simple executable function to demonstrate Camel file transfer.
 * 
 * @param arguments Command line arguments; excepting duration in milliseconds
 *    as single argument.
 */
public static void main(final String[] arguments)
{
   final long durationMs = extractDurationMsFromCommandLineArgs(arguments);
   final CamelContext camelContext = new DefaultCamelContext();
   try
   {
      camelContext.addRoutes(
         new RouteBuilder()
         {
            @Override
            public void configure() throws Exception
            {
               from("file:C:\\datafiles\\input?noop=true").to("file:C:\\datafiles\\output");
            }
         });
      camelContext.start();
      Thread.sleep(durationMs);
      camelContext.stop();
   }
   catch (Exception camelException)
   {
      LOGGER.log(
        Level.SEVERE,
        "Exception trying to copy files - {0}",
        camelException.toString());
   }
}

Приведенный выше код демонстрирует минимальное использование Camel API и поддержку Camel Java DSL. CamelContext определяется с помощью экземпляра DefaultCamelContext (строка 10). Строки 13-21 добавляют маршрут Camel к этому конкретному контексту, а строка 22 начинает контекст с строки 24, останавливая контекст. Все довольно просто, но наиболее интересная часть для меня — это спецификация маршрутизации в строке 19.

Поскольку экземпляр, реализующий интерфейс RoutesBuilder, предоставленный для контекста Camel, требует переопределения только своего абстрактного метода configure, его легко создать как анонимный класс, встроенный в вызов CamelContext.addRoutes (RoutesBuilder) . Это то, что я сделал в приведенном выше коде, и то, что сделано во многих примерах Camel, которые доступны онлайн.

Строка 19 показывает хорошо читаемый синтаксис, описывающий «от» и «до» частей маршрутизации. В этом случае файлы, помещенные во входной каталог («from»), должны быть скопированы в выходной каталог («to»). Протокол «file» используется как для частей «from», так и для частей «to», потому что файловая система — это то место, откуда «сообщение» приходит и собирается. «? Noop = true» в вызове «from» указывает, что ничего не должно быть изменено в файлах в каталоге «input» (обработка должна иметь эффект «noop» для исходных файлов).

Как только что упомянуто, строка 19 в приведенном выше коде инструктирует Camel копировать файлы, уже находящиеся или помещенные в каталог «input», в указанный каталог «output», не затрагивая файлы в каталоге «input». В некоторых случаях я могу захотеть «переместить» файлы, а не «скопировать» их. В таких случаях ?delete=trueможет быть указано вместо ?noop=trueуказания конечной точки «from». Другими словами, строка 19, приведенная выше, может быть заменена на эту, чтобы файлы удалялись из каталога «input» при помещении в каталог «output». Если на входе не указано ни одного параметра (ни того, ?noop=trueни другого ?delete=true), то происходит действие, попадающее между ними: файлы во «входе»каталог перемещается в специально созданный новый подкаталог в каталоге «input».camel, Три случая выделены следующим.

Файлы, скопированные из файлов данных \ input в datafiles \ output без влияния на исходные файлы

from("file:C:\\datafiles\\input?noop=true").to("file:C:\\datafiles\\output"); 

Файлы, перемещенные из файлов данных \ input в datafiles \ output

    from("file:C:\\datafiles\\input?delete=true").to("file:C:\\datafiles\\output");  

Файлы, скопированные из файлов данных \ input в datafiles \ output и исходные файлы, перемещены в подкаталог .camel

from("file:C:\\datafiles\\input").to("file:C:\\datafiles\\output"); 

В качестве примечания, использование беглого «от» и «до» является примером Java DSL Camel . Camel реализует это с помощью наследования реализации (такие методы, как «from» и «to» определены в классе RouteBuilder ), а не с помощью статического импорта (подход, часто используемый для DSL на основе Java.)

Несмотря на то, что анонимные экземпляры обычно передаются RouteBuilderв Camel Context, это не является обязательным требованием. Могут быть ситуации, в которых выгодно иметь автономные классы, которые расширяются RouteBuilderи экземпляры этих расширенных классов передаются в Camel Context. Я буду использовать этот подход, чтобы продемонстрировать все три случая, которые я описал ранее. Следующий листинг кода показывает класс, который расширяется RouteBuilder. Во многих случаях у меня был бы конструктор без аргументов, но в этом случае я использую конструктор, чтобы определить, какой тип передачи файлов должен поддерживаться маршрутом Camel.

В следующем листинге кода показан именованный автономный класс, который обрабатывает все три случая, показанные выше (копирование, копирование с архивированием входных файлов и перемещение). Это единственное расширение RouteBuilderпринимает перечисление в своем конструкторе, чтобы определить, как настроить конечную точку ввода.

package dustin.examples.camel;

import org.apache.camel.builder.RouteBuilder;

/**
 * Camel-based Route Builder for transferring files.
 * 
 * @author Dustin
 */
public class FileTransferRouteBuilder extends RouteBuilder
{
   public enum FileTransferType
   {
      COPY_WITHOUT_IMPACTING_ORIGINALS("C"),
      COPY_WITH_ARCHIVED_ORIGINALS("A"),
      MOVE("M");

      private final String letter;

      FileTransferType(final String newLetter)
      {
         this.letter = newLetter;
      }
 
      public String getLetter()
      {
         return this.letter;
      }
  
      public static FileTransferType fromLetter(final String letter)
      {
         FileTransferType match = null;
         for (final FileTransferType type : FileTransferType.values())
         {
            if (type.getLetter().equalsIgnoreCase(letter))
            {
               match = type;
               break;
            }
         }
         return match;
      }
   }

   private final String fromEndPointString;
   private final static String FROM_BASE = "file:C:\\datafiles\\input";
   private final static String FROM_NOOP = FROM_BASE + "?noop=true";
   private final static String FROM_MOVE = FROM_BASE + "?delete=true";

   public FileTransferRouteBuilder(final FileTransferType newFileTransferType)
   {
      if (newFileTransferType != null)
      {
         switch (newFileTransferType)
         {
            case COPY_WITHOUT_IMPACTING_ORIGINALS :
               this.fromEndPointString = FROM_NOOP;
               break;
            case COPY_WITH_ARCHIVED_ORIGINALS :
               this.fromEndPointString = FROM_BASE;
               break;
            case MOVE :
               this.fromEndPointString = FROM_MOVE;
               break;
            default :
               this.fromEndPointString = FROM_NOOP;
         }
      }
      else
      {
         fromEndPointString = FROM_NOOP;
      }
   }

   @Override
   public void configure() throws Exception
   {
      from(this.fromEndPointString).to("file:C:\\datafiles\\output");
   }
}

Этот блог продемонстрировал использование Camel для простой маршрутизации файлов из одного каталога в другой. Camel поддерживает множество других транспортных механизмов и форматов данных, которые здесь не показаны. Camel также поддерживает возможность трансформации маршрутизируемых сообщений / данных, что также здесь не показано. Этот пост был посвящен тому, что, вероятно, будет самым простым примером того, как применять Camel полезным способом, но Camel поддерживает гораздо больше, чем показано в этом простом примере.