Apache Camel: доступ к запросу и ответному сообщению в конце маршрута

Я хотел бы обработать как запрос, так и ответные сообщения в конце моего маршрута. Однако я не вижу способа доступа к исходному сообщению запроса.

у меня ужасное чувство, что я борюсь с какой-то базовой концепцией.

вот простой пример маршрута в DSL для описания моей проблемы (streamCaching включен для всего контекста):

from("activemq:queue:myQueue")
.to("log:" + getClass().getName() + "?showOut=true")
.to("http://localhost:8080/someBackend")
.log("Now in.Body returns this: ${in.body} and out.Body this: ${out.body}")
.to("log:" + getClass().getName() + "?showOut=true");

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

2012-09-25 17:28:08,312 local.bar.foo.MyRouteBuilder INFO - 
    Exchange[ExchangePattern:InOut, BodyType:byte[],
    Body:<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Header /><env:Body><urn:someRequest  xmlns:urn="http://foo.bar.local/ns"></urn:someRequest></env:Body></env:Envelope>, 
    Out: null]
2012-09-25 17:28:08,398 org.apache.camel.component.http.HttpProducer DEBUG - 
    Executing http POST method: http://localhost:8080/someBackend
2012-09-25 17:28:09,389 org.apache.camel.component.http.HttpProducer DEBUG - 
    Http responseCode: 200
2012-09-25 17:28:09,392 route2 INFO - 
    Now in.Body returns this: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:someResponse xmlns:ns2="http://foo.bar.local/ns"</ns2:someResponse></soap:Body></soap:Envelope>
    and out.Body this: 
2012-09-25 17:28:09,392 local.bar.foo.MyRouteBuilder INFO - 
    Exchange[ExchangePattern:InOut,  
    BodyType:org.apache.camel.converter.stream.InputStreamCache,
    Body:[Body is instance of org.apache.camel.StreamCache],
    Out: null]

Я бы ожидал, что в.тело и наружу.тело будет сохранено на протяжении всего маршрута?

альтернативные решения я рассматриваю:

  • использовать Идентификатор Корреляции шаблон для сопоставления запроса и ответа. Но сохранит ли это сообщение органов? Кроме того, мои сообщения запроса/ответа не имеют уникальных идентификаторов для корреляции.
  • напишите пользовательский компонент, который выполняет вызов бэкэнда http, обрабатывая объекты запроса и ответа (но это в основном решение без верблюда, изобретая колесо и, следовательно, не предпочтительно)

уже неудачные подходы:

Я попытался получить доступ к исходному сообщению запроса с помощью такого процессора в конце моего маршрут, без успеха:

 process(new Processor() {
   @Override
   public void process(Exchange exchange) throws Exception {
      Message originalInMessage = exchange.getUnitOfWork().getOriginalInMessage();
         logger.debug(originalInMessage.getBody(String.class));
         logger.debug(exchange.getIn().getBody(String.class));
   }
 });

Спасибо за помощь

3 ответов


просто сохраните исходное тело сообщения in в заголовке или свойстве и извлеките его в конце:

from("activemq:queue:myQueue")
.setProperty("origInBody", body())
.to("http://localhost:8080/someBackend")

после http-вызова вы можете получить доступ к свойству origInBody.


во-первых, эта статья очень хорошо показывает, как in и out работает в camel:http://camel.apache.org/using-getin-or-getout-methods-on-exchange.html

Как правило, сообщение out не всегда используется, а скорее копируется из сообщения in на каждом шаге.

в вашем случае, когда вы хотите, чтобы исходное сообщение оставалось до конца маршрута, вы могли бы продолжить обогащение EIP. http://camel.apache.org/content-enricher.html

ваш маршрут будет примерно таким:

public class MyAggregationStrategy implements AggregationStrategy {
  public Exchange aggregate(Exchange orig, Exchange httpExchange){
    // if you want to check something with the Http request, you better do that here 
    if( httpExchange is not correct in some way ) 
       throw new RuntimeException("Something went wrong");

    return orig;
  }
}

AggregationStrategy aggStrategy = new MyAggregationStrategy();

from("activemq:queue:myQueue")
  .enrich("http://localhost:8080/someBackend",aggStrategy)
  .//keep processing the original request here if you like, in the "in" message

одна из самых больших проблем верблюда, легкость для того чтобы злоупотребить им. Лучший способ использовать его правильно-думать в терминах EIP:одной из основных целей camel, является реализация EIP в его DSL.

вот список EIP

теперь подумайте об этом. Вы хотите, чтобы запрос и ответ в конце, для чего ? Лесозаготовки, Агрегации ... ? Для ведения журнала достаточно correlationId, поэтому я предполагаю, что вам это нужно создайте ответ, основанный как на запросе, так и на проксированном ответе. Если это то, что вы хотите, вы можете сделать что-то вроде

from("direct:receiveRequest")
   .enrich("direct:proxyResponse", new RequestAndResponseAggregationStrategy())

у вас будет возможность объединить ваш запрос (в oldExchange) и ваш ответ (в newExchange).

при всем моем уважении к Кристиану Шнайдеру,Я думаю, что идея поместить запрос в свойство, которое может быть повторно использовано позже, является плохим дизайном. Делая это, вы создаете побочный эффект между маршруты. Если ваш маршрут является подпространством для другого, вы, возможно, сотрете их собственность. Если вы храните его, чтобы вернуть его позже, возможно, вам следует сделать что-то вроде

from("direct:receiveRequest")
    .enrich("direct:subRouteToIgnoreResponse", AggregationStrategies.useOriginal())

действительно очень плохой дизайн, который я сделал слишком много времени сам, это сделать:

from("direct:receiveRequest")
    .to("direct:subroute")

from("direct:subroute")
    .setProperty("originalBody", body())
    .to("direct:handling")
    .transform(property("originalBody")

это приведет к "свойствам/заголовкам ада" и маршрутам, которые являются просто последовательным вызовом процессоров.

и если вы не можете придумать решение своей проблемы с EIP, возможно, вы должны использовать camel только для доступа к своим компонентам. Например, что-то вроде :

from("http://api.com/services")
   .to(new SomeNotTranslatableToEIPProcessor())
   .to("ftp://destination")

но не забывайте, что эти компоненты имеют свои собственные цели : создание общей абстракции между подобным поведением (e.G, потребитель опроса на основе времени). Если у вас есть очень конкретная потребность, попытка согнуть компонент camel для этой конкретной потребности может привести к огромному куску кода, который нелегко поддерживать.

Не позволяйте верблюду стать вашим Золотой Молоток анти-шаблон