/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.jsf.context; import com.caucho.util.L10N; import java.util.*; import java.util.logging.*; import javax.el.*; import javax.faces.*; import javax.faces.event.PhaseId; import javax.faces.application.*; import javax.faces.context.*; import javax.faces.component.*; import javax.faces.render.*; import javax.servlet.*; import javax.servlet.http.*; public class ServletFacesContextImpl extends FacesContext { private static final Logger log = Logger.getLogger(ServletFacesContextImpl.class.getName()); private static final L10N L = new L10N(ServletFacesContextImpl.class); private static final Iterator<FacesMessage> NO_MESSAGES = new NoMessagesIterator(); private static final Iterator<String> NO_IDS = new NoIdsIterator(); private FacesContextFactoryImpl _factory; private ServletContext _webApp; private HttpServletRequest _request; private HttpServletResponse _response; private ExternalContext _externalContext; private FacesELContext _elContext; private boolean _isResponseComplete; private boolean _isRenderResponse; private UIViewRoot _uiViewRoot; private Object []_messages; private final Object _messagesLock = new Object(); private int _messageModCount = 0; private ResponseWriter _responseWriter; private ResponseStream _responseStream; private boolean _isClosed; private HashMap<Object, Object> _attributes; protected ServletFacesContextImpl(FacesContextFactoryImpl factory, ServletContext webApp, HttpServletRequest request, HttpServletResponse response) { _factory = factory; _webApp = webApp; _request = request; _response = response; setCurrentInstance(this); } public Application getApplication() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); return _factory.getApplication(); } public ExternalContext getExternalContext() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); if (_externalContext == null) { _externalContext = new ServletExternalContext(_webApp, _request, _response); } return _externalContext; } public RenderKit getRenderKit() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); UIViewRoot viewRoot = getViewRoot(); if (viewRoot == null) return null; String renderKitId = viewRoot.getRenderKitId(); if (renderKitId == null) return null; RenderKitFactory factory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); return factory.getRenderKit(this, renderKitId); } public ResponseStream getResponseStream() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); return _responseStream; } public void setResponseStream(ResponseStream responseStream) { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); _responseStream = responseStream; } public ResponseWriter getResponseWriter() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); return _responseWriter; } public void setResponseWriter(ResponseWriter writer) { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); if (writer == null) throw new NullPointerException(L.l("ResponseWriter object can not be null")); _responseWriter = writer; } /** * Returns the root of the UI component tree. */ public UIViewRoot getViewRoot() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); return _uiViewRoot; /* if (_uiViewRoot == null) { _uiViewRoot = getApplication().getViewHandler().createView(this, null); } return _uiViewRoot; */ } /** * Sets the root of the UI component tree. */ public void setViewRoot(UIViewRoot root) { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); if (root == null) throw new NullPointerException(); _uiViewRoot = root; } /** * If true the facelet will skip to the render phase. */ @Override public boolean getRenderResponse() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); return _isRenderResponse; } /** * Ask the lifecycle to skip to the render phase. */ @Override public void renderResponse() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); _isRenderResponse = true; } /** * Return true if the lifecycle should skip the response phase. */ @Override public boolean getResponseComplete() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); return _isResponseComplete; } /** * Ask the lifecycle to skip the response phase. */ @Override public void responseComplete() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); _isResponseComplete = true; } public void addMessage(String clientId, FacesMessage message) { if (_isClosed) throw new IllegalStateException("FacesContext is closed"); if (message == null) throw new NullPointerException(); if (log.isLoggable(Level.FINE)) log.fine("FacesContext.addMessage " + clientId + " " + message); synchronized (_messagesLock) { if (_messages == null) { _messages = new Object[]{clientId, message}; } else { Object []newMessages = new Object[_messages.length + 2]; System.arraycopy(_messages, 0, newMessages, 0, _messages.length); newMessages[newMessages.length - 2] = clientId; newMessages[newMessages.length - 1] = message; _messages = newMessages; } _messageModCount++; } } public Iterator<String> getClientIdsWithMessages() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); synchronized (_messagesLock) { if (_messages == null) return NO_IDS; LinkedHashSet<String> ids = new LinkedHashSet<String>(); for (int i = 0; i < _messages.length / 2; i++) { Object id = _messages[i * 2]; ids.add((String) id); } return ids.iterator(); } } public FacesMessage.Severity getMaximumSeverity() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); synchronized (_messagesLock) { if (_messages == null) return null; FacesMessage.Severity result = null; for (int i = 0; i < _messages.length / 2; i++) { FacesMessage msg = (FacesMessage) _messages[i * 2 + 1]; if (result == null || msg.getSeverity().compareTo(result) > 0) result = msg.getSeverity(); } return result; } } public Iterator<FacesMessage> getMessages() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); synchronized (_messagesLock) { if (_messages == null) return NO_MESSAGES; return new Iterator<FacesMessage>() { private int _cursor = 1; private int _expectedModCount = _messageModCount; public boolean hasNext() { synchronized (_messagesLock) { return (_cursor < _messages.length); } } public FacesMessage next() { synchronized (_messagesLock) { if (_expectedModCount != _messageModCount) throw new ConcurrentModificationException(); int idx = _cursor; _cursor = _cursor + 2; try { return (FacesMessage) _messages[idx]; } catch (ArrayIndexOutOfBoundsException e) { throw new NoSuchElementException(); } } } public void remove() { synchronized (_messagesLock) { if (_expectedModCount != _messageModCount) throw new ConcurrentModificationException(); Object []newMessages = new Object[_messages.length - 2]; System.arraycopy(_messages, 0, newMessages, 0, _cursor - 3); System.arraycopy(_messages, _cursor - 1, newMessages, _cursor - 3, _messages.length - _cursor + 1); _messages = newMessages; _cursor = _cursor - 2; _expectedModCount++; _messageModCount = _expectedModCount; } } }; } } public Iterator<FacesMessage> getMessages(final String clientId) { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); synchronized (_messagesLock) { if (_messages == null) return NO_MESSAGES; return new Iterator<FacesMessage>() { private int _expectedModCount = _messageModCount; private int _cursor = 0; public boolean hasNext() { for (int i = _cursor; i < _messages.length / 2; i++) { int idx = i * 2; if ((clientId == null && _messages[idx] == null) || (clientId != null && clientId.equals(_messages[idx]))) return true; } return false; } public FacesMessage next() { synchronized (_messagesLock) { if (_expectedModCount != _messageModCount) throw new ConcurrentModificationException(); for (int i = _cursor; i < _messages.length / 2; i++) { int idx = i * 2; if ((clientId == null && _messages[idx] == null) || (clientId != null && clientId.equals(_messages[idx]))) { _cursor = i + 1; FacesMessage result = (FacesMessage) _messages[idx + 1]; return result; } } throw new NoSuchElementException(); } } public void remove() { synchronized (_messagesLock) { if (_expectedModCount != _messageModCount) throw new ConcurrentModificationException(); Object []newMessages = new Object[_messages.length - 2]; System.arraycopy(_messages, 0, newMessages, 0, (_cursor - 1) * 2); System.arraycopy(_messages, _cursor * 2, newMessages, (_cursor - 1) * 2, _messages.length - _cursor * 2); _messages = newMessages; _cursor = _cursor - 1; _expectedModCount++; _messageModCount = _expectedModCount; } } }; } } /** * @Since 1.2 */ @Override public ELContext getELContext() { if (_isClosed) throw new IllegalStateException(getClass().getName() + " is closed"); if (_elContext == null) { _elContext = new FacesELContext(this, getApplication().getELResolver()); _elContext.putContext(FacesContext.class, this); } return _elContext; } public void release() { _isClosed = true; if (_attributes != null) { _attributes.clear(); _attributes = null; } _messages = null; FacesContext.setCurrentInstance(null); } public Map<Object, Object> getAttributes() { if (_isClosed) throw new IllegalStateException(); if (_attributes == null) _attributes = new HashMap<Object, Object>(); return _attributes; } public String toString() { return "ServletFacesContextImpl[]"; } private static class NoIdsIterator implements Iterator<String> { public boolean hasNext() { return false; } public String next() { throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException("unimplemented"); } } private static class NoMessagesIterator implements Iterator<FacesMessage> { public boolean hasNext() { return false; } public FacesMessage next() { throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException("unimplemented"); } } }