/*
* Copyright (c) 2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.wso2.carbon.bpel.ode.integration.utils;
import org.apache.axis2.AxisFault;
import org.apache.axis2.deployment.util.Utils;
import org.apache.axis2.description.AxisDescription;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.WSDL11ToAxisServiceBuilder;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ode.bpel.iapi.ProcessConf;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaCollection;
import org.w3c.dom.Element;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.bpel.ode.integration.BPELProcessProxy;
import org.wso2.carbon.bpel.ode.integration.BPELConstants;
import org.wso2.carbon.bpel.ode.integration.axis2.Axis2UriResolver;
import org.wso2.carbon.bpel.ode.integration.axis2.Axis2WSDLLocator;
import org.wso2.carbon.bpel.ode.integration.axis2.receivers.BPELMessageReceiver;
import org.wso2.carbon.utils.ServerConstants;
import javax.wsdl.Definition;
import javax.xml.namespace.QName;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Iterator;
/**
* This class contains utility functions used by ODE-Carbon Integration Layer to create,
* and configure AxisServices.
*/
public class AxisServiceUtils {
private static final Log log = LogFactory.getLog(AxisServiceUtils.class);
/**
* Build the underlying Axis Service from Service QName and Port Name of interest using given WSDL
* for BPEL document.
* In the current implementation we are extracting service name from the soap:address' location property.
* But specified port may not contain soap:adress instead it may contains http:address. We need to handle that
* situation.
*
* @param axisConfiguration AxisConfiguration to which we should publish the service
* @param processProxy BPELProcessProxy
* @return Axis Service build using WSDL, Service and Port
* @throws org.apache.axis2.AxisFault on error
*/
public static AxisService createAxisService(AxisConfiguration axisConfiguration,
BPELProcessProxy processProxy) throws AxisFault {
QName serviceName = processProxy.getServiceName();
String portName = processProxy.getPort();
Definition wsdlDefinition = processProxy.getWsdlDefinition();
ProcessConf processConfiguration = processProxy.getProcessConfiguration();
if (log.isDebugEnabled()) {
log.debug("Creating AxisService: Service=" + serviceName + " port=" + portName +
" WSDL=" + wsdlDefinition.getDocumentBaseURI() + " BPEL=" +
processConfiguration.getBpelDocument());
}
WSDL11ToAxisServiceBuilder serviceBuilder = createAxisServiceBuilder(processProxy);
/** Need to figure out a way to handle service name extractoin. According to my perspective extracting
* the service name from the EPR is not a good decision. But we need to handle JMS case properly.
* I am keeping JMS handling untouched until we figureout best solution. */
/* String axisServiceName = extractServiceName(processConf, wsdlServiceName, portName);*/
AxisService axisService = populateAxisService(processProxy, axisConfiguration, serviceBuilder);
Iterator operations = axisService.getOperations();
BPELMessageReceiver messageRec = new BPELMessageReceiver();
/** Set the corresponding BPELService to message receivers */
messageRec.setProcessProxy(processProxy);
while (operations.hasNext()) {
AxisOperation operation = (AxisOperation) operations.next();
// Setting WSDLAwareMessage Receiver even if operation has a message receiver specified.
// This is to fix the issue when build service configuration using services.xml(Always RPCMessageReceiver
// is set to operations).
operation.setMessageReceiver(messageRec);
}
/**
* TODO: JMS Destination handling.
*/
return axisService;
}
private static AxisService populateAxisService(BPELProcessProxy processProxy,
AxisConfiguration axisConfiguration,
WSDL11ToAxisServiceBuilder serviceBuilder)
throws AxisFault {
ProcessConf pConf = processProxy.getProcessConfiguration();
AxisService axisService = serviceBuilder.populateService();
axisService.setParent(axisConfiguration);
axisService.setWsdlFound(true);
axisService.setCustomWsdl(true);
axisService.setClassLoader(axisConfiguration.getServiceClassLoader());
URL wsdlUrl = null;
for (File file : pConf.getFiles()) {
if (file.getAbsolutePath().
indexOf(processProxy.getWsdlDefinition().getDocumentBaseURI()) > 0) {
try {
wsdlUrl = file.toURI().toURL();
} catch (MalformedURLException e) {
String errorMessage = "Cannot convert File URI to URL.";
handleException(pConf.getProcessId(), errorMessage, e);
}
}
}
if (wsdlUrl != null) {
axisService.setFileName(wsdlUrl);
}
Utils.setEndpointsToAllUsedBindings(axisService);
//axisService.addParameter(new Parameter("useOriginalwsdl", "true"));
//axisService.addParameter(new Parameter("modifyUserWSDLPortAddress", "true"));
//axisService.addParameter(new Parameter("setEndpointsToAllUsedBindings", "true"));
/* Setting service type to use in service management*/
axisService.addParameter(ServerConstants.SERVICE_TYPE, "bpel");
/* Process ID as a service parameter to use with process try-it*/
axisService.addParameter(BPELConstants.PROCESS_ID, pConf.getProcessId());
/* Fix for losing of security configuration when updating BPEL package*/
axisService.addParameter(new Parameter(CarbonConstants.PRESERVE_SERVICE_HISTORY_PARAM,
"true"));
axisService.addParameter(
new Parameter(BPELConstants.MESSAGE_RECEIVER_INVOKE_ON_SEPARATE_THREAD, "true"));
return axisService;
}
private static WSDL11ToAxisServiceBuilder createAxisServiceBuilder(BPELProcessProxy processProxy)
throws AxisFault {
Definition wsdlDef = processProxy.getWsdlDefinition();
QName serviceName = processProxy.getServiceName();
String portName = processProxy.getPort();
ProcessConf pConf = processProxy.getProcessConfiguration();
QName pid = pConf.getProcessId();
InputStream wsdlInStream = null;
URI wsdlBaseURI = pConf.getBaseURI()
.resolve(wsdlDef.getDocumentBaseURI());
try {
wsdlInStream = wsdlBaseURI.toURL().openStream();
} catch (MalformedURLException e) {
String errMsg = "Malformed WSDL base URI.";
handleException(pid, errMsg, e);
} catch (IOException e) {
String errMsg = "Error opening stream.";
handleException(pid, errMsg, e);
}
WSDL11ToAxisServiceBuilder serviceBuilder = new WSDL11ToAxisPatchedBuilder(wsdlInStream,
serviceName,
portName);
serviceBuilder.setBaseUri(wsdlBaseURI.toString());
serviceBuilder.setCustomResolver(new Axis2UriResolver());
try {
serviceBuilder.setCustomWSDLResolver(new Axis2WSDLLocator(wsdlBaseURI));
} catch (URISyntaxException e) {
String errorMessage = "URI syntax invalid.";
handleException(pid, errorMessage, e);
}
serviceBuilder.setServerSide(true);
return serviceBuilder;
}
private static void handleException(QName pid, String errorMessage, Exception e) throws AxisFault {
errorMessage = "Error creating axis service for process " + pid + ".Cause: " + errorMessage;
log.error(errorMessage, e);
throw new AxisFault(errorMessage, e);
}
public static void engageModules(AxisDescription description, String... modules)
throws AxisFault {
for (String m : modules) {
if (description.getAxisConfiguration().getModule(m) != null) {
if (!description.getAxisConfiguration().isEngaged(m) && !description.isEngaged(m)) {
description.engageModule(description.getAxisConfiguration().getModule(m));
}
} else {
if (log.isDebugEnabled()) {
log.debug("Module " + m + " is not available.");
}
}
}
}
/**
* Axis2 monkey patching to force the usage of the read(element,baseUri) method
* of XmlSchema as the normal read is broken.
*/
public static class WSDL11ToAxisPatchedBuilder extends WSDL11ToAxisServiceBuilder {
public WSDL11ToAxisPatchedBuilder(InputStream in, QName serviceName, String portName) {
super(in, serviceName, portName);
}
public WSDL11ToAxisPatchedBuilder(Definition def, QName serviceName, String portName) {
super(def, serviceName, portName);
}
public WSDL11ToAxisPatchedBuilder(Definition def, QName serviceName, String portName,
boolean isAllPorts) {
super(def, serviceName, portName, isAllPorts);
}
public WSDL11ToAxisPatchedBuilder(InputStream in, AxisService service) {
super(in, service);
}
public WSDL11ToAxisPatchedBuilder(InputStream in) {
super(in);
}
protected XmlSchema getXMLSchema(Element element, String baseUri) {
XmlSchemaCollection schemaCollection = new XmlSchemaCollection();
if (baseUri != null) {
schemaCollection.setBaseUri(baseUri);
}
return schemaCollection.read(element, baseUri);
}
}
}