77장. CXF

77.1. CXF 구성 요소

cxf: 구성 요소는 CXF에서 호스팅되는 JAX-WS 서비스에 연결하기 위해 Apache CXF 와의 통합을 제공합니다.

Maven 사용자는 이 구성 요소를 위해 다음 종속성을 pom.xml 에 추가해야 합니다.

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-cxf</artifactId>
    <version>x.x.x</version>
    <!-- use the same version as your Camel core version -->
</dependency>
참고

CXF 종속 항목에 대해 알아보려면 WHICH-JARS 텍스트 파일을 참조하십시오.

참고

스트리밍 모드에서 CXF를 사용하는 경우(DataFormat 옵션 참조) 스트림 캐싱 에 대해 읽어 보십시오.

77.2. EAP 배포용 Camel

이 구성 요소는 Red Hat JBoss EAP(JBoss Enterprise Application Platform) 컨테이너에서 단순화된 배포 모델을 제공하는 Camel on EAP(Wildfly Camel) 프레임워크에서 지원합니다.

CXF 구성 요소는 Apache CXF도 사용하는 JBoss EAP 웹 서비스 susbsystem과 통합됩니다. 자세한 내용은 JAX-WS 를 참조하십시오.

참고

현재 EAP 하위 시스템의 Camel은 CXF 또는 Restlet 소비자를 지원하지 않습니다. 그러나 CamelProxy 를 사용하여 CXF 소비자의 동작을 모방할 수 있습니다.

77.3. URI 형식

cxf:bean:cxfEndpoint[?options]

여기서 cxfEndpoint 는 Spring 빈 레지스트리의 빈을 참조하는 빈 ID를 나타냅니다. 이 URI 형식을 사용하면 대부분의 끝점 세부 정보가 빈 정의에 지정됩니다.

cxf://someAddress[?options]

여기서 someAddress 는 CXF 끝점의 주소를 지정합니다. 이 URI 형식을 사용하면 대부분의 엔드포인트 세부 정보가 옵션을 사용하여 지정됩니다.

위의 두 스타일 모두 다음과 같이 URI에 옵션을 추가할 수 있습니다.

cxf:bean:cxfEndpoint?wsdlURL=wsdl/hello_world.wsdl&dataFormat=PAYLOAD

77.4. 옵션

이름

필수 항목

설명

wsdlURL

없음

WSDL의 위치입니다. WSDL은 기본적으로 끝점 주소에서 가져옵니다. 예를 들면 다음과 같습니다.

file://local/wsdl/hello.wsdl 또는 wsdl/hello.wsdl

serviceClass

있음

SEI(Service Endpoint Interface) 클래스의 이름입니다. 이 클래스에는 포함될 수 있지만 필요한 것은 필수는 아니며, JSR181 주석이 필요하지 않습니다.  2.0부터 이 옵션은 POJO 모드에만 필요합니다. wsdlURL 옵션이 제공되는 경우 PAYLOAD 및 MESSAGE 모드에 serviceClass가 필요하지 않습니다. serviceClass 없이 wsdlURL 옵션을 사용하는 경우 serviceName 및 portName( Spring 구성의endpointName) 옵션을 제공해야 합니다.

2.0부터 \# 표기법을 사용하여 레지스트리에서 serviceClass 개체 인스턴스를 참조할 수 있습니다.

AOP 프록시가 아닌 경우 Object.getClass().getName() 메서드를 사용하므로 참조된 오브젝트가 Proxy (Spring AOP Proxy)가 될 수 없습니다.

2.8부터 PAYLOAD 및 MESSAGE 모드에 대한 wsdlURL 및 serviceClass 옵션을 둘 다 생략할 수 있습니다. 이러한 요소를 생략하면 CXF Dispatch Mode를 용이하게 하기 위해 PAYLOAD 모드에서 CxfPayload의 본문에 임의의 XML 요소를 배치할 수 있습니다.

예: org.apache.camel.Hello

serviceName

WSDL에 두 개 이상의 serviceName 이 있는 경우에만

이 서비스가 구현되고 있는 서비스 이름은 wsdl:service@name 에 매핑됩니다. 예를 들면 다음과 같습니다.

{http://org.apache.camel}ServiceName

endpointName

serviceName 아래에 두 개 이상의 portName 이 있고 camel 2.2 이후 camel-cxf consumer에 필요한 경우에만 해당됩니다.

이 서비스가 구현 중인 포트 이름은 wsdl:port@name 에 매핑됩니다. 예를 들면 다음과 같습니다.

{http://org.apache.camel}PortName

dataFormat

없음

CXF 끝점이 지원하는 메시지 데이터 형식은 무엇입니까. 가능한 값은 POJO (기본값), PAYLOAD,MESSAGE 입니다.

relayHeaders

없음

이 옵션은relayHeaders옵션 섹션에 대한 설명을 참조하십시오. 경로를 따라 CXF 엔드포인트 릴레이 헤더가 있어야 합니다. 현재 dataFormat=POJODefault:true:true,false경우에만 사용할 수 있습니다.

래핑

없음

다음 중 CXF 엔드포인트 생산자가 호출할 작업 유형은 무엇입니까. 가능한 값은 true,false (기본값) 입니다.

wrappedStyle

없음

2.5.0 이후 매개변수가 SOAP 본문에 표시되는 방법을 설명하는 WSDL 스타일입니다. 값이 false 인 경우 CXF는 문서 지향되지 않은 스타일을 선택합니다. 값이 true 인 경우 CXF는 문서 구조를 래핑하는 스타일을 선택합니다.

setDefaultBus

없음

deprecated: 이 끝점에 대해 기본 CXF 버스를 사용할지 여부를 지정합니다. 가능한 값은 true,false (기본값) 입니다. 이 옵션은 더 이상 사용되지 않으며 Camel 2.16 이후의 defaultBus 를 사용해야 합니다.

defaultBus

없음

deprecated: 이 끝점에 대해 기본 CXF 버스를 사용할지 여부를 지정합니다. 가능한 값은 true,false (기본값) 입니다. 이 옵션은 더 이상 사용되지 않으며 Camel 2.16 이후의 defaultBus 를 사용해야 합니다.

bus

없음

\# 표기법을 사용하여 레지스트리에서 버스 오브젝트를 참조할 수 있습니다(예: bus=\#busName ). 참조된 오브젝트는 org.apache.cxf.Bus 의 인스턴스여야 합니다.

기본적으로, CXF 버스 팩토리에 의해 생성된 기본 버스를 사용합니다.

cxfBinding

없음

\# 표기법을 사용하여 레지스트리에서 CXF 바인딩 오브젝트를 참조할 수 있습니다(예: cxfBinding=\#bindingName ). 참조된 오브젝트는 org.apache.camel.component.cxf.CxfBinding 의 인스턴스여야 합니다.

headerFilterStrategy

없음

\# 표기법을 사용하여 레지스트리의 header 필터 전략 오브젝트(예: headerFilterStrategy=\#strategyName )를 참조합니다. 참조된 오브젝트는 org.apache.camel.spi.HeaderFilterStrategy 의 인스턴스여야 합니다.

loggingFeatureEnabled

없음

2.3의 새로운 기능을 사용하면 인바운드 및 아웃바운드 SOAP 메시지를 로그에 쓰는 CXF Logging 기능을 사용할 수 있습니다. 가능한 값은 true,false (기본값) 입니다.

defaultOperationName

없음

2.4에서 새로 추가된 이 옵션은 원격 서비스를 호출하는 CxfProducer 에서 사용할 기본 operationName 을 설정합니다. 예를 들면 다음과 같습니다.

defaultOperationName=greetMe

defaultOperationNamespace

없음

2.4의 새로운 기능 이 옵션은 원격 서비스를 호출하는 CxfProducer에서 사용할 기본 operationNamespace를 설정합니다. 예를 들면 다음과 같습니다.

defaultOperationNamespace=http://apache.org/hello_world_soap_http

synchronous

없음

2.5의 새로운 기능을 통해 CXF 엔드포인트가 동기화 또는 async API를 사용하여 기본 작업을 수행하도록 결정할 수 있습니다. 기본값은 false 이며, 즉 camel-cxf 엔드포인트는 기본적으로 async API를 사용하려고 합니다.

publishedEndpointUrl

없음

2.5의 새로운 기능인 이 옵션은 서비스 주소 URL과 ?wsdl 을 사용하여 액세스한 게시된 WSDL에 나타나는 엔드포인트 URL을 재정의합니다. 예를 들면 다음과 같습니다.

publshedEndpointUrl=http://example.com/service

properties.propName

없음

Camel 2.8: 엔드포인트 URI에서 사용자 지정 CXF 속성을 설정할 수 있습니다. 예를 들어 properties.mtom-enabled=true 를 설정하여 MTOM을 활성화합니다. 호출을 시작할 때 CXF가 스레드를 전환하지 않도록 하려면 properties.org.apache.cxf.interceptor.OneWayProcessorInterceptor.USE_ORIGINAL_THREAD=true.

allowStreaming

없음

2.8.2의 새로운 기능 이 옵션은 PAYLOAD 모드에서 실행할 때(아래 참조)에서 CXF 구성 요소를 제어하는지 여부를 제어합니다(아래 참조)는 수신되는 메시지를 DOM Elements로 구문 분석하거나 페이로드를 일부 경우에 허용하는 javax.xml.transform.Source 개체로 유지합니다.

skipFaultLogging

없음

2.11의 새로운 기능. 이 옵션은 phaseInterceptorChain이 catch하는 Fault 로깅을 건너뛰는지 여부를 제어합니다.

cxfEndpointConfigurer

없음

Camel 2.11 의 새로운 기능. 이 옵션은 프로그래밍 방식으로 CXF 엔드포인트 구성을 지원하는 org.apache.camel.component.cxfEndpointConfigurer 의 구현을 적용할 수 있습니다. Camel 2.15.0 이후 사용자는 CxfEndpointConfigurer 의 configure{Server/Client} 메서드를 구현하여 CXF 서버 및 클라이언트를 구성할 수 있습니다.

사용자 이름

없음

Camel 2.12.3 의 새로운 기능은 CXF 클라이언트에 대한 사용자 이름의 기본 인증 정보를 설정하는 데 사용됩니다.

암호

없음

Camel 2.12.3 의 새로운 기능 이 옵션은 CXF 클라이언트의 암호에 대한 기본 인증 정보를 설정하는 데 사용됩니다.

continuationTimeout

없음

Camel 2.14.0 의 새로운 기능은 CXF 서버가 Jetty 또는 Servlet 전송을 사용할 때 기본적으로 CxfConsumer에서 사용할 수 있는 CXF 연속 타임아웃을 설정하는 데 사용됩니다. ( Cx fConsumer는 연속 시간 초과를 0으로 설정하므로 연속 일시 중지 작업이 시간 초과되지 않음을 의미합니다.)

기본값: 30000 : 연속 = 80000

serviceNameportNameQNames 이므로, 제공한 경우 위의 예에 표시된 대로 {namespace} 로 접두사가 있어야 합니다.

77.5. dataformat에 대한 설명

DataFormat

설명

POJO

POJO(plain old Java 객체)는 대상 서버에서 호출되는 메서드에 대한 Java 매개 변수입니다. 프로토콜 및 논리 JAX-WS 핸들러가 모두 지원됩니다.

페이로드

PAYLOAD 는 CXF 끝점의 메시지 구성이 적용된 후 메시지 페이로드( soap:body)입니다. 프로토콜 JAX-WS 핸들러만 지원됩니다. 논리 JAX-WS 핸들러는 지원되지 않습니다.

MESSAGE

MESSAGE 는 전송 계층에서 수신한 원시 메시지입니다. 이러한 종류의 DataFormat을 사용하는 경우 일부 CXF 인터셉터는 제거되지 않으므로 camel-cxf 소비자 및 JAX-WS 처리기가 지원되지 않습니다.

CXF_MESSAGE

Camel 2.8.2 의 새로운 기능CXF_MESSAGE 를 사용하면 전송 계층에서 원시 SOAP 메시지로 메시지를 변환하여 CXF 인터셉터의 전체 기능을 호출할 수 있습니다.

교환 속성 CamelCXFDataFormat 을 검색하여 교환의 데이터 형식 모드를 결정할 수 있습니다. 교환 키 상수는 org.apache.camel.component.cxf.CxfConstants.DATA_FORMAT_PROPERTY 에서 정의됩니다.

77.6. Apache Aries Blueprint를 사용하여 CXF 엔드포인트 구성.

Camel 2.8부터 CXF 엔드포인트에 대한 Aries 청사진 종속성 주입을 사용할 수 있습니다. 스키마는 Spring 스키마와 매우 유사하므로 전환은 상당히 투명합니다.

예를 들면 다음과 같습니다.

 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
            xmlns:camel-cxf="http://camel.apache.org/schema/blueprint/cxf"
 	   xmlns:cxfcore="http://cxf.apache.org/blueprint/core"
            xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

       <camel-cxf:cxfEndpoint id="routerEndpoint"
                      address="http://localhost:9001/router"
                      serviceClass="org.apache.servicemix.examples.cxf.HelloWorld">
         <camel-cxf:properties>
             <entry key="dataFormat" value="MESSAGE"/>
         </camel-cxf:properties>
      </camel-cxf:cxfEndpoint>

      <camel-cxf:cxfEndpoint id="serviceEndpoint"
			address="http://localhost:9000/SoapContext/SoapPort"
                     serviceClass="org.apache.servicemix.examples.cxf.HelloWorld">
    </camel-cxf:cxfEndpoint>

    <camelContext xmlns="http://camel.apache.org/schema/blueprint">
        <route>
            <from uri="routerEndpoint"/>
            <to uri="log:request"/>
        </route>
    </camelContext>

</blueprint>

현재 endpoint 요소는 지원되는 첫 번째 CXF 네임스페이스handler입니다.

또한 Spring에서와 마찬가지로 빈 참조를 사용할 수도 있습니다.

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
           xmlns:jaxws="http://cxf.apache.org/blueprint/jaxws"
           xmlns:cxf="http://cxf.apache.org/blueprint/core"
           xmlns:camel="http://camel.apache.org/schema/blueprint"
           xmlns:camelcxf="http://camel.apache.org/schema/blueprint/cxf"
           xsi:schemaLocation="
             http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
             http://cxf.apache.org/blueprint/jaxws http://cxf.apache.org/schemas/blueprint/jaxws.xsd
             http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
             ">

    <camelcxf:cxfEndpoint id="reportIncident"
                     address="/camel-example-cxf-blueprint/webservices/incident"
                     wsdlURL="META-INF/wsdl/report_incident.wsdl"
                     serviceClass="org.apache.camel.example.reportincident.ReportIncidentEndpoint">
    </camelcxf:cxfEndpoint>

    <bean id="reportIncidentRoutes" class="org.apache.camel.example.reportincident.ReportIncidentRoutes" />

    <camelContext xmlns="http://camel.apache.org/schema/blueprint">
        <routeBuilder ref="reportIncidentRoutes"/>
    </camelContext>

</blueprint>

77.7. MESSAGE 모드에서 CXF의 LoggingOutInterceptor를 활성화하는 방법

CXF의 LoggingOutInterceptor 는 유선 로깅 시스템 (java.util.logging)으로 들어오는 아웃바운드 메시지를 출력합니다. LoggingOutInterceptorPRE_STREAM 단계에 있기 때문에 (하지만 PRE_STREAM 단계가 MESSAGE 모드에서 제거됨)이므로 WRITE 단계에서 LoggingOutInterceptor 를 실행하도록 구성해야 합니다. 다음은 예제입니다.

   <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor">
        <!--  it really should have been user-prestream but CXF does have such phase! -->
        <constructor-arg value="target/write"/>
   </bean>

<cxf:cxfEndpoint id="serviceEndpoint" address="http://localhost:9002/helloworld"
	serviceClass="org.apache.camel.component.cxf.HelloService">
	<cxf:outInterceptors>
	    <ref bean="loggingOutInterceptor"/>
	</cxf:outInterceptors>
	<cxf:properties>
		<entry key="dataFormat" value="MESSAGE"/>
	</cxf:properties>
</cxf:cxfEndpoint>

77.8. relayHeaders 옵션에 대한 설명

JAXWSWS -first 개발자의 관점에서 볼 때 대역 및 대역 외 온-선 헤더가 있습니다.

인 밴드 헤더는 SOAP 헤더와 같은 끝점에 대한 WSDL 바인딩 계약의 일부로 명시적으로 정의된 헤더입니다.

대역 외 헤더는 유선을 통해 직렬화되는 헤더이지만 WSDL 바인딩 계약의 일부는 명시적으로 포함되지 않습니다.

헤더 릴레이/필터링은 양방향입니다.

경로에 CXF 엔드포인트가 있고 개발자가 SOAP 헤더와 같은 on-the-wire 헤더가 있어야 하는 경우 다른 JAXWS 엔드포인트에서 사용할 경로를 따라 릴레이된 다음 relayHeaderstrue 로 설정해야 합니다. 그러면 relayHeaders는 기본값입니다.

77.9. POJO 모드에서만 사용 가능

relayHeaders=true 설정은 헤더를 릴레이하려는 의도를 표시합니다. 지정된 헤더를 릴레이하는지 여부에 대한 실제 결정은 MessageHeadersRelay 인터페이스를 구현하는 플러그형 인스턴스에 위임됩니다. MessageHeadersRelay 의 구체적인 구현을 참조하여 헤더를 릴레이해야 하는지 여부를 결정합니다. 이미 잘 알려진 SOAP 네임 스페이스에 자체적으로 바인딩하는 SoapMessageHeadersRelay 구현이 이미 있습니다. 현재 대역 외 헤더만 필터링되고, relayHeaders=true 일 때 항상 대역 내 헤더가 중계됩니다. 이름 공간이 런타임에서 알 수 없는 전선에 헤더가 있는 경우 fall DefaultMessageHeadersRelay 가 사용됩니다. 그러면 단순히 모든 헤더를 릴레이할 수 있습니다.

relayHeaders=false 설정은 모든 헤더, 대역 내 및 대역 외가 삭제됨을 나타냅니다.

자체 MessageHeadersRelay 구현을 재정의하거나 릴레이 목록에 추가할 수 있습니다. 사전 로드된 릴레이 인스턴스를 재정의하려면 MessageHeadersRelay 구현 서비스가 재정의하려는 것과 동일한 네임 스페이스를 제공하는지 확인하십시오. 또한 덮어쓰기 릴레이는 모든 네임 스페이스를 재정의하려는 항목으로 제공해야 합니다. 그러지 않으면 인스턴스 매핑을 릴레이하는 네임 스페이스에 모호함을 도입하므로 라우팅 시작 시 런타임 예외가 throw됩니다.

<cxf:cxfEndpoint ...>
   <cxf:properties>
     <entry key="org.apache.camel.cxf.message.headers.relays">
       <list>
         <ref bean="customHeadersRelay"/>
       </list>
     </entry>
   </cxf:properties>
 </cxf:cxfEndpoint>
 <bean id="customHeadersRelay" class="org.apache.camel.component.cxf.soap.headers.CustomHeadersRelay"/>

여기에서 릴레이/drop 헤더를 릴레이할 수 있는 방법을 보여주는 테스트를 살펴보십시오.

링크:https://svn.apache.org/repos/asf/camel/branches/camel-1.x/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/soap/headers/CxfMessageHeadersRelayTest.java[https://svn.apache.org/repos/asf/camel/branches/camel-1.x/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/soap/headers/CxfMessageHeadersRelayTest.java ]

77.10. Release 2.0 이후의 변경

  • POJOPAYLOAD 모드가 지원됩니다. POJO 모드에서는 대역 내 헤더가 CXF에 의해 헤더 목록에서 처리 및 제거됨에 따라 대역 외 메시지 헤더만 필터링할 수 있습니다. 대역 내 헤더는 POJO 모드의 MessageContentList 에 통합되어 있습니다. camel-cxf 구성 요소에서 대역 내 헤더를 필터링해야 하는 경우, CXF 인터셉터/JAXWS Handler에 PAYLOAD 모드 또는 플러그를 사용하여 (prettyly) CXF 인터셉터/JAXWS Handler를 사용하여 MessageContentList 에서 인 대역폭 헤더를 제거하려고 합니다.
  • Message Header Relay 메커니즘이 CxfHeaderFilterStrategy 에 병합되었습니다. relayHeaders 옵션, 해당 의미 체계 및 기본값은 동일하게 유지되지만 CxfHeaderFilterStrategy 의 속성입니다. 다음은 이를 구성하는 예입니다.

    <bean id="dropAllMessageHeadersStrategy" class="org.apache.camel.component.cxf.common.header.CxfHeaderFilterStrategy">
    
        <!--  Set relayHeaders to false to drop all SOAP headers -->
        <property name="relayHeaders" value="false"/>
    
    </bean>

    그런 다음 끝점에서 CxfHeaderFilterStrategy 를 참조할 수 있습니다.

    <route>
        <from uri="cxf:bean:routerNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
        <to uri="cxf:bean:serviceNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
    </route>
  • MessageHeadersRelay 인터페이스가 약간 변경되었으며 이름이 MessageHeaderFilter 로 변경되었습니다. CxfHeaderFilterStrategy 의 속성입니다. 다음은 사용자 정의 메시지 헤더 필터를 구성하는 예입니다.

    <bean id="customMessageFilterStrategy" class="org.apache.camel.component.cxf.common.header.CxfHeaderFilterStrategy">
        <property name="messageHeaderFilters">
            <list>
                <!--  SoapMessageHeaderFilter is the built in filter.  It can be removed by omitting it. -->
                <bean class="org.apache.camel.component.cxf.common.header.SoapMessageHeaderFilter"/>
    
                <!--  Add custom filter here -->
                <bean class="org.apache.camel.component.cxf.soap.headers.CustomHeaderFilter"/>
            </list>
        </property>
    </bean>
  • relayHeaders 외에 CxfHeaderFilterStrategy 에서 구성할 수 있는 새로운 속성이 있습니다.

이름

설명

type

필수 여부

기본값

relayHeaders

모든 메시지 헤더는 Message Header Filters에 의해 처리됩니다.

boolean

없음

True (1.6.1 동작)

relayAllMessageHeaders

모든 메시지 헤더가 전파됩니다(메시지 헤더 필터에 의한 처리 없이)

boolean

없음

False (1.6.1 동작)

allowFilterNamespaceClash

활성화 네임스페이스에서 두 필터가 겹치는 경우 속성은 처리 방법을 제어합니다. 값이 true 이면 마지막으로 이기게 됩니다. 값이 false 인 경우 예외가 throw됩니다.

boolean

없음

False (1.6.1 동작)

77.11. Spring을 사용하여 CXF 엔드포인트 구성

아래에 표시된 Spring 구성 파일을 사용하여 CXF 엔드포인트를 구성할 수 있으며, 해당 엔드포인트를 camelContext 태그에 포함할 수도 있습니다. 서비스 끝점을 호출할 때 operationNameoperationNamespace 헤더를 호출할 작업을 명시적으로 state로 설정할 수 있습니다.

참고 Camel 2.x에서는 http://camel.apache.org/schema/cxf 을 CXF 엔드포인트의 대상 네임스페이스로 사용하도록 변경되었습니다.

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:cxf="http://camel.apache.org/schema/cxf"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd     ">
 ...
참고

Apache Camel 2.x에서 http://activemq.apache.org/camel/schema/cxfEndpoint 네임스페이스가 http://camel.apache.org/schema/cxf 로 변경되었습니다.

루트 빈 요소에 지정된 JAX-WS 스키마Location 속성을 포함해야 합니다. 이를 통해 CXF는 파일의 유효성을 검사하고 필요합니다. 또한 결합된 {namespace}localName 구문이 현재 이 태그의 특성 값에 대해 지원되지 않으므로 < cxf:cxfEndpoint /> 태그의 끝에 네임스페이스 선언이 필요합니다.

cxf:cxfEndpoint 요소는 다음과 같은 많은 추가 특성을 지원합니다.

이름

PortName

이 서비스가 구현되는 엔드포인트 이름은 wsdl:port@name 에 매핑됩니다. ns:PORT_NAME 형식의 에서 ns 는 이 범위에서 유효한 네임스페이스 접두사입니다.

serviceName

이 서비스가 구현되고 있는 서비스 이름은 wsdl:service@name 에 매핑됩니다. ns:SERVICE_NAME 형식의 에서 ns 는 이 범위에서 유효한 네임스페이스 접두사입니다.

wsdlURL

WSDL의 위치입니다. classpath, 파일 시스템에 있거나 원격으로 호스팅될 수 있습니다.

bindingId

사용할 서비스 모델의 bindingId 입니다.

주소

서비스는 공개 주소입니다.

bus

JAX-WS 엔드포인트에서 사용할 버스 이름입니다.

serviceClass

JSR181 주석이 있거나 없을 수 있는 SEI(Service Endpoint Interface) 클래스의 클래스 이름입니다.

또한 많은 자식 요소를 지원합니다.

이름

cxf:inInterceptors

이 끝점의 들어오는 인터셉터입니다. < bean> 또는 & lt; ref> 목록입니다.

cxf:inFaultInterceptors

이 끝점에 대한 들어오는 오류 인터셉터입니다. < bean> 또는 & lt; ref> 목록입니다.

cxf:outInterceptors

이 끝점의 발신 인터셉터입니다. < bean> 또는 & lt; ref> 목록입니다.

cxf:outFaultInterceptors

이 끝점의 발신 오류 인터셉터입니다. < bean> 또는 & lt; ref> 목록입니다.

CXF:properties

JAX-WS 엔드포인트에 제공해야 하는 속성 맵입니다. 아래를 참조하십시오.

cxf:handlers

JAX-WS 엔드포인트에 제공해야 하는 JAX-WS 핸들러 목록입니다. 아래를 참조하십시오.

cxf:dataBinding

끝점에서 사용할 DataBinding을 지정할 수 있습니다.You can specify the DataBinding will be used in the endpoint. 이는 Spring < bean class="MyDataBinding" /> 구문을 사용하여 제공할 수 있습니다.

cxf:binding

이 끝점에서 사용할 BindingFactory 를 지정할 수 있습니다.You can specify the BindingFactory for this endpoint to use. 이는 Spring < bean class="MyBindingFactory" /> 구문을 사용하여 제공할 수 있습니다.

cxf:features

이 끝점에 대한 인터셉터를 보유하는 기능입니다. < bean> s 또는< ref> s목록

cxf:schemaLocations

사용할 끝점의 스키마 위치입니다. < schemaLocation> s목록

cxf:serviceFactory

이 엔드포인트에서 사용할 서비스 팩토리입니다. 이는 Spring < bean class="MyServiceFactory"/> 구문을 사용하여 제공할 수 있습니다.

인터셉터, 속성 및 핸들러를 제공하는 방법을 보여주는 고급 예제를 찾을 수 있습니다. http://cwiki.apache.org/CXF20DOC/jax-ws-configuration.html

참고

CXF:properties를 사용하여 Spring 구성 파일에서 CXF 끝점의 dataFormatsetDefaultBus 속성을 다음과 같이 설정할 수 있습니다.

<cxf:cxfEndpoint id="testEndpoint" address="http://localhost:9000/router"
     serviceClass="org.apache.camel.component.cxf.HelloService"
     endpointName="s:PortName"
     serviceName="s:ServiceName"
     xmlns:s="http://www.example.com/test">
     <cxf:properties>
       <entry key="dataFormat" value="MESSAGE"/>
       <entry key="setDefaultBus" value="true"/>
     </cxf:properties>
   </cxf:cxfEndpoint>

77.12. camel-cxf 구성 요소가 java.util.logging 대신 log4j를 사용하도록 설정하는 방법

CXF의 기본 로거는 java.util.logging 입니다. log4j 로 변경하려면 다음과 같이 진행하십시오. META-INF/cxf/org.apache.cxf.logger 라는 클래스 경로에 파일을 만듭니다. 이 파일에는 주석이 없는 org.apache.cxf.common.logging.Log4jLogger 클래스의 정규화된 이름이 포함되어야 합니다.

77.13. xml 시작 문서로 camel-cxf 응답 메시지를 보내는 방법

PHP와 같은 몇 가지 SOAP 클라이언트를 사용하는 경우 CXF가 XML 시작 문서 < ?xml 버전="1.0" encoding="utf-8"? >을 추가하지 않기 때문에 이러한 종류의 오류가 발생합니다.

Error:sendSms: SoapFault exception: [Client] looks like we got no XML document in [...]

이 문제를 해결하려면 StaxOutInterceptor에 XML 시작 문서를 작성해야 합니다.

public class WriteXmlDeclarationInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    public WriteXmlDeclarationInterceptor() {
        super(Phase.PRE_STREAM);
        addBefore(StaxOutInterceptor.class.getName());
    }

    public void handleMessage(SoapMessage message) throws Fault {
        message.put("org.apache.cxf.stax.force-start-document", Boolean.TRUE);
    }

}

고객 인터셉터를 다음과 같이 추가하고 camel-cxf endpont로 구성할 수 있습니다.

<cxf:cxfEndpoint id="routerEndpoint" address="http://localhost:${CXFTestSupport.port2}/CXFGreeterRouterTest/CamelContext/RouterPort"
 		serviceClass="org.apache.hello_world_soap_http.GreeterImpl"
 		skipFaultLogging="true">
     <cxf:outInterceptors>
         <!-- This interceptor will force the CXF server send the XML start document to client -->
         <bean class="org.apache.camel.component.cxf.WriteXmlDeclarationInterceptor"/>
     </cxf:outInterceptors>
     <cxf:properties>
         <!-- Set the publishedEndpointUrl which could override the service address from generated WSDL as you want -->
         <entry key="publishedEndpointUrl" value="http://www.simple.com/services/test" />
     </cxf:properties>
 </cxf:cxfEndpoint>

또는 Camel 2.4 를 사용하는 경우 이와 같이 메시지 헤더를 추가합니다.

 // set up the response context which force start document
 Map<String, Object> map = new HashMap<String, Object>();
 map.put("org.apache.cxf.stax.force-start-document", Boolean.TRUE);
 exchange.getOut().setHeader(Client.RESPONSE_CONTEXT, map);

77.14. POJO 데이터 형식의 camel-cxf 끝점에서 메시지를 사용하는 방법

camel-cxf 엔드포인트 소비자 POJO 데이터 형식은 cxf 호출자 를 기반으로 하므로 메시지 헤더에는 CxfConstants.OPERATION_NAME 및 메시지 본문이 SEI 메서드 매개 변수의 목록입니다.

public class PersonProcessor implements Processor {

    private static final transient Logger LOG = LoggerFactory.getLogger(PersonProcessor.class);

    @SuppressWarnings("unchecked")
    public void process(Exchange exchange) throws Exception {
        LOG.info("processing exchange in camel");

        BindingOperationInfo boi = (BindingOperationInfo)exchange.getProperty(BindingOperationInfo.class.toString());
        if (boi != null) {
            LOG.info("boi.isUnwrapped" + boi.isUnwrapped());
        }
        // Get the parameters list which element is the holder.
        MessageContentsList msgList = (MessageContentsList)exchange.getIn().getBody();
        Holder<String> personId = (Holder<String>)msgList.get(0);
        Holder<String> ssn = (Holder<String>)msgList.get(1);
        Holder<String> name = (Holder<String>)msgList.get(2);

        if (personId.value == null || personId.value.length() == 0) {
            LOG.info("person id 123, so throwing exception");
            // Try to throw out the soap fault message
            org.apache.camel.wsdl_first.types.UnknownPersonFault personFault =
                new org.apache.camel.wsdl_first.types.UnknownPersonFault();
            personFault.setPersonId("");
            org.apache.camel.wsdl_first.UnknownPersonFault fault =
                new org.apache.camel.wsdl_first.UnknownPersonFault("Get the null value of person name", personFault);
            // Since camel has its own exception handler framework, we can't throw the exception to trigger it
            // We just set the fault message in the exchange for camel-cxf component handling and return
            exchange.getOut().setFault(true);
            exchange.getOut().setBody(fault);
            return;
        }

        name.value = "Bonjour";
        ssn.value = "123";
        LOG.info("setting Bonjour as the response");
        // Set the response message, first element is the return value of the operation,
        // the others are the holders of method parameters
        exchange.getOut().setBody(new Object[] {null, personId, ssn, name});
    }

}

77.15. POJO 데이터 형식에서 camel-cxf 엔드포인트에 대한 메시지를 준비하는 방법

camel-cxf 엔드포인트 생산자는 cxf 클라이언트 API 를 기반으로 합니다. 먼저 메시지 헤더에 작업 이름을 지정한 다음 메서드 매개 변수를 목록에 추가하고 이 매개변수 목록을 사용하여 메시지를 초기화해야 합니다. 응답 메시지의 본문은 messageContentsList 이므로 해당 목록에서 결과를 가져올 수 있습니다.

메시지 헤더에 작업 이름을 지정하지 않으면 CxfProducerCxfEndpoint 에서 defaultOperationName 을 사용합니다. CxfEndpointdefaultOperationName 이 설정되어 있지 않으면 작업 목록에서 첫 번째 작업 이름을 선택합니다.

메시지 본문에서 개체 배열을 가져오려면 다음과 같이 message.getbody(Object[].class) 를 사용하여 본문을 가져올 수 있습니다.

Exchange senderExchange = new DefaultExchange(context, ExchangePattern.InOut);
final List<String> params = new ArrayList<String>();
// Prepare the request message for the camel-cxf procedure
params.add(TEST_MESSAGE);
senderExchange.getIn().setBody(params);
senderExchange.getIn().setHeader(CxfConstants.OPERATION_NAME, ECHO_OPERATION);

Exchange exchange = template.send("direct:EndpointA", senderExchange);

org.apache.camel.Message out = exchange.getOut();
// The response message's body is an MessageContentsList which first element is the return value of the operation,
// If there are some holder parameters, the holder parameter will be filled in the reset of List.
// The result will be extract from the MessageContentsList with the String class type
MessageContentsList result = (MessageContentsList)out.getBody();
LOG.info("Received output text: " + result.get(0));
Map<String, Object> responseContext = CastUtils.cast((Map<?, ?>)out.getHeader(Client.RESPONSE_CONTEXT));
assertNotNull(responseContext);
assertEquals("We should get the response context here", "UTF-8", responseContext.get(org.apache.cxf.message.Message.ENCODING));
assertEquals("Reply body on Camel is wrong", "echo " + TEST_MESSAGE, result.get(0));

77.16. PAYLOAD 데이터 형식의 camel-cxf 엔드포인트에 대한 메시지를 처리하는 방법

Apache Camel 2.0: CxfMessage.getBody() 는 SOAP 메시지 헤더 및 Body 요소에 대한 getter가 있는 org.apache.camel.component.cxf.CxfPayload 오브젝트를 반환합니다. 이러한 변경으로 기본 CXF 메시지를 Apache Camel 메시지에서 분리할 수 있습니다.

protected RouteBuilder createRouteBuilder() {
    return new RouteBuilder() {
        public void configure() {
            from(SIMPLE_ENDPOINT_URI + "&dataFormat=PAYLOAD").to("log:info").process(new Processor() {
                @SuppressWarnings("unchecked")
                public void process(final Exchange exchange) throws Exception {
                    CxfPayload<SoapHeader> requestPayload = exchange.getIn().getBody(CxfPayload.class);
                    List<Source> inElements = requestPayload.getBodySources();
                    List<Source> outElements = new ArrayList<Source>();
                    // You can use a customer toStringConverter to turn a CxfPayLoad message into String as you want
                    String request = exchange.getIn().getBody(String.class);
                    XmlConverter converter = new XmlConverter();
                    String documentString = ECHO_RESPONSE;

                    Element in = new XmlConverter().toDOMElement(inElements.get(0));
                    // Just check the element namespace
                    if (!in.getNamespaceURI().equals(ELEMENT_NAMESPACE)) {
                        throw new IllegalArgumentException("Wrong element namespace");
                    }
                    if (in.getLocalName().equals("echoBoolean")) {
                        documentString = ECHO_BOOLEAN_RESPONSE;
                        checkRequest("ECHO_BOOLEAN_REQUEST", request);
                    } else {
                        documentString = ECHO_RESPONSE;
                        checkRequest("ECHO_REQUEST", request);
                    }
                    Document outDocument = converter.toDOMDocument(documentString);
                    outElements.add(new DOMSource(outDocument.getDocumentElement()));
                    // set the payload header with null
                    CxfPayload<SoapHeader> responsePayload = new CxfPayload<SoapHeader>(null, outElements, null);
                    exchange.getOut().setBody(responsePayload);
                }
            });
        }
    };
}

77.17. How to get and set SOAP headers in POJO mode

POJO 는 CXF 엔드포인트가 Camel Exchange를 생성하거나 사용할 때 데이터 형식이 Java 개체의 목록 임을 의미합니다. Apache Camel은 이 모드에서 메시지 본문을 POJO로 공개하지만 CXF 구성 요소는 SOAP 헤더를 읽고 쓸 수 있는 액세스 권한을 계속 제공합니다. 그러나 CXF 인터셉터는 처리된 후 헤더 목록에서 인 대역 내 SOAP 헤더를 제거하므로 대역 외 SOAP 헤더만 POJO 모드에서 사용할 수 있습니다.

다음 예제에서는 SOAP 헤더를 가져오거나 설정하는 방법을 보여줍니다. 한 CXF 끝점에서 다른 CXF 엔드포인트로 전달하는 경로가 있다고 가정합니다. 즉, SOAP 클라이언트 → Apache Camel → CXF 서비스입니다. 요청이 CXF 서비스에 나가기 전에 (1)에 SOAP 헤더를 가져오고 삽입하기 위해 두 개의 프로세서를 연결하고, (2) 응답이 SOAP Client로 되돌아오기 전에 연결할 수 있습니다. 이 예에서 프로세서 (1) 및 (2)는 InsertRequestOutHeaderProcessor 및 InsertResponseOutHeaderProcessor입니다. 우리의 경로는 다음과 같습니다.

<route>
    <from uri="cxf:bean:routerRelayEndpointWithInsertion"/>
    <process ref="InsertRequestOutHeaderProcessor" />
    <to uri="cxf:bean:serviceRelayEndpointWithInsertion"/>
    <process ref="InsertResponseOutHeaderProcessor" />
</route>

2.x SOAP 헤더는 Apache Camel Message 헤더로 또는 Apache Camel Message 헤더로 전파됩니다. Apache Camel 메시지 헤더 이름은 org.apache.cxf.headers.Header.list 이며, CXF(org.apache.cxf.headers.Header.HEADER_LIST)에 정의된 상수입니다. 헤더 값은 CXF SoapHeader 오브젝트(org.apache.cxf.binding.soap.Soap.Soap.Soap)의 List <>입니다. 다음 스니펫은 InsertResponseOutHeaderProcessor (응답 메시지에 새 SOAP 헤더를 삽입함)입니다. InsertResponseOutHeaderProcessorInsertRequestOutHeaderProcessor 에서 SOAP 헤더에 액세스하는 방법은 실제로 동일합니다. 두 프로세서의 유일한 차이점은 삽입된 SOAP 헤더의 방향을 설정하는 것입니다.

public static class InsertResponseOutHeaderProcessor implements Processor {

    @SuppressWarnings("unchecked")
    public void process(Exchange exchange) throws Exception {
        // You should be able to get the header if exchange is routed from camel-cxf endpoint
        List<SoapHeader> soapHeaders = CastUtils.cast((List<?>)exchange.getIn().getHeader(Header.HEADER_LIST));
        if (soapHeaders == null) {
            // we just create a new soap headers in case the header is null
            soapHeaders = new ArrayList<SoapHeader>();
        }

        // Insert a new header
        String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><outofbandHeader "
            + "xmlns=\"http://cxf.apache.org/outofband/Header\" hdrAttribute=\"testHdrAttribute\" "
            + "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" soap:mustUnderstand=\"1\">"
            + "<name>New_testOobHeader</name><value>New_testOobHeaderValue</value></outofbandHeader>";
        SoapHeader newHeader = new SoapHeader(soapHeaders.get(0).getName(),
                       DOMUtils.readXml(new StringReader(xml)).getDocumentElement());
        // make sure direction is OUT since it is a response message.
        newHeader.setDirection(Direction.DIRECTION_OUT);
        //newHeader.setMustUnderstand(false);
        soapHeaders.add(newHeader);

    }

}

77.18. PAYLOAD 모드에서 SOAP 헤더를 가져오고 설정하는 방법

PAYLOAD 모드에서 SOAP 메시지(CxfPayload 오브젝트)에 액세스하는 방법을 이미 보여주었습니다( “PAYLOAD 데이터 형식의 camel-cxf 엔드포인트에 대한 메시지를 처리하는 방법”참조).

CxfPayload 오브젝트를 확보하면 CxfPayload.getHeaders() 메서드를 호출하여 DOM Elements(SOAP 헤더) 목록 을 반환합니다.

from(getRouterEndpointURI()).process(new Processor() {
    @SuppressWarnings("unchecked")
    public void process(Exchange exchange) throws Exception {
        CxfPayload<SoapHeader> payload = exchange.getIn().getBody(CxfPayload.class);
        List<Source> elements = payload.getBodySources();
        assertNotNull("We should get the elements here", elements);
        assertEquals("Get the wrong elements size", 1, elements.size());

        Element el = new XmlConverter().toDOMElement(elements.get(0));
        elements.set(0, new DOMSource(el));
        assertEquals("Get the wrong namespace URI", "http://camel.apache.org/pizza/types",
                el.getNamespaceURI());

        List<SoapHeader> headers = payload.getHeaders();
        assertNotNull("We should get the headers here", headers);
        assertEquals("Get the wrong headers size", headers.size(), 1);
        assertEquals("Get the wrong namespace URI",
                ((Element)(headers.get(0).getObject())).getNamespaceURI(),
                "http://camel.apache.org/pizza/types");
    }

})
.to(getServiceEndpointURI());

Camel 2.16.0부터 “How to get and set SOAP headers in POJO mode” 에 설명된 것과 동일한 방법을 사용하여 SOAP 헤더를 설정하거나 가져올 수 있습니다. 이제 org.apache.cxf.headers.Header.list 헤더를 사용하여 SOAP 헤더 목록을 가져오고 설정할 수 있습니다. 즉, 하나의 Camel CXF 끝점에서 다른 (SOAP Client → Camel → CXF 서비스)로 전달하는 경로가 있는 경우 SOAP 클라이언트에서 보낸 SOAP 헤더도 CXF 서비스로 전달됩니다. 헤더를 전달하지 않으려면 org.apache.cxf.headers.Header.list Camel 헤더에서 해당 헤더를 제거합니다.

77.19. MESSAGE 모드에서는 SOAP 헤더를 사용할 수 없습니다.

SOAP 처리를 건너뛰기 때문에 MESSAGE 모드에서 SOAP 헤더를 사용할 수 없습니다.

77.20. Apache Camel에서 SOAP Fault를 throw하는 방법

SOAP 요청을 사용하기 위해 CXF 엔드포인트를 사용하는 경우 camel 컨텍스트에서 SOAP Fault 를 throw해야 할 수 있습니다. 기본적으로 throwFault DSL을 사용하여 이 작업을 수행할 수 있습니다. POJO,PAYLOADMESSAGE 데이터 형식에 대해 작동합니다. 다음과 같이 soap 오류를 정의할 수 있습니다.

SOAP_FAULT = new SoapFault(EXCEPTION_MESSAGE, SoapFault.FAULT_CODE_CLIENT);
Element detail = SOAP_FAULT.getOrCreateDetail();
Document doc = detail.getOwnerDocument();
Text tn = doc.createTextNode(DETAIL_TEXT);
detail.appendChild(tn);

그런 다음, 원하는 대로 던질 수 있습니다:

from(routerEndpointURI).setFaultBody(constant(SOAP_FAULT));

CXF 끝점이 MESSAGE 데이터 형식으로 작동하는 경우 메시지 본문에서 SOAP Fault 메시지를 설정하고 메시지 헤더에 응답 코드를 설정할 수 있습니다.

from(routerEndpointURI).process(new Processor() {

    public void process(Exchange exchange) throws Exception {
        Message out = exchange.getOut();
        // Set the message body with the
        out.setBody(this.getClass().getResourceAsStream("SoapFaultMessage.xml"));
        // Set the response code here
        out.setHeader(org.apache.cxf.message.Message.RESPONSE_CODE, new Integer(500));
    }

});

POJO 데이터 형식에도 마찬가지입니다. Out body에 SOAP Fault를 설정하고 다음과 같이 Message.setFault(true) 를 호출하여 오류임을 나타낼 수 있습니다.

from("direct:start").onException(SoapFault.class).maximumRedeliveries(0).handled(true)
    .process(new Processor() {
        public void process(Exchange exchange) throws Exception {
            SoapFault fault = exchange
                .getProperty(Exchange.EXCEPTION_CAUGHT, SoapFault.class);
            exchange.getOut().setFault(true);
            exchange.getOut().setBody(fault);
        }

    }).end().to(serviceURI);

77.21. CXF 엔드포인트의 요청 및 응답 컨텍스트를 전파하는 방법

CXF 클라이언트 API 는 요청 및 응답 컨텍스트를 사용하여 작업을 호출할 수 있는 방법을 제공합니다. CXF 엔드포인트 생산자를 사용하여 외부 웹 서비스를 호출하는 경우 요청 컨텍스트를 설정하고 다음 코드로 응답 컨텍스트를 가져올 수 있습니다.

        CxfExchange exchange = (CxfExchange)template.send(getJaxwsEndpointUri(), new Processor() {
             public void process(final Exchange exchange) {
                 final List<String> params = new ArrayList<String>();
                 params.add(TEST_MESSAGE);
                 // Set the request context to the inMessage
                 Map<String, Object> requestContext = new HashMap<String, Object>();
                 requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, JAXWS_SERVER_ADDRESS);
                 exchange.getIn().setBody(params);
                 exchange.getIn().setHeader(Client.REQUEST_CONTEXT , requestContext);
                 exchange.getIn().setHeader(CxfConstants.OPERATION_NAME, GREET_ME_OPERATION);
             }
         });
         org.apache.camel.Message out = exchange.getOut();
         // The output is an object array, the first element of the array is the return value
         Object\[\] output = out.getBody(Object\[\].class);
         LOG.info("Received output text: " + output\[0\]);
         // Get the response context form outMessage
         Map<String, Object> responseContext = CastUtils.cast((Map)out.getHeader(Client.RESPONSE_CONTEXT));
         assertNotNull(responseContext);
         assertEquals("Get the wrong wsdl opertion name", "{http://apache.org/hello_world_soap_http}greetMe",
                      responseContext.get("javax.xml.ws.wsdl.operation").toString());

77.22. 첨부 파일 지원

POJO 모드: Attachment 및 MTOM을 사용하는 SOAP가 모두 지원됩니다( MTOM 활성화를 위한 Payload Mode 예제 참조). 그러나 Attachment를 사용한 SOAP은 테스트되지 않습니다. 첨부 파일은 POJO로 마샬링 및 손상되지 않으므로 일반적으로 사용자는 첨부 파일을 직접 처리할 필요가 없습니다. 첨부 파일은 2.1 이후 Camel 메시지의 첨부 파일에 전파됩니다. 따라서 Camel Message API로 다시 연결할 수 있습니다.

DataHandler Message.getAttachment(String id)

.

페이로드 모드: MTOM은 2.1 이후 지원됩니다. 위에서 언급한 Camel Message API를 통해 첨부 파일을 검색할 수 있습니다. 이 모드에서는 SOAP 처리가 없기 때문에 Attachment를 사용한 SOAP가 지원되지 않습니다.

MTOM을 활성화하려면 CXF 엔드포인트 속성 "mtom_enabled"를 true 로 설정합니다. (나는 봄에만 할 수 있다고 생각합니다.)

<cxf:cxfEndpoint id="routerEndpoint" address="http://localhost:${CXFTestSupport.port1}/CxfMtomRouterPayloadModeTest/jaxws-mtom/hello"
         wsdlURL="mtom.wsdl"
         serviceName="ns:HelloService"
         endpointName="ns:HelloPort"
         xmlns:ns="http://apache.org/camel/cxf/mtom_feature">

     <cxf:properties>
         <!--  enable mtom by setting this property to true -->
         <entry key="mtom-enabled" value="true"/>

         <!--  set the camel-cxf endpoint data fromat to PAYLOAD mode -->
         <entry key="dataFormat" value="PAYLOAD"/>
     </cxf:properties>

Payload 모드에서 CXF 엔드포인트에 보낼 첨부 파일로 Camel 메시지를 생성할 수 있습니다.

Exchange exchange = context.createProducerTemplate().send("direct:testEndpoint", new Processor() {

    public void process(Exchange exchange) throws Exception {
        exchange.setPattern(ExchangePattern.InOut);
        List&lt;Source> elements = new ArrayList&lt;Source>();
        elements.add(new DOMSource(DOMUtils.readXml(new StringReader(MtomTestHelper.REQ_MESSAGE)).getDocumentElement()));
        CxfPayload<SoapHeader> body = new CxfPayload<SoapHeader>(new ArrayList<SoapHeader>(),
            elements, null);
        exchange.getIn().setBody(body);
        exchange.getIn().addAttachment(MtomTestHelper.REQ_PHOTO_CID,
            new DataHandler(new ByteArrayDataSource(MtomTestHelper.REQ_PHOTO_DATA, "application/octet-stream")));

        exchange.getIn().addAttachment(MtomTestHelper.REQ_IMAGE_CID,
            new DataHandler(new ByteArrayDataSource(MtomTestHelper.requestJpeg, "image/jpeg")));

    }

});

// process response

CxfPayload<SoapHeader> out = exchange.getOut().getBody(CxfPayload.class);
Assert.assertEquals(1, out.getBody().size());

Map<String, String> ns = new HashMap<String, String>();
ns.put("ns", MtomTestHelper.SERVICE_TYPES_NS);
ns.put("xop", MtomTestHelper.XOP_NS);

XPathUtils xu = new XPathUtils(ns);
Element oute = new XmlConverter().toDOMElement(out.getBody().get(0));
Element ele = (Element)xu.getValue("//ns:DetailResponse/ns:photo/xop:Include", oute,
                                   XPathConstants.NODE);
String photoId = ele.getAttribute("href").substring(4); // skip "cid:"

ele = (Element)xu.getValue("//ns:DetailResponse/ns:image/xop:Include", oute,
                                   XPathConstants.NODE);
String imageId = ele.getAttribute("href").substring(4); // skip "cid:"

DataHandler dr = exchange.getOut().getAttachment(photoId);
Assert.assertEquals("application/octet-stream", dr.getContentType());
MtomTestHelper.assertEquals(MtomTestHelper.RESP_PHOTO_DATA, IOUtils.readBytesFromStream(dr.getInputStream()));

dr = exchange.getOut().getAttachment(imageId);
Assert.assertEquals("image/jpeg", dr.getContentType());

BufferedImage image = ImageIO.read(dr.getInputStream());
Assert.assertEquals(560, image.getWidth());
Assert.assertEquals(300, image.getHeight());

Payload 모드에서 CXF 엔드포인트에서 받은 Camel 메시지를 사용할 수도 있습니다.

public static class MyProcessor implements Processor {

    @SuppressWarnings("unchecked")
    public void process(Exchange exchange) throws Exception {
        CxfPayload<SoapHeader> in = exchange.getIn().getBody(CxfPayload.class);

        // verify request
        assertEquals(1, in.getBody().size());

        Map<String, String> ns = new HashMap<String, String>();
        ns.put("ns", MtomTestHelper.SERVICE_TYPES_NS);
        ns.put("xop", MtomTestHelper.XOP_NS);

        XPathUtils xu = new XPathUtils(ns);
        Element body = new XmlConverter().toDOMElement(in.getBody().get(0));
        Element ele = (Element)xu.getValue("//ns:Detail/ns:photo/xop:Include", body,
                                           XPathConstants.NODE);
        String photoId = ele.getAttribute("href").substring(4); // skip "cid:"
        assertEquals(MtomTestHelper.REQ_PHOTO_CID, photoId);

        ele = (Element)xu.getValue("//ns:Detail/ns:image/xop:Include", body,
                                           XPathConstants.NODE);
        String imageId = ele.getAttribute("href").substring(4); // skip "cid:"
        assertEquals(MtomTestHelper.REQ_IMAGE_CID, imageId);

        DataHandler dr = exchange.getIn().getAttachment(photoId);
        assertEquals("application/octet-stream", dr.getContentType());
        MtomTestHelper.assertEquals(MtomTestHelper.REQ_PHOTO_DATA, IOUtils.readBytesFromStream(dr.getInputStream()));

        dr = exchange.getIn().getAttachment(imageId);
        assertEquals("image/jpeg", dr.getContentType());
        MtomTestHelper.assertEquals(MtomTestHelper.requestJpeg, IOUtils.readBytesFromStream(dr.getInputStream()));

        // create response
        List&lt;Source> elements = new ArrayList&lt;Source>();
        elements.add(new DOMSource(DOMUtils.readXml(new StringReader(MtomTestHelper.RESP_MESSAGE)).getDocumentElement()));
        CxfPayload&lt;SoapHeader> sbody = new CxfPayload&lt;SoapHeader>(new ArrayList&lt;SoapHeader>(),
            elements, null);
        exchange.getOut().setBody(sbody);
        exchange.getOut().addAttachment(MtomTestHelper.RESP_PHOTO_CID,
            new DataHandler(new ByteArrayDataSource(MtomTestHelper.RESP_PHOTO_DATA, "application/octet-stream")));

        exchange.getOut().addAttachment(MtomTestHelper.RESP_IMAGE_CID,
            new DataHandler(new ByteArrayDataSource(MtomTestHelper.responseJpeg, "image/jpeg")));

    }
}

메시지 모드: 첨부 파일은 메시지를 처리하지 않으므로 지원되지 않습니다.

CXF_MESSAGE 모드: MTOM이 지원되며 위에서 언급한 Camel Message API를 통해 첨부 파일을 검색할 수 있습니다. 멀티 파트 (즉, MTOM) 메시지를 수신할 때 기본 SOAPMessage to String 변환기가 본문에 대한 전체 멀티 파트 페이로드를 제공합니다. SOAP XML만 문자열이 필요한 경우 message.getSOAPPart() 를 사용하여 메시지 본문을 설정할 수 있으며 Camel 변환은 나머지 작업을 수행할 수 있습니다.

77.23. 스택 추적 정보를 전파하는 방법

서버 측에서 Java 예외가 throw되면 예외에 대한 스택 추적이 오류 메시지로 마샬링되고 클라이언트에 반환되는 CXF 엔드포인트를 구성할 수 있습니다. 이 feaure를 활성화하려면 dataFormatPAYLOAD 로 설정하고 cxfEndpoint 요소에서 faultStackTraceEnabled 속성을 true 로 설정합니다.

<cxf:cxfEndpoint id="router" address="http://localhost:9002/TestMessage"
    wsdlURL="ship.wsdl"
    endpointName="s:TestSoapEndpoint"
    serviceName="s:TestService"
    xmlns:s="http://test">
  <cxf:properties>
    <!-- enable sending the stack trace back to client; the default value is false-->
    <entry key="faultStackTraceEnabled" value="true" /> <entry key="dataFormat" value="PAYLOAD" />
  </cxf:properties>
</cxf:cxfEndpoint>

보안상의 이유로 스택 추적에는 원인이 되는 예외(즉, 스택 추적의 일부)가 포함되어 있지 않습니다. 스택 추적에 causing 예외를 포함하려면 cxfEndpoint 요소에서 exceptionMessage causesEnabled 속성을 true 로 설정합니다.

<cxf:cxfEndpoint id="router" address="http://localhost:9002/TestMessage"
    wsdlURL="ship.wsdl"
    endpointName="s:TestSoapEndpoint"
    serviceName="s:TestService"
    xmlns:s="http://test">
  <cxf:properties>
    <!-- enable to show the cause exception message and the default value is false -->
    <entry key="exceptionMessageCauseEnabled" value="true" />
    <!-- enable to send the stack trace back to client,  the default value is false-->
    <entry key="faultStackTraceEnabled" value="true" />
    <entry key="dataFormat" value="PAYLOAD" />
  </cxf:properties>
</cxf:cxfEndpoint>
주의

테스트 및 진단 목적으로 exceptionMessage causesEnabled 플래그만 활성화해야 합니다. 서버가 예외의 원래 원인을 숨기고 사용자가 서버를 더 쉽게 검색할 수 있도록 하는 것이 일반적입니다.

77.24. PAYLOAD 모드에서 스트리밍 지원

2.8.2에서 camel-cxf 구성 요소는 PAYLOAD 모드를 사용할 때 수신 메시지의 스트리밍을 지원합니다. 이전에는 들어오는 메시지가 완전히 DOM 구문 분석되었습니다. 대규모 메시지의 경우 시간이 오래 걸리고 상당한 양의 메모리를 사용합니다. 2.8.2부터, 수신 메시지는 라우팅되는 동안 javax.xml.transform.Source로 남아 있을 수 있으며, 아무 것도 페이로드를 수정하지 않으면 대상 목적지로 직접 스트리밍할 수 있습니다. 일반적인 "간단 프록시" 사용 사례(예:("cxf:…​").to("cxf:…​")의 경우 성능이 크게 향상되고 메모리 요구 사항이 크게 저하될 수 있습니다.

그러나 스트리밍이 적절하지 않거나 바람직하지 않은 경우가 있습니다. 스트리밍 특성으로 인해 처리 체인에서 나중에 수신될 때까지 잘못된 수신 XML이 캡처되지 않을 수 있습니다. 또한 특정 동작에서는 메시지를 그대로(예: WS-Security 또는 메시지 추적 등과 같이)로 구문 분석해야 할 수 있습니다.이 경우 스트리밍의 장점이 제한됩니다. 이 시점에서 스트리밍을 제어하는 두 가지 방법이 있습니다.

  • endpoint 속성: "allowStreaming=false"를 끝점 속성으로 추가하여 스트리밍을 해제할 수 있습니다.
  • 구성 요소 속성: CxfComponent 개체에도 해당 구성 요소에서 생성된 엔드포인트의 기본값을 설정할 수 있는 allowStreaming 속성이 있습니다.
  • 글로벌 시스템 속성: "org.apache.camel.component.cxf.streaming"의 시스템 속성을 "false"에 추가하여 끌 수 있습니다. 즉, 글로벌 기본값을 설정하지만 위의 엔드포인트 속성을 설정하면 해당 끝점에 대한 이 값이 재정의됩니다.

77.25. 일반 CXF Dispatch 모드 사용

2.8.0에서 camel-cxf 구성 요소는 임의의 구조의 메시지를 전송할 수 있는 일반 CXF 디스패치 모드 를 지원합니다(즉, 특정 XML 스키마에 바인딩되지 않음). 이 모드를 사용하려면 CXF 끝점의 wsdlURL 및 serviceClass 속성만 지정하면 됩니다.

<cxf:cxfEndpoint id="testEndpoint" address="http://localhost:9000/SoapContext/SoapAnyPort">
  <cxf:properties>
    <entry key="dataFormat" value="PAYLOAD"/>
  </cxf:properties>
</cxf:cxfEndpoint>

기본 CXF 디스패치 클라이언트는 특정 SOAPAction 헤더를 전송하지 않습니다. 따라서 대상 서비스에 특정 SOAPAction 값이 필요한 경우 키 SOAPAction(대소문자를 구분하지 않음)을 사용하여 Camel 헤더에 제공됩니다.

77.1. WildFly의 CXF 소비자

WildFly에서 camel-cxf 소비자의 구성은 독립 실행형 Camel과 다릅니다. 생산자 끝점은 정상적으로 작동합니다.

WildFly에서 camel-cxf 소비자는 컨테이너에서 제공하는 기본 Undertow HTTP 서버를 활용합니다. 서버는 undertow 하위 시스템 구성 내에 정의됩니다. 다음은 standalone.xml의 기본 구성의 발췌 내용입니다.

<subsystem xmlns="urn:jboss:domain:undertow:4.0">
    <buffer-cache name="default" />
    <server name="default-server">
        <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true" />
        <https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true" />
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content" />
            <filter-ref name="server-header" />
            <filter-ref name="x-powered-by-header" />
            <http-invoker security-realm="ApplicationRealm" />
        </host>
    </server>
</subsystem>

이 인스턴스에서 Undertow는 http 및 https socket-binding에서 지정된 인터페이스 / 포트에서 수신 대기하도록 구성됩니다. 기본적으로 이는 https의 경우 http 및 8443의 포트 8080입니다.

예를 들어 다른 호스트 또는 포트 조합을 사용하여 끝점 소비자를 구성하면 서버 로그 파일에 경고가 표시됩니다. 예를 들어 다음 호스트 및 포트 구성은 무시됩니다.

<cxf:rsServer id="cxfRsConsumer"
              address="http://somehost:1234/path/to/resource"
              serviceClass="org.example.ServiceClass" />
<cxf:cxfEndpoint id="cxfWsConsumer"
                 address="http://somehost:1234/path/to/resource"
                 serviceClass="org.example.ServiceClass" />
[org.wildfly.extension.camel] (pool-2-thread-1) Ignoring configured host: http://somehost:1234/path/to/resource

그러나 소비자는 여전히 기본 호스트 localhost:8080 또는 localhost:8443에서 사용할 수 있습니다.

참고

camel-cxf 소비자를 사용하는 애플리케이션은 WAR로 패키징 해야 합니다. 이전 WildFly-Camel 릴리스에서 JAR과 같은 다른 유형의 아카이브는 허용되지만 이는 더 이상 지원되지 않습니다.

77.1.1. 대체 포트 구성

대체 포트를 허용해야 하는 경우 WildFly 하위 시스템 구성을 통해 구성해야 합니다. 이 내용은 서버 문서에 설명되어 있습니다.

https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.1/html/configuration_guide/configuring_the_web_server_undertow

77.1.2. SSL 구성

SSL을 구성하려면 WildFly SSL 구성 가이드를 참조하십시오.

https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.1/html-single/how_to_configure_server_security/#configure_one_way_and_two_way_ssl_tls_for_application

77.1.3. Elytron를 사용하여 보안 구성

WildFly-Camel은 Elytron 보안 프레임워크를 사용하여 camel-cxf 소비자 엔드포인트 보안을 지원합니다.

77.1.3.1. 보안 도메인 구성

Elytron를 사용하여 WildFly-Camel 애플리케이션을 보호하려면 WAR 배포의 WEB-INF/jboss-web.xml 내에서 애플리케이션 보안 도메인을 참조해야 합니다.

<jboss-web>
  <security-domain>my-application-security-domain</security-domain>
</jboss-web>

< security-domain > 구성은 Undertow 하위 시스템에서 정의한 < application-security-domain >의 이름을 참조합니다. 예를 들어, Undertow 하위 시스템 < application-security-domain >은 다음과 같이 WildFly 서버 standalone.xml 구성 파일 내에 구성됩니다.

<subsystem xmlns="urn:jboss:domain:undertow:6.0">
    ...
    <application-security-domains>
        <application-security-domain name="my-application-security-domain" http-authentication-factory="application-http-authentication"/>
    </application-security-domains>
</subsystem>

& lt;http-authentication-factory > application-http-authentication 은 Elytron 하위 시스템에 정의되어 있습니다. application-http-authentication 은 기본적으로 standalone.xmlstandalone-full.xml 서버 구성 파일에서 사용할 수 있습니다. 예를 들면 다음과 같습니다.

<subsystem xmlns="urn:wildfly:elytron:1.2">
    ...
    <http>
        ...
        <http-authentication-factory name="application-http-authentication" http-server-mechanism-factory="global" security-domain="ApplicationDomain">
            <mechanism-configuration>
                <mechanism mechanism-name="BASIC">
                    <mechanism-realm realm-name="Application Realm" />
                </mechanism>
                <mechanism mechanism-name="FORM" />
            </mechanism-configuration>
        </http-authentication-factory>
        <provider-http-server-mechanism-factory name="global" />
    </http>
    ...
</subsystem>

application -http-authentication 이라는 <http-authentication-factory >는 ApplicationDomain 이라는 Elytron 보안 도메인에 대한 참조를 보유하고 있습니다.

Elytron 하위 시스템을 구성하는 방법에 대한 자세한 내용은 Elytron 설명서 를 참조하십시오.

77.1.3.2. 보안 제약 조건, 인증 방법 및 보안 역할 구성

camel-cxf 소비자 엔드 포인트에 대한 보안 제약 조건, 인증 방법 및 보안 역할은 WAR 배포 WEB-INF/web.xml 내에서 구성할 수 있습니다. 예를 들어 BASIC 인증을 구성하려면 다음을 수행합니다.

<web-app>
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>secure</web-resource-name>
      <url-pattern>/webservices/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>my-role</role-name>
    </auth-constraint>
  </security-constraint>
  <security-role>
    <description>The role that is required to log in to /webservices/*</description>
    <role-name>my-role</role-name>
  </security-role>
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>my-realm</realm-name>
  </login-config>
</web-app>

Servlet Specification에 의해 정의된 < url-pattern >은 웹 애플리케이션의 컨텍스트 경로를 기준으로 합니다. 애플리케이션이 my-app.war 로 패키징된 경우 WildFly는 컨텍스트 경로 /my-app 및 < url-patternpattern > /webservices/* 에서 액세스할 수 있도록 /my-app 와 관련된 경로에 적용됩니다.

예를 들어 http://my-server/my-app/webservices/my-endpoint 에 대한 요청은 /webservices/* 패턴과 일치하지만 http://my-server/webservices/my-endpoint 는 일치하지 않습니다.

이는 WildFly-Camel을 사용하면 기본 경로가 호스트 웹 애플리케이션 컨텍스트 경로 외부에 있는 camel-cxf 엔드포인트 소비자를 생성할 수 있기 때문에 중요합니다. 예를 들어 my-app.war 내부에 http://my-server/webservices/my-endpoint 용 camel-cxf 소비자를 생성할 수 있습니다.

컨텍스트 외 엔드포인트에 대한 보안 제약 조건을 정의하기 위해 WildFly-Camel은 세 개의 전달 슬래시 /// /를 사용하여 패턴을 접두사로 붙이는 사용자 지정 비표준 <url- pattern> 규칙을 지원합니다. 예를 들어 my-app.war 내에서 http://my-server/webservices/my-endpoint 을 보호하려면 web.xml 에 다음 구성을 추가합니다.

<web-app>
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>secure</web-resource-name>
      <url-pattern>///webservices/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>my-role</role-name>
    </auth-constraint>
  </security-constraint>
  <security-role>
    <description>The role that is required to log in to /webservices/*</description>
    <role-name>my-role</role-name>
  </security-role>
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>my-realm</realm-name>
  </login-config>
</web-app>