Вы все еще работаете с интеграционными продуктами одного из типичных крупных интеграционных вендоров, таких как IBM и Tibco, и ищете более легкий подход? Затем эти две статьи о Mule и Apache ServiceMix могут послужить откровением для потенциала ESB с открытым исходным кодом. Если вы уже знакомы с Mule или Apache ServiceMix, эти статьи предоставят некоторое представление о новых возможностях последних версий этих ESB с открытым исходным кодом и покажут, как подходить к проектированию вашего интеграционного решения.
В этих двух статьях также будет предпринята попытка демистифицировать обсуждение между реализацией ESB на основе Java Business Integration (JBI) (Apache ServiceMix) и разработанной на заказ реализацией ESB (Mule). В этих двух статьях мы реализуем интеграционное решение с Mule и Apache ServiceMix, чтобы показать, что каждый из этих подходов имеет свои преимущества и что между этими двумя подходами действительно есть частичное совпадение.
В этой первой статье мы сфокусируемся на Mule, Mule 2.0, а точнее на последней версии проекта Mule. Вторая статья, посвященная Apache ServiceMix, будет доступна примерно через две недели.
Краткое введение в Mule 2.0
Прежде чем мы рассмотрим подход к разработке на основе шаблонов, давайте углубимся в архитектуру Mule 2.0. Если вы уже знакомы с Mule, вы должны заметить, что мы обсуждаем здесь архитектуру Mule 2.0, которая недавно была выпущена в качестве преемника версии Mule 1.4.x, и что архитектура немного изменилась между этими двумя версиями. , В нижней части этой статьи вы можете найти ссылку на страницу на сайте MuleSource, которая кратко объясняет различия между этими двумя версиями.
Хороший способ начать с архитектуры Mule 2.0 — посмотреть, как Mule обрабатывает сообщение. Это показано на рисунке 1.
[Img_assist | NID = 3181 | название = | убывание = | ссылка = нет | Align = нет | ширина = 351 | Высота = 272]
Рис. 1. Обзор типичного потока сообщений Mule, который получает сообщение по определенному каналу сообщений, выполняет логику интеграции с компонентом и входящими и исходящими маршрутизаторами и передает сообщение в целевой канал сообщений назначения.
На рисунке 1 показано, что для типичного потока сообщений Mule мы должны определить входящий маршрутизатор, который прослушивает определенный канал сообщений. Канал сообщений — это шаблон, описанный в известной книге Hohpe and Woolf «Шаблоны интеграции предприятий». В основном канал сообщений просто передает сообщение. Каналом сообщений может быть, например, очередь JMS, каталог файлов или соединение HTTP. Когда сообщение используется через входящий маршрутизатор, оно передается реализации компонента, которая обычно является классом POJO, разработанным вами, но также может быть компонентом Spring, реализацией сценариев или даже процессом BPEL. Ответ этого компонента будет отправлен на канал выходного сообщения через исходящий маршрутизатор.
Создайте поток сообщений Mule 2.0
Пока мы только что поговорили о теории. Чтобы сделать его немного более практичным и увлекательным, давайте рассмотрим некоторую конфигурацию Mule, которая показывает, как использовать сообщение, содержащее ваше имя, из очереди JMS, добавляет префикс «Hello» и затем перенаправляет сообщение в другую очередь JMS.
Конфигурация Mule, показанная в листинге 1, использует новую нотацию Mule 2.0. Для использования этой конфигурации вам необходим брокер Mule 2.0, который можно загрузить с веб-сайта MuleSource.
Листинг 1. Простой поток сообщений, настроенный для Mule 2.0
<mule xmlns="http://www.mulesource.org/schema/mule/core/2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:spring="http://www.springframework.org/schema/beans"
xmlns:jms="http://www.mulesource.org/schema/mule/jms/2.0"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.mulesource.org/schema/mule/core/2.0
http://www.mulesource.org/schema/mule/core/2.0/mule.xsd
http://www.mulesource.org/schema/mule/jms/2.0
http://www.mulesource.org/schema/mule/jms/2.0/mule-jms.xsd”>
<jms:activemq-connector name=”jmsCon” brokerURL=”tcp://localhost:61616”
<spring:bean id=”helloBean” class=”esb.example.HelloBean”>
<spring:property name=”prefix” value=”hello “ />
</spring:bean>
<model name=”helloModel”>
<service name=”helloService”>
<inbound>
<jms:inbound-endpoint queue=”in-queue” />
</inbound>
<component>
<spring-object bean=”helloBean” />
</component>
<outbound>
<outbound-pass-through-router>
<jms:outbound-endpoint queue=”out-queue” />
</outbound-pass-through-router>
</outbound>
</service>
</model>
</mule>
Пример из листинга 1 дает хорошее представление о функциональности, которую предоставляет Mule. Во-первых, вы можете увидеть, что очень легко подключить Mule к работающему брокеру ActiveMQ, чтобы вы могли обмениваться сообщениями JMS. Это делается с помощью элемента jms: activemq-connector. Кроме того, мы видим, что входящая часть потока сообщений определяется входящим элементом. В этом элементе мы можем определить входящую конечную точку или конкретные маршрутизаторы. В этом примере мы только что настроили входящую конечную точку, которая прослушивает очередь JMS. Обратите внимание, что у входной конечной точки есть определенное пространство имен jms. Этот префикс указывает на схему mule-jms. Эта схема определяет атрибут очереди для входящей конечной точки JMS, поэтому вы можете использовать завершение кода вашей IDE для создания этих элементов. Стандарт, не специфичный для технологии,Входящая конечная точка (как будут знать пользователи Mule версии 1.x) определяет атрибут адреса, в котором вы должны определить очередь JMS с префиксом протокола JMS, например, jms: // in-queue. Используя подход, основанный на схемах, вы получаете гораздо более понятный и простой способ определения входящей конечной точки для очередей, тем и всех других поддерживаемых технологий.
В примере также показана готовая интеграция со средой Spring. Хотя мы также можем указать класс POJO для компонента Mule, используя его имя класса, в этом примере показано использование дочернего элемента spring-object. Когда вы используете этот элемент, вы указываете Mule использовать Spring для разрешения указанного имени в качестве bean-компонента Spring. В этом случае мы ссылаемся на HelloBean, который также определен в листинге 1. Реализация класса HelloBean — это просто базовый POJO, как вы можете видеть в листинге 2.
Листинг 2. HelloBean, который используется в качестве компонента в примере потока
public class HelloBean {
private String prefix;
public String hello(String name) {
return prefix + name;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}
HelloBean определяет атрибут префикса, значение которого вводится из файла конфигурации Mule. Что интересно в реализации этого компонента, так как Mule определяет, какой метод вызывать? По умолчанию контейнер Mule проверяет реализацию компонента на наличие открытых методов с типом ввода, соответствующим типу полезной нагрузки сообщения. В этом примере полезной нагрузкой будет ваше имя как экземпляр String, поэтому два метода HelloBean , hello и setPrefixметоды, будут найдены контейнером Mule. Однако по умолчанию контейнер Mule сначала просматривает методы, которые возвращают значение, а не методы void. В этом случае это означает, что метод hello будет вызываться контейнером Mule. В архитектуре Mule это разрешение точки входа в вызов, и по умолчанию используется преобразователь точки входа в метод. Есть и другие доступные механизмы разрешения точек входа, вы даже можете написать свою собственную реализацию, если вам нужна более сложная логика.
Последняя часть конфигурации Mule направляет возвращаемое значение компонента HelloBean в очередь JMS вне очереди . В этом примере мы использовали простой исходящий проходной маршрутизаторэто просто передает сообщение определенной конечной точке. Mule также предоставляет маршрутизаторы на основе содержимого и многие другие для реализации более сложной логики маршрутизации, как мы увидим в более крупном примере позже.
Этот пример является очень простым примером. Однако он показывает использование тех же архитектурных компонентов, которые можно использовать для реализации сложной логики интеграции. В следующем разделе мы покажем вам больше возможностей Mule, реализовав более сложный случай.
Пример из практики: страховой брокер
Новая страховая компания, EasyInsurance, хочет предоставить потенциальным клиентам веб-сайт, который можно использовать для получения котировок от различных страховых компаний в зависимости от типа страховки, которую вы хотите. Когда веб-сайт будет размещен в Интернете, будет доступен только запрос на страхование путешествий и автомобилей, но в будущем EasyInsurance также намерена предоставить такую же функциональность для страхования жилья.
Когда запрос на страхование вводится через веб-сайт, запрос направляется страховым компаниям в зависимости от типа запроса на страхование. Количество страховых компаний также должно легко расширяться. Ответы страхового провайдера отображаются на веб-сайте, и у провайдера можно запросить договор страхования. На рисунке 2 показан обзор функциональности веб-сайта для отправки запроса страховым компаниям и того, как ответы будут отправлены обратно на веб-сайт.
[Img_assist | нидь = 3182 | название = | убывание = | ссылка = нет | Align = нет | ширина = 432 | высота = 270]
Рисунок 2 Обзор тематического исследования страхового брокера, показывающий сообщения, отправляемые поставщикам страхования в зависимости от типа запроса на страхование.
Еще одна проблема, которую нам необходимо решить в нашем интеграционном решении, заключается в том, что страховой компании budgetCar требуется отправка запросов в формате CSV через FTP (для простоты здесь мы будем использовать файловый коннектор), а для страхования LuxuryCar требуется XML файл через JMS. Компания «Страхование путешествий курорта» требует, чтобы все звонки осуществлялись с использованием веб-сервисов.
Шаблонный подход к дизайну
Большинство людей, которые работали в интеграционных проектах, вероятно, знакомы с книгой Грегора Хоупа и Бобби Вульфа «Шаблоны интеграции предприятия» (EIP). В этой книге показан ряд шаблонов проектирования, которые вы можете использовать для документирования, описания и решения ваших проблем интеграции. В следующих нескольких параграфах мы покажем, как вы можете использовать шаблоны, описанные в книге EIP, для описания тематического исследования страхового брокера.
Давайте сначала посмотрим на рисунок 3, который описывает часть запроса в представленном нами случае.
[Img_assist | NID = 3183 | название = | убывание = | ссылка = нет | Align = нет | ширина = 432 | Высота = 330]
Рисунок 3 На этом рисунке показан поток запросов решения по интеграции страхового брокера, описанного с использованием шаблонов корпоративной интеграции из книги EIP.
Таблица 1. Используемые шаблоны для потока запросов страхового примера.
Шаблон | Описание | |
Канал сообщений [img_assist | nid = 3184 | title = | desc = | link = none | align = left | width = 55 | height = 37] | Канал сообщений позволяет приложениям связываться друг с другом. | |
Адаптер канала [img_assist | nid = 3179 | title = | desc = | link = none | align = middle | width = 46 | height = 31] | Адаптер канала определяет, как вы можете подключиться к системе обмена сообщениями (например, JMS-брокер), чтобы вы могли получать и отправлять сообщения. | |
Маршрутизатор на основе содержимого [img_assist | nid = 3186 | title = | desc = | link = none | align = middle | width = 54 | height = 37] | Поскольку имя подразумевает основанный на содержимом маршрутизатор, маршрутизирует сообщения на основе содержимого сообщения. | |
Список получателей |
Иногда вы хотите отправить сообщение нескольким каналам одновременно. Список получателей предусматривает в этом. | |
Трансформатор |
Преобразователь используется, когда необходимо изменить формат сообщения, прежде чем его можно будет отправить получателю, или когда определен стандартный формат. | |
Конечная точка сообщения [img_assist | nid = 3180 | title = | desc = | link = none | align = middle | width = 55 | height = 32] | Конечная точка сообщения определяет соединение между приложением и каналом обмена сообщениями. |
Теперь давайте посмотрим, как эти шаблоны работают вместе, чтобы решить часть запроса нашего сайта страхования. Мы не будем показывать весь интерфейс, но начнем с запроса о страховке, полученного с веб-сайта EasyInsurance.
- Первое, что мы видим, это то, что веб-сайт использует «конечную точку сообщения» для отправки сообщения на определенный канал (в данном случае очередь JMS), которым управляет брокер.
- Эта очередь затем читается ESB с помощью «канального адаптера» JMS .
- Сообщение теперь маршрутизируется внутри ESB. Первый маршрутизатор — это «контентный маршрутизатор», который принимает сообщение и, в зависимости от типа запроса, автомобиля или поездки, направляет его к следующему компоненту.
- Если сообщение необходимо отправить нескольким страховым компаниям, используется список получателей, и перед тем, как сообщение действительно отправлено, оно сначала преобразуется в целевой формат сообщения с использованием «преобразователя» .
- «Трансформатор» уверил , что сообщение в формате получатель может работать, так что теперь все , что осталось сделать , это использовать другой «адаптер канала» , чтобы отправить сообщение в «канал сообщения» , и страховые компании может использовать «конечную точку сообщения» на своей стороне, чтобы прочитать запрос из «канала сообщений» .
Помимо использования корпоративных интеграционных шаблонов, поток запросов на рисунке 3 также показывает четкое разделение между различными логическими границами интеграционного решения. Конечно, ESB показан как логическая граница, но также брокер сообщений (поставщик JMS), веб-сайт и конечные точки страховых компаний разделены в разных границах. Также обратите внимание, что на рисунке 3 показан только поток запросов решения по изучению страхового случая. Чтобы сохранить дизайн чистым и понятным, часто лучше разделять потоки запросов и ответов в разных схемах проектирования. На рисунке 4 показан ответ интеграционного решения страхового брокера.
[Img_assist | NID = 3188 | название = | убывание = | ссылка = нет | Align = нет | ширина = 432 | Высота = 413]
Рисунок 4 На этом рисунке показан поток ответов решения по интеграции страхования, описанного с использованием шаблонов интеграции предприятия из книги EIP.
Схема проектирования потока ответов, показанная на рисунке 4, содержит множество шаблонов, которые уже использовались при разработке потока запросов, здесь только шаблон агрегатора. Агрегатор используется для объединения сообщений о страховых ответах от страховых компаний BudgetCar и LuxuryCar в один ответ, который можно отобразить на веб-сайте EasyInsurance. Чтобы иметь возможность агрегировать ответные сообщения от двух компаний по страхованию автомобилей, нам нужен какой-то корреляционный идентификатор, который связывает эти ответные сообщения с исходным сообщением запроса на страхование. В этом примере мы используем идентификатор запроса в сообщении запроса страховки, которое также доступно в сообщении страхового ответа.
Это вводит еще один важный шаг на этапе разработки интеграционного решения: дизайн сообщения. Поскольку Mule также может использовать объекты Java в качестве типа полезной нагрузки сообщений, мы будем использовать сообщения на основе Java для связи между веб-сайтом EasyInsurance и брокером JMS и Enterprise Service Bus. В листинге 3 показаны элементы трех типов сообщений, задействованных в этом интеграционном решении.
Листинг 3. Обзор классов Java, представляющих запросы на страхование и ответные сообщения, используемые в реализации брокера интеграции.
public class CarInsuranceRequest implements Serializable {
private String requestID;
private String numberPlate;
private String carType;
private int buildYear;
private boolean companyCar;
private Date startDate;
}
public class TravelInsuranceRequest implements Serializable {
private String requestID;
private String destinationCountry;
private int numberOfPersons;
private Date startDate;
private Date endDate;
}
public class InsuranceResponse implements Serializable {
private String requestID;
private String responseID;
private String insuranceCompanyName;
private float price;
}
Как видно из листинга 3, в этом примере сообщения хранятся очень просто. Важными частями проекта сообщения для интеграционного решения являются различие между CarInsuranceRequest и TravelInsuranceRequest, которое используется для маршрутизации на основе содержимого, и атрибутом requestID, который будет использоваться для агрегирования сообщений с ответами на страхование автомобиля.
Обратите внимание, что пока мы еще не говорили о конкретных инструментах. В дизайне, который мы сделали, мы только что описали, что нужно сделать. Теперь мы можем передать поток интеграции и проектирование сообщения разработчику или специалисту по интеграции, которые могут реализовать его с использованием определенной технологии. В этой статье мы реализуем это сами и будем использовать Mule 2.0 для этого.
Реализация страхового брокера с мулом: часть запроса
Как вы уже видели, это довольно сложная проблема интеграции, которую нам нужно решить. У нас есть разные типы форматов, которые нам нужно поддерживать, разные технологии, к которым нам нужно подключиться, и даже объединяем события из страхования автомобилей обратно в одно сообщение перед возвратом на сайт. Мы начнем с части запроса этого сценария и проведем вас через этот шаг за шагом.
Первое, что нам нужно сделать, это прочитать сообщение из очереди JMS, а затем использовать маршрутизатор на основе содержимого, чтобы выбрать сообщение в качестве следующего пункта назначения. Этот код показан в листинге 4.
Листинг 4. Чтение из очереди JMS и использование основанного на контенте маршрутизатора для определения следующего пункта назначения
<!--omitted the Mule namespaces -->
<mule>
<jms:activemq-connector name="jmsCon" brokerURL="tcp://localhost:61616"/>
<model name=”InsuranceModel”>
<service name="JMSInService">
<inbound>
<jms:inbound-endpoint queue="insurance.in" />
</inbound>
<outbound>
<forwarding-catch-all-strategy>
<jms:outbound-endpoint queue="insurance.invalid"/>
</forwarding-catch-all-strategy>
<filtering-router>
<vm:outbound-endpoint path="car.insurances"/>
<expression-filter evaluator="payload-type"
expression="dzone.mule.model.CarInsuranceRequest"/>
</filtering-router>
<filtering-router>
<vm:outbound-endpoint path="travel.insurances"/>
<expression-filter evaluator="payload-type"
expression="dzone.mule.model.TravelInsuranceRequest"/>
</filtering-router>
</outbound>
</service>
</model>
</mule>
В листинге 4 вы можете увидеть один сервис mule и конфигурацию подключения к activeMQ. Входящая часть этого сервиса mule читает сообщения из очереди jms с именем «insurance.in» и использует соединитель для activeMQ, поскольку это единственный указанный нами соединитель.
После прочтения сообщения из очереди оно обрабатывается исходящими маршрутизаторами. В этом случае мы проверяем класс запроса, используя фильтр выражений типа полезной нагрузки. Если фильтр соответствует, запрос отправляется на указанную внутреннюю (VM) конечную точку. Если ни один из фильтров не совпадает, сообщение отправляется в очередь «Insurance-invalid», которая в нашем сценарии служит очередью недействительных сообщений.
Мы определили тип сообщения и отправили его на конкретную внутреннюю конечную точку, поэтому теперь мы можем использовать это сообщение для вызова двух служб страхования автомобилей и единой службы страхования путешествий.
Давайте сначала посмотрим, как вызвать две страховые компании. Если вы посмотрите на рисунок 3, вы увидите, что мы хотим использовать для этого файл и JMS. В листинге 5 показана конфигурация этого сервиса и необходимые трансформаторы. Обратите внимание, что мы разделили конфигурацию Mule, чтобы объяснить ее порциями, но вся конфигурация Mule, показанная в этой статье, реализована в одной конфигурации Mule, файле insurance-config.xml.
Листинг 5. Отправьте запрос на страхование автомобиля в две службы страхования автомобилей.
<mule>
<jms:object-to-jmsmessage-transformer name="ObjectToJMS"/>
<xm:object-to-xml-transformer name="InsuranceToXML"/>
<xm:xml-to-object-transformer name="XMLToInsurance"/>
<custom-transformer name="InsuranceToCSV"
class="dzone.mule.transformer.CSVTransformer"/>
<!-- repeated the model element to make it comprehensible -->
<model name=”InsuranceModel”>
<service name="SendCarInsurancesService">
<inbound>
<vm:inbound-endpoint path="car.insurances"/>
</inbound>
<outbound>
<multicasting-router>
<file:outbound-endpoint path="budgetCarIn"
outputPattern="${DATE:HH-mm-ss}-carinsurance.csv">
<transformer ref="InsuranceToCSV"/>
</file:outbound-endpoint>
<jms:outbound-endpoint queue="luxurycar.send">
<transformer ref="InsuranceToXML"/>
<transformer ref="ObjectToJMS"/>
</jms:outbound-endpoint>
</multicasting-router>
</outbound>
</service>
</model>
</mule>
В листинге 5. вы можете видеть, что мы сначала настроили нужные нам трансформаторы. В начале этой статьи мы упоминали, что компания BudgetCar требовала, чтобы сообщение было в формате CSV, а компания LuxuryCar требовала XML. Для этого мы создали специальный преобразователь, который принимает java CarInsuranceRequest и преобразует содержимое в CSV. Этот преобразователь показан в листинге 6.
Листинг 6. Пользовательский преобразователь для преобразования CarInsuranceRequest в строку CSV.
public class CSVTransformer extends AbstractTransformer {
protected Object doTransform(Object payload, String encoding)
throws TransformerException {
if(!(payload instanceof CarInsuranceRequest)) {
throw new TransformerException(this, new IllegalArgumentException(
"only car insurance requests can be transformed"));
}
CarInsuranceRequest request = (CarInsuranceRequest) payload;
return new StringBuffer()
.append(request.getRequestID())
.append(",")
.append(request.getNumberPlate())
.append(",")
.append(request.getCarType())
.append(",")
.append(request.getBuildYear())
.append(",")
.append(request.getStartDate())
.toString();
}
}
Для budgetCar insuranceCompany это означает, что при конфигурации из листинга 5. входящее java-сообщение преобразуется в CVS, а затем отправляется в каталог файловой системы.
Для компании LuxuryCar Insurance нам необходимо преобразовать сообщение в XML. Для этого мы просто использовали стандартные трансформаторы, которые предоставляет мул. Это будет проверять Java-бин и использовать его для создания XML-сообщения. Последнее, что мы делаем перед тем, как отправить сообщение в очередь JMS, — это убедитесь, что сообщение является объектом JMSObject. Если мы не используем преобразователь XML, нам не нужно предпринимать этот последний шаг, поскольку тогда Мул будет использовать преобразователь по умолчанию JMS для преобразования сообщения в объект JMSObject. Но так как мы определили преобразователи в конечной точке, мы переопределяем конфигурацию по умолчанию, поэтому нам нужно также явно добавить преобразователь ObjectToJMS.
Ну, мы почти закончили с частью запроса. Единственное, что нам нужно сделать, это настроить вызов веб-службы для страхования путешествий курорта. Эта конфигурация показана в листинге 7.
Листинг 7. Мул-конфигурация, которая вызывает веб-сервис
<service name="travelService">
<inbound>
<vm:inbound-endpoint path="travel.insurances"/>
</inbound>
<outbound>
<chaining-router>
<outbound-endpoint
address="wsdl-cxf:http://localhost:8080/services/TravelInsuranceService?
wsdl&method=getTravelInsurance">
<custom-transformer
class="dzone.mule.custom.TravelRequestToWebserviceRequestTransformer"/>
<properties>
<spring:entry key="service"
value="{http://dzone.com/travelInsurance}TravelInsuranceServiceImplService">
</spring:entry>
<spring:entry key="port"
value="{http://dzone.com/travelInsurance}TravelInsuranceServiceImplPort">
</spring:entry>
</properties>
</outbound-endpoint>
<jms:outbound-endpoint queue="insurance.out">
<transformer ref="WSToResponseTransformer"/>
<transformer ref="ObjectToJMS"/>
</jms:outbound-endpoint>
</chaining-router>
</outbound>
</service>
В конфигурации из листинга 7 видно, что мы снова создали сервис Mule. Эта служба прослушивает внутреннюю конечную точку vm «travel.insurances», на которую запросы на страхование путешествий маршрутизируются маршрутизатором из листинга 4. Когда здесь получено сообщение, выполняется исходящая часть этой службы. В этом случае мы использовали chaining-router. Этот маршрутизатор сначала вызовет первую указанную исходящую конечную точку и будет использовать результат вызова этой конечной точки в качестве параметра для следующей конечной точки. Поэтому в этом случае мы сначала вызываем веб-сервис, а затем отправляем результат этого вызова веб-сервиса в указанную конечную точку JMS, где веб-сайт прослушивает. Для вызова webservice мы делаем вызов на основе указанного файла WSDL.Кроме того, мы также настраиваем службу и порт из того WSDL, который мы хотим вызвать. Последнее, что нам нужно настроить, — это метод, который мы хотим вызвать. Мы сделали это как атрибут адреса исходящей конечной точки. Мы не будем вдаваться в подробности того, как был создан веб-сервис и т. Д. Если вы заинтересованы в коде, см. Раздел ресурсов в нижней части этой статьи, где вы можете скачать все источники и ресурсы этого сценария.
Хорошо, что завершает часть запроса. Мы покажем вам, как мы можем использовать контентный маршрутизатор, чтобы определить, куда отправлять запрос. Мы использовали список получателей для отправки запроса на страхование автомобиля двум компаниям на двух разных видах транспорта в двух разных форматах. Мы также показали, как можно вызвать веб-службу страхования путешествий и как ответ этого веб-службы направляется обратно в очередь JMS, где прослушивает веб-сайт. Итак, мы уже сделали очень маленький раздел ответной части, так как мы уже перенаправили ответ от веб-сервиса обратно в очередь, которую слушает веб-сайт.
Теперь давайте посмотрим, как мы можем реализовать ответы компаний автострахования.
Реализация страхового брокера с Mule: ответная часть
Для завершения ответной части нам нужно только получить ответы от двух компаний по страхованию автомобилей, собрать их и отправить обратно в очередь, которую прослушивает веб-сайт. Как мы уже упоминали, компания BudgetCar работает с файлами CSV через соединение file / ftp, а LuxuryCar использует XML через очередь JMS. Таким образом, помимо агрегации нам нужно преобразовать входящие ответы в объекты Java.
Давайте посмотрим, как выглядит служба, которая будет получать запросы от этих двух страховых компаний.
Листинг 8. Конфигурация Mule, которая получает запросы от бюджетной компании по страхованию автомобилей и от компании по страхованию автомобилей класса люкс.
<service name="ReceiveCarResponseService">
<inbound>
<jms:inbound-endpoint queue="luxurycar.receive">
<transformer ref="JMSToObject"/>
<transformer ref="XMLToInsurance"/>
<transformer ref="CorrelationTransformer" />
</jms:inbound-endpoint>
<file:inbound-endpoint path="budgetCarOut">
<file:file-to-string-transformer />
<transformer ref="CSVToResponse" />
<transformer ref="CorrelationTransformer" />
</file:inbound-endpoint>
</inbound>
<outbound>
<outbound-pass-through-router>
<vm:outbound-endpoint path="aggregator.in" />
</outbound-pass-through-router>
</outbound>
</service>
В листинге 8 вы видите службу, которая прослушивает две входящие конечные точки. Конечная точка jms получает сообщения от страховой компании класса люкс, а конечная точка файла — от бюджетной. Для обоих полученных сообщений мы делаем пару преобразований. Для роскошных ответов мы сначала создаем объект java из объекта JMS (помните, что мы переопределили поведение по умолчанию, поэтому мы должны явным образом преобразовать из JMS в объект), а так как объект является XML, мы преобразуем XML в java объект страхования. Для бюджетных сообщений мы делаем то же самое, только на этот раз мы получаем файл CSV, который необходимо преобразовать.
Последнее преобразование является особенным. Мы добавляем этот преобразователь, поскольку хотим сопоставить сообщения, полученные из бюджета и компании класса люкс, в одно сообщение. Для этого нам нужен некоторый идентификатор, который Мул может использовать для определения того, что собирать. Давайте посмотрим на код для этого преобразователя.
Листинг 9. Корреляционный преобразователь, который устанавливает свойства корреляции Мула
public class ResponseCorrelationTransformer
extends AbstractMessageAwareTransformer {
@Override
public Object transform(MuleMessage message, String outputEncoding)
throws TransformerException {
message.setCorrelationGroupSize(2);
Object obj = message.getPayload();
InsuranceResponse response = (InsuranceResponse) message.getPayload();
String requestID = response.getRequestID();
message.setCorrelationId(requestID);
return message;
}
}
Как видно из листинга 9, мы получаем requestID из сообщения и устанавливаем Mule correlationID для этого requestID. В то же время мы также установили, что при получении двух ответов с этим идентификатором мы закончили корреляцию. Это устанавливается через свойство correlationGroupSize в сообщении.
Таким образом, всякий раз, когда получен ответ, этот преобразователь удостоверится, что вышеупомянутые свойства установлены. Теперь, почему мы это сделали?
Ну, мы сделали это, чтобы мы могли использовать стандартный агрегатор Mule для агрегирования сообщений для нас. Это показано в листинге 10.
Листинг 10. Конфигурация агрегатора мулов
<service name="insuranceAggregator">
<inbound>
<vm:inbound-endpoint path="aggregator.in" />
<collection-aggregator-router />
</inbound>
<outbound>
<outbound-pass-through-router>
<jms:outbound-endpoint queue="insurance.out" />
</outbound-pass-through-router>
</outbound>
</service>
Этот небольшой фрагмент кода из листинга 10 является полной конфигурацией агрегатора. Мы говорим mule для прослушивания внутренней конечной точки, на которую отправляются ответы (см. Листинг 7). После получения сообщения оно будет передано маршрутизатору-агрегатору. Этот стандартный компонент mule использует два свойства, которые мы установили в листинге 9. Поэтому, когда первое сообщение получено, этот агрегатор проверит ожидаемый размер (в нашем случае 2) и requestID. Затем он проверит, сколько сообщений с этим ID он уже получил. Поскольку это первый, агрегатор будет просто ждать. Для второго сообщения те же шаги повторяются. Но так как у нас теперь есть оба наших сообщения, агрегатор помещает их в список и передает их на исходящий маршрутизатор.
Этот исходящий маршрутизатор просто отправляет агрегированные данные в настроенную конечную точку, которая является очередью JMS.
И это все для ответной части!
Реализация страхового брокера с мулом: резюме
Давайте быстро подведем итоги того, что мы сделали. Для части запроса мы получили сообщения через JMS. В зависимости от типа полученного сообщения мы использовали маршрутизатор на основе содержимого, чтобы определить, куда отправить сообщение. Если в сообщении содержался запрос на страхование путешествий, сообщение отправлялось на веб-службу туристического агентства. Если запрос был запросом автострахования, сообщение было отправлено двум страховым компаниям.
Мы также применили несколько шагов преобразования к сообщениям. Мы использовали пару встроенных трансформаторов Mule, но и сами создали пару трансформаторов. Это было необходимо, поскольку наши компании по страхованию автомобилей запрашивали информацию не так, как мы использовали ее внутри страны.
Ответ от веб-службы путешествий был отправлен обратно в очередь ответов, которую прослушивал веб-сайт. Однако ответы от компаний по страхованию автомобилей были агрегированы на основе их requestID. Для этого мы использовали стандартный агрегатор сбора Mule и преобразователь, чтобы установить правильные свойства сообщения.
Если вы хотите проверить это, скачайте исходники этой статьи. Он также содержит небольшой тест JUnit, который можно использовать для имитации веб-сайта и запуска решения по интеграции. Имейте в виду, что вам нужно будет загрузить ActiveMQ отдельно, чтобы весь пример работал.
Вывод
In this article we’ve shown how you can implement an integration design with Mule. We’ve first shown you a general description of the problem we faced, and how you can use EIPs to describe this problem in a technology independent manner. We’ve also shown how easy it is with Mule to implement this example. As you’ve seen the Mule configuration is pretty much a one-on-one copy of figure 3 and figure 4. Mule uses the same terminology as is used for the EIPs which makes implementing these scenarios easy. An additional advantage is that the Mule configuration is very readable and self-explaining.
We hope you enjoyed this first introduction into Mule 2.0 and in the pattern based integration development approach. In a couple of weeks we’ll also show how to implement this same scenario using Java Business Integration (JBI) with Apache ServiceMix.
Дополнительные ресурсы
1. Мул — http://mule.mulesource.org
2. Мул 2.x против Мула 1.x — http://mule.mulesource.org/display/MULE2INTRO/Whats+New+in+Mule+2.0
3. Шаблоны корпоративной интеграции — http://www.enterpriseintegrationpatterns.com
4. Загрузка Mule 2.0.1 — http://mule.mulesource.org/display/MULE/Download
5. Загрузка исходного кода статьи — http: //www.esbinaction .com / файлы / dzonemule.zip
Йос Дирксен
Йос — архитектор программного обеспечения, работающий в Atos Origin и специализирующийся на интеграции предприятий. Джос является соавтором будущей книги Мэннинга «ESB с открытым исходным кодом в действии» ( http://www.manning.com/rademakers ). Он часто выступает на конференциях Java, таких как JavaPolis, JavaZone, JavaOne и NL-JUG, о проектах корпоративной интеграции с открытым исходным кодом, таких как Mule, ServiceMix, jBPM и Axis2.
Тийс Радемакерс
Tijs — разработчик программного обеспечения, работающий на Atos Origin и специализирующийся на интеграции предприятия. Tijs является соавтором будущей книги Мэннинга «ESB с открытым исходным кодом в действии» ( http://www.manning.com/rademakers ). Он часто выступает на конференциях по Java, таких как JavaPolis, JavaZone, JavaOne и NL-JUG, о проектах корпоративной интеграции с открытым исходным кодом, таких как Mule, ServiceMix, Apache Synapse и Apache Tuscany.