/******************************************************************************* * Copyright (c) 2002-2006 Innoopract Informationssysteme GmbH. * 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 ******************************************************************************/ package com.w4t.engine.util; import java.text.MessageFormat; import java.util.Collection; import java.util.Hashtable; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import org.eclipse.rwt.SessionSingletonBase; import org.eclipse.rwt.internal.service.ContextProvider; import org.eclipse.rwt.internal.service.IServiceStateInfo; import org.eclipse.rwt.internal.util.ParamCheck; import com.w4t.IWindowManager; import com.w4t.WebForm; /** * <p>This class maintains a list of (browser) windows and their associated * <code>WebForm</code>s.</p> * <p>The class is not intended to be used by clients.</p> */ //TODO [fappel] check synchronizations public class WindowManager extends SessionSingletonBase implements IWindowManager { private static final String ACTIVE_WINDOW = "COM_W4T_ACTIVE_WINDOW"; /** * <p>Associates windows and their contained forms. (key: form id (String) * value: instance of Window)</p> */ private final Hashtable formIdToWindowMap; //////////////// // inner classes private final class Window implements IWindow { private final String id = createId(); private WebForm formToDispatch; private String lastFormId; private boolean closing; private boolean closed; public String getId() { return id; } public void setFormToDispatch( final WebForm formToDispatch ) { ParamCheck.notNull( formToDispatch, "formToDispatch" ); // TODO: [fappel] this is not safe in case of multiple requests... if( getInstance().findWindow( formToDispatch ) != null ) { String text; text = "The form with id ''{0}'' is already associated with a window."; Object[] args = new Object[] { formToDispatch.getUniqueID() }; String msg = MessageFormat.format( text, args ); throw new IllegalStateException( msg ); } this.formToDispatch = formToDispatch; } public WebForm getFormToDispatch() { return formToDispatch; } public void close() { closing = true; closed = false; } boolean isClosing() { return closing; } boolean isClosed() { return closed; } void setClosing( final boolean closing ) { this.closing = closing; } void setClosed( final boolean closed ) { this.closed = closed; } } /** * <p>Helper class that creates session unique identifiers for window * instances.</p> */ private static class IdBuilder { private int counter = 0; private synchronized String newId() { counter++; StringBuffer result = new StringBuffer( "w" ); result.append( counter ); return result.toString(); } } /** <p>Creates a new session singleton instance.</p> */ private WindowManager() { formIdToWindowMap = new Hashtable(); } /** * <p>Returns the session-singleton instance of <code>WindowManager</code>. * </p> */ public static WindowManager getInstance() { return ( WindowManager )getInstance( WindowManager.class ); } /** * <p>Returns the active <code>IWindow</code>, that is, the window which issued * the current request.</p> */ public static IWindow getActive() { IServiceStateInfo stateInfo = ContextProvider.getStateInfo(); return ( IWindow )stateInfo.getAttribute( ACTIVE_WINDOW ); } /** * <p>Sets the given <code>window</code> as the active window.</p> * @see #getActive() */ public static void setActive( final IWindow window ) { IServiceStateInfo stateInfo = ContextProvider.getStateInfo(); stateInfo.setAttribute( ACTIVE_WINDOW, window ); } /** * <p>Does the actual dispatching for the active window (see * {@link #getActive() <code>getActive()</code>}). If there is no form to * dispatch to, nothing is done.</p> */ public static WebForm doDispatch() { WebForm result = FormManager.getActive(); Window window = ( Window )getActive(); WebForm formToDispatch = window.getFormToDispatch(); if( formToDispatch != null ) { WebForm lastForm = getLastForm( window ); WindowManager manager = getInstance(); if( lastForm != null ) { manager.formIdToWindowMap.remove( lastForm.getUniqueID() ); } manager.formIdToWindowMap.put( formToDispatch.getUniqueID(), window ); window.lastFormId = formToDispatch.getUniqueID(); result = formToDispatch; } FormManager.setActive( result ); return result; } /** * <p>Removes the <code>IWindow</code> which is associated with the given * <code>form</code> form the list of 'known' windows. If there is no * associated window nothing is done.</p> * @param form the <code>WebForm</code> instance whose associated window * should be removed. Must not be <code>null</code>. * @throws NullPointerException when <code>form</code> is <code>null</code>. */ public static void removeAssociatedWindow( final WebForm form ) { ParamCheck.notNull( form, "form" ); Window window = ( Window )getInstance().findWindow( form ); if( window != null && form.getUniqueID().equals( window.lastFormId ) ) { getInstance().remove( window ); } } /** * <p>Returns the most recent <code>WebForm</code> which was displayed in * the given <code>window</code>.<p> */ // TODO [rh] remove this method its functionality is covered by findForm() public static WebForm getLastForm( final IWindow window ) { return FormManager.findById( ( ( Window )window ).lastFormId ); } /** <p>Resets the current form to be dispatched.</p> */ public static void afterRender() { ( ( Window )getActive() ).formToDispatch = null; } /** * <p>Marks the given <code>window</code> as 'in the process of being closed'. * </p> */ public static void setClosing( final IWindow window, final boolean closing ) { Window internalWindow = ( Window )window; internalWindow.setClosing( closing ); } /** * <p>Marks the given <code>window</code> as 'being closed'.</p> */ public static void setClosed( final IWindow window, final boolean closed ) { Window internalWindow = ( Window )window; internalWindow.setClosed( closed ); } /** * <p>Returns whether the given <code>window</code> is marked as 'to be * closed'.</p> */ public static boolean isClosing( final IWindow window ) { Window internalWindow = ( Window )window; return internalWindow.isClosing(); } /** <p>Returns whether the given <code>window</code> is closed.</p> */ public static boolean isClosed( final IWindow window ) { Window internalWindow = ( Window )window; return internalWindow.isClosed(); } /** * <p>Returns an array of all <code>IWindow</code>s known by this * <code>WindowManager</code>. An empty array is returned if no windows * exist.</p> */ public static IWindow[] getAll() { Collection windows = getInstance().formIdToWindowMap.values(); IWindow[] result = new IWindow[ windows.size() ]; windows.toArray( result ); return result; } /////////////////////////////////// // implementation of IWindowManager /** * <p>Creates an <code>IWindow</code> for the given <code>form</code> and * associates the two.</p> * @param form the <code>WebForm</code> to create an <code>IWindow</code> for. * Must not be <code>null</code>. * @throws NullPointerException when <code>form</code> is <code>null</code>. * @throws IllegalStateException when the given <code>form</code> is already * associated with an <code>IWindow</code>. */ public IWindow create( final WebForm form ) { ParamCheck.notNull( form, "form" ); if( findWindow( form ) != null ) { String text; text = "The form with id ''{0}'' is already associated with a window."; Object[] args = new Object[] { form.getUniqueID() }; String msg = MessageFormat.format( text, args ); throw new IllegalStateException( msg ); } Window result = new Window(); result.lastFormId = form.getUniqueID(); formIdToWindowMap.put( form.getUniqueID(), result ); return result; } /** * <p><code>Returns the <code>IWindow</code> which has the given * <code>id</code> or <code>null</code> if no window with the given * <code>id</code> exists.</p> * @param id the id to search for, must not be <code>null</code>. * @throws NullPointerException when <code>id</code> is <code>null</code>. */ public IWindow findById( final String id ) { ParamCheck.notNull( id, "id" ); IWindow result = null; Object[] windows = formIdToWindowMap.values().toArray(); for( int i = 0; result == null && i < windows.length; i++ ) { IWindow window = ( IWindow )windows[ i ]; if( id.equals( window.getId() ) ) { result = window; } } return result; } /** * <p>Returns the <code>window</code> which is associated with the given * <code>form</code>.</p> * @param form the <code>WebForm</code> to find the associated window for, * must not be <code>null</code>. * @throws NullPointerException when <code>form</code> is <code>null</code>. */ public IWindow findWindow( final WebForm form ) { ParamCheck.notNull( form, "form" ); return ( IWindow )formIdToWindowMap.get( form.getUniqueID() ); } /** * <p>Returns the <code>WebForm</code> which is associated with the given * <code>window</code>.</p> */ public WebForm findForm( final IWindow window ) { ParamCheck.notNull( window, "window" ); return FormManager.findById( ( ( Window )window ).lastFormId ); } /** * <p>Removes the given <code>window</code> from the list.</p> * <p>Removing a window which is not maintained by this list is ignored * silently.</p> * @param window the window to be removed, must not be <code>null</code>. * @throws NullPointerException when <code>window</code> is <code>null</code>. */ public void remove( final IWindow window ) { ParamCheck.notNull( window, "window" ); formIdToWindowMap.remove( ( ( Window )window ).lastFormId ); } ////////////////// // helping methods private static String createId() { return getServletContextName() + ( ( IdBuilder )getInstance( IdBuilder.class ) ).newId(); } private static String getServletContextName() { String result = ""; HttpSession session = ContextProvider.getRequest().getSession(); ServletContext servletContext = session.getServletContext(); if( servletContext != null ) { String contextName = servletContext.getServletContextName(); if( contextName != null ) { result = normalizeServletContextName( contextName ); } } return result; } private static String normalizeServletContextName( final String name ) { StringBuffer result = new StringBuffer( name ); int i = 0; while( i < result.length() ) { char c = result.charAt( i ); if( c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_' ) { i++; } else { result.delete( i, i + 1 ); } } if( result.length() > 0 && result.charAt( 0 ) >= '0' && result.charAt( 0 ) <= '9' ) { result.insert( 0, '_' ); } return result.toString(); } }