将验证异常从Camel传递到CXF SOAP服务

时间:2017-02-13 19:49:50

标签: scala apache-camel akka cxf

我有一个问题,我已经解决了一段时间了,加上我对apache camel的新手并没有帮助。

我的简单应用程序使用CXF(使用jetty作为http引擎)公开SOAP Web服务,然后使用camel将soap请求传递给akka actor。

我想在前往actor的路上验证SOAP请求,并检查它是否包含某些标头和内容值。我不想使用CXF拦截器。问题是,camel中发生的事情(例外,故障消息返回)不会传播到cxf。我总是将SUCCESS 202作为响应和有关日志中验证异常的信息。

这是我的简单应用:

class RequestActor extends Actor with WithLogger {
  def receive = {
    case CamelMessage(body: Request, headers) =>
      logger.info(s"Received Request $body [$headers]")
    case msg: CamelMessage =>
      logger.error(s"unknown message ${msg.body}")
  }
}

class CustomRouteBuilder(endpointUrl: String, serviceClassPath: String, system: ActorSystem)
  extends RouteBuilder {
  def configure {
    val requestActor = system.actorOf(Props[RequestActor])

    from(s"cxf:${endpointUrl}?serviceClass=${serviceClassPath}")
      .onException(classOf[PredicateValidationException])
        .handled(true)
        .process(new Processor {
        override def process(exchange: Exchange): Unit = {
          val message = MessageFactory.newInstance().createMessage();
          val envelope = message.getSOAPPart().getEnvelope();
          val body = message.getSOAPBody();
          val fault = body.addFault();
          fault.setFaultCode("Server");
          fault.setFaultString("Unexpected server error.");
          val detail = fault.addDetail();
          val entryName = envelope.createName("message");
          val entry = detail.addDetailEntry(entryName);
          entry.addTextNode("The server is not able to complete the request. Internal error.");

          log.info(s"Returning $message")
          exchange.getOut.setFault(true)
          exchange.getOut.setBody(message)
        }

        })
      .end()
      .validate(header("attribute").isEqualTo("for_sure_not_defined"))
      .to(genericActor)
  }
}

object Init extends App {

  implicit val system = ActorSystem("superman")
  val camel = CamelExtension(system)
  val camelContext = camel.context
  val producerTemplate = camel.template

  val endpointClassPath = classOf[Service].getName
  val endpointUrl = "http://localhost:1234/endpoint"

  camel.context.addRoutes(new CustomRouteBuilder(endpointUrl, endpointClassPath, system))

}

当我运行应用程序时,我会看到来自log.info的日志(s"返回$ message")所以我确定路由调用处理器,因此也没有调用actor:

exchange.getOut.setFault(true)
exchange.getOut.setBody(message)
做他们的工作。但我的SOAP服务仍然返回202 SUCCESS而不是故障信息。

2 个答案:

答案 0 :(得分:1)

我不确定您在寻找什么,但我以不同方式处理了CXF端点的例外情况。我不得不在SOAPFault中返回带有自定义详细信息的HTTP-500(如验证错误消息等),所以......

  1. 保持异常未被Camel处理以将其传递给CXF .onException(classOf[PredicateValidationException]).handled(false)

  2. 使用Exception中的所有必需详细信息创建org.apache.cxf.interceptor.Fault对象。 (不是SOAP Fault)。它允许设置自定义详细信息元素,自定义FaultCode元素,消息。

  3. 最后用cxfFault exchange.setProperty(Exchange.EXCEPTION_CAUGHT, cxfFault)

  4. 替换Exchange.EXCEPTION_CAUGHT属性

    来自CXF Endpoint的结果消息是一个带有SOAPFault的HTTP-500,其中包含我在cxfFault中设置的详细信息

答案 1 :(得分:0)

Camel只关注交易所的部分内容,但您正在修改外部部分。

尝试更改

exchange.getOut.setFault(true)
exchange.getOut.setBody(message)

exchange.getIn.setFault(true)
exchange.getIn.setBody(message)