/* * JBoss, Home of Professional Open Source * Copyright 2009, Red Hat Middleware LLC, and individual contributors * 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. * * $Id$ */ package org.jboss.test.faces.stub.faces; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; 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.UINamingContainer; 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.event.PhaseId; import javax.faces.render.RenderKit; import javax.faces.render.RenderKitFactory; /** * @author Gavin King * @author Thomas Heute * @author Dan Allen */ public class StubFacesContext extends FacesContext { private Application application; private UIViewRoot viewRoot; /** * Store mapping of clientId to ArrayList of FacesMessage instances. The * null key is used to represent FacesMessage instances that are not * associated with a clientId instance. */ private final Map<String, List<FacesMessage>> messages = new LinkedHashMap<String, List<FacesMessage>>(); private Map<Object, Object> attributes = new HashMap<Object, Object>(); private ExternalContext externalContext; private ResponseWriter responseWriter; private RenderKitFactory renderKitFactory; private ELContext elContext; private boolean renderResponse; private boolean responseComplete; private PhaseId currentPhaseId; private boolean postback; public StubFacesContext() { attributes.put(UINamingContainer.SEPARATOR_CHAR_PARAM_NAME, ':'); } public StubFacesContext(boolean postback) { this(); this.postback = postback; } public StubFacesContext(Application application) { this(); this.application = application; } public StubFacesContext(Application application, boolean postback) { this(); this.application = application; this.postback = postback; } public StubFacesContext(ExternalContext externalContext, Application application) { this(); this.externalContext = externalContext; this.application = application; } // Create a StubFacesContext using a ApplicationFactory to get the // Application public StubFacesContext(ExternalContext externalContext) { this(); this.application = ((ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY)).getApplication(); this.renderKitFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); this.externalContext = externalContext; } @Override public Application getApplication() { return application; } @Override public Iterator getClientIdsWithMessages() { return messages.keySet().iterator(); } @Override public ExternalContext getExternalContext() { return externalContext; } @Override public Severity getMaximumSeverity() { Severity max = null; for (List<FacesMessage> messagesForKey : messages.values()) { for (FacesMessage msg : messagesForKey) { if (msg.getSeverity() == FacesMessage.SEVERITY_FATAL) { return FacesMessage.SEVERITY_FATAL; } else if (max == null || msg.getSeverity().compareTo(max) > 0) { max = msg.getSeverity(); } } } return max; } @Override public Iterator getMessages() { return messages.size() > 0 ? new FacesMessagesIterator(messages) : Collections.<FacesMessage>emptyList().iterator(); } @Override public Iterator getMessages(String clientId) { List<FacesMessage> messagesForKey = messages.get(clientId); return messagesForKey != null ? messagesForKey.iterator() : Collections.<FacesMessage>emptyList().iterator(); } @Override public List<FacesMessage> getMessageList() { List<FacesMessage> aggregatedMessages = new ArrayList<FacesMessage>(); for (List<FacesMessage> messagesForKey : messages.values()) { aggregatedMessages.addAll(messagesForKey); } return Collections.unmodifiableList(aggregatedMessages); } @Override public List<FacesMessage> getMessageList(String clientId) { return messages.containsKey(clientId) ? Collections.unmodifiableList(messages.get(clientId)) : Collections.<FacesMessage>emptyList(); } @Override public Map<Object, Object> getAttributes() { return attributes; } @Override public RenderKit getRenderKit() { if (getViewRoot() == null || getViewRoot().getRenderKitId() == null) { return StubRenderKit.INSTANCE; } else { return renderKitFactory.getRenderKit(this, getViewRoot().getRenderKitId()); } } @Override public boolean getRenderResponse() { return renderResponse; } @Override public boolean getResponseComplete() { return responseComplete; } @Override public ResponseStream getResponseStream() { throw new UnsupportedOperationException(); } @Override public void setResponseStream(ResponseStream stream) { throw new UnsupportedOperationException(); } @Override public ResponseWriter getResponseWriter() { return responseWriter; } @Override public void setResponseWriter(ResponseWriter writer) { responseWriter = writer; } @Override public UIViewRoot getViewRoot() { return viewRoot; } @Override public void setViewRoot(UIViewRoot vr) { viewRoot = vr; } @Override public void addMessage(String clientId, FacesMessage msg) { if (!messages.containsKey(clientId)) { List<FacesMessage> messagesForKey = new ArrayList<FacesMessage>(1); messagesForKey.add(msg); messages.put(clientId, messagesForKey); } else { messages.get(clientId).add(msg); } } @Override public void release() { setCurrentInstance(null); StubFacesContextFactory.setFacesContext(null); } @Override public void renderResponse() { renderResponse = true; } @Override public void responseComplete() { responseComplete = true; } @Override public PhaseId getCurrentPhaseId() { return currentPhaseId; } @Override public void setCurrentPhaseId(PhaseId phaseId) { this.currentPhaseId = phaseId; } @Override public boolean isPostback() { return postback; } public void setPostback(boolean postback) { this.postback = postback; } public StubFacesContext setCurrent() { setCurrentInstance(this); StubFacesContextFactory.setFacesContext(this); return this; } public StubFacesContext createViewRoot() { viewRoot = new UIViewRoot(); viewRoot.setRenderKitId(getApplication().getViewHandler().calculateRenderKitId(this)); return this; } @Override public ELContext getELContext() { /* if (elContext == null) { elContext = EL.createELContext(EL.createELContext(), getApplication().getELResolver()); elContext.putContext(FacesContext.class, this); } return elContext; */ return elContext; } public void setELContext(ELContext elContext) { this.elContext = elContext; } private static final class FacesMessagesIterator implements Iterator<FacesMessage> { private Map<String, List<FacesMessage>> messages; private int keyIndex = -1; private int numKeys; private Iterator<FacesMessage> messagesForKey; private Iterator<String> keys; FacesMessagesIterator(Map<String, List<FacesMessage>> messages) { this.messages = messages; numKeys = messages.size(); keys = messages.keySet().iterator(); } public boolean hasNext() { if (keyIndex == -1) { keyIndex++; messagesForKey = messages.get(keys.next()).iterator(); } while (!messagesForKey.hasNext()) { keyIndex++; if ((keyIndex) < numKeys) { messagesForKey = messages.get(keys.next()).iterator(); } else { return false; } } return messagesForKey.hasNext(); } public FacesMessage next() { if (keyIndex >= numKeys) { throw new NoSuchElementException(); } if (messagesForKey != null && messagesForKey.hasNext()) { return messagesForKey.next(); } else { if (!this.hasNext()) { throw new NoSuchElementException(); } else { return messagesForKey.next(); } } } public void remove() { if (keyIndex == -1) { throw new IllegalStateException(); } messagesForKey.remove(); } } }