/*
* Created on Mar 30, 2003
*/
package net.sf.jportlet.portlet.application;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.jportlet.impl.PortletRequestImpl;
import net.sf.jportlet.impl.PortletResponseImpl;
import net.sf.jportlet.portlet.Portlet;
import net.sf.jportlet.portlet.PortletAdapter;
import net.sf.jportlet.portlet.PortletConfig;
import net.sf.jportlet.portlet.PortletException;
import net.sf.jportlet.portlet.PortletRequest;
import net.sf.jportlet.portlet.PortletResponse;
import net.sf.jportlet.portlet.User;
import net.sf.jportlet.portlet.descriptor.CacheDescriptor;
import net.sf.jportlet.portlet.descriptor.PortletDescriptor;
import net.sf.jportlet.portlet.event.ActionEvent;
import net.sf.jportlet.portlet.event.ActionListener;
import net.sf.jportlet.portlet.event.MessageEvent;
import net.sf.jportlet.portlet.event.MessageListener;
import net.sf.jportlet.service.cache.CacheRegion;
import net.sf.jportlet.service.cache.CacheService;
import net.sf.jportlet.service.cache.Cacheable;
import net.sf.jportlet.service.cache.CacheableImpl;
import net.sf.jportlet.service.interceptor.InterceptorFactoryService;
import net.sf.jportlet.service.velocity.VelocityService;
/**
* Proxy that intercepts all the calls to {@link Portlet}
*
* @author <a href="mailto:tchbansi@sourceforge.net">Herve Tchepannou</a>
*/
public class PortletProxy
extends PortletAdapter
implements ActionListener,
MessageListener
{
//~ Static fields/initializers ---------------------------------------------
private static final HashMap __templatePaths = new HashMap( );
public static final String ANONYMOUS_ID = PortletProxy.class.getName( ) + ":Anonymous";
static
{
__templatePaths.put( Portlet.Markup.HTML, "net/sf/jportlet/portlet/html/__proxy.vm" );
}
//~ Instance fields --------------------------------------------------------
private ActionListener _actionListener;
private CacheRegion _cacheRegion;
private String _cacheRegionId;
private PortletDescriptor _descriptor;
private Interceptor _interceptors[];
/** Time of the last time the portlet was rendered, indexed by {@link Portlet.Mode} */
private HashMap _lastService = new HashMap( );
private Log _log = LogFactory.getLog( PortletProxy.class );
private MessageListener _messageListener;
private Portlet _portlet;
//~ Constructors -----------------------------------------------------------
public PortletProxy( PortletDescriptor descriptor )
throws PortletException
{
try
{
String longname = PortletProxy.class.getName( ) + ":" + descriptor.getName( );
_descriptor = descriptor;
_portlet = ( Portlet ) descriptor.getPortletClass( ).newInstance( );
_log = LogFactory.getLog( longname );
_cacheRegionId = longname;
Class clazz = descriptor.getActionListenerClass( );
if ( clazz != null )
{
_actionListener = ( ActionListener ) clazz.newInstance( );
}
clazz = descriptor.getMessageListenerClass( );
if ( clazz != null )
{
_messageListener = ( MessageListener ) clazz.newInstance( );
}
}
catch ( Exception e )
{
throw new PortletException( e );
}
}
//~ Methods ----------------------------------------------------------------
/**
* @see net.sf.jportlet.portlet.event.ActionListener#actionPerformed(net.sf.jportlet.portlet.event.ActionEvent)
*/
public void actionPerformed( ActionEvent event )
throws PortletException
{
boolean debug = _log.isDebugEnabled( );
if ( debug )
{
_log.debug( "actionPerformed(): action=" + event.getAction( ) );
}
if ( _actionListener != null )
{
/* Calling the interceptors before */
Interceptor it[] = getInterceptors( );
for ( int i = 0; i < it.length ; i++ )
{
if ( debug )
{
_log.debug( "(before) calling interceptor: " + it[ i ].getClass( ).getName( ) );
}
if ( it[ i ].beforeActionPerformed(this, event) == Interceptor.SKIP )
{
if ( debug )
{
_log.debug( "...skipping" );
}
return;
}
}
/* performing the actions */
_actionListener.actionPerformed( event );
/* Calling the interceptor after */
for ( int i = it.length - 1; i >= 0; i-- )
{
if ( debug )
{
_log.debug( "(after) calling interceptor: " + it[ i ].getClass( ).getName( ) );
}
it[ i ].afterActionPerformed( this, event );
}
}
}
/*private void afterService( PortletRequest request,
PortletResponse response )
throws PortletException,
IOException
{
boolean debug = _log.isDebugEnabled( );
Interceptor it[] = getInterceptors( );
if ( it != null )
{
for ( int i = it.length - 1; i >= 0; i-- )
{
if ( debug )
{
_log.debug( "(after) calling interceptor: " + it[ i ].getClass( ).getName( ) );
}
it[ i ].afterService( this, request, response );
}
}
}
private int beforeService( PortletRequest request,
PortletResponse response )
throws PortletException,
IOException
{
boolean debug = _log.isDebugEnabled( );
Interceptor it[] = getInterceptors( );
if ( it != null )
{
for ( int i = 0; i < it.length; i++ )
{
if ( debug )
{
_log.debug( "(before) calling interceptor: " + it[ i ].getClass( ).getName( ) );
}
int code = it[ i ].beforeService( this, request, response );
if ( code != Interceptor.CONTINUE )
{
if ( debug )
{
_log.debug( "...skipping" );
}
return code;
}
}
}
return Interceptor.CONTINUE;
}*/
/**
* @see javax.servlet.Servlet#destroy()
*/
public void destroy( )
{
if ( _log.isDebugEnabled( ) )
{
_log.debug( "Destroying" );
}
super.destroy( );
_lastService.clear( );
_portlet.destroy( );
}
private String getCacheableId( CacheDescriptor cache,
PortletRequest request,
PortletResponse response )
{
/* No caching */
if ( ( cache == null ) || ( cache.getExpires( ) == 0 ) )
{
return null;
}
/* Create the id */
StringBuffer id = new StringBuffer( );
Portlet.Mode mode = request.getMode( );
id.append( '/' ).append( mode ).append( '/' ).append( request.getWindow( ).getState( ) );
if ( !cache.isShared( ) )
{
User usr = request.getUser( );
if ( usr == null )
{
id.append( '/' ).append( ANONYMOUS_ID );
}
else
{
id.append( '/' ).append( usr.getId( ) );
}
}
return id.toString( );
}
private CacheRegion getCacheRegion( )
throws PortletException
{
if ( _cacheRegion == null )
{
synchronized ( this )
{
CacheService cacheService = ( CacheService ) getPortletContext( ).getService( CacheService.NAME );
_cacheRegion = cacheService.getRegion( _cacheRegionId, true );
}
}
return _cacheRegion;
}
/**
* @return PortletDescriptor
*/
public PortletDescriptor getDescriptor( )
{
return _descriptor;
}
public Interceptor[] getInterceptors( )
throws PortletException
{
if ( _interceptors == null )
{
InterceptorFactoryService srv = ( InterceptorFactoryService ) getPortletContext( ).getService( InterceptorFactoryService.NAME );
Collection col = srv.getInterceptors( );
_interceptors = new Interceptor[ col.size( ) ];
Iterator it = col.iterator( );
for ( int i = 0; it.hasNext( ); i++ )
{
_interceptors[ i ] = ( Interceptor ) it.next( );
}
}
return _interceptors;
}
/**
* @see net.sf.jportlet.portlet.Portlet#getLastModified(net.sf.jportlet.portlet.PortletRequest)
*/
public long getLastModified( PortletRequest request )
{
return _portlet.getLastModified( request );
}
/**
* @return Portlet
*/
public Portlet getPortlet( )
{
return _portlet;
}
/**
* Return the body of the portlet. The body of the portlet is the what is
* written the the {@link PortletResponse} by {Portlet#service()}
*
* @param request
* @param response
* @return String
*/
public String getPortletBody( PortletRequestImpl request,
PortletResponseImpl response )
throws PortletException,
IOException
{
boolean debug = _log.isDebugEnabled( );
CacheDescriptor cache = _descriptor.getCacheDescriptor( request.getMode( ) );
String id = getCacheableId( cache, request, response );
PortletResponseImpl response2 = new PortletResponseImpl( this, request, response.getHttpResponse( ) );
String body = null;
CacheRegion region = null;
Cacheable cacheable;
/* Load the body from the cache */
if ( id != null )
{
if ( debug )
{
_log.debug( "Loading portlet body from the cache.id=" + id );
}
region = getCacheRegion( );
cacheable = region.get( id );
if ( cacheable != null )
{
if ( !isDirty( request ) )
{
if ( debug )
{
_log.debug( "...Portlet body found in the cache" );
}
body = ( String ) cacheable.getData( );
}
else
{
if ( debug )
{
_log.debug( "...Portlet dirty. expiring the portlet body" );
}
cacheable.expire( );
body = null;
}
}
}
else
{
if ( debug )
{
_log.debug( "Caching not supported" );
}
}
if ( body == null )
{
/* Generate the body */
if ( debug )
{
_log.debug( "Generating the portlet body" );
}
_portlet.service( request, response2 );
body = response2.getBuffer( ).toString( );
/* Cache the body */
if ( region != null )
{
if ( debug )
{
_log.debug( "...Caching the portlet body" );
}
cacheable = new CacheableImpl( id, body, 1000 * cache.getExpires( ) );
_cacheRegion.put( cacheable );
}
}
/* Bye */
return body;
}
/**
* @see net.sf.jportlet.portlet.Portlet#getPortletConfig()
*/
public PortletConfig getPortletConfig( )
{
return _portlet.getPortletConfig( );
}
/**
* @see net.sf.jportlet.portlet.Portlet#init(net.sf.jportlet.portlet.PortletConfig)
*/
public void init( PortletConfig portletConfig )
throws PortletException
{
if ( _log.isDebugEnabled( ) )
{
_log.debug( "Initializing" );
}
super.init( portletConfig );
/* Initializing the lastService to 0 */
Iterator it = Portlet.Mode.getAll( ).iterator( );
while ( it.hasNext( ) )
{
_lastService.put( it.next( ), new Long( 0 ) );
}
/* Initializing the portlet */
_portlet.init( portletConfig );
}
/**
* Returns <code>true</code> if the portlet has been modified since the last time the portlet has
* been rendered
*
* @param request
* @return boolean
*/
public boolean isDirty( PortletRequest request )
{
Long lastService = ( Long ) _lastService.get( request.getMode( ) );
return getLastModified( request ) > lastService.longValue( );
}
/**
* @see net.sf.jportlet.portlet.Portlet#login(net.sf.jportlet.portlet.PortletRequest)
*/
public void login( PortletRequest request )
throws PortletException
{
if ( _log.isDebugEnabled( ) )
{
_log.debug( "login" );
}
_portlet.login( request );
}
/**
* @see net.sf.jportlet.portlet.Portlet#logout(net.sf.jportlet.portlet.PortletRequest)
*/
public void logout( PortletRequest request )
throws PortletException
{
if ( _log.isDebugEnabled( ) )
{
_log.debug( "logout" );
}
_portlet.logout( request );
}
/**
* @see net.sf.jportlet.portlet.event.MessageListener#messageReceived(net.sf.jportlet.portlet.event.MessageEvent)
*/
public void messageReceived( MessageEvent event )
throws PortletException
{
if ( _log.isDebugEnabled( ) )
{
_log.debug( "messageReceived(): message=" + event.getMessage( ) );
}
if ( _messageListener != null )
{
_messageListener.messageReceived( event );
}
}
/**
* @see net.sf.jportlet.portlet.Portlet#service(net.sf.jportlet.portlet.PortletRequest, net.sf.jportlet.portlet.PortletResponse)
*/
public void service( PortletRequest request,
PortletResponse response )
throws PortletException,
IOException
{
boolean debug = _log.isDebugEnabled( );
if ( debug )
{
_log.debug( "service" );
}
/* Calling the interceptors before */
Interceptor it[] = getInterceptors( );
for ( int i = 0; i < it.length ; i++ )
{
if ( debug )
{
_log.debug( "(before) calling interceptor: " + it[ i ].getClass( ).getName( ) );
}
if ( it[ i ].beforeService( this, request, response ) == Interceptor.SKIP )
{
if ( debug )
{
_log.debug( "...skipping" );
}
return;
}
}
/* Render */
Portlet.Markup markup = request.getClient( ).getMarkup( );
String templatePath = ( String ) __templatePaths.get( markup );
if ( templatePath == null )
{
throw new PortletException( "No template for markup: " + markup );
}
VelocityService srv = ( VelocityService ) getPortletContext( ).getService( VelocityService.NAME );
srv.merge( templatePath, request, response );
if ( _log.isDebugEnabled( ) )
{
_log.debug( "request.pageContext=" + ( ( PortletRequestImpl ) request ).getPageContext( ) );
}
/* Call the interceptor after */
for ( int i = it.length - 1; i >= 0; i-- )
{
if ( debug )
{
_log.debug( "(after) calling interceptor: " + it[ i ].getClass( ).getName( ) );
}
it[ i ].afterService( this, request, response );
}
/* Update the date */
_lastService.put( request.getMode( ), new Long( System.currentTimeMillis( ) ) );
}
}