/* * 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.switchyard.bpel.generator; import java.io.ByteArrayOutputStream; import java.util.logging.Level; import java.util.logging.Logger; import javax.wsdl.xml.WSDLReader; 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.IProjectDescription; import org.eclipse.core.resources.IResource; import org.savara.bpel.generator.ProtocolToBPELModelGenerator; import org.savara.bpel.model.TProcess; 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.switchyard.bpel.generator.SwitchyardBPELGenerator; import org.savara.tools.common.ArtifactType; import org.savara.tools.common.generation.AbstractGenerator; import org.savara.tools.common.generation.GeneratorUtil; 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.scribble.protocol.util.RoleUtil; import org.eclipse.core.runtime.*; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; /** * This class provides the mechanism for generating Switchyard BPEL * service artefacts. */ public class SwitchyardBPELGeneratorImpl extends AbstractGenerator { private static final String SWITCHYARD_XML_FILENAME = "switchyard.xml"; private static final String GENERATOR_NAME = "BPEL (Switchyard)"; 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 JAVA_PATH = "src/main/java"; private static final String RESOURCE_PATH = "src/main/resources"; private static final String WSDL_PATH = RESOURCE_PATH; private static final String BPEL_PATH = RESOURCE_PATH; private static final String BPEL_DEPLOY_DESCRIPTOR_FILENAME = "deploy.xml"; private WSDLReader _reader=null; private static Logger logger = Logger.getLogger(SwitchyardBPELGeneratorImpl.class.getName()); /** * This is the constructor for the generator. * */ public SwitchyardBPELGeneratorImpl() { super(GENERATOR_NAME); try { _reader = javax.wsdl.factory.WSDLFactory.newInstance().newWSDLReader(); } catch(Exception e) { logger.log(Level.SEVERE, "Failed to get WSDL reader", e); } } /** * This method returns a WSDL reader. * * @return The WSDL reader */ protected WSDLReader getWSDLReader() { return (_reader); } /** * 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) { java.util.Map<String,javax.wsdl.Definition> wsdls= new java.util.HashMap<String,javax.wsdl.Definition>(); if (logger.isLoggable(Level.FINE)) { logger.fine("Generate local model '"+role+"' for: "+model); } ProtocolModel local=getProtocolModelForRole(model, role, modelResource, handler); if (local != null) { try { final IProject proj=createProject(modelResource, projectName, handler); ProtocolToBPELModelGenerator generator=new ProtocolToBPELModelGenerator(); java.util.Map<String,Object> map=generator.generate(local, handler, null); if (map== null || map.size() != 1) { logger.severe("Protocol to BPEL model generator didn't return a single BPEL process definition"); } else { String targetName=map.keySet().iterator().next(); Object target=map.get(targetName); if (target instanceof TProcess) { TProcess bpelProcess=(TProcess)target; // Store BPEL configuration IPath bpelPath=proj.getFullPath().append( new Path(BPEL_PATH)). append(local.getProtocol().getName()+"_"+ local.getProtocol().getLocatedRole().getName()+".bpel"); IFile bpelFile=proj.getProject().getWorkspace().getRoot().getFile(bpelPath); 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(local.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)); } } 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()); // Generate WSDL with partner link types org.w3c.dom.Document pty=generatePartnerLinkTypes(model, role, proj, local, bpelProcess, wsdls.values(), handler); java.util.Set<Role> refRoles=RoleUtil.getDeclaredRoles(local.getProtocol().getBlock()); // Write the WSDL files for (Role refRole : refRoles) { Contract contract=ContractGeneratorFactory.getContractGenerator().generate(local.getProtocol(), null, refRole, handler); if (contract.getInterfaces().size() > 0) { generateWSDL(model, refRole, proj, local, modelResource, handler, wsdls); } } IFile wsdlFile=generateWSDL(model, role, proj, local, modelResource, handler, wsdls); javax.wsdl.Definition serviceWsdl=null; if (wsdlFile != null) { serviceWsdl = getWSDLReader().readWSDL(wsdlFile.getLocation().toOSString()); } // Generate BPEL deployment descriptor org.w3c.dom.Document deployDescriptor= generateBPELDeploy(model, role, proj, local, bpelProcess, wsdls.values(), pty.getDocumentElement(), handler); // Generate the switchyard descriptor createSwitchyardDescriptor(proj, role.getName(), deployDescriptor.getDocumentElement(), serviceWsdl, wsdls); proj.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); } } } catch(Exception e) { org.savara.tools.switchyard.bpel.osgi.Activator.logError("Failed to create Switchyard BPEL project '"+ projectName+"'", e); handler.error(MessageFormatter.format(java.util.PropertyResourceBundle.getBundle( "org.savara.tools.switchyard.bpel.Messages"), "SAVARA-SWYDBPELTOOLS-00001", projectName), null); } } } protected IFile generateWSDL(ProtocolModel model, Role role, IProject proj, ProtocolModel localcm, IResource resource, FeedbackHandler journal, java.util.Map<String,javax.wsdl.Definition> wsdls) throws Exception { IFile ret=null; 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 WSDL folder IPath wsdlFolderPath=proj.getFullPath().append( new Path(WSDL_PATH)); IFolder wsdlFolder=proj.getProject().getWorkspace().getRoot().getFolder(wsdlFolderPath); GeneratorUtil.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; } String filename=WSDLGeneratorUtil.getWSDLFileName(role, localcm.getProtocol().getName(), num); // Add definition to returned wsdl list wsdls.put(filename, defn); 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, wsdlFolderPath, 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=wsdlFolderPath.append(filename); IFile wsdlFile=proj.getProject().getWorkspace().getRoot().getFile(wsdlPath); if (wsdlFile.getParent() instanceof IFolder) { GeneratorUtil.createFolder((IFolder)wsdlFile.getParent()); } 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()); ret = wsdlFile; } } } return(ret); } protected org.w3c.dom.Document generatePartnerLinkTypes(ProtocolModel model, Role role, IProject proj, ProtocolModel localcm, TProcess bpelProcess, java.util.Collection<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); 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 org.w3c.dom.Element createSwitchyardDescriptor(IProject proj, String name, org.w3c.dom.Element descriptor, javax.wsdl.Definition serviceWsdl, java.util.Map<String,javax.wsdl.Definition> wsdls) throws Exception { SwitchyardBPELGenerator gen=new SwitchyardBPELGenerator(); // Generate the switchyard descriptor org.w3c.dom.Element swdesc=gen.createSwitchyardDescriptor(name, descriptor, serviceWsdl, wsdls); // Write partner link types to file IPath deployDescPath=proj.getFullPath().append( new Path(BPEL_PATH+java.io.File.separatorChar+"META-INF")) .append(SWITCHYARD_XML_FILENAME); IFile deployDescFile=proj.getProject().getWorkspace().getRoot().getFile(deployDescPath); GeneratorUtil.createFolder((IFolder)deployDescFile.getParent()); deployDescFile.create(null, true, new org.eclipse.core.runtime.NullProgressMonitor()); java.io.ByteArrayOutputStream xmlstr= new java.io.ByteArrayOutputStream(); DOMSource source=new DOMSource(); source.setNode(swdesc.getOwnerDocument()); StreamResult result=new StreamResult(xmlstr); Transformer trans= TransformerFactory.newInstance().newTransformer(); trans.transform(source, result); xmlstr.close(); String xml=new String(xmlstr.toByteArray()); deployDescFile.setContents(new java.io.ByteArrayInputStream(xml.getBytes()), true, false, new org.eclipse.core.runtime.NullProgressMonitor()); return(swdesc); } protected org.w3c.dom.Document generateBPELDeploy(ProtocolModel model, Role role, IProject proj, ProtocolModel localcm, TProcess bpelProcess, java.util.Collection<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 deployDescPath=proj.getFullPath().append( new Path(BPEL_PATH)). append(BPEL_DEPLOY_DESCRIPTOR_FILENAME); IFile deployDescFile=proj.getProject().getWorkspace().getRoot().getFile(deployDescPath); deployDescFile.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())); deployDescFile.setContents(new java.io.ByteArrayInputStream(xml.getBytes()), true, false, new org.eclipse.core.runtime.NullProgressMonitor()); return(doc); } 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) { if (targetXSDFile.getParent() instanceof IFolder) { GeneratorUtil.createFolder((IFolder)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 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); IJavaProject jproject=JavaCore.create(project); // Create the java project createJavaProject(jproject); return(project); } protected void createJavaProject(IJavaProject project) { try { IProjectDescription description = project.getProject().getDescription(); String[] prevNatures= description.getNatureIds(); String[] newNatures= new String[prevNatures.length + 1]; System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length); newNatures[prevNatures.length]= JavaCore.NATURE_ID; description.setNatureIds(newNatures); project.getProject().setDescription(description, new org.eclipse.core.runtime.NullProgressMonitor()); IClasspathEntry[] classpaths=new IClasspathEntry[3]; classpaths[0] = JavaCore.newContainerEntry( new Path("org.eclipse.jdt.launching.JRE_CONTAINER")); IFolder srcFolder=project.getProject().getFolder(JAVA_PATH); GeneratorUtil.createFolder(srcFolder); classpaths[1] = JavaCore.newSourceEntry(srcFolder.getFullPath()); IFolder resFolder=project.getProject().getFolder(RESOURCE_PATH); GeneratorUtil.createFolder(resFolder); classpaths[2] = JavaCore.newSourceEntry(resFolder.getFullPath()); // Set classpath project.setRawClasspath(classpaths, new org.eclipse.core.runtime.NullProgressMonitor()); } catch(Exception e) { logger.severe("Failed to create Java project: "+e); } } }