1
2
3
4
5
6
7
8
9
10
11 package org.mule.module.launcher;
12
13 import org.mule.config.StartupContext;
14 import org.mule.module.reboot.MuleContainerBootstrapUtils;
15 import org.mule.util.CollectionUtils;
16 import org.mule.util.FileUtils;
17 import org.mule.util.FilenameUtils;
18 import org.mule.util.StringUtils;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.ScheduledExecutorService;
30 import java.util.concurrent.TimeUnit;
31
32 import org.apache.commons.beanutils.BeanPropertyValueEqualsPredicate;
33 import org.apache.commons.io.filefilter.DirectoryFileFilter;
34 import org.apache.commons.io.filefilter.SuffixFileFilter;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 public class DeploymentService
39 {
40 public static final String APP_ANCHOR_SUFFIX = "-anchor.txt";
41 protected static final int DEFAULT_CHANGES_CHECK_INTERVAL_MS = 5000;
42
43 protected ScheduledExecutorService appDirMonitorTimer;
44
45 protected transient final Log logger = LogFactory.getLog(getClass());
46 protected MuleDeployer deployer = new DefaultMuleDeployer();
47 private List<Application> applications = new ArrayList<Application>();
48
49 public void start()
50 {
51
52 final Map<String, Object> options = StartupContext.get().getStartupOptions();
53 String appString = (String) options.get("app");
54
55 final File appsDir = MuleContainerBootstrapUtils.getMuleAppsDir();
56
57
58 String[] appAnchors = appsDir.list(new SuffixFileFilter(APP_ANCHOR_SUFFIX));
59 for (String anchor : appAnchors)
60 {
61
62 new File(appsDir, anchor).delete();
63 }
64
65 String[] apps;
66
67
68 final boolean explicitAppSet = appString != null;
69
70 if (!explicitAppSet)
71 {
72
73 final String[] zips = appsDir.list(new SuffixFileFilter(".zip"));
74 for (String zip : zips)
75 {
76 try
77 {
78
79 deployer.installFromAppDir(zip);
80 }
81 catch (IOException e)
82 {
83
84 e.printStackTrace();
85 }
86 }
87
88
89
90 apps = appsDir.list(DirectoryFileFilter.DIRECTORY);
91 }
92 else
93 {
94 apps = appString.split(":");
95 }
96
97 for (String app : apps)
98 {
99 final ApplicationWrapper a = new ApplicationWrapper(new DefaultMuleApplication(app));
100 applications.add(a);
101 }
102
103
104 for (Application application : applications)
105 {
106 try
107 {
108 deployer.deploy(application);
109 }
110 catch (Throwable t)
111 {
112
113 t.printStackTrace();
114 }
115 }
116
117
118
119 if (!explicitAppSet)
120 {
121 scheduleChangeMonitor(appsDir);
122 }
123 }
124
125 protected void scheduleChangeMonitor(File appsDir)
126 {
127 final int reloadIntervalMs = DEFAULT_CHANGES_CHECK_INTERVAL_MS;
128 appDirMonitorTimer = Executors.newSingleThreadScheduledExecutor(new AppDeployerMonitorThreadFactory());
129
130 appDirMonitorTimer.scheduleWithFixedDelay(new AppDirWatcher(appsDir),
131 0,
132 reloadIntervalMs,
133 TimeUnit.MILLISECONDS);
134
135 if (logger.isInfoEnabled())
136 {
137 logger.info("Application directory check interval: " + reloadIntervalMs);
138 }
139 }
140
141 public void stop()
142 {
143 if (appDirMonitorTimer != null)
144 {
145 appDirMonitorTimer.shutdownNow();
146 }
147
148
149 Collections.reverse(applications);
150 for (Application application : applications)
151 {
152 try
153 {
154 application.stop();
155 application.dispose();
156 }
157 catch (Throwable t)
158 {
159
160 t.printStackTrace();
161 }
162 }
163
164 }
165
166
167
168
169 public List<Application> getApplications()
170 {
171 return Collections.unmodifiableList(applications);
172 }
173
174 public MuleDeployer getDeployer()
175 {
176 return deployer;
177 }
178
179 public void setDeployer(MuleDeployer deployer)
180 {
181 this.deployer = deployer;
182 }
183
184
185
186
187 protected class AppDirWatcher implements Runnable
188 {
189 protected File appsDir;
190
191 protected String[] deployedApps;
192
193
194 protected String[] appAnchors = new String[0];
195
196 public AppDirWatcher(File appsDir)
197 {
198 this.appsDir = appsDir;
199
200 this.deployedApps = new String[applications.size()];
201 for (int i = 0; i < applications.size(); i++)
202 {
203 deployedApps[i] = applications.get(i).getAppName();
204
205 }
206 }
207
208
209
210
211
212 public void run()
213 {
214
215 final String[] zips = appsDir.list(new SuffixFileFilter(".zip"));
216 String[] apps = appsDir.list(DirectoryFileFilter.DIRECTORY);
217
218 String[] currentAnchors = appsDir.list(new SuffixFileFilter(APP_ANCHOR_SUFFIX));
219 @SuppressWarnings("unchecked")
220 final Collection<String> deletedAnchors = CollectionUtils.subtract(Arrays.asList(appAnchors), Arrays.asList(currentAnchors));
221 for (String deletedAnchor : deletedAnchors)
222 {
223
224 String appName = StringUtils.removeEnd(deletedAnchor, APP_ANCHOR_SUFFIX);
225 try
226 {
227 onApplicationUndeployRequested(appName);
228 }
229 catch (Throwable t)
230 {
231 logger.error("Failed to undeploy application: " + appName, t);
232 }
233 }
234 appAnchors = currentAnchors;
235
236
237
238 for (String zip : zips)
239 {
240 try
241 {
242
243 final String appName = StringUtils.removeEnd(zip, ".zip");
244 Application app = (Application) CollectionUtils.find(applications, new BeanPropertyValueEqualsPredicate("appName", appName));
245 if (app != null)
246 {
247 onApplicationUndeployRequested(appName);
248 }
249 onNewApplicationArchive(new File(appsDir, zip));
250 }
251 catch (Throwable t)
252 {
253 logger.error("Failed to deploy application archive: " + zip, t);
254 }
255 }
256
257
258 if (zips.length > 0)
259 {
260 apps = appsDir.list(DirectoryFileFilter.DIRECTORY);
261 deployedApps = apps;
262 }
263
264
265 @SuppressWarnings("unchecked")
266 final Collection<String> addedApps = CollectionUtils.subtract(Arrays.asList(apps), Arrays.asList(deployedApps));
267 for (String addedApp : addedApps)
268 {
269 try
270 {
271 onNewExplodedApplication(addedApp);
272 }
273 catch (Throwable t)
274 {
275 logger.error("Failed to deploy exploded application: " + addedApp, t);
276 }
277 }
278
279 deployedApps = apps;
280 }
281
282 protected void onApplicationUndeployRequested(String appName) throws Exception
283 {
284 if (logger.isInfoEnabled())
285 {
286 logger.info("================== Request to Undeploy Application: " + appName);
287 }
288
289 Application app = (Application) CollectionUtils.find(applications, new BeanPropertyValueEqualsPredicate("appName", appName));
290 applications.remove(app);
291 deployer.undeploy(app);
292 }
293
294
295
296
297 protected void onNewExplodedApplication(String appName) throws Exception
298 {
299 if (logger.isInfoEnabled())
300 {
301 logger.info("================== New Exploded Application: " + appName);
302 }
303
304 Application a = new ApplicationWrapper(new DefaultMuleApplication(appName));
305
306 applications.add(a);
307 deployer.deploy(a);
308 }
309
310 protected void onNewApplicationArchive(File file) throws Exception
311 {
312 if (logger.isInfoEnabled())
313 {
314 logger.info("================== New Application Archive: " + file);
315 }
316
317
318 final String appName = FilenameUtils.getBaseName(file.getName());
319 FileUtils.deleteTree(new File(appsDir, appName));
320
321 Application app = deployer.installFrom(file.toURL());
322
323 applications.add(app);
324 deployer.deploy(app);
325 }
326 }
327
328 }