##### Coverage Report - org.webmacro.directive.IncludeDirective

Classes in this File | Line Coverage | Branch Coverage | Complexity
IncludeDirective |
2% | 3/124
0% | 0/69
| 6.384615384615385;6.385

1 |  |
     /*
2 |  |
      * Copyright (C) 1998-2000 Semiotek Inc.  All Rights Reserved.
3 |  |
      *
4 |  |
      * Redistribution and use in source and binary forms, with or without
5 |  |
      * modification, are permitted under the terms of either of the following
6 |  |
      * Open Source licenses:
7 |  |
      *
8 |  |
      * The GNU General Public License, version 2, or any later version, as
9 |  |
      * published by the Free Software Foundation
10 |  |
      * (http://www.fsf.org/copyleft/gpl.html);
11 |  |
      *
12 |  |
      *  or
13 |  |
      *
14 |  |
      * The Semiotek Public License (http://webmacro.org/LICENSE.)
15 |  |
      *
16 |  |
      * This software is provided "as is", with NO WARRANTY, not even the
17 |  |
      * implied warranties of fitness to purpose, or merchantability. You
18 |  |
      * assume all risks and liabilities associated with its use.
19 |  |
      *
20 |  |
      * See www.webmacro.org for more information on the WebMacro project.
21 |  |
      */
22 |  |
23 |  |
     package org.webmacro.directive;
24 |  |
25 |  |
     import java.io.IOException;
26 |  |
     import java.io.InputStream;
27 |  |
     import java.net.URL;
28 |  |
     import java.net.URLConnection;
29 |  |
     import java.util.StringTokenizer;
30 |  |
31 |  |
     import org.slf4j.Logger;
32 |  |
33 |  |
     import org.webmacro.Broker;
34 |  |
     import org.webmacro.Context;
35 |  |
     import org.webmacro.FastWriter;
36 |  |
     import org.webmacro.Macro;
37 |  |
     import org.webmacro.NotFoundException;
38 |  |
     import org.webmacro.PropertyException;
39 |  |
     import org.webmacro.ResourceException;
40 |  |
     import org.webmacro.Template;
41 |  |
     import org.webmacro.TemplateVisitor;
42 |  |
     import org.webmacro.engine.BuildContext;
43 |  |
     import org.webmacro.engine.BuildException;
44 |  |
45 |  |
     /**
46 |  |
      * IncludeDirective allows you to include other text files or Templates into
47 |  |
      * the current Template.
48 |  |
      * <p>
49 |  |
      * Syntax:<pre>
50 |  |
      *    #include [as text|template|macro] quoted-string-variable
51 |  |
      *</pre>
52 |  |
      *
53 |  |
      * <code>IncludeDirective</code> has 4 modes of operation which are detailed
54 |  |
      * below.<p>
55 |  |
      *
56 |  |
      * Please note that #include is now the preferred way to include files or
57 |  |
      * templates.  Although you can still use #parse (in the same manner as
58 |  |
      * described below), its use has been deprecated.<p>
59 |  |
      *
60 |  |
      * <b>Including as text</b><br>
61 |  |
      * Including a file as text causes the raw bytes of the file to be included
62 |  |
      * in the current template.  The file is <b>not</b> considered to be a Template,
63 |  |
      * and is not parsed by WebMacro.  This allows you to include external files
64 |  |
      * that contain javascript or stylesheets without fear of mangling by WebMacro's
65 |  |
      * parser.<p>
66 |  |
      *
67 |  |
      * Files included as text are found using the default <code>URLProvider</code>.
68 |  |
      * If the URLProvider cannot find the file, the Broker is asked to find it.
69 |  |
      * This allows you to include files from any of the following places:
70 |  |
      * <li>other websites
71 |  |
      * <li>local filesystem
72 |  |
      * <li>active classpath<p>
73 |  |
      *
74 |  |
      * Files included as text are located once.  Changes to the included file
75 |  |
      * will not be found by WebMacro!<p>
76 |  |
      *
77 |  |
      * Examples:<pre>
78 |  |
      *
79 |  |
      *   // include your system password file (not a good idea! :)
80 |  |
      *   #include as text "/etc/password"
81 |  |
      *
82 |  |
      *   // include the WebMacro homepage
83 |  |
      *   #include as text "http://www.webmacro.org"
84 |  |
      *
85 |  |
      *   // inlude a file that is in your classpath
86 |  |
      *   #include as text "somefile.txt"
87 |  |
      *
88 |  |
      * </pre><br>
89 |  |
      *
90 |  |
      * <b>Including as template</b><br>
91 |  |
      * Including a file as template causes the file to be parsed and evaluated
92 |  |
      * by WebMacro using the current <code>Context</code>.  The evaluated output of
93 |  |
      * the Template is included in your main template.<p>
94 |  |
      *
95 |  |
      * Please note that files included "as template" that contains #macro's <b>DO NOT</b>
96 |  |
      * make their #macro's available to the outer template.  See "Including as macro" below
97 |  |
      * for this.<p>
98 |  |
      *
99 |  |
      * Files included as template are found in your <code>TemplatePath</code>.
100 |  |
      * This path, if not explicitly set in <code>WebMacro.properties</code>, defaults
101 |  |
      * to the system classpath (standalone and JSDK 1.0), or the "web-app" directory
102 |  |
      * (JSDK 2.x).<p>
103 |  |
      *
104 |  |
      * Files included as templates are located and conditionally reloaded/parsed when
105 |  |
      * they change.<p>
106 |  |
      *
107 |  |
      * Examples:<pre>
108 |  |
      *
109 |  |
      *   // include a global header template
110 |  |
      *   #include as template "header.wm"
111 |  |
      *
112 |  |
      *   // include a header template from a subdirectory of your TemplatePath
113 |  |
      *   #include as template "common/header.wm"
114 |  |
      *
115 |  |
      *   // include a header template using an absolute path in your TemplatePath
116 |  |
      *   #include as template "/mysite/common/header.wm"
117 |  |
      *
118 |  |
      * </pre><br>
119 |  |
      *
120 |  |
      * <b>Including as macro</b><br>
121 |  |
      * Including a file as a macro is similiar to the above, except that #macro's
122 |  |
      * defined in the included file <b>are</b> made available to the outer template.
123 |  |
      * "Macro" templates are found using the same TemplatePath settings as
124 |  |
      * "#include as template".<p>
125 |  |
      *
126 |  |
      * Files included as macros are located once.  Changes to the included template
127 |  |
      * will not be found by WebMacro!<p>
128 |  |
      *
129 |  |
      * Exapmles:<pre>
130 |  |
      *
131 |  |
      *   // include a template with macros
132 |  |
      *   #include as macro "my_macros.wm"
133 |  |
      *
134 |  |
      * </pre><br>
135 |  |
      *
136 |  |
      *
137 |  |
      * <b>Including without qualification</b><br></a>
138 |  |
      * Including a file without first qualifing it as a <i>text</i> file or
139 |  |
      * <i>template</i> causes <code>IncludeDirective</code> to make some educated
140 |  |
      * guesses about what type of file it is.<p>
141 |  |
      *
142 |  |
      * If the filename contains <code>://</code>, it is assumed to be a URL and is
143 |  |
      * treated as if it were a <code>text</code> file.<p>
144 |  |
      *
145 |  |
      * Else if the filename ends with any of the configured template file extensions
146 |  |
      * (see below), it is assumed to be a template.<p>
147 |  |
      *
148 |  |
      * Else it is assumed to be <code>text</code>.<p>
149 |  |
      *
150 |  |
      * Examples:<pre>
151 |  |
      *
152 |  |
      *    // include homepage of WebMacro -- assumed to be "as text"
153 |  |
      *    #include "http://www.webmacro.org/"
154 |  |
      *
155 |  |
      *    // include a template -- assumed to be "as template"
156 |  |
      *    #include "header.wm"
157 |  |
      *
158 |  |
      *    // include a text file from local filesystem -- assumed to be "as text"
159 |  |
      *    #include "somefile.txt"
160 |  |
      *
161 |  |
      * </pre>
162 |  |
      *
163 |  |
      *
164 |  |
      * <b><code>WebMacro.properties</code> Configuration Options</b><br>
165 |  |
      *
166 |  |
      * <code>include.TemplateExtensions</code>: list of file extensions<br>
167 |  |
      * This list of file extensions is used to determine the file type of an
168 |  |
      * unqualified #include'd file.<p>
169 |  |
      *
170 |  |
      * The default set of extensions are: <code>wm, wmt, tml</code>
171 |  |
      *
172 |  |
      * @author <a href=mailto:ebr@tcdi.com>Eric B. Ridge</a>
173 |  |
      * @since the beginning, but consolidated with #parse post 0.97
174 |  |
      *
175 |  |
      */
176 | 0 |
     public class IncludeDirective extends Directive
177 |  |
     {
178 |  |
179 |  |
         /** The file to include is a Template. */
180 |  |
         public static final int TYPE_TEMPLATE = 0;
181 |  |
         /** The file to include as a Template containing #macro's. */
182 |  |
         public static final int TYPE_MACRO = 1;
183 |  |
         /** The file to include is a static file. */
184 |  |
         public static final int TYPE_TEXT = 2;
185 |  |
         /** The file to include is unknown. */
186 |  |
         public static final int TYPE_DYNAMIC = 3;
187 |  |
188 |  |
189 |  |
         private static final int PARSE_AS_K = 1;
190 |  |
         private static final int PARSE_TEMPLATE_K = 2;
191 |  |
         private static final int PARSE_TEXT_K = 3;
192 |  |
         private static final int PARSE_MACRO_K = 4;
193 |  |
         private static final int PARSE_FILENAME = 5;
194 |  |
195 | 2 |
         private static final ArgDescriptor[] _args = new ArgDescriptor[]{
196 |  |
             new OptionalGroup(4),
197 |  |
             new KeywordArg(PARSE_AS_K, "as"),
198 |  |
             new OptionalGroup(1),
199 |  |
             new KeywordArg(PARSE_TEMPLATE_K, "template"),
200 |  |
             new OptionalGroup(1),
201 |  |
             new KeywordArg(PARSE_TEXT_K, "text"),
202 |  |
             new OptionalGroup(1),
203 |  |
             new KeywordArg(PARSE_MACRO_K, "macro"),
204 |  |
             new QuotedStringArg(PARSE_FILENAME),
205 |  |
         };
206 | 2 |
         private static final DirectiveDescriptor _desc = new DirectiveDescriptor("include", null, _args, null);
207 |  |
208 |  |
         public static DirectiveDescriptor getDescriptor ()
209 |  |
         {
210 | 12 |
             return _desc;
211 |  |
         }
212 |  |
213 |  |
214 |  |
         //
215 |  |
         // these values are customized for this directive during build()
216 |  |
         //
217 |  |
218 |  |
         /** Place holder for the TemplateExtensions configuration key name. */
219 | 0 |
         private String TEMPLATE_EXTENSIONS_NAME = ".TemplateExtensions";
220 |  |
221 |  |
222 |  |
         /** Logging can be good */
223 |  |
         protected Logger _log;
224 |  |
         /** The included file type.
225 |  |
          * One of TYPE_TEMPLATE, TYPE_STATIC, TYPE_MACRO, or TYPE_DYNAMIC. */
226 |  |
         protected int _type;
227 |  |
         /** The filename as a Macro, if the filename arg is a Macro. */
228 |  |
         protected Macro _macFilename;
229 |  |
         /**
230 |  |
          * The filename as a String, if it is something we can determine during
231 |  |
          * build().
232 |  |
          */
233 |  |
         protected String _strFilename;
234 |  |
         /**
235 |  |
          * The name given to the directive by webmacro configuration.  Used in
236 |  |
          * conjuction with the <code>StrictCompatibility</code>  configuration
237 |  |
          * and to make determinitaions on how the #included file should be included.
238 |  |
          */
239 |  |
         protected String _directiveName;
240 |  |
241 |  |
         /**
242 |  |
          * Build this use of the directive.<p>
243 |  |
          *
244 |  |
          * The specified file to include is included during <b>build/parse</b>
245 |  |
          * time if:<br>
246 |  |
          *    1) The specified filename is a String, not a $Variable; and<br>
247 |  |
          *    2) The "as" keyword is <b>"macro"</b>; or<br>
248 |  |
          *    3) if the <code>Lazy</code> configuration option is set for
249 |  |
          *       this directive.<p>
250 |  |
          *
251 |  |
          * Otherwise, template is found and including during runtime evaluation
252 |  |
          * of this directive.
253 |  |
          */
254 |  |
         public final Object build (DirectiveBuilder builder, BuildContext bc)
255 |  |
             throws BuildException
256 |  |
         {
257 | 0 |
             Broker broker = bc.getBroker();
258 | 0 |
             _log = bc.getLog("IncludeDirective");
259 |  |
             // build configuration key names, since they're based
260 |  |
             // on the configured name of this directive
261 | 0 |
             _directiveName = builder.getName();
262 | 0 |
             TEMPLATE_EXTENSIONS_NAME = _directiveName + TEMPLATE_EXTENSIONS_NAME;
263 |  |
264 |  |
             // determine what type of file we need to deal with
265 | 0 |
             if (builder.getArg(PARSE_TEXT_K, bc) != null)
266 |  |
             {
267 | 0 |
                 _type = TYPE_TEXT;
268 |  |
             }
269 | 0 |
             else if (builder.getArg(PARSE_TEMPLATE_K, bc) != null)
270 |  |
             {
271 | 0 |
                 _type = TYPE_TEMPLATE;
272 |  |
             }
273 | 0 |
             else if (builder.getArg(PARSE_MACRO_K, bc) != null)
274 |  |
             {
275 | 0 |
                 _type = TYPE_MACRO;
276 |  |
             }
277 |  |
             else
278 |  |
             {
279 | 0 |
                 _type = TYPE_DYNAMIC;
280 |  |
             }
281 |  |
282 |  |
283 |  |
             // if the filename passed to us was a Macro (needs to be evaluated later)
284 |  |
             // then store it as _macFilename.  Otherwise, assume it's a String
285 |  |
             // and we'll just use that string as the filename
286 | 0 |
             Object o = builder.getArg(PARSE_FILENAME, bc);
287 | 0 |
             if (o instanceof Macro)
288 |  |
             {
289 | 0 |
                 if (_type == TYPE_TEXT || _type == TYPE_MACRO)
290 |  |
                 {
291 | 0 |
                     _log.warn("Included a 'static' file type using a dynamic filename. "
292 |  |
                             + "File will be included, but any included #macro's will not at " + bc.getCurrentLocation());
293 |  |
                 }
294 | 0 |
                 _macFilename = (Macro) o;
295 |  |
             }
296 |  |
             else
297 |  |
             {
298 | 0 |
                 _strFilename = o.toString();
299 | 0 |
                 if (_strFilename == null || _strFilename.length() == 0)
300 | 0 |
                     throw makeBuildException("Filename cannot be null or empty");
301 |  |
302 |  |
303 | 0 |
                 if (_type == TYPE_TEXT)
304 |  |
                 {
305 |  |
                     // we're a static type, need to
306 |  |
                     // include the file (by returning it) now,
307 |  |
                     // during build time
308 |  |
                     try
309 |  |
                     {
310 | 0 |
                         return getThingToInclude(broker, _type, _strFilename);
311 |  |
                     }
312 | 0 |
                     catch (Exception e)
313 |  |
                     {
314 | 0 |
                         throw makeBuildException("Unable to include as text", e);
315 |  |
                     }
316 |  |
                 }
317 | 0 |
                 else if (_type == TYPE_MACRO)
318 |  |
                 {
319 |  |
                     // we're a template type.  ned to get the template (already parsed)
320 |  |
                     // and merge its macros into our build context.
321 |  |
                     // then we return the template so its contents can also be included
322 | 0 |
                     Template t = null;
323 |  |
                     try
324 |  |
                     {
325 | 0 |
                         t = getTemplate(broker, _strFilename);
326 | 0 |
                         bc.mergeConstants(t);
327 |  |
                     }
328 | 0 |
                     catch (Exception e)
329 |  |
                     {
330 | 0 |
                         throw makeBuildException("Unable to include as macro", e);
331 | 0 |
                     }
332 |  |
                     try {
333 | 0 |
                         return t.evaluateAsString(bc);
334 |  |
                     }
335 | 0 |
                     catch (PropertyException e) {
336 | 0 |
                         return "";
337 |  |
                     }
338 |  |
                 }
339 | 0 |
                 else if (_type == TYPE_DYNAMIC)
340 |  |
                 {
341 |  |
                     // being dynamic means we need to guess the
342 |  |
                     // file type based on the file's extension
343 |  |
                     // and take care of finding the file during runtime
344 | 0 |
                     _type = guessType(broker, _strFilename);
345 |  |
                 }
346 |  |
347 |  |
             }
348 |  |
349 |  |
             // we are configured to be lazy, or we couldn't determine the filename
350 |  |
             // during the build() process (b/c it is a Macro)
351 | 0 |
             return this;
352 |  |
         }
353 |  |
354 |  |
         /**
355 |  |
          * Write out the included file to the specified FastWriter.  If the
356 |  |
          * included file is actually a template, it is evaluated against the
357 |  |
          * <code>context</code> parameter before being written to the FastWriter
358 |  |
          */
359 |  |
         public void write (FastWriter out, Context context)
360 |  |
             throws PropertyException, IOException
361 |  |
         {
362 | 0 |
             Broker broker = context.getBroker();
363 |  |
364 |  |
             // the filename arg passed to us was a Macro, so
365 |  |
             // evaluate and check it now
366 | 0 |
             if (_macFilename != null)
367 |  |
             {
368 | 0 |
                 _strFilename = _macFilename.evaluate(context).toString();
369 | 0 |
                 if (_strFilename == null || _strFilename.length() == 0)
370 |  |
                 {
371 | 0 |
                     throw makePropertyException("Filename cannot be null or empty");
372 |  |
                 }
373 |  |
             }
374 |  |
375 | 0 |
             if (_log.isDebugEnabled() && context.getCurrentLocation().indexOf(_strFilename) > -1)
376 |  |
             {
377 |  |
                 // when in debug mode, output a warning if a template tries to include itself
378 |  |
                 // there are situations where this is desired, but it's good to make
379 |  |
                 // the user aware of what they're doing
380 | 0 |
                 _log.warn(context.getCurrentLocation() + " includes itself.");
381 |  |
             }
382 |  |
383 |  |
             // this should only be true if StrictCompatibility is set to false
384 |  |
             // and "as <something>" wasn't specified in the arg list
385 | 0 |
             if (_type == TYPE_DYNAMIC)
386 | 0 |
                 _type = guessType(broker, _strFilename);
387 |  |
388 | 0 |
             _log.debug("Including '" + _strFilename + "' as "
389 |  |
                         + ((_type == TYPE_MACRO) ? "MACRO"
390 |  |
                         : (_type == TYPE_TEMPLATE) ? "TEMPLATE"
391 |  |
                         : (_type == TYPE_TEXT) ? "TEXT"
392 |  |
                         : "UNKNOWN.  Throwing exception"));
393 |  |
394 | 0 |
             Object toInclude = getThingToInclude(broker, _type, _strFilename);
395 | 0 |
             switch (_type)
396 |  |
             {
397 |  |
                 case TYPE_MACRO:
398 |  |
                     // during runtime evaluation of a template,
399 |  |
                     // a TYPE_MACRO doesn't really work as expected.
400 |  |
                     // we logged a warning above in build(), but
401 |  |
                     // we still need to write it out as a template
402 |  |
                     // so just fall through
403 |  |
                 case TYPE_TEMPLATE:
404 | 0 |
                     ((Template) toInclude).write(out, context);
405 | 0 |
                     break;
406 |  |
407 |  |
                 case TYPE_TEXT:
408 |  |
                     // static types are strings
409 | 0 |
                     out.write(toInclude.toString());
410 | 0 |
                     break;
411 |  |
412 |  |
                 default:
413 |  |
                     // should never happen
414 | 0 |
                     throw makePropertyException("Unrecognized file type: " + _type);
415 |  |
             }
416 | 0 |
         }
417 |  |
418 |  |
         /**
419 |  |
          * Get an array of Template file extensions we should use, if type==dynamic,
420 |  |
          * to decide if the specified file is a template or not.
421 |  |
          */
422 |  |
         protected String[] getTemplateExtensions (Broker b)
423 |  |
         {
424 | 0 |
             String[] ret = (String[]) b.getBrokerLocal(TEMPLATE_EXTENSIONS_NAME);
425 |  |
426 | 0 |
             if (ret == null)
427 |  |
             {
428 | 0 |
                 String prop = b.getSettings().getSetting(TEMPLATE_EXTENSIONS_NAME, "wm");
429 | 0 |
                 StringTokenizer st = new StringTokenizer(prop, ",; ");
430 | 0 |
                 ret = new String[st.countTokens()];
431 | 0 |
                 int x = 0;
432 | 0 |
                 while (st.hasMoreElements())
433 |  |
                 {
434 | 0 |
                     ret[x] = st.nextToken();
435 | 0 |
                     x++;
436 |  |
                 }
437 |  |
438 | 0 |
                 b.setBrokerLocal(TEMPLATE_EXTENSIONS_NAME, ret);
439 |  |
             }
440 |  |
441 | 0 |
             return ret;
442 |  |
         }
443 |  |
444 |  |
         /**
445 |  |
          * If the filename contains <i>://</i> assume it's a file b/c it's probably
446 |  |
          * a url.<p>
447 |  |
          *
448 |  |
          * If the filename ends with any of the configured
449 |  |
          * <code>ParseDirective.TemplateExtensions</code>, assume it's a template.<p>
450 |  |
          *
451 |  |
          * Otherwise, it must be a file
452 |  |
          */
453 |  |
         protected int guessType (Broker b, String filename)
454 |  |
         {
455 | 0 |
             if (filename.indexOf("://") > -1)
456 |  |
             {
457 | 0 |
                 return TYPE_TEXT;
458 |  |
             }
459 |  |
             else
460 |  |
             {
461 | 0 |
                 String[] extensions = getTemplateExtensions(b);
462 | 0 |
                 for (int x = 0; x < extensions.length; x++)
463 |  |
                 {
464 | 0 |
                     if (filename.endsWith(extensions[x]))
465 | 0 |
                         return TYPE_TEMPLATE;
466 |  |
                 }
467 |  |
             }
468 |  |
469 | 0 |
             return TYPE_TEXT;
470 |  |
         }
471 |  |
472 |  |
         /**
473 |  |
          * Get the template or file that the user wants to include, based on the
474 |  |
          * specified type.  This method does not know how to get a file whose type.
475 |  |
          * is "TYPE_DYNAMIC".
476 |  |
          */
477 |  |
         protected Object getThingToInclude (Broker b, int type, String filename) throws PropertyException
478 |  |
         {
479 | 0 |
             switch (type)
480 |  |
             {
481 |  |
                 case TYPE_TEMPLATE:
482 |  |
                     // wants to include a template
483 | 0 |
                     return getTemplate(b, filename);
484 |  |
485 |  |
                 case TYPE_MACRO:
486 |  |
                     // wants to include a template
487 | 0 |
                     return getTemplate(b, filename);
488 |  |
489 |  |
                 case TYPE_TEXT:
490 |  |
                     // wants to include a static file
491 | 0 |
                     return getFile(b, filename);
492 |  |
493 |  |
                 case TYPE_DYNAMIC:
494 |  |
                     // this should never happen
495 | 0 |
                     throw makePropertyException("Internal Error.  Never guessed file type");
496 |  |
497 |  |
                 default:
498 |  |
                     // default case should never happen b/c we take care of this
499 |  |
                     // during build()
500 | 0 |
                     throw makePropertyException("Internal Error.  Unrecognized file type: " + type);
501 |  |
             }
502 |  |
         }
503 |  |
504 |  |
         /**
505 |  |
          * Get a Template via the "template" provider known by the specified broker.
506 |  |
          */
507 |  |
         protected Template getTemplate (Broker b, String name) throws PropertyException
508 |  |
         {
509 |  |
             try
510 |  |
             {
511 | 0 |
                 return (Template) b.get("template", name);
512 |  |
             }
513 | 0 |
             catch (NotFoundException nfe)
514 |  |
             {
515 | 0 |
                 throw makePropertyException("Not found by template provider");
516 |  |
             }
517 | 0 |
             catch (ResourceException re)
518 |  |
             {
519 | 0 |
                 throw makePropertyException("Unable to get template", re);
520 |  |
             }
521 | 0 |
             catch (Exception e)
522 |  |
             {
523 | 0 |
                 throw makePropertyException("Unexpected exception while getting template");
524 |  |
             }
525 |  |
         }
526 |  |
527 |  |
         /**
528 |  |
          * Get the contents of a file (local file or url) via the "url" provider
529 |  |
          * known by the specified broker.  If the url provider can't find it
530 |  |
          * we check the Broker (Broker.getResource).
531 |  |
          */
532 |  |
         protected String getFile (Broker b, String name) throws PropertyException
533 |  |
         {
534 |  |
             try
535 |  |
             {
536 |  |
                 // first, ask the URL provider (if we have one) to find the file for us
537 | 0 |
                 return b.get("url", name).toString();
538 |  |
             }
539 | 0 |
             catch (Exception e)
540 |  |
             {
541 |  |
                 // for whatever reason, the URL provider couldn't find the file
542 |  |
                 // (maybe we don't have a URL provider?).  No matter, directly
543 |  |
                 // ask the Broker to load it as a resource
544 | 0 |
                 URL url = null;
545 |  |
546 |  |
                 try
547 |  |
                 {
548 | 0 |
                     url = b.getResource(name);
549 | 0 |
                     if (url == null) // doh!  the Broker couldn't find it either.  Guess it doesn't exist
550 | 0 |
                         throw makePropertyException("Resource not found by URL provider or Broker");
551 |  |
552 |  |
                     // open a URLConnection...
553 | 0 |
                     URLConnection conn = url.openConnection();
554 | 0 |
                     StringBuffer sb = new StringBuffer();
555 | 0 |
                     InputStream in = conn.getInputStream();
556 | 0 |
                     String enc = conn.getContentEncoding();
557 | 0 |
                     if (enc == null)
558 | 0 |
                         enc = b.getSetting("TemplateEncoding");
559 |  |
560 |  |
                     // ...and stream the contents of the URL into a String
561 | 0 |
                     int cnt = 0;
562 | 0 |
                     byte[] buff = new byte[4096];
563 | 0 |
                     while ((cnt = in.read(buff)) > 0)
564 |  |
                     {
565 | 0 |
                         sb.append(new String(buff, 0, cnt, enc));
566 |  |
                     }
567 | 0 |
                     in.close();
568 |  |
569 |  |
                     // return the string form of the resource.
570 |  |
                     // This is what will be included in the template
571 | 0 |
                     return sb.toString();
572 |  |
                 }
573 | 0 |
                 catch (IOException ioe)
574 |  |
                 {
575 | 0 |
                     throw makePropertyException("Error streaming file from: " + url, ioe);
576 |  |
                 }
577 |  |
             }
578 |  |
         }
579 |  |
580 |  |
         public void accept (TemplateVisitor v)
581 |  |
         {
582 | 0 |
             v.beginDirective(_desc.name);
583 | 0 |
             v.visitDirectiveArg("IncludeDirective", _strFilename);
584 | 0 |
             v.endDirective();
585 | 0 |
         }
586 |  |
587 |  |
         //
588 |  |
         // helper methods for throwing exceptions
589 |  |
         //
590 |  |
591 |  |
         private BuildException makeBuildException (String message)
592 |  |
         {
593 | 0 |
             return makeBuildException(message, null);
594 |  |
         }
595 |  |
596 |  |
         private BuildException makeBuildException (String message, Exception cause)
597 |  |
         {
598 | 0 |
             message = "#" + _directiveName + " " + _strFilename + ": " + message;
599 | 0 |
             if (cause != null)
600 | 0 |
                 return new BuildException(message, cause);
601 |  |
             else
602 | 0 |
                 return new BuildException(message);
603 |  |
         }
604 |  |
605 |  |
         private PropertyException makePropertyException (String message)
606 |  |
         {
607 | 0 |
             return makePropertyException(message, null);
608 |  |
         }
609 |  |
610 |  |
         private PropertyException makePropertyException (String message, Exception cause)
611 |  |
         {
612 | 0 |
             message = "#" + _directiveName + " " + _strFilename + ": " + message;
613 | 0 |
             if (cause != null)
614 | 0 |
                 return new PropertyException(message, cause);
615 |  |
             else
616 | 0 |
                 return new PropertyException(message);
617 |  |
         }
618 |  |
     }
619 |  |