001: package org.objectweb.celtix.application;
002:
003: import java.text.MessageFormat;
004: import java.util.ArrayList;
005: import java.util.List;
006: import java.util.logging.Level;
007: import java.util.logging.Logger;
008:
009: import org.objectweb.celtix.common.i18n.Message;
010: import org.objectweb.celtix.common.logging.LogUtils;
011: import org.objectweb.celtix.configuration.Configuration;
012: import org.objectweb.celtix.plugins.PluginException;
013: import org.objectweb.celtix.plugins.PluginManager;
014:
015: /**
016: * @author asmyth The ApplicationPluginManager manages objects loaded on demand
017: * in response to a getPlugin request. The loading of one pluggable
018: * object may require explicitly loading dependent objects. Such
019: * dependencies are always specified by plugin name (as otherwise they
020: * can trivially be resolved by the clasloader). Circular dependencies
021: * are not allowed and will cause a PluginException. Plugins may be
022: * unloaded after they have been explicitly unregistered.
023: */
024: public class ApplicationPluginManager implements PluginManager {
025:
026: private static final Logger LOG = LogUtils
027: .getL7dLogger(ApplicationPluginManager.class);
028:
029: private static final MessageFormat PLUGINS_CLASSNAME_FMT = new MessageFormat(
030: "plugins:{0}:className");
031:
032: private static final MessageFormat PLUGINS_PREREQUISITES_FMT = new MessageFormat(
033: "plugins:{0}:prerequisites");
034:
035: private final List<PluginInfo> plugins;
036:
037: public ApplicationPluginManager() {
038: plugins = new ArrayList<PluginInfo>();
039: }
040:
041: /*
042: * (non-Javadoc)
043: *
044: * @see org.objectweb.celtix.plugins.PluginManager#getPlugin(java.lang.String)
045: */
046: public Object getPlugin(String className) throws PluginException {
047: return getPlugin(null, className, null);
048: }
049:
050: /*
051: * (non-Javadoc)
052: *
053: * @see org.objectweb.celtix.plugins.PluginManager#getPluginByName(java.lang.String)
054: */
055: public Object getPluginByName(String pluginName)
056: throws PluginException {
057: return getPluginByName(pluginName, null);
058: }
059:
060: /*
061: * (non-Javadoc)
062: *
063: * @see org.objectweb.celtix.plugins.PluginManager#registerPlugin(org.objectweb.celtix.plugins.Plugin)
064: */
065: public synchronized void registerPlugin(Object plugin)
066: throws PluginException {
067: PluginInfo info = findPluginInfo(plugin);
068: if (info.isRegisteredWith(this )) {
069: throw new PluginException(new Message(
070: "ALREADY_REGISTERED_EXC", LOG, info.getClassName()));
071: } else {
072: info.register(this );
073: }
074: }
075:
076: /*
077: * (non-Javadoc)
078: *
079: * @see org.objectweb.celtix.plugins.PluginManager#unloadPlugin(java.lang.String)
080: */
081: public synchronized void unloadPlugin(Object plugin)
082: throws PluginException {
083: PluginInfo info = findPluginInfo(plugin);
084: if (info.isRegistered()) {
085: throw new PluginException(new Message(
086: "STILL_REGISTERED_EXC", LOG, info.getClassName()));
087: } else {
088: plugins.remove(plugin);
089: info = null;
090: }
091: }
092:
093: /*
094: * (non-Javadoc)
095: *
096: * @see org.objectweb.celtix.plugins.PluginManager#unregisterPlugin(java.lang.String)
097: */
098: public synchronized void unregisterPlugin(Object plugin)
099: throws PluginException {
100: PluginInfo info = findPluginInfo(plugin);
101: if (info.isRegisteredWith(this )) {
102: info.unregister(this );
103: } else {
104: throw new PluginException(new Message("NOT_REGISTERED_EXC",
105: LOG, info.getClassName()));
106: }
107: }
108:
109: /*
110: * (non-Javadoc)
111: *
112: * @see org.objectweb.celtix.plugins.PluginManager#getPluginClassLoader()
113: */
114: public ClassLoader getPluginClassLoader() {
115: return getClass().getClassLoader();
116: }
117:
118: /* (non-Javadoc)
119: * @see org.objectweb.celtix.plugins.PluginManager#getConfiguration()
120: */
121: public Configuration getConfiguration() {
122: return Application.getInstance().getConfiguration();
123: }
124:
125: Object getPluginByName(String pluginName, PluginInfo dependent)
126: throws PluginException {
127: String key = PLUGINS_CLASSNAME_FMT.format(pluginName);
128: Configuration configuration = getConfiguration();
129: String pluginClassName = (String) configuration.getObject(key);
130:
131: return getPlugin(pluginName, pluginClassName, dependent);
132: }
133:
134: Object getPlugin(String pluginName, String pluginClassName,
135: PluginInfo dependent) throws PluginException {
136: LOG.entering(getClass().getName(), "getPlugin");
137: PluginInfo info = null;
138: PluginStateMachine state = null;
139: synchronized (this ) {
140: info = findPluginByClassname(pluginClassName);
141: if (info == null) {
142: info = new PluginInfo(pluginClassName, this );
143: plugins.add(info);
144: }
145: state = info.getState();
146: if (PluginStateMachine.PluginState.LOADING == state
147: .getCurrentState()) {
148: state
149: .waitForState(PluginStateMachine.PluginState.LOADED);
150: LOG.exiting(getClass().getName(), "getPlugin",
151: "object currently being loaded");
152: return info.getPlugin();
153: } else if (PluginStateMachine.PluginState.LOADED == state
154: .getCurrentState()) {
155: LOG.exiting(getClass().getName(), "getPlugin",
156: "object already loaded");
157: return info.getPlugin();
158: }
159: state.setNextState(PluginStateMachine.PluginState.LOADING);
160: }
161:
162: // check for circular dependencies
163:
164: if (dependent != null) {
165: info.setRequiredFor(dependent);
166: if (info.isCircularDependency()) {
167: throw new PluginException(
168: new Message("CIRCULAR_DEPENDENCY_EXC", LOG,
169: pluginClassName));
170: }
171: }
172:
173: if (null != pluginName) {
174: Configuration configuration = getConfiguration();
175:
176: String key = PLUGINS_PREREQUISITES_FMT.format(pluginName);
177: String[] prerequisites = (String[]) configuration
178: .getObject(key);
179:
180: if (prerequisites != null) {
181: for (String p : prerequisites) {
182: getPluginByName(p, info);
183: }
184: }
185: }
186:
187: Object plugin = createPlugin(pluginClassName);
188: info.setPlugin(plugin);
189: state.setNextState(PluginStateMachine.PluginState.LOADED);
190: LOG.exiting(getClass().getName(), "getPlugin",
191: "object newly created");
192: return plugin;
193: }
194:
195: Object createPlugin(String pluginClassName) throws PluginException {
196:
197: ClassLoader cl = getPluginClassLoader();
198: Object plugin = null;
199: try {
200: Class<?> pluginClass = Class.forName(pluginClassName, true,
201: cl);
202: plugin = pluginClass.newInstance();
203: } catch (Exception ex) {
204: LogUtils.log(LOG, Level.SEVERE, "PLUGIN_LOAD_FAILURE_MSG",
205: ex, pluginClassName);
206: throw new PluginException(new Message("LOAD_FAILED_EXC",
207: LOG, pluginClassName), ex);
208: }
209: return plugin;
210: }
211:
212: PluginInfo findPluginByClassname(String className) {
213: for (PluginInfo info : plugins) {
214: if (info.getClassName().equals(className)
215: && info.getClassLoader() == getPluginClassLoader()) {
216: return info;
217: }
218: }
219: LOG.info("Could not find plugin info for class " + className);
220: return null;
221: }
222:
223: PluginInfo findPluginInfo(Object plugin) {
224:
225: for (PluginInfo info : plugins) {
226: if (plugin == info.getPlugin()) {
227: return info;
228: }
229: }
230: LOG.info("Could not find plugin info for plugin " + plugin);
231: return null;
232: }
233: }
|