/* 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.net.URL; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicInteger; import javax.wsdl.Definition; import javax.wsdl.Types; import javax.wsdl.WSDLException; import javax.wsdl.extensions.schema.Schema; import javax.xml.namespace.QName; import org.activiti.bpmn.model.Import; 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.BpmnParseXMLImportHandler; import org.activiti.engine.impl.bpmn.parser.XMLImporter; import org.activiti.engine.impl.util.ReflectUtil; import org.apache.cxf.Bus; import org.apache.cxf.BusFactory; import org.apache.cxf.common.i18n.UncheckedException; import org.apache.cxf.endpoint.dynamic.DynamicClientFactory; import org.apache.cxf.resource.URIResolver; import org.apache.cxf.service.model.EndpointInfo; import org.apache.cxf.service.model.OperationInfo; import org.apache.cxf.service.model.ServiceInfo; import org.apache.cxf.wsdl.WSDLManager; import org.apache.cxf.wsdl11.WSDLServiceBuilder; import com.ibm.wsdl.extensions.schema.SchemaImpl; import com.sun.codemodel.JClass; 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; /** * @author Esteban Robles Luna */ public class CxfWSDLImporter implements XMLImporter { protected static final String JAXB_BINDINGS_RESOURCE = "activiti-bindings.xjc"; protected Map wsServices = new HashMap(); protected Map wsOperations = new HashMap(); protected Map structures = new HashMap(); protected String wsdlLocation; protected String namespace; public CxfWSDLImporter() { this.namespace = ""; } public void importFrom(Import theImport, BpmnParseXMLImportHandler parseHandler) { this.namespace = theImport.getNamespace() == null ? "" : theImport.getNamespace() + ":"; try { final URIResolver uriResolver = new URIResolver(parseHandler.getSourceSystemId(), theImport.getLocation()); if (uriResolver.isResolved()) { if (uriResolver.getURI() != null) { this.importFrom(uriResolver.getURI().toString()); } else if (uriResolver.isFile()) { this.importFrom(uriResolver.getFile().getAbsolutePath()); } else if (uriResolver.getURL() != null) { this.importFrom(uriResolver.getURL().toString()); } } else { throw new UncheckedException(new Exception("Unresolved import against " + parseHandler.getSourceSystemId())); } this.transferImportsToParse(parseHandler); } catch (final IOException e) { throw new UncheckedException(e); } } private void transferImportsToParse(BpmnParseXMLImportHandler parseHandler) { if (parseHandler != null) { for (StructureDefinition structure : this.structures.values()) { parseHandler.addStructure(structure); } for (WSService service : this.wsServices.values()) { parseHandler.addService(service); } for (WSOperation operation : this.wsOperations.values()) { parseHandler.addOperation(operation); } } } public void importFrom(String url) { this.wsServices.clear(); this.wsOperations.clear(); this.structures.clear(); this.wsdlLocation = url; try { Bus bus = BusFactory.getDefaultBus(); final Enumeration xjcBindingUrls = Thread.currentThread().getContextClassLoader().getResources(JAXB_BINDINGS_RESOURCE); if (xjcBindingUrls.hasMoreElements()) { final URL xjcBindingUrl = xjcBindingUrls.nextElement(); if (xjcBindingUrls.hasMoreElements()) { throw new ActivitiException("Several JAXB binding definitions found for activiti-cxf: " + JAXB_BINDINGS_RESOURCE); } DynamicClientFactory.newInstance(bus).createClient(url, Arrays.asList(new String[] { xjcBindingUrl.toString() })); WSDLManager wsdlManager = bus.getExtension(WSDLManager.class); Definition def = wsdlManager.getDefinition(url); WSDLServiceBuilder builder = new WSDLServiceBuilder(bus); List services = builder.buildServices(def); for (ServiceInfo service : services) { WSService wsService = this.importService(service); this.wsServices.put(this.namespace + wsService.getName(), wsService); } if(def != null && def.getTypes() != null) { this.importTypes(def.getTypes()); } } else { throw new ActivitiException("The JAXB binding definitions are not found for activiti-cxf: " + JAXB_BINDINGS_RESOURCE); } } catch (WSDLException e) { e.printStackTrace(); } catch (IOException e) { throw new ActivitiException("Error retrieveing the JAXB binding definitions", e); } } private WSService importService(ServiceInfo service) { String name = service.getName().getLocalPart(); String location = ""; for (EndpointInfo endpoint : service.getEndpoints()) { location = endpoint.getAddress(); } WSService wsService = new WSService(this.namespace + name, location, this.wsdlLocation); for (OperationInfo operation : service.getInterface().getOperations()) { WSOperation wsOperation = this.importOperation(operation, wsService); wsService.addOperation(wsOperation); this.wsOperations.put(this.namespace + operation.getName().getLocalPart(), wsOperation); } return wsService; } private WSOperation importOperation(OperationInfo operation, WSService service) { WSOperation wsOperation = new WSOperation(this.namespace + operation.getName().getLocalPart(), operation.getName().getLocalPart(), service); return wsOperation; } private void importTypes(Types types) { SchemaCompiler compiler = XJC.createSchemaCompiler(); ErrorListener elForRun = new ConsoleErrorReporter(); compiler.setErrorListener(elForRun); SchemaImpl impl = (SchemaImpl) types.getExtensibilityElements().get(0); S2JJAXBModel intermediateModel = this.compileModel(types, compiler, impl.getElement()); Collection 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 = new SimpleStructureDefinition(this.namespace + qname.getLocalPart()); this.structures.put(structure.getId(), structure); importFields(theClass, structure); } private static void importFields(final JDefinedClass theClass, final SimpleStructureDefinition structure) { final AtomicInteger index = new AtomicInteger(0); _importFields(theClass, index, structure); } private static void _importFields(final JDefinedClass theClass, final AtomicInteger index, final SimpleStructureDefinition structure) { final JClass parentClass = theClass._extends(); if (parentClass != null && parentClass instanceof JDefinedClass) { _importFields((JDefinedClass)parentClass, index, structure); } for (Entry entry : theClass.fields().entrySet()) { Class fieldClass = ReflectUtil.loadClass(entry.getValue().type().boxify().fullName()); structure.setFieldName(index.getAndIncrement(), entry.getKey(), fieldClass); } } private S2JJAXBModel compileModel(Types types, SchemaCompiler compiler, org.w3c.dom.Element rootTypes) { Schema schema = (Schema) types.getExtensibilityElements().get(0); compiler.parseSchema(schema.getDocumentBaseURI() + "#types1", rootTypes); S2JJAXBModel intermediateModel = compiler.bind(); return intermediateModel; } public Collection getStructures() { return this.structures.values(); } public Collection getServices() { return this.wsServices.values(); } public Collection getOperations() { return this.wsOperations.values(); } }