/* 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.activiti.engine.impl.webservice;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.wsdl.BindingOperation;
import javax.wsdl.Definition;
import javax.wsdl.Operation;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.Types;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.schema.Schema;
import javax.wsdl.extensions.soap.SOAPAddress;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.xml.namespace.QName;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.impl.bpmn.data.SimpleStructureDefinition;
import org.activiti.engine.impl.bpmn.data.StructureDefinition;
import org.activiti.engine.impl.bpmn.parser.BpmnParse;
import org.activiti.engine.impl.bpmn.parser.XMLImporter;
import org.activiti.engine.impl.util.ReflectUtil;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JFieldVar;
import com.sun.tools.xjc.ConsoleErrorReporter;
import com.sun.tools.xjc.api.ErrorListener;
import com.sun.tools.xjc.api.Mapping;
import com.sun.tools.xjc.api.S2JJAXBModel;
import com.sun.tools.xjc.api.SchemaCompiler;
import com.sun.tools.xjc.api.XJC;
/**
* A WSDL importer
*
* @author Esteban Robles Luna
*/
public class WSDLImporter implements XMLImporter {
protected Map<String, WSService> wsServices = new HashMap<String, WSService>();
protected Map<String, WSOperation> wsOperations = new HashMap<String, WSOperation>();
protected Map<String, StructureDefinition> structures = new HashMap<String, StructureDefinition>();
protected String wsdlLocation;
protected String namespace;
public WSDLImporter() {
this.namespace = "";
}
public void importFrom(org.activiti.engine.impl.util.xml.Element element, BpmnParse parse) {
this.namespace = element.attribute("namespace") == null ? "" : element.attribute("namespace") + ":";
this.importFrom(element.attribute("location"));
this.transferImportsToParse(parse);
}
public void importFrom(String url) {
this.wsServices.clear();
this.wsOperations.clear();
this.structures.clear();
this.wsdlLocation = url;
try {
Definition definition = this.parseWSDLDefinition();
this.importServicesAndOperations(definition);
this.importTypes(definition.getTypes());
} catch (WSDLException e) {
throw new ActivitiException(e.getMessage(), e);
}
}
/**
* Parse the WSDL definition using WSDL4J.
*/
private Definition parseWSDLDefinition() throws WSDLException {
WSDLFactory wsdlFactory = WSDLFactory.newInstance();
WSDLReader reader = wsdlFactory.newWSDLReader();
reader.setFeature("javax.wsdl.verbose", false);
reader.setFeature("javax.wsdl.importDocuments", true);
Definition definition = reader.readWSDL(this.wsdlLocation);
return definition;
}
/**
* Imports services and operations from the WSDL definition
*/
private void importServicesAndOperations(Definition definition) {
for (Object serviceObject : definition.getServices().values()) {
Service service = (Service) serviceObject;
WSService wsService = this.importService(service);
this.wsServices.put(this.namespace + wsService.getName(), wsService);
Port port = (Port) service.getPorts().values().iterator().next();
for (Object bindOperationObject : port.getBinding().getBindingOperations()) {
BindingOperation bindOperation = (BindingOperation) bindOperationObject;
WSOperation operation = this.processOperation(bindOperation.getOperation(), wsService);
wsService.addOperation(operation);
this.wsOperations.put(this.namespace + operation.getName(), operation);
}
}
}
/**
* Imports the service from the WSDL service definition
*/
private WSService importService(Service service) {
String name = service.getQName().getLocalPart();
Port port = (Port) service.getPorts().values().iterator().next();
String location = "";
List extensionElements = port.getExtensibilityElements();
for (Object extension : extensionElements) {
if (extension instanceof SOAPAddress) {
SOAPAddress address = (SOAPAddress) extension;
location = address.getLocationURI();
}
}
WSService wsService = new WSService(this.namespace + name, location, this.wsdlLocation);
return wsService;
}
private WSOperation processOperation(Operation wsOperation, WSService service) {
WSOperation operation = new WSOperation(this.namespace + wsOperation.getName(), wsOperation.getName(), service);
return operation;
}
/**
* Import the Types from the WSDL definition using the same strategy that
* Cxf uses taking advantage of JAXB
*/
private void importTypes(Types types) {
SchemaCompiler compiler = XJC.createSchemaCompiler();
ErrorListener elForRun = new ConsoleErrorReporter();
compiler.setErrorListener(elForRun);
Element rootTypes = this.getRootTypes();
this.createDefaultStructures(rootTypes);
S2JJAXBModel intermediateModel = this.compileModel(types, compiler, rootTypes);
Collection<? extends Mapping> mappings = intermediateModel.getMappings();
for (Mapping mapping : mappings){
this.importStructure(mapping);
}
}
private void importStructure(Mapping mapping) {
QName qname = mapping.getElement();
JDefinedClass theClass = (JDefinedClass) mapping.getType().getTypeClass();
SimpleStructureDefinition structure = (SimpleStructureDefinition) this.structures.get(this.namespace + qname.getLocalPart());
Map<String, JFieldVar> fields = theClass.fields();
int index = 0;
for (Entry<String, JFieldVar> entry : fields.entrySet()) {
Class<?> fieldClass = ReflectUtil.loadClass(entry.getValue().type().boxify().fullName());
structure.setFieldName(index, entry.getKey(), fieldClass);
index++;
}
}
private S2JJAXBModel compileModel(Types types, SchemaCompiler compiler, Element rootTypes) {
Schema schema = (Schema) types.getExtensibilityElements().get(0);
compiler.parseSchema(schema.getDocumentBaseURI() + "#types1", rootTypes);
S2JJAXBModel intermediateModel = compiler.bind();
return intermediateModel;
}
private void createDefaultStructures(Element rootTypes) {
NodeList complexTypes = rootTypes.getElementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "complexType");
for (int i = 0; i < complexTypes.getLength(); i++) {
Element element = (Element) complexTypes.item(i);
String structureName = this.namespace + element.getAttribute("name");
SimpleStructureDefinition structure = new SimpleStructureDefinition(structureName);
this.structures.put(structure.getId(), structure);
}
}
private Element getRootTypes() {
try {
DOMParser parser = new DOMParser();
parser.parse(this.wsdlLocation);
Document doc = parser.getDocument();
Element root = (Element) doc.getFirstChild();
Element typesElement = (Element) root.getElementsByTagName("wsdl:types").item(0);
return (Element) typesElement.getElementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "schema").item(0);
} catch (SAXException e) {
throw new ActivitiException(e.getMessage(), e);
} catch (IOException e) {
throw new ActivitiException(e.getMessage(), e);
}
}
private void transferImportsToParse(BpmnParse parse) {
if (parse != null) {
for (StructureDefinition structure : this.structures.values()) {
parse.addStructure(structure);
}
for (WSService service : this.wsServices.values()) {
parse.addService(service);
}
for (WSOperation operation : this.wsOperations.values()) {
parse.addOperation(operation);
}
}
}
public Collection<StructureDefinition> getStructures() {
return this.structures.values();
}
public Collection<WSService> getServices() {
return this.wsServices.values();
}
public Collection<WSOperation> getOperations() {
return this.wsOperations.values();
}
}