1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.tools.pamanager;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.security.Permission;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.jetspeed.cluster.NodeManager;
30 import org.apache.jetspeed.components.portletentity.PortletEntityAccessComponent;
31 import org.apache.jetspeed.components.portletentity.PortletEntityNotDeletedException;
32 import org.apache.jetspeed.components.portletregistry.PortletRegistry;
33 import org.apache.jetspeed.components.portletregistry.RegistryException;
34 import org.apache.jetspeed.container.window.PortletWindowAccessor;
35 import org.apache.jetspeed.factory.PortletFactory;
36 import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
37 import org.apache.jetspeed.om.common.servlet.MutableWebApplication;
38 import org.apache.jetspeed.search.SearchEngine;
39 import org.apache.jetspeed.security.PermissionManager;
40 import org.apache.jetspeed.security.PortletPermission;
41 import org.apache.jetspeed.security.Role;
42 import org.apache.jetspeed.security.RoleManager;
43 import org.apache.jetspeed.security.SecurityException;
44 import org.apache.jetspeed.util.DirectoryHelper;
45 import org.apache.jetspeed.util.FileSystemHelper;
46 import org.apache.jetspeed.util.MultiFileChecksumHelper;
47 import org.apache.jetspeed.util.descriptor.PortletApplicationWar;
48 import org.apache.pluto.om.common.SecurityRole;
49 import org.apache.pluto.om.entity.PortletEntity;
50 import org.apache.pluto.om.entity.PortletEntityCtrl;
51 import org.apache.pluto.om.portlet.PortletDefinition;
52
53 /***
54 * PortletApplicationManager
55 *
56 * @author <a href="mailto:ate@douma.nu">Ate Douma</a>
57 * @version $Id: PortletApplicationManager.java,v 1.21 2005/04/09 00:24:44 shinsuke Exp $
58 */
59 public class PortletApplicationManager implements PortletApplicationManagement
60 {
61 private static int DEFAULT_DESCRIPTOR_CHANGE_MONITOR_INTERVAL = 10*1000;
62 private static int DEFAULT_MAX_RETRIED_STARTS = 10;
63 private static final Log log = LogFactory.getLog("deployment");
64
65 protected PortletEntityAccessComponent entityAccess;
66 protected PortletFactory portletFactory;
67 protected PortletRegistry registry;
68 protected PortletWindowAccessor windowAccess;
69 protected SearchEngine searchEngine;
70 protected RoleManager roleManager;
71 protected PermissionManager permissionManager;
72 protected boolean autoCreateRoles;
73 protected List permissionRoles;
74 protected int descriptorChangeMonitorInterval = DEFAULT_DESCRIPTOR_CHANGE_MONITOR_INTERVAL;
75 /***
76 * holds the max number of retries in case of unsuccessful PA start
77 * this addresses possible startup errors in clustered environments
78 */
79 protected int maxRetriedStarts = DEFAULT_MAX_RETRIED_STARTS;
80 protected DescriptorChangeMonitor monitor;
81 protected boolean started;
82 protected String appRoot;
83 protected NodeManager nodeManager;
84
85 /***
86 * Creates a new PortletApplicationManager object.
87 */
88 public PortletApplicationManager(PortletFactory portletFactory, PortletRegistry registry,
89 PortletEntityAccessComponent entityAccess, PortletWindowAccessor windowAccess,
90 PermissionManager permissionManager, SearchEngine searchEngine,
91 RoleManager roleManager, List permissionRoles, NodeManager nodeManager, String appRoot)
92 {
93 this.portletFactory = portletFactory;
94 this.registry = registry;
95 this.entityAccess = entityAccess;
96 this.windowAccess = windowAccess;
97 this.permissionManager = permissionManager;
98 this.searchEngine = searchEngine;
99 this.roleManager = roleManager;
100 this.permissionRoles = permissionRoles;
101 this.nodeManager = nodeManager;
102 this.appRoot = appRoot;
103 }
104
105 public void start()
106 {
107 if ( descriptorChangeMonitorInterval > 0 )
108 {
109 try
110 {
111 monitor = new DescriptorChangeMonitor(Thread.currentThread().getThreadGroup(),
112 "PortletApplicationManager Descriptor Change Monitor Thread", this, descriptorChangeMonitorInterval, maxRetriedStarts);
113
114 monitor.setContextClassLoader(getClass().getClassLoader());
115 monitor.start();
116 log.info("PortletApplicationManager Descriptor Change Monitor started!");
117 }
118 catch (Exception e)
119 {
120 log.warn("Unable to start PortletApplicationManager Descriptor Change Monitor: "+ e.toString(), e);
121 monitor.safeStop();
122 monitor = null;
123 }
124 }
125 started = true;
126 }
127
128 public void stop()
129 {
130 started = false;
131 if (monitor != null)
132 {
133 monitor.safeStop();
134 monitor = null;
135 }
136 }
137
138 public boolean isStarted()
139 {
140 return started;
141 }
142
143 public void setRoleManager(RoleManager roleManager)
144 {
145 this.roleManager = roleManager;
146 }
147
148 public void setAutoCreateRoles(boolean autoCreateRoles)
149 {
150 this.autoCreateRoles = autoCreateRoles;
151 }
152
153 public void setSearchEngine(SearchEngine searchEngine)
154 {
155 this.searchEngine = searchEngine;
156 }
157
158 private void checkStarted()
159 {
160 if (!started)
161 {
162 throw new IllegalStateException("Not started yet");
163 }
164 }
165
166 public void startLocalPortletApplication(String contextName, FileSystemHelper warStruct,
167 ClassLoader paClassLoader)
168 throws RegistryException
169 {
170 checkStarted();
171 startPA(contextName, "/"+contextName, warStruct, paClassLoader, MutablePortletApplication.LOCAL);
172 }
173
174 public void startInternalApplication(String contextName) throws RegistryException
175 {
176 checkStarted();
177 File webinf = new File (appRoot);
178 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
179 DirectoryHelper dir = new DirectoryHelper(webinf);
180 String appName = (contextName.startsWith("/")) ? contextName.substring(1) : contextName;
181 MutablePortletApplication app = registry.getPortletApplicationByIdentifier(appName);
182 if (app != null && app.getApplicationType() == MutablePortletApplication.LOCAL)
183 {
184 app.setApplicationType(MutablePortletApplication.INTERNAL);
185 registry.updatePortletApplication(app);
186 }
187 startPA(contextName, "/"+contextName, dir, contextClassLoader, MutablePortletApplication.INTERNAL);
188
189 }
190
191 public void startPortletApplication(String contextName, FileSystemHelper warStruct,
192 ClassLoader paClassLoader)
193 throws RegistryException
194 {
195 startPortletApplication(contextName, "/"+contextName, warStruct, paClassLoader);
196 }
197
198 public void startPortletApplication(String contextName, String contextPath, FileSystemHelper warStruct,
199 ClassLoader paClassLoader) throws RegistryException
200 {
201 checkStarted();
202 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
203 Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
204 try
205 {
206 startPA(contextName, contextPath, warStruct, paClassLoader, MutablePortletApplication.WEBAPP);
207 }
208 finally
209 {
210 Thread.currentThread().setContextClassLoader(contextClassLoader);
211 }
212
213 }
214
215 public void stopLocalPortletApplication(String contextName)
216 throws RegistryException
217 {
218 stopPA(contextName, MutablePortletApplication.LOCAL);
219 }
220
221 public void stopPortletApplication(String contextName)
222 throws RegistryException
223 {
224 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
225 Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
226 try
227 {
228 stopPA(contextName, MutablePortletApplication.WEBAPP);
229 }
230 finally
231 {
232 Thread.currentThread().setContextClassLoader(contextClassLoader);
233 }
234 }
235
236 public void unregisterPortletApplication(String paName)
237 throws RegistryException
238 {
239 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
240 Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
241 try
242 {
243 MutablePortletApplication pa = null;
244
245 try
246 {
247 pa = registry.getPortletApplication(paName);
248 }
249 catch (Exception e)
250 {
251
252 }
253
254
255 if (pa != null)
256 {
257 if (portletFactory.isPortletApplicationRegistered(pa))
258 {
259 throw new RegistryException("Portlet Application " + paName + " still running");
260 }
261
262 unregisterPortletApplication(pa, true);
263 try
264 {
265 nodeManager.removeNode(paName);
266 }
267 catch (Exception ee)
268 {
269
270 }
271 }
272 }
273 finally
274 {
275 Thread.currentThread().setContextClassLoader(contextClassLoader);
276 }
277 }
278
279 protected void checkValidContextName(String contextName, boolean local)
280 throws RegistryException
281 {
282 int prefixLength = LOCAL_PA_PREFIX.length();
283
284 if ((contextName.length() >= prefixLength)
285 && contextName.substring(0, prefixLength).equalsIgnoreCase(LOCAL_PA_PREFIX))
286 {
287 if (!local)
288 {
289 throw new RegistryException("Prefix \"" + LOCAL_PA_PREFIX
290 + "\" is reserved for Local Portlet Applications only.");
291 }
292 }
293 else if (local)
294 {
295 throw new RegistryException("Prefix \"" + LOCAL_PA_PREFIX
296 + "\" is required for Local Portlet Applications.");
297 }
298 }
299
300 protected MutablePortletApplication registerPortletApplication(PortletApplicationWar paWar,
301 MutablePortletApplication oldPA, int paType, ClassLoader paClassLoader)
302 throws RegistryException
303 {
304 if (oldPA != null)
305 {
306 unregisterPortletApplication(oldPA, false);
307 oldPA = null;
308 }
309
310 MutablePortletApplication pa = null;
311 boolean registered = false;
312 String paName = paWar.getPortletApplicationName();
313
314 try
315 {
316 log.info("Loading portlet.xml...." + paName);
317 pa = paWar.createPortletApp(paClassLoader);
318 pa.setApplicationType(paType);
319
320
321 log.info("Loading web.xml...." + paName);
322 MutableWebApplication wa = paWar.createWebApp();
323 paWar.validate();
324
325 if (paType == MutablePortletApplication.LOCAL)
326 {
327 wa.setContextRoot("<portal>");
328 }
329 else if (paType == MutablePortletApplication.INTERNAL)
330 {
331
332 wa.setContextRoot("/" + paName);
333 }
334
335 pa.setWebApplicationDefinition(wa);
336
337
338
339 Collection portletDefs = pa.getPortletDefinitions();
340 if(portletDefs != null && portletDefs.size() > 0)
341 {
342 Iterator pdItr = portletDefs.iterator();
343 while(pdItr.hasNext())
344 {
345 PortletDefinition pd = (PortletDefinition) pdItr.next();
346 Collection portletEntites = entityAccess.getPortletEntities(pd);
347 if(portletEntites != null && portletEntites.size() > 0)
348 {
349 Iterator peItr = portletEntites.iterator();
350 while(peItr.hasNext())
351 {
352 PortletEntityCtrl portletEntity = (PortletEntityCtrl) peItr.next();
353 portletEntity.setPortletDefinition(pd);
354 }
355 }
356 }
357 }
358 }
359 catch (Exception e)
360 {
361 String msg = "Failed to load portlet application for "
362 + paWar.getPortletApplicationName();
363 log.error(msg, e);
364 throw new RegistryException(msg);
365 }
366
367
368 try
369 {
370 registry.registerPortletApplication(pa);
371 registered = true;
372 log.info("Registered the portlet application " + paName);
373
374
375 this.updateSearchEngine(false, pa);
376
377
378 nodeManager.addNode(new Long(pa.getId().toString()), pa.getName());
379
380
381 grantDefaultPermissions(paName);
382
383 if ( autoCreateRoles && roleManager != null && pa.getWebApplicationDefinition().getSecurityRoles() != null )
384 {
385 try
386 {
387 Iterator rolesIter = pa.getWebApplicationDefinition().getSecurityRoles().iterator();
388 SecurityRole sr;
389 while ( rolesIter.hasNext() )
390 {
391 sr = (SecurityRole)rolesIter.next();
392 if ( !roleManager.roleExists(sr.getRoleName()) )
393 {
394 roleManager.addRole(sr.getRoleName());
395 log.info("AutoCreated role: "+sr.getRoleName()+" from portlet application "+paName+" its web definition");
396 }
397 }
398 }
399 catch (SecurityException sex)
400 {
401 log.warn("Failed to autoCreate roles for portlet application " + paName+": "+sex.getMessage(), sex);
402 }
403 }
404
405 return pa;
406 }
407 catch (Exception e)
408 {
409 String msg = "Failed to register portlet application, " + paName;
410 log.error(msg, e);
411
412 if (registered)
413 {
414 try
415 {
416 unregisterPortletApplication(pa, (paType == MutablePortletApplication.LOCAL));
417 }
418 catch (Exception re)
419 {
420 log.error("Failed to rollback registration of portlet application " + paName, re);
421 }
422 }
423
424 throw new RegistryException(msg, e);
425 }
426 }
427
428 protected void startPA(String contextName, String contextPath, FileSystemHelper warStruct,
429 ClassLoader paClassLoader, int paType)
430 throws RegistryException
431 {
432 startPA(contextName, contextPath, warStruct, paClassLoader, paType, 0);
433 }
434
435 protected void startPA(String contextName, String contextPath, FileSystemHelper warStruct,
436 ClassLoader paClassLoader, int paType, long checksum)
437 throws RegistryException
438 {
439 boolean register = true;
440 boolean monitored = false;
441 DescriptorChangeMonitor changeMonitor = this.monitor;
442 if (changeMonitor != null)
443 {
444 monitored = changeMonitor.isMonitored(contextName);
445 }
446 if (log.isDebugEnabled())
447 {
448 log.debug("Is portlet application " + contextName + " monitored? -> " + monitored);
449 }
450 PortletApplicationWar paWar = null;
451 try
452 {
453 if (log.isDebugEnabled())
454 {
455 log.debug("Try to start portlet application " + contextName + ".");
456 }
457
458
459 paWar = new PortletApplicationWar(warStruct, contextName, contextPath, checksum);
460 try
461 {
462 if (paClassLoader == null)
463 {
464 paClassLoader = paWar.createClassloader(getClass().getClassLoader());
465 }
466
467 checksum = paWar.getPortletApplicationChecksum();
468
469 if (log.isDebugEnabled())
470 {
471 log.debug("New checksum for portlet application " + contextName + " is " + checksum);
472 }
473 }
474 catch (IOException e)
475 {
476 String msg = "Invalid PA WAR for " + contextName;
477 log.error(msg, e);
478 if ( paClassLoader == null )
479 {
480
481 throw new RegistryException(e);
482 }
483 register = false;
484 }
485
486
487 MutablePortletApplication pa = registry.getPortletApplication(contextName);
488
489 if (pa != null)
490 {
491 if (log.isDebugEnabled())
492 {
493 log.debug("Portlet Application " + contextName + " found in registry.");
494 }
495 if ( pa.getApplicationType() != paType )
496 {
497 throw new RegistryException("Cannot start portlet application "+contextName+": as Application Types don't match: " + pa.getApplicationType() + " != " + paType);
498 }
499 if (!monitored && changeMonitor != null)
500 {
501 changeMonitor.remove(contextName);
502 }
503 if (log.isDebugEnabled())
504 {
505 log.debug("unregistering portlet application " + contextName + "...");
506 }
507 portletFactory.unregisterPortletApplication(pa);
508 }
509
510 if (register)
511 {
512 if (pa == null)
513 {
514
515 try
516 {
517 if (log.isDebugEnabled())
518 {
519 log.debug("Register new portlet application " + contextName + ".");
520 }
521 pa = registerPortletApplication(paWar, pa, paType, paClassLoader);
522 }
523 catch (Exception e)
524 {
525 String msg = "Error register new portlet application " + contextName + ".";
526
527 if (log.isDebugEnabled())
528 {
529 log.debug(msg);
530 }
531 throw new RegistryException(msg);
532
533 }
534 }
535 else
536 {
537 if (log.isDebugEnabled())
538 {
539 log.debug("Re-register existing portlet application " + contextName + ".");
540 }
541 int status = nodeManager.checkNode(new Long(pa.getId().toString()), pa.getName());
542 boolean reregister = false;
543 boolean deploy = false;
544 switch (status)
545 {
546 case NodeManager.NODE_NEW:
547 {
548 if (log.isDebugEnabled())
549 {
550 log.debug("Node for Portlet application " + contextName + " is NEW.");
551 }
552
553
554
555 log.warn("The portlet application " + pa.getName() + " is registered in the database but not locally .... we will reregister");
556 reregister = true;
557 if (checksum != pa.getChecksum())
558 {
559 log.warn("The provided portlet application " + pa.getName() + " is a different version than in the database (db-checksum=" + pa.getChecksum() + ", local-checksum=: " + checksum + ") .... we will redeploy (also to the database)");
560 deploy = true;
561 }
562 break;
563 }
564 case NodeManager.NODE_SAVED:
565 {
566 if (log.isDebugEnabled())
567 {
568 log.debug("Node for Portlet application " + contextName + " is SAVED.");
569 }
570 if (checksum != pa.getChecksum())
571 {
572 log.warn("The provided portlet application " + pa.getName() + " is a different version than in the local node info and the database (db-checksum=" + pa.getChecksum() + ", local-checksum=: " + checksum + ") .... we will reregister AND redeploy (also to the database)");
573
574
575 reregister = true;
576 deploy = true;
577 }
578 break;
579 }
580 case NodeManager.NODE_OUTDATED:
581 {
582
583 if (log.isDebugEnabled())
584 {
585 log.debug("Node for Portlet application " + contextName + " is OUTDATED (local PA.id < DB PA.id).");
586 }
587
588
589 if (checksum != pa.getChecksum())
590 {
591 log.error("The portlet application " + pa.getName() + " provided for the upgrade IS WRONG. The database checksum= " + pa.getChecksum() + ", but the local=" + checksum + "....THIS NEEDS TO BE CORRECTED");
592
593
594 deploy = true;
595 }
596 reregister = true;
597 break;
598 }
599 }
600 if (deploy)
601 {
602 if (log.isDebugEnabled())
603 {
604 log.debug("Register (deploy=true) Portlet application " + contextName + " in database.");
605 }
606 pa = registerPortletApplication(paWar, pa, paType, paClassLoader);
607 }
608 else
609 if (reregister)
610 {
611 if (log.isDebugEnabled())
612 {
613 log.debug("Re-Register (reregister=true) Portlet application " + contextName + ".");
614 }
615
616 this.updateSearchEngine(true, pa);
617 this.updateSearchEngine(false, pa);
618
619
620 try
621 {
622 nodeManager.addNode(new Long(pa.getId().toString()), pa.getName());
623 } catch (Exception e)
624 {
625 log.error("Adding node for portlet application " + pa.getName() + " caused exception" , e);
626 }
627 }
628
629
630 }
631 }
632 if (register)
633 {
634 if (log.isDebugEnabled())
635 {
636 log.debug("Register Portlet application " + contextName + " in portlet factory.");
637 }
638 portletFactory.registerPortletApplication(pa, paClassLoader);
639 }
640
641 if (!monitored && changeMonitor != null)
642 {
643 if (log.isDebugEnabled())
644 {
645 log.debug("Add change monitor for application " + contextName + " with checksum " + checksum + ".");
646 }
647 changeMonitor.monitor(contextName, contextPath, paClassLoader, paType, warStruct.getRootDirectory(), checksum);
648 }
649 }
650 catch (Exception e)
651 {
652 String msg = "Error starting portlet application " + contextName;
653
654 log.error(msg, e);
655
656
657 if (!monitored && changeMonitor != null)
658 {
659
660 if (log.isDebugEnabled())
661 {
662 log.debug("Add change monitor for application " + contextName + " and set unsuccessful starts to 1.");
663 }
664 changeMonitor.monitor(contextName, contextPath, paClassLoader, paType, warStruct.getRootDirectory(), checksum);
665 changeMonitor.get(contextName).setUnsuccessfulStarts(1);
666 }
667 throw new RegistryException(msg);
668 }
669 finally
670 {
671 if (paWar != null)
672 {
673 try
674 {
675 paWar.close();
676 }
677 catch (IOException e)
678 {
679 log.error("Failed to close PA WAR for " + contextName, e);
680 }
681 }
682 }
683 }
684
685 protected void stopPA(String contextName, int paType)
686 throws RegistryException
687 {
688 MutablePortletApplication pa = null;
689
690 try
691 {
692 pa = registry.getPortletApplication(contextName);
693 }
694 catch (Exception e)
695 {
696
697 }
698 if (pa != null && pa.getApplicationType() != paType)
699 {
700 throw new RegistryException("Cannot stop portlet application "+contextName+": as Application Types don't match: " + pa.getApplicationType() + " != " + paType);
701 }
702 DescriptorChangeMonitor monitor = this.monitor;
703 if ( monitor != null )
704 {
705 monitor.remove(contextName);
706 }
707 if (pa != null)
708 {
709 portletFactory.unregisterPortletApplication(pa);
710 }
711 }
712
713
714 protected void updateSearchEngine(boolean remove,MutablePortletApplication pa )
715 {
716 if (searchEngine != null)
717 {
718 if (remove)
719 {
720 searchEngine.remove(pa);
721 searchEngine.remove(pa.getPortletDefinitions());
722 log.info("Un-Registered the portlet application in the search engine... " + pa.getName());
723 }
724 else
725 {
726 searchEngine.add(pa);
727 searchEngine.add(pa.getPortletDefinitions());
728 log.info("Registered the portlet application in the search engine... " + pa.getName());
729 }
730 }
731
732 }
733 protected void unregisterPortletApplication(MutablePortletApplication pa,
734 boolean purgeEntityInfo)
735 throws RegistryException
736 {
737
738 updateSearchEngine(true,pa);
739 log.info("Remove all registry entries defined for portlet application " + pa.getName());
740
741 Iterator portlets = pa.getPortletDefinitions().iterator();
742
743 while (portlets.hasNext())
744 {
745 PortletDefinition portletDefinition = (PortletDefinition) portlets.next();
746 Iterator entities = entityAccess.getPortletEntities(portletDefinition)
747 .iterator();
748
749 while (entities.hasNext())
750 {
751 PortletEntity entity = (PortletEntity) entities.next();
752
753 if (purgeEntityInfo)
754 {
755 try
756 {
757 entityAccess.removePortletEntity(entity);
758 }
759 catch (PortletEntityNotDeletedException e)
760 {
761 String msg = "Failed to delete Portlet Entity " + entity.getId();
762 log.error(msg, e);
763 throw new RegistryException(msg, e);
764 }
765 }
766
767 entityAccess.removeFromCache(entity);
768 windowAccess.removeWindows(entity);
769 }
770 }
771
772
773 registry.removeApplication(pa);
774 revokeDefaultPermissions(pa.getName());
775 }
776
777 protected void grantDefaultPermissions(String paName)
778 {
779 try
780 {
781
782 Iterator roles = permissionRoles.iterator();
783 while (roles.hasNext())
784 {
785 String roleName = (String)roles.next();
786 Role userRole = roleManager.getRole(roleName);
787 if (userRole != null)
788 {
789 Permission permission = new PortletPermission(paName + "::*", "view, edit");
790 if (!permissionManager.permissionExists(permission))
791 {
792 permissionManager.addPermission(permission);
793 permissionManager.grantPermission(userRole.getPrincipal(), permission);
794 }
795 }
796 }
797 }
798 catch (SecurityException e)
799 {
800 log.error("Error granting default permissions for " + paName, e);
801 }
802 }
803
804 protected void revokeDefaultPermissions(String paName)
805 {
806 try
807 {
808 Iterator roles = permissionRoles.iterator();
809 while (roles.hasNext())
810 {
811 String roleName = (String)roles.next();
812 Role userRole = roleManager.getRole(roleName);
813 if (userRole != null)
814 {
815 Permission permission = new PortletPermission(paName + "::*", "view, edit");
816 if (permissionManager.permissionExists(permission))
817 {
818 permissionManager.removePermission(permission);
819 }
820
821 }
822 }
823 }
824 catch (SecurityException e)
825 {
826 log.error("Error revoking default permissions for " + paName, e);
827 }
828 }
829
830 public int getDescriptorChangeMonitorInterval()
831 {
832 return descriptorChangeMonitorInterval/1000;
833 }
834
835 public void setDescriptorChangeMonitorInterval(int descriptorChangeMonitorInterval)
836 {
837 this.descriptorChangeMonitorInterval = descriptorChangeMonitorInterval*1000;
838 }
839
840 private static class DescriptorChangeMonitor extends Thread
841 {
842 private static class DescriptorChangeMonitorInfo
843 {
844 private String contextName;
845 private String contextPath;
846 private ClassLoader paClassLoader;
847 private int paType;
848 private File paDir;
849 private File[] descriptors;
850 private long descriptorModificationTime;
851 private long extendedDescriptorModificationTime;
852 private long checksum;
853 private boolean obsolete;
854
855 /***
856 * holds the number of unsuccessful starts of the monitored PA
857 */
858 private int unsuccessfulStarts;
859
860
861
862
863 public DescriptorChangeMonitorInfo(String contextName)
864 {
865 this.contextName = contextName;
866 }
867
868 public DescriptorChangeMonitorInfo(String contextName, String contextPath, ClassLoader paClassLoader, int paType, File paDir, long checksum)
869 {
870 this.contextName = contextName;
871 this.contextPath = contextPath;
872 this.paClassLoader = paClassLoader;
873 this.paType = paType;
874 this.paDir = paDir.isAbsolute() ? paDir : paDir.getAbsoluteFile();
875 this.checksum = checksum;
876
877 this.descriptors = new File[] {
878 new File(paDir, PortletApplicationWar.WEB_XML_PATH),
879 new File(paDir, PortletApplicationWar.PORTLET_XML_PATH),
880 new File(paDir, PortletApplicationWar.EXTENDED_PORTLET_XML_PATH) };
881
882 descriptorModificationTime = descriptors[1].lastModified();
883 extendedDescriptorModificationTime = descriptors[2].lastModified();
884 }
885
886 public String getContextName()
887 {
888 return contextName;
889 }
890
891 public ClassLoader getPAClassLoader()
892 {
893 return paClassLoader;
894 }
895
896 public int getPortletApplicationType()
897 {
898 return paType;
899 }
900
901 public File getPADir()
902 {
903 return paDir;
904 }
905
906 public long getChecksum()
907 {
908 return checksum;
909 }
910
911 public boolean isChanged()
912 {
913 if ( !obsolete)
914 {
915 long newDescriptorModificationTime = descriptors[1].lastModified();
916 long newExtendedDescriptorModificationTime = descriptors[2].lastModified();
917 if ( descriptorModificationTime != newDescriptorModificationTime ||
918 extendedDescriptorModificationTime != newExtendedDescriptorModificationTime )
919 {
920 descriptorModificationTime = newDescriptorModificationTime;
921 extendedDescriptorModificationTime = newExtendedDescriptorModificationTime;
922 long newChecksum = MultiFileChecksumHelper.getChecksum(descriptors);
923 if (log.isDebugEnabled())
924 {
925 log.debug("checksum check for descriptors for application " + contextName + ": old (" + checksum + ") new (" + newChecksum + ").");
926 }
927 if ( checksum != newChecksum )
928 {
929 if (log.isDebugEnabled())
930 {
931 log.debug("portlet descriptors for application " + contextName + " have changed.");
932 }
933 checksum = newChecksum;
934
935 unsuccessfulStarts = 0;
936 return true;
937 }
938 }
939 }
940 return false;
941 }
942
943 public void setObsolete()
944 {
945 obsolete = true;
946 }
947
948 public boolean isObsolete()
949 {
950 return obsolete;
951 }
952
953 public int getUnsuccessfulStarts()
954 {
955 return unsuccessfulStarts;
956 }
957
958 public void setUnsuccessfulStarts(int unsuccessfulStarts)
959 {
960 this.unsuccessfulStarts = unsuccessfulStarts;
961 }
962
963 public String getContextPath()
964 {
965 return contextPath;
966 }
967 }
968
969 private PortletApplicationManager pam;
970 private long interval;
971 private boolean started = true;
972 private ArrayList monitorInfos;
973 private int maxRetriedStarts;
974
975 public DescriptorChangeMonitor(ThreadGroup group, String name, PortletApplicationManager pam, long interval, int maxretriedStarts)
976 {
977 super(group, name);
978 this.pam = pam;
979 this.interval = interval;
980 monitorInfos = new ArrayList();
981 setPriority(MIN_PRIORITY);
982 setDaemon(true);
983 this.maxRetriedStarts = maxretriedStarts;
984 }
985
986 public void run()
987 {
988 try
989 {
990 sleep(interval);
991 }
992 catch (InterruptedException e)
993 {
994 }
995 while (started)
996 {
997 checkDescriptorChanges();
998
999 try
1000 {
1001 sleep(interval);
1002 }
1003 catch (InterruptedException e)
1004 {
1005
1006 }
1007 }
1008 }
1009
1010 /***
1011 * notifies a switch variable that exits the watcher's montior loop started in the <code>run()</code> method.
1012 */
1013 public synchronized void safeStop()
1014 {
1015 started = false;
1016 monitorInfos.clear();
1017 }
1018
1019 public synchronized void monitor(String contextName, String contextPath, ClassLoader paClassLoader, int paType, File paDir, long checksum)
1020 {
1021 monitorInfos.add(new DescriptorChangeMonitorInfo(contextName, contextPath, paClassLoader, paType, paDir, checksum));
1022 }
1023
1024 public synchronized void remove(String contextName)
1025 {
1026 DescriptorChangeMonitorInfo monitorInfo;
1027 for ( int i = monitorInfos.size()-1; i > -1; i-- )
1028 {
1029 monitorInfo = (DescriptorChangeMonitorInfo)monitorInfos.get(i);
1030 if (contextName.equals(monitorInfo.getContextName()))
1031 {
1032
1033 monitorInfo.setObsolete();
1034 break;
1035 }
1036 }
1037 }
1038
1039 public synchronized DescriptorChangeMonitorInfo get(String contextName)
1040 {
1041 DescriptorChangeMonitorInfo monitorInfo;
1042 for ( int i = monitorInfos.size()-1; i > -1; i-- )
1043 {
1044 monitorInfo = (DescriptorChangeMonitorInfo)monitorInfos.get(i);
1045 if (contextName.equals(monitorInfo.getContextName()))
1046 {
1047 return monitorInfo;
1048 }
1049 }
1050 return null;
1051 }
1052
1053 public boolean isMonitored(String contextName)
1054 {
1055 DescriptorChangeMonitorInfo monitorInfo = this.get(contextName);
1056 if (monitorInfo != null && !monitorInfo.isObsolete())
1057 {
1058 return true;
1059 }
1060 return false;
1061 }
1062
1063 private void checkDescriptorChanges()
1064 {
1065 int size;
1066 synchronized (this)
1067 {
1068 size = monitorInfos.size();
1069 }
1070
1071 if (log.isDebugEnabled())
1072 {
1073 log.debug("check for portlet application descriptor changes.");
1074 }
1075
1076 for (int i = size-1; i > -1; i--)
1077 {
1078 DescriptorChangeMonitorInfo monitorInfo;
1079 synchronized (this)
1080 {
1081 if ( started )
1082 {
1083 monitorInfo = (DescriptorChangeMonitorInfo)monitorInfos.get(i);
1084 if (monitorInfo.isObsolete())
1085 {
1086 monitorInfos.remove(i);
1087 }
1088 else
1089 {
1090 try
1091 {
1092 int unsuccessfulStarts = monitorInfo.getUnsuccessfulStarts();
1093
1094
1095
1096
1097
1098
1099
1100
1101 if (monitorInfo.isChanged() || (unsuccessfulStarts > 0 && unsuccessfulStarts <= maxRetriedStarts))
1102 {
1103 try
1104 {
1105 pam.startPA(monitorInfo.getContextName(), monitorInfo.getContextPath(), new DirectoryHelper(monitorInfo.getPADir()),
1106 monitorInfo.getPAClassLoader(), monitorInfo.getPortletApplicationType(), monitorInfo.getChecksum());
1107
1108 monitorInfo.setUnsuccessfulStarts(0);
1109 }
1110 catch (Exception e)
1111 {
1112 if (monitorInfo.isChanged())
1113 {
1114 log.error("Failed to restart PortletApplication "+monitorInfo.getContextName(),e);
1115 }
1116 else if (log.isWarnEnabled())
1117 {
1118 log.warn("Failed to restart PortletApplication "+monitorInfo.getContextName(),e);
1119 }
1120
1121
1122
1123 monitorInfo.setUnsuccessfulStarts(unsuccessfulStarts + 1);
1124 if (log.isDebugEnabled())
1125 {
1126 log.debug("Number of unsuccessful PA starts is " + monitorInfo.getUnsuccessfulStarts() + ".");
1127 }
1128 if (monitorInfo.getUnsuccessfulStarts() > maxRetriedStarts)
1129 {
1130 log.error("Max number of retries (" + maxRetriedStarts +") reached. Ignoring Monitor for " + monitorInfo.getContextName());
1131 }
1132 }
1133 }
1134 }
1135 catch (Exception e)
1136 {
1137
1138 log.error("Descriptor Change check failure for PortletApplication "+monitorInfo.getContextName(),e);
1139 }
1140 }
1141 }
1142 }
1143 }
1144 }
1145 }
1146
1147 public void setMaxRetriedStarts(int maxRetriedStarts)
1148 {
1149 this.maxRetriedStarts = maxRetriedStarts;
1150 }
1151
1152 public int getMaxRetriedStarts()
1153 {
1154 return maxRetriedStarts;
1155 }
1156 }