h:commandButton 등으로 설정하는 action속성은 언제 실행될까?
HTML에서 submit버튼을 클릭하게 되면 해당 버튼의 id 및 ViewState를 보낸다.(RESTORE_VIEW)
이후 Lifecycle에 의해 INVOKE_APPLICATION 에서는 AjaxViewRoot인스턴스를 생성후에 해당 UIComponent를 찾아서 broadcast한다.
AjaxViewRoot.java에서 실제 호출하는 부분은 아래.
public void processEvents(FacesContext context, EventsQueue phaseEventsQueue, boolean havePhaseEvents) { while (havePhaseEvents) try { FacesEvent event = (FacesEvent)phaseEventsQueue.remove(); UIComponent source = event.getComponent(); try { source.broadcast(event); } catch (AbortProcessingException e) { if (_log.isErrorEnabled()) { UIComponent component = event.getComponent(); String id = null != component ? component.getClientId(context) : ""; _log.error("Error processing faces event for the component " + id, e); } } } catch (NoSuchElementException e) { havePhaseEvents = false; } }아래는 UICommand.java에서의 처리부분. (UICommand는 HtmlCommandButton의 슈퍼클래스)
public void broadcast(FacesEvent event) throws AbortProcessingException { super.broadcast(event); if ((event instanceof ActionEvent)) { FacesContext context = getFacesContext(); MethodBinding mb = getActionListener(); if (mb != null) { mb.invoke(context, new Object[] { event }); } ActionListener listener = context.getApplication().getActionListener(); if (listener != null) listener.processAction((ActionEvent)event); } }참고로 Lifecycle에서 각각의 phase에서 실행되는 doPhase에 등록된 listener는 아래와 같다. (sample.war작성하여 출력해본 결과)
listener.add> com.sun.faces.lifecycle.ELResolverInitPhaseListener listener.add> com.sun.faces.renderkit.JsfJsResourcePhaseListener listener.add> org.jboss.seam.debug.jsf.SeamDebugPhaseListener listener.add> org.jboss.seam.jsf.SeamPhaseListener listener.add> org.jboss.seam.document.DocumentStorePhaseListener listener.add> org.ajax4jsf.event.AjaxPhaseListener listener.add> org.ajax4jsf.event.InitPhaseListener listener.add> org.richfaces.component.FileUploadPhaselistener아래는 Seam과 JSF에서 가장 핵심적인 부분의 소스를 찾아보았다.
package javax.faces.webapp; import java.io.IOException; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; import javax.faces.FacesException; import javax.faces.FactoryFinder; import javax.faces.context.FacesContext; import javax.faces.context.FacesContextFactory; import javax.faces.lifecycle.Lifecycle; import javax.faces.lifecycle.LifecycleFactory; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public final class FacesServlet implements Servlet { public static final String CONFIG_FILES_ATTR = "javax.faces.CONFIG_FILES"; public static final String LIFECYCLE_ID_ATTR = "javax.faces.LIFECYCLE_ID"; private static final Logger LOGGER = Logger.getLogger("javax.faces.webapp", "javax.faces.LogStrings"); private FacesContextFactory facesContextFactory = null; private Lifecycle lifecycle = null; private ServletConfig servletConfig = null; public void destroy() { this.facesContextFactory = null; this.lifecycle = null; this.servletConfig = null; } public ServletConfig getServletConfig() { return this.servletConfig; } public String getServletInfo() { return getClass().getName(); } public void init(ServletConfig servletConfig) throws ServletException { this.servletConfig = servletConfig; try { this.facesContextFactory = ((FacesContextFactory) FactoryFinder.getFactory("javax.faces.context.FacesContextFactory")); } catch (FacesException e) { ResourceBundle rb = LOGGER.getResourceBundle(); String msg = rb.getString("severe.webapp.facesservlet.init_failed"); Throwable rootCause = e.getCause() != null ? e.getCause() : e; LOGGER.log(Level.SEVERE, msg, rootCause); throw new UnavailableException(msg); } try { LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory("javax.faces.lifecycle.LifecycleFactory"); String lifecycleId; if (null == (lifecycleId = servletConfig.getInitParameter("javax.faces.LIFECYCLE_ID"))) { lifecycleId = servletConfig.getServletContext().getInitParameter("javax.faces.LIFECYCLE_ID"); } if (lifecycleId == null) { lifecycleId = "DEFAULT"; } this.lifecycle = lifecycleFactory.getLifecycle(lifecycleId); } catch (FacesException e) { Throwable rootCause = e.getCause(); if (rootCause == null) { throw e; } throw new ServletException(e.getMessage(), rootCause); } } public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException { String pathInfo = ((HttpServletRequest) request).getPathInfo(); if (pathInfo != null) { pathInfo = pathInfo.toUpperCase(); if ((pathInfo.startsWith("/WEB-INF/")) || (pathInfo.equals("/WEB-INF")) || (pathInfo.startsWith("/META-INF/")) || (pathInfo.equals("/META-INF"))) { ((HttpServletResponse) response).sendError(404); return; } } FacesContext context = this.facesContextFactory.getFacesContext(this.servletConfig.getServletContext(), request, response, this.lifecycle); System.out.println("> " + lifecycle); try { System.out.println("> lifecycle.execute(context)"); this.lifecycle.execute(context); System.out.println("> lifecycle.render(context)"); this.lifecycle.render(context); } catch (FacesException e) { Throwable t = e.getCause(); if (t == null) { throw new ServletException(e.getMessage(), e); } if ((t instanceof ServletException)) throw ((ServletException) t); if ((t instanceof IOException)) { throw ((IOException) t); } throw new ServletException(t.getMessage(), t); } finally { System.out.println("> context.release()"); context.release(); } } }
package com.sun.faces.context; import com.sun.faces.el.ELContextImpl; import com.sun.faces.util.FacesLogger; import com.sun.faces.util.RequestStateManager; import com.sun.faces.util.Util; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.el.ELContext; import javax.faces.FactoryFinder; import javax.faces.application.Application; import javax.faces.application.ApplicationFactory; import javax.faces.application.FacesMessage; import javax.faces.application.FacesMessage.Severity; import javax.faces.component.UIViewRoot; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.context.ResponseStream; import javax.faces.context.ResponseWriter; import javax.faces.lifecycle.Lifecycle; import javax.faces.render.RenderKit; import javax.faces.render.RenderKitFactory; public class FacesContextImpl extends FacesContext { private static Logger LOGGER; private boolean released; private ResponseStream responseStream = null; private ResponseWriter responseWriter = null; private ExternalContext externalContext = null; private Application application = null; private UIViewRoot viewRoot = null; private ELContext elContext = null; private RenderKitFactory rkFactory; private RenderKit lastRk; private String lastRkId; private Map<String, List<FacesMessage>> componentMessageLists; private boolean renderResponse = false; private boolean responseComplete = false; public FacesContextImpl() { } public FacesContextImpl(ExternalContext ec, Lifecycle lifecycle) { Util.notNull("ec", ec); Util.notNull("lifecycle", lifecycle); this.externalContext = ec; setCurrentInstance(this); this.rkFactory = ((RenderKitFactory) FactoryFinder.getFactory("javax.faces.render.RenderKitFactory")); } public ExternalContext getExternalContext() { assertNotReleased(); return this.externalContext; } public Application getApplication() { assertNotReleased(); if (null != this.application) { return this.application; } ApplicationFactory aFactory = (ApplicationFactory) FactoryFinder.getFactory("javax.faces.application.ApplicationFactory"); this.application = aFactory.getApplication(); assert (null != this.application); return this.application; } public ELContext getELContext() { assertNotReleased(); if (this.elContext == null) { this.elContext = new ELContextImpl(getApplication().getELResolver()); this.elContext.putContext(FacesContext.class, this); UIViewRoot root = getViewRoot(); if (null != root) { this.elContext.setLocale(root.getLocale()); } } return this.elContext; } public Iterator<String> getClientIdsWithMessages() { assertNotReleased(); if ( this.componentMessageLists == null ) { List<String> x = Collections.emptyList(); return x.iterator(); } return this.componentMessageLists.keySet().iterator(); } public FacesMessage.Severity getMaximumSeverity() { assertNotReleased(); FacesMessage.Severity result = null; if ((this.componentMessageLists != null) && (!this.componentMessageLists.isEmpty())) { Iterator i = new ComponentMessagesIterator(this.componentMessageLists); while (i.hasNext()) { FacesMessage.Severity severity = ((FacesMessage) i.next()).getSeverity(); if ((result == null) || (severity.compareTo(result) > 0)) { result = severity; } if (result == FacesMessage.SEVERITY_FATAL) { break; } } } return result; } public Iterator<FacesMessage> getMessages() { assertNotReleased(); if (null == this.componentMessageLists) { List emptyList = Collections.emptyList(); return emptyList.iterator(); } if (RequestStateManager.containsKey(this, "com.sun.faces.clientIdMessagesNotDisplayed")) { Set pendingClientIds = (Set) RequestStateManager.get(this, "com.sun.faces.clientIdMessagesNotDisplayed"); pendingClientIds.clear(); } if (this.componentMessageLists.size() > 0) { return new ComponentMessagesIterator(this.componentMessageLists); } List emptyList = Collections.emptyList(); return emptyList.iterator(); } public Iterator<FacesMessage> getMessages(String clientId) { assertNotReleased(); Set pendingClientIds = (Set) RequestStateManager.get(this, "com.sun.faces.clientIdMessagesNotDisplayed"); if ((pendingClientIds != null) && (!pendingClientIds.isEmpty())) { pendingClientIds.remove(clientId); } if (null == this.componentMessageLists) { List emptyList = Collections.emptyList(); return emptyList.iterator(); } List list = (List) this.componentMessageLists.get(clientId); if (list == null) { List emptyList = Collections.emptyList(); return emptyList.iterator(); } return list.iterator(); } public RenderKit getRenderKit() { assertNotReleased(); UIViewRoot vr = getViewRoot(); if (vr == null) { return null; } String renderKitId = vr.getRenderKitId(); if (renderKitId == null) { return null; } if (renderKitId.equals(this.lastRkId)) { return this.lastRk; } this.lastRk = this.rkFactory.getRenderKit(this, renderKitId); this.lastRkId = renderKitId; return this.lastRk; } public ResponseStream getResponseStream() { assertNotReleased(); return this.responseStream; } public void setResponseStream(ResponseStream responseStream) { assertNotReleased(); Util.notNull("responseStream", responseStream); this.responseStream = responseStream; } public UIViewRoot getViewRoot() { assertNotReleased(); return this.viewRoot; } public void setViewRoot(UIViewRoot viewRoot) { assertNotReleased(); Util.notNull("viewRoot", viewRoot); this.viewRoot = viewRoot; } public ResponseWriter getResponseWriter() { assertNotReleased(); return this.responseWriter; } public void setResponseWriter(ResponseWriter responseWriter) { assertNotReleased(); Util.notNull("responseWriter", responseWriter); this.responseWriter = responseWriter; } public void addMessage(String clientId, FacesMessage message) { assertNotReleased(); Util.notNull("message", message); if (this.componentMessageLists == null) { this.componentMessageLists = new LinkedHashMap(); } List list = (List) this.componentMessageLists.get(clientId); if (list == null) { list = new ArrayList(); this.componentMessageLists.put(clientId, list); } list.add(message); if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Adding Message[sourceId=" + (clientId != null ? clientId : "<<NONE>>") + ",summary=" + message.getSummary() + ")"); } public void release() { RequestStateManager.remove(this, "com.sun.faces.FacesContextImpl"); RequestStateManager.remove(this, "com.sun.faces.clientIdMessagesNotDisplayed"); this.released = true; this.externalContext = null; this.responseStream = null; this.responseWriter = null; this.componentMessageLists = null; this.renderResponse = false; this.responseComplete = false; this.viewRoot = null; setCurrentInstance(null); } public void renderResponse() { assertNotReleased(); this.renderResponse = true; } public void responseComplete() { assertNotReleased(); this.responseComplete = true; } public boolean getRenderResponse() { assertNotReleased(); return this.renderResponse; } public boolean getResponseComplete() { assertNotReleased(); return this.responseComplete; } private void assertNotReleased() { if (this.released) throw new IllegalStateException(); } static { LOGGER = FacesLogger.CONTEXT.getLogger(); } private static final class ComponentMessagesIterator implements Iterator<FacesMessage> { private Map<String, List<FacesMessage>> messages; private int outerIndex = -1; private int messagesSize; private Iterator<FacesMessage> inner; private Iterator<String> keys; ComponentMessagesIterator(Map<String, List<FacesMessage>> messages) { this.messages = messages; this.messagesSize = messages.size(); this.keys = messages.keySet().iterator(); } public boolean hasNext() { if (this.outerIndex == -1) { this.outerIndex += 1; this.inner = ((List) this.messages.get(this.keys.next())).iterator(); } while (!this.inner.hasNext()) { this.outerIndex += 1; if (this.outerIndex < this.messagesSize) { this.inner = ((List) this.messages.get(this.keys.next())).iterator(); continue; } return false; } return this.inner.hasNext(); } public FacesMessage next() { if (this.outerIndex >= this.messagesSize) { throw new NoSuchElementException(); } if ((this.inner != null) && (this.inner.hasNext())) { return (FacesMessage) this.inner.next(); } if (!hasNext()) { throw new NoSuchElementException(); } return (FacesMessage) this.inner.next(); } public void remove() { if (this.outerIndex == -1) { throw new IllegalStateException(); } this.inner.remove(); } } }
package com.sun.faces.lifecycle; import com.sun.faces.util.FacesLogger; import com.sun.faces.util.MessageUtils; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.logging.Level; import java.util.logging.Logger; import javax.faces.FacesException; import javax.faces.context.FacesContext; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.faces.lifecycle.Lifecycle; public class LifecycleImpl extends Lifecycle { private static Logger LOGGER = FacesLogger.LIFECYCLE.getLogger(); private Phase response = new RenderResponsePhase(); private Phase[] phases = { null, new RestoreViewPhase(), new ApplyRequestValuesPhase(), new ProcessValidationsPhase(), new UpdateModelValuesPhase(), new InvokeApplicationPhase(), this.response }; private List<PhaseListener> listeners = new CopyOnWriteArrayList(); public void execute(FacesContext context) throws FacesException { if (context == null) { throw new NullPointerException(MessageUtils.getExceptionMessageString("com.sun.faces.NULL_PARAMETERS_ERROR", new Object[] { "context" })); } if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("execute(" + context + ")"); } int i = 1; for (int len = this.phases.length - 1; i < len; i++) { if ((context.getRenderResponse()) || (context.getResponseComplete())) { break; } this.phases[i].doPhase(context, this, this.listeners.listIterator()); } } public void render(FacesContext context) throws FacesException { if (context == null) { throw new NullPointerException(MessageUtils.getExceptionMessageString("com.sun.faces.NULL_PARAMETERS_ERROR", new Object[] { "context" })); } if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("render(" + context + ")"); } if (!context.getResponseComplete()) this.response.doPhase(context, this, this.listeners.listIterator()); } public void addPhaseListener(PhaseListener listener) { if (listener == null) { throw new NullPointerException(MessageUtils.getExceptionMessageString("com.sun.faces.NULL_PARAMETERS_ERROR", new Object[] { "listener" })); } if (this.listeners == null) { this.listeners = new CopyOnWriteArrayList(); } if (this.listeners.contains(listener)) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "jsf.lifecycle.duplicate_phase_listener_detected", listener.getClass().getName()); } } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "addPhaseListener({0},{1})", new Object[] { listener.getPhaseId().toString(), listener.getClass().getName() }); } this.listeners.add(listener); } } public PhaseListener[] getPhaseListeners() { return (PhaseListener[]) this.listeners.toArray(new PhaseListener[this.listeners.size()]); } public void removePhaseListener(PhaseListener listener) { if (listener == null) { throw new NullPointerException(MessageUtils.getExceptionMessageString("com.sun.faces.NULL_PARAMETERS_ERROR", new Object[] { "listener" })); } if ((this.listeners.remove(listener)) && (LOGGER.isLoggable(Level.FINE))) LOGGER.log(Level.FINE, "removePhaseListener({0})", new Object[] { listener.getClass().getName() }); } }
package org.ajax4jsf.application; import java.io.IOException; import java.util.Map; import javax.faces.FacesException; import javax.faces.application.ViewHandler; import javax.faces.component.UIViewRoot; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import org.ajax4jsf.Messages; import org.ajax4jsf.component.AjaxViewRoot; import org.ajax4jsf.context.AjaxContext; import org.ajax4jsf.context.ViewIdHolder; import org.ajax4jsf.context.ViewResources; import org.ajax4jsf.resource.InternetResource; import org.ajax4jsf.resource.InternetResourceBuilder; import org.ajax4jsf.webapp.FilterServletResponseWrapper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.richfaces.event.RenderPhaseComponentListener; public class AjaxViewHandler extends ViewHandlerWrapper { public static final String RESOURCES_PROCESSED = "org.ajax4jsf.framework.HEADER_PROCESSED"; public static final String STATE_MARKER_KEY = "org.ajax4jsf.view.state"; public static final String SERIALIZED_STATE_KEY = "org.ajax4jsf.view.serializedstate"; private static final Log _log = LogFactory.getLog(AjaxViewHandler.class); public static final String VIEW_EXPIRED = "org.ajax4jsf.view.EXPIRED"; public static final String VIEW_ID_KEY = "org.ajax4jsf.VIEW_ID"; public AjaxViewHandler(ViewHandler parent) { super(parent); if (_log.isDebugEnabled()) _log.debug("Create instance of Ajax ViewHandler"); } public UIViewRoot createView(FacesContext facesContext, String viewId) { AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); ViewIdHolder viewIdHolder = ajaxContext.getViewIdHolder(); UIViewRoot riRoot; UIViewRoot riRoot; if ((null != viewIdHolder) && (viewIdHolder.skipNavigation(viewId))) { viewIdHolder.setViewId(viewId); riRoot = facesContext.getViewRoot(); } else { riRoot = super.createView(facesContext, viewId); riRoot.addPhaseListener(new RenderPhaseComponentListener()); if (null != facesContext.getViewRoot()) { ajaxContext.setAjaxRequest(false); } } return riRoot; } public void writeState(FacesContext context) throws IOException { AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context); if ((ajaxContext.isAjaxRequest()) && (ajaxContext.isSelfRender())) { ResponseWriter writer = context.getResponseWriter(); writer.startElement("span", null); writer.writeAttribute("id", "org.ajax4jsf.view.state", null); writer.writeAttribute("name", "org.ajax4jsf.view.state", null); writer.endElement("span"); } else { super.writeState(context); } } public String getResourceURL(FacesContext context, String url) { String resourceURL; String resourceURL; if (url.startsWith("resource://")) { InternetResource resource = InternetResourceBuilder.getInstance().createResource(null, url.substring(InternetResource.RESOURCE_URI_PREFIX_LENGTH)); resourceURL = resource.getUri(context, null); } else { resourceURL = super.getResourceURL(context, url); } return resourceURL; } public void renderView(FacesContext context, UIViewRoot root) throws IOException, FacesException { AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context); if ((root instanceof AjaxViewRoot)) { AjaxViewRoot ajaxRoot = (AjaxViewRoot)root; if (ajaxContext.isAjaxRequest()) { processAjaxEvents(context, ajaxRoot); if (ajaxContext.isSelfRender()) { ajaxContext.renderAjax(context); } } if (!context.getResponseComplete()) super.renderView(context, root); } else { super.renderView(context, root); } Map requestMap = context.getExternalContext().getRequestMap(); FilterServletResponseWrapper filterServletResponseWrapper = (FilterServletResponseWrapper)requestMap.get("com.exade.vcp.Filter.ResponseWrapper"); if (null != filterServletResponseWrapper) { if ((!filterServletResponseWrapper.isError()) && (!Boolean.TRUE.equals(requestMap.get("org.ajax4jsf.framework.HEADER_PROCESSED")))) { ViewResources viewResources = new ViewResources(); viewResources.initialize(context); viewResources.processHeadResources(context); requestMap.put("org.ajax4jsf.framework.HEAD_EVENTS_LIST", viewResources.getHeadEvents()); requestMap.put("org.ajax4jsf.framework.HEADER_PROCESSED", Boolean.TRUE); } requestMap.put("org.ajax4jsf.VIEW_ID", context.getViewRoot().getViewId()); } } private void processAjaxEvents(FacesContext context, AjaxViewRoot ajaxRoot) { if (_log.isDebugEnabled()) { _log.debug(Messages.getMessage("PROCESS_AJAX_EVENTS_INFO")); } ajaxRoot.broadcastAjaxEvents(context); } }
package javax.faces.component; import javax.el.ELException; import javax.el.MethodExpression; import javax.el.ValueExpression; import javax.faces.FacesException; import javax.faces.application.Application; import javax.faces.context.FacesContext; import javax.faces.el.MethodBinding; import javax.faces.event.AbortProcessingException; import javax.faces.event.ActionEvent; import javax.faces.event.ActionListener; import javax.faces.event.FacesEvent; import javax.faces.event.PhaseId; public class UICommand extends UIComponentBase implements ActionSource2 { public static final String COMPONENT_TYPE = "javax.faces.Command"; public static final String COMPONENT_FAMILY = "javax.faces.Command"; private Object value = null; private Boolean immediate; private MethodBinding methodBindingActionListener = null; private MethodExpression actionExpression = null; private Object[] values; public UICommand() { setRendererType("javax.faces.Button"); } public String getFamily() { return "javax.faces.Command"; } /** @deprecated */ public MethodBinding getAction() { MethodBinding result = null; MethodExpression me; if (null != (me = getActionExpression())) { if (me.getClass().equals(MethodExpressionMethodBindingAdapter.class)) { result = ((MethodExpressionMethodBindingAdapter)me).getWrapped(); } else { result = new MethodBindingMethodExpressionAdapter(me); } } return result; } /** @deprecated */ public void setAction(MethodBinding action) { if (null != action) { MethodExpressionMethodBindingAdapter adapter = new MethodExpressionMethodBindingAdapter(action); setActionExpression(adapter); } else { setActionExpression(null); } } /** @deprecated */ public MethodBinding getActionListener() { return this.methodBindingActionListener; } /** @deprecated */ public void setActionListener(MethodBinding actionListener) { this.methodBindingActionListener = actionListener; } public boolean isImmediate() { if (this.immediate != null) { return this.immediate.booleanValue(); } ValueExpression ve = getValueExpression("immediate"); if (ve != null) { try { return Boolean.TRUE.equals(ve.getValue(getFacesContext().getELContext())); } catch (ELException e) { throw new FacesException(e); } } return false; } public void setImmediate(boolean immediate) { this.immediate = Boolean.valueOf(immediate); } public Object getValue() { if (this.value != null) { return this.value; } ValueExpression ve = getValueExpression("value"); if (ve != null) { try { return ve.getValue(getFacesContext().getELContext()); } catch (ELException e) { throw new FacesException(e); } } return null; } public void setValue(Object value) { this.value = value; } public MethodExpression getActionExpression() { return this.actionExpression; } public void setActionExpression(MethodExpression actionExpression) { this.actionExpression = actionExpression; } public void addActionListener(ActionListener listener) { addFacesListener(listener); } public ActionListener[] getActionListeners() { ActionListener[] al = (ActionListener[])(ActionListener[])getFacesListeners(ActionListener.class); return al; } public void removeActionListener(ActionListener listener) { removeFacesListener(listener); } public Object saveState(FacesContext context) { if (this.values == null) { this.values = new Object[5]; } this.values[0] = super.saveState(context); this.values[1] = saveAttachedState(context, this.methodBindingActionListener); this.values[2] = saveAttachedState(context, this.actionExpression); this.values[3] = this.immediate; this.values[4] = this.value; return this.values; } public void restoreState(FacesContext context, Object state) { this.values = ((Object[])(Object[])state); super.restoreState(context, this.values[0]); this.methodBindingActionListener = ((MethodBinding)restoreAttachedState(context, this.values[1])); this.actionExpression = ((MethodExpression)restoreAttachedState(context, this.values[2])); this.immediate = ((Boolean)this.values[3]); this.value = this.values[4]; } public void broadcast(FacesEvent event) throws AbortProcessingException { super.broadcast(event); if ((event instanceof ActionEvent)) { FacesContext context = getFacesContext(); MethodBinding mb = getActionListener(); if (mb != null) { mb.invoke(context, new Object[] { event }); } ActionListener listener = context.getApplication().getActionListener(); if (listener != null) listener.processAction((ActionEvent)event); } } public void queueEvent(FacesEvent e) { UIComponent c = e.getComponent(); if (((e instanceof ActionEvent)) && ((c instanceof ActionSource))) { if (((ActionSource)c).isImmediate()) e.setPhaseId(PhaseId.APPLY_REQUEST_VALUES); else { e.setPhaseId(PhaseId.INVOKE_APPLICATION); } } super.queueEvent(e); } }
package org.ajax4jsf.component; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import javax.el.MethodExpression; import javax.faces.FacesException; import javax.faces.FactoryFinder; import javax.faces.component.ContextCallback; import javax.faces.component.UIComponent; import javax.faces.component.UIViewRoot; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.event.AbortProcessingException; import javax.faces.event.FacesEvent; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.faces.lifecycle.Lifecycle; import javax.faces.lifecycle.LifecycleFactory; import javax.faces.render.Renderer; import org.ajax4jsf.Messages; import org.ajax4jsf.context.AjaxContext; import org.ajax4jsf.context.InvokerCallback; import org.ajax4jsf.context.ViewIdHolder; import org.ajax4jsf.event.AjaxListener; import org.ajax4jsf.event.EventsQueue; import org.ajax4jsf.renderkit.AjaxContainerRenderer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class AjaxViewRoot extends UIViewRoot implements AjaxContainer { public static final String ROOT_ID = "_viewRoot"; public static final String JS_NULL = "null"; private Lifecycle lifecycle; private AjaxRegionBrige _brige; private static final Log _log = LogFactory.getLog(AjaxViewRoot.class); private List<PhaseListener> phaseListeners = null; private EventsQueue[] events; private EventsQueue ajaxEvents = new EventsQueue(); private InvokerCallback _decodeInvoker = new InvokerCallback() { public void invokeContextCallback(FacesContext context, UIComponent component) { component.processDecodes(context); } public void invokeRoot(FacesContext context) { AjaxViewRoot.this.decode(context); } }; private InvokerCallback _updatesInvoker = new InvokerCallback() { public void invokeContextCallback(FacesContext context, UIComponent component) { component.processUpdates(context); } public void invokeRoot(FacesContext context) { } }; private InvokerCallback _validatorsInvoker = new InvokerCallback() { public void invokeContextCallback(FacesContext context, UIComponent component) { component.processValidators(context); } public void invokeRoot(FacesContext context) { } }; private ContextCallback _ajaxInvoker = new ContextCallback() { public void invokeContextCallback(FacesContext context, UIComponent component) { try { if ((component instanceof AjaxContainer)) { AjaxContainer ajax = (AjaxContainer)component; ajax.encodeAjax(context); } else { AjaxViewRoot.this.encodeAjax(context); } } catch (IOException e) { throw new FacesException(e); } } }; public AjaxViewRoot() { super.setId("_viewRoot"); this._brige = new AjaxRegionBrige(this); } public String getRendererType() { return "javax.faces.ViewRoot"; } public void broadcast(FacesEvent event) throws AbortProcessingException { super.broadcast(event); getBrige().broadcast(event); } public MethodExpression getAjaxListener() { return getBrige().getAjaxListener(); } public boolean isImmediate() { return getBrige().isImmediate(); } public boolean isSubmitted() { return getBrige().isSubmitted(); } public void removePhaseListener(PhaseListener toRemove) { if (null != this.phaseListeners) { this.phaseListeners.remove(toRemove); } super.removePhaseListener(toRemove); } public void addPhaseListener(PhaseListener newPhaseListener) { if (null == this.phaseListeners) { this.phaseListeners = new ArrayList(); } this.phaseListeners.add(newPhaseListener); super.addPhaseListener(newPhaseListener); } protected void processPhaseListeners(FacesContext context, PhaseId phase, boolean before) { MethodExpression listenerExpression = before ? getBeforePhaseListener() : getAfterPhaseListener(); PhaseEvent event = null; if (null != listenerExpression) { event = createPhaseEvent(context, phase); listenerExpression.invoke(context.getELContext(), new Object[] { event }); } if (null != this.phaseListeners) for (PhaseListener listener : this.phaseListeners) { PhaseId phaseId = listener.getPhaseId(); if ((phaseId == phase) || (phaseId == PhaseId.ANY_PHASE)) { if (null == event) { event = createPhaseEvent(context, phase); } if (before) listener.beforePhase(event); else listener.afterPhase(event); } } } protected PhaseEvent createPhaseEvent(FacesContext context, PhaseId phaseId) throws FacesException { if (this.lifecycle == null) { LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory("javax.faces.lifecycle.LifecycleFactory"); String lifecycleId = context.getExternalContext().getInitParameter("javax.faces.LIFECYCLE_ID"); if (lifecycleId == null) { lifecycleId = "DEFAULT"; } this.lifecycle = lifecycleFactory.getLifecycle(lifecycleId); } return new PhaseEvent(context, phaseId, this.lifecycle); } protected void processPhase(FacesContext context, PhaseId phase, InvokerCallback callback) { processPhaseListeners(context, phase, true); InvokerCallback invokerCallback; if ((null != callback) && (!context.getRenderResponse()) && (!context.getResponseComplete())) { AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context); String submittedRegionClientId = ajaxContext.getSubmittedRegionClientId(); if ((ajaxContext.isAjaxRequest()) && (submittedRegionClientId != null) && (!submittedRegionClientId.equals("null")) && (!submittedRegionClientId.equals(getClientId(context)))) { invokeOnComponent(context, submittedRegionClientId, new InvokerCallbackWrapper(callback)); } else { try { callback.invokeRoot(context); } catch (RuntimeException e) { context.renderResponse(); throw e; } String ajaxSingleClientId = ajaxContext.getAjaxSingleClientId(); if (null == ajaxSingleClientId) { Iterator iter = getFacetsAndChildren(); while (iter.hasNext()) callback.invokeContextCallback(context, (UIComponent)iter.next()); } else { invokerCallback = new InvokerCallbackWrapper(callback); invokeOnComponent(context, ajaxSingleClientId, invokerCallback); Set areasToProcess = ajaxContext.getAjaxAreasToProcess(); if (null != areasToProcess) { for (String areaId : areasToProcess) { invokeOnComponent(context, areaId, invokerCallback); } } } } } broadcastEvents(context, phase); processPhaseListeners(context, phase, false); } public void queueEvent(FacesEvent event) { if (event == null) { throw new NullPointerException(Messages.getMessage("NULL_EVENT_SUBMITTED_ERROR")); } if (event.getPhaseId().compareTo(PhaseId.RENDER_RESPONSE) == 0) { getAjaxEventsQueue().offer(event); } else getEventsQueue(event.getPhaseId()).offer(event); } void broadcastEvents(FacesContext context, PhaseId phaseId) { EventsQueue[] events = getEvents(); EventsQueue anyPhaseEvents = events[PhaseId.ANY_PHASE.getOrdinal()]; EventsQueue phaseEvents = events[phaseId.getOrdinal()]; if ((phaseEvents.isEmpty()) && (anyPhaseEvents.isEmpty())) { return; } boolean haveAnyPhaseEvents = !anyPhaseEvents.isEmpty(); boolean havePhaseEvents = !phaseEvents.isEmpty(); do { processEvents(context, anyPhaseEvents, haveAnyPhaseEvents); processEvents(context, phaseEvents, havePhaseEvents); haveAnyPhaseEvents = !anyPhaseEvents.isEmpty(); havePhaseEvents = !phaseEvents.isEmpty(); }while ((haveAnyPhaseEvents) || (havePhaseEvents)); if ((context.getRenderResponse()) || (context.getResponseComplete())) clearEvents(); } public void processEvents(FacesContext context, EventsQueue phaseEventsQueue, boolean havePhaseEvents) { while (havePhaseEvents) try { FacesEvent event = (FacesEvent)phaseEventsQueue.remove(); UIComponent source = event.getComponent(); try { source.broadcast(event); } catch (AbortProcessingException e) { if (_log.isErrorEnabled()) { UIComponent component = event.getComponent(); String id = null != component ? component.getClientId(context) : ""; _log.error("Error processing faces event for the component " + id, e); } } } catch (NoSuchElementException e) { havePhaseEvents = false; } } public void broadcastAjaxEvents(FacesContext context) { EventsQueue queue = getAjaxEventsQueue(); processEvents(context, queue, !queue.isEmpty()); } protected EventsQueue getEventsQueue(PhaseId phase) { return getEvents()[phase.getOrdinal()]; } protected EventsQueue[] getEvents() { if (this.events == null) { clearEvents(); } return this.events; } protected EventsQueue getAjaxEventsQueue() { return this.ajaxEvents; } public void clearEvents() { int len; this.events = new EventsQueue[len = PhaseId.VALUES.size()]; for (int i = 0; i < len; i++) this.events[i] = new EventsQueue(); } public void processDecodes(FacesContext context) { if (context == null) throw new NullPointerException("context"); processPhase(context, PhaseId.APPLY_REQUEST_VALUES, this._decodeInvoker); } public void processUpdates(FacesContext context) { if (context == null) throw new NullPointerException("context"); processPhase(context, PhaseId.UPDATE_MODEL_VALUES, this._updatesInvoker); } public void processValidators(FacesContext context) { if (context == null) throw new NullPointerException("context"); processPhase(context, PhaseId.PROCESS_VALIDATIONS, this._validatorsInvoker); } public void processApplication(FacesContext context) { if (context == null) throw new NullPointerException("context"); processPhase(context, PhaseId.INVOKE_APPLICATION, null); } public void encodeBegin(FacesContext context) throws IOException { processPhaseListeners(context, PhaseId.RENDER_RESPONSE, true); String rendererType = getRendererType(); if (rendererType != null) { Renderer renderer = getRenderer(context); if (renderer != null) renderer.encodeBegin(context, this); } } public void encodeEnd(FacesContext context) throws IOException { String rendererType = getRendererType(); if (rendererType != null) { Renderer renderer = getRenderer(context); if (renderer != null) { renderer.encodeEnd(context, this); } } processPhaseListeners(context, PhaseId.RENDER_RESPONSE, false); } public void encodeChildren(FacesContext context) throws IOException { AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context); if (ajaxContext.isAjaxRequest()) { String submittedRegionClientId = ajaxContext.getSubmittedRegionClientId(); boolean invoked = false; if ((submittedRegionClientId != null) && (!submittedRegionClientId.equals("null")) && (!submittedRegionClientId.equals(getClientId(context)))) { invoked = invokeOnComponent(context, submittedRegionClientId, this._ajaxInvoker); } if (!invoked) encodeAjax(context); } else { super.encodeChildren(context); } } public void restoreState(FacesContext context, Object state) { Object[] mystate = (Object[])(Object[])state; super.restoreState(context, mystate[0]); getBrige().restoreState(context, mystate[1]); Object listeners = restoreAttachedState(context, mystate[2]); if (null != listeners) this.phaseListeners = ((List)listeners); } public Object saveState(FacesContext context) { Object[] state = new Object[3]; state[0] = super.saveState(context); state[1] = getBrige().saveState(context); state[2] = saveAttachedState(context, this.phaseListeners); return state; } public String getViewId() { ViewIdHolder viewIdHolder = AjaxContext.getCurrentInstance().getViewIdHolder(); String viewId; String viewId; if (null != viewIdHolder) viewId = viewIdHolder.getViewId(); else { viewId = super.getViewId(); } return viewId; } public void setAjaxListener(MethodExpression ajaxListener) { getBrige().setAjaxListener(ajaxListener); } public void setImmediate(boolean immediate) { getBrige().setImmediate(immediate); } public void setSubmitted(boolean submitted) { getBrige().setSubmitted(submitted); } public void addAjaxListener(AjaxListener listener) { addFacesListener(listener); } public AjaxListener[] getAjaxListeners() { return (AjaxListener[])(AjaxListener[])getFacesListeners(AjaxListener.class); } public void removeAjaxListener(AjaxListener listener) { removeFacesListener(listener); } public boolean isSelfRendered() { return false; } public void setSelfRendered(boolean selfRendered) { } public boolean getRendersChildren() { FacesContext context = FacesContext.getCurrentInstance(); return AjaxContext.getCurrentInstance(context).isAjaxRequest(); } public boolean isRenderRegionOnly() { return false; } public void setRenderRegionOnly(boolean reRenderPage) { } public void encodeAjax(FacesContext context) throws IOException { String rendererType = getRendererType(); if (rendererType != null) ((AjaxContainerRenderer)getRenderer(context)).encodeAjax(context, this); } protected AjaxRegionBrige getBrige() { return this._brige; } }
package com.sun.facelets; import com.sun.facelets.compiler.Compiler; import com.sun.facelets.compiler.SAXCompiler; import com.sun.facelets.compiler.TagLibraryConfig; import com.sun.facelets.impl.DefaultFaceletFactory; import com.sun.facelets.impl.DefaultResourceResolver; import com.sun.facelets.impl.ResourceResolver; import com.sun.facelets.tag.TagDecorator; import com.sun.facelets.tag.TagLibrary; import com.sun.facelets.tag.jsf.ComponentSupport; import com.sun.facelets.tag.ui.UIDebug; import com.sun.facelets.util.DevTools; import com.sun.facelets.util.FacesAPI; import com.sun.facelets.util.ReflectionUtil; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Writer; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.el.ELException; import javax.faces.FacesException; import javax.faces.application.Application; import javax.faces.application.StateManager; import javax.faces.application.StateManager.SerializedView; import javax.faces.application.ViewHandler; import javax.faces.component.UIViewRoot; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.render.RenderKit; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class FaceletViewHandler extends ViewHandler { protected static final Logger log = Logger.getLogger("facelets.viewhandler"); public static final long DEFAULT_REFRESH_PERIOD = 2L; public static final String PARAM_REFRESH_PERIOD = "facelets.REFRESH_PERIOD"; /** @deprecated */ public static final String PARAM_REFRESH_PERIO = "facelets.REFRESH_PERIOD"; public static final String PARAM_SKIP_COMMENTS = "facelets.SKIP_COMMENTS"; public static final String PARAM_VIEW_MAPPINGS = "facelets.VIEW_MAPPINGS"; public static final String PARAM_LIBRARIES = "facelets.LIBRARIES"; public static final String PARAM_DECORATORS = "facelets.DECORATORS"; public static final String PARAM_DEVELOPMENT = "facelets.DEVELOPMENT"; public static final String PARAM_RESOURCE_RESOLVER = "facelets.RESOURCE_RESOLVER"; public static final String PARAM_BUILD_BEFORE_RESTORE = "facelets.BUILD_BEFORE_RESTORE"; public static final String PARAM_BUFFER_SIZE = "facelets.BUFFER_SIZE"; private static final String STATE_KEY = "~facelets.VIEW_STATE~"; private static final int STATE_KEY_LEN = "~facelets.VIEW_STATE~".length(); private static final Object STATE_NULL = new Object(); private final ViewHandler parent; private boolean developmentMode = false; private boolean buildBeforeRestore = false; private int bufferSize; private String defaultSuffix; private FaceletFactory faceletFactory; private String[] extensionsArray; private String[] prefixesArray; public FaceletViewHandler(ViewHandler parent) { this.parent = parent; } protected void initialize(FacesContext context) { synchronized (this) { if (this.faceletFactory == null) { log.fine("Initializing"); Compiler c = createCompiler(); initializeCompiler(c); this.faceletFactory = createFaceletFactory(c); initializeMappings(context); initializeMode(context); initializeBuffer(context); log.fine("Initialization Successful"); } } } private void initializeMode(FacesContext context) { ExternalContext external = context.getExternalContext(); String param = external.getInitParameter("facelets.DEVELOPMENT"); this.developmentMode = "true".equals(param); String restoreMode = external.getInitParameter("facelets.BUILD_BEFORE_RESTORE"); this.buildBeforeRestore = "true".equals(restoreMode); } private void initializeBuffer(FacesContext context) { ExternalContext external = context.getExternalContext(); String param = external.getInitParameter("facelets.BUFFER_SIZE"); this.bufferSize = ((param != null) && (!"".equals(param)) ? Integer.parseInt(param) : -1); } private void initializeMappings(FacesContext context) { ExternalContext external = context.getExternalContext(); String viewMappings = external.getInitParameter("facelets.VIEW_MAPPINGS"); if ((viewMappings != null) && (viewMappings.length() > 0)) { String[] mappingsArray = viewMappings.split(";"); List extensionsList = new ArrayList(mappingsArray.length); List prefixesList = new ArrayList(mappingsArray.length); for (int i = 0; i < mappingsArray.length; i++) { String mapping = mappingsArray[i].trim(); int mappingLength = mapping.length(); if (mappingLength <= 1) { continue; } if (mapping.charAt(0) == '*') extensionsList.add(mapping.substring(1)); else if (mapping.charAt(mappingLength - 1) == '*') { prefixesList.add(mapping.substring(0, mappingLength - 1)); } } this.extensionsArray = new String[extensionsList.size()]; extensionsList.toArray(this.extensionsArray); this.prefixesArray = new String[prefixesList.size()]; prefixesList.toArray(this.prefixesArray); } } protected FaceletFactory createFaceletFactory(Compiler c) { long refreshPeriod = 2L; FacesContext ctx = FacesContext.getCurrentInstance(); String userPeriod = ctx.getExternalContext().getInitParameter("facelets.REFRESH_PERIOD"); if ((userPeriod != null) && (userPeriod.length() > 0)) { refreshPeriod = Long.parseLong(userPeriod); } ResourceResolver resolver = new DefaultResourceResolver(); String resolverName = ctx.getExternalContext().getInitParameter("facelets.RESOURCE_RESOLVER"); if ((resolverName != null) && (resolverName.length() > 0)) { try { resolver = (ResourceResolver)ReflectionUtil.forName(resolverName).newInstance(); } catch (Exception e) { throw new FacesException("Error Initializing ResourceResolver[" + resolverName + "]", e); } } return new DefaultFaceletFactory(c, resolver, refreshPeriod); } protected Compiler createCompiler() { return new SAXCompiler(); } protected void initializeCompiler(Compiler c) { FacesContext ctx = FacesContext.getCurrentInstance(); ExternalContext ext = ctx.getExternalContext(); String libParam = ext.getInitParameter("facelets.LIBRARIES"); if (libParam != null) { libParam = libParam.trim(); String[] libs = libParam.split(";"); for (int i = 0; i < libs.length; i++) { try { URL src = ext.getResource(libs[i].trim()); if (src == null) { throw new FileNotFoundException(libs[i]); } TagLibrary libObj = TagLibraryConfig.create(src); c.addTagLibrary(libObj); log.fine("Successfully Loaded Library: " + libs[i]); } catch (IOException e) { log.log(Level.SEVERE, "Error Loading Library: " + libs[i], e); } } } String decParam = ext.getInitParameter("facelets.DECORATORS"); if (decParam != null) { decParam = decParam.trim(); String[] decs = decParam.split(";"); for (int i = 0; i < decs.length; i++) { try { TagDecorator decObj = (TagDecorator)ReflectionUtil.forName(decs[i]).newInstance(); c.addTagDecorator(decObj); log.fine("Successfully Loaded Decorator: " + decs[i]); } catch (Exception e) { log.log(Level.SEVERE, "Error Loading Decorator: " + decs[i], e); } } } String skipParam = ext.getInitParameter("facelets.SKIP_COMMENTS"); if ((skipParam != null) && ("true".equals(skipParam))) c.setTrimmingComments(true); } public UIViewRoot restoreView(FacesContext context, String viewId) { if (UIDebug.debugRequest(context)) { return new UIViewRoot(); } if ((!this.buildBeforeRestore) || (!handledByFacelets(viewId))) { return this.parent.restoreView(context, viewId); } if (this.faceletFactory == null) { initialize(context); } if ((FacesAPI.getVersion() < 12) && (!isPostback11(context))) { return null; } ViewHandler outerViewHandler = context.getApplication().getViewHandler(); String renderKitId = outerViewHandler.calculateRenderKitId(context); UIViewRoot viewRoot = createView(context, viewId); context.setViewRoot(viewRoot); try { buildView(context, viewRoot); } catch (IOException ioe) { log.log(Level.SEVERE, "Error Building View", ioe); } context.getApplication().getStateManager().restoreView(context, viewId, renderKitId); return viewRoot; } protected ViewHandler getWrapped() { return this.parent; } protected ResponseWriter createResponseWriter(FacesContext context) throws IOException, FacesException { ExternalContext extContext = context.getExternalContext(); RenderKit renderKit = context.getRenderKit(); if (renderKit == null) { String id = context.getViewRoot().getRenderKitId(); throw new IllegalStateException("No render kit was available for id \"" + id + "\""); } ServletResponse response = (ServletResponse)extContext.getResponse(); if (this.bufferSize != -1) { response.setBufferSize(this.bufferSize); } String contentType = (String)extContext.getRequestMap().get("facelets.ContentType"); String encoding = (String)extContext.getRequestMap().get("facelets.Encoding"); if ((contentType != null) && (!contentType.equals("*/*"))) { contentType = contentType + ",*/*"; } try { writer = renderKit.createResponseWriter(NullWriter.Instance, contentType, encoding); } catch (IllegalArgumentException e) { log.fine("The impl didn't correctly handled '*/*' in the content type list. Trying '*/*' directly."); writer = renderKit.createResponseWriter(NullWriter.Instance, "*/*", encoding); } contentType = getResponseContentType(context, writer.getContentType()); encoding = getResponseEncoding(context, writer.getCharacterEncoding()); response.setContentType(contentType + "; charset=" + encoding); ResponseWriter writer = writer.cloneWithWriter(response.getWriter()); return writer; } protected String getResponseEncoding(FacesContext context, String orig) { String encoding = orig; Map m = context.getExternalContext().getRequestMap(); Map sm = context.getExternalContext().getSessionMap(); if (m.containsKey("facelets.Encoding")) { encoding = (String)m.get("facelets.Encoding"); if (log.isLoggable(Level.FINEST)) { log.finest("Facelet specified alternate encoding '" + encoding + "'"); } sm.put("javax.faces.request.charset", encoding); } Object request = context.getExternalContext().getRequest(); if ((encoding == null) && ((request instanceof ServletRequest))) { encoding = ((ServletRequest)request).getCharacterEncoding(); } if (encoding == null) { encoding = (String)sm.get("javax.faces.request.charset"); if (log.isLoggable(Level.FINEST)) { log.finest("Session specified alternate encoding '" + encoding + "'"); } } if (encoding == null) { encoding = "UTF-8"; if (log.isLoggable(Level.FINEST)) { log.finest("ResponseWriter created had a null CharacterEncoding, defaulting to UTF-8"); } } return encoding; } protected String getResponseContentType(FacesContext context, String orig) { String contentType = orig; Map m = context.getExternalContext().getRequestMap(); if (m.containsKey("facelets.ContentType")) { contentType = (String)m.get("facelets.ContentType"); if (log.isLoggable(Level.FINEST)) { log.finest("Facelet specified alternate contentType '" + contentType + "'"); } } if (contentType == null) { contentType = "text/html"; if (log.isLoggable(Level.FINEST)) { log.finest("ResponseWriter created had a null ContentType, defaulting to text/html"); } } return contentType; } protected void buildView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException { String renderedViewId = getRenderedViewId(context, viewToRender.getViewId()); viewToRender.setViewId(renderedViewId); if (log.isLoggable(Level.FINE)) { log.fine("Building View: " + renderedViewId); } Facelet f = null; FaceletFactory.setInstance(this.faceletFactory); try { f = this.faceletFactory.getFacelet(viewToRender.getViewId()); } finally { FaceletFactory.setInstance(null); } long time = System.currentTimeMillis(); f.apply(context, viewToRender); time = System.currentTimeMillis() - time; if (log.isLoggable(Level.FINE)) log.fine("Took " + time + "ms to build view: " + viewToRender.getViewId()); } public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException { if (this.faceletFactory == null) { initialize(context); } if (!viewToRender.isRendered()) { return; } if (!handledByFacelets(viewToRender.getViewId())) { this.parent.renderView(context, viewToRender); return; } if (log.isLoggable(Level.FINE)) { log.fine("Rendering View: " + viewToRender.getViewId()); } StateWriter stateWriter = null; try { if ((!this.buildBeforeRestore) || (viewToRender.getChildren().isEmpty())) { buildView(context, viewToRender); } ResponseWriter origWriter = createResponseWriter(context); stateWriter = new StateWriter(origWriter, this.bufferSize != -1 ? this.bufferSize : 1024); ResponseWriter writer = origWriter.cloneWithWriter(stateWriter); context.setResponseWriter(writer); StateManager stateMgr = context.getApplication().getStateManager(); if (!stateMgr.isSavingStateInClient(context)) { context.getExternalContext().getSession(true); } long time = System.currentTimeMillis(); writer.startDocument(); if (FacesAPI.getVersion() >= 12) viewToRender.encodeAll(context); else { ComponentSupport.encodeRecursive(context, viewToRender); } writer.endDocument(); writer.close(); if (FacesAPI.getVersion() < 12) { ComponentSupport.removeTransient(viewToRender); } boolean writtenState = stateWriter.isStateWritten(); if (writtenState) { String content = stateWriter.getAndResetBuffer(); int end = content.indexOf("~facelets.VIEW_STATE~"); if (end >= 0) { Object stateObj = stateMgr.saveSerializedView(context); String stateStr; String stateStr; if (stateObj == null) { stateStr = null; } else { stateMgr.writeState(context, (StateManager.SerializedView)stateObj); stateStr = stateWriter.getAndResetBuffer(); } int start = 0; while (end != -1) { origWriter.write(content, start, end - start); if (stateStr != null) { origWriter.write(stateStr); } start = end + STATE_KEY_LEN; end = content.indexOf("~facelets.VIEW_STATE~", start); } origWriter.write(content, start, content.length() - start); } else { origWriter.write(content); if ((FacesAPI.getVersion() < 12) && (!stateMgr.isSavingStateInClient(context))) { stateMgr.saveSerializedView(context); } } } time = System.currentTimeMillis() - time; if (log.isLoggable(Level.FINE)) { log.fine("Took " + time + "ms to render view: " + viewToRender.getViewId()); } } catch (FileNotFoundException fnfe) { handleFaceletNotFound(context, viewToRender.getViewId()); } catch (Exception e) { handleRenderException(context, e); } finally { if (stateWriter != null) stateWriter.release(); } } protected void handleRenderException(FacesContext context, Exception e) throws IOException, ELException, FacesException { Object resp = context.getExternalContext().getResponse(); if (log.isLoggable(Level.SEVERE)) { UIViewRoot root = context.getViewRoot(); StringBuffer sb = new StringBuffer(64); sb.append("Error Rendering View"); if (root != null) { sb.append('['); sb.append(root.getViewId()); sb.append(']'); } log.log(Level.SEVERE, sb.toString(), e); } if ((this.developmentMode) && (!context.getResponseComplete()) && ((resp instanceof HttpServletResponse))) { HttpServletResponse httpResp = (HttpServletResponse)resp; if (!httpResp.isCommitted()) { httpResp.reset(); httpResp.setContentType("text/html; charset=UTF-8"); Writer w = httpResp.getWriter(); DevTools.debugHtml(w, context, e); w.flush(); context.responseComplete(); } } else { if ((e instanceof RuntimeException)) throw ((RuntimeException)e); if ((e instanceof IOException)) { throw ((IOException)e); } throw new FacesException(e.getMessage(), e); } } protected void handleFaceletNotFound(FacesContext context, String viewId) throws FacesException, IOException { String actualId = getActionURL(context, viewId); Object respObj = context.getExternalContext().getResponse(); if ((respObj instanceof HttpServletResponse)) { HttpServletResponse respHttp = (HttpServletResponse)respObj; respHttp.sendError(404, actualId); context.responseComplete(); } } private boolean handledByFacelets(String viewId) { if ((this.extensionsArray == null) && (this.prefixesArray == null)) { return true; } if (this.extensionsArray != null) { for (int i = 0; i < this.extensionsArray.length; i++) { String extension = this.extensionsArray[i]; if (viewId.endsWith(extension)) { return true; } } } if (this.prefixesArray != null) { for (int i = 0; i < this.prefixesArray.length; i++) { String prefix = this.prefixesArray[i]; if (viewId.startsWith(prefix)) { return true; } } } return false; } public String getDefaultSuffix(FacesContext context) throws FacesException { if (this.defaultSuffix == null) { ExternalContext extCtx = context.getExternalContext(); String viewSuffix = extCtx.getInitParameter("javax.faces.DEFAULT_SUFFIX"); this.defaultSuffix = (viewSuffix != null ? viewSuffix : ".jsp"); } return this.defaultSuffix; } protected String getRenderedViewId(FacesContext context, String actionId) { ExternalContext extCtx = context.getExternalContext(); String viewId = actionId; if (extCtx.getRequestPathInfo() == null) { String viewSuffix = getDefaultSuffix(context); viewId = new StringBuffer(viewId).replace(viewId.lastIndexOf('.'), viewId.length(), viewSuffix).toString(); } if (log.isLoggable(Level.FINE)) { log.fine("ActionId -> ViewId: " + actionId + " -> " + viewId); } return viewId; } public void writeState(FacesContext context) throws IOException { if (handledByFacelets(context.getViewRoot().getViewId())) { StateWriter.getCurrentInstance().writingState(); context.getResponseWriter().write("~facelets.VIEW_STATE~"); } else { this.parent.writeState(context); } } public Locale calculateLocale(FacesContext context) { return this.parent.calculateLocale(context); } public String calculateRenderKitId(FacesContext context) { return this.parent.calculateRenderKitId(context); } public UIViewRoot createView(FacesContext context, String viewId) { if (UIDebug.debugRequest(context)) { return new UIViewRoot(); } return this.parent.createView(context, viewId); } public String getActionURL(FacesContext context, String viewId) { return this.parent.getActionURL(context, viewId); } public String getResourceURL(FacesContext context, String path) { return this.parent.getResourceURL(context, path); } private static boolean isPostback11(FacesContext context) { Object reqObject = context.getExternalContext().getRequest(); if ((reqObject instanceof HttpServletRequest)) { HttpServletRequest request = (HttpServletRequest)reqObject; String method = request.getMethod(); return ("POST".equals(method)) || ("PUT".equals(method)); } Map paramMap = context.getExternalContext().getRequestParameterMap(); return !paramMap.isEmpty(); } protected static class NullWriter extends Writer { static final NullWriter Instance = new NullWriter(); public void write(char[] buffer) { } public void write(char[] buffer, int off, int len) { } public void write(String str) { } public void write(int c) { } public void write(String str, int off, int len) { } public void close() { } public void flush() { } } }PhaseListener는 아래와 같은것들이 등록되어 있는데 이중에서 중요한것은 SeamPhaseListener이다. 13:53:40,494 INFO [ lifecycle: 80] [] listener.add> com.sun.faces.lifecycle.ELResolverInitPhaseListener 13:53:40,499 INFO [ lifecycle: 80] [] listener.add> com.sun.faces.renderkit.JsfJsResourcePhaseListener 13:53:40,509 INFO [ lifecycle: 80] [] listener.add> org.jboss.seam.debug.jsf.SeamDebugPhaseListener 13:53:40,517 INFO [ lifecycle: 80] [] listener.add> org.jboss.seam.jsf.SeamPhaseListener 13:53:40,522 INFO [ lifecycle: 80] [] listener.add> org.jboss.seam.document.DocumentStorePhaseListener 13:53:40,525 INFO [ lifecycle: 80] [] listener.add> org.ajax4jsf.event.AjaxPhaseListener 13:53:40,534 INFO [ lifecycle: 80] [] listener.add> org.ajax4jsf.event.InitPhaseListener 13:53:40,539 INFO [ lifecycle: 80] [] listener.add> org.richfaces.component.FileUploadPhaselistener
/* * JBoss, Home of Professional Open Source * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.seam.jsf; import static javax.faces.event.PhaseId.ANY_PHASE; import static javax.faces.event.PhaseId.INVOKE_APPLICATION; import static javax.faces.event.PhaseId.PROCESS_VALIDATIONS; import static javax.faces.event.PhaseId.RENDER_RESPONSE; import static javax.faces.event.PhaseId.RESTORE_VIEW; import static org.jboss.seam.transaction.Transaction.TRANSACTION_FAILED; import java.lang.reflect.Method; import java.util.Map; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.servlet.http.HttpServletRequest; import org.jboss.seam.Seam; import org.jboss.seam.contexts.Context; import org.jboss.seam.contexts.Contexts; import org.jboss.seam.contexts.FacesLifecycle; import org.jboss.seam.core.ConversationPropagation; import org.jboss.seam.core.Events; import org.jboss.seam.core.Init; import org.jboss.seam.core.Manager; import org.jboss.seam.exception.Exceptions; import org.jboss.seam.faces.FacesManager; import org.jboss.seam.faces.FacesMessages; import org.jboss.seam.faces.FacesPage; import org.jboss.seam.faces.Switcher; import org.jboss.seam.faces.Validation; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; import org.jboss.seam.navigation.Pages; import org.jboss.seam.pageflow.Pageflow; import org.jboss.seam.persistence.PersistenceContexts; import org.jboss.seam.transaction.Transaction; import org.jboss.seam.transaction.UserTransaction; import org.jboss.seam.util.Reflections; import org.jboss.seam.web.ServletContexts; /** * Manages the Seam contexts associated with a JSF request * throughout the lifecycle of the request. Performs * transaction demarcation when Seam transaction management * is enabled. Hacks the JSF lifecyle to provide page * actions and page parameters. * * @author Gavin King */ public class SeamPhaseListener implements PhaseListener { private static final long serialVersionUID = -9127555729455066493L; private static final LogProvider log = Logging.getLogProvider(SeamPhaseListener.class); private static boolean exists = false; private static final Method SET_RENDER_PARAMETER; private static final Class ACTION_RESPONSE; private static final Class PORTLET_REQUEST; static { Method method = null; Class actionResponseClass = null; Class portletRequestClass = null; try { Class[] parameterTypes = { String.class, String.class }; actionResponseClass = Class.forName("javax.portlet.ActionResponse"); portletRequestClass = Class.forName("javax.portlet.PortletRequest"); method = actionResponseClass.getMethod("setRenderParameter", parameterTypes); } catch (Exception e) {} SET_RENDER_PARAMETER = method; ACTION_RESPONSE = actionResponseClass; PORTLET_REQUEST = portletRequestClass; } public SeamPhaseListener() { if (exists) { log.warn("There should only be one Seam phase listener per application"); } exists=true; } public PhaseId getPhaseId() { return ANY_PHASE; } public void beforePhase(PhaseEvent event) { log.trace( "before phase: " + event.getPhaseId() ); FacesLifecycle.setPhaseId( event.getPhaseId() ); try { if ( isPortletRequest(event) ) { beforePortletPhase(event); } else { beforeServletPhase(event); } raiseEventsBeforePhase(event); } catch (Exception e) { try { Exceptions.instance().handle(e); } catch (Exception ehe) { log.error("swallowing exception", e); } } } private void beforeServletPhase(PhaseEvent event) { if ( event.getPhaseId() == RESTORE_VIEW ) { beforeRestoreView( event.getFacesContext() ); ServletContexts.instance().setRequest((HttpServletRequest) event.getFacesContext().getExternalContext().getRequest()); } handleTransactionsBeforePhase(event); if ( event.getPhaseId() == RENDER_RESPONSE ) { beforeRenderResponse( event.getFacesContext() ); } } private void beforePortletPhase(PhaseEvent event) { FacesContext facesContext = event.getFacesContext(); boolean notInitialised=false; if ( event.getPhaseId() == RESTORE_VIEW ) { beforeRestoreView(facesContext); } if ( event.getPhaseId() == RENDER_RESPONSE && !Contexts.isApplicationContextActive() ) { beforeRestoreView(facesContext); notInitialised = true; } //delegate to subclass: handleTransactionsBeforePhase(event); if (event.getPhaseId() == RENDER_RESPONSE) { if (notInitialised) { afterRestoreView(facesContext); } beforeRenderResponse(event.getFacesContext()); } } public void afterPhase(PhaseEvent event) { log.trace( "after phase: " + event.getPhaseId() ); try { raiseEventsAfterPhase(event); if ( isPortletRequest(event) ) { afterPortletPhase(event); } else { afterServletPhase(event); } } catch (Exception e) { log.warn("uncaught exception, passing to exception handler", e); try { Exceptions.instance().handle(e); // A redirect occurred inside the error handler, and we are in after // phase, so we need to clean up now as there are no more after // phases to be run if ( event.getFacesContext().getResponseComplete() ) { afterResponseComplete(event.getFacesContext()); } } catch (Exception ehe) { log.error("swallowing exception", e); } } FacesLifecycle.clearPhaseId(); } private void afterServletPhase(PhaseEvent event) { FacesContext facesContext = event.getFacesContext(); if ( event.getPhaseId() == RESTORE_VIEW ) { afterRestoreView(facesContext); } else if ( event.getPhaseId() == INVOKE_APPLICATION ) { afterInvokeApplication(); } else if ( event.getPhaseId() == PROCESS_VALIDATIONS ) { afterProcessValidations(facesContext); } //has to happen after, since restoreAnyConversationContext() //can add messages FacesMessages.afterPhase(); handleTransactionsAfterPhase(event); if ( event.getPhaseId() == RENDER_RESPONSE ) { afterRenderResponse(facesContext); } else if ( facesContext.getResponseComplete() ) { afterResponseComplete(facesContext); } } private void afterPortletPhase(PhaseEvent event) { Object portletPhase = event.getFacesContext().getExternalContext().getRequestMap().get("javax.portlet.faces.phase"); if (event.getPhaseId() == RESTORE_VIEW) { afterRestoreView(event.getFacesContext()); } else if (event.getPhaseId() == INVOKE_APPLICATION) { afterInvokeApplication(); } else if (event.getPhaseId() == PROCESS_VALIDATIONS) { afterProcessValidations(event.getFacesContext()); } FacesMessages.afterPhase(); // delegate to subclass: handleTransactionsAfterPhase(event); if (event.getPhaseId() == RENDER_RESPONSE) { // writeConversationIdToResponse( // facesContext.getExternalContext().getResponse() ); afterRenderResponse(event.getFacesContext()); } else if ( (null != portletPhase && "ActionPhase".equals(portletPhase.toString()) ) && (event.getPhaseId() == INVOKE_APPLICATION || event.getFacesContext().getRenderResponse() || event.getFacesContext().getResponseComplete()) ) { Manager.instance().beforeRedirect(); if ( Manager.instance().isLongRunningConversation() ) { setPortletRenderParameter( event.getFacesContext().getExternalContext().getResponse(), Manager.instance().getConversationIdParameter(), Manager.instance().getCurrentConversationId() ); } afterResponseComplete( event.getFacesContext() ); } } private static void setPortletRenderParameter(Object response, String conversationIdParameter, String conversationId) { if ( ACTION_RESPONSE.isInstance(response) ) { Reflections.invokeAndWrap(SET_RENDER_PARAMETER, response, conversationIdParameter, conversationId); } } private static boolean isPortletRequest(PhaseEvent event) { return PORTLET_REQUEST!=null && PORTLET_REQUEST.isInstance( event.getFacesContext().getExternalContext().getRequest() ); } public void handleTransactionsBeforePhase(PhaseEvent event) { if ( Init.instance().isTransactionManagementEnabled() ) { PhaseId phaseId = event.getPhaseId(); boolean beginTran = phaseId == PhaseId.RENDER_RESPONSE || phaseId == ( Transaction.instance().isConversationContextRequired() ? PhaseId.APPLY_REQUEST_VALUES : PhaseId.RESTORE_VIEW ); //( phaseId == PhaseId.RENDER_RESPONSE && !Init.instance().isClientSideConversations() ); if (beginTran) { begin(phaseId); } } } public void handleTransactionsAfterPhase(PhaseEvent event) { if ( Init.instance().isTransactionManagementEnabled() ) { PhaseId phaseId = event.getPhaseId(); boolean commitTran = phaseId == PhaseId.INVOKE_APPLICATION || event.getFacesContext().getRenderResponse() || //TODO: no need to commit the tx if we failed to restore the view event.getFacesContext().getResponseComplete() || phaseId == PhaseId.RENDER_RESPONSE; //( phaseId == PhaseId.RENDER_RESPONSE && !Init.instance().isClientSideConversations() ); if (commitTran) { commitOrRollback(phaseId); //we commit before destroying contexts, cos the contexts have the PC in them } } } protected void handleTransactionsAfterPageActions(FacesContext facesContext) { if ( Init.instance().isTransactionManagementEnabled() ) { commitOrRollback("after invoking page actions"); if ( !facesContext.getResponseComplete() ) { begin("before continuing render"); } } } protected void afterInvokeApplication() { if ( Init.instance().isTransactionManagementEnabled() ) { raiseTransactionFailedEvent(); } } protected void afterProcessValidations(FacesContext facesContext) { Validation.instance().afterProcessValidations(facesContext); } /** * Set up the Seam contexts, except for the conversation * context */ protected void beforeRestoreView(FacesContext facesContext) { FacesLifecycle.beginRequest( facesContext.getExternalContext() ); } /** * Restore the page and conversation contexts during a JSF request */ protected void afterRestoreView(FacesContext facesContext) { FacesLifecycle.resumePage(); Map parameters = facesContext.getExternalContext().getRequestParameterMap(); ConversationPropagation.instance().restoreConversationId(parameters); boolean conversationFound = Manager.instance().restoreConversation(); FacesLifecycle.resumeConversation( facesContext.getExternalContext() ); postRestorePage(facesContext, parameters, conversationFound); } public void raiseEventsBeforePhase(PhaseEvent event) { if ( Contexts.isApplicationContextActive() ) { Events.instance().raiseEvent("org.jboss.seam.beforePhase", event); } /*if ( Contexts.isConversationContextActive() && Init.instance().isJbpmInstalled() && Pageflow.instance().isInProcess() ) { String name; PhaseId phaseId = event.getPhaseId(); if ( phaseId == PhaseId.PROCESS_VALIDATIONS ) { name = "process-validations"; } else if ( phaseId == PhaseId.UPDATE_MODEL_VALUES ) { name = "update-model-values"; } else if ( phaseId == PhaseId.INVOKE_APPLICATION ) { name = "invoke-application"; } else if ( phaseId == PhaseId.RENDER_RESPONSE ) { name = "render-response"; } else { return; } Pageflow.instance().processEvents(name); }*/ } public void raiseEventsAfterPhase(PhaseEvent event) { if ( Contexts.isApplicationContextActive() ) { Events.instance().raiseEvent("org.jboss.seam.afterPhase", event); } } /** * Raise an event so that an observer may add a faces message when Seam-managed transactions fail. */ protected void raiseTransactionFailedEvent() { try { UserTransaction tx = Transaction.instance(); if ( tx.isRolledBackOrMarkedRollback() ) { if (Events.exists()) Events.instance().raiseEvent(TRANSACTION_FAILED, tx.getStatus()); } } catch (Exception e) {} //swallow silently, not important } protected void beforeRenderResponse(FacesContext facesContext) { if ( Contexts.isPageContextActive() ) { Context pageContext = Contexts.getPageContext(); //after every time that the view may have changed, //we need to flush the page context, since the //attribute map is being discarder pageContext.flush(); //force refresh of the conversation lists (they are kept in PAGE context) pageContext.remove(Seam.getComponentName(Switcher.class)); pageContext.remove("org.jboss.seam.core.conversationList"); pageContext.remove("org.jboss.seam.core.conversationStack"); } preRenderPage(facesContext); if ( facesContext.getResponseComplete() ) { //workaround for a bug in MyFaces prior to 1.1.3 if ( Init.instance().isMyFacesLifecycleBug() ) { FacesLifecycle.endRequest( facesContext.getExternalContext() ); } } else //if the page actions did not call responseComplete() { FacesMessages.instance().beforeRenderResponse(); //do this both before and after render, since conversations //and pageflows can begin during render FacesManager.instance().prepareBackswitch(facesContext); } FacesPage.instance().storeConversation(); FacesPage.instance().storePageflow(); PersistenceContexts persistenceContexts = PersistenceContexts.instance(); if (persistenceContexts != null) { persistenceContexts.beforeRender(); } } protected void afterRenderResponse(FacesContext facesContext) { //do this both before and after render, since conversations //and pageflows can begin during render FacesManager.instance().prepareBackswitch(facesContext); PersistenceContexts persistenceContexts = PersistenceContexts.instance(); if (persistenceContexts != null) { persistenceContexts.afterRender(); } ExternalContext externalContext = facesContext.getExternalContext(); Manager.instance().endRequest( externalContext.getSessionMap() ); FacesLifecycle.endRequest(externalContext); } protected void afterResponseComplete(FacesContext facesContext) { //responseComplete() was called by one of the other phases, //so we will never get to the RENDER_RESPONSE phase //Note: we can't call Manager.instance().beforeRedirect() here, //since a redirect is not the only reason for a responseComplete ExternalContext externalContext = facesContext.getExternalContext(); Manager.instance().endRequest( externalContext.getSessionMap() ); FacesLifecycle.endRequest( facesContext.getExternalContext() ); } private void postRestorePage(FacesContext facesContext, Map parameters, boolean conversationFound) { if ( !Pages.isDebugPage() ) { // Only redirect to no-conversation-view if a login redirect isn't required if (!conversationFound && !Pages.instance().isLoginRedirectRequired(facesContext)) { Pages.instance().redirectToNoConversationView(); } Manager.instance().handleConversationPropagation(parameters); if ( Init.instance().isJbpmInstalled() && !isExceptionHandlerRedirect() ) { Pageflow.instance().validatePageflow(facesContext); } Pages.instance().postRestore(facesContext); } } private boolean preRenderPage(FacesContext facesContext) { if ( Pages.isDebugPage() ) { return false; } else { FacesLifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION); boolean actionsWereCalled = false; try { actionsWereCalled = Pages.instance().preRender(facesContext); return actionsWereCalled; } finally { FacesLifecycle.setPhaseId(PhaseId.RENDER_RESPONSE); if (actionsWereCalled) { FacesMessages.afterPhase(); handleTransactionsAfterPageActions(facesContext); //TODO: does it really belong in the finally? } } } } private boolean isExceptionHandlerRedirect() { return Contexts.getConversationContext().isSet("org.jboss.seam.handledException"); } void begin(PhaseId phaseId) { begin("prior to phase: " + phaseId); } void begin(String phaseString) { try { if ( !Transaction.instance().isActiveOrMarkedRollback() ) { log.debug("beginning transaction " + phaseString); Transaction.instance().begin(); } } catch (Exception e) { throw new IllegalStateException("Could not start transaction", e); } } void commitOrRollback(PhaseId phaseId) { commitOrRollback("after phase: " + phaseId); } void commitOrRollback(String phaseString) { try { if (Transaction.instance().isActive()) { try { log.debug("committing transaction " + phaseString); Transaction.instance().commit(); } catch (IllegalStateException e) { log.warn("TX commit failed with illegal state exception. This may be " + "because the tx timed out and was rolled back in the background.", e); } } else if ( Transaction.instance().isRolledBackOrMarkedRollback()) { log.debug("rolling back transaction " + phaseString); Transaction.instance().rollback(); } } catch (Exception e) { throw new IllegalStateException("Could not commit transaction", e); } } }]]>