Организация B2B интеграции с использованием 1С и JMS
В данной статье будет рассмотрен, пример организации автоматизированного взаимодействия Business2Business при помощи шины сообщений ActiveMQ (реализация Java Message Service). Основное внимание будет уделено специфичным вещам, которые требуются при интеграции разнородных систем с помощью шины сообщений: промежуточной обработке и преобразованию сообщений, маршрутизации и вопросам безопасности.
- Описание
- Подробнее
Описание
Из Википедии.
Основная задача систем В2В — повышение эффективности работы компаний на В2В-рынке за счёт снижения затрат на подготовку торговых процедур и расширения географии бизнеса до масштаба всего мира.
В задачи B2B систем также входит:
- организация взаимодействия между предприятиями — быстро и удобно
- построение защищённых надёжных каналов обмена информацией между фирмами
- координация действий предприятий и совместное их развитие на основе информационного обмена
Взаимодействие может быть связано с торговлей, обменом технологиями, опытом, инвестиционной деятельностью и.т.д.
Общие соображения.
Аббревиатуру B2B очень любят разные гламурные консультанты, евангелисты от IT и прочие впариватели и профессиональные гипнотизеры «серьезных бузинес дядей». А что же за ней стоит? Из чего состоит B2B? А состоит она ровно из двух частей: административной (договориться о взаимодействии, принять необходимые административные шаги) и технической (согласовать и реализовать техническую сторону вопроса). В самом просто виде B2B реализуется при помощи электронной почты, офисного пакета и/или сайта с закрытой зоной (взаимодействие поставщика и менеджера по закупками — переписка, анализ прайсов, согласование, обмен документами и пр.) Данный вариант предельно прост, но в нем очень много ручной работы.
Между тем, у обеих сторон обычно есть свои информационные системы, в которых отражены их бизнес-процессы, и, так и напрашивается, автоматизировать это взаимодействие, приземляя его непосредственно на информационные системы взаимодействующих предприятий. К примеру, организация сразу может получить информацию о номенклатуре поставщика, и привязать ее к своей, узнать об остатках и их прогнозируемых изменениях, ценах и пр. А потом, исходя из этих данных, в полуавтоматическом режиме сформировать заказ на нужное число, показать его менеджеру по закупкам и, после исправления и одобрения, заказ приземлится напрямую в ИС поставщика…. Ляпота…. 🙂
Поле для усовершенствований и улучшений со всех сторон тут бесконечное, но можно выделить ряд принципиальных требований, которым должны соответствовать такие решения с технической стороны:
1. Защищенность от несанкционированного вмешательства и преднамеренных деструктивных воздействий.
2. Устойчивость к изменениям, чтобы при добавление еще одной стороны не пришлось выкидывать всю систему.
3. Надежность, имеется в виду защищенность от сбоев и непреднамеренных ошибочных действий.
4. Оперативность.
5. Расширяемость и интегрируемость с другими системами.
Инструментарий.
1. Netbeans 6.5/6.7 + жаба + ActiveMQ (я взял снапшот версии 5.3)
2. SharpDevelop 3.1 + .NET 3.5 SP1
3. 1С 8.1
Краткое описание примера.
В качестве центрального элемента в примере будете выступать шина сообщений ActiveMQ, реализующая спецификацию JMS с прикрученной «искаропки» реализацией Enterprise Intergration Patterns, в виде апачевского проекта Camel. Более подробно про шины сообщений можно почитать в статье «Организация обмена с помощью шины сообщений MSMQ»(1), здесь же я сразу перейду к описанию возможностей Camel’а, вот лишь некоторые:
1. Описания маршрутов движения сообщений в конфигурационном файле — позволяет легко изменять их без кодирования.
2. Простота написания компонентов, обрабатывающих сообщениях на этих маршрутах (минимум кода, массовое использования аннотаций жабы, Spring в качестве IoC фреймворка) — все это позволяет легко разрабатывать различные фильтры, преобразователи, ретранслятор,а также легко устанавливать их, достаточно кинуть JAR в каталог lib и можно начинать использовать компоненты в конфигурационном файле.
3. Готовая реализация шаблонов интеграции.
В данном примере шина будет использоваться для сбора информации с внешней системы, ее преобразования и приземления в 1С, а также для отправки ответных сообщений по обратном маршруту.
Роль внешней системы будет играть набор скриптов на Питоне (красноглазики захватили контору-контрагента 🙂 ).
Вопросы безопасности будут решены следующим образом:
1. Аутентфикация при доступе к шине со стороны внешней системы будет проверятся по паролю – в примере будет использоваться самый простой плагин для аутентифакции, с явным заданием пароля в конфигурационном файле ActiveMQ.
2. Защищенность канала будет осуществляться путем организации SSH туннеля (пробрасывание портов) — в примере реализовано не будет.
Основной сценарий взаимодействия имеет вид:
1. Контрагент формирует заказ в виде XML(исходим из того, что коды номенклатуры ему известны) и помещает его в некую очередь шины сообщений.
2. Заказ двигается по некоторому маршруту, подвергаясь обработке и преобразованию, например, к схеме CommerceML, хотя в примере все будет гораздо более упрощенно — просто будет добавляться код контрагента. В конце-концов заказ попадает в очередь, которую, с помощью адаптера, опрашивает 1С.
3. В 1С обеспечивается прием и сохранение заказа в виде документа, с возможностью заполнения полей, исходя из которых формируется ответ. Ну и наконец, собственно отправка ответа на выбранный заказ.
4. Ответ на заказ двигается по обратному маршруту, который определяется исходя из кода контрагента, если задан код, для которого не определен маршрут — сообщение отправляется по маршруту обработки ошибок маршрутизации (в примере, просто сохраняется в виде файла на жесткий диск).
Предложенная схема удовлетворяет (в первом приближении) всем вышеприведенным требованиям:
1. Она обеспечивает защищенный доступ с аутентфикацией.
2. Гибкость за счет полной развязки систем (они видят только шину) и простоты изменения маршрутов сообщений.
3. Возможность определение для каждого контрагента свое входящего и исходящего маршрута, с уникальной обработкой и преобразованием сообщений.
4. Надежность доставки, за счет транзакционности шины и сохранения сообщений в постоянном хранилище.
Схема входящих и исходящих маршрутов, рассмотренных в примере, будет иметь вид:
здесь, голубым цветом обозначены очереди и другие штатные элементы, а светло-зеленым — компоненты, в данном случае, компонент осуществляющий преобразования XML.
Общая схема будет иметь вид:
здесь, зеленым цветом обозначены входящие маршруты, а желтым — исходящие.
Примечание. В данном примере будет реализовано только верхняя часть схемы, пример реализации нижней части есть в статье про обмен через MSMQ(1). Также входящий маршрут для 1С в примере явно не используется, сообщения сразу передаются на очередь, которую опрашивает 1С.
Ограничения примера.
1. В примере не используется SSH-туннель.
2. В примере реализована чисто умозрительная схема обработки заказов, с самой простой структурой XML-сообщения.
3. В примере реализован упрощенный вариант обработки ошибок (в частности, ошибок маршрутизации) — они просто перенаправляются в специальную очередь, а потом сохраняются в файлы.
4. В примере используется снапшот ActiveMQ 5.3.
5. В ActiveMQ используется самый простой плагин для аутентификации — имя пользователя и пароль задаются в явном виде в конфигурации.
Реализация.
В данном примере используется расширенная библиотека адаптеров из (1), в нее добавлен AcitveMQAdapter, все с тем же интерфейсом:
[ComVisible(true)]
public interface IAdapter : IDisposable
{
void SetParameter(string _name, string _value);
void ClearParameters();
void SendFile(string _text);
void Send(string _text);
bool HasMessage();
string Receive();
void Start();
void Stop();
void Begin();
void Commit();
void Rollback();
}
Реализация обработки и трансформации сообщений вынесена в отдельный Java проект message-processing. Ключевое место в нем занимают классы ErrorConsumer (содержит компоененты-потребители, обрабатывающие сообщения попавшие в очереди для обработки ошибок) и XslProcessor, который выполняется XSL преобразование сообщений. Также в проект входит набор юнит-тестов. Рассмотрим в качестве примере один из методов класса ErrorConsumer:
@Consume(uri = «activemq:routeError»)
public void onRouteError(byte[] _message)
{
try
{
saveToFile(getUniqueFileName(«routeError»), _message);
}
catch (Throwable _t)
{
logger.log(Level.SEVERE, «Fatal exception in ErrorConsumenrt», _t);
}
}
как видно из кода, с помощью аннотации явно указано, из какой очереди должен извлекать данные этот метод (routeError), о его вызове позаботится Camel.
Переходим к рассмотрению конфигурационного файла activemq.xml, в нем есть три важных участка:
во-первых, это конфигурирования аутентификации и авторизации
<plugins>
<authorizationPlugin>
<map>
<authorizationMap>
<authorizationEntries>
<authorizationEntry queue=«>» read=«admins,users» write=«admins,users» admin=«admins,users»/>
<authorizationEntry topic=«ActiveMQ.Advisory.>» read=«guests,users» write=«guests,users» admin=«guests,users»/>
</authorizationEntries>
</authorizationMap>
</map>
</authorizationPlugin>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username=«test» password=«test» groups=«users»/>
<authenticationUser username=«system» password=«manager» groups=«admins,users»/>
</users>
</simpleAuthentincationPlugin>
</plugins>
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=«>» memoryLimit=«5mb»/>
<policyEntry topic=«>» memoryLimit=«5mb»>
<dispatchPolicy>
<strictOrderDispatchPolicy/>
</destinationPolicy>
<subscriptionRecoveryPolicy>
<lastImageSubscriptionRecoveryPolicy/>
</subscriptionRecoveryPolicy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
во-вторых, настройка маршрутов, и в-третьих, объявление используемых компонентов, их здесь полностью приводить не буду, ибо надоело бороться с разукрашкой, скажу лишь что секция описания маршрутов полностью совпадает с первым рисунком, а в качестве примера, приведу часть исходящего маршрута:
<!— OneC outbound route —>
<route>
<from uri=«activemq:oneCOut»/>
<choice>
<when>
<xpath>//contr-id = ‘1’</xpath>
<to uri=«activemq:contr1OutTransform»/>
</when>
<otherwise>
<to uri=«activemq:routeError»/>
</otherwise>
</choice>
</route>
как видите, здесь все довольно прозрачно, маршрут определяется по коду контрагента, в случе если для данного кода контрагента не находится подходящего маршрута — сообщение направлется в очередь ошибок маршрутизации, где его и дожидается рассмотренный выше компонент ErrorConsumer. В реальной системе безусловно небходимо будет предусмотреть возможность повторной отправки такого сообщения, например, если маршрут для данного контрагента будет объявлен в будущем.
Рассматривать подробно базу 1С и питоновские скрипты тоже смысла нет: там все очень просто и примитивно (справочники «Номенклатура» и «Контрагенты», документ «Заказ», да обработка «СогласованиеЗаказов»; в скриптах — скрипт на отправку и скрипт на получение).