View Javadoc

1   package org.apache.maven.jelly;
2   
3   /* ====================================================================
4    *   Licensed to the Apache Software Foundation (ASF) under one or more
5    *   contributor license agreements.  See the NOTICE file distributed with
6    *   this work for additional information regarding copyright ownership.
7    *   The ASF licenses this file to You under the Apache License, Version 2.0
8    *   (the "License"); you may not use this file except in compliance with
9    *   the License.  You may obtain a copy of the License at
10   *
11   *       http://www.apache.org/licenses/LICENSE-2.0
12   *
13   *   Unless required by applicable law or agreed to in writing, software
14   *   distributed under the License is distributed on an "AS IS" BASIS,
15   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   *   See the License for the specific language governing permissions and
17   *   limitations under the License.
18   * ====================================================================
19   */
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.InputStreamReader;
26  import java.net.URL;
27  import java.util.Iterator;
28  
29  import javax.xml.parsers.SAXParserFactory;
30  
31  import org.apache.commons.jelly.JellyContext;
32  import org.apache.commons.jelly.Script;
33  import org.apache.commons.jelly.XMLOutput;
34  import org.apache.commons.jelly.expression.CompositeExpression;
35  import org.apache.commons.jelly.expression.Expression;
36  import org.apache.commons.jelly.parser.XMLParser;
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.xml.sax.InputSource;
40  import org.xml.sax.XMLReader;
41  
42  /**
43   * Utilities for Jelly.
44   *
45   * @see <a href="http://commons.apache.org/jelly/">
46   *      commons-jelly</a>
47   * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
48   * @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
49   * @version $Id: JellyUtils.java 517014 2007-03-11 21:15:50Z ltheussl $
50   */
51  public class JellyUtils
52  {
53      /**
54       * Logger
55       */
56      private static final Log LOGGER = LogFactory.getLog( JellyUtils.class );
57  
58      /** Maven Expression Factory. */
59      private static MavenExpressionFactory mavenExpressionFactory = new MavenExpressionFactory();
60  
61      /**
62       * Run a jelly script.
63       *
64       * @param scriptInputStream Script input stream.
65       * @param rootUrl Root explicit context of the script.
66       * @param context Jelly context.
67       * @param output Output sink.
68       * @throws Exception If an error occurs while locating, compiling or
69       *      executing the script.
70       */
71      public static void runScript( InputStream scriptInputStream, URL rootUrl, JellyContext context, XMLOutput output )
72          throws Exception
73      {
74          runScript( scriptInputStream, null, rootUrl, context, output );
75      }
76  
77      /**
78       * Run a jelly script.
79       *
80       * @param scriptInputStream Script input stream.
81       * @param systemId the system identifier to help resolve relative URLs
82       * @param rootUrl Root explicit context of the script.
83       * @param context Jelly context.
84       * @param output Output sink.
85       * @throws Exception If an error occurs while locating, compiling or
86       *      executing the script.
87       */
88      public static void runScript( InputStream scriptInputStream, String systemId, URL rootUrl, JellyContext context,
89                                    XMLOutput output )
90          throws Exception
91      {
92          URL oldRoot = context.getRootURL();
93          URL oldCurrent = context.getCurrentURL();
94  
95          if ( rootUrl != null )
96          {
97              context.setRootURL( rootUrl );
98              context.setCurrentURL( rootUrl );
99          }
100 
101         Script script = compileScript( scriptInputStream, systemId, context );
102         script.run( context, output );
103 
104         context.setRootURL( oldRoot );
105         context.setCurrentURL( oldCurrent );
106     }
107 
108     /**
109      * Run a jelly script.
110      *
111      * @param scriptFile Location of the script to run.
112      * @param rootUrl Root explicit context of the script.
113      * @param context Jelly context.
114      * @param output Output sink.
115      * @throws Exception If an error occurs while locating, compiling or
116      *      executing the script.
117      */
118     public static void runScript( File scriptFile, URL rootUrl, JellyContext context, XMLOutput output )
119         throws Exception
120     {
121         if ( !scriptFile.canRead() || ( scriptFile.length() < 1 ) )
122         {
123             return;
124         }
125         FileInputStream fis = null;
126         try
127         {
128             fis = new FileInputStream( scriptFile );
129             runScript( fis, scriptFile.toURL().toString(), rootUrl, context, output );
130         }
131         finally
132         {
133             if ( fis != null )
134             {
135                 try
136                 {
137                     fis.close();
138                 }
139                 catch ( IOException e )
140                 {
141                     LOGGER.debug( "WARNING: Cannot close stream!", e );
142                 }
143                 fis = null;
144             }
145 
146         }
147     }
148 
149     /**
150      * Compile a jelly script.
151      *
152      * @param scriptFile Location of the script to run.
153      * @param context Jelly context.
154      * @throws Exception If an error occurs while locating or compiling the
155      *      script.
156      * @return The compiled script.
157      */
158     public static Script compileScript( File scriptFile, JellyContext context )
159         throws Exception
160     {
161         FileInputStream fis = null;
162         Script result = null;
163         try
164         {
165             fis = new FileInputStream( scriptFile );
166             result = compileScript( fis, scriptFile.toURL().toString(), context );
167         }
168         finally
169         {
170             if ( fis != null )
171             {
172                 try
173                 {
174                     fis.close();
175                 }
176                 catch ( IOException e )
177                 {
178                     LOGGER.debug( "WARNING: Cannot close stream!", e );
179                 }
180                 fis = null;
181             }
182         }
183         return result;
184     }
185 
186     /**
187      * Compile a jelly script.
188      *
189      * @param scriptInputStream Script input stream.
190      * @param context Jelly context.
191      * @throws Exception If an error occurs while locating or compiling the
192      *      script.
193      * @return The compiled script.
194      */
195     public static Script compileScript( InputStream scriptInputStream, JellyContext context )
196         throws Exception
197     {
198         return compileScript( scriptInputStream, null, context, null );
199     }
200 
201     /**
202      * Compile a jelly script.
203      *
204      * @param scriptInputStream Script input stream.
205      * @param systemId the system identifier to help resolve relative URLs
206      * @param context Jelly context.
207      * @throws Exception If an error occurs while locating or compiling the
208      *      script.
209      * @return The compiled script.
210      */
211     public static Script compileScript( InputStream scriptInputStream, String systemId, JellyContext context )
212         throws Exception
213     {
214         return compileScript( scriptInputStream, systemId, context, null );
215     }
216 
217     /**
218      * Compile a jelly script.
219      *
220      * @param scriptInputStream Script input stream.
221      * @param systemId the system identifier to help resolve relative URLs
222      * @param context Jelly context.
223      * @param encoding To use when reading XML.
224      * @throws Exception If an error occurs while locating or compiling the
225      *      script.
226      * @return The compiled script.
227      * @todo throw something else
228      */
229     public static Script compileScript( InputStream scriptInputStream, String systemId, JellyContext context,
230                                         String encoding )
231         throws Exception
232     {
233         // FIXME: This should all be done by Jelly.
234         SAXParserFactory factory = SAXParserFactory.newInstance();
235         factory.setNamespaceAware( true );
236         XMLReader reader = factory.newSAXParser().getXMLReader();
237         XMLParser parser = new XMLParser( reader );
238         parser.setContext( context );
239         parser.setClassLoader( context.getClassLoader() );
240 
241         Script script = null;
242 
243         InputSource source = null;
244         if ( encoding != null )
245         {
246             InputStreamReader isr = null;
247             try
248             {
249                 isr = new InputStreamReader( scriptInputStream, encoding );
250                 source = new InputSource( isr );
251 
252             }
253             finally
254             {
255                 if ( isr != null )
256                 {
257                     try
258                     {
259                         isr.close();
260                     }
261                     catch ( IOException e )
262                     {
263                         LOGGER.debug( "WARNING: Cannot close stream!", e );
264                     }
265                     isr = null;
266                 }
267             }
268 
269         }
270         else
271         {
272             source = new InputSource( scriptInputStream );
273         }
274 
275         if ( systemId != null )
276         {
277             source.setSystemId( systemId );
278         }
279         if ( LOGGER.isDebugEnabled() )
280         {
281             LOGGER.debug( "the system identifier to help resolve relative URLs : " + systemId );
282         }
283         script = parser.parse( source );
284 
285         script = script.compile();
286 
287         return script;
288     }
289 
290     /**
291      * Recursively evaluate a string representation of a jelly expression.
292      *
293      * @param text String representation of the a Jelly expression.
294      * @param context The Jelly context to compute the expression against.
295      *
296      * @return The recursively evaluated Jelly expression.
297      */
298     public static Expression decomposeExpression( String text, JellyContext context )
299     {
300         Expression expression = null;
301 
302         try
303         {
304             expression = CompositeExpression.parse( text, mavenExpressionFactory );
305 
306             String expressionText = expression.evaluateAsString( context );
307 
308             if ( CompositeExpression.parse( expressionText, mavenExpressionFactory ) instanceof CompositeExpression )
309             {
310                 expression = decomposeExpression( expressionText, context );
311             }
312         }
313         catch ( Exception e )
314         {
315             // do nothing.
316         }
317 
318         return expression;
319     }
320 
321     /**
322      * Debugging function to show the differences between two Jelly contexts.
323      * @param ctx1 first context
324      * @param ctx2 second context
325      */
326     public static void compareContexts( MavenJellyContext ctx1, MavenJellyContext ctx2 )
327     {
328         System.out.println( "======== compare contexts ========" );
329         for ( Iterator i = ctx1.getVariableNames(); i.hasNext(); )
330         {
331             String name = (String) i.next();
332             if ( ctx2.getVariable( name ) == null )
333             {
334                 System.out.println( name + " not in ctx2" );
335             }
336             else
337             {
338                 if ( !ctx2.getVariable( name ).equals( ctx1.getVariable( name ) ) )
339                 {
340                     System.out.println( name + " doesn't match: '" + ctx1.getVariable( name ) + "' vs '"
341                         + ctx2.getVariable( name ) + "'" );
342                 }
343             }
344         }
345         System.out.println( "======== comparison  done ========" );
346     }
347 
348     /**
349      * Populate a context with variables, including parent variables if inheritance is enabled.
350      *
351      * @param destContext the destination context
352      * @param sourceContext the source context
353      */
354     public static void populateVariables( JellyContext destContext, JellyContext sourceContext )
355     {
356         if ( sourceContext != null )
357         {
358             if ( !"false".equals( sourceContext.getVariable( "maven.property.inheritance" ) )
359                 && ( !"false".equals( destContext.getVariable( "maven.property.inheritance" ) ) ) )
360             {
361                 populateVariables( destContext, sourceContext.isInherit() ? sourceContext.getParent() : null );
362             }
363             destContext.getVariables().putAll( sourceContext.getVariables() );
364         }
365         destContext.setVariable( "context", destContext );
366     }
367 }