/*
* #%L
* Talend :: ESB :: Job :: Controller
* %%
* Copyright (C) 2011 - 2012 Talend Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.talend.esb.job.controller.internal;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import org.apache.cxf.Bus;
import org.apache.cxf.BusException;
import org.apache.cxf.configuration.security.AuthorizationPolicy;
import org.apache.cxf.databinding.source.SourceDataBinding;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.EndpointException;
import org.apache.cxf.feature.Feature;
import org.apache.cxf.frontend.ClientFactoryBean;
import org.apache.cxf.headers.Header;
import org.apache.cxf.service.model.InterfaceInfo;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.ws.policy.WSPolicyFeature;
import org.apache.cxf.wsdl.service.factory.AbstractServiceConfiguration;
import org.talend.esb.job.controller.ESBEndpointConstants;
import org.talend.esb.job.controller.internal.util.DOM4JMarshaller;
import org.talend.esb.policy.correlation.feature.CorrelationIDFeature;
import org.talend.esb.sam.agent.feature.EventFeature;
import org.talend.esb.sam.common.handler.impl.CustomInfoHandler;
import org.talend.esb.servicelocator.cxf.LocatorFeature;
import routines.system.api.ESBConsumer;
//@javax.jws.WebService()
public class RuntimeESBConsumer implements ESBConsumer {
private static final Logger LOG = Logger.getLogger(RuntimeESBConsumer.class.getName());
private final QName operationName;
private final EventFeature samFeature;
private final List<Header> soapHeaders;
private AuthorizationPolicy authorizationPolicy;
private final ClientFactoryBean clientFactory;
private Client client;
private boolean enhancedResponse;
static interface GenericServiceClass {
Object invoke(Object param);
}
RuntimeESBConsumer(final QName serviceName,
final QName portName,
final QName operationName,
String publishedEndpointUrl,
String wsdlURL,
final boolean useServiceLocator,
final Map<String, String> locatorProps,
final EventFeature samFeature,
boolean useServiceRegistry,
final SecurityArguments securityArguments,
Bus bus,
boolean logging,
final List<Header> soapHeaders,
final Feature httpHeadersFeature,
boolean enhancedResponse,
Object correlationIDCallbackHandler) {
this.operationName = operationName;
this.samFeature = samFeature;
this.soapHeaders = soapHeaders;
this.enhancedResponse = enhancedResponse;
clientFactory = new ClientFactoryBean();
clientFactory.setServiceClass(GenericServiceClass.class);
clientFactory.getServiceFactory().getServiceConfigurations().add(0, new AbstractServiceConfiguration() {
@Override
public Boolean isOperation(Method method) {
return "invoke".equals(method.getName());
}
@Override
public QName getOperationName(InterfaceInfo service, Method method) {
return operationName;
}
@Override
public Boolean isWrapped() {
return Boolean.FALSE;
}
});
clientFactory.setServiceName(serviceName);
clientFactory.setEndpointName(portName);
if (!useServiceRegistry) {
String endpointUrl = (useServiceLocator) ? "locator://" + serviceName.getLocalPart() : publishedEndpointUrl;
clientFactory.setAddress(endpointUrl);
}
if (!useServiceRegistry && null != wsdlURL) {
clientFactory.setWsdlURL(wsdlURL);
}
clientFactory.setDataBinding(new SourceDataBinding());
clientFactory.setBus(bus);
final List<Feature> features = new ArrayList<Feature>();
if (useServiceLocator) {
features.add(new LocatorFeature());
}
if (samFeature != null) {
features.add(samFeature);
}
if (correlationIDCallbackHandler != null && (!useServiceRegistry)) {
features.add(new CorrelationIDFeature());
}
if (null != securityArguments.getPolicy()) {
features.add(new WSPolicyFeature(securityArguments.getPolicy()));
}
if (null != httpHeadersFeature){
features.add(httpHeadersFeature);
}
if (logging) {
features.add(new org.apache.cxf.feature.LoggingFeature());
}
clientFactory.setFeatures(features);
authorizationPolicy = securityArguments.buildAuthorizationPolicy();
Map<String, Object> clientProps = securityArguments.buildClientConfig(bus, useServiceRegistry,
serviceName.toString());
clientProps.put("soap.no.validate.parts", Boolean.TRUE);
clientProps.put(ESBEndpointConstants.USE_SERVICE_REGISTRY_PROP, Boolean.toString(useServiceRegistry));
if ((useServiceLocator || useServiceRegistry) && null != locatorProps && !locatorProps.isEmpty()) {
clientProps.put(LocatorFeature.LOCATOR_PROPERTIES, locatorProps);
}
if (correlationIDCallbackHandler != null) {
clientProps.put(CorrelationIDFeature.CORRELATION_ID_CALLBACK_HANDLER, correlationIDCallbackHandler);
}
clientFactory.setProperties(clientProps);
LOG.fine("Generic consumer created, serviceName: " + serviceName +
" portName: " + portName +
" operationName: " + operationName +
" publishedEndpointUrl: " + publishedEndpointUrl +
" wsdlURL: " + wsdlURL);
LOG.fine("Generic consumer properties: " + clientProps);
}
@Override
@SuppressWarnings("unchecked")
public Object invoke(Object payload) throws Exception {
LOG.fine("Generic consumer for operation " + operationName + " invoked with payload " + payload);
if (payload instanceof org.dom4j.Document) {
return sendDocument((org.dom4j.Document) payload);
} else if (payload instanceof java.util.Map) {
Map<?, ?> map = (Map<?, ?>) payload;
if (samFeature != null) {
Object samProps = map.get(ESBEndpointConstants.REQUEST_SAM_PROPS);
if (samProps != null) {
LOG.info("SAM custom properties received: " + samProps);
CustomInfoHandler ciHandler = new CustomInfoHandler();
ciHandler.setCustomInfo((Map<String, String>) samProps);
samFeature.setHandler(ciHandler);
}
}
return sendDocument((org.dom4j.Document) map.get(ESBEndpointConstants.REQUEST_PAYLOAD));
} else {
throw new RuntimeException("Consumer try to send incompatible object: " + payload.getClass().getName());
}
}
private Object sendDocument(org.dom4j.Document doc) throws Exception {
Client client = getClient();
if (null != soapHeaders) {
LOG.fine("Generic consumer sendDocument soapHeaders: " + Arrays.toString(soapHeaders.toArray()));
client.getRequestContext().put(org.apache.cxf.headers.Header.HEADER_LIST, soapHeaders);
}
Object[] result = null;
try {
result = client.invoke(operationName, DOM4JMarshaller.documentToSource(doc));
} catch (Exception ex) {
LOG.fine("Generic consumer client.invoke throwed exception " + ex.getMessage() +
" trace: " + Arrays.toString(ex.getStackTrace()));
throw ex;
}
if (result != null) {
org.dom4j.Document response = DOM4JMarshaller.sourceToDocument((Source) result[0]);
if (enhancedResponse) {
Map<String, Object> enhancedBody = new HashMap<String, Object>();
enhancedBody.put("payload", response);
enhancedBody.put(CorrelationIDFeature.MESSAGE_CORRELATION_ID,
client.getResponseContext().get(CorrelationIDFeature.MESSAGE_CORRELATION_ID));
return enhancedBody;
} else {
return response;
}
}
return null;
}
private Client getClient() throws BusException, EndpointException {
if (client == null) {
client = clientFactory.create();
if (null != authorizationPolicy) {
HTTPConduit conduit = (HTTPConduit) client.getConduit();
conduit.setAuthorization(authorizationPolicy);
}
}
return client;
}
}