/* * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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. */ package org.jbpm.process.workitem.webservice; import java.lang.reflect.Array; import java.util.concurrent.ConcurrentHashMap; import javax.xml.namespace.QName; import org.apache.cxf.endpoint.Client; import org.apache.cxf.endpoint.dynamic.DynamicClientFactory; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; import org.apache.cxf.message.Message; import org.kie.api.executor.Command; import org.kie.api.executor.CommandContext; import org.kie.api.executor.ExecutionResults; import org.kie.api.runtime.process.WorkItem; import org.kie.internal.runtime.Cacheable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Web Service executor command that executes web service call using Apache CXF. * It expects following parameters to be able to operate: * <ul> * <li>Interface - valid interface/service name of the web service (port type name from wsdl)</li> * <li>Operation - valid operation name</li> * <li>Parameter - object that is going to be used as web service message</li> * <li>Url - location of the wsdl file used to look up service definition</li> * <li>Namespace - name space of the web service</li> * <li>Endpoint - overrides the endpoint address defined in the referenced WSDL.</li> * </ul> * * Web service call is synchronous but since it's executor command it will be invoked as asynchronous task any way. */ public class WebServiceCommand implements Command, Cacheable { private static final Logger logger = LoggerFactory.getLogger(WebServiceCommand.class); private volatile static ConcurrentHashMap<String, Client> clients = new ConcurrentHashMap<String, Client>(); private DynamicClientFactory dcf = null; @Override public ExecutionResults execute(CommandContext ctx) throws Exception { // since JaxWsDynamicClientFactory will change the TCCL we need to restore it after creating client ClassLoader origClassloader = Thread.currentThread().getContextClassLoader(); try { Object[] parameters = null; WorkItem workItem = (WorkItem) ctx.getData("workItem"); String interfaceRef = (String) workItem.getParameter("Interface"); String operationRef = (String) workItem.getParameter("Operation"); String endpointAddress = (String) workItem.getParameter("Endpoint"); if ( workItem.getParameter("Parameter") instanceof Object[]) { parameters = (Object[]) workItem.getParameter("Parameter"); } else if (workItem.getParameter("Parameter") != null && workItem.getParameter("Parameter").getClass().isArray()) { int length = Array.getLength(workItem.getParameter("Parameter")); parameters = new Object[length]; for(int i = 0; i < length; i++) { parameters[i] = Array.get(workItem.getParameter("Parameter"), i); } } else { parameters = new Object[]{ workItem.getParameter("Parameter")}; } Client client = getWSClient(workItem, interfaceRef, ctx); //Override endpoint address if configured. if (endpointAddress != null && !"".equals(endpointAddress)) { client.getRequestContext().put(Message.ENDPOINT_ADDRESS, endpointAddress) ; } Object[] result = client.invoke(operationRef, parameters); ExecutionResults results = new ExecutionResults(); if (result == null || result.length == 0) { results.setData("Result", null); } else { results.setData("Result", result[0]); } logger.debug("Received sync response {}", result); return results; }finally { Thread.currentThread().setContextClassLoader(origClassloader); } } protected synchronized Client getWSClient(WorkItem workItem, String interfaceRef, CommandContext ctx) { if (clients.containsKey(interfaceRef)) { return clients.get(interfaceRef); } String importLocation = (String) workItem.getParameter("Url"); String importNamespace = (String) workItem.getParameter("Namespace"); if (importLocation != null && importLocation.trim().length() > 0 && importNamespace != null && importNamespace.trim().length() > 0) { Client client = getDynamicClientFactory(ctx).createClient(importLocation, new QName(importNamespace, interfaceRef), Thread.currentThread().getContextClassLoader(), null); clients.put(interfaceRef, client); return client; } return null; } protected synchronized DynamicClientFactory getDynamicClientFactory(CommandContext ctx) { if (this.dcf == null) { this.dcf = JaxWsDynamicClientFactory.newInstance(); } return this.dcf; } @Override public void close() { if (clients != null) { for (Client client : clients.values()) { client.destroy(); } } } }