myfaces-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Myfaces Wiki] Update of "NestedFacesContext" by MarioIvankovits
Date Wed, 28 Mar 2007 09:58:58 GMT
Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Myfaces Wiki" for change notification.

The following page has been changed by MarioIvankovits:
http://wiki.apache.org/myfaces/NestedFacesContext

New page:
=== Nested FacesContext ===

If you create a custom FacesContext e.g. like described here ["AccessFacesContextFromServlet"]
you might face a problem that e.g. messages added to your custom FacesContext won't show up
in h:messages.

The FacesServlet creates its own new FacesContext which will be used for all subsequent JSF
operations.

One reason why this is good is, that the FacesServlet can't be sure that your custom FacesContext
use the correct ServletRequest/ServletResponse objects.

An example when your custom FacesContext is not good is when you use requestDispatcher.forward.
Like my setup:
 * A custom filter which creates a custom FacesContext
 * A custom servlet which forwards to the FacesServlet (getServletContext().getRequestDispatcher(jsfPath).forward(req,
res);)
 * The FacesServlet which creates a FacesContext too

If the FacesServlet uses our own custom FacesContext you will see that JSF did not use the
jsfPath for further operations, but the original url - which is false.

So, I found to let the FacesServlet create a new FacesContext is fine and the easiest solution,
but I still wanted it to show any messages added to the custom FacesContext.

I ended with the following FacesContextFactory (adjust the package names as needed):

Configuration in faces-config.xml:
{{{
	<factory>
		<faces-context-factory>org.apache....StateCopyFacesContextFactory</faces-context-factory>
	</factory>
}}}

Source:
{{{
/*
 * 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.....;

import javax.faces.context.FacesContextFactory;
import javax.faces.context.FacesContext;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import java.util.Iterator;

/**
 * FacesContextFactory which first checks if a FacesContext is already there
 */
public class StateCopyFacesContextFactory extends FacesContextFactory
{
	private final FacesContextFactory original;

	public StateCopyFacesContextFactory(FacesContextFactory original)
	{
		this.original = original;
	}

	@Override
	public FacesContext getFacesContext(Object context, Object request, Object response, Lifecycle
lifecycle) throws FacesException
	{
		FacesContext previousContext = FacesContext.getCurrentInstance();

		FacesContext newContext = original.getFacesContext(context, request, response, lifecycle);

		if (previousContext != null)
		{
			// transfer the default locale (might have been changed)
			newContext.getApplication().setDefaultLocale(previousContext.getApplication().getDefaultLocale());

			// transfer all already collected messages
			Iterator iterClientIds = previousContext.getClientIdsWithMessages();
			while (iterClientIds.hasNext())
			{
				String clientId = (String) iterClientIds.next();
				Iterator iterMessages = previousContext.getMessages(clientId);
				while (iterMessages.hasNext())
				{
					FacesMessage message = (FacesMessage) iterMessages.next();

					newContext.addMessage(clientId, message);
				}
			}
		}

		return newContext;
	}
}
}}}

Notice: This solution do not deal with resetting to the previousContext on newContext.release().
One can enhance it. For me it was sufficient that way as after the JSF request there is nothing
further I will do with the FacesContext ... and the problem might be, that then one might
copy some state back ... too complicated.

Mime
View raw message