1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.plugin;
17
18 import org.kuali.rice.core.api.config.CoreConfigHelper;
19 import org.kuali.rice.core.api.config.property.Config;
20 import org.kuali.rice.core.api.config.property.ConfigContext;
21 import org.kuali.rice.core.api.resourceloader.ResourceLoader;
22 import org.kuali.rice.core.api.util.ClassLoaderUtils;
23 import org.kuali.rice.kew.plugin.PluginUtils.PluginZipFileFilter;
24
25 import javax.xml.namespace.QName;
26 import java.io.File;
27 import java.util.ArrayList;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.TreeMap;
33 import java.util.concurrent.Executors;
34 import java.util.concurrent.ScheduledExecutorService;
35 import java.util.concurrent.ScheduledFuture;
36 import java.util.concurrent.ThreadFactory;
37 import java.util.concurrent.TimeUnit;
38
39
40
41
42
43
44 public class ServerPluginRegistry extends BasePluginRegistry {
45
46 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ServerPluginRegistry.class);
47
48 private List<String> pluginDirectories = new ArrayList<String>();
49 private File sharedPluginDirectory;
50 private Reloader reloader;
51 private HotDeployer hotDeployer;
52
53 private ScheduledExecutorService scheduledExecutor;
54 private ScheduledFuture<?> reloaderFuture;
55 private ScheduledFuture<?> hotDeployerFuture;
56
57
58 public ServerPluginRegistry() {
59 super(new QName(CoreConfigHelper.getApplicationId(), ResourceLoader.PLUGIN_REGISTRY_LOADER_NAME));
60 }
61
62 public void start() throws Exception {
63 if (!isStarted()) {
64 LOG.info("Starting server Plugin Registry...");
65 scheduledExecutor = Executors.newScheduledThreadPool(2, new KEWThreadFactory());
66 sharedPluginDirectory = loadSharedPlugin();
67 reloader = new Reloader();
68 hotDeployer = new HotDeployer(this, sharedPluginDirectory, pluginDirectories);
69 loadPlugins(sharedPluginDirectory);
70 this.reloaderFuture = scheduledExecutor.scheduleWithFixedDelay(reloader, 5, 5, TimeUnit.SECONDS);
71 this.hotDeployerFuture = scheduledExecutor.scheduleWithFixedDelay(hotDeployer, 5, 5, TimeUnit.SECONDS);
72 super.start();
73 LOG.info("...server Plugin Registry successfully started.");
74 }
75 }
76
77 public void stop() throws Exception {
78 if (isStarted()) {
79 LOG.info("Stopping server Plugin Registry...");
80 stopReloader();
81 stopHotDeployer();
82 reloader = null;
83 hotDeployer = null;
84
85 if (scheduledExecutor != null) {
86 scheduledExecutor.shutdownNow();
87 scheduledExecutor = null;
88 }
89 super.stop();
90 LOG.info("...server Plugin Registry successfully stopped.");
91 }
92 }
93
94 protected void stopReloader() {
95 if (reloaderFuture != null) {
96 if (!reloaderFuture.cancel(true)) {
97 LOG.warn("Failed to cancel the plugin reloader.");
98 }
99 reloaderFuture = null;
100 }
101 }
102
103 protected void stopHotDeployer() {
104 if (hotDeployerFuture != null) {
105 if (!hotDeployerFuture.cancel(true)) {
106 LOG.warn("Failed to cancel the hot deployer.");
107 }
108 hotDeployerFuture = null;
109 }
110 }
111
112 protected void loadPlugins(File sharedPluginDirectory) {
113 Map<String, File> pluginLocations = new TreeMap<String, File>(new PluginNameComparator());
114 PluginZipFileFilter pluginFilter = new PluginZipFileFilter();
115 Set<File> visitedFiles = new HashSet<File>();
116 for (String pluginDir : pluginDirectories) {
117 LOG.info("Reading plugins from " + pluginDir);
118 File file = new File(pluginDir);
119 if (visitedFiles.contains(file)) {
120 LOG.info("Skipping visited directory: " + pluginDir);
121 continue;
122 }
123 visitedFiles.add(file);
124 if (!file.exists() || !file.isDirectory()) {
125 LOG.warn(file.getAbsoluteFile()+" is not a valid plugin directory.");
126 continue;
127 }
128 File[] pluginZips = file.listFiles(pluginFilter);
129 for (int i = 0; i < pluginZips.length; i++) {
130 File pluginZip = pluginZips[i];
131 int indexOf = pluginZip.getName().lastIndexOf(".zip");
132 String pluginName = pluginZip.getName().substring(0, indexOf);
133 if (pluginLocations.containsKey(pluginName)) {
134 LOG.warn("There already exists an installed plugin with the name '"+ pluginName + "', ignoring plugin " + pluginZip.getAbsolutePath());
135 continue;
136 }
137 pluginLocations.put(pluginName, pluginZip);
138 }
139 }
140 for (String pluginName : pluginLocations.keySet()) {
141 File pluginZipFile = pluginLocations.get(pluginName);
142 try {
143 LOG.info("Loading plugin '" + pluginName + "'");
144 ClassLoader parentClassLoader = ClassLoaderUtils.getDefaultClassLoader();
145 Config parentConfig = ConfigContext.getCurrentContextConfig();
146 ZipFilePluginLoader loader = new ZipFilePluginLoader(pluginZipFile,
147 sharedPluginDirectory,
148 parentClassLoader,
149 parentConfig);
150 PluginEnvironment environment = new PluginEnvironment(loader, this);
151 try {
152 environment.load();
153 } finally {
154
155 addPluginEnvironment(environment);
156 }
157 } catch (Exception e) {
158 LOG.error("Failed to read workflow plugin '"+pluginName+"'", e);
159 }
160 }
161 }
162
163 @Override
164 public void addPluginEnvironment(PluginEnvironment pluginEnvironment) {
165 super.addPluginEnvironment(pluginEnvironment);
166 reloader.addReloadable(pluginEnvironment);
167 }
168
169 @Override
170 public PluginEnvironment removePluginEnvironment(String pluginName) {
171 PluginEnvironment environment = super.removePluginEnvironment(pluginName);
172 reloader.removeReloadable(environment);
173 return environment;
174 }
175
176 public File loadSharedPlugin() {
177 return PluginUtils.findSharedDirectory(pluginDirectories);
178 }
179
180 public void setPluginDirectories(List<String> pluginDirectories) {
181 this.pluginDirectories = pluginDirectories;
182 }
183
184 public void setSharedPluginDirectory(File sharedPluginDirectory) {
185 this.sharedPluginDirectory = sharedPluginDirectory;
186 }
187
188 protected HotDeployer getHotDeployer() {
189 return hotDeployer;
190 }
191
192 protected Reloader getReloader() {
193 return reloader;
194 }
195
196 private static class KEWThreadFactory implements ThreadFactory {
197
198 private ThreadFactory defaultThreadFactory = Executors.defaultThreadFactory();
199
200 public Thread newThread(Runnable runnable) {
201 Thread thread = defaultThreadFactory.newThread(runnable);
202 thread.setName("ServerPluginRegistry-" + thread.getName());
203 return thread;
204 }
205 }
206
207 }