001: /*****************************************************************************
002: * Java Plug-in Framework (JPF)
003: * Copyright (C) 2004-2007 Dmitry Olshansky
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: *****************************************************************************/package org.java.plugin;
019:
020: import java.net.URL;
021: import java.security.AccessController;
022: import java.security.PrivilegedAction;
023: import java.util.Map;
024:
025: import org.java.plugin.registry.Identity;
026: import org.java.plugin.registry.PluginDescriptor;
027: import org.java.plugin.registry.PluginRegistry;
028:
029: /**
030: * JPF "runtime" class - the entry point to the framework API. It is expected
031: * that only one instance of this class will be created per application (other
032: * scenarios may be possible but not tested).
033: * <p>
034: * Usage example. Somewhere in the beginning of your application:
035: *
036: * <pre>
037: * manager = factory.createManager();
038: * manager.publishPlugins(getLocations(dir));
039: * </pre>
040: *
041: * Later on, before accessing plug-in:
042: *
043: * <pre>
044: * manager.activatePlugin(pluginId);
045: * </pre>
046: *
047: * @see org.java.plugin.ObjectFactory#createManager()
048: *
049: * @version $Id: PluginManager.java,v 1.5 2007/04/07 12:42:14 ddimon Exp $
050: */
051: public abstract class PluginManager {
052: /**
053: * JPF version number.
054: */
055: //NB: don't forget to update version number with new release
056: public static final String VERSION = "1.5.1"; //$NON-NLS-1$
057:
058: /**
059: * JPF version system property name.
060: */
061: public static final String VERSION_PROPERTY = "org.java.plugin.jpf-version"; //$NON-NLS-1$
062:
063: static {
064: try {
065: AccessController
066: .doPrivileged(new PrivilegedAction<Object>() {
067: public Object run() {
068: System.setProperty(VERSION_PROPERTY,
069: VERSION);
070: return null;
071: }
072: });
073: } catch (SecurityException se) {
074: // ignore
075: }
076: }
077:
078: /**
079: * Looks for plug-in manager instance for given object.
080: *
081: * @param obj
082: * any object that may be managed by some plug-in manager
083: * @return plug-in manager instance or <code>null</code> if given object
084: * doesn't belong to any plug-in (possibly it is part of "host"
085: * application) and thus doesn't managed by the Framework directly
086: * or indirectly.
087: */
088: public static PluginManager lookup(final Object obj) {
089: if (obj == null) {
090: return null;
091: }
092: ClassLoader clsLoader;
093: if (obj instanceof Plugin) {
094: return ((Plugin) obj).getManager();
095: } else if (obj instanceof Class) {
096: clsLoader = ((Class) obj).getClassLoader();
097: } else if (obj instanceof ClassLoader) {
098: clsLoader = (ClassLoader) obj;
099: } else {
100: clsLoader = obj.getClass().getClassLoader();
101: }
102: if (!(clsLoader instanceof PluginClassLoader)) {
103: return lookup(clsLoader.getParent());
104: }
105: return ((PluginClassLoader) clsLoader).getPluginManager();
106: }
107:
108: /**
109: * @return registry, used by this manager
110: */
111: public abstract PluginRegistry getRegistry();
112:
113: /**
114: * @return path resolver
115: */
116: public abstract PathResolver getPathResolver();
117:
118: /**
119: * Registers plug-ins and their locations with this plug-in manager. You
120: * should use this method to register new plug-ins to make them available
121: * for activation with this manager instance (compare this to
122: * {@link PluginRegistry#register(URL[])} method that just makes plug-in's
123: * meta-data available for reading and doesn't "know" where are things
124: * actually located).
125: * <p>
126: * Note that this method only load plug-ins to this manager but not activate
127: * them. Call {@link #activatePlugin(String)} method to make plug-in
128: * activated. It is recommended to do this immediately before first plug-in
129: * use.
130: *
131: * @param locations
132: * plug-in locations data
133: * @return map where keys are manifest URL's and values are registered
134: * plug-ins or plug-in fragments, URL's for unprocessed manifests
135: * are not included
136: * @throws JpfException
137: * if given plug-ins can't be registered or published (optional
138: * behavior)
139: *
140: * @see org.java.plugin.registry.PluginDescriptor
141: * @see org.java.plugin.registry.PluginFragment
142: */
143: public abstract Map<String, Identity> publishPlugins(
144: final PluginLocation[] locations) throws JpfException;
145:
146: /**
147: * Looks for plug-in with given ID and activates it if it is not activated
148: * yet. Note that this method will never return <code>null</code>.
149: *
150: * @param id
151: * plug-in ID
152: * @return found plug-in
153: * @throws PluginLifecycleException
154: * if plug-in can't be found or activated
155: */
156: public abstract Plugin getPlugin(final String id)
157: throws PluginLifecycleException;
158:
159: /**
160: * Activates plug-in with given ID if it is not activated yet. Actually this
161: * makes plug-in "running" and calls {@link Plugin#doStart()} method. This
162: * method will effectively activate all depending plug-ins. It is safe to
163: * call this method more than once.
164: *
165: * @param id
166: * plug-in ID
167: * @throws PluginLifecycleException
168: * if plug-in can't be found or activated
169: */
170: public abstract void activatePlugin(final String id)
171: throws PluginLifecycleException;
172:
173: /**
174: * Looks for plug-in, given object belongs to.
175: *
176: * @param obj
177: * any object that maybe belongs to some plug-in
178: * @return plug-in or <code>null</code> if given object doesn't belong to
179: * any plug-in (possibly it is part of "host" application) and thus
180: * doesn't managed by the Framework directly or indirectly
181: */
182: public abstract Plugin getPluginFor(final Object obj);
183:
184: /**
185: * @param descr
186: * plug-in descriptor
187: * @return <code>true</code> if plug-in with given descriptor is activated
188: */
189: public abstract boolean isPluginActivated(
190: final PluginDescriptor descr);
191:
192: /**
193: * @param descr
194: * plug-in descriptor
195: * @return <code>true</code> if plug-in disabled as it's activation fails
196: */
197: public abstract boolean isBadPlugin(final PluginDescriptor descr);
198:
199: /**
200: * @param descr
201: * plug-in descriptor
202: * @return <code>true</code> if plug-in is currently activating
203: */
204: public abstract boolean isPluginActivating(
205: final PluginDescriptor descr);
206:
207: /**
208: * Returns instance of plug-in's class loader and not tries to activate
209: * plug-in. Use this method if you need to get access to plug-in resources
210: * and don't want to cause plug-in activation.
211: *
212: * @param descr
213: * plug-in descriptor
214: * @return class loader instance for plug-in with given descriptor
215: */
216: public abstract PluginClassLoader getPluginClassLoader(
217: final PluginDescriptor descr);
218:
219: /**
220: * Shuts down the framework. <br>
221: * Calling this method will deactivate all active plug-ins in order, reverse
222: * to the order they was activated. It also releases all resources allocated
223: * by this manager (class loaders, plug-in descriptors etc.). All disabled
224: * plug-ins will be marked as "enabled", all registered event listeners will
225: * be unregistered.
226: */
227: public abstract void shutdown();
228:
229: /**
230: * Deactivates plug-in with given ID if it has been successfully activated
231: * before. This method makes plug-in "not running" and calls
232: * {@link Plugin#doStop()} method. Note that this method will effectively
233: * deactivate all depending plug-ins.
234: *
235: * @param id
236: * plug-in ID
237: */
238: public abstract void deactivatePlugin(final String id);
239:
240: /**
241: * Disables plug-in (with dependencies) in this manager instance. Disabled
242: * plug-in can't be activated although it may be valid and successfully
243: * registered with plug-in registry. Before disabling, plug-in will be
244: * deactivated if it was successfully activated.
245: * <p>
246: * Be careful with this method as it can effectively disable large set of
247: * inter-depending plug-ins and your application may become unstable or even
248: * disabled as whole.
249: *
250: * @param descr
251: * descriptor of plug-in to be disabled
252: * @return descriptors of plug-ins that was actually disabled
253: */
254: public abstract PluginDescriptor[] disablePlugin(
255: final PluginDescriptor descr);
256:
257: /**
258: * Enables plug-in (or plug-ins) in this manager instance. Don't miss this
259: * with plug-in activation semantic. Enabled plug-in is simply ready to be
260: * activated. By default all loaded plug-ins are enabled.
261: *
262: * @param descr
263: * descriptor of plug-in to be enabled
264: * @param includeDependings
265: * if <code>true</code>, depending plug-ins will be also
266: * enabled
267: * @return descriptors of plug-ins that was actually enabled
268: * @see #disablePlugin(PluginDescriptor)
269: */
270: public abstract PluginDescriptor[] enablePlugin(
271: final PluginDescriptor descr,
272: final boolean includeDependings);
273:
274: /**
275: * @param descr
276: * plug-in descriptor
277: * @return <code>true</code> if given plug-in is disabled in this manager
278: */
279: public abstract boolean isPluginEnabled(final PluginDescriptor descr);
280:
281: /**
282: * Registers plug-in manager event listener. If given listener has been
283: * registered before, this method will throw an
284: * {@link IllegalArgumentException}.
285: *
286: * @param listener
287: * new manager event listener
288: */
289: public abstract void registerListener(final EventListener listener);
290:
291: /**
292: * Unregisters manager event listener. If given listener hasn't been
293: * registered before, this method will throw an
294: * {@link IllegalArgumentException}.
295: *
296: * @param listener
297: * registered listener
298: */
299: public abstract void unregisterListener(final EventListener listener);
300:
301: // Delegating methods
302:
303: /**
304: * Initializes given plug-in with this manager instance and given
305: * descriptor.
306: *
307: * @param plugin
308: * plug-in instance to be initialized
309: * @param descr
310: * plug-in descriptor
311: */
312: protected final void initPlugin(final Plugin plugin,
313: final PluginDescriptor descr) {
314: plugin.setManager(this );
315: plugin.setDescriptor(descr);
316: }
317:
318: /**
319: * Starts given plug-in. Simply forward call to {@link Plugin#doStart()}
320: * method.
321: *
322: * @param plugin
323: * plug-in to be started
324: * @throws Exception
325: * if any error has occurred during plug-in start
326: */
327: protected final void startPlugin(final Plugin plugin)
328: throws Exception {
329: plugin.start();
330: }
331:
332: /**
333: * Stops given plug-in. Simply forward call to {@link Plugin#doStop()}
334: * method.
335: *
336: * @param plugin
337: * plug-in to be stopped
338: * @throws Exception
339: * if any error has occurred during plug-in stop
340: */
341: protected final void stopPlugin(final Plugin plugin)
342: throws Exception {
343: plugin.stop();
344: }
345:
346: /**
347: * Forwards call to {@link PluginClassLoader#dispose()} method.
348: *
349: * @param cl
350: * plug-in class loader to be disposed
351: */
352: protected final void disposeClassLoader(final PluginClassLoader cl) {
353: cl.dispose();
354: }
355:
356: /**
357: * Forwards call to {@link PluginClassLoader#pluginsSetChanged()} method.
358: *
359: * @param cl
360: * plug-in class loader to be notified
361: */
362: protected final void notifyClassLoader(final PluginClassLoader cl) {
363: cl.pluginsSetChanged();
364: }
365:
366: /**
367: * Plug-ins life-cycle events callback interface.
368: *
369: * @version $Id: PluginManager.java,v 1.5 2007/04/07 12:42:14 ddimon Exp $
370: */
371: public interface EventListener {
372: /**
373: * This method will be called by the manager just after plug-in has been
374: * successfully activated.
375: *
376: * @param plugin
377: * just activated plug-in
378: */
379: void pluginActivated(Plugin plugin);
380:
381: /**
382: * This method will be called by the manager just before plug-in
383: * deactivation.
384: *
385: * @param plugin
386: * plug-in to be deactivated
387: */
388: void pluginDeactivated(Plugin plugin);
389:
390: /**
391: * This method will be called by the manager just before plug-in
392: * disabling.
393: *
394: * @param descriptor
395: * descriptor of plug-in to be disabled
396: */
397: void pluginDisabled(PluginDescriptor descriptor);
398:
399: /**
400: * This method will be called by the manager just after plug-in
401: * enabling.
402: *
403: * @param descriptor
404: * descriptor of enabled plug-in
405: */
406: void pluginEnabled(PluginDescriptor descriptor);
407: }
408:
409: /**
410: * An abstract adapter class for receiving plug-ins life-cycle events. The
411: * methods in this class are empty. This class exists as convenience for
412: * creating listener objects.
413: *
414: * @version $Id: PluginManager.java,v 1.5 2007/04/07 12:42:14 ddimon Exp $
415: */
416: public abstract static class EventListenerAdapter implements
417: EventListener {
418: /**
419: * @see org.java.plugin.PluginManager.EventListener#pluginActivated(
420: * org.java.plugin.Plugin)
421: */
422: public void pluginActivated(final Plugin plugin) {
423: // no-op
424: }
425:
426: /**
427: * @see org.java.plugin.PluginManager.EventListener#pluginDeactivated(
428: * org.java.plugin.Plugin)
429: */
430: public void pluginDeactivated(final Plugin plugin) {
431: // no-op
432: }
433:
434: /**
435: * @see org.java.plugin.PluginManager.EventListener#pluginDisabled(
436: * org.java.plugin.registry.PluginDescriptor)
437: */
438: public void pluginDisabled(final PluginDescriptor descriptor) {
439: // no-op
440: }
441:
442: /**
443: * @see org.java.plugin.PluginManager.EventListener#pluginEnabled(
444: * org.java.plugin.registry.PluginDescriptor)
445: */
446: public void pluginEnabled(final PluginDescriptor descriptor) {
447: // no-op
448: }
449: }
450:
451: /**
452: * Simple callback interface to hold info about plug-in manifest and plug-in
453: * data locations.
454: *
455: * @version $Id: PluginManager.java,v 1.5 2007/04/07 12:42:14 ddimon Exp $
456: */
457: public static interface PluginLocation {
458: /**
459: * @return location of plug-in manifest
460: */
461: URL getManifestLocation();
462:
463: /**
464: * @return location of plug-in context ("home")
465: */
466: URL getContextLocation();
467: }
468: }
|