001: /*
002: * $Id: Application.java 4893 2006-03-13 12:27:09 -0800 (Mon, 13 Mar 2006)
003: * eelco12 $ $Revision: 464667 $ $Date: 2006-03-13 12:27:09 -0800 (Mon, 13 Mar
004: * 2006) $
005: *
006: * ==============================================================================
007: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
008: * use this file except in compliance with the License. You may obtain a copy of
009: * the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
015: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
016: * License for the specific language governing permissions and limitations under
017: * the License.
018: */
019: package wicket;
020:
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.Serializable;
024: import java.net.URL;
025: import java.util.ArrayList;
026: import java.util.Enumeration;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.Map;
031: import java.util.Properties;
032:
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035:
036: import wicket.application.IComponentInstantiationListener;
037: import wicket.markup.MarkupCache;
038: import wicket.markup.html.image.resource.DefaultButtonImageResourceFactory;
039: import wicket.markup.resolver.AutoComponentResolver;
040: import wicket.markup.resolver.FragmentResolver;
041: import wicket.markup.resolver.HtmlHeaderResolver;
042: import wicket.markup.resolver.MarkupInheritanceResolver;
043: import wicket.markup.resolver.ParentResolver;
044: import wicket.markup.resolver.WicketLinkResolver;
045: import wicket.markup.resolver.WicketMessageResolver;
046: import wicket.session.ISessionStore;
047: import wicket.settings.IAjaxSettings;
048: import wicket.settings.IApplicationSettings;
049: import wicket.settings.IDebugSettings;
050: import wicket.settings.IExceptionSettings;
051: import wicket.settings.IFrameworkSettings;
052: import wicket.settings.IMarkupSettings;
053: import wicket.settings.IPageSettings;
054: import wicket.settings.IRequestCycleSettings;
055: import wicket.settings.IResourceSettings;
056: import wicket.settings.ISecuritySettings;
057: import wicket.settings.ISessionSettings;
058: import wicket.settings.Settings;
059: import wicket.util.file.IResourceFinder;
060: import wicket.util.lang.Classes;
061: import wicket.util.lang.Objects;
062: import wicket.util.time.Duration;
063:
064: /**
065: * Base class for all Wicket applications. To create a Wicket application, you
066: * generally should <i>not </i> directly subclass this class. Instead, you will
067: * want to subclass some subclass of Application, like WebApplication, which is
068: * appropriate for the protocol and markup type you are working with.
069: * <p>
070: * Application has the following interesting features / attributes:
071: * <ul>
072: * <li><b>Name </b>- The Application's name, which is the same as its class
073: * name.
074: *
075: * <li><b>Home Page </b>- The Application's home Page class. Subclasses must
076: * override getHomePage() to provide this property value.
077: *
078: * <li><b>Settings </b>- Application settings are partitioned into sets of
079: * related settings using interfaces in the wicket.settings package. These
080: * interfaces are returned by the following methods, which should be used to
081: * configure framework settings for your application: getApplicationSettings(),
082: * getDebugSettings(), getExceptionSettings(), getMarkupSettings(),
083: * getPageSettings(), getRequestCycleSettings(), getSecuritySettings and
084: * getSessionSettings(). These settings are configured by default through the
085: * constructor or internalInit methods. Default the application is configured
086: * for DEVELOPMENT. You can configure this globally to DEPLOYMENT or override
087: * specific settings by implementing the init() method.
088: *
089: * <li><b>Shared Resources </b>- Resources added to an Application's
090: * SharedResources have application-wide scope and can be referenced using a
091: * logical scope and a name with the ResourceReference class. ResourceReferences
092: * can then be used by multiple components in the same application without
093: * additional overhead (beyond the ResourceReference instance held by each
094: * referee) and will yield a stable URL, permitting efficient browser caching of
095: * the resource (even if the resource is dynamically generated). Resources
096: * shared in this manner may also be localized. See
097: * {@link wicket.ResourceReference} for more details.
098: *
099: * <li><b>Session Factory </b>- The Application subclass WebApplication
100: * supplies an implementation of getSessionFactory() which returns an
101: * implementation of ISessionFactory that creates WebSession Session objects
102: * appropriate for web applications. You can (and probably will want to)
103: * override getSessionFactory() to provide your own session factory that creates
104: * Session instances of your own application-specific subclass of WebSession.
105: *
106: * </ul>
107: *
108: * @see wicket.protocol.http.WebApplication
109: * @author Jonathan Locke
110: */
111: public abstract class Application {
112: /** Configuration constant for the 2 types */
113: public static final String CONFIGURATION = "configuration";
114:
115: /**
116: * Configuration type constant for getting the context path out of the
117: * web.xml
118: */
119: public static final String CONTEXTPATH = "contextpath";
120:
121: /** Configuration type constant for deployment */
122: public static final String DEPLOYMENT = "deployment";
123:
124: /** Configuration type constant for development */
125: public static final String DEVELOPMENT = "development";
126:
127: /**
128: * Applications keyed on the {@link #getApplicationKey()} so that they can
129: * be retrieved even without being in a request/ being set in the thread
130: * local (we need that e.g. for when we are in a destruction thread).
131: */
132: private static final Map applicationKeyToApplication = new HashMap(
133: 1);
134:
135: /** Thread local holder of the application object. */
136: private static final ThreadLocal current = new ThreadLocal();
137:
138: /** Log. */
139: private static final Log log = LogFactory.getLog(Application.class);
140:
141: /**
142: * Checks if the <code>Application</code> threadlocal is set in this
143: * thread
144: *
145: * @return true if {@link Application#get()} can return the instance of
146: * application, false otherwise
147: */
148: public static boolean exists() {
149: return current.get() != null;
150: }
151:
152: /**
153: * Get Application for current thread.
154: *
155: * @return The current thread's Application
156: */
157: public static Application get() {
158: final Application application = (Application) current.get();
159: if (application == null) {
160: throw new WicketRuntimeException(
161: "There is no application attached to current thread "
162: + Thread.currentThread().getName());
163: }
164: return application;
165: }
166:
167: /**
168: * Gets the Application based on the application key of that application.
169: * THIS METHOD IS NOT MEANT INTENDED FOR FRAMEWORK CLIENTS.
170: *
171: * @param applicationKey
172: * The unique key of the application within a certain context
173: * (e.g. a web application)
174: * @return The application
175: * @throws IllegalArgumentException
176: * When no application was found with the provided key
177: */
178: public static Application get(String applicationKey) {
179: Application application = (Application) applicationKeyToApplication
180: .get(applicationKey);
181: return application;
182: }
183:
184: /**
185: * @return True if the current thread is attached to an application.
186: */
187: public static boolean isAttached() {
188: return current.get() != null;
189: }
190:
191: /**
192: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
193: *
194: * @param application
195: * The current application or null for this thread
196: */
197: public static void set(final Application application) {
198: if (application == null) {
199: throw new IllegalArgumentException(
200: "Argument application can not be null");
201: }
202: current.set(application);
203: }
204:
205: /**
206: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
207: */
208: public static void unset() {
209: current.set(null);
210: }
211:
212: /** list of {@link IComponentInstantiationListener}s. */
213: private IComponentInstantiationListener[] componentInstantiationListeners = new IComponentInstantiationListener[0];
214:
215: /** Record what the configuration is, so that we can query for it later. */
216: private String configurationType;
217:
218: /** list of initializers. */
219: private List initializers = new ArrayList();
220:
221: /** Markup cache for this application */
222: private final MarkupCache markupCache;
223:
224: /** Application level meta data. */
225: private MetaDataEntry[] metaData;
226:
227: /** Name of application subclass. */
228: private final String name;
229:
230: /** The session facade. */
231: private ISessionStore sessionStore;
232:
233: /** Settings for this application. */
234: private Settings settings;
235:
236: /** can the settings object be set/used. */
237: private boolean settingsAccessible;
238:
239: /** Shared resources for this application */
240: private final SharedResources sharedResources;
241:
242: /**
243: * Constructor. <strong>Use {@link #init()} for any configuration of your
244: * application instead of overriding the constructor.</strong>
245: */
246: public Application() {
247: // Create name from subclass
248: this .name = Classes.simpleName(getClass());
249:
250: // Construct markup cache for this application
251: this .markupCache = new MarkupCache(this );
252:
253: // Create shared resources repository
254: this .sharedResources = new SharedResources(this );
255:
256: // Install default component instantiation listener that uses
257: // authorization strategy to check component instantiations.
258: addComponentInstantiationListener(new IComponentInstantiationListener() {
259: /**
260: * @see wicket.application.IComponentInstantiationListener#onInstantiation(wicket.Component)
261: */
262: public void onInstantiation(final Component component) {
263: // If component instantiation is not authorized
264: if (!Session
265: .get()
266: .getAuthorizationStrategy()
267: .isInstantiationAuthorized(component.getClass())) {
268: // then call any unauthorized component instantiation
269: // listener
270: getSecuritySettings()
271: .getUnauthorizedComponentInstantiationListener()
272: .onUnauthorizedInstantiation(component);
273: }
274: }
275: });
276: }
277:
278: /**
279: * Adds a component instantiation listener. This method should typicaly only
280: * be called during application startup; it is not thread safe.
281: * <p>
282: * Note: wicket does not guarantee the execution order of added listeners
283: *
284: * @param listener
285: * the listener to add
286: */
287: public final void addComponentInstantiationListener(
288: final IComponentInstantiationListener listener) {
289: if (listener == null) {
290: throw new IllegalArgumentException(
291: "argument listener may not be null");
292: }
293:
294: // if an instance of this listener is already present ignore this call
295: for (int i = 0; i < componentInstantiationListeners.length; i++) {
296: if (listener == componentInstantiationListeners[i]) {
297: return;
298: }
299: }
300:
301: final IComponentInstantiationListener[] newListeners = new IComponentInstantiationListener[componentInstantiationListeners.length + 1];
302: System
303: .arraycopy(componentInstantiationListeners, 0,
304: newListeners, 0,
305: componentInstantiationListeners.length);
306: newListeners[componentInstantiationListeners.length] = listener;
307: componentInstantiationListeners = newListeners;
308: }
309:
310: /**
311: * Convenience method that sets application settings to good defaults for
312: * the given configuration type (either DEVELOPMENT or DEPLOYMENT).
313: *
314: * @param configurationType
315: * The configuration type (either DEVELOPMENT or DEPLOYMENT)
316: * @see wicket.Application#configure(String, IResourceFinder)
317: */
318: public final void configure(final String configurationType) {
319: configure(configurationType, (IResourceFinder) null);
320: }
321:
322: /**
323: * Configures application settings to good defaults for the given
324: * configuration type (either DEVELOPMENT or DEPLOYMENT).
325: *
326: * @param configurationType
327: * The configuration type. Must currently be either DEVELOPMENT
328: * or DEPLOYMENT. Currently, if the configuration type is
329: * DEVELOPMENT, resources are polled for changes, component usage
330: * is checked, wicket tags are not stripped from ouput and a
331: * detailed exception page is used. If the type is DEPLOYMENT,
332: * component usage is not checked, wicket tags are stripped from
333: * output and a non-detailed exception page is used to display
334: * errors.
335: * @param resourceFinder
336: * Resource finder for looking up resources
337: */
338: public final void configure(final String configurationType,
339: final IResourceFinder resourceFinder) {
340: this .configurationType = configurationType;
341:
342: if (resourceFinder != null) {
343: getResourceSettings().setResourceFinder(resourceFinder);
344: }
345: // As long as this is public api the developermenat and deployment mode
346: // should counter act each other for all properties.
347: if (DEVELOPMENT.equalsIgnoreCase(configurationType)) {
348: getResourceSettings().setResourcePollFrequency(
349: Duration.ONE_SECOND);
350: getDebugSettings().setComponentUseCheck(true);
351: getDebugSettings().setSerializeSessionAttributes(true);
352: getMarkupSettings().setStripWicketTags(false);
353: getExceptionSettings().setUnexpectedExceptionDisplay(
354: IExceptionSettings.SHOW_EXCEPTION_PAGE);
355: getAjaxSettings().setAjaxDebugModeEnabled(true);
356: } else if (DEPLOYMENT.equalsIgnoreCase(configurationType)) {
357: getResourceSettings().setResourcePollFrequency(null);
358: getDebugSettings().setComponentUseCheck(false);
359: getDebugSettings().setSerializeSessionAttributes(false);
360: getMarkupSettings().setStripWicketTags(true);
361: getExceptionSettings().setUnexpectedExceptionDisplay(
362: IExceptionSettings.SHOW_INTERNAL_ERROR_PAGE);
363: getAjaxSettings().setAjaxDebugModeEnabled(false);
364: } else {
365: throw new IllegalArgumentException(
366: "Invalid configuration type. Must be \"development\" or \"deployment\".");
367: }
368: }
369:
370: /**
371: * Convenience method that sets application settings to good defaults for
372: * the given configuration type (either DEVELOPMENT or DEPLOYMENT).
373: *
374: * @param configurationType
375: * The configuration type (either DEVELOPMENT or DEPLOYMENT)
376: * @param resourceFolder
377: * Folder for polling resources
378: */
379: public final void configure(final String configurationType,
380: final String resourceFolder) {
381: configure(configurationType);
382: if (resourceFolder != null) {
383: getResourceSettings().addResourceFolder(resourceFolder);
384: }
385: }
386:
387: /**
388: * @return Application's ajax related settings
389: * @see IAjaxSettings
390: * @since 1.2
391: * @deprecated use {@link #getDebugSettings()} instead
392: */
393: public final IAjaxSettings getAjaxSettings() {
394: return getSettings();
395: }
396:
397: /**
398: * Gets the unique key of this application within a given context (like a
399: * web application). NOT INTENDED FOR FRAMEWORK CLIENTS.
400: *
401: * @return The unique key of this application
402: */
403: public abstract String getApplicationKey();
404:
405: /**
406: * @return Application's application-wide settings
407: * @see IApplicationSettings
408: * @since 1.2
409: */
410: public final IApplicationSettings getApplicationSettings() {
411: return getSettings();
412: }
413:
414: /**
415: * Gets the configuration mode that is currently set, either
416: * {@link #DEVELOPMENT} or {@link #DEPLOYMENT}.
417: *
418: * @return configuration
419: * @since 1.2.3
420: */
421: public String getConfigurationType() {
422: return configurationType;
423: }
424:
425: /**
426: * @return Application's debug related settings
427: * @see IDebugSettings
428: * @since 1.2
429: */
430: public final IDebugSettings getDebugSettings() {
431: return getSettings();
432: }
433:
434: /**
435: * @return Application's exception handling settings
436: * @see IExceptionSettings
437: * @since 1.2
438: */
439: public final IExceptionSettings getExceptionSettings() {
440: return getSettings();
441: }
442:
443: /**
444: * @return Wicket framework settings
445: * @see IFrameworkSettings
446: * @since 1.2
447: */
448: public final IFrameworkSettings getFrameworkSettings() {
449: return getSettings();
450: }
451:
452: /**
453: * Application subclasses must specify a home page class by implementing
454: * this abstract method.
455: *
456: * @return Home page class for this application
457: */
458: public abstract Class getHomePage();
459:
460: /**
461: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
462: *
463: * @return The markup cache associated with the application
464: */
465: public final MarkupCache getMarkupCache() {
466: return this .markupCache;
467: }
468:
469: /**
470: * @return Application's markup related settings
471: * @see IMarkupSettings
472: * @since 1.2
473: */
474: public final IMarkupSettings getMarkupSettings() {
475: return getSettings();
476: }
477:
478: /**
479: * Gets metadata for this application using the given key.
480: *
481: * @param key
482: * The key for the data
483: * @return The metadata
484: * @see MetaDataKey
485: */
486: public final Serializable getMetaData(final MetaDataKey key) {
487: return key.get(metaData);
488: }
489:
490: /**
491: * Gets the name of this application.
492: *
493: * @return The application name.
494: */
495: public final String getName() {
496: return name;
497: }
498:
499: /**
500: * @return Application's page related settings
501: * @see IPageSettings
502: * @since 1.2
503: */
504: public final IPageSettings getPageSettings() {
505: return getSettings();
506: }
507:
508: /**
509: * @return Application's request cycle related settings
510: * @see IDebugSettings
511: * @since 1.2
512: */
513: public final IRequestCycleSettings getRequestCycleSettings() {
514: return getSettings();
515: }
516:
517: /**
518: * @return Application's resources related settings
519: * @see IResourceSettings
520: * @since 1.2
521: */
522: public final IResourceSettings getResourceSettings() {
523: return getSettings();
524: }
525:
526: /**
527: * @return Application's security related settings
528: * @see ISecuritySettings
529: * @since 1.2
530: */
531: public final ISecuritySettings getSecuritySettings() {
532: return getSettings();
533: }
534:
535: /**
536: * @return Application's session related settings
537: * @see ISessionSettings
538: * @since 1.2
539: */
540: public final ISessionSettings getSessionSettings() {
541: return getSettings();
542: }
543:
544: /**
545: * Gets the facade object for working getting/ storing session instances.
546: *
547: * @return The session facade
548: */
549: public final ISessionStore getSessionStore() {
550: return sessionStore;
551: }
552:
553: /**
554: * This method is still here for backwards compatibility with 1.1 source
555: * code. The getXXXSettings() methods are now preferred. This method will be
556: * removed post 1.2 version.
557: *
558: * @return Application settings
559: *
560: * @see Application#getApplicationSettings()
561: * @see Application#getDebugSettings()
562: * @see Application#getExceptionSettings()
563: * @see Application#getMarkupSettings()
564: * @see Application#getPageSettings()
565: * @see Application#getRequestCycleSettings()
566: * @see Application#getResourceSettings()
567: * @see Application#getSecuritySettings()
568: * @see Application#getSessionSettings()
569: * @deprecated will be made private after 1.2
570: */
571: // TODO Post 1.2: Make private
572: public Settings getSettings() {
573: if (!settingsAccessible) {
574: throw new WicketRuntimeException(
575: "Use Application.init() method for configuring your application object");
576: }
577:
578: if (settings == null) {
579: settings = new Settings(this );
580: }
581: return settings;
582: }
583:
584: /**
585: * Gets the shared resources.
586: *
587: * @return The SharedResources for this application.
588: */
589: public final SharedResources getSharedResources() {
590: return sharedResources;
591: }
592:
593: /**
594: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL.
595: *
596: * Initializes wicket components.
597: */
598: public final void initializeComponents() {
599: // Load any wicket properties files we can find
600: try {
601: // Load properties files used by all libraries
602: final Enumeration resources = getClass().getClassLoader()
603: .getResources("wicket.properties");
604: while (resources.hasMoreElements()) {
605: InputStream in = null;
606: try {
607: final URL url = (URL) resources.nextElement();
608: final Properties properties = new Properties();
609: in = url.openStream();
610: properties.load(in);
611: load(properties);
612: } finally {
613: if (in != null) {
614: in.close();
615: }
616: }
617: }
618: } catch (IOException e) {
619: throw new WicketRuntimeException(
620: "Unable to load initializers file", e);
621: }
622:
623: // now call any initializers we read
624: callInitializers();
625: }
626:
627: /**
628: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL.
629: *
630: * @param target
631: */
632: public void logEventTarget(IRequestTarget target) {
633: }
634:
635: /**
636: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL.
637: *
638: * @param requestTarget
639: */
640: public void logResponseTarget(IRequestTarget requestTarget) {
641: }
642:
643: /**
644: * Removes a component instantiation listener. This method should typicaly
645: * only be called during application startup; it is not thread safe.
646: *
647: * @param listener
648: * the listener to remove
649: */
650: public final void removeComponentInstantiationListener(
651: final IComponentInstantiationListener listener) {
652: final IComponentInstantiationListener[] listeners = componentInstantiationListeners;
653: final int len = listeners.length;
654:
655: if (listener != null && len > 0) {
656: int pos = 0;
657:
658: for (pos = 0; pos < len; pos++) {
659: if (listener == listeners[pos]) {
660: break;
661: }
662: }
663:
664: if (pos < len) {
665: listeners[pos] = listeners[len - 1];
666: final IComponentInstantiationListener[] newListeners = new IComponentInstantiationListener[len - 1];
667: System.arraycopy(listeners, 0, newListeners, 0,
668: newListeners.length);
669:
670: componentInstantiationListeners = newListeners;
671: }
672: }
673: }
674:
675: /**
676: * Sets the metadata for this application using the given key. If the
677: * metadata object is not of the correct type for the metadata key, an
678: * IllegalArgumentException will be thrown. For information on creating
679: * MetaDataKeys, see {@link MetaDataKey}.
680: *
681: * @param key
682: * The singleton key for the metadata
683: * @param object
684: * The metadata object
685: * @throws IllegalArgumentException
686: * @see MetaDataKey
687: */
688: public final synchronized void setMetaData(final MetaDataKey key,
689: final Serializable object) {
690: metaData = key.set(metaData, object);
691: }
692:
693: /**
694: * Called when wicket servlet is destroyed. Overrides do not have to call
695: * super.
696: */
697: protected void destroy() {
698: callDestroyers();
699: }
700:
701: /**
702: * Gets the factory for creating session instances.
703: *
704: * @return Factory for creating session instances
705: */
706: protected abstract ISessionFactory getSessionFactory();
707:
708: /**
709: * Allows for initialization of the application by a subclass. <strong>Use
710: * this method for any application setup instead of the constructor.</strong>
711: */
712: protected void init() {
713: }
714:
715: /**
716: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
717: */
718: protected void internalDestroy() {
719: destroy();
720: applicationKeyToApplication.remove(getApplicationKey());
721: }
722:
723: /**
724: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT OVERRIDE OR
725: * CALL.
726: *
727: * Internal initialization.
728: */
729: protected void internalInit() {
730: settingsAccessible = true;
731: IPageSettings pageSettings = getPageSettings();
732: // Install default component resolvers
733: pageSettings.addComponentResolver(new ParentResolver());
734: pageSettings.addComponentResolver(new AutoComponentResolver());
735: pageSettings
736: .addComponentResolver(new MarkupInheritanceResolver());
737: pageSettings.addComponentResolver(new HtmlHeaderResolver());
738: pageSettings.addComponentResolver(new WicketLinkResolver());
739: pageSettings.addComponentResolver(new WicketMessageResolver());
740: pageSettings.addComponentResolver(new FragmentResolver());
741:
742: // Install button image resource factory
743: getResourceSettings().addResourceFactory("buttonFactory",
744: new DefaultButtonImageResourceFactory());
745:
746: String applicationKey = getApplicationKey();
747: applicationKeyToApplication.put(applicationKey, this );
748:
749: sessionStore = newSessionStore();
750: }
751:
752: /**
753: * Creates a new session facade. Is called once per application, and is
754: * typically not something clients reimplement.
755: *
756: * @return The session facade
757: */
758: protected abstract ISessionStore newSessionStore();
759:
760: /**
761: * Notifies the registered component instantiation listeners of the
762: * construction of the provided component
763: *
764: * @param component
765: * the component that is being instantiated
766: */
767: final void notifyComponentInstantiationListeners(
768: final Component component) {
769: final int len = componentInstantiationListeners.length;
770: for (int i = 0; i < len; i++) {
771: componentInstantiationListeners[i]
772: .onInstantiation(component);
773: }
774: }
775:
776: /**
777: * Construct and add initializer from the provided class name.
778: *
779: * @param className
780: */
781: private final void addInitializer(String className) {
782: IInitializer initializer = (IInitializer) Objects
783: .newInstance(className);
784: if (initializer != null) {
785: initializers.add(initializer);
786: }
787: }
788:
789: /**
790: * @param properties
791: * Properties map with names of any library destroyers in it
792: */
793: private final void callDestroyers() {
794: for (Iterator i = initializers.iterator(); i.hasNext();) {
795: IInitializer initializer = (IInitializer) i.next();
796: if (initializer instanceof IDestroyer) {
797: log.info("[" + getName() + "] destroy: " + initializer);
798: ((IDestroyer) initializer).destroy(this );
799: }
800: }
801: }
802:
803: /**
804: * @param properties
805: * Properties map with names of any library destroyers in it
806: */
807: private final void callInitializers() {
808: for (Iterator i = initializers.iterator(); i.hasNext();) {
809: IInitializer initializer = (IInitializer) i.next();
810: log.info("[" + getName() + "] init: " + initializer);
811: initializer.init(this );
812: }
813: }
814:
815: /**
816: * @param properties
817: * Properties map with names of any library initializers in it
818: */
819: private final void load(final Properties properties) {
820: addInitializer(properties.getProperty("initializer"));
821: addInitializer(properties.getProperty(getName()
822: + "-initializer"));
823: }
824: }
|