##### Coverage Report - org.webmacro.Broker

Classes in this File | Line Coverage | Branch Coverage | Complexity
Broker |
45% | 118/262
40% | 34/84
| 2.4583333333333335;2.458
Broker$1 |
N/A | N/A
N/A | N/A
| 2.4583333333333335;2.458
Broker$AutoLoaderSettingHandler |
75% | 6/8
N/A | N/A
| 2.4583333333333335;2.458
Broker$MacroIncludeSettingHandler |
12% | 1/8
0% | 0/2
| 2.4583333333333335;2.458
Broker$ProviderSettingHandler |
75% | 6/8
N/A | N/A
| 2.4583333333333335;2.458

1 |  |
     /*
2 |  |
      * Copyright (c) 1998, 1999 Semiotek Inc. All Rights Reserved.
3 |  |
      *
4 |  |
      * This software is the confidential intellectual property of
5 |  |
      * of Semiotek Inc.; it is copyrighted and licensed, not sold.
6 |  |
      * You may use it under the terms of the GNU General Public License,
7 |  |
      * version 2, as published by the Free Software Foundation. If you
8 |  |
      * do not want to use the GPL, you may still use the software after
9 |  |
      * purchasing a proprietary developers license from Semiotek Inc.
10 |  |
      *
11 |  |
      * This software is provided "as is", with NO WARRANTY, not even the
12 |  |
      * implied warranties of fitness to purpose, or merchantability. You
13 |  |
      * assume all risks and liabilities associated with its use.
14 |  |
      *
15 |  |
      * See the attached License.html file for details, or contact us
16 |  |
      * by e-mail at info@semiotek.com to get a copy.
17 |  |
      */
18 |  |
19 |  |
20 |  |
     package org.webmacro;
21 |  |
22 |  |
     import java.io.BufferedReader;
23 |  |
     import java.io.File;
24 |  |
     import java.io.FileInputStream;
25 |  |
     import java.io.FileNotFoundException;
26 |  |
     import java.io.IOException;
27 |  |
     import java.io.InputStream;
28 |  |
     import java.io.InputStreamReader;
29 |  |
     import java.io.OutputStream;
30 |  |
     import java.io.UnsupportedEncodingException;
31 |  |
     import java.lang.ref.WeakReference;
32 |  |
     import java.net.MalformedURLException;
33 |  |
     import java.net.URL;
34 |  |
     import java.util.Arrays;
35 |  |
     import java.util.Enumeration;
36 |  |
     import java.util.Hashtable;
37 |  |
     import java.util.Iterator;
38 |  |
     import java.util.Map;
39 |  |
     import java.util.Properties;
40 |  |
     import java.util.WeakHashMap;
41 |  |
42 |  |
     import org.slf4j.Logger;
43 |  |
     import org.slf4j.LoggerFactory;
44 |  |
45 |  |
     import org.webmacro.broker.ContextAutoLoader;
46 |  |
     import org.webmacro.engine.DefaultEvaluationExceptionHandler;
47 |  |
     import org.webmacro.engine.EvaluationExceptionHandler;
48 |  |
     import org.webmacro.engine.IntrospectionUtils;
49 |  |
     import org.webmacro.engine.MethodWrapper;
50 |  |
     import org.webmacro.engine.PropertyOperatorCache;
51 |  |
     import org.webmacro.util.Settings;
52 |  |
     import org.webmacro.util.SubSettings;
53 |  |
54 |  |
     import java.util.concurrent.ConcurrentHashMap;
55 |  |
56 |  |
     /**
57 |  |
      * The Broker is responsible for loading and initializing almost everything
58 |  |
      * in WebMacro. It reads a set of Properties and uses them to determine
59 |  |
      * which components of WebMacro should be loaded. It is also responsible
60 |  |
      * for loading in things like Templates, URLs, and so forth.
61 |  |
      * <p>
62 |  |
      * By default the Broker reads a file called WebMacro.properties, searching
63 |  |
      * your CLASSPATH and system CLASSPATH for it. There are constructors to
64 |  |
      * allow you to specify a different location, a URL, or even just supply
65 |  |
      * a properties object directly.
66 |  |
      * <p>
67 |  |
      * The most common WebMacro installation problems revolve around the
68 |  |
      * Broker. Without a properly configured Broker WebMacro is unable to
69 |  |
      * load templates, parse templates, fetch URLs, or perform most of its
70 |  |
      * other basic functions.
71 |  |
      *
72 |  |
      * @author Marcel Huijkman
73 |  |
      *
74 |  |
      * @version        23-07-2002
75 |  |
      */
76 | 0 |
     public class Broker
77 |  |
     {
78 |  |
79 |  |
         public static final String WEBMACRO_DEFAULTS = "WebMacro.defaults";
80 |  |
         public static final String WEBMACRO_PROPERTIES = "WebMacro.properties";
81 |  |
         public static final String SETTINGS_PREFIX = "org.webmacro";
82 |  |
83 | 2 |
         public static final WeakHashMap BROKERS = new WeakHashMap();
84 |  |
85 |  |
         private static Settings _defaultSettings;
86 | 2 |
         protected static ClassLoader _myClassLoader = Broker.class.getClassLoader();
87 | 2 |
         protected static ClassLoader _systemClassLoader = ClassLoader.getSystemClassLoader();
88 |  |
89 | 6 |
         final protected Hashtable _providers = new Hashtable();
90 | 6 |
         final protected Settings _config = new Settings();
91 |  |
         final protected String _name;
92 | 6 |
         final public PropertyOperatorCache _propertyOperators
93 |  |
                 = new PropertyOperatorCache();
94 |  |
95 | 6 |
         protected Logger _log =  LoggerFactory.getLogger(Broker.class);
96 |  |
97 |  |
         private EvaluationExceptionHandler _eeHandler;
98 |  |
99 |  |
         /** a local map for one to dump stuff into, specific to this Broker */
100 | 6 |
         private Map _brokerLocal = new ConcurrentHashMap();
101 |  |
102 |  |
         /** a local map for "global functions" */
103 | 6 |
         private Map _functionMap = new ConcurrentHashMap();
104 |  |
105 |  |
         /** a local map for context tools and other automatic context goodies */
106 | 6 |
         private Map _toolLoader = new ConcurrentHashMap();
107 |  |
108 |  |
         /** map of global macros */
109 | 6 |
         private Map _macros = new ConcurrentHashMap();
110 |  |
111 |  |
         /*
112 |  |
     * Constructors.  Callers shouldn't use them; they should use the
113 |  |
     * factory methods (getBroker).
114 |  |
     *
115 |  |
     * Broker construction is kind of confusing.  There's a common
116 |  |
     * constructor, which initializes the log and a few other private
117 |  |
     * fields but doesn't do much else.  There's a bit of a
118 |  |
     * chicken-and-egg problem with loading the properties; we want to
119 |  |
     * be able to post log messages to indicate success or failure of
120 |  |
     * finding the configuration files, but we can't set a log target
121 |  |
     * until we do so.  The log system writes to standard error until
122 |  |
     * we set a target, so we let the constructor set up the default
123 |  |
     * target, then try and load properties, and then continue with the
124 |  |
     * setup by calling the various init() routines.
125 |  |
     */
126 |  |
127 |  |
         /**
128 |  |
          * Equivalent to Broker("WebMacro.properties"), except that it doesn't
129 |  |
          * complain if WebMacro.properties can't be found.
130 |  |
          */
131 |  |
         protected Broker () throws InitException
132 |  |
         {
133 | 2 |
             this((Broker) null, WEBMACRO_PROPERTIES);
134 | 2 |
             String propertySource = WEBMACRO_DEFAULTS + ", " + WEBMACRO_PROPERTIES
135 |  |
                     + ", " + "(System Properties)";
136 | 2 |
             loadDefaultSettings();
137 | 2 |
             loadSettings(WEBMACRO_PROPERTIES, true);
138 | 2 |
             loadSystemSettings();
139 | 2 |
             _log.info("Loaded settings from " + propertySource);
140 | 2 |
             init();
141 | 2 |
         }
142 |  |
143 |  |
         /**
144 |  |
          * Equivalent to Broker("WebMacro.properties"), except that it doesn't
145 |  |
          * complain if WebMacro.properties can't be found, and it loads properties
146 |  |
          * from a specified Properties.
147 |  |
          */
148 |  |
         protected Broker (Properties props) throws InitException
149 |  |
         {
150 | 0 |
             this((Broker) null, "Ad-hoc Properties " + props.hashCode());
151 | 0 |
             String propertySource = WEBMACRO_DEFAULTS + ", " + WEBMACRO_PROPERTIES
152 |  |
                     + ", (caller-supplied Properties), (System Properties)";
153 | 0 |
             loadDefaultSettings();
154 | 0 |
             loadSettings(WEBMACRO_PROPERTIES, true);
155 | 0 |
             loadSettings(props);
156 | 0 |
             loadSystemSettings();
157 | 0 |
             _log.info("Loaded settings from " + propertySource);
158 | 0 |
             init();
159 | 0 |
         }
160 |  |
161 |  |
         /**
162 |  |
          * Search the classpath for the properties file under
163 |  |
          * the specified name.
164 |  |
          * @param fileName Use this name instead of "WebMacro.properties"
165 |  |
          */
166 |  |
         protected Broker (String fileName) throws InitException
167 |  |
         {
168 | 0 |
             this((Broker) null, fileName);
169 | 0 |
             String propertySource = WEBMACRO_DEFAULTS + ", " + fileName;
170 | 0 |
             loadDefaultSettings();
171 | 0 |
             boolean loaded = loadSettings(fileName, false);
172 | 0 |
             if (!loaded)
173 |  |
             {
174 | 0 |
                 propertySource += "(not found)";
175 |  |
             }
176 | 0 |
             loadSystemSettings();
177 | 0 |
             propertySource += ", " + "(System Properties)";
178 | 0 |
             _log.info("Loaded settings from " + propertySource);
179 | 0 |
             init();
180 | 0 |
         }
181 |  |
182 |  |
         /**
183 |  |
          * Explicitly provide the properties that WebMacro should
184 |  |
          * configure from. You also need to specify a name for this
185 |  |
          * set of properties so WebMacro can figure out whether
186 |  |
          * two brokers point at the same properties information.
187 |  |
          * @param dummy a Broker instance that is never used
188 |  |
          * @param name Two brokers are the "same" if they have the same name
189 |  |
          */
190 |  |
         protected Broker (Broker dummy, String name)
191 |  |
                 throws InitException
192 | 6 |
         {
193 | 6 |
             _name = name;
194 | 6 |
         }
195 |  |
196 |  |
197 |  |
         /**
198 |  |
          * Provide access to the broker's log.
199 |  |
          */
200 |  |
         public Logger getBrokerLog()
201 |  |
         {
202 | 0 |
                 return _log;
203 |  |
         }
204 |  |
205 | 12 |
         private class ProviderSettingHandler extends Settings.ListSettingHandler
206 |  |
         {
207 |  |
             public void processSetting (String settingKey, String settingValue)
208 |  |
             {
209 |  |
                 try
210 |  |
                 {
211 | 36 |
                     Class pClass = classForName(settingValue);
212 | 36 |
                     Provider instance = (Provider) pClass.newInstance();
213 | 36 |
                     addProvider(instance, settingKey);
214 |  |
                 }
215 | 0 |
                 catch (Exception e)
216 |  |
                 {
217 | 0 |
                     _log.error("Provider (" + settingValue + ") failed to load", e);
218 | 36 |
                 }
219 | 36 |
             }
220 |  |
         }
221 |  |
222 | 12 |
         private class AutoLoaderSettingHandler extends Settings.ListSettingHandler
223 |  |
         {
224 |  |
             public void processSetting (String settingKey, String settingValue)
225 |  |
             {
226 |  |
                 try
227 |  |
                 {
228 | 12 |
                     Class pClass = classForName(settingValue);
229 | 12 |
                     ContextAutoLoader instance = (ContextAutoLoader) pClass.newInstance();
230 | 12 |
                     instance.init(Broker.this, settingKey);
231 |  |
                 }
232 | 0 |
                 catch (Exception e)
233 |  |
                 {
234 | 0 |
                     _log.error("ContextAutoLoader (" + settingValue + ") failed to load", e);
235 | 12 |
                 }
236 | 12 |
             }
237 |  |
         }
238 |  |
239 |  |
240 |  |
         /**
241 |  |
          * Constructors should call this after they've set up the properties
242 |  |
          * to set up common things like profiling, providers, etc.
243 |  |
          */
244 |  |
         protected void init () throws InitException
245 |  |
         {
246 |  |
             String eehClass;
247 |  |
248 |  |
             // Initialize the property operator cache
249 | 6 |
             _propertyOperators.init(this, _config);
250 |  |
251 |  |
             // Write out our properties as debug records
252 | 6 |
             if (_log.isDebugEnabled())
253 |  |
             {
254 | 0 |
                 String[] properties = _config.getKeys();
255 | 0 |
                 Arrays.sort(properties);
256 | 0 |
                 for (int i = 0; i < properties.length; i++)
257 |  |
                 {
258 | 0 |
                     _log.debug("Property " + properties[i] + ": "
259 |  |
                             + _config.getSetting(properties[i]));
260 |  |
                 }
261 |  |
             }
262 |  |
263 |  |
             // set up providers
264 | 6 |
             _config.processListSetting("Providers", new ProviderSettingHandler());
265 | 6 |
             if (_providers.size() == 0)
266 |  |
             {
267 | 0 |
                 _log.error("No Providers specified");
268 | 0 |
                 throw new InitException("No Providers specified in configuration");
269 |  |
             }
270 |  |
271 | 6 |
             _config.processListSetting("ContextAutoLoaders", new AutoLoaderSettingHandler());
272 |  |
             // @@@ load autoloaders
273 |  |
274 | 6 |
             eehClass = _config.getSetting("ExceptionHandler");
275 | 6 |
             if (eehClass != null && !eehClass.equals(""))
276 |  |
             {
277 |  |
                 try
278 |  |
                 {
279 | 6 |
                     _eeHandler = (EvaluationExceptionHandler)
280 |  |
                             classForName(eehClass).newInstance();
281 |  |
                 }
282 | 0 |
                 catch (Exception e)
283 |  |
                 {
284 | 0 |
                     _log.warn("Unable to instantiate exception handler of class "
285 |  |
                             + eehClass + "; " + e);
286 | 6 |
                 }
287 |  |
             }
288 | 6 |
             if (_eeHandler == null)
289 |  |
             {
290 | 0 |
                 _eeHandler = new DefaultEvaluationExceptionHandler();
291 |  |
             }
292 |  |
293 | 6 |
             _eeHandler.init(this, _config);
294 |  |
295 |  |
             // Initialize function map
296 | 6 |
             SubSettings fnSettings = new SubSettings(_config, "Functions");
297 | 6 |
             String[] fns = fnSettings.getKeys();
298 | 132 |
             for (int i = 0; fns != null && i < fns.length; i++)
299 |  |
             {
300 | 126 |
                 String fn = fns[i];
301 | 126 |
                 String fnSetting = fnSettings.getSetting(fn);
302 | 126 |
                 int lastDot = fnSetting.lastIndexOf('.');
303 | 126 |
                 if (lastDot == -1)
304 |  |
                 {
305 | 0 |
                     throw new IllegalArgumentException("Bad function declaration for "
306 |  |
                             + fn + ": " + fnSetting
307 |  |
                             + ".  This setting must include full class name followed by a '.' and method name");
308 |  |
                 }
309 | 126 |
                 String fnClassName = fnSetting.substring(0, lastDot);
310 | 126 |
                 String fnMethName = fnSetting.substring(lastDot + 1);
311 |  |
                 // function type may be static, instance, or factory.  Default is static
312 | 126 |
                 String fnType = _config.getSetting("Function." + fn + ".type", "static");
313 | 126 |
                 Object[] args = null;
314 | 126 |
                 if ("factory".equals(fnType))
315 |  |
                 {
316 |  |
                     //TODO: implement this!!!
317 |  |
                     // get function from a factory method
318 |  |
                     // declared class/method is the factory class/instance method
319 |  |
                     // get the factory class method name
320 |  |
                     //String factoryMeth = _config.getSetting("Function." + fn + ".factory.method");
321 |  |
                 }
322 | 126 |
                 if (!"static".equals(fnType))
323 |  |
                 {
324 |  |
                     // get arg string
325 | 0 |
                     String argString = _config.getSetting("Function." + fn + ".args");
326 | 0 |
                     if (argString != null)
327 |  |
                     {
328 | 0 |
                         if (!argString.startsWith("["))
329 |  |
                         {
330 | 0 |
                             argString = "[" + argString + "]";
331 |  |
                         }
332 | 0 |
                         org.webmacro.engine.StringTemplate tmpl =
333 |  |
                                 new org.webmacro.engine.StringTemplate(this, "#set $args=" + argString);
334 | 0 |
                         Context argContext = new Context(this);
335 |  |
                         try
336 |  |
                         {
337 | 0 |
                             tmpl.evaluateAsString(argContext);
338 |  |
                         }
339 | 0 |
                         catch (Exception e)
340 |  |
                         {
341 | 0 |
                             _log.error("Unable to evaluate arguments to function " + fn
342 |  |
                                     + ".  The specified string was " + argString + ".", e);
343 | 0 |
                         }
344 | 0 |
                         args = (Object[]) argContext.get("args");
345 | 0 |
                         _log.debug("Args for function " + fn + ": " + Arrays.asList(args));
346 |  |
                     }
347 |  |
                 }
348 |  |
349 | 126 |
                 Class c = null;
350 |  |
                 try
351 |  |
                 {
352 | 126 |
                     c = Class.forName(fnClassName);
353 |  |
                 }
354 | 0 |
                 catch (Exception e)
355 |  |
                 {
356 | 0 |
                     _log.error("Unable to load class " + fnClassName + " for function " + fn, e);
357 | 126 |
                 }
358 |  |
359 | 126 |
                 Object o = c;
360 |  |
                 try
361 |  |
                 {
362 | 126 |
                     if (c != null)
363 |  |
                     {
364 | 126 |
                         if ("instance".equals(fnType))
365 |  |
                         {
366 |  |
                             // instantiate the class
367 | 0 |
                             o = IntrospectionUtils.instantiate(c, args);
368 |  |
                         }
369 |  |
                     }
370 | 126 |
                     MethodWrapper mw = new MethodWrapper(o, fnMethName);
371 | 126 |
                     _functionMap.put(fn, mw);
372 |  |
                 }
373 | 0 |
                 catch (Exception e)
374 |  |
                 {
375 | 0 |
                     _log.error("Unable to instantiate the function " + fn
376 |  |
                             + " using the supplied configuration.", e);
377 | 126 |
                 }
378 |  |
             }
379 |  |
380 | 6 |
             MacroIncludeSettingHandler macroHandler = new MacroIncludeSettingHandler();
381 |  |
382 |  |
             // parse all macro libraries
383 | 6 |
             _config.processListSetting("Macros.Include",macroHandler);
384 |  |
385 |  |
             // handle exceptions if any
386 | 6 |
             if (macroHandler.e != null) {
387 | 0 |
                 throw new InitException("Error loading one or more macro libraries",macroHandler.e);
388 |  |
             }
389 |  |
390 | 6 |
         }
391 |  |
392 |  |
         /** This class is necessary as we cannot throw an exception directly from
393 |  |
          * processSetting(String,String)
394 |  |
          */
395 | 12 |
         private class MacroIncludeSettingHandler extends Settings.ListSettingHandler {
396 |  |
             Exception e;
397 |  |
398 |  |
             public void processSetting(String settingKey, String settingValue) {
399 |  |
                 try {
400 | 0 |
                     Template t = (Template) getProvider("template").get(settingValue);
401 | 0 |
                     _macros.putAll(t.getMacros());
402 | 0 |
                 } catch (ResourceException e) {
403 | 0 |
                     _log.error("Error loading macro library '"+settingValue+"', ignoring it",e);
404 |  |
                     // store exception
405 | 0 |
                     if (this.e == null) this.e = e;
406 | 0 |
                 }
407 | 0 |
             }
408 |  |
409 |  |
         }
410 |  |
411 |  |
         /* Factory methods -- the supported way of getting a Broker */
412 |  |
413 |  |
         public static Broker getBroker () throws InitException
414 |  |
         {
415 |  |
             try
416 |  |
             {
417 | 850 |
                 Broker b = findBroker(WEBMACRO_PROPERTIES);
418 | 850 |
                 if (b == null)
419 |  |
                 {
420 | 2 |
                     b = new Broker();
421 | 2 |
                     register(WEBMACRO_PROPERTIES, b);
422 |  |
                 }
423 | 850 |
                 return b;
424 |  |
             }
425 | 0 |
             catch (InitException e)
426 |  |
             {
427 | 0 |
                 throw new InitException("Failed to initialize WebMacro with default config",e);
428 |  |
             }
429 |  |
         }
430 |  |
431 |  |
         public static Broker getBroker (Properties p) throws InitException
432 |  |
         {
433 | 0 |
             Broker b = findBroker(p);
434 | 0 |
             if (b == null)
435 |  |
             {
436 | 0 |
                 b = new Broker(p);
437 | 0 |
                 register(p, b);
438 |  |
             }
439 | 0 |
             return b;
440 |  |
         }
441 |  |
442 |  |
         public static Broker getBroker (String settingsFile) throws InitException
443 |  |
         {
444 | 0 |
             Broker b = findBroker(settingsFile);
445 | 0 |
             if (b == null)
446 |  |
             {
447 | 0 |
                 b = new Broker(settingsFile);
448 | 0 |
                 register(settingsFile, b);
449 |  |
             }
450 |  |
451 | 0 |
             return b;
452 |  |
         }
453 |  |
454 |  |
         /* Static (internal) methods used for loading settings */
455 |  |
456 |  |
         protected synchronized void loadDefaultSettings ()
457 |  |
                 throws InitException
458 |  |
         {
459 | 6 |
             if (_defaultSettings == null)
460 |  |
             {
461 |  |
                 try
462 |  |
                 {
463 | 2 |
                     _defaultSettings = new Settings(WEBMACRO_DEFAULTS);
464 |  |
                 }
465 | 0 |
                 catch (IOException e)
466 |  |
                 {
467 | 0 |
                     throw new InitException("IO Error reading " + WEBMACRO_DEFAULTS,
468 |  |
                             e);
469 | 2 |
                 }
470 |  |
             }
471 |  |
             // _log.info("Loading properties file " + WEBMACRO_DEFAULTS);
472 | 6 |
             _config.load(_defaultSettings);
473 | 6 |
         }
474 |  |
475 |  |
         protected boolean loadSettings (String name,
476 |  |
                                         boolean optional) throws InitException
477 |  |
         {
478 | 8 |
             URL u = getResource(name);
479 | 8 |
             if (u != null)
480 |  |
             {
481 |  |
                 try
482 |  |
                 {
483 | 0 |
                     _config.load(u);
484 | 0 |
                     return true;
485 |  |
                 }
486 | 0 |
                 catch (IOException e)
487 |  |
                 {
488 | 0 |
                     if (optional)
489 |  |
                     {
490 | 0 |
                         _log.info("Cannot find properties file " + name + ", continuing");
491 |  |
                     }
492 | 0 |
                     e.printStackTrace();
493 | 0 |
                     if (!optional)
494 |  |
                     {
495 | 0 |
                         throw new InitException("Error reading settings from " + name, e);
496 |  |
                     }
497 | 0 |
                 }
498 |  |
             }
499 |  |
             else
500 |  |
             {
501 | 8 |
                 if (!optional)
502 |  |
                 {
503 | 0 |
                     throw new InitException("Error reading settings from " + name);
504 |  |
                 }
505 |  |
             }
506 | 8 |
             return false;
507 |  |
         }
508 |  |
509 |  |
         protected void loadSettings (Properties p)
510 |  |
         {
511 | 0 |
             _config.load(p);
512 | 0 |
         }
513 |  |
514 |  |
         protected void loadSystemSettings ()
515 |  |
         {
516 |  |
             // _log.info("Loading properties from system properties");
517 | 6 |
             _config.load(System.getProperties(), SETTINGS_PREFIX);
518 | 6 |
         }
519 |  |
520 |  |
         /**
521 |  |
          * Used to maintain a weak map mapping the partition _key to the
522 |  |
          * Broker.  Registers a broker for a given partition _key.
523 |  |
          */
524 |  |
         protected static void register (Object key, Broker broker)
525 |  |
         {
526 | 6 |
             BROKERS.put(key, new WeakReference(broker));
527 | 6 |
         }
528 |  |
529 |  |
         /**
530 |  |
          * Find the broker for the specified partition _key, if one is
531 |  |
          * registered.  Used by factory methods to ensure that there is
532 |  |
          * only one broker per WM partition
533 |  |
          */
534 |  |
         protected static Broker findBroker (Object key)
535 |  |
         {
536 | 882 |
             WeakReference ref = (WeakReference) BROKERS.get(key);
537 | 882 |
             if (ref != null)
538 |  |
             {
539 | 876 |
                 Broker broker = (Broker) ref.get();
540 | 876 |
                 if (broker == null)
541 | 0 |
                     BROKERS.remove(key);
542 | 876 |
                 return broker;
543 |  |
             }
544 |  |
             else
545 |  |
             {
546 | 6 |
                 return null;
547 |  |
             }
548 |  |
         }
549 |  |
550 |  |
         /**
551 |  |
          * Access to the settings in WebMacro.properties
552 |  |
          */
553 |  |
         public Settings getSettings ()
554 |  |
         {
555 | 1746 |
             return _config;
556 |  |
         }
557 |  |
558 |  |
         /**
559 |  |
          * Access to the settings in WebMacro.properties
560 |  |
          */
561 |  |
         public String getSetting (String key)
562 |  |
         {
563 | 56 |
             return _config.getSetting(key);
564 |  |
         }
565 |  |
566 |  |
         /**
567 |  |
          * Access to the settings in WebMacro.properties
568 |  |
          */
569 |  |
         public boolean getBooleanSetting (String key)
570 |  |
         {
571 | 0 |
             return _config.getBooleanSetting(key);
572 |  |
         }
573 |  |
574 |  |
         /**
575 |  |
          * Access to the settings in WebMacro.properties
576 |  |
          */
577 |  |
         public int getIntegerSetting (String key)
578 |  |
         {
579 | 0 |
             return _config.getIntegerSetting(key);
580 |  |
         }
581 |  |
582 |  |
         /**
583 |  |
          * Access to the settings in WebMacro.properties
584 |  |
          */
585 |  |
         public int getIntegerSetting (String key, int defaultValue)
586 |  |
         {
587 | 0 |
             return _config.getIntegerSetting(key, defaultValue);
588 |  |
         }
589 |  |
590 |  |
591 |  |
         /**
592 |  |
          * Register a new provider, calling its getType() method to find
593 |  |
          * out what type of requests it wants to serve.
594 |  |
          */
595 |  |
         public void addProvider (Provider p, String pType) throws InitException
596 |  |
         {
597 | 36 |
             if (pType == null || pType.equals(""))
598 |  |
             {
599 | 0 |
                 pType = p.getType();
600 |  |
             }
601 | 36 |
             p.init(this, _config);
602 | 36 |
             _providers.put(pType, p);
603 | 36 |
             _log.info("Loaded provider " + p);
604 | 36 |
             if (!pType.equals(p.getType()))
605 |  |
             {
606 | 0 |
                 _log.info("Provider name remapped from " + p.getType()
607 |  |
                         + " to " + pType);
608 |  |
             }
609 | 36 |
         }
610 |  |
611 |  |
         /**
612 |  |
          * Get a provider
613 |  |
          */
614 |  |
         public Provider getProvider (String type) throws NotFoundException
615 |  |
         {
616 | 3990 |
             Provider p = (Provider) _providers.get(type);
617 | 3990 |
             if (p == null)
618 |  |
             {
619 | 0 |
                 throw new NotFoundException("No provider for type " + type
620 |  |
                         + ": perhaps WebMacro couldn't load its configuration?");
621 |  |
             }
622 | 3990 |
             return p;
623 |  |
         }
624 |  |
625 |  |
         /**
626 |  |
          * Get an Iterator of String names that the Provider items in this
627 |  |
          * Broker have been registered under.  This can then be used with
628 |  |
          * getProvider(type) to retrieve the registered Provider.
629 |  |
          * @return Iterator of String
630 |  |
          **/
631 |  |
         public Iterator getProviderTypes()
632 |  |
         {
633 | 0 |
             return _providers.keySet().iterator();
634 |  |
         }
635 |  |
636 |  |
         /**
637 |  |
          * Close down this Broker.  This will call destroy() on all
638 |  |
          * registered Providers with the Broker.
639 |  |
          * @see Provider#destroy()
640 |  |
          **/
641 |  |
         public void destroy()
642 |  |
         {
643 | 0 |
             Iterator providers = _providers.values().iterator();
644 | 0 |
             while (providers.hasNext()) {
645 | 0 |
                 ((Provider) providers.next()).destroy();
646 |  |
             }
647 | 0 |
         }
648 |  |
649 |  |
         /**
650 |  |
          * Get a new FastWriter
651 |  |
          * A FastWriter is used when writing templates to an output stream
652 |  |
          *
653 |  |
          * @param out The output stream the FastWriter should write to.  Typically
654 |  |
          *           this will be your ServletOutputStream.  It can be null if
655 |  |
          *           only want the fast writer to buffer the output.
656 |  |
          * @param enctype the Encoding type to use
657 |  |
          * @deprecated
658 |  |
          */
659 |  |
         public final FastWriter getFastWriter (OutputStream out, String enctype)
660 |  |
                 throws UnsupportedEncodingException
661 |  |
         {
662 | 0 |
             return FastWriter.getInstance(this, out, enctype);
663 |  |
         }
664 |  |
665 |  |
         /**
666 |  |
          * Get the EvaluationExceptionHandler
667 |  |
          */
668 |  |
         public EvaluationExceptionHandler getEvaluationExceptionHandler ()
669 |  |
         {
670 | 30 |
             return _eeHandler;
671 |  |
         }
672 |  |
673 |  |
674 |  |
         /**
675 |  |
          * Set a new EvaluationExceptionHandler
676 |  |
          */
677 |  |
         public void setEvaluationExceptionHandler (EvaluationExceptionHandler eeh)
678 |  |
         {
679 | 0 |
             _eeHandler = eeh;
680 | 0 |
         }
681 |  |
682 |  |
683 |  |
         /**
684 |  |
          * Return a map of all global macros. These macros will be included into
685 |  |
          * all templates. As the Map implementation is thread-safe, you can even
686 |  |
          * add macros to the map, if you want to.
687 |  |
          * @return map of global macros.
688 |  |
          */
689 |  |
         public Map getMacros() {
690 | 224 |
             return _macros;
691 |  |
         }
692 |  |
         /**
693 |  |
          * Get a resource (file) from the the Broker's class loader.
694 |  |
          * We look first with the Broker's class loader, then with the system
695 |  |
          * class loader, and then for a file.
696 |  |
          */
697 |  |
         public URL getResource (String name)
698 |  |
         {
699 | 378 |
             URL u = _myClassLoader.getResource(name);
700 | 378 |
             if (u == null)
701 |  |
             {
702 | 324 |
                 u = _systemClassLoader.getResource(name);
703 |  |
             }
704 | 378 |
             if (u == null)
705 |  |
             {
706 |  |
                 try
707 |  |
                 {
708 | 324 |
                     u = new URL("file", null, -1, name);
709 | 324 |
                     File f = new File(u.getFile());
710 | 324 |
                     if (!f.exists())
711 |  |
                     {
712 | 324 |
                         u = null;
713 |  |
                     }
714 |  |
                 }
715 | 0 |
                 catch (MalformedURLException ignored)
716 |  |
                 {
717 | 0 |
                     _log.error("MalformedURL", ignored);
718 | 324 |
                 }
719 |  |
             }
720 | 378 |
             return u;
721 |  |
         }
722 |  |
723 |  |
         /**
724 |  |
          * Get a resource (file) from the Broker's class loader
725 |  |
          */
726 |  |
         public InputStream getResourceAsStream (String name)
727 |  |
         {
728 | 0 |
             InputStream is = _myClassLoader.getResourceAsStream(name);
729 | 0 |
             if (is == null)
730 |  |
             {
731 | 0 |
                 is = _systemClassLoader.getResourceAsStream(name);
732 |  |
             }
733 | 0 |
             if (is == null)
734 |  |
             {
735 |  |
                 try
736 |  |
                 {
737 | 0 |
                     is = new FileInputStream(name);
738 |  |
                 }
739 | 0 |
                 catch (FileNotFoundException ignored)
740 |  |
                 {
741 | 0 |
                     _log.error("FileNotFound", ignored);
742 | 0 |
                 }
743 |  |
             }
744 | 0 |
             return is;
745 |  |
         }
746 |  |
747 |  |
         /**
748 |  |
          * Get a template from the Broker.  By default, this just calls
749 |  |
          * getResource, but allows brokers to substitute their own idea
750 |  |
          * of where templates should come from.
751 |  |
          */
752 |  |
         public URL getTemplate (String name)
753 |  |
         {
754 | 200 |
             return getResource(name);
755 |  |
         }
756 |  |
757 |  |
758 |  |
         /**
759 |  |
          * Load a class through the broker's class loader.  Subclasses can
760 |  |
          * redefine or chain if they know of other ways to load a class.
761 |  |
          */
762 |  |
         public Class classForName (String name) throws ClassNotFoundException
763 |  |
         {
764 | 96 |
             return Class.forName(name);
765 |  |
         }
766 |  |
767 |  |
768 |  |
         /**
769 |  |
          * Look up query against a provider using its integer type handle.
770 |  |
          */
771 |  |
         public Object get (String type, final String query)
772 |  |
                 throws ResourceException
773 |  |
         {
774 | 3478 |
             return getProvider(type).get(query);
775 |  |
         }
776 |  |
777 |  |
         /**
778 |  |
          * Store a _key/value in this Broker.  This is a utility feature for
779 |  |
          * one to save data that is specific to this instance of WebMacro.<p>
780 |  |
          *
781 |  |
          * Please remember that you probably aren't the only one storing keys
782 |  |
          * in here, so be specific with your _key names.  Don't use names like
783 |  |
          * <code>String</code> or <code>Foo</code>.  Instead, use
784 |  |
          * <code>IncludeDirective.String</code> and <code>IncludeDirective.Foo</code>.
785 |  |
          */
786 |  |
         public void setBrokerLocal (Object key, Object value)
787 |  |
         {
788 | 6 |
             _brokerLocal.put(key, value);
789 | 6 |
         }
790 |  |
791 |  |
         /**
792 |  |
          * Get a value that was previously stored in this Broker.
793 |  |
          *
794 |  |
          * @see #setBrokerLocal
795 |  |
          */
796 |  |
         public Object getBrokerLocal (Object key)
797 |  |
         {
798 | 0 |
             return _brokerLocal.get(key);
799 |  |
         }
800 |  |
801 |  |
         /** fetch a "global function" */
802 |  |
         public MethodWrapper getFunction (String fnName)
803 |  |
         {
804 | 0 |
             return (MethodWrapper) _functionMap.get(fnName);
805 |  |
         }
806 |  |
807 |  |
         /** store a "global function" */
808 |  |
         public void putFunction (String fnName, MethodWrapper mw)
809 |  |
         {
810 | 0 |
             _functionMap.put(fnName, mw);
811 | 0 |
         }
812 |  |
813 |  |
         /** store a "global function" by name */
814 |  |
         public void putFunction (String fnName, Object instance, String methodName)
815 |  |
         {
816 | 0 |
             MethodWrapper func = new MethodWrapper(instance, methodName);
817 | 0 |
             putFunction(fnName, func);
818 | 0 |
         }
819 |  |
820 |  |
         /** Fetch a tool */
821 |  |
         public Object getAutoContextVariable(String variableName, Context context) {
822 | 12204 |
             ContextAutoLoader loader = (ContextAutoLoader) _toolLoader.get(variableName);
823 |  |
             try {
824 | 12204 |
                 if (loader == null)
825 | 11044 |
                     return null;
826 |  |
                 else
827 | 1160 |
                     return loader.get(variableName, context);
828 |  |
             }
829 | 0 |
             catch (PropertyException e) {
830 | 0 |
                 return null;
831 |  |
             }
832 |  |
         }
833 |  |
834 |  |
         public void registerAutoContextVariable(String variableName, ContextAutoLoader loader) {
835 | 72 |
             _toolLoader.put(variableName, loader);
836 | 72 |
         }
837 |  |
838 |  |
         /**
839 |  |
          * Backwards compatible, calls get(String,String)
840 |  |
          * @deprecated call get(String,String) instead
841 |  |
          */
842 |  |
         public final Object getValue (String type, String query)
843 |  |
                 throws ResourceException
844 |  |
         {
845 | 0 |
             return get(type, query);
846 |  |
         }
847 |  |
848 |  |
         /**
849 |  |
          * Explain myself
850 |  |
          */
851 |  |
         public String toString ()
852 |  |
         {
853 | 0 |
             StringBuffer buf = new StringBuffer();
854 | 0 |
             buf.append("Broker:");
855 | 0 |
             buf.append(_name);
856 | 0 |
             buf.append("(");
857 | 0 |
             Enumeration e = _providers.elements();
858 | 0 |
             while (e.hasMoreElements())
859 |  |
             {
860 | 0 |
                 Provider pr = (Provider) e.nextElement();
861 | 0 |
                 buf.append(pr);
862 | 0 |
                 if (e.hasMoreElements())
863 |  |
                 {
864 | 0 |
                     buf.append(", ");
865 |  |
                 }
866 | 0 |
             }
867 | 0 |
             return buf.toString();
868 |  |
         }
869 |  |
870 |  |
         public String getName ()
871 |  |
         {
872 | 284 |
             return _name;
873 |  |
         }
874 |  |
875 |  |
         public ClassLoader getClassLoader ()
876 |  |
         {
877 | 0 |
             return _myClassLoader;
878 |  |
         }
879 |  |
880 |  |
         /**
881 |  |
          * Test the broker or a provider. Reads from stdin: TYPE NAME
882 |  |
          */
883 |  |
         public static void main (String[] arg)
884 |  |
         {
885 |  |
             try
886 |  |
             {
887 | 0 |
                 if (arg.length != 1)
888 |  |
                 {
889 | 0 |
                     System.out.println("Arg required: config file URL");
890 | 0 |
                     System.out.println("Then input is: TYPE NAME lines on stdin");
891 | 0 |
                     System.exit(1);
892 |  |
                 }
893 | 0 |
                 Broker broker = new Broker(arg[0]);
894 |  |
895 | 0 |
                 BufferedReader in =
896 |  |
                         new BufferedReader(new InputStreamReader(System.in));
897 |  |
898 |  |
                 String line;
899 | 0 |
                 while ((line = in.readLine()) != null)
900 |  |
                 {
901 |  |
902 | 0 |
                     int space = line.indexOf(' ');
903 | 0 |
                     String type = line.substring(0, space);
904 | 0 |
                     String name = line.substring(space + 1);
905 | 0 |
                     System.out.println("broker.get(\"" + type + "\", \""
906 |  |
                             + name + "\"):");
907 | 0 |
                     Object o = broker.get(type, name);
908 | 0 |
                     System.out.println("RESULT:");
909 | 0 |
                     System.out.println(o.toString());
910 | 0 |
                 }
911 |  |
             }
912 | 0 |
             catch (Exception e)
913 |  |
             {
914 | 0 |
                 e.printStackTrace();
915 | 0 |
             }
916 | 0 |
         }
917 |  |
     }