You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by gc...@apache.org on 2009/05/20 00:44:56 UTC
svn commit: r776491 - in /myfaces/trinidad/trunk:
trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/
trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/
trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/...
Author: gcrawford
Date: Tue May 19 22:44:56 2009
New Revision: 776491
URL: http://svn.apache.org/viewvc?rev=776491&view=rev
Log:
TRINIDAD-1474 Add Window abstraction to Trinidad
Added:
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/Window.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManager.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManagerFactory.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowEvent.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleEvent.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleListener.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleNavigateEvent.java
Modified:
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java
myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/RequestContextImpl.java
myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/FormRenderer.java
myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/MFacesContext.java
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java?rev=776491&r1=776490&r2=776491&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java Tue May 19 22:44:56 2009
@@ -20,7 +20,10 @@
import java.awt.Color;
+import java.io.IOException;
+
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -32,6 +35,7 @@
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
@@ -40,7 +44,9 @@
import org.apache.myfaces.trinidad.component.visit.VisitContext;
import org.apache.myfaces.trinidad.component.visit.VisitHint;
import org.apache.myfaces.trinidad.config.RegionManager;
+import org.apache.myfaces.trinidad.event.WindowLifecycleListener;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
import org.apache.myfaces.trinidad.webapp.UploadedFileProcessor;
/**
@@ -549,6 +555,79 @@
IllegalAccessException;
/**
+ * <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()
+ {
+ // implement getWindowManager() in RequestContext for backwards compatibility
+
+ // check if we have cached it for the request
+ WindowManager windowManager = _windowManager;
+
+ // get instance using the WindowManagerFactory
+ if (windowManager == null)
+ {
+ // check if we have cached it per session
+ ExternalContext extContext = FacesContext.getCurrentInstance().getExternalContext();
+
+ // create a new instance using the WindowManagerFactory
+ ConcurrentMap<String, Object> concurrentAppMap =
+ getCurrentInstance().getApplicationScopedConcurrentMap();
+
+ WindowManagerFactory windowManagerFactory = (WindowManagerFactory)concurrentAppMap.get(
+ _WINDOW_MANAGER_FACTORY_CLASS_NAME);
+
+ if (windowManagerFactory == null)
+ {
+ // we haven't registered a WindowManagerFactory yet, so use the services api to see
+ // if a factory has been registered
+ List<WindowManagerFactory> windowManagerFactories =
+ ClassLoaderUtils.getServices(_WINDOW_MANAGER_FACTORY_CLASS_NAME);
+
+ if (windowManagerFactories.isEmpty())
+ {
+ // no factory registered so use the factory that returns dummy stub WindowManagers
+ windowManagerFactory = _STUB_WINDOW_MANAGER_FACTORY;
+ }
+ else
+ {
+ // only one WindowManager is allowed, use it
+ windowManagerFactory = windowManagerFactories.get(0);
+ }
+
+ // save the WindowManagerFactory to the application if it hasn't already been saved
+ // if it has been saved, use the previously registered WindowManagerFactory
+ WindowManagerFactory oldWindowManagerFactory = (WindowManagerFactory)
+ concurrentAppMap.putIfAbsent(_WINDOW_MANAGER_FACTORY_CLASS_NAME,
+ windowManagerFactory);
+
+ if (oldWindowManagerFactory != null)
+ windowManagerFactory = oldWindowManagerFactory;
+ } // create WindowManagerFactory
+
+ // get the WindowManager from the factory. The factory will create a new instance
+ // for this session if necessary
+ windowManager = windowManagerFactory.getWindowManager(extContext);
+
+ // remember for the next call on this thread
+ _windowManager = windowManager;
+ }
+
+ return windowManager;
+ }
+
+ /**
* Releases the RequestContext object. This method must only
* be called by the code that created the RequestContext.
* @exception IllegalStateException if no RequestContext is attached
@@ -617,6 +696,66 @@
return Thread.currentThread().getContextClassLoader();
}
+ /**
+ * Default WindowManagerFactory implementation that returns the StubWindowManager
+ */
+ private static final class StubWindowManagerFactory extends WindowManagerFactory
+ {
+ public WindowManager getWindowManager(ExternalContext extContext)
+ {
+ return _STUB_WINDOW_MANAGER;
+ }
+
+ private static final WindowManager _STUB_WINDOW_MANAGER = new StubWindowManager();
+ }
+
+ /**
+ * Default WindowManager implementation that returns no Windows
+ */
+ private static final class StubWindowManager extends WindowManager
+ {
+ @Override
+ public Window getCurrentWindow(ExternalContext extContext)
+ {
+ return null;
+ }
+
+ @Override
+ public Map<String, Window> getWindows(ExternalContext extContext)
+ {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public void addWindowLifecycleListener(
+ ExternalContext extContext,
+ WindowLifecycleListener windowListener)
+ {
+ // do nothing
+ }
+
+ @Override
+ public void removeWindowLifecycleListener(
+ ExternalContext extContext,
+ WindowLifecycleListener windowListener)
+ {
+ // do nothing
+ }
+
+ @Override
+ public void writeState(FacesContext context) throws IOException
+ {
+ // do nothing
+ }
+ }
+
+ /* singleton for WindowManagerFactory that returns WindowManagers that don't do anything */
+ private static final WindowManagerFactory _STUB_WINDOW_MANAGER_FACTORY =
+ new StubWindowManagerFactory();
+
+ private static final String _WINDOW_MANAGER_FACTORY_CLASS_NAME =
+ WindowManagerFactory.class.getName();
+
@SuppressWarnings({"CollectionWithoutInitialCapacity"})
private static final ConcurrentMap<ClassLoader, ConcurrentMap<String, Object>> _APPLICATION_MAPS =
new ConcurrentHashMap<ClassLoader, ConcurrentMap<String, Object>>();
@@ -624,4 +763,7 @@
new ThreadLocal<RequestContext>();
static private final TrinidadLogger _LOG =
TrinidadLogger.createTrinidadLogger(RequestContext.class);
+
+ // window manager for this request
+ private WindowManager _windowManager;
}
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/Window.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/Window.java?rev=776491&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/Window.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/Window.java Tue May 19 22:44:56 2009
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.context;
+
+import java.io.Serializable;
+
+import javax.faces.context.ExternalContext;
+
+/**
+ * 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();
+
+ /**
+ * @return <code>true</code> if the window's document hasn't been rendered since the Window
+ * was created.
+ */
+ public abstract boolean isNew();
+}
+
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManager.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManager.java?rev=776491&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManager.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManager.java Tue May 19 22:44:56 2009
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.context;
+
+import java.io.IOException;
+
+import java.util.Map;
+
+import javax.faces.context.ExternalContext;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.event.WindowLifecycleListener;
+
+/**
+ * <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 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>
+ * WindowLifecycleListener 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 addWindowLifecycleListener(
+ ExternalContext extContext, WindowLifecycleListener 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 removeWindowLifecycleListener(
+ ExternalContext extContext, WindowLifecycleListener 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;
+}
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManagerFactory.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManagerFactory.java?rev=776491&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManagerFactory.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/WindowManagerFactory.java Tue May 19 22:44:56 2009
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.context;
+
+import javax.faces.context.ExternalContext;
+
+/**
+ * <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);
+}
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowEvent.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowEvent.java?rev=776491&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowEvent.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowEvent.java Tue May 19 22:44:56 2009
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.event;
+
+import java.util.EventObject;
+import org.apache.myfaces.trinidad.context.Window;
+
+/**
+ * Represents an event delivered with a Window as the source.
+ * @see org.apache.myfaces.trinidad.context.Window
+ * @see org.apache.myfaces.trinidad.event.WindowLifecycleListener
+ */
+public abstract class WindowEvent extends EventObject
+{
+ /**
+ * Constructs a WindowEvent for the specified Window
+ * @param source the Window that tis the source of this event.
+ */
+ protected WindowEvent(Window source)
+ {
+ super(source);
+
+ if (source == null)
+ throw new NullPointerException();
+ }
+
+ /**
+ * @return the Window that this event ocurred on.
+ */
+ @Override
+ public Window getSource()
+ {
+ return (Window)super.getSource();
+ }
+
+ /**
+ * Called by subclass <code>equals</code> implementation to check the WindowEvent
+ * portion of equivalence.
+ * @param e Non-null WindowEvent to compare for equality
+ * @return <code>true</code> if the the WindowEvent satisfies the WindowEvent portion
+ * of equivalence.
+ */
+ protected final boolean subclassEquals(WindowEvent e)
+ {
+ return getSource().equals(e.getSource());
+ }
+}
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleEvent.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleEvent.java?rev=776491&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleEvent.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleEvent.java Tue May 19 22:44:56 2009
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.event;
+
+import org.apache.myfaces.trinidad.context.Window;
+import org.apache.myfaces.trinidad.context.Window.LifecycleState;
+
+/**
+ * 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)
+ {
+ super(source);
+
+ if (cause == null)
+ throw new NullPointerException();
+
+ _cause = cause;
+ }
+
+ /**
+ * @return the cause of the WindowOpen event.
+ */
+ public Cause getCause()
+ {
+ return _cause;
+ }
+
+ /**
+ * Returns the new LifecycleState that the Window has moved to.
+ */
+ public final LifecycleState getNewLifecycleState()
+ {
+ return getSource().getLifecycleState();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return getSource().hashCode() * 37 + _cause.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ return true;
+ else if ((o != null) && (o.getClass() == WindowLifecycleEvent.class))
+ {
+ return subclassEquals((WindowLifecycleEvent)o);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return super.toString() + ",cause=" + _cause;
+ }
+
+ /**
+ * Called by subclass <code>equals</code> implementation to check the WindowEvent
+ * portion of equivalence.
+ * @param e Non-null WindowEvent to compare for equality
+ * @return <code>true</code> if the the WindowEvent satisfies the WindowEvent portion
+ * of equivalence.
+ */
+ protected final boolean subclassEquals(WindowLifecycleEvent e)
+ {
+ return super.subclassEquals(e) && _cause.equals(e._cause);
+ }
+
+ private final Cause _cause;
+
+ private static final long serialVersionUID = 1L;
+}
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleListener.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleListener.java?rev=776491&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleListener.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleListener.java Tue May 19 22:44:56 2009
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.event;
+
+import java.util.EventListener;
+
+import javax.faces.context.ExternalContext;
+
+/**
+ * <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 WindowLifecycleListener in a file named
+ * <code>org.apache.myfaces.trinidad.event.WindowLifecycleListener</code> inside of
+ * the <code>META_INF/services</code> directory or manually by calling
+ * <code>WindowManager.addWindowLifecycleListener</code>
+ * @see org.apache.myfaces.trinidad.context.WindowManager
+ */
+public interface WindowLifecycleListener extends EventListener
+{
+ /**
+ * <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 processWindowLifecylce(
+ ExternalContext extContext, WindowLifecycleEvent event);
+}
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleNavigateEvent.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleNavigateEvent.java?rev=776491&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleNavigateEvent.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/WindowLifecycleNavigateEvent.java Tue May 19 22:44:56 2009
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.event;
+
+import org.apache.myfaces.trinidad.context.Window;
+
+/**
+ * WindowLifecycleEvent delivered when the current window is being unloaded
+ * in order to navigate to a new location
+ */
+public final class WindowLifecycleNavigateEvent extends WindowLifecycleEvent
+{
+ public WindowLifecycleNavigateEvent(Window source, String destination)
+ {
+ super(source, WindowLifecycleEvent.Cause.NAVIGATE);
+
+ if (destination == null)
+ throw new NullPointerException();
+
+ _destination = 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()
+ {
+ return _destination;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return super.hashCode() * 37 + _destination.hashCode();
+ }
+
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ return true;
+ else if ((o != null) && (o instanceof WindowLifecycleNavigateEvent))
+ {
+ return subclassEquals((WindowLifecycleEvent)o) &&
+ _destination.equals(((WindowLifecycleNavigateEvent)o)._destination);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return super.toString() + ",destination=" + _destination;
+ }
+
+
+ private final String _destination;
+
+ private static final long serialVersionUID = 1L;
+}
Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java?rev=776491&r1=776490&r2=776491&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java Tue May 19 22:44:56 2009
@@ -52,6 +52,7 @@
import java.io.ObjectOutputStream;
import org.apache.myfaces.trinidad.bean.util.StateUtils;
+import org.apache.myfaces.trinidad.context.Window;
import org.apache.myfaces.trinidadinternal.context.RequestContextImpl;
import org.apache.myfaces.trinidadinternal.context.TrinidadPhaseListener;
@@ -312,9 +313,12 @@
Map<String, Object> sessionMap = extContext.getSessionMap();
- // Store bits of the session as subkeys off of the session
- Map<String, PageState> stateMap = new SubKeyMap<PageState>(sessionMap,
- _VIEW_CACHE_KEY + ".");
+ RequestContext trinContext = RequestContext.getCurrentInstance();
+
+ // get view cache key with "." separator suffix to separate the SubKeyMap keys
+ String subkey = _getViewCacheKey(extContext, trinContext, _SUBKEY_SEPARATOR);
+
+ Map<String, PageState> stateMap = new SubKeyMap<PageState>(sessionMap, subkey);
// Sadly, we can't save just a SerializedView, because we should
// save a serialized object, and SerializedView is a *non*-static
@@ -332,12 +336,14 @@
// laying around if the user navigates off of a page using a GET
synchronized(extContext.getSession(true))
{
- PageState activePageState = (PageState)sessionMap.get(_ACTIVE_PAGE_STATE_SESSION_KEY);
+ // get the per-window key for the active page state
+ String activePageStateKey = _getActivePageStateKey(extContext, trinContext);
+ PageState activePageState = (PageState)sessionMap.get(activePageStateKey);
if (activePageState != null)
activePageState.clearViewRootState();
- sessionMap.put(_ACTIVE_PAGE_STATE_SESSION_KEY, pageState);
+ sessionMap.put(activePageStateKey, pageState);
}
String requestToken = _getRequestTokenForResponse(context);
@@ -497,10 +503,12 @@
public UIViewRoot restoreView(FacesContext context, String viewId,
String renderKitId)
{
+ final ExternalContext extContext = context.getExternalContext();
+
// If we're being asked to execute a "return" event from, say, a dialog, always
// restore the "launch view", which was set over in the TrinidadFilter.
UIViewRoot launchView = (UIViewRoot)
- context.getExternalContext().getRequestMap().remove(RequestContextImpl.LAUNCH_VIEW);
+ extContext.getRequestMap().remove(RequestContextImpl.LAUNCH_VIEW);
if (launchView != null)
{
TrinidadPhaseListener.markPostback(context);
@@ -561,9 +569,14 @@
}
else
{
+ // get view cache key with "." separator suffix to separate the SubKeyMap keys
+ String subkey = _getViewCacheKey(extContext,
+ RequestContext.getCurrentInstance(),
+ _SUBKEY_SEPARATOR);
+
Map<String, PageState> stateMap = new SubKeyMap<PageState>(
- context.getExternalContext().getSessionMap(),
- _VIEW_CACHE_KEY + ".");
+ extContext.getSessionMap(),
+ subkey);
viewState = stateMap.get(token);
if (viewState != null)
@@ -702,10 +715,111 @@
private TokenCache _getViewCache(FacesContext context)
{
+ ExternalContext extContext = context.getExternalContext();
+
return TokenCache.getTokenCacheFromSession(context,
- _VIEW_CACHE_KEY,
+ _getViewCacheKey(extContext,
+ RequestContext.getCurrentInstance(),
+ null),
true,
- _getCacheSize(context));
+ _getCacheSize(extContext));
+ }
+
+
+
+ /**
+ * Returns a key suitable for finding the per-window active page state key
+ * @param extContext
+ * @param trinContext
+ * @return
+ */
+ static private String _getActivePageStateKey(
+ ExternalContext extContext,
+ RequestContext trinContext)
+ {
+ return _getPerWindowCacheKey(extContext, trinContext, _ACTIVE_PAGE_STATE_SESSION_KEY, null);
+ }
+
+ /**
+ * Returns a key suitable for finding the per-window cache key
+ * @param extContext
+ * @param trinContext
+ * @param suffix
+ * @return
+ */
+ static private String _getViewCacheKey(
+ ExternalContext extContext,
+ RequestContext trinContext,
+ Character suffix)
+ {
+ return _getPerWindowCacheKey(extContext, trinContext, _VIEW_CACHE_KEY, suffix);
+ }
+
+ /**
+ * Returns a key of the form <prefix>.<windowid><suffix> if a window and a suffix are available
+ * <prefix>.<window> if just a window is available
+ * <prefix> if neither a window or a suffix is available
+ * @param eContext
+ * @param trinContext
+ * @param prefix
+ * @param suffix
+ * @return
+ */
+ static private String _getPerWindowCacheKey(
+ ExternalContext eContext,
+ RequestContext trinContext,
+ String prefix,
+ Character suffix)
+ {
+ Window currWindow = trinContext.getWindowManager().getCurrentWindow(eContext);
+
+ // if we have a current window or a suffix, we need a StringBuilder to calculate the cache key
+ if ((currWindow != null) || (suffix != null))
+ {
+ // get the window id and the extra size neeeded to store it and its separator
+ String windowId;
+ int windowPartSize;
+
+ if (currWindow != null)
+ {
+ windowId = currWindow.getId();
+
+ // add 1 for separator
+ windowPartSize = windowId.length() + 1;
+ }
+ else
+ {
+ windowId = null;
+ windowPartSize = 0;
+ }
+
+ int builderSize = prefix.length() + windowPartSize;
+
+ // add extra space for the suffix Character
+ if (suffix != null)
+ builderSize += 1;
+
+ // add the constant part to the StringBuilder
+ StringBuilder keyBuilder = new StringBuilder(builderSize);
+ keyBuilder.append(prefix);
+
+ // add the windowId and its separator
+ if (currWindow != null)
+ {
+ keyBuilder.append('.');
+ keyBuilder.append(windowId);
+ }
+
+ // add the suffix if any
+ if (suffix != null)
+ keyBuilder.append(suffix);
+
+ return keyBuilder.toString();
+ }
+ else
+ {
+ return prefix;
+ }
}
/**
@@ -725,11 +839,10 @@
return true;
}
- private int _getCacheSize(FacesContext context)
+ private int _getCacheSize(ExternalContext extContext)
{
- ExternalContext external = context.getExternalContext();
Object maxTokens =
- external.getInitParameterMap().get(CLIENT_STATE_MAX_TOKENS_PARAM_NAME);
+ extContext.getInitParameterMap().get(CLIENT_STATE_MAX_TOKENS_PARAM_NAME);
if (maxTokens != null)
{
try
@@ -767,7 +880,7 @@
return cache;
}
}
-
+
@SuppressWarnings("unchecked")
static private Map<String, PageState> _getPerSessionApplicationViewCache(FacesContext context)
{
@@ -1110,9 +1223,13 @@
private Boolean _useApplicationViewCache;
private Boolean _structureGeneratedByTemplate;
+ private static final Character _SUBKEY_SEPARATOR = new Character('.');
+
private static final int _DEFAULT_CACHE_SIZE = 15;
private static final Object _APPLICATION_VIEW_CACHE_LOCK = new Object();
+
+ // base key used to identify the view cache. The window name, if any, is appended to this
private static final String _VIEW_CACHE_KEY =
"org.apache.myfaces.trinidadinternal.application.VIEW_CACHE";
Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/RequestContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/RequestContextImpl.java?rev=776491&r1=776490&r2=776491&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/RequestContextImpl.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/RequestContextImpl.java Tue May 19 22:44:56 2009
@@ -871,7 +871,6 @@
{
private MockPartialPageContext(FacesContext facesContext)
{
- _facesContext = facesContext;
}
@Override
@@ -942,8 +941,7 @@
throw new NotImplementedException();
}
- private FacesContext _facesContext;
- private HashSet<String> _componentIds = new HashSet<String>();
+ private final HashSet<String> _componentIds = new HashSet<String>();
}
private RequestContextBean _bean;
Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/FormRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/FormRenderer.java?rev=776491&r1=776490&r2=776491&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/FormRenderer.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/FormRenderer.java Tue May 19 22:44:56 2009
@@ -386,6 +386,9 @@
// Include JSF state.
context.getApplication().getViewHandler().writeState(context);
+ // Include the Window state, if any
+ RequestContext.getCurrentInstance().getWindowManager().writeState(context);
+
// Render any needed values
//VAC this condition is needed for bug 4526850- It ensures that only
//state token and form name parameters are overwritten when there is
Modified: myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/MFacesContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/MFacesContext.java?rev=776491&r1=776490&r2=776491&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/MFacesContext.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/MFacesContext.java Tue May 19 22:44:56 2009
@@ -54,7 +54,7 @@
{
super(application);
setCurrentInstance(this);
- _external = new External(testMode);
+ _external = new External(testMode, application);
}
@Override
@@ -201,11 +201,13 @@
private static final class External extends MockExternalContext
{
- public External(boolean testMode)
+ public External(boolean testMode, Object contextObject)
{
super(null, null, null);
_testMode = testMode;
+ _contextObject = contextObject;
+
File file = null;
try
{
@@ -223,16 +225,27 @@
}
@Override
- public Object getContext() { return null; }
+ public Object getContext() { return _contextObject; }
@Override
- public Object getRequest() { return null; }
+ public Object getRequest() { return _requestObject; }
@Override
- public Object getResponse() { return null; }
+ public Object getResponse() { return _responseObject; }
@Override
- public Object getSession(boolean create) { return null; }
+ public Object getSession(boolean create)
+ {
+ // implement lazy behavior for session creation
+ if (create)
+ {
+ // force SessionMap to be created
+ getSessionMap();
+ }
+
+ // use the session Map as the session object
+ return _sessionMap;
+ }
@Override
public String getRequestContextPath() { return "/test-context-path"; }
@@ -320,6 +333,17 @@
// we shouldn't use any servlet APIs. So, intercept the
// session map. Ideally, renderers shouldn't write into
// the session map, but see above...
+ if (_sessionMap == null)
+ {
+ synchronized (_contextObject)
+ {
+ if (_sessionMap == null)
+ {
+ _sessionMap = Collections.synchronizedMap(new HashMap<String, Object>(2));
+ }
+ }
+ }
+
return _sessionMap;
}
@@ -331,9 +355,16 @@
return _requestMap;
}
+ private final Object _contextObject;
+ private final Object _requestObject = new String("request object");
+ private final Object _responseObject = new String("response object");
+
private final Map<String, Object> _requestMap = new HashMap<String, Object>(2);
- private final Map<String, Object> _sessionMap = new HashMap<String, Object>(2);
- private final Map<String, Object> _applicationMap = new HashMap<String, Object>(2);
+ private final Map<String, Object> _applicationMap =
+ Collections.synchronizedMap(new HashMap<String, Object>(2));
+
+ private volatile Map<String, Object> _sessionMap = null;
+
private final boolean _testMode;
}
private static final String _GLOBAL_MESSAGE = "org.apache.myfaces.trinidadinternal.renderkit.MFacesContext.GLOBAL_MESSAGE";