1 package org.apache.maven.jelly;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
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 }