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 LOG.info("Starting server Plugin Registry...");
64 scheduledExecutor = Executors.newScheduledThreadPool(2, new KEWThreadFactory());
65 sharedPluginDirectory = loadSharedPlugin();
66 reloader = new Reloader();
67 hotDeployer = new HotDeployer(PluginUtils.getPluginRegistry(), sharedPluginDirectory, pluginDirectories);
68 loadPlugins(sharedPluginDirectory);
69
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 public void stop() throws Exception {
77 LOG.info("Stopping server Plugin Registry...");
78 stopReloader();
79 stopHotDeployer();
80 reloader = null;
81 hotDeployer = null;
82
83 if (scheduledExecutor != null) {
84 scheduledExecutor.shutdownNow();
85 scheduledExecutor = null;
86 }
87 super.stop();
88 LOG.info("...server Plugin Registry successfully stopped.");
89 }
90
91 protected void stopReloader() {
92 if (reloaderFuture != null) {
93 if (!reloaderFuture.cancel(true)) {
94 LOG.warn("Failed to cancel the plugin reloader.");
95 }
96 reloaderFuture = null;
97 }
98 }
99
100 protected void stopHotDeployer() {
101 if (hotDeployerFuture != null) {
102 if (!hotDeployerFuture.cancel(true)) {
103 LOG.warn("Failed to cancel the hot deployer.");
104 }
105 hotDeployerFuture = null;
106 }
107 }
108
109 protected void loadPlugins(File sharedPluginDirectory) {
110 Map<String, File> pluginLocations = new TreeMap<String, File>(new PluginNameComparator());
111 PluginZipFileFilter pluginFilter = new PluginZipFileFilter();
112
113 Set<File> visitedFiles = new HashSet<File>();
114 for (String pluginDir : pluginDirectories) {
115 LOG.info("Reading plugins from " + pluginDir);
116 File file = new File(pluginDir);
117 if (visitedFiles.contains(file)) {
118 LOG.info("Skipping visited directory: " + pluginDir);
119 continue;
120 }
121 visitedFiles.add(file);
122 if (!file.exists() || !file.isDirectory()) {
123 LOG.warn(file.getAbsoluteFile()+" is not a valid plugin directory.");
124 continue;
125 }
126 File[] pluginZips = file.listFiles(pluginFilter);
127 for (int i = 0; i < pluginZips.length; i++) {
128 File pluginZip = pluginZips[i];
129 int indexOf = pluginZip.getName().lastIndexOf(".zip");
130 String pluginName = pluginZip.getName().substring(0, indexOf);
131 if (pluginLocations.containsKey(pluginName)) {
132 LOG.warn("There already exists an installed plugin with the name '"+ pluginName + "', ignoring plugin " + pluginZip.getAbsolutePath());
133 continue;
134 }
135 pluginLocations.put(pluginName, pluginZip);
136 }
137 }
138 for (String pluginName : pluginLocations.keySet()) {
139 File pluginZipFile = pluginLocations.get(pluginName);
140 try {
141 LOG.info("Loading plugin '" + pluginName + "'");
142 ClassLoader parentClassLoader = ClassLoaderUtils.getDefaultClassLoader();
143 Config parentConfig = ConfigContext.getCurrentContextConfig();
144 ZipFilePluginLoader loader = new ZipFilePluginLoader(pluginZipFile,
145 sharedPluginDirectory,
146 parentClassLoader,
147 parentConfig);
148 PluginEnvironment environment = new PluginEnvironment(loader, this);
149 try {
150 environment.load();
151 } finally {
152
153 addPluginEnvironment(environment);
154 }
155 } catch (Exception e) {
156 LOG.error("Failed to read workflow plugin '"+pluginName+"'", e);
157 }
158 }
159 }
160
161 @Override
162 public void addPluginEnvironment(PluginEnvironment pluginEnvironment) {
163 super.addPluginEnvironment(pluginEnvironment);
164 reloader.addReloadable(pluginEnvironment);
165 }
166
167 @Override
168 public PluginEnvironment removePluginEnvironment(String pluginName) {
169 PluginEnvironment environment = super.removePluginEnvironment(pluginName);
170 reloader.removeReloadable(environment);
171 return environment;
172 }
173
174 public File loadSharedPlugin() {
175 return PluginUtils.findSharedDirectory(pluginDirectories);
176 }
177
178 public void setPluginDirectories(List<String> pluginDirectories) {
179 this.pluginDirectories = pluginDirectories;
180 }
181
182 public void setSharedPluginDirectory(File sharedPluginDirectory) {
183 this.sharedPluginDirectory = sharedPluginDirectory;
184 }
185
186 protected HotDeployer getHotDeployer() {
187 return hotDeployer;
188 }
189
190 protected Reloader getReloader() {
191 return reloader;
192 }
193
194 private static class KEWThreadFactory implements ThreadFactory {
195
196 private ThreadFactory defaultThreadFactory = Executors.defaultThreadFactory();
197
198 public Thread newThread(Runnable runnable) {
199 Thread thread = defaultThreadFactory.newThread(runnable);
200 thread.setName("ServerPluginRegistry-" + thread.getName());
201 return thread;
202 }
203 }
204
205 }