GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / commons / org / codehaus / groovy / grails / plugins / DefaultGrailsPlugin.java
blob2537c0c49cd626004076eb607624ac48c43a171f
1 /*
2 * Copyright 2004-2005 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.codehaus.groovy.grails.plugins;
18 import grails.spring.BeanBuilder;
19 import grails.util.GrailsUtil;
20 import groovy.lang.*;
21 import groovy.util.slurpersupport.GPathResult;
22 import org.apache.commons.lang.ArrayUtils;
23 import org.apache.commons.lang.StringUtils;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.codehaus.groovy.grails.commons.ArtefactHandler;
27 import org.codehaus.groovy.grails.commons.GrailsApplication;
28 import org.codehaus.groovy.grails.commons.GrailsClassUtils;
29 import org.codehaus.groovy.grails.commons.GrailsResourceUtils;
30 import org.codehaus.groovy.grails.commons.spring.RuntimeSpringConfiguration;
31 import org.codehaus.groovy.grails.compiler.GrailsClassLoader;
32 import org.codehaus.groovy.grails.compiler.support.GrailsResourceLoader;
33 import org.codehaus.groovy.grails.compiler.support.GrailsResourceLoaderHolder;
34 import org.codehaus.groovy.grails.plugins.exceptions.PluginException;
35 import org.codehaus.groovy.grails.support.ParentApplicationContextAware;
36 import org.springframework.beans.BeanWrapper;
37 import org.springframework.beans.BeanWrapperImpl;
38 import org.springframework.context.ApplicationContext;
39 import org.springframework.core.io.Resource;
40 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
42 import java.io.IOException;
43 import java.io.File;
44 import java.lang.reflect.Modifier;
45 import java.net.URL;
46 import java.net.URLConnection;
47 import java.util.*;
49 /**
50 * Implementation of the GrailsPlugin interface that wraps a Groovy plugin class
51 * and provides the magic to invoke its various methods from Java
53 * @author Graeme Rocher
54 * @since 0.4
57 public class DefaultGrailsPlugin extends AbstractGrailsPlugin implements GrailsPlugin, ParentApplicationContextAware {
59 private static final String PLUGIN_CHANGE_EVENT_CTX = "ctx";
60 private static final String PLUGIN_CHANGE_EVENT_APPLICATION = "application";
61 private static final String PLUGIN_CHANGE_EVENT_PLUGIN = "plugin";
62 private static final String PLUGIN_CHANGE_EVENT_SOURCE = "source";
63 private static final String PLUGIN_CHANGE_EVENT_MANAGER = "manager";
64 private static final String PLUGIN_LOAD_AFTER_NAMES = "loadAfter";
66 private static final String PLUGIN_OBSERVE = "observe";
67 private static final Log LOG = LogFactory.getLog(DefaultGrailsPlugin.class);
68 private GrailsPluginClass pluginGrailsClass;
69 private GroovyObject plugin;
71 protected BeanWrapper pluginBean;
72 private Closure onChangeListener;
73 private Resource[] watchedResources = new Resource[0];
74 private long[] modifiedTimes = new long[0];
76 private PathMatchingResourcePatternResolver resolver;
77 private String[] resourcesReferences;
78 private int[] resourceCount;
79 private String[] loadAfterNames = new String[0];
80 private String[] influencedPluginNames = new String[0];
81 private String status = STATUS_ENABLED;
82 private String[] observedPlugins;
83 private long pluginLastModified = Long.MAX_VALUE;
84 private URL pluginUrl;
85 private Closure onConfigChangeListener;
86 private Closure onShutdownListener;
87 private Class[] providedArtefacts = new Class[0];
90 public DefaultGrailsPlugin(Class pluginClass, Resource resource, GrailsApplication application) {
91 super(pluginClass, application);
92 // create properties
93 this.dependencies = Collections.EMPTY_MAP;
94 this.resolver = new PathMatchingResourcePatternResolver();
95 if(resource != null) {
96 try {
97 pluginUrl = resource.getURL();
98 this.pluginLastModified = pluginUrl
99 .openConnection()
100 .getLastModified();
101 } catch (IOException e) {
102 LOG.warn("I/O error reading last modified date of plug-in ["+pluginClass+"], you won't be able to reload changes: " + e.getMessage(),e);
107 initialisePlugin(pluginClass);
110 private void initialisePlugin(Class pluginClass) {
111 this.pluginGrailsClass = new GrailsPluginClass(pluginClass);
112 this.plugin = (GroovyObject)this.pluginGrailsClass.newInstance();
113 this.pluginBean = new BeanWrapperImpl(this.plugin);
115 // configure plugin
116 evaluatePluginVersion();
117 evaluatePluginDependencies();
118 evaluatePluginLoadAfters();
119 evaluateProvidedArtefacts();
120 evaluatePluginEvictionPolicy();
121 evaluatePluginInfluencePolicy();
122 evaluateOnChangeListener();
123 evaluateObservedPlugins();
124 evaluatePluginStatus();
127 private void evaluateProvidedArtefacts() {
128 Object providedArtefacts = GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, PROVIDED_ARTEFACTS);
129 if(providedArtefacts instanceof Collection) {
130 final Collection artefactList = (Collection) providedArtefacts;
131 this.providedArtefacts = (Class[])artefactList.toArray(new Class[artefactList.size()]);
135 public DefaultGrailsPlugin(Class pluginClass, GrailsApplication application) {
136 this(pluginClass, null,application);
139 private void evaluateObservedPlugins() {
140 if(this.pluginBean.isReadableProperty(PLUGIN_OBSERVE)) {
141 Object observeProperty = GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, PLUGIN_OBSERVE);
142 if(observeProperty instanceof Collection) {
143 Collection observeList = (Collection)observeProperty;
144 observedPlugins = new String[observeList.size()];
145 int j = 0;
146 for (Iterator i = observeList.iterator(); i.hasNext();) {
147 String pluginName = i.next().toString();
148 observedPlugins[j++] = pluginName;
152 if(observedPlugins == null) observedPlugins = new String[0];
155 private void evaluatePluginStatus() {
156 if(this.pluginBean.isReadableProperty(STATUS)) {
157 Object statusObj = GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, STATUS);
158 if(statusObj != null) {
159 this.status = statusObj.toString().toLowerCase();
164 private void evaluateOnChangeListener() {
165 if(this.pluginBean.isReadableProperty(ON_CONFIG_CHANGE)) {
166 this.onConfigChangeListener = (Closure)GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, ON_CONFIG_CHANGE);
168 if(this.pluginBean.isReadableProperty(ON_SHUTDOWN)) {
169 this.onShutdownListener= (Closure)GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, ON_SHUTDOWN);
171 if(this.pluginBean.isReadableProperty(ON_CHANGE)) {
172 this.onChangeListener = (Closure) GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, ON_CHANGE);
173 Object referencedResources = GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, WATCHED_RESOURCES);
176 try {
177 List resourceList = null;
178 if(referencedResources instanceof String) {
179 if(LOG.isDebugEnabled()) {
180 LOG.debug("Configuring plugin "+this+" to watch resources with pattern: " + referencedResources);
182 resourceList = new ArrayList();
183 resourceList.add(referencedResources.toString());
185 else if(referencedResources instanceof List) {
186 resourceList = (List)referencedResources;
189 if(resourceList!=null) {
191 this.resourcesReferences = new String[resourceList.size()];
192 this.resourceCount = new int[resourceList.size()];
193 for (int i = 0; i < resourcesReferences.length; i++) {
194 String resRef = resourceList.get(i).toString();
195 resourcesReferences[i]=resRef;
197 for (int i = 0; i < resourcesReferences.length; i++) {
198 String res = resourcesReferences[i];
199 Resource[] tmp = resolver.getResources(res);
200 resourceCount[i] = tmp.length;
202 if(LOG.isDebugEnabled()) {
203 LOG.debug("Watching resource set ["+(i+1)+"]: " + ArrayUtils.toString(tmp));
205 if(tmp.length == 0)
206 tmp = resolver.getResources("classpath*:" + res);
208 if(tmp.length > 0){
209 watchedResources = (Resource[])ArrayUtils.addAll(this.watchedResources, tmp);
215 catch (IllegalArgumentException e) {
216 if(GrailsUtil.isDevelopmentEnv())
217 LOG.debug("Cannot load plug-in resource watch list from ["+ ArrayUtils.toString(resourcesReferences) +"]. This means that the plugin "+this+", will not be able to auto-reload changes effectively. Try runnng grails upgrade.: " + e.getMessage());
219 catch (IOException e) {
220 if(GrailsUtil.isDevelopmentEnv())
221 LOG.debug("Cannot load plug-in resource watch list from ["+ ArrayUtils.toString(resourcesReferences) +"]. This means that the plugin "+this+", will not be able to auto-reload changes effectively. Try runnng grails upgrade.: " + e.getMessage());
223 if(LOG.isDebugEnabled()) {
224 LOG.debug("Plugin "+this+" found ["+watchedResources.length+"] to watch");
226 try {
227 initializeModifiedTimes();
228 } catch (IOException e) {
229 LOG.warn("I/O exception initializing modified times for watched resources: " + e.getMessage(), e);
235 private void evaluatePluginInfluencePolicy() {
236 if(this.pluginBean.isReadableProperty(INFLUENCES)) {
237 List influencedList = (List)this.pluginBean.getPropertyValue(INFLUENCES);
238 if(influencedList != null) {
239 this.influencedPluginNames = (String[])influencedList.toArray(new String[influencedList.size()]);
244 private void evaluatePluginVersion() {
245 if(this.pluginBean.isReadableProperty(VERSION)) {
246 Object vobj = this.plugin.getProperty(VERSION);
247 if(vobj != null)
248 this.version = vobj.toString();
249 else
250 throw new PluginException("Plugin "+this+" must specify a version. eg: def version = 0.1");
252 else {
253 throw new PluginException("Plugin ["+getName()+"] must specify a version!");
257 private void evaluatePluginEvictionPolicy() {
258 if(this.pluginBean.isReadableProperty(EVICT)) {
259 List pluginsToEvict = (List) GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, EVICT);
260 if(pluginsToEvict != null) {
261 this.evictionList = new String[pluginsToEvict.size()];
262 int index = 0;
263 for (Iterator i = pluginsToEvict.iterator(); i.hasNext();) {
264 Object o = i.next();
265 evictionList[index++] = o != null ? o.toString() : "";
271 private void evaluatePluginLoadAfters() {
272 if(this.pluginBean.isReadableProperty(PLUGIN_LOAD_AFTER_NAMES)) {
273 List loadAfterNamesList = (List) GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, PLUGIN_LOAD_AFTER_NAMES);
274 if(loadAfterNamesList != null) {
275 this.loadAfterNames = (String[])loadAfterNamesList.toArray(new String[loadAfterNamesList.size()]);
280 private void evaluatePluginDependencies() {
281 if(this.pluginBean.isReadableProperty(DEPENDS_ON)) {
282 this.dependencies = (Map) GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, DEPENDS_ON);
283 this.dependencyNames = (String[])this.dependencies.keySet().toArray(new String[this.dependencies.size()]);
288 public String[] getLoadAfterNames() {
289 return this.loadAfterNames;
294 * @return the resolver
296 public PathMatchingResourcePatternResolver getResolver() {
297 return resolver;
302 public ApplicationContext getParentCtx() {
303 return application.getParentContext();
306 public BeanBuilder beans(Closure closure) {
307 BeanBuilder bb = new BeanBuilder(getParentCtx(), new GroovyClassLoader(application.getClassLoader()));
308 bb.invokeMethod("beans", new Object[]{closure});
309 return bb;
312 private void initializeModifiedTimes() throws IOException {
313 modifiedTimes = new long[watchedResources.length];
314 for (int i = 0; i < watchedResources.length; i++) {
315 Resource r = watchedResources[i];
316 URLConnection c = r.getURL().openConnection();
317 c.setDoInput(false);
318 c.setDoOutput(false);
319 modifiedTimes[i] = c.getLastModified();
323 public void doWithApplicationContext(ApplicationContext applicationContext) {
324 if(this.pluginBean.isReadableProperty(DO_WITH_APPLICATION_CONTEXT)) {
325 Closure c = (Closure)this.plugin.getProperty(DO_WITH_APPLICATION_CONTEXT);
326 c.setDelegate(this);
327 c.call(new Object[]{applicationContext});
331 public void doWithRuntimeConfiguration(
332 RuntimeSpringConfiguration springConfig) {
334 if(this.pluginBean.isReadableProperty(DO_WITH_SPRING)) {
335 if(LOG.isDebugEnabled()) {
336 LOG.debug("Plugin " + this + " is participating in Spring configuration...");
338 Closure c = (Closure)this.plugin.getProperty(DO_WITH_SPRING);
339 BeanBuilder bb = new BeanBuilder(getParentCtx(), application.getClassLoader());
340 bb.setSpringConfig(springConfig);
341 Binding b = new Binding();
342 b.setVariable("application", application);
343 b.setVariable("manager", getManager());
344 b.setVariable("plugin", this);
345 b.setVariable("parentCtx", getParentCtx());
346 b.setVariable("resolver", getResolver());
347 bb.setBinding(b);
348 c.setDelegate(bb);
349 bb.invokeMethod("beans", new Object[]{c});
354 public String getName() {
355 return this.pluginGrailsClass.getLogicalPropertyName();
358 public String getVersion() {
359 return this.version;
361 public String[] getDependencyNames() {
362 return this.dependencyNames;
366 * @return the watchedResources
368 public Resource[] getWatchedResources() {
369 return watchedResources;
372 public String getDependentVersion(String name) {
373 Object dependentVersion = this.dependencies.get(name);
374 if(dependentVersion == null)
375 throw new PluginException("Plugin ["+getName()+"] referenced dependency ["+name+"] with no version!");
376 else
377 return dependentVersion.toString();
380 public String toString() {
381 return "["+getName()+":"+getVersion()+"]";
384 public void doWithWebDescriptor(GPathResult webXml) {
385 if(this.pluginBean.isReadableProperty(DO_WITH_WEB_DESCRIPTOR)) {
386 Closure c = (Closure)this.plugin.getProperty(DO_WITH_WEB_DESCRIPTOR);
387 c.setResolveStrategy(Closure.DELEGATE_FIRST);
388 c.setDelegate(this);
389 c.call(webXml);
395 * Monitors the plugin resources defined in the watchResources property for changes and
396 * fires onChange events by calling an onChange closure defined in the plugin (if it exists)
398 public boolean checkForChanges() {
399 if(pluginUrl != null) {
400 long currentModified = -1;
401 URLConnection conn = null;
402 try {
403 conn = pluginUrl
404 .openConnection();
406 currentModified = conn
407 .getLastModified();
408 if(currentModified > pluginLastModified) {
410 if(LOG.isInfoEnabled())
411 LOG.info("Grails plug-in "+this+" changed, reloading changes..");
413 GroovyClassLoader gcl = new GroovyClassLoader(application.getClassLoader());
414 initialisePlugin(gcl.parseClass(conn.getInputStream()));
415 pluginLastModified = currentModified;
416 return true;
418 } catch (IOException e) {
419 LOG.warn("Error reading plugin ["+pluginClass+"] last modified date, cannot reload following change: " + e.getMessage());
421 finally {
422 if(conn!=null) {
423 try {
424 conn.getInputStream().close();
425 } catch (IOException e) {
426 LOG.warn("Error closing URL connection to plugin resource ["+pluginUrl+"]: " + e.getMessage(), e);
433 if(onChangeListener!=null) {
434 checkForNewResources(this);
436 if(LOG.isDebugEnabled()) {
437 LOG.debug("Plugin "+this+" checking ["+watchedResources.length+"] resources for changes..");
439 for (int i = 0; i < watchedResources.length; i++) {
440 final Resource r = watchedResources[i];
441 long modifiedFlag = checkModified(r, modifiedTimes[i]) ;
442 if( modifiedFlag > -1) {
443 if(LOG.isInfoEnabled())
444 LOG.info("Grails plug-in resource ["+r+"] changed, reloading changes..");
446 modifiedTimes[i] = modifiedFlag;
447 fireModifiedEvent(r, this);
448 refreshInfluencedPlugins();
453 return false;
457 * This method will retrieve all the influenced plugins from the manager and
458 * call refresh() on each one
460 private void refreshInfluencedPlugins() {
461 GrailsPluginManager manager = getManager();
462 if(LOG.isDebugEnabled())
463 LOG.debug("Plugin "+this+" starting refresh of influenced plugins " + ArrayUtils.toString(influencedPluginNames));
464 if(manager != null) {
465 for (int i = 0; i < influencedPluginNames.length; i++) {
466 String name = influencedPluginNames[i];
467 GrailsPlugin plugin = manager.getGrailsPlugin(name);
469 if(plugin!=null) {
470 if(LOG.isDebugEnabled())
471 LOG.debug(this+" plugin is refreshing influenced plugin " + plugin +" following change to resource");
473 plugin.refresh();
477 else if(LOG.isDebugEnabled()) {
478 LOG.debug("Plugin "+this+" cannot refresh influenced plugins, manager is not found");
485 * This method will take a Resource and check it against the previous modified time passed
486 * in the arguments. If the resource was modified it will return the new modified time, otherwise
487 * it will return -1
489 * @param r The Resource instance
490 * @param previousModifiedTime The last time the Resource was modified
491 * @return The new modified time or -1
493 private long checkModified(Resource r, long previousModifiedTime) {
494 try {
495 URL url = r.getURL();
497 if(LOG.isDebugEnabled())
498 LOG.debug("Checking modified for url " + url);
500 URLConnection c = url.openConnection();
501 c.setDoInput(false);
502 c.setDoOutput(false);
503 long lastModified = c.getLastModified();
505 if( previousModifiedTime < lastModified ) {
506 return lastModified;
508 } catch (IOException e) {
509 LOG.debug("Unable to read last modified date of plugin resource" +e.getMessage(),e);
511 return -1;
514 private void checkForNewResources(final GrailsPlugin plugin) {
517 if(resourcesReferences != null) {
518 if(LOG.isDebugEnabled()) {
519 LOG.debug("Plugin "+plugin+" checking ["+ArrayUtils.toString(resourcesReferences)+"] resource references new resources that have been added..");
522 for (int i = 0; i < resourcesReferences.length; i++) {
523 String resourcesReference = resourcesReferences[i];
524 try {
525 Resource[] tmp = resolver.getResources(resourcesReference);
526 if(resourceCount[i] < tmp.length) {
527 Resource newResource = null;
528 resourceCount[i] = tmp.length;
530 for (int j = 0; j < tmp.length; j++) {
531 Resource resource = tmp[j];
532 if(!ArrayUtils.contains(watchedResources, resource)) {
533 newResource = resource;
534 break;
538 if(newResource!=null) {
539 watchedResources = (Resource[])ArrayUtils.add(watchedResources, newResource);
541 if(LOG.isInfoEnabled())
542 LOG.info("Found new Grails plug-in resource ["+newResource+"], adding to application..");
545 if(newResource.getFilename().endsWith(".groovy")) {
546 if(LOG.isDebugEnabled())
547 LOG.debug("[GrailsPlugin] plugin resource ["+newResource+"] added, registering resource with class loader...");
549 GroovyClassLoader classLoader = this.application.getClassLoader();
551 GrailsResourceLoader resourceLoader = GrailsResourceLoaderHolder.getResourceLoader();
553 Resource[] classLoaderResources = resourceLoader.getResources();
554 classLoaderResources = (Resource[])ArrayUtils.add(classLoaderResources, newResource);
555 resourceLoader.setResources(classLoaderResources);
557 if(classLoader instanceof GrailsClassLoader) {
558 ((GrailsClassLoader)classLoader).setGrailsResourceLoader(resourceLoader);
562 initializeModifiedTimes();
564 if(LOG.isDebugEnabled())
565 LOG.debug("[GrailsPlugin] plugin resource ["+newResource+"] added, firing event if possible..");
566 fireModifiedEvent(newResource, plugin);
570 catch (IllegalArgumentException e) {
571 LOG.debug("Plugin "+this+" was unable to check for new plugin resources: " + e.getMessage());
573 catch (IOException e) {
574 LOG.debug("Plugin "+this+" was unable to check for new plugin resources: " + e.getMessage());
581 protected void fireModifiedEvent(final Resource resource, final GrailsPlugin plugin) {
583 Class loadedClass = null;
584 String className = GrailsResourceUtils.getClassName(resource);
586 if(className != null) {
587 Class oldClass = application.getClassForName(className);
588 loadedClass = attemptClassReload(className);
589 if(oldClass != null) {
590 GroovySystem.getMetaClassRegistry().removeMetaClass(oldClass);
594 final Class resourceClass = loadedClass;
595 Object source;
596 if(resourceClass != null)source=resourceClass;
597 else source = resource;
599 if(loadedClass != null && Modifier.isAbstract(loadedClass.getModifiers())) {
600 restartContainer();
602 else {
603 Map event = notifyOfEvent(EVENT_ON_CHANGE, source);
604 if(LOG.isDebugEnabled()) {
605 LOG.debug("Firing onChange event listener with event object ["+event+"]");
608 getManager().informObservers(getName(), event);
613 public void restartContainer() {
614 // here we touch the classes directory if the file is abstract to force the Grails server
615 // to restart the web application
616 try {
617 String classesDir = System.getProperty("grails.classes.dir");
618 File classesFile = null;
619 if(!StringUtils.isBlank(classesDir)) {
620 classesFile = new File(classesDir);
622 else {
624 Resource r = this.applicationContext.getResource("/WEB-INF/classes");
625 classesFile = r.getFile();
628 classesFile.setLastModified(System.currentTimeMillis());
629 } catch (IOException e) {
630 LOG.error("Error retrieving /WEB-INF/classes directory: " + e.getMessage(),e);
634 private Class attemptClassReload(final Resource resource) {
635 String className = GrailsResourceUtils.getClassName(resource);
636 if(className != null) {
637 return attemptClassReload(className);
639 return null;
644 private Class attemptClassReload(String className) {
645 final GroovyClassLoader loader = application.getClassLoader();
646 if(loader instanceof GrailsClassLoader) {
647 GrailsClassLoader grailsLoader = (GrailsClassLoader)loader;
649 return grailsLoader.reloadClass(className);
651 return null;
655 public void setWatchedResources(Resource[] watchedResources) throws IOException {
656 this.watchedResources = watchedResources;
657 initializeModifiedTimes();
661 * These two properties help the closures to resolve a log and plugin variable during executing
663 public Log getLog() {
664 return LOG;
666 public GrailsPlugin getPlugin() {
667 return this;
671 public void setParentApplicationContext(ApplicationContext parent) {
672 // do nothing for the moment
677 /* (non-Javadoc)
678 * @see org.codehaus.groovy.grails.plugins.AbstractGrailsPlugin#refresh()
680 public void refresh() {
681 refresh(true);
684 public void refresh(boolean fireEvent) {
685 for (int i = 0; i < watchedResources.length; i++) {
686 Resource r = watchedResources[i];
687 try {
688 r.getFile().setLastModified(System.currentTimeMillis());
689 } catch (IOException e) {
690 // ignore
692 if(fireEvent)
693 fireModifiedEvent(r, this);
698 public GroovyObject getInstance() {
699 return this.plugin;
702 public void doWithDynamicMethods(ApplicationContext applicationContext) {
703 if(this.pluginBean.isReadableProperty(DO_WITH_DYNAMIC_METHODS)) {
704 Closure c = (Closure)this.plugin.getProperty(DO_WITH_DYNAMIC_METHODS);
705 c.setDelegate(this);
706 c.call(new Object[]{applicationContext});
710 public boolean isEnabled() {
711 return STATUS_ENABLED.equals(this.status);
714 public String[] getObservedPluginNames() {
715 return this.observedPlugins;
718 public void notifyOfEvent(Map event) {
719 if(onChangeListener != null) {
720 invokeOnChangeListener(event);
724 public Map notifyOfEvent(int eventKind, final Object source) {
725 Map event = new HashMap() {{
726 put(PLUGIN_CHANGE_EVENT_SOURCE, source);
727 put(PLUGIN_CHANGE_EVENT_PLUGIN, plugin);
728 put(PLUGIN_CHANGE_EVENT_APPLICATION, application);
729 put(PLUGIN_CHANGE_EVENT_MANAGER, getManager());
730 put(PLUGIN_CHANGE_EVENT_CTX, applicationContext);
733 switch (eventKind) {
734 case EVENT_ON_CHANGE:
735 notifyOfEvent(event);
736 break;
737 case EVENT_ON_SHUTDOWN:
738 invokeOnShutdownEventListener(event);
739 break;
741 case EVENT_ON_CONFIG_CHANGE:
742 invokeOnConfigChangeListener(event);
743 break;
744 default:
745 notifyOfEvent(event);
748 return event;
751 private void invokeOnShutdownEventListener(Map event) {
752 callEvent(onShutdownListener,event); }
754 private void invokeOnConfigChangeListener(Map event) {
755 callEvent(onConfigChangeListener,event);
758 private void callEvent(Closure closureHook, Map event) {
759 if(closureHook !=null) {
760 closureHook.setDelegate(this);
761 closureHook.call(new Object[]{event});
765 private void invokeOnChangeListener(Map event) {
766 onChangeListener.setDelegate(this);
767 onChangeListener.call(new Object[]{event});
770 public void doArtefactConfiguration() {
771 if(this.pluginBean.isReadableProperty(ARTEFACTS)) {
772 List l = (List)this.plugin.getProperty(ARTEFACTS);
773 for (Iterator iter = l.iterator(); iter.hasNext();) {
774 Object artefact = iter.next();
775 if(artefact instanceof Class) {
776 Class artefactClass = (Class)artefact;
777 if(ArtefactHandler.class.isAssignableFrom(artefactClass)) {
778 try {
779 this.application.registerArtefactHandler((ArtefactHandler)artefactClass.newInstance());
780 } catch (InstantiationException e) {
781 LOG.error("Cannot instantiate an Artefact Handler:" + e.getMessage(),e);
782 } catch (IllegalAccessException e) {
783 LOG.error("The constructor of the Artefact Handler is not accessible:" + e.getMessage(),e);
785 } else {
786 LOG.error("This class is not an ArtefactHandler:" + artefactClass.getName());
788 } else {
789 if(artefact instanceof ArtefactHandler) {
790 this.application.registerArtefactHandler((ArtefactHandler)artefact);
791 } else {
792 LOG.error("This object is not an ArtefactHandler:" + artefact + "[" + artefact.getClass().getName()+"]");
799 public Class[] getProvidedArtefacts() {
800 return this.providedArtefacts;