package org.apache.maven.jelly;
/* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
* ====================================================================
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Iterator;
import javax.xml.parsers.SAXParserFactory;
import org.apache.commons.jelly.JellyContext;
import org.apache.commons.jelly.Script;
import org.apache.commons.jelly.XMLOutput;
import org.apache.commons.jelly.expression.CompositeExpression;
import org.apache.commons.jelly.expression.Expression;
import org.apache.commons.jelly.parser.XMLParser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
/**
* Utilities for Jelly.
*
* @see <a href="http://jakarta.apache.org/commons/jelly/">
* commons-jelly</a>
* @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
* @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
* @version $Id: JellyUtils.java 517014 2007-03-11 21:15:50Z ltheussl $
*/
public class JellyUtils
{
/**
* Logger
*/
private static final Log LOGGER = LogFactory.getLog( JellyUtils.class );
/** Maven Expression Factory. */
private static MavenExpressionFactory mavenExpressionFactory = new MavenExpressionFactory();
/**
* Run a jelly script.
*
* @param scriptInputStream Script input stream.
* @param rootUrl Root explicit context of the script.
* @param context Jelly context.
* @param output Output sink.
* @throws Exception If an error occurs while locating, compiling or
* executing the script.
*/
public static void runScript( InputStream scriptInputStream, URL rootUrl, JellyContext context, XMLOutput output )
throws Exception
{
runScript( scriptInputStream, null, rootUrl, context, output );
}
/**
* Run a jelly script.
*
* @param scriptInputStream Script input stream.
* @param systemId the system identifier to help resolve relative URLs
* @param rootUrl Root explicit context of the script.
* @param context Jelly context.
* @param output Output sink.
* @throws Exception If an error occurs while locating, compiling or
* executing the script.
*/
public static void runScript( InputStream scriptInputStream, String systemId, URL rootUrl, JellyContext context,
XMLOutput output )
throws Exception
{
URL oldRoot = context.getRootURL();
URL oldCurrent = context.getCurrentURL();
if ( rootUrl != null )
{
context.setRootURL( rootUrl );
context.setCurrentURL( rootUrl );
}
Script script = compileScript( scriptInputStream, systemId, context );
script.run( context, output );
context.setRootURL( oldRoot );
context.setCurrentURL( oldCurrent );
}
/**
* Run a jelly script.
*
* @param scriptFile Location of the script to run.
* @param rootUrl Root explicit context of the script.
* @param context Jelly context.
* @param output Output sink.
* @throws Exception If an error occurs while locating, compiling or
* executing the script.
*/
public static void runScript( File scriptFile, URL rootUrl, JellyContext context, XMLOutput output )
throws Exception
{
if ( !scriptFile.canRead() || ( scriptFile.length() < 1 ) )
{
return;
}
FileInputStream fis = null;
try
{
fis = new FileInputStream( scriptFile );
runScript( fis, scriptFile.toURL().toString(), rootUrl, context, output );
}
finally
{
if ( fis != null )
{
try
{
fis.close();
}
catch ( IOException e )
{
LOGGER.debug( "WARNING: Cannot close stream!", e );
}
fis = null;
}
}
}
/**
* Compile a jelly script.
*
* @param scriptFile Location of the script to run.
* @param context Jelly context.
* @throws Exception If an error occurs while locating or compiling the
* script.
* @return The compiled script.
*/
public static Script compileScript( File scriptFile, JellyContext context )
throws Exception
{
FileInputStream fis = null;
Script result = null;
try
{
fis = new FileInputStream( scriptFile );
result = compileScript( fis, scriptFile.toURL().toString(), context );
}
finally
{
if ( fis != null )
{
try
{
fis.close();
}
catch ( IOException e )
{
LOGGER.debug( "WARNING: Cannot close stream!", e );
}
fis = null;
}
}
return result;
}
/**
* Compile a jelly script.
*
* @param scriptInputStream Script input stream.
* @param context Jelly context.
* @throws Exception If an error occurs while locating or compiling the
* script.
* @return The compiled script.
*/
public static Script compileScript( InputStream scriptInputStream, JellyContext context )
throws Exception
{
return compileScript( scriptInputStream, null, context, null );
}
/**
* Compile a jelly script.
*
* @param scriptInputStream Script input stream.
* @param systemId the system identifier to help resolve relative URLs
* @param context Jelly context.
* @throws Exception If an error occurs while locating or compiling the
* script.
* @return The compiled script.
*/
public static Script compileScript( InputStream scriptInputStream, String systemId, JellyContext context )
throws Exception
{
return compileScript( scriptInputStream, systemId, context, null );
}
/**
* Compile a jelly script.
*
* @param scriptInputStream Script input stream.
* @param systemId the system identifier to help resolve relative URLs
* @param context Jelly context.
* @param encoding To use when reading XML.
* @throws Exception If an error occurs while locating or compiling the
* script.
* @return The compiled script.
* @todo throw something else
*/
public static Script compileScript( InputStream scriptInputStream, String systemId, JellyContext context,
String encoding )
throws Exception
{
// FIXME: This should all be done by Jelly.
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware( true );
XMLReader reader = factory.newSAXParser().getXMLReader();
XMLParser parser = new XMLParser( reader );
parser.setContext( context );
parser.setClassLoader( context.getClassLoader() );
Script script = null;
InputSource source = null;
if ( encoding != null )
{
InputStreamReader isr = null;
try
{
isr = new InputStreamReader( scriptInputStream, encoding );
source = new InputSource( isr );
}
finally
{
if ( isr != null )
{
try
{
isr.close();
}
catch ( IOException e )
{
LOGGER.debug( "WARNING: Cannot close stream!", e );
}
isr = null;
}
}
}
else
{
source = new InputSource( scriptInputStream );
}
if ( systemId != null )
{
source.setSystemId( systemId );
}
if ( LOGGER.isDebugEnabled() )
{
LOGGER.debug( "the system identifier to help resolve relative URLs : " + systemId );
}
script = parser.parse( source );
script = script.compile();
return script;
}
/**
* Recursively evaluate a string representation of a jelly expression.
*
* @param text String representation of the a Jelly expression.
* @param context The Jelly context to compute the expression against.
*
* @return The recursively evaluated Jelly expression.
*/
public static Expression decomposeExpression( String text, JellyContext context )
{
Expression expression = null;
try
{
expression = CompositeExpression.parse( text, mavenExpressionFactory );
String expressionText = expression.evaluateAsString( context );
if ( CompositeExpression.parse( expressionText, mavenExpressionFactory ) instanceof CompositeExpression )
{
expression = decomposeExpression( expressionText, context );
}
}
catch ( Exception e )
{
// do nothing.
}
return expression;
}
/**
* Debugging function to show the differences between two Jelly contexts.
* @param ctx1 first context
* @param ctx2 second context
*/
public static void compareContexts( MavenJellyContext ctx1, MavenJellyContext ctx2 )
{
System.out.println( "======== compare contexts ========" );
for ( Iterator i = ctx1.getVariableNames(); i.hasNext(); )
{
String name = (String) i.next();
if ( ctx2.getVariable( name ) == null )
{
System.out.println( name + " not in ctx2" );
}
else
{
if ( !ctx2.getVariable( name ).equals( ctx1.getVariable( name ) ) )
{
System.out.println( name + " doesn't match: '" + ctx1.getVariable( name ) + "' vs '"
+ ctx2.getVariable( name ) + "'" );
}
}
}
System.out.println( "======== comparison done ========" );
}
/**
* Populate a context with variables, including parent variables if inheritance is enabled.
*
* @param destContext the destination context
* @param sourceContext the source context
*/
public static void populateVariables( JellyContext destContext, JellyContext sourceContext )
{
if ( sourceContext != null )
{
if ( !"false".equals( sourceContext.getVariable( "maven.property.inheritance" ) )
&& ( !"false".equals( destContext.getVariable( "maven.property.inheritance" ) ) ) )
{
populateVariables( destContext, sourceContext.isInherit() ? sourceContext.getParent() : null );
}
destContext.getVariables().putAll( sourceContext.getVariables() );
}
destContext.setVariable( "context", destContext );
}
}