Статьи

От HTTP к ESB – Новый шлюз HTTP на основе сервлетов JBossESB 4.7


Одной из основных функций, выполняемых JBossESB, является маршрутизация сообщений между службами. (Помните, что в ESB все является либо сообщением, либо службой.) Сообщения, которые обрабатывает JBoss ESB, соответствуют org.jboss.soa.esb.message.Message. Конечные точки службы, которые могут обрабатывать сообщения в этом формате, описаны как «поддерживающие ESB». Это хорошо для сервисов и приложений, которые были разработаны и написаны с учетом этого формата сообщений, но как насчет других сервисов, включая унаследованные приложения, которые взаимодействуют через другие форматы данных, отличные от ESB?

JBossESB обрабатывает соединяющиеся сервисы, которые обмениваются сообщениями в форматах, отличных от ESB, через свои шлюзы-слушатели. Эти прослушиватели направляют входящие сообщения извне ESB в службы ESB. Набор слушателей шлюза ESB (обычно называемый «шлюзами») поддерживает различные форматы сообщений, такие как файлы, FTP и JMS. Эти шлюзы принимают сообщения в формате, не поддерживающем ESB, на ESB, а затем преобразуют их (фактически, они переносят полезную нагрузку сообщения) в сообщения, поддерживающие ESB, перед отправкой их в конвейер действий их службы.

В этой статье мы рассмотрим новый HTTP-шлюз JBossESB 4.7 («http-gateway»).
[1]

Вы используете http-шлюз, чтобы «выставить» ESB-незнакомую конечную точку на ESB. Другими словами, http-шлюз позволяет взаимодействовать со службами ESB через конечные точки HTTP в привычном формате, используемом сервлетами Java. Этот подход, основанный на сервлетах, становится возможным благодаря http-шлюзу, использующему HTTP-контейнер JBossESB Server или JBoss Application Server, как любой сервлет. Это означает, что многие свойства конфигурации HTTP, такие как адреса портов, уже обработаны для вас. Вам не нужно создавать полную конфигурацию HTTP для вашего http-шлюза, так как многие конфигурации работают прямо из коробки. Это согласуется с другими функциями JBossESB, такими как богатый набор готовых действий.
[2]

Очень простой пример

Давайте кратко рассмотрим очень простую конфигурацию http-шлюза. Далее мы рассмотрим варианты использования http-шлюза позже в этом посте. Для начала давайте начнем с малого. Вот определение сервиса, взятое из руководства пользователя JBossESB
[3], которое вы создадите в файле jboss-esb.xml вашего приложения JBossESB:

  <service category="Vehicles" name="Cars" description="" invmScope="GLOBAL">
<listeners>
<http-gateway name="Http" />
</listeners>
<actions mep="RequestResponse">
<!-- Service Actions.... -->
</actions>
</service>

Как и многие другие вещи с JBossESB, вы можете многое сделать с небольшим. Давайте рассмотрим этот пример построчно:

  • Строка 1: название сервиса и категория используются для дифференциации сервисов. Каждый сервис имеет категорию и имя атрибута. JBossESB использует эти атрибуты для регистрации конечных точек слушателей службы (слушателей шлюза или ESB-осведомленных) в реестре службы. Транспорт InVM позволяет службам взаимодействовать с использованием той же JVM и без необходимости проходить через второго поставщика, не являющегося шлюзом. Это делает вещи более эффективными, поскольку сервисы не используют никаких сетевых протоколов между экземплярами JVM. Значение «GLOBAL» указывает, что эта служба может быть вызвана с использованием транспорта InVM с использованием той же JVM.
  • Строка 3: вот определение шлюза http.
  • Строка 5: Помните, что, поскольку шлюз основан на сервлетах, ему требуется шаблон обмена сообщениями запроса / ответа (или, для краткости, «mep»).
  • Строка 6: И вот где будет определен порядок действий.

Просто, правда? Прежде чем мы продолжим, вы заметили, что здесь нет? Чувак, где мой поставщик услуг?

Поскольку поставщик не определен, служба использует HTTP-провайдера ESB по умолчанию. И, поскольку отсутствует идентификатор ссылки на шину (элемент busrefid в определении провайдера, а затем ссылка в других местах в файлах jboss-esb.xml), ESB создает конечную точку HTTP, которую он предоставляет из этих полей:

     http://<host>:<port>/<.esbname>/http/Vehicles/Cars

Хост и номер порта поступают с сервера ESB. Токен <.esbname> — это фактическое имя развернутого архива .esb, за исключением расширения .esb. Обратите внимание, что хотя эта строка является URL-адресом HTTP, она также является конечной точкой. Префикс «http» на самом деле является пространством имен, которое используется для всех конечных точек шлюза http.

Также важно отметить, что прослушиватель http-шлюза перехватывает все входящие HTTP-запросы, которые соответствуют шаблону отображения сервлета, выраженному в конечной точке HTTP. Вы можете использовать это отображение со свойством шлюза «urlPattern». Например, если мы изменим определение сервиса и шлюза, которое мы только что рассмотрели, включив urlPattern:

  <service category="Vehicles" name="Cars" description="" invmScope="GLOBAL">
<listeners>
<http-gateway name="Http" urlPattern="esb-cars/*" />
</listeners>
<actions mep="RequestResponse">
<!-- Service Aactions.... -->
</actions>
</service>

Затем открытая конечная точка HTTP службы будет перехватывать входящие HTTP-запросы по этому адресу:

Http: // <хост>: <порт> / <.esbname> / HTTP / ESB-автомобили / *

Создание сообщения из запроса

Каким образом http-шлюз на самом деле преобразует входящий HTTP-запрос в сообщение ESB? Это зависит от типа MIME запроса. Это контролирует свойство конфигурации «core: org.jboss.soa.esb.mime.text.types». Это свойство определено в jbossesb-properties.xml вашего сервера как список символов MIME, разделенных точкой с запятой. Значение по умолчанию для свойства включает поддержку подстановочных знаков и устанавливается равным этому набору:

text/*
application/xml
application/*-xml

Http-шлюз использует это свойство, чтобы определить, должна ли полезная нагрузка запроса быть декодирована в строку Java перед передачей ее службе, или же полезная нагрузка должна оставаться в виде байтового массива, и чтобы служба выполняла само декодирование в действии. Http-шлюз также может переопределить тип MIME по умолчанию с помощью атрибута «payloadAs». Этот атрибут позволяет шлюзу обрабатывать полезную нагрузку как «БАЙТЫ» или «СТРОКА». Для текстовых полезных данных шлюз использует ту же кодировку символов из запроса.

Как насчет другой информации во входящем HTTP-запросе?

Параметры запроса содержатся в RequestParameterMap (java.util.Map). Эти параметры строки запроса запроса сохраняются как свойства сообщения в сообщении ESB, созданном шлюзом. Полный доступ к аргументам URL / строке запроса поддерживается в том смысле, что вы можете получить доступ к параметрам в действиях вашей службы следующим образом:

  Map params = (Map) message.getProperties().getProperty(“RequestParameterMap”);

 

RequestInfoMap — это еще одна java.util.Map, которая содержит информацию запроса, такую ​​как authType, characterEncoding, HTTP-метод, remoteHost, contentLength и т. Д. Вы можете получить доступ к параметрам в действиях своей службы с помощью:

  Map params = (Map) message.getProperties().getProperty(“RequestInfoMap”);

 

Давайте переключимся сейчас и посмотрим на более обширный пример.

Пример

быстрого запуска http_gateway JBossESB, выпуск 4.7, включает в себя пример приложения быстрого запуска http_gateway. (Как я всегда говорю людям, быстрый запуск, включенный в JBossESB, является и отличным инструментом обучения, и отличной отправной точкой для разработки ваших собственных приложений ESB.) Быстрый запуск http_gateway демонстрирует несколько способов использования шлюза для передачи HTTP-запросов в службы ESB:

  • Базовая аутентификация
  • Http-шина по умолчанию
  • Отображение исключений ESB для глобальных кодов ошибок HTTP для http-провайдера …
  • … и как преодолеть эту глобальную обстановку
  • Настройка асинхронного ответа, который изменяет код ответа по умолчанию
  • Безопасность на уровне сообщений

Мы возьмем их по одному.

Базовая аутентификация

В быстром запуске используется домен безопасности «java: / jaas / JBossWS», который уже установлен в конфигурации JBoss ESB / App Server из коробки. Имя пользователя для входа — «kermit», а пароль — «thefrog». Вы можете увидеть эту комбинацию имени пользователя и пароля, определенную в файле «server / [профиль сервера] /conf/props/jbossws-roles.properties». Давайте посмотрим на настройки безопасности в файле быстрого запуска jboss-esb.xml:

  <globals>
<!-- Security setting for all http-providers and all EBWSs in this jboss-esb.xml file.-->
<war-security method="BASIC" domain="JBossWS" />
</globals>

 

Этот «глобальный» раздел впервые появился в http-шлюзе в JBossESB 4.7. Как говорится в комментарии, это определяет глобальную настройку безопасности для всех провайдеров http и EBWS в этом приложении. Другие поддерживаемые настройки для метода обеспечения безопасности войны: DIGEST [4] и CLIENT-CERT.

А вот определение http-провайдера:

  <http-provider name="http">
<http-bus busid="secureFriends">
<!-- Only users in the "friend" role are allowed
access via the "GET" method. Unspecified
methods are not protected (i.e. are allowed)... -->
<allowed-roles>
<role name="friend" />
</allowed-roles>
<protected-methods>
<method name="GET" />
<method name="POST" />
</protected-methods>
</http-bus>
<!-- Global exception mappings file... -->
<exception mappingsFile="/http-exception-mappings.properties" />
</http-provider>

 

В этом фрагменте файла мы видим:

  • Строка 2: Здесь начинается определение http-шины. Обратите внимание на имя, выбранное для busid («secureFriends»). Мы будем ссылаться на это в определении http-шлюза через минуту.
  • Строка 5: набор разрешенных ролей начинается здесь.
  • Строка 8: здесь определен набор методов HTTP, которые может использовать пользователь в разрешенных ролях. Обратите внимание, что http-шлюз поддерживает использование следующих методов HTTP: GET, PUT, POST и DELETE.
  • Строка 14: Вот еще одно глобальное (то есть глобальное для http-провайдера) определение. Мы вернемся к исключению mappingsFile чуть позже. Это определение позволяет вам определять коды состояния, которые будут возвращаться для исключений.

Теперь давайте посмотрим на фактическое определение http-шлюза:

  <service category="Sales" name="List" description="" invmScope="GLOBAL">
<listeners>
<!-- Receives: http://<host>:<port>/Quickstart_http_gateway/http/sales/* but will be forced to
authenticate because the "sales" bus has basic auth configured (above)... -->
<http-gateway name="sales" busidref="secureFriends" urlPattern="sales/*" />
</listeners>
<actions mep="RequestResponse">
<action name="print" class="org.jboss.soa.esb.samples.quickstart.httpgateway.MyAction"/>
</actions>
</service>

 

Вот где все это связано:

  • Строка 1: определение сервиса начинается здесь. Обратите внимание на «глобальную область InVM, о которой мы говорили ранее.
  • Строка 5: определение http-шлюза здесь. Обратите внимание на ссылку на busidref, который мы определили в http-bus. Также обратите внимание на urlPattern. Мы будем использовать этот шаблон при запуске быстрого старта.
  • Строка 6: шаблон обмена сообщениями (mep) — RequestResponse as, помните, что мы имеем дело с HTTP.
  • Строка 7: наши действия с клиентами. Этот класс выводит информацию из запроса.

ОК — давайте запустим быстрый старт и посмотрим результаты.

Где находится клиентская программа, которую мы запускаем? Ну, этот быстрый запуск отличается от большинства других быстрых запусков тем, что вы не запускаете тест, генерируя сообщение. Помните, как http-провайдер, который мы определили, задал HTTP-глаголы GET и POST? Чтобы запустить эту часть быстрого запуска, вы можете просто запустить свой любимый браузер и отправить запрос HTTP GET, введя этот URL:

http://localhost:8080/Quickstart_http_gateway/http/sales/a/b/c

Для иллюстрации будем использовать браузер lynx (текстовый).

  lynx -dump -source -auth=kermit:thefrog http://localhost:8080/Quickstart_http_gateway/http/sales/a/b/c
Service: Sales:List

------------Http Request Info (XStream Encoded)-------------------
<org.jboss.soa.esb.http.HttpRequest>
<authType>BASIC</authType>
<contextPath>/Quickstart_http_gateway</contextPath>
<localAddr>127.0.0.1</localAddr>
<localName>localhost.localdomain</localName>
<method>GET</method>
<pathInfo>/a/b/c</pathInfo>
<protocol>HTTP/1.0</protocol>
<remoteAddr>127.0.0.1</remoteAddr>
<remoteHost>127.0.0.1</remoteHost>
<remoteUser>kermit</remoteUser>
<contentLength>-1</contentLength>
<requestURI>/Quickstart_http_gateway/http/sales/a/b/c</requestURI>
<scheme>http</scheme>
<serverName>localhost</serverName>
<requestPath>/http/sales</requestPath>
<pathInfoTokens>
<string>a</string>
<string>b</string>
<string>c</string>
</pathInfoTokens>
<queryParams/>
<headers>
<org.jboss.soa.esb.http.HttpHeader>
<name>host</name>
<value>localhost:8080</value>
</org.jboss.soa.esb.http.HttpHeader>
<org.jboss.soa.esb.http.HttpHeader>
<name>accept</name>
<value>text/html, text/plain, audio/mod, image/*, application/msword, application/pdf, application/postscript, application/x-java-jnlp-file, text/sgml, video/mpeg, */*;q=0.01</value>
</org.jboss.soa.esb.http.HttpHeader>
<org.jboss.soa.esb.http.HttpHeader>
<name>accept-language</name>
<value>en</value>
</org.jboss.soa.esb.http.HttpHeader>
<org.jboss.soa.esb.http.HttpHeader>
<name>user-agent</name>
<value>Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.8e-fips-rhel5</value>
</org.jboss.soa.esb.http.HttpHeader>
<org.jboss.soa.esb.http.HttpHeader>
<name>authorization</name>
<value>Basic a2VybWl0OnRoZWZyb2c=</value>
</org.jboss.soa.esb.http.HttpHeader>
</headers>

Шина HTTP по умолчанию в действии

В следующей части QuickStart мы еще раз рассмотрим определение службы, где определение не ссылается на определение шины (busidref), а вместо этого использует шину http «по умолчанию». Определение этого сервиса выглядит следующим образом:

 <service category="Index" name="List" description="" invmScope="GLOBAL">
<listeners>
<!-- Receives: http://<host>:<port>/Quickstart_http_gateway/http/index/*
Uses the default http bus configuration... -->
<http-gateway name="Index" urlPattern="index/*" />
</listeners>
<actions mep="RequestResponse">
<action name="print" class="org.jboss.soa.esb.samples.quickstart.httpgateway.MyAction"/>
</actions>
</service>

Ну, здесь особо не на что смотреть, так как используется шина http по умолчанию. Чтобы получить доступ к этой услуге, вы указываете свой браузер на этот URL:

http://localhost:8080/Quickstart_http_gateway/http/index/XXXX/yyy?a=1,b=2

Обратите внимание, что мы обсуждали ранее в этом посте и этот URL-адрес показывает, что мы можем обрабатывать параметры запроса в URL-адресе. Вот что показывает нам рысь:

 lynx -dump -source http://localhost:8080/Quickstart_http_gateway/http/index/XXXX/yyy?a=1,b=2
Service: Index:List

------------Http Request Info (XStream Encoded)-------------------
<org.jboss.soa.esb.http.HttpRequest>
<contextPath>/Quickstart_http_gateway</contextPath>
<localAddr>127.0.0.1</localAddr>
<localName>localhost.localdomain</localName>
<method>GET</method>
<pathInfo>/XXXX/yyy</pathInfo>
<protocol>HTTP/1.0</protocol>
<queryString>a=1,b=2</queryString>
<remoteAddr>127.0.0.1</remoteAddr>
<remoteHost>127.0.0.1</remoteHost>
<contentLength>-1</contentLength>
<requestURI>/Quickstart_http_gateway/http/index/XXXX/yyy</requestURI>
<scheme>http</scheme>
<serverName>localhost</serverName>
<requestPath>/http/index</requestPath>
<pathInfoTokens>
<string>XXXX</string>
<string>yyy</string>
</pathInfoTokens>
<queryParams>
<entry>
<string>a</string>
<string-array>
<string>1,b=2</string>
</string-array>
</entry>
</queryParams>
<headers>
<org.jboss.soa.esb.http.HttpHeader>
<name>host</name>
<value>localhost:8080</value>
</org.jboss.soa.esb.http.HttpHeader>
<org.jboss.soa.esb.http.HttpHeader>
<name>accept</name>
<value>text/html, text/plain, audio/mod, image/*, application/msword, application/pdf, application/postscript, application/x-java-jnlp-file, text/sgml, video/mpeg, */*;q=0.01</value>
</org.jboss.soa.esb.http.HttpHeader>
<org.jboss.soa.esb.http.HttpHeader>
<name>accept-language</name>
<value>en</value>
</org.jboss.soa.esb.http.HttpHeader>
<org.jboss.soa.esb.http.HttpHeader>
<name>user-agent</name>
<value>Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.8e-fips-rhel5</value>
</org.jboss.soa.esb.http.HttpHeader>
</headers>

 

Обратите особое внимание на эти строки:

  <queryParams>
<entry>
<string>a</string>
<string-array>
<string>1,b=2</string>
</string-array>
</entry>
</queryParams>

 

Давайте немного изменим URL и убедимся, что сервис и его действия действительно могут получить доступ к параметрам запроса:

  lynx -dump -source http://localhost:8080/Quickstart_http_gateway/http/index/XXXX/yyy?param1=hello,param2=world

<queryParams>
<entry>
<string>param1</string>
<string-array>
<string>hello,param2=world</string>
</string-array>
</entry>
</queryParams>

 

Ага! Это они!

Глобальное исключение

В описании примера базовой аутентификации, который мы обсуждали ранее, мы пропустили определение глобального сопоставления исключений для http-провайдера:

  <!-- Global exception mappings file... -->
<<exception mappingsFile="/http-exception-mappings.properties" />

 

Как видно из названия, эта функция позволяет вам определить код состояния, который будет возвращен для всех запросов, полученных службой. Давайте посмотрим на файл http-exception-mappings.properties:

  org.jboss.soa.esb.services.security.SecurityServiceException=401
org.jboss.soa.esb.samples.quickstart.httpgateway.MyActionException=502

 

Этот файл указывает, что все запросы, которые вызывают исключение типа org.jboss.soa.esb.services.security.SecurityServiceException, приведут к возврату кода состояния HTTP-возврата 401 клиенту, который отправил запрос, и все запросы, которые вызывают исключение типа org.jboss.soa.esb.samples.quickstart.httpgateway.MyActionException, приведут к возврату HTTP-кода возврата 502. Чтобы проиллюстрировать это, мы будем вызывать этот сервис:

  <service category="Exceptions" name="Exception1" description="" invmScope="GLOBAL">
<listeners>
<http-gateway name="Exception2" />
</listeners>
<actions mep="RequestResponse">
<!-- Uses the globally defined exception mappings defined on the <http-provider>... -->
<action name="print" class="org.jboss.soa.esb.samples.quickstart.httpgateway.MyExceptionAction"/>
</actions>
</service>

 

Класс MyExceptionAction минимален — достаточно кода, чтобы вызвать исключение:

  public class MyExceptionAction extends AbstractActionPipelineProcessor {

public MyExceptionAction(ConfigTree config) {
}

public Message process(Message message) throws ActionProcessingException {
throw new MyActionException("MyActionException!!!!");
}

 

Чтобы получить доступ к этой услуге, вы указываете свой браузер по следующему URL: http: // localhost: 8080 / Quickstart_http_gateway / http / Exceptions / Exception1

  lynx -dump -source http://localhost:8080/Quickstart_http_gateway/http/Exceptions/Exception1 -error_file=error.txt
org.jboss.soa.esb.couriers.FaultMessageException: org.jboss.soa.esb.samples.quickstart.httpgateway.MyActionException: MyActionException!!!!
at org.jboss.soa.esb.listeners.message.errors.Factory.createExceptionFromFault(Factory.java:50)
at org.jboss.internal.soa.esb.couriers.TwoWayCourierImpl.pickup(TwoWayCourierImpl.java:207)
at org.jboss.soa.esb.client.ServiceInvoker$EPRInvoker.attemptDelivery(ServiceInvoker.java:675)
at org.jboss.soa.esb.client.ServiceInvoker$EPRInvoker.access$200(ServiceInvoker.java:569)
at org.jboss.soa.esb.client.ServiceInvoker.post(ServiceInvoker.java:359)
at org.jboss.soa.esb.client.ServiceInvoker.deliverSync(ServiceInvoker.java:219)
at org.jboss.soa.esb.listeners.gateway.http.HttpGatewayServlet.service(HttpGatewayServlet.java:187)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:432)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
at java.lang.Thread.run(Thread.java:636)
Caused by: org.jboss.soa.esb.samples.quickstart.httpgateway.MyActionException: MyActionException!!!!
at org.jboss.soa.esb.samples.quickstart.httpgateway.MyExceptionAction.process(MyExceptionAction.java:34)
at org.jboss.soa.esb.listeners.message.ActionProcessingPipeline.processPipeline(ActionProcessingPipeline.java:634)
at org.jboss.soa.esb.listeners.message.ActionProcessingPipeline.processPipeline(ActionProcessingPipeline.java:586)
at org.jboss.soa.esb.listeners.message.ActionProcessingPipeline.process(ActionProcessingPipeline.java:420)
at org.jboss.soa.esb.listeners.message.MessageAwareListener$TransactionalRunner.run(MessageAwareListener.java:540)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
... 1 more

 

И — вот код возврата, который мы хотели:

 cat error.txt
URL=http://localhost:8080/Quickstart_http_gateway/http/Exceptions/Exception1 (GET)
STATUS=HTTP/1.1 502 Bad Gateway

Преодоление глобального исключения

Хорошо иметь возможность обрабатывать все исключения на глобальном уровне. Однако могут быть случаи, когда вы захотите получить другой код возврата. Для этого вы можете переопределить эту глобальную настройку. Вот определение сервиса для отмены глобальной переменной, которую мы только что обсуждали:

 <service category="Exceptions" name="Exception2" description="" invmScope="GLOBAL">
<listeners>
<http-gateway name="Exception1">
<!-- Override the exception mappings defined on the <http-provider>... -->
<exception>
<mapping class="org.jboss.soa.esb.samples.quickstart.httpgateway.MyActionException" status="503" />
</exception>
</http-gateway>
</listeners>
<actions mep="RequestResponse">
<!-- Uses the override exception mappings defined on the <http-gateway>... -->
<action name="print" class="org.jboss.soa.esb.samples.quickstart.httpgateway.MyExceptionAction"/>
</actions>
</service>

 

Строка 6 — это та, которая нас интересует. Здесь мы сопоставляем класс, который выдает исключение, с кодом, который возвращается. И вот что происходит:

  lynx -dump -source http://localhost:8080/Quickstart_http_gateway/http/Exceptions/Exception2 -error_file=error.txt
org.jboss.soa.esb.couriers.FaultMessageException: org.jboss.soa.esb.samples.quickstart.httpgateway.MyActionException: MyActionException!!!!
at org.jboss.soa.esb.listeners.message.errors.Factory.createExceptionFromFault(Factory.java:50)
at org.jboss.internal.soa.esb.couriers.TwoWayCourierImpl.pickup(TwoWayCourierImpl.java:207)
at org.jboss.soa.esb.client.ServiceInvoker$EPRInvoker.attemptDelivery(ServiceInvoker.java:675)
at org.jboss.soa.esb.client.ServiceInvoker$EPRInvoker.access$200(ServiceInvoker.java:569)
at org.jboss.soa.esb.client.ServiceInvoker.post(ServiceInvoker.java:359)
at org.jboss.soa.esb.client.ServiceInvoker.deliverSync(ServiceInvoker.java:219)
at org.jboss.soa.esb.listeners.gateway.http.HttpGatewayServlet.service(HttpGatewayServlet.java:187)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:432)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
at java.lang.Thread.run(Thread.java:636)
Caused by: org.jboss.soa.esb.samples.quickstart.httpgateway.MyActionException: MyActionException!!!!
at org.jboss.soa.esb.samples.quickstart.httpgateway.MyExceptionAction.process(MyExceptionAction.java:34)
at org.jboss.soa.esb.listeners.message.ActionProcessingPipeline.processPipeline(ActionProcessingPipeline.java:634)
at org.jboss.soa.esb.listeners.message.ActionProcessingPipeline.processPipeline(ActionProcessingPipeline.java:586)
at org.jboss.soa.esb.listeners.message.ActionProcessingPipeline.process(ActionProcessingPipeline.java:420)
at org.jboss.soa.esb.listeners.message.MessageAwareListener$TransactionalRunner.run(MessageAwareListener.java:540)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
... 1 more

cat error.txt
URL=http://localhost:8080/Quickstart_http_gateway/http/Exceptions/Exception2 (GET)
STATUS=HTTP/1.1 503 Service Unavailable

 

Асинхронный ответ

До сих пор мы видели только синхронные ответы на наши запросы. Также возможно, чтобы вызываемая служба отвечала асинхронно. Вот определение сервиса быстрого запуска, которое иллюстрирует это:

  <service category="Async" name="List" description="" invmScope="GLOBAL">
<listeners>
<!-- Receives: http://<host>:<port>/Quickstart_http_gateway/http/Async/List
Uses the default http bus configuration... -->
<http-gateway name="Async">
<asyncResponse statusCode="202">
<payload classpathResource="/readme.txt" contentType="text/plain" characterEncoding="UTF-8" />
</asyncResponse>
</http-gateway>
</listeners>
<actions mep="RequestResponse">
<action name="print" class="org.jboss.soa.esb.samples.quickstart.httpgateway.MyAction"/>
</actions>
</service>

 

  • Строка 5: здесь начинается определение асинхронного ответа. Обратите внимание, что код возврата 202.
  • Строка 6: а. мы также можем указать в ответе файл, содержимое которого будет возвращено в виде статического содержимого вместе с кодом возврата.

  lynx -dump -source http://localhost:8080/Quickstart_http_gateway/http/Async/List -error_file=error.txt
Overview:
=========
The purpose of the http_gateway quickstart sample is to demonstarte how to
configue a http gateway to pass the http request into ESB service.


Running this quickstart:
========================
Please refer to 'ant help-quickstarts' for prerequisites about the quickstarts
and a more detailed descripton of the different ways to run the quickstarts.

To Run '.esb' archive mode:
===========================
1. In a command terminal window in this folder ("Window1"), type 'ant deploy'.
2. Open the web brower and send http requests to the following addresses. Be sure to
check the Server console after executing each request:
a) http://localhost:8080/Quickstart_http_gateway/http/sales/a/b/c - Will be routed to the Sales:List
service. Will return some details about the request. This Service's <http-gateway> references a
"secureFriends" bus, which contains login configurations. The login username is "kermit" and the
password is "thefrog". It usee the "java:/jaas/JBossWS" security domain, which is already installed
in your JBoss ESB/App Server.
b) http://localhost:8080/Quickstart_http_gateway/http/index/XXXX/yyy?a=1,b=2 - Will be routed to the Index:List
service. Will return some details about the request. This Service's <http-listener> does not refer
to any bus and so simply uses the "default" http bus.
c) http://localhost:8080/Quickstart_http_gateway/http/Exceptions/Exception1 - Will be routed to the
Exceptions:Exception1 service. This service throws a "MyActionException", resulting in a
502 (Bad Gateway) status being returned in accordance with the Exception to HTTP status code
mappings defined globally on the <http-provider>.
d) http://localhost:8080/Quickstart_http_gateway/http/Exceptions/Exception2 - Will be routed to the
Exceptions:Exception2 service. This service also throws a "MyActionException", but the <http-gateway>
on this service overrides the globally defined Exception to HTTP status code mappings defined globally
on the <http-provider> to return a 503 (Service Unavailable) status for the "MyActionException" exception.
e) http://localhost:8080/Quickstart_http_gateway/http/Async/List - Will be routed to the
Async:List service, which responds asynchronously with a 202 (Accepted) response code and a static
payload of this readme.txt.
f) http://localhost:8080/Quickstart_http_gateway/http/soap/ - Will be routed to the
Soap:List service, which requires message level seurity. An 401 error will occur. Now
switch to the command line and run "ant soap". This POSTs a SOAP message, with login credentials
to the gateway. The service should respond successfully this time!!
3. In this folder ("Window1"), type 'ant undeploy'.

cat error.txt
URL=http://localhost:8080/Quickstart_http_gateway/http/Async/List (GET)
STATUS=HTTP/1.1 202 Accepted

SOAP и безопасность

Быстрый старт заканчивается там, где он начался; с примером некоторой базовой безопасности. Вот определение сервиса:

  <service category="Soap" name="List" description="" invmScope="GLOBAL">
<listeners>
<!-- Receives: http://<host>:<port>/Quickstart_http_gateway/http/soap/*
Execute "ant soap" on command line.... -->
<http-gateway name="soap" busidref="secureFriends" urlPattern="soap/*">
<exception>
<mapping class="org.jboss.soa.esb.services.security.SecurityServiceException" status="401" />
</exception>
</http-gateway>
</listeners>
<actions mep="RequestResponse">
<action name="print" class="org.jboss.soa.esb.samples.quickstart.httpgateway.MyAction"/>
</actions>
</service>

  • Строка 5: вот определение http-шлюза. Обратите внимание, что мы снова используем busidref «secureFriends». (Это означает, что kermit придется войти снова.)
  • Строка 7: И вот исключение, которое мы сгенерируем, с кодом состояния возврата 401.

Конечно, когда мы отправляем запрос, мы получаем это исключение и код возврата:

  lynx -dump -source http://localhost:8080/Quickstart_http_gateway/http/soap -error_file=error.txt
HTTP: Access authorization required.
Use the -auth=id:pw parameter.

Looking up localhost:8080
Making HTTP connection to localhost:8080
Sending HTTP request.
HTTP request sent; waiting for response.
Alert!: Access without authorization denied -- retrying

lynx: Can't access startfile http://localhost:8080/Quickstart_http_gateway/http/soap

cat error.txt
URL=http://localhost:8080/Quickstart_http_gateway/http/soap (GET)
STATUS=HTTP/1.1 401 Unauthorized

 

Теперь мы можем просто предоставить учетные данные для входа в систему вручную через пользовательский интерфейс браузера, но мы хотим, чтобы наш клиентский код мог делать это программно. Чтобы избежать этого исключения, ответом на запрос, который мы отправляем, должны быть данные для входа в систему. Файл build.xml быстрого запуска предоставляет цель ant для этого, вызывая действие JBossESB HttpRouter (org.jboss.soa.esb.actions.routing.http.HttpRouter). Это действие является одним из большого набора «готовых» действий JBossESB.

  <target name="soap" depends="compile" description="sends a SOAP HTTP request to the http gateway">
<echo>Http Client</echo>
<java fork="yes" classname="org.jboss.soa.esb.actions.routing.http.HttpRouter" failonerror="true">
<arg value="endpointUrl=http://localhost:8080/Quickstart_http_gateway/http/soap/"/>
<!-- The EBWS is secured with container level security -->
<arg value="configurators=HttpProtocol,AuthBASIC"/>
<arg value="method=POST"/>
<arg value="auth-username=kermit"/>
<arg value="auth-password=thefrog"/>
<arg value="authscope-host=localhost"/>
<arg value="authscope-port=8080"/>
<!-- The actual payload to POST -->
<arg value="payload=soap-login.xml"/>
<classpath refid="exec-classpath"/>
</java>
</target>

 

Фактическая полезная нагрузка отправляемого сообщения определяется в файле soap-login.xml:

  <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<soap:Header>
</soap:Header>

<soap:Body>
</soap:Body>

</soap:Envelope>

 

И успешные результаты выглядят так:

  soap:
[echo] Http Client
[java] Request payload:
[java] <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
[java] xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
[java] xmlns:xsd="http://www.w3.org/2001/XMLSchema">
[java]
[java] <soap:Header>
[java] </soap:Header>
[java]
[java] <soap:Body>
[java] </soap:Body>
[java]
[java] </soap:Envelope>
[java]
[java] --------------------------
[java]
[java]
[java] Response Status Code: 200
[java] Response payload:
[java] Service: Soap:List
[java]
[java] ------------Http Request Info (XStream Encoded)-------------------
[java] <org.jboss.soa.esb.http.HttpRequest>
[java] <authType>BASIC</authType>
[java] <characterEncoding>UTF-8</characterEncoding>
[java] <contentType>text/xml;charset=UTF-8</contentType>
[java] <contextPath>/Quickstart_http_gateway</contextPath>
[java] <localAddr>127.0.0.1</localAddr>
[java] <localName>localhost.localdomain</localName>
[java] <method>POST</method>
[java] <pathInfo>/</pathInfo>
[java] <protocol>HTTP/1.1</protocol>
[java] <remoteAddr>127.0.0.1</remoteAddr>
[java] <remoteHost>127.0.0.1</remoteHost>
[java] <remoteUser>kermit</remoteUser>
[java] <contentLength>268</contentLength>
[java] <requestURI>/Quickstart_http_gateway/http/soap/</requestURI>
[java] <scheme>http</scheme>
[java] <serverName>localhost</serverName>
[java] <requestPath>/http/soap</requestPath>
[java] <pathInfoTokens/>
[java] <queryParams/>
[java] <headers>
[java] <org.jboss.soa.esb.http.HttpHeader>
[java] <name>content-type</name>
[java] <value>text/xml;charset=UTF-8</value>
[java] </org.jboss.soa.esb.http.HttpHeader>
[java] <org.jboss.soa.esb.http.HttpHeader>
[java] <name>user-agent</name>
[java] <value>Jakarta Commons-HttpClient/3.0.1</value>
[java] </org.jboss.soa.esb.http.HttpHeader>
[java] <org.jboss.soa.esb.http.HttpHeader>
[java] <name>content-length</name>
[java] <value>268</value>
[java] </org.jboss.soa.esb.http.HttpHeader>
[java] <org.jboss.soa.esb.http.HttpHeader>
[java] <name>authorization</name>
[java] <value>Basic a2VybWl0OnRoZWZyb2c=</value>
[java] </org.jboss.soa.esb.http.HttpHeader>
[java] <org.jboss.soa.esb.http.HttpHeader>
[java] <name>host</name>
[java] <value>localhost:8080</value>
[java] </org.jboss.soa.esb.http.HttpHeader>
[java] </headers>
[java] </org.jboss.soa.esb.http.HttpRequest>
[java] --------------------------
[java]

 

Заключительные мысли

Новый http-шлюз JBossESB обеспечивает большую гибкость в интеграции HTTP-приложений через ESB. Быстрый запуск http_gateway иллюстрирует эту гибкость и, кстати, показывает, сколько вы можете сделать, не написав много пользовательского кода. Заметили ли вы, читая этот пост, что нам не нужно было писать подпрограммы поддержки для обработки аутентификации, обработки исключений и работы с шаблонами URL? Http-шлюз и JBossESB сделали для нас тяжелую работу.

Благодарности

Спасибо сообществу JBossESB и его авторам (см. Http://anonsvn.jboss.org/repos/labs/labs/jbossesb/trunk/Contributors.txt ) — и Кевину Коннеру за его своевременные комментарии!

Рекомендации

[1] http://www.jboss.org/community/wiki/HTTPGateway
[2] http://jboss-soa-p.blogspot.com/2009/09/works-great-right-out-of-box.html
[3] http://www.jboss.org/jbossesb/docs/4.7/manuals/html/ProgrammersGuide.html
[4] http://en.wikipedia.org/wiki/Digest_access_authentication