| /* |
| * Copyright 2002,2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.commons.jelly; |
| |
| import java.io.File; |
| import java.io.InputStream; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.Enumeration; |
| import java.util.Properties; |
| |
| import org.apache.commons.jelly.parser.XMLParser; |
| import org.apache.commons.jelly.util.ClassLoaderUtils; |
| import org.apache.commons.jelly.util.CommandLineParser; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.xml.sax.SAXException; |
| |
| /** |
| * <p><code>Jelly</code> is a helper class which is capable of |
| * running a Jelly script. This class can be used from the command line |
| * or can be used as the basis of an Ant task.</p> Command line usage is as follows: |
| * |
| * <pre> |
| * jelly [scriptFile] [-script scriptFile -o outputFile -Dsysprop=syspropval] |
| * </pre> |
| * |
| * @author <a href="mailto:jstrachan@apache.org">James Strachan</a> |
| * @version $Revision: 1.35 $ |
| */ |
| public class Jelly { |
| |
| /** The Log to which logging calls will be made. */ |
| private static final Log log = LogFactory.getLog(Jelly.class); |
| |
| /** The JellyContext to use */ |
| private JellyContext context; |
| |
| /** The URL of the script to execute */ |
| private URL url; |
| |
| /** The URL of the root context for other scripts */ |
| private URL rootContext; |
| |
| /** Whether we have loaded the properties yet */ |
| private boolean loadedProperties = false; |
| |
| /** |
| * whether to override the default namespace |
| */ |
| private String defaultNamespaceURI = null; |
| |
| /** |
| * whether or not to validate the Jelly script |
| */ |
| private boolean validateXML = false; |
| |
| public Jelly() { |
| } |
| |
| /** |
| * Usage: jelly [scriptFile] [-script scriptFile -o outputFile -Dsysprop=syspropval] |
| */ |
| public static void main(String[] args) throws Exception { |
| |
| try { |
| if (args.length <= 0) { |
| System.out.println("Usage: jelly [scriptFile] [-script scriptFile -o outputFile -Dsysprop=syspropval]"); |
| return; |
| } |
| |
| // parse the command line options using CLI |
| // using a separate class to avoid unnecessary |
| // dependencies |
| CommandLineParser.getInstance().invokeCommandLineJelly(args); |
| } |
| catch (JellyException e) { |
| Throwable cause = e.getCause(); |
| |
| if (cause == null) { |
| e.printStackTrace(); |
| } else { |
| cause.printStackTrace(); |
| } |
| } |
| } |
| |
| |
| public static String getJellyVersion() { |
| return readBuildTimestampResource("jelly-version.txt"); |
| } |
| |
| public static String getJellyBuildDate() { |
| return readBuildTimestampResource("jelly-build-date.txt"); |
| } |
| |
| private static String readBuildTimestampResource(String name) { |
| java.io.Reader in = null; |
| try { |
| java.io.StringWriter w = new java.io.StringWriter(); |
| in = new java.io.InputStreamReader(Jelly.class.getResourceAsStream(name),"utf-8"); |
| int r; |
| while ( (r=in.read()) >= 0 ) { |
| w.write((char) r); |
| } |
| return w.toString(); |
| } catch(Exception ex) { |
| ex.printStackTrace(); |
| try { in.close(); } catch(Exception e) {} |
| throw new IllegalStateException("Resource \"" + name + "\" not found."); |
| } |
| } |
| |
| |
| |
| /** |
| * Compiles the script |
| */ |
| public Script compileScript() throws JellyException { |
| if (! loadedProperties) { |
| loadedProperties = true; |
| loadJellyProperties(); |
| } |
| |
| XMLParser parser = new XMLParser(); |
| try { |
| parser.setContext(getJellyContext()); |
| } catch (MalformedURLException e) { |
| throw new JellyException(e.toString()); |
| } |
| |
| Script script = null; |
| try { |
| parser.setDefaultNamespaceURI(this.defaultNamespaceURI); |
| parser.setValidating(this.validateXML); |
| script = parser.parse(getUrl()); |
| script = script.compile(); |
| if (log.isDebugEnabled()) { |
| log.debug("Compiled script: " + getUrl()); |
| } |
| } catch (IOException e) { |
| throw new JellyException("could not parse Jelly script",e); |
| } catch (SAXException e) { |
| throw new JellyException("could not parse Jelly script",e); |
| } |
| |
| return script; |
| } |
| |
| |
| // Properties |
| //------------------------------------------------------------------------- |
| |
| /** |
| * Sets the script URL to use as an absolute URL or a relative filename |
| */ |
| public void setScript(String script) throws MalformedURLException { |
| setUrl(resolveURL(script)); |
| } |
| |
| public URL getUrl() { |
| return url; |
| } |
| |
| /** |
| * Sets the script URL to use |
| */ |
| public void setUrl(URL url) { |
| this.url = url; |
| } |
| |
| /** |
| * Gets the root context |
| */ |
| public URL getRootContext() throws MalformedURLException { |
| if (rootContext == null) { |
| rootContext = new File(System.getProperty("user.dir")).toURL(); |
| } |
| return rootContext; |
| } |
| |
| /** |
| * Sets the root context |
| */ |
| public void setRootContext(URL rootContext) { |
| this.rootContext = rootContext; |
| } |
| |
| /** |
| * The context to use |
| */ |
| public JellyContext getJellyContext() throws MalformedURLException { |
| if (context == null) { |
| // take off the name off the URL |
| String text = getUrl().toString(); |
| int idx = text.lastIndexOf('/'); |
| text = text.substring(0, idx + 1); |
| context = new JellyContext(getRootContext(), new URL(text)); |
| } |
| return context; |
| } |
| |
| |
| /** |
| * Set the jelly namespace to use for unprefixed elements. |
| * Will be overridden by an explicit namespace in the |
| * XML document. |
| * |
| * @param namespace jelly namespace to use (e.g. 'jelly:core') |
| */ |
| public void setDefaultNamespaceURI(String namespace) { |
| this.defaultNamespaceURI = namespace; |
| } |
| |
| /** |
| * When set to true, the XML parser will attempt to validate |
| * the Jelly XML before converting it into a Script. |
| * |
| * @param validate whether or not to validate |
| */ |
| public void setValidateXML(boolean validate) { |
| this.validateXML = validate; |
| } |
| |
| // Implementation methods |
| //------------------------------------------------------------------------- |
| /** |
| * @return the URL for the relative file name or absolute URL |
| */ |
| protected URL resolveURL(String name) throws MalformedURLException { |
| |
| URL resourceUrl = ClassLoaderUtils.getClassLoader(getClass()).getResource(name); |
| if (resourceUrl == null) |
| { |
| File file = new File(name); |
| if (file.exists()) { |
| return file.toURL(); |
| } |
| return new URL(name); |
| } else { |
| return resourceUrl; |
| } |
| } |
| |
| /** |
| * Attempts to load jelly.properties from the current directory, |
| * the users home directory or from the classpath |
| */ |
| protected void loadJellyProperties() { |
| InputStream is = null; |
| |
| String userDir = System.getProperty("user.home"); |
| File f = new File(userDir + File.separator + "jelly.properties"); |
| loadProperties(f); |
| |
| f = new File("jelly.properties"); |
| loadProperties(f); |
| |
| |
| is = ClassLoaderUtils.getClassLoader(getClass()).getResourceAsStream("jelly.properties"); |
| if (is != null) { |
| try { |
| loadProperties(is); |
| } |
| catch (Exception e) { |
| log.error( "Caught exception while loading jelly.properties from the classpath. Reason: " + e, e ); |
| } |
| } |
| } |
| |
| /** |
| * Load properties from a file into the context |
| * @param f |
| */ |
| private void loadProperties(File f) { |
| InputStream is = null; |
| try { |
| if (f.exists()) { |
| is = new FileInputStream(f); |
| loadProperties(is); |
| } |
| } catch (Exception e) { |
| log.error( "Caught exception while loading: " + f.getName() + ". Reason: " + e, e ); |
| } finally { |
| if (is != null) { |
| try { |
| is.close(); |
| } catch (IOException e) { |
| if (log.isDebugEnabled()) log.debug("error closing property input stream", e); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Loads the properties from the given input stream |
| */ |
| protected void loadProperties(InputStream is) throws IOException { |
| JellyContext theContext = getJellyContext(); |
| Properties props = new Properties(); |
| props.load(is); |
| Enumeration propsEnum = props.propertyNames(); |
| while (propsEnum.hasMoreElements()) { |
| String key = (String) propsEnum.nextElement(); |
| String value = props.getProperty(key); |
| |
| // @todo we should parse the value in case its an Expression |
| theContext.setVariable(key, value); |
| } |
| } |
| } |