/******************************************************************************* * Copyright (c) 2006, 2012 Oracle Corporation and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Oracle Corporation *******************************************************************************/ package org.eclipse.bpel.ui; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.eclipse.bpel.ui.wizards.WSDLServiceDetail; import org.osgi.framework.Bundle; /** * You can think of BPEL templates as a 1 dimensional list of stencils that are * used to create an initial BPEL process. * <p> * Each template for a process may contain just 1 resource - just the template * for the BPEL process itself. But it may also contain other resources which * are useful in creating that particular process from that particular template. * Simply put, a template may have 1-N template resources that need to be * created as a result of creating what appears to be a single process file. * * @author Michal Chmielewski (michal.chmielewski@oracle.com) */ public class Templates { /** this file defines the properties for a particular template */ static final String TEMPLATE_PROPERTIES = "template.properties"; //$NON-NLS-1$ /** location within the bundle where we look for templates */ static final String TEMPLATE_LOCATION = "/templates/"; //$NON-NLS-1$ /** default template file encoding, for a given set of template resources */ static final String DEFAULT_ENCODING = "UTF-8"; //$NON-NLS-1$ /** the main bpel file has this extension */ @Deprecated // use content type instead of bpel file extensions static final String BPEL_FILE_EXTENSION = ".bpel"; //$NON-NLS-1$ /** Entries which are directories of the bundle */ static final String BUNDLE_DIRECTORY = "/"; //$NON-NLS-1$ /** Key or property under which the name of the template is present */ public static final String PROPERTY_NAME = "name"; //$NON-NLS-1$ /** The key name of the template */ public static final String PROPERTY_KEY = "key"; //$NON-NLS-1$ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330813 // https://jira.jboss.org/browse/JBIDE-7165 /** All of the known template keys */ public static final String TEMPLATE_KEY_ASYNC = "async"; public static final String TEMPLATE_KEY_SYNC = "sync"; public static final String TEMPLATE_KEY_EMPTY = "empty"; /** Add more above, as new templates are created */ /** * Key or property under which the encoding information for the template * resources is present */ public static final String PROPERTY_ENCODING = "encoding"; //$NON-NLS-1$ /** Key or property under which the description of the template is present */ public static final String PROPERTY_DESCRIPTION = "description"; //$NON-NLS-1$ /** avoid empty string */ static final String EMPTY = ""; //$NON-NLS-1$ static final String[] EMPTY_NAMES = {}; /** Templates contribute namespaces to the new file wizard */ Set<String> mNamespaceNames = new TreeSet<String>(); /** * Templates indexed by name, sorted by name, according to the natural * ordering */ Map<String, Template> mTemplateByName = new TreeMap<String, Template>(); /** Templates indexed by id, sorted by name */ Map<String, Template> mTemplateByKey = new HashMap<String, Template>(); /** * Initialize the template information from the bundle passed. This is * typically the bundle of the plugin. * * @author Michal Chmielewski (michal.chmielewski@oracle.com) * @param bundle * the bundle where the template information ought to be looked * for */ @SuppressWarnings("nls") public void initializeFrom(Bundle bundle) { initializeFrom(bundle, TEMPLATE_LOCATION); } /** * @param templateLocation */ public void initializeFrom(String templateLocation) { initializeFrom(BPELUIPlugin.INSTANCE.getBundle(), templateLocation); } /** * @param bundle * @param templateLocation */ @SuppressWarnings( { "nls", "boxing", "unchecked" }) public void initializeFrom(Bundle bundle, String templateLocation) { Enumeration<String> list = bundle.getEntryPaths(templateLocation); if (list == null) { return; } // got some elements, look for "template.properties" int count = 0; while (list.hasMoreElements()) { String nextRoot = list.nextElement(); if (nextRoot.endsWith(BUNDLE_DIRECTORY) == false) { continue; } String nextEntry = nextRoot + TEMPLATE_PROPERTIES; // found another template URL nextURL = bundle.getEntry(nextEntry); if (nextURL == null) { // no such thing continue; } // looks like we have properties count += 1; Properties props = new Properties(); InputStream is = null; try { is = nextURL.openStream(); props.load(is); } catch (IOException e) { BPELUIPlugin.log(e); // skip to the next entry continue; } finally { try { is.close(); } catch (Throwable t) { } } String name = props.getProperty(PROPERTY_NAME); // No name, no game. if (name == null) { continue; } String enc = props.getProperty(PROPERTY_ENCODING, DEFAULT_ENCODING); String desc = props.getProperty(PROPERTY_DESCRIPTION, EMPTY); // add any namespaces we are supplying ... mNamespaceNames.addAll(findProperties(props, "namespace.{0}")); Template template = new Template(); template.mName = name; template.mDescription = desc; template.mProperties = (Map) props; mTemplateByName.put(name, template); String id = props.getProperty(PROPERTY_KEY); if (id != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330813 // https://jira.jboss.org/browse/JBIDE-7165 template.mKey = id; mTemplateByKey.put(id, template); } int hole = 3; for (int i = 0; hole >= 0; i++) { String key = MessageFormat.format("resource.{0}", i); String resourceName = props.getProperty(key); if (resourceName == null) { hole--; continue; } hole = 3; key = MessageFormat.format("resource.{0}.name", i); String nameTemplate = props.getProperty(key); String entryLoc = nextRoot + resourceName; TemplateResource resource = new TemplateResource(); resource.mName = resourceName; resource.mContent = slurpContent(bundle.getEntry(entryLoc), enc); resource.mNameTemplate = nameTemplate; // add the resource which makes up this "template" template.add(resource); } } } /** * Slurp the resource into memory and return as a String. If an exception * occurs, it is logged, and the return value is empty string. * * @param loc * the location from which we should slurp ... * @param enc * the encoding to use * @return the text */ String slurpContent(URL loc, String enc) { if (loc == null) { return null; } StringBuilder sb = new StringBuilder(2 * 1048); char[] buf = new char[256]; InputStreamReader isr = null; try { isr = new InputStreamReader(loc.openStream(), enc); do { int cnt = isr.read(buf); if (cnt < 0) { break; } sb.append(buf, 0, cnt); } while (true); } catch (Exception ex) { BPELUIPlugin.log(ex); } finally { try { isr.close(); } catch (Throwable t) { } } return sb.toString(); } List<String> findProperties(Properties props, String pattern) { List<String> list = new ArrayList<String>(); int hole = 3; for (int i = 0; hole >= 0; i++) { String key = MessageFormat.format(pattern, new Object[] { Integer.valueOf( i )}); String val = props.getProperty(key, null); if (val != null) { list.add(val); hole = 3; } else { hole--; } } return list; } /** * @param key * @return the template whose key is key */ public Template getTemplateByKey(String key) { return mTemplateByKey.get(key); } /** * Return the template definition (which includes other resources that may * be present) to the caller. * * @param name * name of the template * @return the template definition, including template resources */ public Template getTemplateByName(String name) { return mTemplateByName.get(name); } /** * * @return Return the namespaces contributed by the templates. */ public String[] getNamespaceNames() { return mNamespaceNames.toArray(EMPTY_NAMES); } /** * Return the template names that have been discovered. * * @return Return the template names. */ public String[] getTemplateNames() { return mTemplateByName.keySet().toArray(EMPTY_NAMES); } /** * A given "BPEL Process" Template has a name, description, and a list of * resources (file templates) that will be used to create the initial * process source file. * * @author Michal Chmielewski (michal.chmielewski@oracle.com) * */ public class Template { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330813 // https://jira.jboss.org/browse/JBIDE-7165 /** Template key so we don't have to worry about using localized names everywhere */ String mKey; /** Name of the process template */ String mName; /** Description of this process template */ String mDescription; Map<String, String> mProperties; /** list of resources that this template has (1-N) */ List<TemplateResource> mResources = new ArrayList<TemplateResource>(); /** * @return the name */ public String getName() { return mName; } /** * @return the key * https://bugs.eclipse.org/bugs/show_bug.cgi?id=330813 * @see https://jira.jboss.org/browse/JBIDE-7165 */ public String getKey() { return mKey; } void add(TemplateResource resource) { mResources.add(resource); resource.mTemplate = this; } /** * @return the template resources */ public List<TemplateResource> getResources() { return mResources; } /** * @return the description */ public String getDescription() { return mDescription; } /** * Return the property under the key or null if not found. * * @param key * @return the property under the key, or null. */ public String getProperty(String key) { return mProperties.get(key); } TemplateResource lookupResource(String name) { String name2 = mProperties.get(name); for (TemplateResource resource : mResources) { if (name.equals(resource.mName)) { return resource; } if (name2 != null && name2.equals(resource.mName)) { return resource; } } return null; } } /** * A template resource is the actual file which will be used to create the * source file or other auxiliary files for the BPEL process source. * * @author Michal Chmielewski, (michal.chmielewski@oracle.com) * */ public class TemplateResource { /** The template I belong to */ Template mTemplate = null; /** Name of the resource (from the bundle) */ String mName; /** The content of the resource (slurped from the bundle) */ String mContent; /** * The name template, that is, the file name template if depended on * process name */ String mNameTemplate; /** * @return the content */ public String getContent() { return mContent; } /** * @return the name */ public String getName() { return mName; } /** * Process the content of the template and replace anything within * ${...} by the corresponding key prent in the map passed. * * @param args * the keys that will be replaced in the content * @return the replaced content */ public String process(Map<String, Object> args) { return process(mContent, args); } /** * Process the content of the template and replace anything within * ${...} by the corresponding key present in the map passed. * * @param args * the keys that will be replaced in the content * @return the replaced content */ @SuppressWarnings("nls") String process(String src, Map<String, Object> args) { // empty content, empty result if (src == null) { return ""; } // add the service and binding content int start = src.indexOf("</definitions>"); if (start > 0) { StringBuffer ss = new StringBuffer(src.substring(0, start)); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330813 // https://jira.jboss.org/browse/JBIDE-7165 // use key instead of [possibly] localized template name Object key = args.get(Templates.PROPERTY_KEY); String protocol = (String) args.get("protocol"); if (protocol!=null) protocol = protocol.toLowerCase(); if (Templates.TEMPLATE_KEY_ASYNC.equals(key)) { if ("soap".equals(protocol)) { ss.append(WSDLServiceDetail.Async_SOAPDetail); } else { ss.append(WSDLServiceDetail.Async_HTTPDetail); } } else if (Templates.TEMPLATE_KEY_SYNC.equals(key)) { if ("soap".equals(protocol)) { ss.append(WSDLServiceDetail.Sync_SOAPDetail); } else { ss.append(WSDLServiceDetail.Sync_HTTPDetail); } } else if (Templates.TEMPLATE_KEY_EMPTY.equals(key)) { ss.append(WSDLServiceDetail.Empty_Detail); } ss.append("</definitions>"); src = ss.toString(); } StringBuilder sb = new StringBuilder(src.length()); int cursor = 0; do { int openReplace = src.indexOf("${", cursor); if (openReplace < 0) { break; } sb.append(src.substring(cursor, openReplace)); cursor = openReplace + 2; int closeReplace = src.indexOf("}", cursor); if (closeReplace < 0) { return sb.toString(); } String expr = src.substring(cursor, closeReplace).trim(); sb.append(lookup(expr, args)); cursor = closeReplace + 1; } while (true); // the last segment sb.append(src.substring(cursor)); return sb.toString(); } @SuppressWarnings("nls") Object lookup(String key, Map<String, Object> args) { Object value = null; TemplateResource r = null; if (key.startsWith(":include:")) { key = key.substring(9); r = mTemplate.lookupResource(key); if (r != null) { value = r.mContent; } } else if (key.startsWith(":parse:")) { key = key.substring(7); r = mTemplate.lookupResource(key); /** Avoid recursion at this point */ if (r != null && r != this) { value = r.process(args); } } else { value = args.get(key); if (value == null) { value = mTemplate.mProperties.get(key); } } return value; } /** * Return the name of the resource * * @param args * map of arguments that are used in replacing * @return the name of the resource, after token replacement. */ public String getName(Map<String, Object> args) { if (mNameTemplate == null) { return mName; } return process(mNameTemplate, args); } /** * Ask if this TemplateResource is specifically a BPEL source file. * * @return Answer true if the extension is .bpel */ public boolean isProcess() { return mName.endsWith(BPEL_FILE_EXTENSION); } } }