/******************************************************************************* | |
* 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); | |
} | |
} | |
} |