| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| IncludeDirective |
|
| 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 |