View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of CosyBeans.
5    *
6    * CosyBeans is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * CosyBeans is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with CosyBeans.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.application;
21  
22  import java.util.ArrayList;
23  import java.util.HashSet;
24  
25  import com.cosylab.util.ObjectList;
26  
27  
28  /**
29   * Deafultimplementation of a <code>PlugInManager</code> interface.
30   *
31   * @author Igor Kriznar (<a
32   *         href="mailto:igor.kriznar@cosylab.com">igor.kriznar&x40;cosylab.com</a>)
33   * @version $$id$$
34   */
35  public class DefaultPlugInManager implements PlugInManager
36  {
37  	private String name= "DefaultPlugInManager";
38  	private ApplicationPanel parent;
39  	private boolean destroyed = false;
40  	private ArrayList<PlugIn> plugins = new ArrayList<PlugIn>();
41  	private HashSet<Class> cyclicPlugIn = new HashSet<Class>();
42  	private ObjectList listeners = new ObjectList(PlugInListener.class);
43  
44  	/**
45  	 * A default constructor for the plug-in manager.
46  	 */
47  	public DefaultPlugInManager()
48  	{
49  	}
50  
51  	/**
52  	 * Returns the parent of this manager.
53  	 *
54  	 * @return the logical parent of this
55  	 */
56  	public ApplicationPanel getOwnerPanel()
57  	{
58  		return parent;
59  	}
60  
61  	/**
62  	 * Returns <code>true</code> iff this panel has been destroyed.
63  	 *
64  	 * @return boolean <code>true</code> if destroyed
65  	 */
66  	public final synchronized boolean isDestroyed()
67  	{
68  		return destroyed;
69  	}
70  
71  	/**
72  	 * Destroys this cosy panel. If already destroyed, this method returns NOP.
73  	 * If plugin has visual component, first is from parent removed plugins
74  	 * visual component, tha is plugin destroyed.
75  	 * 
76  	 * <p>
77  	 * All plug-ins are destroyed before managers <code>destroyed</code> flag
78  	 * is set to <code>true</code> and destruction completes.
79  	 * </p>
80  	 */
81  	public synchronized final void destroy()
82  	{
83  		if (destroyed) {
84  			return;
85  		}
86  
87  		PlugIn[] pl = getPlugIns();
88  
89  		for (int i = 0; i < pl.length; i++) {
90  			try {
91  				if (pl[i] instanceof VisiblePlugIn) {
92  					getOwnerPanel().removePlugInGUI((VisiblePlugIn)pl[i]);
93  				}
94  			} catch (Exception e) {
95  				// notify
96  			}
97  
98  			try {
99  				pl[i].destroy();
100 			} catch (Exception e) {
101 				// notify
102 			}
103 			plugins.clear();
104 		}
105 
106 		destroyed = true;
107 	}
108 
109 	/**
110 	 * Installs a new plugin. Checks if the <code>plugType</code> parameter is
111 	 * valid, otherwise a <code>PlugInException</code> is thrown; checks if
112 	 * the state of this object is valid;  checks if the cyclic installation
113 	 * is occuring; checks if the plug has already been  installed. If all
114 	 * these checks are passed, a new instance of the plugin is created, added
115 	 * as a child of this cosy panel, and the <code>installPlugIn</code>
116 	 * method of the plugin is invoked. If it completes successfully, the cosy
117 	 * listeners are notified about the  new plugin. If it fails, the plugin
118 	 * is removed from the cosy component children of this panel.
119 	 *
120 	 * @param plugType the class representing the plug, which must implement
121 	 *        <code>PlugIn</code> interface
122 	 *
123 	 * @exception PlugInException if the plug installation fails
124 	 * @throws NullPointerException if input is null
125 	 * @throws IllegalStateException if no parent is set
126 	 *
127 	 * @see PlugInManager#installPlugIn(Class)
128 	 */
129 	public final synchronized void installPlugIn(Class plugType)
130 		throws PlugInException
131 	{
132 		if (plugType == null) {
133 			throw new NullPointerException("plugType");
134 		}
135 
136 		if (isDestroyed()) {
137 			return;
138 		}
139 
140 		if (parent == null) {
141 			throw new IllegalStateException("parent == null");
142 		}
143 
144 		// check plug type
145 		if (!PlugIn.class.isAssignableFrom(plugType)) {
146 			throw new PlugInException(this,
147 			    "Class '" + plugType.getName() + "' does not implement '"
148 			    + PlugIn.class.getName() + "'.", plugType, null);
149 		}
150 
151 		// check if already installed
152 		if (getPlugIn(plugType) != null) {
153 			return;
154 		}
155 
156 		// check cyclic resolver
157 		if (cyclicPlugIn.contains(plugType)) {
158 			throw new PlugInException(this,
159 			    "Cyclic plugin dependency: cannot instantiate without causing endless loop",
160 			    plugType, null);
161 		}
162 
163 		cyclicPlugIn.add(plugType);
164 
165 		// instantiate plug
166 		PlugIn plugIn = null;
167 
168 		try {
169 			plugIn = (PlugIn)plugType.newInstance();
170 		} catch (Exception e) {
171 			throw new PlugInException(this,
172 			    "Could not invoke the plugin constructor.", plugType, e);
173 		}
174 
175 		// add to this container
176 		plugins.add(plugIn);
177 
178 		// initialize plug
179 		try {
180 			plugIn.installPlugIn(this);
181 		} catch (Exception e) {
182 			// remove from the container
183 			plugins.remove(plugIn);
184 			throw new PlugInException(this,
185 			    "Exception while installing the plugin", plugType, e);
186 		} finally {
187 			// remove from cyclic resolution list 
188 			cyclicPlugIn.remove(plugType);
189 		}
190 
191 		// notify listeners
192 		PlugInListener[] l = (PlugInListener[])listeners.toArray();
193 		PlugInEvent event = new PlugInEvent(this, plugIn);
194 
195 		for (int i = 0; i < l.length; i++) {
196 			try {
197 				l[i].plugInInstalled(event);
198 			} catch (Exception e) {
199 				e.printStackTrace();
200 			}
201 		}
202 	}
203 
204 	/**
205 	 * Returns all plugins managed by this cosy component.
206 	 *
207 	 * @return PlugIn[] a list of plug ins
208 	 *
209 	 * @see PlugInManager#getPlugIns()
210 	 */
211 	public synchronized PlugIn[] getPlugIns()
212 	{
213 		return plugins.toArray(new PlugIn[plugins.size()]);
214 	}
215 
216 	/**
217 	 * Returns a plugin with a given type. Since plugins are installed by their
218 	 * type and installations with the same type are not allowed, the
219 	 * designation by type is unique.
220 	 *
221 	 * @param plugType the type of the plug to look up
222 	 *
223 	 * @return PlugIn the plugin instance of <code>null</code> if no plugin
224 	 *         with the specified type was found
225 	 *
226 	 * @throws NullPointerException if input  is null
227 	 *
228 	 * @see PlugInManager#getPlugIn(Class)
229 	 */
230 	public PlugIn getPlugIn(Class plugType)
231 	{
232 		if (plugType == null) {
233 			throw new NullPointerException("plugType");
234 		}
235 
236 		PlugIn[] array = getPlugIns();
237 
238 		for (int i = 0; i < array.length; i++) {
239 			if (array[i].getClass().equals(plugType)) {
240 				return array[i];
241 			}
242 		}
243 
244 		return null;
245 	}
246 
247 	/**
248 	 * Adds a plugin listener.
249 	 *
250 	 * @param l a listener object
251 	 *
252 	 * @see PlugInManager#addPlugInListener(PlugInListener)
253 	 */
254 	public void addPlugInListener(PlugInListener l)
255 	{
256 		listeners.add(l);
257 	}
258 
259 	/**
260 	 * Removes a plugin listener.
261 	 *
262 	 * @param l a listener object
263 	 *
264 	 * @see PlugInManager#removePlugInListener(PlugInListener)
265 	 */
266 	public void removePlugInListener(PlugInListener l)
267 	{
268 		listeners.remove(l);
269 	}
270 
271 	/**
272 	 * Returns a list of all plugin listeners, as required by Java 1.4 Beans
273 	 * specs.
274 	 *
275 	 * @return PlugInListener[] an array of listeners
276 	 *
277 	 * @see PlugInManager#getPlugInListeners()
278 	 */
279 	public PlugInListener[] getPlugInListeners()
280 	{
281 		return (PlugInListener[])listeners.toArray();
282 	}
283 
284 	/**
285 	 * Removes plugin from meneger. First removes plugin visual component from
286 	 * parent, then calls destroy() and then sets parent to null.
287 	 *
288 	 * @see com.cosylab.gui.core.PlugInManager#removePlugIn(java.lang.Class)
289 	 */
290 	public void removePlugIn(Class plugType)
291 	{
292 		if (plugType == null) {
293 			throw new NullPointerException("plugType");
294 		}
295 
296 		if (isDestroyed()) {
297 			return;
298 		}
299 
300 		if (parent == null) {
301 			throw new IllegalStateException("parent == null");
302 		}
303 
304 		PlugIn plugIn = getPlugIn(plugType);
305 
306 		if (plugIn == null) {
307 			return;
308 		}
309 
310 		plugins.remove(plugIn);
311 
312 		// remove plug
313 		try {
314 			if (plugIn instanceof VisiblePlugIn) {
315 				getOwnerPanel().removePlugInGUI((VisiblePlugIn)plugIn);
316 			}
317 
318 			plugIn.destroy();
319 		} catch (Exception e) {
320 			//  we should not throw further
321 			e.printStackTrace();
322 		}
323 
324 		// notify listeners
325 		PlugInListener[] l = (PlugInListener[])listeners.toArray();
326 		PlugInEvent event = new PlugInEvent(this, plugIn);
327 
328 		for (int i = 0; i < l.length; i++) {
329 			try {
330 				l[i].plugInRemoved(event);
331 			} catch (Exception e) {
332 				e.printStackTrace();
333 			}
334 		}
335 	}
336 
337 	/**
338 	 * Sets logical parent to this manager.
339 	 *
340 	 * @see com.cosylab.gui.core.CosyComponent#setCosyPanelParent(com.cosylab.gui.core.CosyApplicationPanel)
341 	 */
342 	public void setOwnerPanel(ApplicationPanel panel)
343 	{
344 		this.parent = panel;
345 	}
346 
347 	/* (non-Javadoc)
348 	 * @see com.cosylab.gui.core.CosyComponent#getName()
349 	 */
350 	public String getName()
351 	{
352 		return name;
353 	}
354 	/* (non-Javadoc)
355 	 * @see com.cosylab.gui.core.PlugInManager#acquirePlugIn(java.lang.Class)
356 	 */
357 	public PlugIn acquirePlugIn(Class plugType) throws PlugInException {
358 		PlugIn pl= getPlugIn(plugType);
359 		if (pl==null) installPlugIn(plugType);
360 		return getPlugIn(plugType);
361 	}
362 
363 }
364 
365 /* __oOo__ */