/*
* Copyright (c) 2009, 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.b4p.utils;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axis2.AxisFault;
import org.apache.axis2.client.Options;
import org.apache.axis2.deployment.ServiceBuilder;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ode.bpel.iapi.*;
import org.apache.ode.bpel.epr.EndpointFactory;
import org.apache.ode.bpel.epr.MutableEndpoint;
import org.apache.ode.utils.DOMUtils;
import org.apache.ode.utils.Namespaces;
import org.apache.ode.utils.stl.CollectionsX;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaCollection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.Binding;
import javax.wsdl.extensions.UnknownExtensibilityElement;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.soap12.SOAP12Binding;
import javax.wsdl.extensions.http.HTTPAddress;
import javax.wsdl.extensions.http.HTTPBinding;
import javax.wsdl.extensions.soap.SOAPAddress;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import java.io.InputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Collection;
import java.util.ArrayList;
public class HumanServiceUtil {
private static final Log log = LogFactory.getLog(HumanServiceUtil.class);
public static final String TARGET_SESSION_ENDPOINT = "targetSessionEndpoint";
public static final String CALLBACK_SESSION_ENDPOINT = "callbackSessionEndpoint";
public static final String CONFIGURED_USING_BPEL_PKG_CONFIG_FILES ="confgiuredUsingBpelPkgFiles";
public static final String MODULE_RAMPART = "rampart";
public static final String MODULE_RAHAS = "rahas";
/**
* Get the EPR of this service from the WSDL.
*
* @param wsdlDef WSDL Definition
* @param serviceName service name
* @param portName port name
* @return XML representation of the EPR
*/
public static Element genEPRfromWSDL(Definition wsdlDef, QName serviceName, String portName) {
Service serviceDef = wsdlDef.getService(serviceName);
if (serviceDef != null) {
Port portDef = serviceDef.getPort(portName);
if (portDef != null) {
Document doc = DOMUtils.newDocument();
Element service = doc.createElementNS(Namespaces.WSDL_11, "service");
service.setAttribute("name", serviceDef.getQName().getLocalPart());
service.setAttribute("targetNamespace", serviceDef.getQName().getNamespaceURI());
Element port = doc.createElementNS(Namespaces.WSDL_11, "port");
service.appendChild(port);
port.setAttribute("name", portDef.getName());
port.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:bindns", portDef.getBinding().getQName()
.getNamespaceURI());
port.setAttribute("bindns:binding", portDef.getName());
for (Object extElmt : portDef.getExtensibilityElements()) {
if (extElmt instanceof SOAPAddress) {
Element soapAddr = doc.createElementNS(Namespaces.SOAP_NS, "address");
port.appendChild(soapAddr);
soapAddr.setAttribute("location", ((SOAPAddress) extElmt).getLocationURI());
} else if (extElmt instanceof HTTPAddress) {
Element httpAddr = doc.createElementNS(Namespaces.HTTP_NS, "address");
port.appendChild(httpAddr);
httpAddr.setAttribute("location", ((HTTPAddress) extElmt).getLocationURI());
} else {
port.appendChild(doc.importNode(((UnknownExtensibilityElement) extElmt).getElement(), true));
}
}
return service;
}
}
return null;
}
/**
* Create-and-copy a service-ref element.
*
* @param elmt Service Reference element
* @return wrapped element
*/
public static MutableEndpoint createServiceRef(Element elmt) {
Document doc = DOMUtils.newDocument();
QName elQName = new QName(elmt.getNamespaceURI(), elmt.getLocalName());
// If we get a service-ref, just copy it, otherwise make a service-ref
// wrapper
if (!EndpointReference.SERVICE_REF_QNAME.equals(elQName)) {
Element serviceref = doc.createElementNS(EndpointReference.SERVICE_REF_QNAME.getNamespaceURI(),
EndpointReference.SERVICE_REF_QNAME.getLocalPart());
serviceref.appendChild(doc.importNode(elmt, true));
doc.appendChild(serviceref);
} else {
doc.appendChild(doc.importNode(elmt, true));
}
return EndpointFactory.createEndpoint(doc.getDocumentElement());
}
/**
* Configure a service instance woth the specified service.xml document.
* If modules are mentioned in the document, <code>this</code> method will make sure they are properly engaged and engage them if necessary.
* The modules have to be available in the module repository otherwise an AxisFault will be thrown.
*
* @param configCtx Server configuration context
* @param axisService the service to configure
* @param service_file the service.xm document to configure the service with
* @param basePath base direcotry of the bpel package
* @throws java.io.IOException if error ocurred during opening stream
* @throws javax.xml.stream.XMLStreamException
* when error reading XML stream
* @throws org.apache.axis2.AxisFault if a module listed in the service.xml is not available in the module repository
*/
public static void configureService(ConfigurationContext configCtx, AxisService axisService, String service_file, String basePath) throws IOException, XMLStreamException {
FileLoadingUtil fileLoader = new FileLoadingUtil(basePath);
InputStream serviceDescIs = null;
try {
serviceDescIs = fileLoader.load(service_file);
} catch (FileLoadingUtilException e) {
log.error("Service Description loading error.", e);
}
if (log.isDebugEnabled()) {
log.debug("Looking for Axis2 service configuration file: " + service_file);
}
if (serviceDescIs != null) {
if (log.isDebugEnabled()) {
log.debug("Configuring service " + axisService.getName() + " using: " + service_file);
}
try {
if (configCtx == null)
configCtx = new ConfigurationContext(axisService.getAxisConfiguration());
ServiceBuilder builder = new ServiceBuilder(configCtx, axisService);
StAXOMBuilder omBuilder = new StAXOMBuilder(serviceDescIs);
OMElement documentEle = omBuilder.getDocumentElement();
Iterator itr = documentEle.getChildElements();
while (itr.hasNext()) {
OMElement serviceEle = (OMElement) itr.next();
if (serviceEle.getLocalName().toLowerCase().equals("service")) {
if (serviceEle.getAttribute(new QName("name")) != null &&
serviceEle.getAttribute(new QName("name")).getAttributeValue().equals(axisService.getName())) {
builder.populateService(serviceEle);
// This is a hack to avoid security configurations get persisted when we configure using
// services.xml file or policy.xml file BPEL package. But this should be fix at the
// Carbon Persistence manager.
Parameter param = new Parameter(CONFIGURED_USING_BPEL_PKG_CONFIG_FILES, "true");
axisService.addParameter(param);
} else if (serviceEle.getAttribute(new QName("name")) != null && // Starts with check is used to handle anonymous services generated for external service.
axisService.getName().startsWith("axis_service_for_" + serviceEle.getAttributeValue(new QName("name")))) {
String svcName = axisService.getName();
AxisService axisSvc = builder.populateService(serviceEle);
axisSvc.setName(svcName);
}
}
}
} finally {
serviceDescIs.close();
}
// the service builder only updates the module list but do not engage them
// modules have to be engaged manually,
for (int i = 0; i < axisService.getModules().size(); i++) {
String moduleRef = axisService.getModules().get(i);
AxisModule module = axisService.getAxisConfiguration().getModule(moduleRef);
if (module != null) {
axisService.engageModule(module);
} else {
throw new AxisFault("Unable to engage module: " + moduleRef);
}
}
}
}
public static void applySecurityPolicy(AxisService service, String policy_file, String basePath) {
FileLoadingUtil fileLoader = new FileLoadingUtil(basePath);
if (log.isDebugEnabled()) log.debug("Applying security policy: " + policy_file);
try {
InputStream policyStream = fileLoader.load(policy_file);
try {
Policy policyDoc = PolicyEngine.getPolicy(policyStream);
service.getPolicySubject().attachPolicy(policyDoc);
// make sure the proper modules are engaged, if they are available
engageModules(service, "rampart", "rahas");
} finally {
policyStream.close();
}
// This is a hack to avoid security configurations get persisted when we configure using
// services.xml file or policy.xml file BPEL package. But this should be fix at the
// Carbon Persistence manager.
Parameter param = new Parameter(CONFIGURED_USING_BPEL_PKG_CONFIG_FILES, "true");
service.addParameter(param);
} catch (IOException e) {
log.error("Fialed to attach policy to service. Exception while parsing policy: " + policy_file, e);
} catch (FileLoadingUtilException e) {
log.error("Fialed to attach policy to service. Error locating policy file " + policy_file, 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);
}
}
public static ExtensibilityElement getBindingExtension(Binding binding) {
Collection bindings = new ArrayList();
CollectionsX.filter(bindings, binding.getExtensibilityElements(), HTTPBinding.class);
CollectionsX.filter(bindings, binding.getExtensibilityElements(), SOAPBinding.class);
CollectionsX.filter(bindings, binding.getExtensibilityElements(), SOAP12Binding.class);
if (bindings.size() == 0) {
return null;
} else if (bindings.size() > 1) {
// exception if multiple bindings found
throw new IllegalArgumentException("Multiple bindings: " + binding.getQName());
} else {
// retrieve the single element
ExtensibilityElement result = (ExtensibilityElement) bindings.iterator().next();
return result;
}
}
/**
* Clones the given {@link org.apache.axis2.client.Options} object. This is not a deep copy
* because this will be called for each and every message going out from synapse. The parent
* of the cloning options object is kept as a reference.
*
* @param options clonning object
* @return clonned Options object
*/
public static Options cloneOptions(Options options) {
// create new options object and set the parent
Options clonedOptions = new Options(options.getParent());
// copy general options
clonedOptions.setCallTransportCleanup(options.isCallTransportCleanup());
clonedOptions.setExceptionToBeThrownOnSOAPFault(options.isExceptionToBeThrownOnSOAPFault());
clonedOptions.setManageSession(options.isManageSession());
clonedOptions.setSoapVersionURI(options.getSoapVersionURI());
clonedOptions.setTimeOutInMilliSeconds(options.getTimeOutInMilliSeconds());
clonedOptions.setUseSeparateListener(options.isUseSeparateListener());
// copy transport related options
clonedOptions.setListener(options.getListener());
clonedOptions.setTransportIn(options.getTransportIn());
clonedOptions.setTransportInProtocol(options.getTransportInProtocol());
clonedOptions.setTransportOut(clonedOptions.getTransportOut());
// copy username and password options
clonedOptions.setUserName(options.getUserName());
clonedOptions.setPassword(options.getPassword());
// cloen the property set of the current options object
for (Object o : options.getProperties().keySet()) {
String key = (String) o;
clonedOptions.setProperty(key, options.getProperty(key));
}
return clonedOptions;
}
}