Coverage report

  %line %branch
org.apache.jetspeed.tools.pamanager.PortletApplicationManager$DescriptorChangeMonitor$DescriptorChangeMonitorInfo
0% 
0% 

 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  * 
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  * 
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 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; // 10 seconds
 62  
     private static int DEFAULT_MAX_RETRIED_STARTS = 10; // 10 times retry PA
 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  
         // startInternal(contextName, warStruct, paClassLoader, true);        
 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  
                 // ignore errors during portal shutdown
 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  
                 	// we actually do not care about an exception in the remove operation...
 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  
 			// load the web.xml
 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  
                 // TODO: this is screwing up the PSML as its set all over the place to "jetspeed-layouts", not good
 332  
                 wa.setContextRoot("/" + paName);                
 333  
             }
 334  
 
 335  
 			pa.setWebApplicationDefinition(wa);
 336  
             
 337  
             // Make sure existing entities are refreshed with the most
 338  
             // recent PortletDefintion.
 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  
 		// register the portlet application
 368  
 		try
 369  
 		{
 370  
 			registry.registerPortletApplication(pa);
 371  
 			registered = true;
 372  
 			log.info("Registered the portlet application " + paName);
 373  
 
 374  
 			// add to search engine result
 375  
 			this.updateSearchEngine(false, pa);
 376  
 			
 377  
 			// and add to the current node info
 378  
 			nodeManager.addNode(new Long(pa.getId().toString()), pa.getName());
 379  
             
 380  
             // grant default permissions to portlet application
 381  
 			grantDefaultPermissions(paName);
 382  
             
 383  
             if ( autoCreateRoles && roleManager != null && pa.getWebApplicationDefinition().getSecurityRoles() != class="keyword">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  
             // create PA  from war (file) structure
 458  
             // paWar = new PortletApplicationWar(warStruct, contextName, "/" + contextName, checksum);
 459  
             paWar = new PortletApplicationWar(warStruct, contextName, contextPath, checksum);
 460  
             try
 461  
             {
 462  
                 if (paClassLoader == null)
 463  
                 {
 464  
                     paClassLoader = paWar.createClassloader(getClass().getClassLoader());
 465  
                 }                
 466  
                 // create checksum from PA descriptors
 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  
                     // nothing to be done about it anymore: this pa is beyond repair :(
 481  
                     throw new RegistryException(e);
 482  
                 }
 483  
                 register = false;
 484  
             }
 485  
 
 486  
 			// try to get the PA from database by context name
 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  
 //            if (register && (pa == null || checksum != pa.getChecksum()))
 510  
             if (register)
 511  
             {
 512  
             	if (pa == null)
 513  
             	{ 
 514  
             		// new
 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  
             				//only reason is that the file got somehow corrupted 
 553  
             				// so we really do not know what is going on here...
 554  
             				// the best chance at this point is to reregister (which might be the absolute wrong choice)
 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  
         						//database and local node info are in synch, so we assume that this is a brand new
 574  
         						// war .... let's deploy
 575  
         						reregister = true;
 576  
         						deploy = true;
 577  
                     		}
 578  
         					break;
 579  
         				}
 580  
         				case  NodeManager.NODE_OUTDATED:
 581  
         				{
 582  
                             // new version in database, maybe changed by a different cluster node
 583  
         				    if (log.isDebugEnabled())
 584  
         				    {
 585  
         				        log.debug("Node for Portlet application " + contextName + " is OUTDATED (local PA.id < DB PA.id).");
 586  
         				    }
 587  
             				//database version is older (determined by id) than the database 
 588  
         					//let's deploy and reregister
 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  
         					    // if the checksums do not match make sure the database is updated with the new PA from file system
 593  
         					    // I've observed "unavailable PA" in clustered env for the cluster node that reported OUTDATED state
 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  
         					// add to search engine result
 616  
         					this.updateSearchEngine(true, pa);
 617  
         					this.updateSearchEngine(false, pa);
 618  
         					
 619  
         					// and add to the current node info
 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  
             // monitor PA for changes
 656  
             // do not add monitor if a monitor already exists
 657  
             if (!monitored && changeMonitor != null)
 658  
             {
 659  
                 // this code should be hit only during startup process
 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  
             // ignore errors during portal shutdown
 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  
 		// todo keep (User)Prefs?
 773  
 		registry.removeApplication(pa);
 774  
         revokeDefaultPermissions(pa.getName());
 775  
 	}
 776  
     
 777  
     protected void grantDefaultPermissions(String paName)
 778  
     {
 779  
         try
 780  
         {
 781  
             // create a default permission for this portlet app, granting configured roles to the portlet application 
 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  
              * Constructor only used for looking up the matching registered one in monitorsInfo
 862  
              */
 863  
             public DescriptorChangeMonitorInfo(String contextName)
 864  0
             {
 865  0
                 this.contextName = contextName;
 866  0
             }
 867  
             
 868  
             public DescriptorChangeMonitorInfo(String contextName, String contextPath, ClassLoader paClassLoader, int paType, File paDir, long checksum)
 869  0
             {
 870  0
                 this.contextName = contextName;
 871  0
                 this.contextPath = contextPath;
 872  0
                 this.paClassLoader = paClassLoader;
 873  0
                 this.paType = paType;
 874  0
                 this.paDir = paDir.isAbsolute() ? paDir : paDir.getAbsoluteFile();
 875  0
                 this.checksum = checksum;
 876  
                 
 877  0
                 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  0
                 descriptorModificationTime = descriptors[1].lastModified();
 883  0
                 extendedDescriptorModificationTime = descriptors[2].lastModified();
 884  0
             }
 885  
             
 886  
             public String getContextName()
 887  
             {
 888  0
                 return contextName;
 889  
             }
 890  
             
 891  
             public ClassLoader getPAClassLoader()
 892  
             {
 893  0
                 return paClassLoader;
 894  
             }
 895  
             
 896  
             public int getPortletApplicationType()
 897  
             {
 898  0
                 return paType;
 899  
             }
 900  
             
 901  
             public File getPADir()
 902  
             {
 903  0
                 return paDir;
 904  
             }
 905  
 
 906  
             public long getChecksum()
 907  
             {
 908  0
                 return checksum;
 909  
             }
 910  
             
 911  
             public boolean isChanged()
 912  
             {
 913  0
                 if ( !obsolete)
 914  
                 {
 915  0
                     long newDescriptorModificationTime = descriptors[1].lastModified();
 916  0
                     long newExtendedDescriptorModificationTime = descriptors[2].lastModified();
 917  0
                     if ( descriptorModclass="keyword">ificationTime != newDescriptorModclass="keyword">ificationTime ||
 918  
                             extendedDescriptorModificationTime != newExtendedDescriptorModificationTime )
 919  
                     {
 920  0
                         descriptorModificationTime = newDescriptorModificationTime;
 921  0
                         extendedDescriptorModificationTime = newExtendedDescriptorModificationTime;
 922  0
                         long newChecksum = MultiFileChecksumHelper.getChecksum(descriptors);
 923  0
                     	if (log.isDebugEnabled())
 924  
                         {
 925  0
                     		log.debug("checksum check for descriptors for application " + contextName + ": old (" + checksum + ") new (" + newChecksum + ").");
 926  
                     	}
 927  0
                         if ( checksum != newChecksum )
 928  
                         {
 929  0
                         	if (log.isDebugEnabled())
 930  
                             {
 931  0
                         		log.debug("portlet descriptors for application " + contextName + " have changed.");
 932  
                         	}
 933  0
                             checksum = newChecksum;
 934  
                             // reset this to restart unsuccessful PA start handling for evers PA descriptor change
 935  0
                             unsuccessfulStarts = 0;
 936  0
                             return true;
 937  
                         }
 938  
                     }
 939  
                 }
 940  0
                 return false;
 941  
             }
 942  
             
 943  
             public void setObsolete()
 944  
             {
 945  0
                 obsolete = true;
 946  0
             }
 947  
             
 948  
             public boolean isObsolete()
 949  
             {
 950  0
                 return obsolete;
 951  
             }
 952  
 
 953  
             public int getUnsuccessfulStarts()
 954  
             {
 955  0
                 return unsuccessfulStarts;
 956  
             }
 957  
             
 958  
             public void setUnsuccessfulStarts(int unsuccessfulStarts)
 959  
             {
 960  0
                 this.unsuccessfulStarts = unsuccessfulStarts;
 961  0
             }
 962  
             
 963  
             public String getContextPath()
 964  
             {
 965  0
                 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  
                     // will be removed by checkDescriptorChanges on next iteration
 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  
                                 // try to restart PA if the PA-descriptors have change
 1094  
                                 // OR (if we encountered an exception while starting the PA)
 1095  
                                 // keep on trying to restart PA until maxRetriedStarts is reached
 1096  
                                 // This ensures we finally startup in a clustered enviroment, where parallel registration
 1097  
                                 // of PAs could lead to contraint violation eceptions in DB.
 1098  
                                 // see https://issues.apache.org/jira/browse/JS2-666
 1099  
                                 // Note: monitorInfo.isChanged() will reset unsuccessfulStarts to 0 if a PA descriptor change 
 1100  
                                 // has been detected (monitorInfo.isChanged() == true).
 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  
                                         // great! we have a successful start. set unsuccessful starts to 0
 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  
                                         // we encountered an error while starting the PA
 1121  
                                         // this could result from clustered environments problems (see above)
 1122  
                                         // increase unsuccessfulStarts until the maxRetriedStarts is reached
 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  
                                 // ignore filesystem and/or descriptor errors, maybe next time round they'll be fixed again
 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  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.