/*
* 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();
}
}
}