001 package org.apache.myfaces.tobago.component; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one or more 005 * contributor license agreements. See the NOTICE file distributed with 006 * this work for additional information regarding copyright ownership. 007 * The ASF licenses this file to You under the Apache License, Version 2.0 008 * (the "License"); you may not use this file except in compliance with 009 * the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020 import org.apache.myfaces.tobago.context.ClientProperties; 021 import org.apache.myfaces.tobago.context.ResourceManagerImpl; 022 import org.apache.commons.logging.Log; 023 import org.apache.commons.logging.LogFactory; 024 //import org.apache.myfaces.tobago.util.FacesVersion; 025 026 import javax.faces.component.UIComponent; 027 //import javax.faces.context.ExternalContext; 028 import javax.faces.context.FacesContext; 029 import javax.faces.event.AbortProcessingException; 030 import javax.faces.event.FacesEvent; 031 import javax.faces.event.PhaseId; 032 import javax.faces.FacesException; 033 import java.util.ArrayList; 034 import java.util.List; 035 import java.util.ListIterator; 036 import java.util.Locale; 037 import java.util.Map; 038 039 /* 040 * User: weber 041 * Date: Jun 13, 2005 042 * Time: 5:19:31 PM 043 */ 044 public class UIViewRoot extends javax.faces.component.UIViewRoot { 045 046 private static final Log LOG = LogFactory.getLog(UIViewRoot.class); 047 private static final String EVENT_LIST_KEY = UIViewRoot.class.getName() + ".EventList"; 048 049 private ResourceManagerImpl.CacheKey rendererCacheKey; 050 051 private ClientProperties clientProperties; 052 053 //private int nextUniqueId; 054 055 public static final int ANY_PHASE_ORDINAL = PhaseId.ANY_PHASE.getOrdinal(); 056 057 058 /** 059 * <p>Create a new {@link UIViewRoot} instance with default property 060 * values.</p> 061 */ 062 public UIViewRoot() { 063 super(); 064 updateRendererCachePrefix(); 065 } 066 067 public ClientProperties getClientProperties() { 068 return clientProperties; 069 } 070 071 public void setClientProperties(final ClientProperties clientProperties) { 072 this.clientProperties = clientProperties; 073 updateRendererCachePrefix(); 074 } 075 076 public void setLocale(final Locale locale) { 077 super.setLocale(locale); 078 updateRendererCachePrefix(); 079 } 080 081 public ResourceManagerImpl.CacheKey getRendererCacheKey() { 082 return rendererCacheKey; 083 } 084 085 086 public void updateRendererCachePrefix() { 087 rendererCacheKey = ResourceManagerImpl.getRendererCacheKey( 088 clientProperties != null ? clientProperties.getId() : "null", getLocale()); 089 // LOG.info("updateRendererCachePrefix :" + rendererCachePrefix); 090 } 091 092 public void broadcastEventsForPhase(final FacesContext context, final PhaseId phaseId) { 093 broadcastForPhase(phaseId); 094 if (context.getRenderResponse() || context.getResponseComplete()) { 095 clearEvents(context); 096 } 097 } 098 099 // ----------------------------------------------------------------------------- 100 // ----------------------------------------------------------------------------- 101 // 102 // The following code is copied from myfaces implementation! 103 // In suns jsf-api 1.1.01 are the events not cleared if renderResponse is true 104 // after processUpdates, seems to be a bug. This is fixed at least in 105 // Nightly Snapshot from 15.08.2005, but not in stable yet. 106 // Events are private member of UIViewRoot, so we have to copy anny code 107 // accessing them. 108 // 109 // TODO: remove if fixed in stable release! 110 111 public void queueEvent(final FacesEvent event) { 112 if (event == null) { 113 throw new NullPointerException("event"); 114 } 115 getEvents(FacesContext.getCurrentInstance(), true).add(event); 116 } 117 118 119 private void broadcastForPhase(final PhaseId phaseId) { 120 List<FacesEvent> events = getEvents(FacesContext.getCurrentInstance(), false); 121 if (events == null) { 122 return; 123 } 124 125 boolean abort = false; 126 127 int phaseIdOrdinal = phaseId.getOrdinal(); 128 for (ListIterator listiterator = events.listIterator(); listiterator.hasNext();) { 129 FacesEvent event = (FacesEvent) listiterator.next(); 130 int ordinal = event.getPhaseId().getOrdinal(); 131 if (ordinal == ANY_PHASE_ORDINAL 132 || ordinal == phaseIdOrdinal) { 133 UIComponent source = event.getComponent(); 134 try { 135 source.broadcast(event); 136 } catch (FacesException e) { 137 Throwable fe = e; 138 while (fe != null) { 139 if (fe instanceof AbortProcessingException) { 140 if (LOG.isTraceEnabled()) { 141 LOG.trace("AbortProcessingException caught!"); 142 } 143 // abort event processing 144 // Page 3-30 of JSF 1.1 spec: "Throw an AbortProcessingException, to tell the JSF implementation 145 // that no further broadcast of this event, or any further events, should take place." 146 abort = true; 147 break; 148 } 149 fe = fe.getCause(); 150 } 151 if (!abort) { 152 throw e; 153 } else { 154 break; 155 } 156 } finally { 157 listiterator.remove(); 158 } 159 } 160 } 161 162 if (abort) { 163 // TODO: abort processing of any event of any phase or just of any event of the current phase??? 164 clearEvents(FacesContext.getCurrentInstance()); 165 } 166 } 167 168 169 private void clearEvents(final FacesContext context) { 170 context.getExternalContext().getRequestMap().remove(EVENT_LIST_KEY); 171 } 172 173 174 public void processDecodes(final FacesContext context) { 175 if (context == null) { 176 throw new NullPointerException("context"); 177 } 178 super.processDecodes(context); 179 broadcastForPhase(PhaseId.APPLY_REQUEST_VALUES); 180 if (context.getRenderResponse() || context.getResponseComplete()) { 181 clearEvents(context); 182 } 183 } 184 185 public void processValidators(final FacesContext context) { 186 if (context == null) { 187 throw new NullPointerException("context"); 188 } 189 super.processValidators(context); 190 broadcastForPhase(PhaseId.PROCESS_VALIDATIONS); 191 if (context.getRenderResponse() || context.getResponseComplete()) { 192 clearEvents(context); 193 } 194 } 195 196 public void processUpdates(final FacesContext context) { 197 if (context == null) { 198 throw new NullPointerException("context"); 199 } 200 super.processUpdates(context); 201 broadcastForPhase(PhaseId.UPDATE_MODEL_VALUES); 202 if (context.getRenderResponse() || context.getResponseComplete()) { 203 clearEvents(context); 204 } 205 } 206 207 public void processApplication(final FacesContext context) { 208 if (context == null) { 209 throw new NullPointerException("context"); 210 } 211 broadcastForPhase(PhaseId.INVOKE_APPLICATION); 212 if (context.getRenderResponse() || context.getResponseComplete()) { 213 clearEvents(context); 214 } 215 } 216 217 private List<FacesEvent> getEvents(final FacesContext context, boolean create) { 218 final Map requestMap = context.getExternalContext().getRequestMap(); 219 List<FacesEvent> events = (List<FacesEvent>) requestMap.get(EVENT_LIST_KEY); 220 if (events == null && create) { 221 events = new ArrayList<FacesEvent>(); 222 requestMap.put(EVENT_LIST_KEY, events); 223 } 224 return events; 225 } 226 227 /* 228 229 public Object saveState(FacesContext facesContext) { 230 if (FacesVersion.supports12()) { 231 return super.saveState(facesContext); 232 } else { 233 Object[] state = new Object[2]; 234 state[0] = super.saveState(facesContext); 235 state[1] = nextUniqueId; 236 return state; 237 } 238 } 239 240 public void restoreState(FacesContext facesContext, Object o) { 241 Object[] state = (Object[]) o; 242 super.restoreState(facesContext, state[0]); 243 if (!FacesVersion.supports12()) { 244 nextUniqueId = (Integer) state[1]; 245 } 246 } 247 248 public String createUniqueId() { 249 if (FacesVersion.supports12()) { 250 return super.createUniqueId(); 251 } else { 252 ExternalContext extCtx = FacesContext.getCurrentInstance().getExternalContext(); 253 return extCtx.encodeNamespace(UNIQUE_ID_PREFIX + nextUniqueId++); 254 } 255 } */ 256 257 }