1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
package org.mule.module.launcher; |
8 | |
|
9 | |
import static org.mule.util.SplashScreen.miniSplash; |
10 | |
import org.mule.config.StartupContext; |
11 | |
import org.mule.config.i18n.MessageFactory; |
12 | |
import org.mule.module.launcher.application.Application; |
13 | |
import org.mule.module.launcher.application.ApplicationFactory; |
14 | |
import org.mule.module.launcher.util.DebuggableReentrantLock; |
15 | |
import org.mule.module.launcher.util.ElementAddedEvent; |
16 | |
import org.mule.module.launcher.util.ElementRemovedEvent; |
17 | |
import org.mule.module.launcher.util.ObservableList; |
18 | |
import org.mule.module.reboot.MuleContainerBootstrapUtils; |
19 | |
import org.mule.util.ArrayUtils; |
20 | |
import org.mule.util.CollectionUtils; |
21 | |
import org.mule.util.FileUtils; |
22 | |
import org.mule.util.StringUtils; |
23 | |
|
24 | |
import java.beans.PropertyChangeEvent; |
25 | |
import java.beans.PropertyChangeListener; |
26 | |
import java.io.File; |
27 | |
import java.io.IOException; |
28 | |
import java.net.MalformedURLException; |
29 | |
import java.net.URL; |
30 | |
import java.util.ArrayList; |
31 | |
import java.util.Arrays; |
32 | |
import java.util.Collection; |
33 | |
import java.util.Collections; |
34 | |
import java.util.HashMap; |
35 | |
import java.util.LinkedList; |
36 | |
import java.util.List; |
37 | |
import java.util.Map; |
38 | |
import java.util.concurrent.CopyOnWriteArrayList; |
39 | |
import java.util.concurrent.Executors; |
40 | |
import java.util.concurrent.ScheduledExecutorService; |
41 | |
import java.util.concurrent.TimeUnit; |
42 | |
import java.util.concurrent.locks.ReentrantLock; |
43 | |
|
44 | |
import org.apache.commons.beanutils.BeanPropertyValueEqualsPredicate; |
45 | |
import org.apache.commons.beanutils.BeanToPropertyValueTransformer; |
46 | |
import org.apache.commons.io.filefilter.AndFileFilter; |
47 | |
import org.apache.commons.io.filefilter.DirectoryFileFilter; |
48 | |
import org.apache.commons.io.filefilter.FileFileFilter; |
49 | |
import org.apache.commons.io.filefilter.IOFileFilter; |
50 | |
import org.apache.commons.io.filefilter.SuffixFileFilter; |
51 | |
import org.apache.commons.logging.Log; |
52 | |
import org.apache.commons.logging.LogFactory; |
53 | |
|
54 | 0 | public class DeploymentService |
55 | |
{ |
56 | |
public static final String APP_ANCHOR_SUFFIX = "-anchor.txt"; |
57 | |
public static final String ZIP_FILE_SUFFIX = ".zip"; |
58 | 0 | public static final IOFileFilter ZIP_APPS_FILTER = new AndFileFilter(new SuffixFileFilter(ZIP_FILE_SUFFIX), FileFileFilter.FILE); |
59 | |
|
60 | |
protected static final int DEFAULT_CHANGES_CHECK_INTERVAL_MS = 5000; |
61 | |
|
62 | |
protected ScheduledExecutorService appDirMonitorTimer; |
63 | |
|
64 | 0 | protected transient final Log logger = LogFactory.getLog(getClass()); |
65 | |
protected MuleDeployer deployer; |
66 | |
protected ApplicationFactory appFactory; |
67 | |
|
68 | 0 | private ReentrantLock lock = new DebuggableReentrantLock(true); |
69 | |
|
70 | 0 | private ObservableList<Application> applications = new ObservableList<Application>(); |
71 | 0 | private Map<URL, Long> zombieMap = new HashMap<URL, Long>(); |
72 | |
|
73 | 0 | private List<StartupListener> startupListeners = new ArrayList<StartupListener>(); |
74 | |
|
75 | 0 | private List<DeploymentListener> deploymentListeners = new CopyOnWriteArrayList<DeploymentListener>(); |
76 | |
|
77 | |
public DeploymentService() |
78 | 0 | { |
79 | 0 | deployer = new DefaultMuleDeployer(this); |
80 | 0 | appFactory = new ApplicationFactory(this); |
81 | 0 | } |
82 | |
|
83 | |
public void start() |
84 | |
{ |
85 | |
|
86 | 0 | final Map<String, Object> options = StartupContext.get().getStartupOptions(); |
87 | 0 | String appString = (String) options.get("app"); |
88 | |
|
89 | 0 | final File appsDir = MuleContainerBootstrapUtils.getMuleAppsDir(); |
90 | |
|
91 | |
|
92 | 0 | String[] appAnchors = appsDir.list(new SuffixFileFilter(APP_ANCHOR_SUFFIX)); |
93 | 0 | for (String anchor : appAnchors) |
94 | |
{ |
95 | |
|
96 | 0 | new File(appsDir, anchor).delete(); |
97 | |
} |
98 | |
|
99 | 0 | String[] apps = ArrayUtils.EMPTY_STRING_ARRAY; |
100 | |
|
101 | |
|
102 | 0 | final boolean explicitAppSet = appString != null; |
103 | |
|
104 | 0 | DeploymentStatusTracker deploymentStatusTracker = new DeploymentStatusTracker(); |
105 | 0 | addDeploymentListener(deploymentStatusTracker); |
106 | |
|
107 | 0 | StartupSummaryDeploymentListener summaryDeploymentListener = new StartupSummaryDeploymentListener(deploymentStatusTracker); |
108 | 0 | addStartupListener(summaryDeploymentListener); |
109 | |
|
110 | 0 | if (!explicitAppSet) |
111 | |
{ |
112 | 0 | String[] dirApps = appsDir.list(DirectoryFileFilter.DIRECTORY); |
113 | 0 | apps = (String[]) ArrayUtils.addAll(apps, dirApps); |
114 | |
|
115 | 0 | String[] zipApps = appsDir.list(ZIP_APPS_FILTER); |
116 | 0 | for (int i = 0; i < zipApps.length; i++) |
117 | |
{ |
118 | 0 | zipApps[i] = StringUtils.removeEndIgnoreCase(zipApps[i], ZIP_FILE_SUFFIX); |
119 | |
} |
120 | |
|
121 | |
|
122 | |
|
123 | 0 | apps = (String[]) ArrayUtils.addAll(dirApps, zipApps); |
124 | 0 | Arrays.sort(apps); |
125 | 0 | } |
126 | |
else |
127 | |
{ |
128 | 0 | apps = appString.split(":"); |
129 | |
} |
130 | |
|
131 | 0 | apps = removeDuplicateAppNames(apps); |
132 | |
|
133 | 0 | for (String app : apps) |
134 | |
{ |
135 | |
final Application a; |
136 | 0 | String appMarker = app; |
137 | 0 | File applicationFile = null; |
138 | |
try |
139 | |
{ |
140 | |
|
141 | 0 | applicationFile = new File(appsDir, app + ".zip"); |
142 | 0 | if (applicationFile.exists() && applicationFile.isFile()) |
143 | |
{ |
144 | 0 | appMarker = app + ZIP_FILE_SUFFIX; |
145 | 0 | a = deployer.installFromAppDir(applicationFile.getName()); |
146 | |
} |
147 | |
else |
148 | |
{ |
149 | |
|
150 | 0 | applicationFile = new File(appsDir, appMarker); |
151 | 0 | a = appFactory.createApp(app); |
152 | |
} |
153 | 0 | applications.add(a); |
154 | |
} |
155 | 0 | catch (Throwable t) |
156 | |
{ |
157 | 0 | fireOnDeploymentFailure(appMarker, t); |
158 | |
|
159 | |
try |
160 | |
{ |
161 | 0 | URL url = applicationFile.toURI().toURL(); |
162 | 0 | addZombie(url); |
163 | |
} |
164 | 0 | catch (MalformedURLException e) |
165 | |
{ |
166 | 0 | if (logger.isDebugEnabled()) |
167 | |
{ |
168 | 0 | logger.debug("Error adding zombie app", e); |
169 | |
} |
170 | 0 | } |
171 | 0 | logger.error(String.format("Failed to create application [%s]", appMarker), t); |
172 | 0 | } |
173 | |
} |
174 | |
|
175 | |
|
176 | 0 | for (Application application : applications) |
177 | |
{ |
178 | |
try |
179 | |
{ |
180 | 0 | fireOnDeploymentStart(application.getAppName()); |
181 | 0 | deployer.deploy(application); |
182 | 0 | fireOnDeploymentSuccess(application.getAppName()); |
183 | |
} |
184 | 0 | catch (Throwable t) |
185 | |
{ |
186 | 0 | fireOnDeploymentFailure(application.getAppName(), t); |
187 | |
|
188 | |
|
189 | 0 | final String msg = miniSplash(String.format("Failed to deploy app '%s', see below", application.getAppName())); |
190 | 0 | logger.error(msg); |
191 | 0 | logger.error(t); |
192 | 0 | } |
193 | |
} |
194 | |
|
195 | 0 | for (StartupListener listener : startupListeners) |
196 | |
{ |
197 | |
try |
198 | |
{ |
199 | 0 | listener.onAfterStartup(); |
200 | |
} |
201 | 0 | catch (Throwable t) |
202 | |
{ |
203 | 0 | logger.error(t); |
204 | 0 | } |
205 | |
} |
206 | |
|
207 | |
|
208 | |
|
209 | 0 | if (!explicitAppSet) |
210 | |
{ |
211 | 0 | scheduleChangeMonitor(appsDir); |
212 | |
} |
213 | |
else |
214 | |
{ |
215 | 0 | if (logger.isInfoEnabled()) |
216 | |
{ |
217 | 0 | logger.info(miniSplash("Mule is up and running in a fixed app set mode")); |
218 | |
} |
219 | |
} |
220 | 0 | } |
221 | |
|
222 | |
private String[] removeDuplicateAppNames(String[] apps) |
223 | |
{ |
224 | 0 | List<String> appNames = new LinkedList<String>(); |
225 | |
|
226 | 0 | for (String appName : apps) |
227 | |
{ |
228 | 0 | if (!appNames.contains(appName)) |
229 | |
{ |
230 | 0 | appNames.add(appName); |
231 | |
} |
232 | |
} |
233 | |
|
234 | 0 | return appNames.toArray(ArrayUtils.EMPTY_STRING_ARRAY); |
235 | |
} |
236 | |
|
237 | |
protected void scheduleChangeMonitor(File appsDir) |
238 | |
{ |
239 | 0 | final int reloadIntervalMs = DEFAULT_CHANGES_CHECK_INTERVAL_MS; |
240 | 0 | appDirMonitorTimer = Executors.newSingleThreadScheduledExecutor(new AppDeployerMonitorThreadFactory()); |
241 | |
|
242 | 0 | appDirMonitorTimer.scheduleWithFixedDelay(new AppDirWatcher(appsDir), |
243 | |
0, |
244 | |
reloadIntervalMs, |
245 | |
TimeUnit.MILLISECONDS); |
246 | |
|
247 | 0 | if (logger.isInfoEnabled()) |
248 | |
{ |
249 | 0 | logger.info(miniSplash(String.format("Mule is up and kicking (every %dms)", reloadIntervalMs))); |
250 | |
} |
251 | 0 | } |
252 | |
|
253 | |
public void stop() |
254 | |
{ |
255 | 0 | if (appDirMonitorTimer != null) |
256 | |
{ |
257 | 0 | appDirMonitorTimer.shutdownNow(); |
258 | |
} |
259 | |
|
260 | |
|
261 | 0 | Collections.reverse(applications); |
262 | 0 | for (Application application : applications) |
263 | |
{ |
264 | |
try |
265 | |
{ |
266 | 0 | application.stop(); |
267 | 0 | application.dispose(); |
268 | |
} |
269 | 0 | catch (Throwable t) |
270 | |
{ |
271 | 0 | logger.error(t); |
272 | 0 | } |
273 | |
} |
274 | |
|
275 | 0 | } |
276 | |
|
277 | |
|
278 | |
|
279 | |
|
280 | |
|
281 | |
public Application findApplication(String appName) |
282 | |
{ |
283 | 0 | return (Application) CollectionUtils.find(applications, new BeanPropertyValueEqualsPredicate("appName", appName)); |
284 | |
} |
285 | |
|
286 | |
|
287 | |
|
288 | |
|
289 | |
public List<Application> getApplications() |
290 | |
{ |
291 | 0 | return Collections.unmodifiableList(applications); |
292 | |
} |
293 | |
|
294 | |
|
295 | |
|
296 | |
|
297 | |
public Map<URL, Long> getZombieMap() |
298 | |
{ |
299 | 0 | return zombieMap; |
300 | |
} |
301 | |
|
302 | |
protected MuleDeployer getDeployer() |
303 | |
{ |
304 | 0 | return deployer; |
305 | |
} |
306 | |
|
307 | |
public void setDeployer(MuleDeployer deployer) |
308 | |
{ |
309 | 0 | this.deployer = deployer; |
310 | 0 | } |
311 | |
|
312 | |
public void setAppFactory(ApplicationFactory appFactory) |
313 | |
{ |
314 | 0 | this.appFactory = appFactory; |
315 | 0 | } |
316 | |
|
317 | |
public ApplicationFactory getAppFactory() |
318 | |
{ |
319 | 0 | return appFactory; |
320 | |
} |
321 | |
|
322 | |
public ReentrantLock getLock() { |
323 | 0 | return lock; |
324 | |
} |
325 | |
|
326 | |
public void onApplicationInstalled(Application a) |
327 | |
{ |
328 | 0 | applications.add(a); |
329 | 0 | } |
330 | |
|
331 | |
protected void undeploy(Application app) |
332 | |
{ |
333 | 0 | if (logger.isInfoEnabled()) |
334 | |
{ |
335 | 0 | logger.info("================== Request to Undeploy Application: " + app.getAppName()); |
336 | |
} |
337 | |
|
338 | 0 | applications.remove(app); |
339 | 0 | deployer.undeploy(app); |
340 | 0 | } |
341 | |
|
342 | |
public void undeploy(String appName) |
343 | |
{ |
344 | 0 | Application app = (Application) CollectionUtils.find(applications, new BeanPropertyValueEqualsPredicate("appName", appName)); |
345 | 0 | undeploy(app); |
346 | 0 | } |
347 | |
|
348 | |
public void deploy(URL appArchiveUrl) throws IOException |
349 | |
{ |
350 | |
final Application application; |
351 | |
try |
352 | |
{ |
353 | 0 | application = deployer.installFrom(appArchiveUrl); |
354 | 0 | applications.add(application); |
355 | 0 | deployer.deploy(application); |
356 | |
} |
357 | 0 | catch (Throwable t) |
358 | |
{ |
359 | 0 | addZombie(appArchiveUrl); |
360 | 0 | if (t instanceof DeploymentException) |
361 | |
{ |
362 | |
|
363 | 0 | throw ((DeploymentException) t); |
364 | |
} |
365 | |
|
366 | 0 | final String msg = "Failed to deploy from URL: " + appArchiveUrl; |
367 | 0 | throw new DeploymentException(MessageFactory.createStaticMessage(msg), t); |
368 | 0 | } |
369 | 0 | } |
370 | |
|
371 | |
protected void addZombie(URL appArchiveUrl) |
372 | |
{ |
373 | |
|
374 | 0 | if (appArchiveUrl == null) |
375 | |
{ |
376 | 0 | return; |
377 | |
} |
378 | |
|
379 | 0 | long lastModified = FileUtils.getFileTimeStamp(appArchiveUrl); |
380 | |
|
381 | 0 | zombieMap.put(appArchiveUrl, lastModified); |
382 | 0 | } |
383 | |
|
384 | |
public void addStartupListener(StartupListener listener) |
385 | |
{ |
386 | 0 | this.startupListeners.add(listener); |
387 | 0 | } |
388 | |
|
389 | |
public void removeStartupListener(StartupListener listener) |
390 | |
{ |
391 | 0 | this.startupListeners.remove(listener); |
392 | 0 | } |
393 | |
|
394 | |
public void addDeploymentListener(DeploymentListener listener) |
395 | |
{ |
396 | 0 | this.deploymentListeners.add(listener); |
397 | 0 | } |
398 | |
|
399 | |
public void removeDeploymentListener(DeploymentListener listener) |
400 | |
{ |
401 | 0 | this.deploymentListeners.remove(listener); |
402 | 0 | } |
403 | |
|
404 | |
|
405 | |
|
406 | |
|
407 | |
|
408 | |
|
409 | |
|
410 | |
protected void fireOnDeploymentStart(String appName) |
411 | |
{ |
412 | 0 | for (DeploymentListener listener : deploymentListeners) |
413 | |
{ |
414 | |
try |
415 | |
{ |
416 | 0 | listener.onDeploymentStart(appName); |
417 | |
} |
418 | 0 | catch (Throwable t) |
419 | |
{ |
420 | 0 | logger.error("Listener failed to process onDeploymentStart notification", t); |
421 | 0 | } |
422 | |
} |
423 | 0 | } |
424 | |
|
425 | |
|
426 | |
|
427 | |
|
428 | |
|
429 | |
|
430 | |
|
431 | |
protected void fireOnDeploymentSuccess(String appName) |
432 | |
{ |
433 | 0 | for (DeploymentListener listener : deploymentListeners) |
434 | |
{ |
435 | |
try |
436 | |
{ |
437 | 0 | listener.onDeploymentSuccess(appName); |
438 | |
} |
439 | 0 | catch (Throwable t) |
440 | |
{ |
441 | 0 | logger.error("Listener failed to process onDeploymentSuccess notification", t); |
442 | 0 | } |
443 | |
} |
444 | 0 | } |
445 | |
|
446 | |
|
447 | |
|
448 | |
|
449 | |
|
450 | |
|
451 | |
|
452 | |
|
453 | |
protected void fireOnDeploymentFailure(String appName, Throwable cause) |
454 | |
{ |
455 | 0 | for (DeploymentListener listener : deploymentListeners) |
456 | |
{ |
457 | |
try |
458 | |
{ |
459 | 0 | listener.onDeploymentFailure(appName, cause); |
460 | |
} |
461 | 0 | catch (Throwable t) |
462 | |
{ |
463 | 0 | logger.error("Listener failed to process onDeploymentFailure notification", t); |
464 | 0 | } |
465 | |
} |
466 | 0 | } |
467 | |
|
468 | |
public interface StartupListener |
469 | |
{ |
470 | |
|
471 | |
|
472 | |
|
473 | |
|
474 | |
|
475 | |
void onAfterStartup(); |
476 | |
} |
477 | |
|
478 | |
|
479 | |
|
480 | |
|
481 | |
protected class AppDirWatcher implements Runnable |
482 | |
{ |
483 | |
protected File appsDir; |
484 | |
|
485 | |
protected volatile boolean dirty; |
486 | |
|
487 | |
public AppDirWatcher(final File appsDir) |
488 | 0 | { |
489 | 0 | this.appsDir = appsDir; |
490 | 0 | applications.addPropertyChangeListener(new PropertyChangeListener() |
491 | 0 | { |
492 | |
public void propertyChange(PropertyChangeEvent e) |
493 | |
{ |
494 | 0 | if (e instanceof ElementAddedEvent || e instanceof ElementRemovedEvent) |
495 | |
{ |
496 | 0 | if (logger.isDebugEnabled()) |
497 | |
{ |
498 | 0 | logger.debug("Deployed applications set has been modified, flushing state."); |
499 | |
} |
500 | 0 | dirty = true; |
501 | |
} |
502 | 0 | } |
503 | |
}); |
504 | 0 | } |
505 | |
|
506 | |
|
507 | |
|
508 | |
|
509 | |
|
510 | |
public void run() |
511 | |
{ |
512 | |
try |
513 | |
{ |
514 | 0 | if (logger.isDebugEnabled()) |
515 | |
{ |
516 | 0 | logger.debug("Checking for changes..."); |
517 | |
} |
518 | |
|
519 | |
|
520 | 0 | if (!lock.tryLock(0, TimeUnit.SECONDS)) |
521 | |
{ |
522 | 0 | if (logger.isDebugEnabled()) |
523 | |
{ |
524 | 0 | logger.debug("Another deployment operation in progress, will skip this cycle. Owner thread: " + |
525 | |
((DebuggableReentrantLock) lock).getOwner()); |
526 | |
} |
527 | |
return; |
528 | |
} |
529 | |
|
530 | |
|
531 | 0 | final String[] zips = appsDir.list(ZIP_APPS_FILTER); |
532 | 0 | String[] apps = appsDir.list(DirectoryFileFilter.DIRECTORY); |
533 | |
|
534 | |
|
535 | 0 | String[] currentAnchors = appsDir.list(new SuffixFileFilter(APP_ANCHOR_SUFFIX)); |
536 | 0 | if (logger.isDebugEnabled()) |
537 | |
{ |
538 | 0 | StringBuilder sb = new StringBuilder(); |
539 | 0 | sb.append(String.format("Current anchors:%n")); |
540 | 0 | for (String currentAnchor : currentAnchors) |
541 | |
{ |
542 | 0 | sb.append(String.format(" %s%n", currentAnchor)); |
543 | |
} |
544 | 0 | logger.debug(sb.toString()); |
545 | |
} |
546 | |
|
547 | 0 | String[] appAnchors = findExpectedAnchorFiles(); |
548 | |
|
549 | |
@SuppressWarnings("unchecked") |
550 | 0 | final Collection<String> deletedAnchors = CollectionUtils.subtract(Arrays.asList(appAnchors), Arrays.asList(currentAnchors)); |
551 | 0 | if (logger.isDebugEnabled()) |
552 | |
{ |
553 | 0 | StringBuilder sb = new StringBuilder(); |
554 | 0 | sb.append(String.format("Deleted anchors:%n")); |
555 | 0 | for (String deletedAnchor : deletedAnchors) |
556 | |
{ |
557 | 0 | sb.append(String.format(" %s%n", deletedAnchor)); |
558 | |
} |
559 | 0 | logger.debug(sb.toString()); |
560 | |
} |
561 | |
|
562 | 0 | for (String deletedAnchor : deletedAnchors) |
563 | |
{ |
564 | 0 | String appName = StringUtils.removeEnd(deletedAnchor, APP_ANCHOR_SUFFIX); |
565 | |
try |
566 | |
{ |
567 | 0 | if (findApplication(appName) != null) |
568 | |
{ |
569 | 0 | undeploy(appName); |
570 | |
} |
571 | 0 | else if (logger.isDebugEnabled()) |
572 | |
{ |
573 | 0 | logger.debug(String.format("Application [%s] has already been undeployed via API", appName)); |
574 | |
} |
575 | |
} |
576 | 0 | catch (Throwable t) |
577 | |
{ |
578 | 0 | logger.error("Failed to undeploy application: " + appName, t); |
579 | 0 | } |
580 | 0 | } |
581 | |
|
582 | |
|
583 | 0 | for (String zip : zips) |
584 | |
{ |
585 | 0 | URL url = null; |
586 | |
try |
587 | |
{ |
588 | |
|
589 | 0 | final String appName = StringUtils.removeEnd(zip, ".zip"); |
590 | 0 | Application app = (Application) CollectionUtils.find(applications, new BeanPropertyValueEqualsPredicate("appName", appName)); |
591 | 0 | if (app != null) |
592 | |
{ |
593 | 0 | undeploy(appName); |
594 | |
} |
595 | 0 | url = new File(appsDir, zip).toURI().toURL(); |
596 | |
|
597 | 0 | if (isZombieApplicationFile(url)) |
598 | |
{ |
599 | |
|
600 | 0 | continue; |
601 | |
} |
602 | |
|
603 | 0 | deploy(url); |
604 | |
} |
605 | 0 | catch (Throwable t) |
606 | |
{ |
607 | 0 | logger.error("Failed to deploy application archive: " + zip, t); |
608 | 0 | addZombie(url); |
609 | 0 | } |
610 | |
} |
611 | |
|
612 | |
|
613 | 0 | if (zips.length > 0 || dirty) |
614 | |
{ |
615 | 0 | apps = appsDir.list(DirectoryFileFilter.DIRECTORY); |
616 | |
} |
617 | |
|
618 | 0 | Collection deployedAppNames = CollectionUtils.collect(applications, new BeanToPropertyValueTransformer("appName")); |
619 | |
|
620 | |
|
621 | |
@SuppressWarnings("unchecked") |
622 | 0 | final Collection<String> addedApps = CollectionUtils.subtract(Arrays.asList(apps), deployedAppNames); |
623 | 0 | for (String addedApp : addedApps) |
624 | |
{ |
625 | |
try |
626 | |
{ |
627 | 0 | onNewExplodedApplication(addedApp); |
628 | |
} |
629 | 0 | catch (Throwable t) |
630 | |
{ |
631 | 0 | logger.error("Failed to deploy exploded application: " + addedApp, t); |
632 | |
try |
633 | |
{ |
634 | 0 | addZombie(new File(appsDir, addedApp).toURI().toURL()); |
635 | |
} |
636 | 0 | catch (MalformedURLException e) |
637 | |
{ |
638 | 0 | if (logger.isDebugEnabled()) |
639 | |
{ |
640 | 0 | logger.debug(e); |
641 | |
} |
642 | 0 | } |
643 | 0 | } |
644 | |
} |
645 | |
|
646 | |
} |
647 | 0 | catch (InterruptedException e) |
648 | |
{ |
649 | |
|
650 | 0 | Thread.currentThread().interrupt(); |
651 | |
} |
652 | |
finally |
653 | |
{ |
654 | 0 | if (lock.isHeldByCurrentThread()) |
655 | |
{ |
656 | 0 | lock.unlock(); |
657 | |
} |
658 | 0 | dirty = false; |
659 | 0 | } |
660 | 0 | } |
661 | |
|
662 | |
|
663 | |
|
664 | |
|
665 | |
|
666 | |
|
667 | |
private String[] findExpectedAnchorFiles() |
668 | |
{ |
669 | 0 | String[] appAnchors = new String[applications.size()]; |
670 | 0 | int i =0; |
671 | 0 | for (Application application : applications) |
672 | |
{ |
673 | 0 | appAnchors[i++] = application.getAppName() + APP_ANCHOR_SUFFIX; |
674 | |
} |
675 | 0 | return appAnchors; |
676 | |
} |
677 | |
|
678 | |
|
679 | |
|
680 | |
|
681 | |
|
682 | |
|
683 | |
|
684 | |
|
685 | |
|
686 | |
protected boolean isZombieApplicationFile(URL url) |
687 | |
{ |
688 | 0 | boolean result = false; |
689 | |
|
690 | 0 | if (FileUtils.isFile(url) && zombieMap.containsKey(url)) |
691 | |
{ |
692 | 0 | long originalTimeStamp = zombieMap.get(url); |
693 | 0 | long newTimeStamp = FileUtils.getFileTimeStamp(url); |
694 | |
|
695 | 0 | if (originalTimeStamp == newTimeStamp) |
696 | |
{ |
697 | 0 | result = true; |
698 | |
} |
699 | |
} |
700 | |
|
701 | 0 | return result; |
702 | |
} |
703 | |
|
704 | |
|
705 | |
|
706 | |
|
707 | |
protected void onNewExplodedApplication(String appName) throws Exception |
708 | |
{ |
709 | 0 | if (logger.isInfoEnabled()) |
710 | |
{ |
711 | 0 | logger.info("================== New Exploded Application: " + appName); |
712 | |
} |
713 | |
|
714 | 0 | Application a = appFactory.createApp(appName); |
715 | |
|
716 | 0 | onApplicationInstalled(a); |
717 | 0 | deployer.deploy(a); |
718 | 0 | } |
719 | |
|
720 | |
} |
721 | |
} |