blob: 3a87d0476268e6584a1d10220c7d2dc2b21dc359 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002, 2012 Innoopract Informationssysteme GmbH 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:
* Innoopract Informationssysteme GmbH - initial API and implementation
* EclipseSource - ongoing development
******************************************************************************/
package org.eclipse.rap.rwt.internal.service;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import org.eclipse.rap.rwt.client.Client;
import org.eclipse.rap.rwt.client.service.ClientInfo;
import org.eclipse.rap.rwt.internal.application.ApplicationContextImpl;
import org.eclipse.rap.rwt.internal.application.ApplicationContextUtil;
import org.eclipse.rap.rwt.internal.client.ClientSelector;
import org.eclipse.rap.rwt.internal.lifecycle.ContextUtil;
import org.eclipse.rap.rwt.internal.lifecycle.ISessionShutdownAdapter;
import org.eclipse.rap.rwt.internal.util.ParamCheck;
import org.eclipse.rap.rwt.internal.util.SerializableLock;
import org.eclipse.rap.rwt.service.UISession;
import org.eclipse.rap.rwt.service.UISessionEvent;
import org.eclipse.rap.rwt.service.UISessionListener;
import org.eclipse.swt.internal.SerializableCompatibility;
public final class UISessionImpl
implements UISession, HttpSessionBindingListener, SerializableCompatibility
{
private static final String ATTR_SESSION_STORE = UISessionImpl.class.getName();
private static final String ATTR_LOCALE = UISessionImpl.class.getName() + "#locale";
private final SerializableLock requestLock;
private final SerializableLock lock;
private final Map<String, Object> attributes;
private final Set<UISessionListener> listeners;
private final String id;
private transient HttpSession httpSession;
private boolean bound;
private boolean inDestroy;
private transient ISessionShutdownAdapter shutdownAdapter;
public UISessionImpl( HttpSession httpSession ) {
ParamCheck.notNull( httpSession, "httpSession" );
requestLock = new SerializableLock();
lock = new SerializableLock();
attributes = new HashMap<String, Object>();
listeners = new HashSet<UISessionListener>();
id = httpSession.getId();
bound = true;
this.httpSession = httpSession;
}
public void setShutdownAdapter( ISessionShutdownAdapter adapter ) {
shutdownAdapter = adapter;
if( shutdownAdapter != null ) {
shutdownAdapter.setUISession( this );
shutdownAdapter.setShutdownCallback( new Runnable() {
public void run() {
destroy();
}
} );
}
}
public ISessionShutdownAdapter getShutdownAdapter() {
return shutdownAdapter;
}
public Object getAttribute( String name ) {
ParamCheck.notNull( name, "name" );
Object result = null;
synchronized( lock ) {
result = attributes.get( name );
}
return result;
}
public boolean setAttribute( String name, Object value ) {
ParamCheck.notNull( name, "name" );
boolean result = false;
synchronized( lock ) {
if( bound ) {
result = true;
removeAttributeInternal( name );
attributes.put( name, value );
}
}
return result;
}
public boolean removeAttribute( String name ) {
ParamCheck.notNull( name, "name" );
boolean result = false;
synchronized( lock ) {
if( bound ) {
result = true;
removeAttributeInternal( name );
}
}
return result;
}
public Enumeration<String> getAttributeNames() {
return createAttributeNameEnumeration();
}
public String getId() {
return id;
}
public HttpSession getHttpSession() {
synchronized( lock ) {
return httpSession;
}
}
public void attachHttpSession( HttpSession httpSession ) {
ParamCheck.notNull( httpSession, "httpSession" );
synchronized( lock ) {
this.httpSession = httpSession;
}
}
public boolean isBound() {
synchronized( lock ) {
return bound;
}
}
public Client getClient() {
ApplicationContextImpl applicationContext = ApplicationContextUtil.get( this );
ClientSelector clientSelector = applicationContext.getClientSelector();
return clientSelector.getSelectedClient( this );
}
public Locale getLocale() {
Locale locale = ( Locale )getAttribute( ATTR_LOCALE );
if( locale == null ) {
ClientInfo clientInfo = getClient().getService( ClientInfo.class );
if( clientInfo != null ) {
locale = clientInfo.getLocale();
}
if( locale == null ) {
locale = Locale.getDefault();
}
}
return locale;
}
public void setLocale( Locale locale ) {
setAttribute( ATTR_LOCALE, locale );
}
public void exec( Runnable runnable ) {
ParamCheck.notNull( runnable, "runnable" );
ContextUtil.runNonUIThreadWithFakeContext( this, runnable );
}
public boolean addSessionStoreListener( UISessionListener listener ) {
return addUISessionListener( listener );
}
public boolean addUISessionListener( UISessionListener listener ) {
ParamCheck.notNull( listener, "listener" );
boolean result = false;
synchronized( lock ) {
if( bound && !inDestroy ) {
result = true;
listeners.add( listener );
}
}
return result;
}
public boolean removeSessionStoreListener( UISessionListener listener ) {
return removeUISessionListener( listener );
}
public boolean removeUISessionListener( UISessionListener listener ) {
ParamCheck.notNull( listener, "listener" );
boolean result = false;
synchronized( lock ) {
if( bound && !inDestroy ) {
result = true;
listeners.remove( listener );
}
}
return result;
}
public void valueBound( HttpSessionBindingEvent event ) {
synchronized( lock ) {
bound = true;
inDestroy = false;
}
}
public void valueUnbound( HttpSessionBindingEvent event ) {
if( shutdownAdapter != null ) {
shutdownAdapter.interceptShutdown();
} else {
boolean fakeContext = false;
if( !ContextProvider.hasContext() ) {
fakeContext = true;
ServiceContext context = ContextUtil.createFakeContext( this );
ContextProvider.setContext( context );
}
try {
destroy();
} finally {
if( fakeContext ) {
ContextProvider.releaseContextHolder();
}
}
}
}
public static UISessionImpl getInstanceFromSession( HttpSession httpSession ) {
return ( UISessionImpl )httpSession.getAttribute( ATTR_SESSION_STORE );
}
public static void attachInstanceToSession( HttpSession httpSession, UISession uiSession ) {
httpSession.setAttribute( ATTR_SESSION_STORE, uiSession );
}
Object getRequestLock() {
return requestLock;
}
private void removeAttributeInternal( String name ) {
attributes.remove( name );
}
private void destroy() {
synchronized( lock ) {
inDestroy = true;
}
fireBeforeDestroy();
synchronized( lock ) {
attributes.clear();
listeners.clear();
bound = false;
inDestroy = false;
}
}
private void fireBeforeDestroy() {
UISessionListener[] listenersCopy;
synchronized( lock ) {
int size = listeners.size();
listenersCopy = listeners.toArray( new UISessionListener[ size ] );
}
UISessionEvent event = new UISessionEvent( this );
for( UISessionListener listener : listenersCopy ) {
try {
listener.beforeDestroy( event );
} catch( RuntimeException exception ) {
handleBeforeDestroyException( listener, exception );
}
}
}
private void handleBeforeDestroyException( UISessionListener listener,
RuntimeException exception )
{
String txt = "Could not execute {0}.beforeDestroy(UISessionEvent).";
Object[] param = new Object[] { listener.getClass().getName() };
String msg = MessageFormat.format( txt, param );
httpSession.getServletContext().log( msg, exception );
}
private Enumeration<String> createAttributeNameEnumeration() {
Set<String> names;
synchronized( lock ) {
names = new HashSet<String>( attributes.keySet() );
}
final Iterator<String> iterator = names.iterator();
return new Enumeration<String>() {
public boolean hasMoreElements() {
return iterator.hasNext();
}
public String nextElement() {
return iterator.next();
}
};
}
}