/*
* Copyright 2000-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jetspeed.tools.pamanager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jetspeed.components.portletentity.PortletEntityAccessComponent;
import org.apache.jetspeed.components.portletentity.PortletEntityNotDeletedException;
import org.apache.jetspeed.components.portletregistry.PortletRegistry;
import org.apache.jetspeed.components.portletregistry.RegistryException;
import org.apache.jetspeed.container.window.PortletWindowAccessor;
import org.apache.jetspeed.factory.PortletFactory;
import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
import org.apache.jetspeed.om.common.servlet.MutableWebApplication;
import org.apache.jetspeed.search.SearchEngine;
import org.apache.jetspeed.security.RoleManager;
import org.apache.jetspeed.util.FileSystemHelper;
import org.apache.jetspeed.util.descriptor.PortletApplicationWar;
import org.apache.pluto.om.common.SecurityRole;
import org.apache.pluto.om.entity.PortletEntity;
import org.apache.pluto.om.portlet.PortletDefinition;
import java.io.IOException;
import java.util.Iterator;
/**
* PortletApplicationManager
*
* @author <a href="mailto:ate@douma.nu">Ate Douma</a>
* @version $Id: PortletApplicationManager.java,v 1.20 2005/03/26 22:05:13 ate Exp $
*/
public class PortletApplicationManager implements PortletApplicationManagement
{
private static final Log log = LogFactory.getLog("deployment");
private static final String PORTLET_XML = "WEB-INF/portlet.xml";
protected PortletEntityAccessComponent entityAccess;
protected PortletFactory portletFactory;
protected PortletRegistry registry;
protected PortletWindowAccessor windowAccess;
protected SearchEngine searchEngine;
protected RoleManager roleManager;
protected boolean autoCreateRoles;
/**
* Creates a new PortletApplicationManager object.
*/
public PortletApplicationManager(PortletFactory portletFactory, PortletRegistry registry,
PortletEntityAccessComponent entityAccess, PortletWindowAccessor windowAccess)
{
this.portletFactory = portletFactory;
this.registry = registry;
this.entityAccess = entityAccess;
this.windowAccess = windowAccess;
}
public void setRoleManager(RoleManager roleManager)
{
this.roleManager = roleManager;
}
public void setAutoCreateRoles(boolean autoCreateRoles)
{
this.autoCreateRoles = autoCreateRoles;
}
public void setSearchEngine(SearchEngine searchEngine)
{
this.searchEngine = searchEngine;
}
public void startLocalPortletApplication(String contextName, FileSystemHelper warStruct,
ClassLoader paClassLoader)
throws RegistryException
{
checkValidContextName(contextName, true);
startPA(contextName, warStruct, paClassLoader, true);
}
public void startPortletApplication(String contextName, FileSystemHelper warStruct,
ClassLoader paClassLoader)
throws RegistryException
{
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try
{
checkValidContextName(contextName, false);
startPA(contextName, warStruct, paClassLoader, false);
}
finally
{
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}
public void stopLocalPortletApplication(String contextName)
throws RegistryException
{
checkValidContextName(contextName, true);
stopPA(contextName);
}
public void stopPortletApplication(String contextName)
throws RegistryException
{
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try
{
checkValidContextName(contextName, false);
stopPA(contextName);
}
finally
{
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}
public void unregisterPortletApplication(String paName)
throws RegistryException
{
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try
{
MutablePortletApplication pa = null;
try
{
pa = (MutablePortletApplication) registry.getPortletApplication(paName);
}
catch (Exception e)
{
// ignore errors during portal shutdown
}
if (pa != null)
{
if (portletFactory.getPortletApplicationClassLoader(pa) != null)
{
throw new RegistryException("Portlet Application " + paName + " still running");
}
unregisterPortletApplication(pa, true);
}
}
finally
{
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}
protected void checkValidContextName(String contextName, boolean local)
throws RegistryException
{
int prefixLength = LOCAL_PA_PREFIX.length();
if ((contextName.length() >= prefixLength)
&& contextName.substring(0, prefixLength).equalsIgnoreCase(LOCAL_PA_PREFIX))
{
if (!local)
{
throw new RegistryException("Prefix \"" + LOCAL_PA_PREFIX
+ "\" is reserved for Local Portlet Applications only.");
}
}
else if (local)
{
throw new RegistryException("Prefix \"" + LOCAL_PA_PREFIX
+ "\" is required for Local Portlet Applications.");
}
}
protected MutablePortletApplication registerPortletApplication(PortletApplicationWar paWar,
MutablePortletApplication oldPA, boolean local)
throws RegistryException
{
if (oldPA != null)
{
unregisterPortletApplication(oldPA, false);
oldPA = null;
}
MutablePortletApplication pa = null;
boolean registered = false;
String paName = paWar.getPortletApplicationName();
try
{
log.info("Loading portlet.xml...." + paName);
pa = paWar.createPortletApp();
if (local)
{
pa.setApplicationType(MutablePortletApplication.LOCAL);
}
else
{
pa.setApplicationType(MutablePortletApplication.WEBAPP);
}
// load the web.xml
log.info("Loading web.xml...." + paName);
MutableWebApplication wa = paWar.createWebApp();
paWar.validate();
if (local)
{
wa.setContextRoot("<portal>");
}
pa.setWebApplicationDefinition(wa);
}
catch (Exception e)
{
String msg = "Failed to load portlet application for "
+ paWar.getPortletApplicationName();
log.error(msg);
throw new RegistryException(msg);
}
// register the portlet application
try
{
registry.registerPortletApplication(pa);
registered = true;
log.info("Registered the portlet application " + paName);
// add to search engine result
if (searchEngine != null)
{
searchEngine.add(pa);
searchEngine.add(pa.getPortletDefinitions());
log.info("Registered the portlet application in the search engine... " + paName);
}
if ( autoCreateRoles && roleManager != null && pa.getWebApplicationDefinition().getSecurityRoles() != null )
{
try
{
Iterator rolesIter = pa.getWebApplicationDefinition().getSecurityRoles().iterator();
SecurityRole sr;
while ( rolesIter.hasNext() )
{
sr = (SecurityRole)rolesIter.next();
if ( !roleManager.roleExists(sr.getRoleName()) )
{
roleManager.addRole(sr.getRoleName());
log.info("AutoCreated role: "+sr.getRoleName()+" from portlet application "+paName+" its web definition");
}
}
}
catch (SecurityException sex)
{
log.warn("Failed to autoCreate roles for portlet application " + paName+": "+sex.getMessage(), sex);
}
}
return pa;
}
catch (Exception e)
{
String msg = "Failed to register portlet application, " + paName;
log.error(msg, e);
if (registered)
{
try
{
unregisterPortletApplication(pa, local);
}
catch (Exception re)
{
log.error("Failed to rollback registration of portlet application" + paName, re);
}
}
throw new RegistryException(msg, e);
}
}
protected void startPA(String contextName, FileSystemHelper warStruct,
ClassLoader paClassLoader, boolean local)
throws RegistryException
{
PortletApplicationWar paWar = null;
try
{
try
{
paWar = new PortletApplicationWar(warStruct, contextName, "/" + contextName);
if (paClassLoader == null)
{
paClassLoader = paWar.createClassloader(getClass().getClassLoader());
}
}
catch (IOException e)
{
String msg = "Failed to create PA WAR for " + contextName;
log.error(msg, e);
throw new RegistryException(msg, e);
}
MutablePortletApplication pa = (MutablePortletApplication) registry
.getPortletApplication(contextName);
if ((pa != null) && (paWar.getPortletApplicationChecksum() == pa.getChecksum()))
{
portletFactory.unregisterPortletApplication(pa);
}
else
{
pa = registerPortletApplication(paWar, pa, local);
}
portletFactory.registerPortletApplication(pa, paClassLoader);
}
finally
{
if (paWar != null)
{
try
{
paWar.close();
}
catch (IOException e)
{
log.error("Failed to close PA WAR for " + contextName, e);
}
}
}
}
protected void stopPA(String contextName)
throws RegistryException
{
MutablePortletApplication pa = null;
try
{
pa = (MutablePortletApplication) registry.getPortletApplication(contextName);
}
catch (Exception e)
{
// ignore errors during portal shutdown
}
if (pa != null)
{
portletFactory.unregisterPortletApplication(pa);
}
}
protected void unregisterPortletApplication(MutablePortletApplication pa,
boolean purgeEntityInfo)
throws RegistryException
{
if (searchEngine != null)
{
searchEngine.remove(pa);
searchEngine.remove(pa.getPortletDefinitions());
}
log.info("Remove all registry entries defined for portlet application " + pa.getName());
Iterator portlets = pa.getPortletDefinitions().iterator();
while (portlets.hasNext())
{
PortletDefinition portletDefinition = (PortletDefinition) portlets.next();
Iterator entities = entityAccess.getPortletEntities(portletDefinition)
.iterator();
while (entities.hasNext())
{
PortletEntity entity = (PortletEntity) entities.next();
if (purgeEntityInfo)
{
try
{
entityAccess.removePortletEntity(entity);
}
catch (PortletEntityNotDeletedException e)
{
String msg = "Failed to delete Portlet Entity " + entity.getId();
log.error(msg, e);
throw new RegistryException(msg, e);
}
}
entityAccess.removeFromCache(entity);
windowAccess.removeWindows(entity);
}
}
// todo keep (User)Prefs?
registry.removeApplication(pa);
}
}