cxf: 구성 요소는 CXF에서 호스팅되는 Cryostat-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>
<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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow
SEI(Service Endpoint Interface) 클래스의 이름입니다. 이 클래스에는 주석이 있을 수 있지만 필요하지는 않습니다. 2.0부터 이 옵션은 Cryostat 모드에서만 필요합니다. wsdlURL 옵션이 제공되면 PAYLOAD 및 MESSAGE 모드에 serviceClass가 필요하지 않습니다. serviceClass 없이 wsdlURL 옵션을 사용하는 경우 serviceName 및 portName( Spring 구성의 경우 endpointName) 옵션을 제공해야 합니다.
2.0부터 \# 표기법을 사용하여 레지스트리의 serviceClass 오브젝트 인스턴스를 참조할 수 있습니다.
참조된 오브젝트는 Spring AOP 프록시 이외의 Object.getClass().getName() 메서드에 의존하므로 프록시(Spring AOP Proxy는 OK)가 될 수 없습니다.
2.8부터 PAYLOAD 및 MESSAGE 모드에 대해 wsdlURL 및 serviceClass 옵션을 모두 생략할 수 있습니다. 생략하면 임의의 XML 요소를 PAYLOAD 모드에서 CxfPayload의 본문에 배치하여 CXF Dispatch Mode를 용이하게 할 수 있습니다.
예: org.apache.camel.Hello
serviceName
WSDL에 둘 이상의 serviceName 이 있는 경우에만
이 서비스가 구현 중인 서비스 이름이며 wsdl:service@name 에 매핑됩니다. 예를 들면 다음과 같습니다.
{http://org.apache.camel}ServiceName
endpointName
serviceName 아래에 있는 portName 이 두 개 이상 있고 camel 2.2 이후 camel-cxf 소비자에는 필요합니다.
이 서비스가 구현 중인 포트 이름이며 wsdl:port@name 에 매핑됩니다. 예를 들면 다음과 같습니다.
{http://org.apache.camel}PortName
dataFormat
없음
CXF 엔드포인트에서 지원하는 메시지 데이터 형식은 무엇입니까. 가능한 값은 Cryostat ( 기본값 ), PAYLOAD,MESSAGE 입니다.
relayHeaders
없음
CXF 엔드포인트가 경로를 따라 헤더를 릴레이하는지 여부를 정의합니다. “relayHeaders 옵션에 대한 설명”을 참조하십시오. 현재 dataFormat=POJO기본값:true예:true,false경우에만 사용할 수 있습니다.
래핑됨
없음
CXF 엔드포인트 프로듀서에서 호출하는 작업 유형은 무엇입니까. 가능한 값은 true,false(기본값)입니다.
wrappedStyle
없음
2.5.0 이후 매개 변수가 Cryostat 본문에 표시되는 방법을 설명하는 WSDL 스타일입니다. 값이 false 이면 CXF는 document-literal 래핑되지 않은 스타일을 선택합니다. 값이 true 인 경우 CXF는 문서별 줄 바꿈 스타일을 선택합니다.
setDefaultBus
없음
deprecated: 이 끝점에 기본 CXF 버스를 사용할지 여부를 지정합니다. 가능한 값은 true,false(기본값)입니다. 이 옵션은 더 이상 사용되지 않습니다. Camel 2.16 이상에서 defaultBus 를 사용합니다.
defaultBus
없음
deprecated: 이 끝점에 기본 CXF 버스를 사용할지 여부를 지정합니다. 가능한 값은 true,false(기본값)입니다. 이 옵션은 더 이상 사용되지 않습니다. Camel 2.16 이상에서 defaultBus 를 사용합니다.
버스
없음
\# 표기법을 사용하여 registry Cryostat- Cryostat의 버스 오브젝트를 참조합니다(예: bus=\#busName ). 참조된 오브젝트는 org.apache.cxf.Bus 의 인스턴스여야 합니다.
기본적으로 는 CXF Bus factory에서 생성한 기본 버스를 사용합니다.
cxfBinding
없음
\# 표기법을 사용하여 registry 인터페이스와 CXF 바인딩 오브젝트를 참조합니다(예: cxfBinding=\#bindingName ). 참조된 오브젝트는 org.apache.camel.component.cxf.CxfBinding 의 인스턴스여야 합니다.
headerFilterStrategy
없음
예를 들어 headerFilterStrategy= \# strategyName )의 헤더 필터 전략 개체를 참조하려면 \# 표기법을 사용합니다. 참조된 오브젝트는 org.apache.camel.spi.HeaderFilterStrategy 의 인스턴스여야 합니다.
loggingFeatureEnabled
없음
2.3의 새로운 기능인 이 옵션을 사용하면 인바운드 및 아웃바운드 Cryostat 메시지를 로그에 쓰는 CXF 로깅 기능을 사용할 수 있습니다. 가능한 값은 true,false(기본값)입니다.
defaultOperationName
없음
2.4에서 새로 추가된 이 옵션은 원격 서비스를 호출하는 CxfProducer 에서 사용하는 기본 operationName 을 설정합니다. 예를 들면 다음과 같습니다.
defaultOperationName=greetMe
defaultOperationNamespace
없음
2.4에서 새로 추가된 이 옵션은 원격 서비스를 호출하는 CxfProducer에서 사용하는 기본 operationNamespace를 설정합니다. 예를 들면 다음과 같습니다.
2.5의 새로운 기능인 이 옵션을 사용하면 CXF 엔드포인트에서 동기화 또는 비동기 API를 사용하여 기본 작업을 수행할 수 있습니다. 기본값은 false 이므로 camel-cxf 끝점은 기본적으로 async API를 사용하려고 합니다.
publishedEndpointUrl
없음
2.5에 새로 추가된 이 옵션은 서비스 주소 URL과 ?wsdl.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의 새로운 기능 이 옵션은 CXF 구성 요소를 PAYLOAD 모드에서 실행할 때(아래 참조)를 통해 들어오는 메시지를 Cryostat로 구문 분석하거나 페이로드를 일부 사례에서 스트리밍할 수 있는 javax.xml.transform.Source 개체로 유지합니다.
skipFaultLogging
없음
2.11의 새로운 기능. 이 옵션은 PhaseInterceptor Cryostat가 캡처한 Fault를 로깅하는지 여부를 제어합니다.
cxfEndpointConfigurer
없음
Camel 2.11 의 새로운 기능 이 옵션은 프로그래밍 방식으로 CXF 엔드포인트를 구성하도록 지원하는 org.apache.camel.component.cxf.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 서버가 Cryostat 또는 Servlet 전송을 사용하는 경우 기본적으로 CxfConsumer에서 사용할 수 있는 CXF 연속 타임아웃을 설정하는 데 사용됩니다. ( Camel 2.14.0 이전에 CxfConsumer는 연속 타임아웃을 0으로 설정하면 연속 일시 중지 작업이 시간 초과되지 않습니다.)
기본값: 30000 예: 연속 = 80000
serviceName 및 portName 은 QNames 이므로 위의 예제와 같이 해당 이름 앞에 {namespace} 접두사를 붙여야 합니다.
Cryostats(이전 Java 개체 설명)는 대상 서버에서 호출되는 메서드에 대한 Java 매개 변수입니다. Protocol 및 Logical Cryostat-WS 핸들러가 모두 지원됩니다.
페이로드
PAYLOAD 는 CXF 끝점의 메시지 구성이 적용된 후 메시지 페이로드( soap:body의 콘텐츠)입니다. Protocol Cryostat-WS 핸들러만 지원됩니다. logical Cryostat-WS 처리기는 지원되지 않습니다.
메시지
MESSAGE 는 전송 계층에서 수신되는 원시 메시지입니다. 스트림을 만지거나 변경할 수 없으며, 이러한 종류의 DataFormat을 사용하는 경우 CXF 인터셉터 중 일부가 제거되므로 camel-cxf 소비자 및 Cryostat-WS 처리기 후에는 soap 헤더를 볼 수 없습니다.
CXF_MESSAGE
Camel 2.8.2 의 새로운 기능CXF_MESSAGE 는 CXF 인터셉터의 전체 기능을 호출할 수 있으며 메시지를 전송 계층에서 원시 source 메시지로 변환하여
교환 속성 CamelCXFDataFormat 을 검색하여 교환 형식의 데이터 형식 모드를 확인할 수 있습니다. 교환 키 상수는 org.apache.camel.component.cxf.CxfConstants.DATA_FORMAT_PROPERTY 에서 정의됩니다.
CXF의 LoggingOutInterceptor 는 로깅 시스템(java.util.logging)으로 이동되는 아웃바운드 메시지를 출력합니다. LoggingOutInterceptor 는 PRE_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>
<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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow
relayHeaders=true 설정은 헤더를 릴레이하려는 의도를 나타냅니다. 지정된 헤더가 릴레이되는지에 대한 실제 결정은 MessageHeadersRelay 인터페이스를 구현하는 플러그형 인스턴스에 위임됩니다. MessageHeadersRelay 의 구체적인 구현은 헤더를 릴레이해야 하는지 여부를 결정합니다. 이미 잘 알려진 Cryostat 네임스페이스에 바인딩하는 SoapMessageHeadersRelay 의 구현이 있습니다. 현재 대역 외 헤더만 필터링되고, relayHeaders=true 인 경우 대역 내 헤더는 항상 릴레이됩니다. 런타임에 네임스페이스가 알 수 없는 유선 헤더가 있는 경우 모든 헤더를 릴레이할 수 있는 fall back DefaultMessageHeadersRelay 가 사용됩니다.
relayHeaders=false 설정은 모든 헤더 in-band 및 대역 외가 삭제됨을 나타냅니다.
자체 MessageHeadersRelay 구현을 플러그인하거나 릴레이 목록에 추가 기능을 추가할 수 있습니다. 사전 로드된 릴레이 인스턴스를 재정의하려면 MessageHeadersRelay 구현 서비스가 재정의하려는 네임스페이스와 동일한 네임스페이스를 사용해야 합니다. 또한 덮어쓰기 릴레이는 모든 네임스페이스를 재정의하려는 네임스페이스로 서비스해야 하거나, 인스턴스 매핑을 릴레이하기 위해 네임스페이스의 모호성을 도입하므로 경로 시작 시 런타임 예외가 발생합니다.
Cryo stat 및 PAYLOAD 모드가 지원됩니다. Cryo stat 모드에서는 대역 내 헤더가 CXF에 의해 헤더 목록에서 처리 및 제거되었으므로 대역 외 메시지 헤더만 필터링에 사용할 수 있습니다. 대역 내 헤더는 Cryostat 모드의 MessageContentList 에 통합되어 있습니다. camel-cxf 구성 요소는 대역폭 내 헤더를 필터링해야 하는 경우 PAYLOAD 모드 또는 (pretty 직접) CXF 인터셉터/JAXWS Handler를 CXF 엔드포인트에 연결해 주십시오.
메시지 헤더 릴레이 메커니즘이 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>
<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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Copy to ClipboardCopied!Toggle word wrapToggle overflow
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>
<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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow
relayHeaders 외에도 CxfHeaderFilterStrategy 에서 구성할 수 있는 새 속성이 있습니다.
Expand
이름
설명
type
필수 여부
기본값
relayHeaders
모든 메시지 헤더는 메시지 헤더 필터에 의해 처리됩니다.
boolean
없음
True (1.6.1 동작)
relayAllMessageHeaders
모든 메시지 헤더는 메시지 헤더 필터로 처리하지 않고 전파됩니다.
boolean
없음
false (1.6.1 동작)
allowFilterNamespaceClash
활성화 네임스페이스에서 겹치는 필터 처리 값이 true 이면 마지막 값이 성공한 것입니다. 값이 false 이면 예외가 발생합니다.
아래에 표시된 Spring 구성 파일을 사용하여 CXF 끝점을 구성할 수 있으며, camelContext 태그에 끝점을 포함할 수도 있습니다. 서비스 끝점을 호출할 때 operationName 및 operationNamespace 헤더를 설정하여 호출하는 작업을 명시적으로 표시할 수 있습니다.
root 빈 요소에 지정된 Cryostat-WS schemaLocation 속성을 포함해야 합니다. 이를 통해 CXF는 파일의 유효성을 검증할 수 있으며 필수 항목입니다. 또한 결합된 {namespace}localName 구문이 이 태그의 속성 값에 대해 지원되지 않기 때문에 < cxf:cxfEndpoint/ > 태그 끝에 네임스페이스 선언이 필요합니다.
cxf:cxfEndpoint 요소는 다음과 같은 많은 추가 특성을 지원합니다.
Expand
이름
현재의
PortName
이 서비스가 구현 중인 엔드포인트 이름입니다. wsdl:port@name. ns:PORT_NAME 형식에서 ns 는 이 범위에서 유효한 네임스페이스 접두사입니다.
serviceName
이 서비스가 구현 중인 서비스 이름이며 wsdl:service@name 에 매핑됩니다. ns:SERVICE_NAME 형식에서 ns 는 이 범위에서 유효한 네임스페이스 접두사입니다.
wsdlURL
WSDL의 위치입니다. classpath, 파일 시스템 또는 원격으로 호스팅할 수 있습니다.
bindingId
서비스 모델에 사용할 bindingId 입니다.
address
서비스는 주소를 게시합니다.
버스
Cryostat-WS 엔드포인트에 사용되는 버스 이름입니다.
serviceClass
SEI(Service Endpoint Interface) 클래스의 클래스 이름입니다. 이 클래스에는 Cryostat181 주석이 있을 수 있습니다.
또한 많은 자식 요소를 지원합니다.
Expand
이름
현재의
cxf:inInterceptors
이 엔드포인트에 대한 들어오는 인터셉터입니다. < bean> 또는 & lt; ref> 목록입니다.
cxf:inFaultInterceptors
이 엔드포인트의 들어오는 오류 인터셉터입니다. < bean> 또는 & lt; ref> 목록입니다.
cxf:outInterceptors
이 엔드포인트의 발신 인터셉터입니다. < bean> 또는 & lt; ref> 목록입니다.
cxf:outFaultInterceptors
이 엔드포인트의 발신 오류 인터셉터입니다. < bean> 또는 & lt; ref> 목록입니다.
CXF:properties
Cryostat-WS 엔드포인트에 제공할 속성 맵입니다.
CXF:handlers
Cryostat-WS 엔드포인트에 제공할 Cryostat-WS 처리기 목록.
cxf:dataBinding
끝점에서 사용하는 DataBinding 을 지정할 수 있습니다. Spring < bean class="MyDataBinding"/ > 구문을 사용하여 제공할 수 있습니다.
cxf:binding
이 끝점에서 사용할 BindingFactory 를 지정할 수 있습니다. Spring < bean class="MyBindingFactory"/ > 구문을 사용하여 제공할 수 있습니다.
cxf:features
이 엔드포인트의 인터셉터를 보유하는 기능입니다. < bean> s 또는< ref>s 목록
cxf:schemaLocations
사용할 끝점의 스키마 위치입니다. < schemaLocation> s목록
cxf:serviceFactory
이 엔드포인트에서 사용할 서비스 팩토리입니다. Spring < bean class="MyServiceFactory"/ > 구문을 사용하여 제공할 수 있습니다.
CXF의 기본 로거는 java.util.logging 입니다. 이를 log4j 로 변경하려면 다음과 같이 진행하십시오. META-INF/cxf/org.apache.cxf.logger 라는 classpath에 파일을 만듭니다. 이 파일은 한 줄에 주석 없이 클래스 org.apache.cxf.common.logging.Log4jLogger 의 정규화된 이름을 포함해야 합니다.
PHP와 같은 일부 Cryostat 클라이언트를 사용하는 경우 CXF가 XML 시작 문서 < ?xml version="1.0" encoding="utf-8"?>을 추가하지 않기 때문에 이러한 종류의 오류가 발생할 수 있습니다.
Error:sendSms: SoapFault exception: [Client] looks like we got no XML document in [...]
Error:sendSms: SoapFault exception: [Client] looks like we got no XML document in [...]
Copy to ClipboardCopied!Toggle word wrapToggle overflow
이 문제를 해결하려면 stayxOutInterceptor에게 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);
}
}
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);
}
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
이와 같이 고객 인터셉터를 추가하고 사용자가 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 forces 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>
<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 forces 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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow
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);
// 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);
Copy to ClipboardCopied!Toggle word wrapToggle overflow
camel-cxf 끝점 소비자 데이터 형식은 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});
}
}
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});
}
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
camel-cxf 엔드포인트 생산자는 cxf 클라이언트 API 를 기반으로 합니다. 먼저 메시지 헤더에 작업 이름을 지정한 다음 메서드 매개 변수를 목록에 추가하고 이 매개변수 목록으로 메시지를 초기화해야 합니다. 응답 메시지의 본문은 messageContentsList 이며 해당 목록에서 결과를 가져올 수 있습니다.
메시지 헤더에 작업 이름을 지정하지 않으면 CxfProducer 는 CxfEndpoint 의 defaultOperationName 을 사용하려고 합니다. CxfEndpoint 에 기본OperationName 이 설정되지 않은 경우 작업 목록에서 첫 번째 작업 이름을 선택합니다.
메시지 본문에서 오브젝트 배열을 가져오려면 다음과 같이 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 is filled in the reset of List.
// The result is 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("The response context", "UTF-8", responseContext.get(org.apache.cxf.message.Message.ENCODING));
assertEquals("Reply body on Camel is wrong", "echo " + TEST_MESSAGE, result.get(0));
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 is filled in the reset of List.
// The result is 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("The response context", "UTF-8", responseContext.get(org.apache.cxf.message.Message.ENCODING));
assertEquals("Reply body on Camel is wrong", "echo " + TEST_MESSAGE, result.get(0));
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Apache Camel 2.0에서 CxfMessage.getBody() 는 org.apache.camel.component.cxf.CxfPayload 오브젝트를 반환합니다. 이러한 변경으로 Apache Camel 메시지에서 기본 CXF 메시지를 분리할 수 있습니다.
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);
}
});
}
};
}
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);
}
});
}
};
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Cryo stat는 CXF 엔드포인트에서 Camel 교환을 생성하거나 사용할 때 데이터 형식이 Java 개체 목록 임을 의미합니다. Apache Camel은 이 모드에서 메시지 본문을 이 모드에서 Cryostat로 노출하지만 CXF 구성 요소는 여전히 read 및 write Cryostat 헤더에 대한 액세스를 제공합니다. 그러나 CXF 인터셉터는 처리된 후 헤더 목록에서 대역 내 headers를 제거하므로, outside-of-band Cryostat 헤더만 Cryostat 모드에서 사용할 수 있습니다.
다음 예제에서는 Cryostat 헤더를 가져오고 설정하는 방법을 보여줍니다. 한 CXF 끝점에서 다른 엔드포인트로 전달되는 경로가 있다고 가정하겠습니다. 즉, Cryostat 클라이언트 Apache Camel CXF 서비스입니다. 요청이 CXF 서비스로 돌아가기 전에 (1)에서 두 개의 프로세서를 연결하여 CXF 서비스로 응답하기 전에 2)를 가져올 수 있습니다. 이 예에서 프로세서(1) 및 (2)는 InsertRequestOutHeaderProcessor 및 InsertResponseOutHeaderProcessor입니다. 이 경로는 다음과 같습니다.
Copy to ClipboardCopied!Toggle word wrapToggle overflow
2.x #159 헤더는 Apache Camel Message headers로 전파됩니다. Apache Camel 메시지 헤더 이름은 org.apache.cxf.headers.Header.list 입니다. 이는 CXF에 정의된 상수입니다(org.apache.cxf.headers.Header.HEADER_LIST). 헤더 값은 List <> of CXF SoapHeader 오브젝트(org.apache.cxf.binding.soapHeader)입니다. 다음 스니펫은 InsertResponseOutHeaderProcessor (응답 메시지에 새 Cryostat 헤더를 삽입하는)입니다. InsertResponseOutHeaderProcessor 및 InsertRequestOutHeaderProcessor 모두에서 Cryostat 헤더에 액세스하는 방법은 실제로 동일합니다. 두 프로세서의 유일한 차이점은 삽입된 Cryostat 헤더의 방향을 설정하는 것입니다.
public static class InsertResponseOutHeaderProcessor implements Processor {
@SuppressWarnings("unchecked")
public void process(Exchange exchange) throws Exception {
// If exchange is routed from camel-cxf endpoint, this is the header
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);
}
}
public static class InsertResponseOutHeaderProcessor implements Processor {
@SuppressWarnings("unchecked")
public void process(Exchange exchange) throws Exception {
// If exchange is routed from camel-cxf endpoint, this is the header
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);
}
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
CxfPayload 오브젝트를 가져온 후에는 CxfPayload.getHeaders() 메서드를 호출하여 List of Cryostat(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("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("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());
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("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("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());
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Camel 2.16.0부터 “Cryostat 모드에서 Cryostat 헤더를 가져오고 설정하는 방법” 에 설명된 것과 동일한 접근 방식을 사용하여 Cryostat 헤더를 설정하거나 가져올 수 있습니다. 이제 org.apache.cxf.headers.Header.list 헤더를 사용하여 Cryostat 헤더 목록을 가져오고 설정할 수 있습니다. 즉, 하나의 Camel CXF 끝점에서 다른(SOAP 클라이언트 Camel CXF 서비스)로 전달하는 경로가 있는 경우 Cryostat 클라이언트가 전송한 Cryostat 헤더도 CXF 서비스로 전달됩니다. 헤더를 전달하지 않으려면 org.apache.cxf.headers.Header.list Camel 헤더에서 해당 헤더를 제거합니다.
CXF 엔드포인트를 사용하여 Cryostat 요청을 사용하는 경우 camel 컨텍스트에서 Cryostat Fault 를 throw해야 할 수 있습니다. 기본적으로 throwFault DSL을 사용하여 이를 수행할 수 있습니다. 이 DSL은 Cryostat ,PAYLOAD 및 MESSAGE 데이터 형식에서 작동합니다. 다음과 같이 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);
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);
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Copy to ClipboardCopied!Toggle word wrapToggle overflow
CXF 엔드포인트가 MESSAGE 데이터 형식으로 작동하는 경우 메시지 본문에서 Cryostat 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));
}
});
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));
}
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Cryostat 데이터 형식에도 마찬가지입니다. 외부 본문에서 Cryostat Fault를 설정하고 다음과 같이 Message.setFault(true) 를 호출하여 오류가 있음을 나타낼 수도 있습니다.
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());
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());
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Cryostat 모드: 첨부 파일 및 MTOM 모두 지원됩니다(예: MTOM 활성화를 위해 Payload Mode 참조). 그러나 첨부 파일은 테스트되지 않습니다. 일반적으로 사용자가 직접 첨부를 처리할 필요가 없습니다.Attachments는 2.1.So 이후 Camel 메시지의 첨부 파일로 전파됩니다.
DataHandler Message.getAttachment(String id)
DataHandler Message.getAttachment(String id)
Copy to ClipboardCopied!Toggle word wrapToggle overflow
.
페이로드 모드: MTOM은 2.1 이후 지원됩니다. 첨부 파일은 위에서 언급한 Camel Message API에서 검색할 수 있습니다. 이 모드에서 Cryostat 처리가 없기 때문에 Attachment가 있는 Cryostat는 지원되지 않습니다.
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>
<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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow
첨부 파일이 있는 Camel 메시지를 생성하여 Payload 모드에서 CXF 엔드포인트로 보낼 수 있습니다.
Exchange exchange = context.createProducerTemplate().send("direct:testEndpoint", new Processor() {
public void process(Exchange exchange) throws Exception {
exchange.setPattern(ExchangePattern.InOut);
List<Source> elements = new ArrayList<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());
Exchange exchange = context.createProducerTemplate().send("direct:testEndpoint", new Processor() {
public void process(Exchange exchange) throws Exception {
exchange.setPattern(ExchangePattern.InOut);
List<Source> elements = new ArrayList<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());
Copy to ClipboardCopied!Toggle word wrapToggle overflow
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<Source> elements = new ArrayList<Source>();
elements.add(new DOMSource(DOMUtils.readXml(new StringReader(MtomTestHelper.RESP_MESSAGE)).getDocumentElement()));
CxfPayload<SoapHeader> sbody = new CxfPayload<SoapHeader>(new ArrayList<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")));
}
}
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<Source> elements = new ArrayList<Source>();
elements.add(new DOMSource(DOMUtils.readXml(new StringReader(MtomTestHelper.RESP_MESSAGE)).getDocumentElement()));
CxfPayload<SoapHeader> sbody = new CxfPayload<SoapHeader>(new ArrayList<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")));
}
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
메시지 모드: 첨부 파일은 메시지를 전혀 처리하지 않으므로 지원되지 않습니다.
CXF_MESSAGE 모드: MTOM이 지원되며, 위에서 언급한 Camel Message API에서 첨부 파일을 검색할 수 있습니다.
참고
다중 부분(즉, MTOM) 메시지를 수신할 때 기본 Cryostat Message to String converter는 본문의 전체 다중 부분 페이로드를 제공합니다. Cryostat XML만 문자열로 필요한 경우 message.getSOAPPart() 를 사용하여 메시지 본문을 설정할 수 있으며 Camel 변환은 나머지 작업을 수행할 수 있습니다.
Java 예외가 서버 측에서 throw될 때 예외에 대한 스택 추적이 오류 메시지로 마샬링되어 클라이언트에 반환되도록 CXF 엔드포인트를 구성할 수 있습니다. 이 페어링을 사용하려면 dataFormat 을 PAYLOAD 로 설정하고 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>
<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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow
보안상의 이유로 스택 추적에는 발생 예외가 포함되지 않습니다(즉, 에서 문제를 따르는 스택 추적의 일부). 스택 추적에 발생 예외를 포함하려면 다음과 같이 cxfEndpoint 요소에서 exceptionMessageCauseEnabled 속성을 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>
<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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow
주의
테스트 및 진단을 위해 exceptionMessageCauseEnabled 플래그만 활성화합니다. 서버는 적대적인 사용자가 서버를 프로브하는 것을 더 어렵게 만들기 위해 예외의 원래 원인을 숨기는 것이 일반적인 방법입니다.
2.8.2에서 camel-cxf 구성 요소는 이제 PAYLOAD 모드를 사용할 때 들어오는 메시지의 스트리밍을 지원합니다. 이전에는 들어오는 메시지가 완전히 구문 분석되었습니다. 대규모 메시지의 경우 시간이 오래 걸리며 상당한 양의 메모리를 사용합니다. 2.8.2부터 수신되는 메시지는 라우팅되는 동안 javax.xml.transform.Source로 남아 있을 수 있으며, 페이로드를 수정하지 않으면 대상 대상으로 직접 스트리밍할 수 있습니다. 일반적인 "간단한 프록시" 사용 사례의 경우(예: from("cxf:…").to("cxf:…")의 경우 성능이 크게 향상되고 메모리 요구 사항이 크게 저하될 수 있습니다.
그러나 스트리밍이 적절하거나 바람직하지 않은 경우가 있습니다. 스트리밍 특성으로 인해 잘못된 들어오는 XML이 처리 체인의 나중까지 catch되지 않을 수 있습니다. 또한 특정 작업을 수행하려면 메시지를(예: WS-Security 또는 메시지 추적 등)로 구문 분석해야 할 수 있습니다. 이 경우 스트리밍의 이점이 제한됩니다. 이 시점에서 스트리밍을 제어하는 방법에는 두 가지가 있습니다.
엔드포인트 속성: "allowStreaming=false"를 엔드포인트 속성으로 추가하여 스트리밍을 켜거나 해제할 수 있습니다.
구성 요소 속성: CxfComponent 개체에는 해당 구성 요소에서 생성된 끝점에 대한 기본값을 설정할 수 있는 allowStreaming 속성도 있습니다.
글로벌 시스템 속성: org.apache.camel.component.cxf.streaming 의 시스템 속성을 false 에 추가하여 전원을 끌 수 있습니다. 전역 기본값을 설정하지만 위의 끝점 속성을 설정하면 해당 끝점에 대한 이 값이 재정의됩니다.
2.8.0에서 camel-cxf 구성 요소는 임의의 구조의 메시지를 전송할 수 있는 일반 CXF 디스패치 모드를 지원합니다(즉, 특정 XML 스키마에 바인딩되지 않음). 이 모드를 사용하려면 CXF 끝점의 wsdlURL 및 serviceClass 속성을 지정하는 것을 생략하면 됩니다.
Copy to ClipboardCopied!Toggle word wrapToggle overflow
& lt;security-domain > 구성은 Cryostat 하위 시스템에서 정의한 < application-security-domain >의 이름을 참조합니다. 예를 들어 Cryostat 하위 시스템 < application-security-domain >은 다음과 같이 WildFly 서버 standalone.xml 구성 파일 내에 구성됩니다.
Copy to ClipboardCopied!Toggle word wrapToggle overflow
& lt;http-authentication-factory > application-http-authentication 은 Elytron 하위 시스템에 정의되어 있습니다. application-http-authentication 은 standalone.xml 및 standalone-full.xml 서버 구성 파일에서 기본적으로 사용할 수 있습니다. 예를 들면 다음과 같습니다.
보안 제약 조건, camel-cxf 소비자 끝점의 인증 방법 및 보안 역할은 WAR 배포 article -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>
<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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow
서블릿 사양에 의해 정의된 < ;url-pattern >은 웹 애플리케이션의 컨텍스트 경로를 기준으로 합니다. 애플리케이션이 my-app.war 로 패키지된 경우 WildFly는 컨텍스트 경로 /my-app 및 < url-patternpattern > /webservices/* 에서 액세스할 수 있도록 /my-app 과 관련된 경로에 적용됩니다.
이는 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>
<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>
Copy to ClipboardCopied!Toggle word wrapToggle overflow