1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.kuali.rice.kew.plugin;
18
19 import java.io.File;
20 import java.util.ArrayList;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.TreeMap;
26 import java.util.concurrent.Executors;
27 import java.util.concurrent.ScheduledExecutorService;
28 import java.util.concurrent.ScheduledFuture;
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.TimeUnit;
31
32 import javax.xml.namespace.QName;
33
34 import org.kuali.rice.core.api.config.CoreConfigHelper;
35 import org.kuali.rice.core.api.config.property.Config;
36 import org.kuali.rice.core.api.config.property.ConfigContext;
37 import org.kuali.rice.core.api.resourceloader.ResourceLoader;
38 import org.kuali.rice.core.util.ClassLoaderUtils;
39 import org.kuali.rice.kew.plugin.PluginUtils.PluginZipFileFilter;
40
41
42
43
44
45
46 public class ServerPluginRegistry extends BasePluginRegistry {
47
48 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ServerPluginRegistry.class);
49
50 private List<String> pluginDirectories = new ArrayList<String>();
51 private File sharedPluginDirectory;
52 private Reloader reloader;
53 private HotDeployer hotDeployer;
54
55 private ScheduledExecutorService scheduledExecutor;
56 private ScheduledFuture<?> reloaderFuture;
57 private ScheduledFuture<?> hotDeployerFuture;
58
59
60 public ServerPluginRegistry() {
61 super(new QName(CoreConfigHelper.getApplicationId(), ResourceLoader.PLUGIN_REGISTRY_LOADER_NAME));
62 }
63
64 public void start() throws Exception {
65 LOG.info("Starting server Plugin Registry...");
66 scheduledExecutor = Executors.newScheduledThreadPool(2, new KEWThreadFactory());
67 sharedPluginDirectory = loadSharedPlugin();
68 reloader = new Reloader();
69 hotDeployer = new HotDeployer(PluginUtils.getPluginRegistry(), sharedPluginDirectory, pluginDirectories);
70 loadPlugins(sharedPluginDirectory);
71
72 this.reloaderFuture = scheduledExecutor.scheduleWithFixedDelay(reloader, 5, 5, TimeUnit.SECONDS);
73 this.hotDeployerFuture = scheduledExecutor.scheduleWithFixedDelay(hotDeployer, 5, 5, TimeUnit.SECONDS);
74 super.start();
75 LOG.info("...server Plugin Registry successfully started.");
76 }
77
78 public void stop() throws Exception {
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 protected void stopReloader() {
94 if (reloaderFuture != null) {
95 if (!reloaderFuture.cancel(true)) {
96 LOG.warn("Failed to cancel the plugin reloader.");
97 }
98 reloaderFuture = null;
99 }
100 }
101
102 protected void stopHotDeployer() {
103 if (hotDeployerFuture != null) {
104 if (!hotDeployerFuture.cancel(true)) {
105 LOG.warn("Failed to cancel the hot deployer.");
106 }
107 hotDeployerFuture = null;
108 }
109 }
110
111 protected void loadPlugins(File sharedPluginDirectory) {
112 Map<String, File> pluginLocations = new TreeMap<String, File>(new PluginNameComparator());
113 PluginZipFileFilter pluginFilter = new PluginZipFileFilter();
114
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 }