sounds good! -M
On Sat, May 16, 2009 at 10:14 AM, Blake Sullivan <blake.sulli...@oracle.com> wrote: > Here are the changes: > > WindowNavigateEvent: > rename to WindowLifecycleNavigateEvent > > WindowListener: > > rename to WindowLifecycleListener > change to interface and extend EventListener > rename processWindowEvent to processWindowLifecylce > > WindowManager: > > replace isCurrentWindowNew() with Window.isNew() > rename addWindowListener to addWindowLifecycleListener > rename removeWindowListener to removeWindowLifecycleListener > > Window: > add isNew() > > -- Blake Sullivan > > > Blake Sullivan said the following On 5/15/2009 10:18 PM PT: > > Simon Lessard said the following On 5/15/2009 12:35 PM PT: > > Hi Blake, > > I'm + 1 with the idea and the general API, but I have some concerns: > > I don't really like the API to expose a read only map through > WindowManager.getWindows, I would prefer > WindowManager.getWindowIds(ExternalContext) and > WindowManager.getWindow(ExternalContext, String); > > Is your worry over that the Map is read only? The two separate methods > prevent the developer from leveraging the Map interface. > > WindowListener should be an interface extending EventListener one of its > subclasses; > > Fair enough, the rationale for making this an abstract class was so we could > add more event types later. However, since the WindowManager class is > itself an abstract class we could add more event listener interfaces later > to the WindowManager later, so I agree that the interface is fine > > Either WindowListener or WindowLifecycleEvent is wrongly named from a JSF > point of view (althoguh it could be potentially correctly named in Swing). > All JSF Listener handle events with the exact same name as the listener, but > with Listener changed to Event, so it should either be > WindowLifecycleListener or WindowEvent for the API to be coherent with the > usual JSF nomenclature. > > See above. I agree that if we use an interface then the listener class must > be WindowLifecycleListener > > WindowListener method is not properly named. Pretty much as above, in JSF > all listener methods are called process<evenType> so it should either be > public void processWindowEvent or processWindowLifecycleEventdepending on > the resolution of the previous point; > The process method parameters do not match the usual listener convention to > receive a single event object. Would it be possible to place the > ExternalContext instance in the event? > > I guess we could put the ExternalContext in the event, though the field will > need to be transient and getExternalContext() method on the event would need > to document that it might return null if the event has been serialized. All > of which is pretty gross. In this case the extra parameter is much > cleaner. I believe that the convention is really to aid Java Beans design > tools using introspection and would prefer cleanliness in this case. > > I would prefer to see WindowManager.isCurrentWindowNew as Window.isNew, it's > more OOP correct; > > OK. The original implementation only tracked the new status of the current > window, which was tracked by the WindowManager (which is why the > WindowManager). However, due to the need to answer this question in the > face of redirects and other weirdness, the Windows in the implementation I > have been testing do maintain their "new" state, so I agree that it makes > more sense for the Window to answer this question. > > Actually I would prefer the same for the add/get/removeWindowListener > > Prefer the same what? Are you talking about the ExternalContext? > > Thanks for the helpful feedback. > > --Blake Sullivan > > > Regards, > > ~ Simon > > > On Fri, May 15, 2009 at 3:09 PM, Blake Sullivan <blake.sulli...@oracle.com> > wrote: >> >> Here is the proposed api: >> >> package org.apache.myfaces.trinidad.context; >> >> >> /** >> * Represents a Window in the current user's Session. Windows are created >> and vended >> * by the Session's WindowManager and the Window for the current request is >> * available from <code>WindowManager.getCurrentWindow</code> >> * @see WindowManager#getCurrentWindow >> */ >> public abstract class Window implements Serializable >> { >> /** >> * <p> >> * Represents the current state of the Window. Windows start out >> <code>OPEN</code>, >> * when the current window's document is being unloaded, they move to the >> <code>UNLOADING</code> >> * state and then either move back to the <code>OPEN</code> state if the >> Window's content >> * is populated with a new document from the same application, or to the >> <code>CLOSED</code> >> * state if it is not. >> * </p><p> >> * This represents the framework's best guess at the current status of the >> Window. >> * </p> >> */ >> public enum LifecycleState >> { >> /** The Window is currently open */ >> OPEN, >> >> /** The Window is being unloaded */ >> UNLOADING, >> >> /** The Window is believed to be closed, either because the window was >> explicitly closed >> * or because the window is suspected to have been closed >> */ >> CLOSED >> } >> >> /** >> * Represents how the window is used in the application >> */ >> public enum Usage >> { >> /** Used as a top-level application window */ >> FRAME, >> >> /** Used as a dialog */ >> DIALOG >> } >> >> /** >> * @return The unique identifier for this Window within the Session >> */ >> public abstract String getId(); >> >> /** >> * @return The current state of the Window >> */ >> public abstract LifecycleState getLifecycleState(); >> >> /** >> * Returns the Usage of the Window--either a top-level frame or a dialog >> * @return how the window is used >> */ >> public abstract Usage getUsage(); >> } >> >> /** >> * <p> >> * Manages the set of Windows currently in the Session and allows listeners >> on the Windows' >> * lifecycles to be registered. >> * </p> >> * @see org.apache.myfaces.trinidad.context.RequestContext#getWindowManager >> */ >> abstract public class WindowManager >> { >> /** >> * @param extContext ExternalContext so that the WindowManager may be >> called before the >> * FacesContext is available >> * @return The Window that contains the document making the current >> request >> */ >> public abstract Window getCurrentWindow(ExternalContext extContext); >> >> /** >> * @param extContext ExternalContext so that the WindowManager may be >> called before the >> * FacesContext is available >> * @return <code>true</code> if the Window making the current request is >> newly created. >> */ >> public abstract boolean isCurrentWindowNew(ExternalContext extContext); >> >> /** >> * @param extContext ExternalContext so that the WindowManager may be >> called before the >> * FacesContext is available >> * @return The Unmodifiable Map of WindowIds to Windows >> */ >> public abstract Map<String, ? extends Window> getWindows(ExternalContext >> extContext); >> >> /** >> * <p> >> * Registers a listener that will be informed of changes to the Lifecylce >> state of any of >> * the known Windows. >> * </p> >> * <p> >> * Window listeners may be registered automatically by adding a file >> * containing the names of the classes implementing the WindowListener in >> a file named >> * <code>org.apache.myfaces.trinidad.event.WindowListener</code> inside of >> * the <code>META_INF/services</code> directory. >> * </p> >> * @param extContext ExternalContext so that the WindowManager may be >> called before the >> * FacesContext is available >> * @param windowListener >> */ >> public abstract void addWindowListener(ExternalContext extContext, >> WindowListener windowListener); >> >> /** >> * Removes a listener that will be informed of changes to the Lifecylce >> state of any of >> * the known Windows >> * @param extContext ExternalContext so that the WindowManager may be >> called before the >> * FacesContext is available >> * @param windowListener >> */ >> public abstract void removeWindowListener(ExternalContext extContext, >> WindowListener windowListener); >> >> /** >> * Performs any necessary action to embed the current window identifier >> into the output >> * @param context FacesContext to use to write the output >> * @throws IOException if an output exception occurs >> */ >> public abstract void writeState(FacesContext context) throws IOException; >> } >> >> /** >> * <p> >> * Application-scoped factory for creating per-Session WindowManager >> instances. It is the >> * WindowManagerFactory implementation's responsibility to ensure that only >> one >> * WindowManager instance is created per-session. The WindowManagerFactory >> is also responsible >> * for ensuring that any mutable state in the WindowManager instances will >> be successfully failed >> * over. >> * </p> >> * <p> >> * The factory is usually specified by placing the name of the >> WindowManagerFactory >> * implementation class in a file named >> * <code>org.apache.myfaces.trinidad.context.WindowManagerFactory</code> >> * in the <code>META-INF/services</code> directory >> * </p> >> * @see org.apache.myfaces.trinidad.context.WindowManager >> * @see org.apache.myfaces.trinidad.context.RequestContext#getWindowManager >> */ >> abstract public class WindowManagerFactory >> { >> /** >> * Returns the WindowManager to use for this session, creating a new >> instance if one doesn't >> * already exist. >> * @param extContext ExternalContext >> * @return WindowManager to use for this Session >> */ >> public abstract WindowManager getWindowManager(ExternalContext >> extContext); >> } >> >> To RequestContext add; >> >> /** >> * <p> >> * Returns the WindowManager for this request. A non-null WindowManager >> * will always be returned. >> * </p><p> >> * The default implementation uses the first WindowManagerFactory >> specified >> * implementation class in a file named >> * <code>org.apache.myfaces.trinidad.context.WindowManagerFactory</code> >> * in the <code>META-INF/services</code> directory and uses the >> WindowManagerFactory >> * to create the WindowManager for this Session. If no >> WindowManagerFactory is >> * found, a default WindowManager that never returns any Windows is used. >> * </p> >> * @return the WindowManager used for this Session. >> */ >> public WindowManager getWindowManager() >> >> In package: >> >> package org.apache.myfaces.trinidad.event; >> >> >> /** >> * Represents an event delivered with a Window as the source. >> * @see org.apache.myfaces.trinidad.context.Window >> * @see org.apache.myfaces.trinidad.event.WindowListener >> */ >> public abstract class WindowEvent extends EventObject >> { /** >> * @return the Window that this event ocurred on. >> */ >> public Window getSource() >> } >> >> /** >> * Event delivered when the LifecycleState of a Window changes. The >> <code>cause</code> >> * indicates the cause ot the state change. The state diagram for >> theWindow LifecycleStates >> * is >> <pre> >> +-----------load---------------+ >> | | ---expire--- >> V /---unload----\ | / \ >> <start> ---open--->OPEN----- ----->UNLOADED-- >> -->CLOSED >> | \--navigate---/ ^ \ / >> | | ---close---- >> +---------closing--------------+ >> >> </pre> >> * The new LifecycleStates can be retrieved by calling >> <code>getLifecycleState</code> on the >> * source Window or by calling the <code>getNewLifecycleState</code> >> convenience function >> * on the WindowLifecycleEvent >> * @see org.apache.myfaces.trinidad.context.Window >> * @see org.apache.myfaces.trinidad.context.Window.LifecycleState >> */ >> public class WindowLifecycleEvent extends WindowEvent >> { >> /** >> * What caused the delivery of the WindowLifecycleEvent. >> */ >> public enum Cause >> { >> /** >> * Delivered when a new Window is open >> */ >> OPEN, >> /** >> * Delivered when the content of a Window have been unloaded but cause >> of the unloading >> * isn't known. >> */ >> UNLOAD, >> /** >> * Delivered when the content of a Window have been unloaded as a result >> of >> * navigating within the application >> */ >> NAVIGATE, >> /** >> * Delivered when the content of a Window have been unloaded in order to >> * close the window >> */ >> CLOSING, >> /** >> * The contents of an existing Window are being reloaded >> */ >> RELOAD, >> /** >> * The Window is believed to have been closed by the user >> */ >> EXPIRE, >> >> /** >> * The Window is believed to have been closed by the user >> */ >> CLOSE >> } >> >> /** >> * Creates a WindowOpenEvent event for the specified Window and cause. >> */ >> public WindowLifecycleEvent(Window source, Cause cause) >> >> /** >> * @return the cause of the WindowOpen event. >> */ >> public Cause getCause() >> >> /** >> * Returns the new LifecycleState that the Window has moved to. >> */ >> public final LifecycleState getNewLifecycleState() >> } >> >> /** >> * WindowLifecycleEvent delivered when the current window is being unloaded >> * in order to navigate to a new location >> */ >> public final class WindowNavigateEvent extends WindowLifecycleEvent >> { >> public WindowNavigateEvent(Window source, String destination) >> >> /** >> * Returns the URL to which the page is navigating. >> * <p> >> * The destination is not guaranteed to be normalized; it may >> * be absolute, page-relative, or server-relative. It is also >> * not guaranteed to be correct, as a browser >> * may be redirected to an alternate destination. >> */ >> public String getDestination() >> } >> >> /** >> * <p> >> * A listener called when the Lifecyle of a Window changes. >> * </p> >> * <p> >> * Window listeners may be registered automatically by adding a file >> * containing the names of the classes implementing the WindowListener in a >> file named >> * <code>org.apache.myfaces.trinidad.event.WindowListener</code> inside of >> * the <code>META_INF/services</code> directory or manually by calling >> * <code>WindowManager.addWindowListener</code> >> * @see org.apache.myfaces.trinidad.context.WindowManager >> */ >> public abstract class WindowListener >> { >> /** >> * <p> >> * Called when the LifecycleState of a Window changes. >> * </p> >> * <p> >> * The current lifecycle state of a Window is the framework's best guess >> and may not be accurate. >> * In particular, the last remaining open window may never move into the >> <code>CLOSED</code> state >> * once it has moved into the <code>UNLOADED</code> state. In addition, >> no Window lifecycle events >> * are delivered if the Session ceases to exist. >> * </p> >> * <p> >> * The FacesContext may not be available at the time that this event is >> delivered. >> * </p> >> * @param extContext ExternalContext available for this event >> * @param event WindowLifecycleEvent indicating the cause of the change to >> the Window's >> * LifecycleState >> */ >> public abstract void processLifecylceEvent(ExternalContext extContext, >> WindowLifecycleEvent event); >> } >> >> Blake Sullivan (JIRA) said the following On 5/15/2009 11:41 AM PT: >>> >>> Add Window abstraction to Trinidad >>> ---------------------------------- >>> >>> Key: TRINIDAD-1474 >>> URL: https://issues.apache.org/jira/browse/TRINIDAD-1474 >>> Project: MyFaces Trinidad >>> Issue Type: New Feature >>> Components: Archetype >>> Affects Versions: 1.2.12-core >>> Environment: All >>> Reporter: Blake Sullivan >>> >>> >>> Add Window abstraction to Trinidad. Currently, Trinidad knows nothing of >>> the separate browser Windows that make up a browser session. This causes >>> weird problems. For example, the state management token cache is shared >>> across all of the active windows with a simple LRU. If the user opens up >>> two windows and operates on one window long enough, he will cause the token >>> state for the original window to be purged. When the user switches back to >>> the original window and POSTs back, the token won't be found, Trinidad will >>> assume that this is because the session expired, and the user will be given >>> an error. >>> >>> Adding the concept of a Window and a Window lifecyle opens up the >>> following capabilities: >>> 1) Correct handling of per-window UI state by segregating tokens by >>> window >>> 2) Early clean-up of UI state by aggressively purging state for closed >>> windows >>> 3) Applications can manager per-window state by listening for window >>> lifecycle events >>> 4) Sessions can be cleaned up earlier by terminating the session when the >>> last window in the session is closed >>> 5) A window scope can be implemented to ease using per-window state with >>> EL >>> 6) A window manager implementation can hide the details of handling >>> control-N in the browser >>> >>> >> > > > > -- Matthias Wessendorf blog: http://matthiaswessendorf.wordpress.com/ sessions: http://www.slideshare.net/mwessendorf twitter: http://twitter.com/mwessendorf