/* * JBoss, Home of Professional Open Source * Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated * by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.savara.tools.bpel.generator; import java.io.ByteArrayOutputStream; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.savara.bpel.generator.ProtocolToBPELModelGenerator; import org.savara.bpel.model.*; import org.savara.bpel.util.BPELGeneratorUtil; import org.savara.bpel.util.BPELModelUtil; import org.savara.common.logging.FeedbackHandler; import org.savara.common.logging.MessageFormatter; import org.savara.common.model.annotation.Annotation; import org.savara.common.model.annotation.AnnotationDefinitions; import org.savara.common.util.XMLUtils; import org.savara.contract.model.Contract; import org.savara.contract.model.Interface; import org.savara.contract.model.Namespace; import org.savara.protocol.contract.generator.ContractGenerator; import org.savara.protocol.contract.generator.ContractGeneratorFactory; import org.savara.tools.bpel.osgi.Activator; import org.savara.tools.common.ArtifactType; import org.savara.tools.common.generation.AbstractGenerator; import org.savara.wsdl.generator.WSDLGeneratorFactory; import org.savara.wsdl.generator.soap.SOAPDocLitWSDLBinding; import org.savara.wsdl.util.WSDLGeneratorUtil; import org.scribble.protocol.model.*; import org.eclipse.core.runtime.*; import org.eclipse.jst.common.project.facet.WtpUtils; import org.eclipse.wst.common.project.facet.core.IFacetedProject; import org.eclipse.wst.common.project.facet.core.IProjectFacet; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; /** * This class provides the mechanism for generating BPEL * service artefacts. */ public class BPELGeneratorImpl extends AbstractGenerator { private static final String GENERATOR_NAME = "BPEL"; private static final String SCHEMA_LOCATION_ATTR = "schemaLocation"; private static final String INCLUDE_ELEMENT = "include"; private static final String XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; private static final String BPEL_DEPLOY_DESCRIPTOR_FILENAME = "deploy.xml"; private static final String BPEL_PATH = "bpelContent"; private static Logger logger = Logger.getLogger(BPELGeneratorImpl.class.getName()); /** * This is the constructor for the generator. * */ public BPELGeneratorImpl() { super(GENERATOR_NAME); } /** * This method returns the artifact type that will be generated. * * @return The artifact type */ public ArtifactType getArtifactType() { return(ArtifactType.ServiceImplementation); } /** * This method generates some artifacts based on the supplied model and * role. * * If specified, the optional project name will be used to create a * new Eclipse project for the generated artifacts. If no project name * is specified, then the artifacts will be created in the model * resource's project. * * @param model The protocol model * @param role The role * @param projectName The optional project name * @param modelResource The resource associated with the model * @param handler The feedback handler for reporting issues */ public void generate(ProtocolModel model, Role role, String projectName, IResource modelResource, FeedbackHandler handler) { if (logger.isLoggable(Level.FINE)) { logger.fine("Generate local model '"+role+"' for: "+model); } ProtocolModel local=getProtocolModelForRole(model, role, modelResource, handler); if (local != null) { // TODO: Obtain model generator from manager class (SAVARA-156) ProtocolToBPELModelGenerator generator=new ProtocolToBPELModelGenerator(); java.util.Map<String,Object> target=generator.generate(local, handler, null); if (target == null || target.size() != 1) { logger.severe("Protocol to BPEL model generator didn't return a single BPEL process definition"); } else { String targetName=target.keySet().iterator().next(); Object targetProcess=target.get(targetName); if (targetProcess instanceof TProcess) { try { generateRoleProject(model, projectName, role, targetName, (TProcess)targetProcess, local, modelResource, handler); } catch(Exception e) { logger.log(Level.SEVERE, "Failed to create BPEL project '"+projectName+"'", e); handler.error(MessageFormatter.format(java.util.PropertyResourceBundle.getBundle( "org.savara.tools.bpel.Messages"), "SAVARA-BPELTOOLS-00001", projectName), null); } } } } } protected void generateRoleProject(ProtocolModel model, String projectName, Role role, String bpelName, TProcess bpelProcess, ProtocolModel localcm, IResource resource, FeedbackHandler journal) throws Exception { java.util.List<javax.wsdl.Definition> wsdls= new java.util.Vector<javax.wsdl.Definition>(); final IProject proj=createProject(resource, projectName, journal); if (proj != null && bpelProcess != null) { // Store BPEL configuration IPath bpelPath=proj.getFullPath().append( new Path(BPEL_PATH)). append(bpelName); IFile bpelFile=proj.getProject().getWorkspace().getRoot().getFile(bpelPath); createFolder(bpelFile); bpelFile.create(null, true, new org.eclipse.core.runtime.NullProgressMonitor()); // Obtain any namespace prefix map java.util.Map<String, String> prefixes= new java.util.HashMap<String, String>(); java.util.List<Annotation> list= AnnotationDefinitions.getAnnotations(localcm.getProtocol().getAnnotations(), AnnotationDefinitions.TYPE); for (Annotation annotation : list) { if (annotation.getProperties().containsKey(AnnotationDefinitions.NAMESPACE_PROPERTY) && annotation.getProperties().containsKey(AnnotationDefinitions.PREFIX_PROPERTY)) { prefixes.put((String)annotation.getProperties().get(AnnotationDefinitions.NAMESPACE_PROPERTY), (String)annotation.getProperties().get(AnnotationDefinitions.PREFIX_PROPERTY)); } } //String bpelText=XMLUtils.toText(bpelProcess.getDOMElement()); ByteArrayOutputStream os=new ByteArrayOutputStream(); BPELModelUtil.serialize(bpelProcess, os, prefixes); os.close(); bpelFile.setContents(new java.io.ByteArrayInputStream( os.toByteArray()), true, false, new org.eclipse.core.runtime.NullProgressMonitor()); // Write the WSDL files generateWSDL(model, role, proj, localcm, resource, journal, wsdls); java.util.List<Role> roles=localcm.getProtocol().getRoles(); for (int i=0; i < roles.size(); i++) { generateWSDL(model, roles.get(i), proj, localcm, resource, journal, wsdls); } // Generate WSDL with partner link types org.w3c.dom.Document pty=generatePartnerLinkTypes(model, role, proj, localcm, bpelProcess, wsdls, journal); // Generate BPEL deployment descriptor generateBPELDeploy(model, role, proj, localcm, bpelProcess, wsdls, pty.getDocumentElement(), journal); } } protected void generateWSDL(ProtocolModel model, Role role, IProject proj, ProtocolModel localcm, IResource resource, FeedbackHandler journal, java.util.List<javax.wsdl.Definition> wsdls) throws Exception { ContractGenerator cg=ContractGeneratorFactory.getContractGenerator(); Contract contract=null; if (cg != null) { contract=cg.generate(model.getProtocol(), null, role, journal); } if (contract != null) { javax.wsdl.xml.WSDLWriter writer= javax.wsdl.factory.WSDLFactory.newInstance().newWSDLWriter(); org.savara.wsdl.generator.WSDLGenerator generator= WSDLGeneratorFactory.getWSDLGenerator(); // Generate BPEL folder IPath bpelFolderPath=proj.getFullPath().append( new Path(BPEL_PATH)); IFolder wsdlFolder=proj.getProject().getWorkspace().getRoot().getFolder(bpelFolderPath); createFolder(wsdlFolder); // Generate definition java.util.List<javax.wsdl.Definition> defns=generator.generate(contract, new SOAPDocLitWSDLBinding(), journal); // Check if contract has atleast one message exchange pattern boolean f_hasMEP=false; java.util.Iterator<Interface> iter=contract.getInterfaces().iterator(); while (f_hasMEP == false && iter.hasNext()) { Interface intf=iter.next(); f_hasMEP = (intf.getMessageExchangePatterns().size() > 0); } for (int i=defns.size()-1; i >= 0; i--) { javax.wsdl.Definition defn=defns.get(i); // Check if definition has a port type if (defn.getPortTypes().size() > 0 || defn.getMessages().size() > 0 || (f_hasMEP && defn.getServices().size() > 0)) { String num=""; if (i > 0) { num += i; } // Add definition to returned wsdl list wsdls.add(defn); String filename=WSDLGeneratorUtil.getWSDLFileName(role, localcm.getProtocol().getName(), num); byte[] b=null; if (i > 0) { javax.wsdl.Import imp=defns.get(0).createImport(); imp.setDefinition(defn); imp.setNamespaceURI(defn.getTargetNamespace()); imp.setLocationURI(filename); defns.get(0).addImport(imp); java.io.ByteArrayOutputStream baos=new java.io.ByteArrayOutputStream(); writer.writeWSDL(defn, baos); b = baos.toByteArray(); baos.close(); } else { org.w3c.dom.Document doc=writer.getDocument(defn); importSchemas(resource, contract, bpelFolderPath, doc); // Create bytearray from DOM java.io.ByteArrayOutputStream xmlstr= new java.io.ByteArrayOutputStream(); DOMSource source=new DOMSource(); source.setNode(doc); StreamResult result=new StreamResult(xmlstr); Transformer trans= TransformerFactory.newInstance().newTransformer(); trans.transform(source, result); xmlstr.close(); b = XMLUtils.format(new String(xmlstr.toByteArray())).getBytes(); } IPath wsdlPath=bpelFolderPath.append(filename); IFile wsdlFile=proj.getProject().getWorkspace().getRoot().getFile(wsdlPath); createFolder(wsdlFile); if (wsdlFile.exists() == false) { wsdlFile.create(null, true, new org.eclipse.core.runtime.NullProgressMonitor()); } wsdlFile.setContents(new java.io.ByteArrayInputStream(b), true, false, new org.eclipse.core.runtime.NullProgressMonitor()); } } } } protected void importSchemas(IResource resource, Contract contract, IPath bpelFolderPath, org.w3c.dom.Document doc) throws Exception { // NOTE: Unfortunate workaround due to issue with WSDLWriter not // generating output for extensible elements created to represent // the xsd:schema/xsd:import elements. So instead had to obtain // the DOM document and insert the relevant elements. if (contract.getNamespaces().size() > 0) { org.w3c.dom.Element defnElem=doc.getDocumentElement(); // Added types node org.w3c.dom.Element types=doc.createElementNS("http://schemas.xmlsoap.org/wsdl/", "types"); org.w3c.dom.Element schema=doc.createElementNS("http://www.w3.org/2001/XMLSchema", "schema"); types.appendChild(schema); // Generate imports for specified message schema for (Namespace ns : contract.getNamespaces()) { if (ns.getSchemaLocation() != null && ns.getSchemaLocation().trim().length() > 0) { java.util.StringTokenizer st=new java.util.StringTokenizer(ns.getSchemaLocation()); while (st.hasMoreTokens()) { String location=st.nextToken(); IFile file=resource.getParent().getFile(new Path(location)); org.w3c.dom.Element imp=doc.createElementNS("http://www.w3.org/2001/XMLSchema", "import"); imp.setAttribute("namespace", ns.getURI()); if (file.exists()) { imp.setAttribute("schemaLocation", file.getProjectRelativePath().toPortableString()); // Copy schema file into generated BPEL project IPath artifactPath=bpelFolderPath.append(file.getProjectRelativePath()); IFile artifactFile=resource.getProject().getWorkspace().getRoot().getFile(artifactPath); copySchema(file, artifactFile, bpelFolderPath); } else { imp.setAttribute("schemaLocation", location); } schema.appendChild(imp); } } } defnElem.insertBefore(types, defnElem.getFirstChild()); } } protected void copySchema(IFile srcXSDFile, IFile targetXSDFile, IPath bpelFolderPath) throws Exception { if (targetXSDFile.exists() == false) { createFolder(targetXSDFile.getParent()); targetXSDFile.create(null, true, new org.eclipse.core.runtime.NullProgressMonitor()); } targetXSDFile.setContents(srcXSDFile.getContents(), true, false, new org.eclipse.core.runtime.NullProgressMonitor()); // Check XSD for further 'include' statements DocumentBuilderFactory fact=DocumentBuilderFactory.newInstance(); fact.setNamespaceAware(true); DocumentBuilder builder=fact.newDocumentBuilder(); org.w3c.dom.Document doc=builder.parse(srcXSDFile.getContents()); org.w3c.dom.NodeList nl=doc.getElementsByTagNameNS(XML_SCHEMA, INCLUDE_ELEMENT); for (int i=0; i < nl.getLength(); i++) { org.w3c.dom.Node includeNode=nl.item(i); if (includeNode instanceof org.w3c.dom.Element) { String schemaLocation=((org.w3c.dom.Element)includeNode).getAttribute(SCHEMA_LOCATION_ATTR); // Check if a relative path IFile file=srcXSDFile.getParent().getFile(new Path(schemaLocation)); if (file.exists()) { IPath artifactPath=bpelFolderPath.append(file.getProjectRelativePath()); IFile artifactFile=file.getProject().getWorkspace().getRoot().getFile(artifactPath); copySchema(file, artifactFile, bpelFolderPath); } } } } protected org.w3c.dom.Document generatePartnerLinkTypes(ProtocolModel model, Role role, IProject proj, ProtocolModel localcm, TProcess bpelProcess, java.util.List<javax.wsdl.Definition> wsdls, FeedbackHandler journal) throws Exception { org.w3c.dom.Document doc=BPELGeneratorUtil.generatePartnerLinkTypes(model, role, localcm, bpelProcess, journal); // Write partner link types to file String filename=WSDLGeneratorUtil.getWSDLFileName(role, localcm.getProtocol().getName(), "Artifacts"); IPath wsdlPath=proj.getFullPath().append( new Path(BPEL_PATH)). append(filename); IFile wsdlFile=proj.getProject().getWorkspace().getRoot().getFile(wsdlPath); createFolder(wsdlFile); wsdlFile.create(null, true, new org.eclipse.core.runtime.NullProgressMonitor()); java.io.ByteArrayOutputStream xmlstr= new java.io.ByteArrayOutputStream(); DOMSource source=new DOMSource(); source.setNode(doc); StreamResult result=new StreamResult(xmlstr); Transformer trans= TransformerFactory.newInstance().newTransformer(); trans.transform(source, result); xmlstr.close(); String xml=XMLUtils.format(new String(xmlstr.toByteArray())); wsdlFile.setContents(new java.io.ByteArrayInputStream(xml.getBytes()), true, false, new org.eclipse.core.runtime.NullProgressMonitor()); return (doc); } protected void generateBPELDeploy(ProtocolModel model, Role role, IProject proj, ProtocolModel localcm, TProcess bpelProcess, java.util.List<javax.wsdl.Definition> wsdls, org.w3c.dom.Element partnerLinkTypes, FeedbackHandler journal) throws Exception { org.w3c.dom.Document doc=BPELGeneratorUtil.generateDeploymentDescriptor(model, role, localcm, bpelProcess, wsdls, partnerLinkTypes, journal); // Write partner link types to file IPath wsdlPath=proj.getFullPath().append( new Path(BPEL_PATH)). append(BPEL_DEPLOY_DESCRIPTOR_FILENAME); IFile wsdlFile=proj.getProject().getWorkspace().getRoot().getFile(wsdlPath); createFolder(wsdlFile); wsdlFile.create(null, true, new org.eclipse.core.runtime.NullProgressMonitor()); java.io.ByteArrayOutputStream xmlstr= new java.io.ByteArrayOutputStream(); DOMSource source=new DOMSource(); source.setNode(doc); StreamResult result=new StreamResult(xmlstr); Transformer trans= TransformerFactory.newInstance().newTransformer(); trans.transform(source, result); xmlstr.close(); String xml=XMLUtils.format(new String(xmlstr.toByteArray())); wsdlFile.setContents(new java.io.ByteArrayInputStream(xml.getBytes()), true, false, new org.eclipse.core.runtime.NullProgressMonitor()); } protected IProject createProject(IResource resource, String projectName, FeedbackHandler journal) throws Exception { // Create project IProject project = resource.getWorkspace().getRoot().getProject(projectName); project.create(new org.eclipse.core.runtime.NullProgressMonitor()); // Open the project project.open(new org.eclipse.core.runtime.NullProgressMonitor()); // Add wtp natures WtpUtils.addNatures(project); // Add required project facets try { IProjectFacet bpelFacet = ProjectFacetsManager.getProjectFacet("bpel.facet.core"); IProjectFacetVersion ipfv = bpelFacet.getVersion("2.0"); IFacetedProject ifp = ProjectFacetsManager.create(project, true, null); ifp.installProjectFacet(ipfv, null, new org.eclipse.core.runtime.NullProgressMonitor()); } catch(Exception e) { Activator.logError("Failed to add BPEL facet to project", e); } return(project); } /** * This method checks whether the folder exists, * and if not attempts to create it. * * @param res The current resource */ public static void createFolder(IResource res) { if (res instanceof IFolder) { IFolder folder=(IFolder)res; if (folder.exists() == false) { createFolder(folder.getParent()); try { folder.create(true, true, new org.eclipse.core.runtime.NullProgressMonitor()); } catch(Exception e) { e.printStackTrace(); } } } else if (res.getParent() != null) { createFolder(res.getParent()); } } }