All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.birt.report.session.ViewingSessionManager Maven / Gradle / Ivy

There is a newer version: 4.5.0
Show newest version
/*************************************************************************************
 * Copyright (c) 2008 Actuate Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Actuate Corporation - Initial implementation.
 ************************************************************************************/

package org.eclipse.birt.report.session;

import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

import org.eclipse.birt.report.exception.ViewerException;
import org.eclipse.birt.report.resource.BirtResources;
import org.eclipse.birt.report.resource.ResourceConstants;

/**
 * BIRT viewing session manager.
This class manages the BIRT viewing * sessions that reside under a master HTTP session. Each HTTP session can have * more than one BIRT viewing session. This class has two ways to trigger the * cleanup:
*
    *
  • After a given timeout value is reached. This value is checked after each * call to createSession().
  • *
  • After a given BIRT viewing session count threshold has been reached. * After each cleanup, the session count threshold will be increased using the * following formula: sessionCountThreshold = remainingSessionsCount + * remainingSessionsCount * sessionCountThreshold. The * remainingSessionsCount is the number of sessions that remain after cleanup. * If the result of this calculation is smaller than * minimumSessionCountThreshold, then sessionCountThreshold will take the value * of minimumSessionCountThreshold.
  • *
*/ public class ViewingSessionManager implements IViewingSessionManager, HttpSessionBindingListener, Serializable { private static final long serialVersionUID = -7623325281275814412L; private ViewingCache viewingCache; private long nextCleanupTime; /** * Linked hash map containing the ViewingSession objects in access order. */ private Map sessions; /** * HTTP session ID to which the contained BIRT viewing sessions belong. */ private String httpSessionId; /** * Expired flag. */ private boolean expired; /** * Session count threshold after which the cleanup process will be * triggered. This value will change dynamically according to the number of * remaining sessions after cleanup. */ private int sessionCountThreshold; private ViewingSessionConfig config; /** * Wrapper for the IViewingSession interface, to hook the interface's * methods. */ private static class ViewingSessionWrapper implements IViewingSession, Serializable { private static final long serialVersionUID = -5837896305154946951L; private IViewingSession session; private ViewingSessionManager manager; public ViewingSessionWrapper( ViewingSessionManager manager, IViewingSession session ) { this.manager = manager; this.session = session; } public IViewingSession getWrappedSession( ) { return session; } public String getCachedReportDocument( String reportFile, String viewerId ) { return session.getCachedReportDocument( reportFile, viewerId ); } public String getId( ) { return session.getId( ); } public String getImageTempFolder( ) { return session.getImageTempFolder( ); } public Date getLastAccess( ) { return session.getLastAccess( ); } public void invalidate( ) { synchronized ( manager ) { session.invalidate( ); // remove the session from the map manager.sessions.remove( session.getId( ) ); } } public boolean isExpired( ) { return session.isExpired( ); } public boolean isLocked( ) { return session.isLocked( ); } public void lock( ) { session.lock( ); } public void unlock( ) { session.unlock( ); manager.refreshSession( session ); manager.cleanUp( ); } public void refresh( ) { manager.refreshSession( session ); } } /** * Instantiates a new viewing session manager. * * @param viewingCache * viewing cache instance * @param httpSessionId * HTTP session ID * @param config * viewing session configuration */ public ViewingSessionManager( ViewingCache viewingCache, String httpSessionId, ViewingSessionConfig config ) { this.httpSessionId = httpSessionId; this.viewingCache = viewingCache; this.config = config; this.sessionCountThreshold = config.getMinimumSessionCountThreshold( ); // using LinkedHashMap to keep the insertion order and access time (LRU) this.sessions = new LinkedHashMap( config .getMinimumSessionCountThreshold( ), config .getSessionCountThresholdFactor( ), true ); this.expired = false; this.nextCleanupTime = new Date( ).getTime( ) + config.getSessionTimeout( ) * 1000l; } /** * Returns the cache manager used by this manager. * * @return the cacheManager */ public ViewingCache getCacheManager( ) { return viewingCache; } /** * @see * org.eclipse.birt.report.session.IViewingSessionManager#getHttpSessionId() */ public String getHttpSessionId( ) { return httpSessionId; } /** * @see * org.eclipse.birt.report.session.IViewingSessionManager#createSession() */ public synchronized IViewingSession createSession( ) throws ViewerException { checkExpired( ); cleanUp( ); if ( config.getMaximumSessionCount( ) > 0 && sessions.size( ) >= config.getMaximumSessionCount( ) ) { switch ( config.getMaxSessionCountPolicy( ) ) { case SESSION_POLICY_DISCARD_NEW : throw new ViewerException( BirtResources .getMessage( ResourceConstants.GENERAL_ERROR_VIEWING_SESSION_MAX_REACHED ) ); case SESSION_POLICY_DISCARD_OLDEST : if ( !deleteOldestSession( ) ) { // no oldest session could be removed (lock) throw new ViewerException( BirtResources .getMessage( ResourceConstants.GENERAL_ERROR_VIEWING_SESSION_MAX_REACHED ) ); } break; } } IViewingSession newSession = new ViewingSessionWrapper( this, new ViewingSession( httpSessionId, viewingCache ) ); sessions.put( newSession.getId( ), newSession ); return newSession; } /** * @see * org.eclipse.birt.report.session.IViewingSessionManager#getSession(java * .lang.String) */ public synchronized IViewingSession getSession( String id ) { checkExpired( ); ViewingSessionWrapper session = (ViewingSessionWrapper) sessions .get( id ); if ( session != null ) { session.getWrappedSession( ).refresh( ); } return session; } /** * @see org.eclipse.birt.report.session.IViewingSessionManager#invalidate() */ public synchronized void invalidate( ) { if ( expired ) { return; } expired = true; try { for ( Iterator> i = sessions .entrySet( ).iterator( ); i.hasNext( ); ) { Map.Entry entry = i.next( ); IViewingSession session = ((ViewingSessionWrapper) entry .getValue( )).getWrappedSession( ); if ( !session.isExpired( ) ) { while ( session.isLocked() ) { session.unlock( ); } session.invalidate( ); } } } finally { // clear master session cache viewingCache.clearSession( httpSessionId, null ); sessions.clear( ); } } /** * Refreshes the given session by calling its refresh() method * and by updating the internal map order. * @param session viewing session */ private synchronized void refreshSession( IViewingSession session ) { // touches the linked hash map to make it move // the entry to the end sessions.get( session.getId() ); session.refresh(); } /** * Removes a session id from the map. * * @param id * session id */ public synchronized void removeSession( String id ) { sessions.remove( id ); } /** * Requests a cleanup operation. The operation is only performed if the * session count threshold or the timeout value has been reached. * * @param sessions * sessions */ private synchronized void cleanUp( ) { long now = new Date( ).getTime( ); if ( now >= nextCleanupTime || sessions.size( ) > sessionCountThreshold ) { doCleanup( ); if ( sessions.size( ) > 0 ) { // the oldest date is the first entry in the linked hash map IViewingSession oldestSession = sessions.values( ).iterator( ) .next( ); nextCleanupTime = oldestSession.getLastAccess( ).getTime( ) + config.getSessionTimeout( ) * 1000l; } else { nextCleanupTime = now + config.getSessionTimeout( ) * 1000l; } int minimumThreshold = config.getMinimumSessionCountThreshold( ); float factor = config.getSessionCountThresholdFactor( ); sessionCountThreshold = sessions.size( ) + (int) ( sessions.size( ) * factor ); if ( sessionCountThreshold < minimumThreshold ) { sessionCountThreshold = minimumThreshold; } } } /** * Checks whether there are existing sessions that have expired and clean * them up accordingly. * * @param sessions * sessions */ private synchronized void doCleanup( ) { if ( sessions.size( ) == 0 ) { return; } long sessionTimeout = config.getSessionTimeout( ) * 1000l; long currentTime = new java.util.Date( ).getTime( ) - sessionTimeout; for ( Iterator> i = sessions .entrySet( ).iterator( ); i.hasNext( ); ) { Map.Entry entry = i.next( ); IViewingSession session = entry.getValue( ); Date lastAccess = session.getLastAccess( ); if ( currentTime >= lastAccess.getTime( ) && !session.isLocked( ) ) { if ( !session.isExpired( ) ) { ( (ViewingSessionWrapper) session ).getWrappedSession( ) .invalidate( ); } i.remove( ); } else { // since the linked hash map is ordered by insertion, the // iteration will stop as soon as the first non-expired session // is met. break; } } } /** * Deletes the oldest session that is not locked regardless whether it is * has expired or not. */ private boolean deleteOldestSession( ) { for ( Iterator> i = sessions .entrySet( ).iterator( ); i.hasNext( ); ) { Map.Entry entry = i.next( ); IViewingSession session = entry.getValue( ); if ( !session.isLocked( ) ) { ( (ViewingSessionWrapper) session ).getWrappedSession( ) .invalidate( ); i.remove( ); return true; } } return false; } /** * Asserts that the session has not expired. * * @throws ViewingSessionExpiredException */ private void checkExpired( ) { if ( expired ) { throw new IllegalStateException( BirtResources .getMessage( ResourceConstants.GENERAL_ERROR_VIEWING_SESSION_EXPIRED ) ); } } /** * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent) */ public void valueBound( HttpSessionBindingEvent event ) { } /** * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent) */ public void valueUnbound( HttpSessionBindingEvent event ) { synchronized (this) { if ( !expired ) { invalidate(); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy