On 11/30/05, Andrus Adamchik <andru..bjectstyle.org> wrote:
> This will work only if
> (a) you use it consistently and there is no other code that sticks
> a DataContext in a session and
> (b) you app carries no Cayenne-related state between requests (such
> as session DataObjects).
I took it a step further and created a DataContextManager filter that
runs before any other filter. That takes care of (a). For (b), I
disallow such state, and explicitly check for it and throw an error in
the same filter at the end of the request lifecycle.
Here's how. The JSF stuff is only used for logging, so it can be
removed/replaced in other environments.
package com.xyz.servlet.filter;
import java.io.IOException;
import java.util.Iterator;
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.objectstyle.cayenne.DataObject;
import org.objectstyle.cayenne.access.DataContext;
import org.objectstyle.cayenne.conf.ServletUtil;
public class DataContextManagerFilter implements Filter
{
public void init(FilterConfig arg0) throws ServletException
{
}
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain chain) throws
IOException, ServletException
{
requestInitialized(servletRequest, servletResponse);
chain.doFilter(servletRequest, servletResponse);
requestDestroyed(servletRequest, servletResponse);
}
public void destroy()
{
}
public void requestInitialized(ServletRequest servletRequest,
ServletResponse servletResponse)
{
HttpSession session =
((HttpServletRequest)servletRequest).getSession(true);
DataContext dataContext=
ServletUtil.getSessionContext(session);
DataContext.bindThreadDataContext(dataContext);
}
public void requestDestroyed(ServletRequest servletRequest,
ServletResponse servletResponse)
{
DataContext dataContext = DataContext.getThreadDataContext();
// Try to get it first
boolean createdFacesContext = false;
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext == null)
{
facesContext = createFacesContext(servletRequest, servletResponse);
createdFacesContext = true;
}
try
{
reportUncommittedObjects(dataContext, facesContext);
}
finally
{
if (createdFacesContext)
{
facesContext.release();
}
}
dataContext.rollbackChanges();
DataContext.bindThreadDataContext(null);
}
///////////////////////////////////////
// You need an inner class to be able to call
// FacesContext.setCurrentInstance
// since it's a protected method
private abstract static class InnerFacesContext extends FacesContext
{
protected static void setFacesContextAsCurrentInstance(
FacesContext facesContext)
{
FacesContext.setCurrentInstance(facesContext);
}
}
private FacesContext createFacesContext(ServletRequest request,
ServletResponse response)
{
FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder
.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory
.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
// Either set a private member servletContext =
// filterConfig.getServletContext();
// in you filter init() method or set it here like this:
ServletContext servletContext =
((HttpServletRequest)request).getSession().getServletContext();
// Note that the above line would fail if you are using any other
// protocol than http
// Doesn't set this instance as the current instance of
// FacesContext.getCurrentInstance
FacesContext facesContext =
contextFactory.getFacesContext(servletContext, request,
response, lifecycle);
// Set using our inner class
InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);
// set a new viewRoot, otherwise context.getViewRoot returns null
UIViewRoot view = facesContext.getApplication().getViewHandler()
.createView(facesContext, "yourOwnID");
facesContext.setViewRoot(view);
return facesContext;
}
private void reportUncommittedObjects(DataContext dataContext,
FacesContext facesContext)
{
if (dataContext.hasChanges())
{
ExternalContext externalContext = facesContext.getExternalContext();
if (0 != dataContext.newObjects().size())
{
Iterator objectIterator = dataContext.newObjects().iterator();
while (objectIterator.hasNext())
{
DataObject dataObject = (DataObject) objectIterator.next();
externalContext.log("Leftover new object: " + dataObject);
}
}
if (0 != dataContext.modifiedObjects().size())
{
Iterator objectIterator =
dataContext.modifiedObjects().iterator();
while (objectIterator.hasNext())
{
DataObject dataObject = (DataObject) objectIterator.next();
externalContext.log("Leftover modified object: " +
dataObject);
}
}
if (0 != dataContext.deletedObjects().size())
{
Iterator objectIterator =
dataContext.deletedObjects().iterator();
while (objectIterator.hasNext())
{
DataObject dataObject = (DataObject) objectIterator.next();
externalContext.log("Leftover deleted object: " +
dataObject);
}
}
// Maybe remove later?
throw new RuntimeException("DataContext is dirty.");
}
}
}
This archive was generated by hypermail 2.0.0 : Wed Nov 30 2005 - 12:02:26 EST