/******************************************************************************
* JBoss, a division of Red Hat *
* Copyright 2006, Red Hat Middleware, LLC, and individual *
* contributors as indicated by the @authors tag. See the *
* copyright.txt in the distribution for a full listing of *
* individual contributors. *
* *
* This is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of *
* the License, or (at your option) any later version. *
* *
* This software is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this software; if not, write to the Free *
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
******************************************************************************/
package org.jboss.portletbridge;
import javax.faces.application.ViewHandler;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.portlet.faces.BridgeException;
import javax.portlet.PortletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.portletbridge.application.PortletWindowState;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.contexts.FacesLifecycle;
import org.jboss.seam.core.ConversationPropagation;
import org.jboss.seam.core.Manager;
import org.jboss.seam.exception.Exceptions;
import org.jboss.seam.transaction.Transaction;
import org.jboss.seam.transaction.UserTransaction;
import org.jboss.seam.faces.FacesMessages;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author asmirnov
* @author <a href="mailto:whales@redhat.com">Wesley Hales</a>
*/
public class SeamExceptionHandlerImpl implements ExceptionHandler
{
protected static final Log log = LogFactory.getLog(SeamExceptionHandlerImpl.class);
Map windowMessageMap;
List messageList;
/* (non-Javadoc)
* @see org.jboss.portletbridge.ExceptionHandler#processActionException(javax.faces.context.FacesContext, org.jboss.portletbridge.application.PortletViewState, java.lang.Exception)
*/
public void processActionException(FacesContext context,
PortletWindowState windowState, Exception e) throws BridgeException
{
log.error("Error processing action lifecycle", e);
windowState.reset();
handleViewSetup(context, windowState, e);
windowState.setViewId(context.getViewRoot().getViewId());
}
/* (non-Javadoc)
* @see org.jboss.portletbridge.ExceptionHandler#processRenderException(javax.faces.context.FacesContext, org.jboss.portletbridge.application.PortletViewState, java.lang.Exception)
*/
public void processRenderException(FacesContext context,
PortletWindowState windowState, Exception e) throws BridgeException
{
log.error("Error processing render lifecycle", e);
handleViewSetup(context, windowState, e);
}
public void handleViewSetup(FacesContext context,
PortletWindowState windowState, Exception e){
windowState.saveBeans(context);
windowState.saveMessages(context);
windowMessageMap = new HashMap<String, List<FacesMessage>>();
messageList = new ArrayList();
String viewId = windowState.getViewId();
if(null == context.getViewRoot() && null != viewId){
ViewHandler viewHandler = context.getApplication().getViewHandler();
UIViewRoot viewRoot = viewHandler.createView(context, viewId);
context.setViewRoot(viewRoot);
}else if (viewId != null){
//refresh the viewId to get error page redirect
viewId = windowState.getViewId();
context.getViewRoot().setViewId(viewId);
}
handleException(context, e);
//todo - figure out why FacesMessages.createFacesMessage(FacesMessage.SEVERITY_ERROR,"... isn't working
//need to sync seam message transport with our context
windowMessageMap.put("",messageList);
windowState.setMessages(windowMessageMap);
windowState.restoreMessages(context);
windowState.setViewRoot(context.getViewRoot());
}
public static Class classForName(String name) throws ClassNotFoundException
{
try
{
return Thread.currentThread().getContextClassLoader().loadClass(name);
}
catch (Exception e)
{
return Class.forName(name);
}
}
private void handleException(FacesContext facesContext, Exception e) throws BridgeException {
//if the event context was cleaned up, fish the conversation id
//directly out of the ServletRequest attributes, else get it from
//the event context
Manager manager = Contexts.isEventContextActive() ?
(Manager) Contexts.getEventContext().get(Manager.class) :
null;
String conversationId = manager==null ? null : manager.getCurrentConversationId();
//Initialize the temporary context objects
FacesLifecycle.beginExceptionRecovery( facesContext.getExternalContext() );
//If there is an existing long-running conversation on
//the failed request, propagate it
if (conversationId==null)
{
Manager.instance().initializeTemporaryConversation();
}
else
{
ConversationPropagation.instance().setConversationId(conversationId);
Manager.instance().restoreConversation();
}
//Now do the exception handling
try
{
messageList.add(new FacesMessage("An Internal error has occured.",""));
rollbackTransactionIfNecessary();
Exceptions.instance().handle(e);
}
catch (Exception ehe)
{
try {
//todo - there is an evaluation problem when trying to handle with Seam exception handler
throw new BridgeException(ehe);
} catch (BridgeException e1) {
messageList.add(new FacesMessage("Unable to process with Seam exception handler",""));
log.error("throwing new BridgeException was unsuccessfull");
e1.printStackTrace();
}
}
finally
{
//Finally, clean up the contexts
try
{
FacesLifecycle.endRequest( facesContext.getExternalContext() );
log.debug("done running exception handlers");
}
catch (Exception ere)
{
log.error("could not destroy contexts", ere);
}
}
}
protected void rollbackTransactionIfNecessary()
{
try
{
UserTransaction transaction = Transaction.instance();
if ( transaction.isActiveOrMarkedRollback() || transaction.isRolledBack() )
{
log.debug("killing transaction");
transaction.rollback();
}
}
catch (Exception te)
{
log.error("could not roll back transaction", te);
}
}
}