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
;
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
;
44 import java
.lang
.reflect
.Modifier
;
46 import java
.net
.URLConnection
;
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
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
);
93 this.dependencies
= Collections
.EMPTY_MAP
;
94 this.resolver
= new PathMatchingResourcePatternResolver();
95 if(resource
!= null) {
97 pluginUrl
= resource
.getURL();
98 this.pluginLastModified
= pluginUrl
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
);
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()];
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
);
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
));
206 tmp
= resolver
.getResources("classpath*:" + res
);
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");
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
);
248 this.version
= vobj
.toString();
250 throw new PluginException("Plugin "+this+" must specify a version. eg: def version = 0.1");
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()];
263 for (Iterator i
= pluginsToEvict
.iterator(); i
.hasNext();) {
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() {
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
});
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();
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
);
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());
349 bb
.invokeMethod("beans", new Object
[]{c
});
354 public String
getName() {
355 return this.pluginGrailsClass
.getLogicalPropertyName();
358 public String
getVersion() {
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!");
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
);
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;
406 currentModified
= conn
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
;
418 } catch (IOException e
) {
419 LOG
.warn("Error reading plugin ["+pluginClass
+"] last modified date, cannot reload following change: " + e
.getMessage());
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();
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
);
470 if(LOG
.isDebugEnabled())
471 LOG
.debug(this+" plugin is refreshing influenced plugin " + plugin
+" following change to resource");
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
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
) {
495 URL url
= r
.getURL();
497 if(LOG
.isDebugEnabled())
498 LOG
.debug("Checking modified for url " + url
);
500 URLConnection c
= url
.openConnection();
502 c
.setDoOutput(false);
503 long lastModified
= c
.getLastModified();
505 if( previousModifiedTime
< lastModified
) {
508 } catch (IOException e
) {
509 LOG
.debug("Unable to read last modified date of plugin resource" +e
.getMessage(),e
);
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
];
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
;
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
;
596 if(resourceClass
!= null)source
=resourceClass
;
597 else source
= resource
;
599 if(loadedClass
!= null && Modifier
.isAbstract(loadedClass
.getModifiers())) {
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
617 String classesDir
= System
.getProperty("grails.classes.dir");
618 File classesFile
= null;
619 if(!StringUtils
.isBlank(classesDir
)) {
620 classesFile
= new File(classesDir
);
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
);
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
);
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() {
666 public GrailsPlugin
getPlugin() {
671 public void setParentApplicationContext(ApplicationContext parent
) {
672 // do nothing for the moment
678 * @see org.codehaus.groovy.grails.plugins.AbstractGrailsPlugin#refresh()
680 public void refresh() {
684 public void refresh(boolean fireEvent
) {
685 for (int i
= 0; i
< watchedResources
.length
; i
++) {
686 Resource r
= watchedResources
[i
];
688 r
.getFile().setLastModified(System
.currentTimeMillis());
689 } catch (IOException e
) {
693 fireModifiedEvent(r
, this);
698 public GroovyObject
getInstance() {
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
);
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
);
734 case EVENT_ON_CHANGE
:
735 notifyOfEvent(event
);
737 case EVENT_ON_SHUTDOWN
:
738 invokeOnShutdownEventListener(event
);
741 case EVENT_ON_CONFIG_CHANGE
:
742 invokeOnConfigChangeListener(event
);
745 notifyOfEvent(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
)) {
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
);
786 LOG
.error("This class is not an ArtefactHandler:" + artefactClass
.getName());
789 if(artefact
instanceof ArtefactHandler
) {
790 this.application
.registerArtefactHandler((ArtefactHandler
)artefact
);
792 LOG
.error("This object is not an ArtefactHandler:" + artefact
+ "[" + artefact
.getClass().getName()+"]");
799 public Class
[] getProvidedArtefacts() {
800 return this.providedArtefacts
;