/*
* Copyright 2000-2001,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.factory;
import java.util.HashMap;
import java.util.Iterator;
import javax.portlet.Portlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.UnavailableException;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jetspeed.container.PortalAccessor;
import org.apache.jetspeed.om.common.portlet.PortletApplication;
import org.apache.pluto.om.portlet.PortletDefinition;
/**
* <p>
* JetspeedPortletFactory
* </p>
* <p>
*
* </p>
* @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
* @version $Id: JetspeedPortletFactory.java,v 1.7 2005/03/23 22:25:50 ate Exp $
*
*/
public class JetspeedPortletFactory implements PortletFactory
{
private HashMap portletCache;
private static final Log log = LogFactory.getLog(JetspeedPortletFactory.class);
private final HashMap classLoaderMap;
/**
*
*/
public JetspeedPortletFactory()
{
this.portletCache = new HashMap();
classLoaderMap = new HashMap();
}
public void registerPortletApplication(PortletApplication pa, ClassLoader cl)
{
synchronized (classLoaderMap)
{
unregisterPortletApplication(pa);
classLoaderMap.put(pa.getId().toString(), cl);
}
}
public void unregisterPortletApplication(PortletApplication pa)
{
synchronized (classLoaderMap)
{
synchronized (portletCache)
{
ClassLoader cl = (ClassLoader)classLoaderMap.remove(pa.getId().toString());
if ( cl != null )
{
ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
Iterator portletDefinitions = pa.getPortletDefinitions().iterator();
while (portletDefinitions.hasNext())
{
PortletDefinition pd = (PortletDefinition)portletDefinitions.next();
Portlet portlet = (Portlet)portletCache.remove(pd.getId().toString());
if ( portlet != null )
{
try
{
Thread.currentThread().setContextClassLoader(cl);
portlet.destroy();
}
finally
{
Thread.currentThread().setContextClassLoader(currentContextClassLoader);
}
}
}
}
}
}
}
/**
* Gets a portlet by either creating it or returning a handle to it from the portlet 'cache'
*
* @param portletDefinition The definition of the portlet
* @return PortletInstance
* @throws PortletException
*/
public PortletInstance getPortletInstance( ServletContext servletContext, PortletDefinition pd ) throws PortletException
{
PortletInstance portlet = null;
String portletName = pd.getId().toString();
PortletApplication pa = (PortletApplication)pd.getPortletApplicationDefinition();
try
{
synchronized (portletCache)
{
portlet = (PortletInstance)portletCache.get(portletName);
if (null != portlet)
{
return portlet;
}
ClassLoader paCl = (ClassLoader)classLoaderMap.get(pa.getId().toString());
if ( paCl == null )
{
throw new UnavailableException("Portlet Application "+pa.getName()+" not available");
}
ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
try
{
Class clazz = paCl.loadClass(pd.getClassName());
try
{
Thread.currentThread().setContextClassLoader(paCl);
// wrap new Portlet inside PortletInstance which ensures the destroy
// method will wait for all its invocation threads to complete
// and thereby releasing all its ClassLoader locks as needed for local portlets.
portlet = new JetspeedPortletInstance((Portlet)clazz.newInstance());
}
finally
{
Thread.currentThread().setContextClassLoader(currentContextClassLoader);
}
}
catch (Exception e)
{
String msg = "Cannot create Portlet instance "+pd.getClassName()+" for Portlet Application "+pa.getName();
log.error(msg,e);
throw new UnavailableException(msg);
}
PortletContext portletContext = PortalAccessor.createPortletContext(servletContext, pa);
PortletConfig portletConfig = PortalAccessor.createPortletConfig(portletContext, pd);
try
{
try
{
Thread.currentThread().setContextClassLoader(paCl);
portlet.init(portletConfig);
}
finally
{
Thread.currentThread().setContextClassLoader(currentContextClassLoader);
}
}
catch (PortletException e1)
{
log.error("Failed to initialize Portlet "+pd.getClassName()+" for Portlet Application "+pa.getName(), e1);
throw e1;
}
portletCache.put(portletName, portlet);
}
}
catch (PortletException pe)
{
throw pe;
}
catch (Throwable e)
{
log.error("PortletFactory: Failed to load portlet "+pd.getClassName(), e);
throw new UnavailableException( "Failed to load portlet " + pd.getClassName() +": "+e.toString());
}
return portlet;
}
public ClassLoader getPortletApplicationClassLoader(PortletApplication pa)
{
synchronized (classLoaderMap)
{
if ( pa != null )
{
return (ClassLoader)classLoaderMap.get(pa.getId().toString());
}
return null;
}
}
public boolean isPortletApplicationRegistered(PortletApplication pa)
{
return getPortletApplicationClassLoader(pa) != null;
}
}