blob: b9a7220e0bf09a1173395e5fe691117018b119c1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 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.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 */
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 */
static final String PROPERTY_NAME = "name"; //$NON-NLS-1$
/** The key name of the template */
static final String PROPERTY_KEY = "key"; //$NON-NLS-1$
/** Key or property under which the encoding information for the template resources is present */
static final String PROPERTY_ENCODING = "encoding"; //$NON-NLS-1$
/** Key or property under which the description of the template is present */
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" })
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) {
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[] { new Integer(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 {
/** 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;
}
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 "";
}
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 );
}
}
}