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 025 import javax.faces.component.UIComponent; 026 import javax.faces.context.FacesContext; 027 import javax.faces.event.AbortProcessingException; 028 import javax.faces.event.FacesEvent; 029 import javax.faces.event.PhaseId; 030 import javax.faces.FacesException; 031 import java.util.ArrayList; 032 import java.util.ConcurrentModificationException; 033 import java.util.List; 034 import java.util.ListIterator; 035 import java.util.Locale; 036 037 /* 038 * User: weber 039 * Date: Jun 13, 2005 040 * Time: 5:19:31 PM 041 */ 042 public class UIViewRoot extends javax.faces.component.UIViewRoot { 043 044 private static final Log LOG = LogFactory.getLog(UIViewRoot.class); 045 046 private ResourceManagerImpl.CacheKey rendererCacheKey; 047 048 private ClientProperties clientProperties; 049 050 public static final int ANY_PHASE_ORDINAL = PhaseId.ANY_PHASE.getOrdinal(); 051 private List events = null; 052 053 054 /** 055 * <p>Create a new {@link UIViewRoot} instance with default property 056 * values.</p> 057 */ 058 public UIViewRoot() { 059 super(); 060 updateRendererCachePrefix(); 061 } 062 063 public ClientProperties getClientProperties() { 064 return clientProperties; 065 } 066 067 public void setClientProperties(ClientProperties clientProperties) { 068 this.clientProperties = clientProperties; 069 updateRendererCachePrefix(); 070 } 071 072 public void setLocale(Locale locale) { 073 super.setLocale(locale); 074 updateRendererCachePrefix(); 075 } 076 077 public ResourceManagerImpl.CacheKey getRendererCacheKey() { 078 return rendererCacheKey; 079 } 080 081 082 public void updateRendererCachePrefix() { 083 rendererCacheKey = ResourceManagerImpl.getRendererCacheKey( 084 clientProperties != null ? clientProperties.getId() : "null", getLocale()); 085 // LOG.info("updateRendererCachePrefix :" + rendererCachePrefix); 086 } 087 088 public void broadcastEventsForPhase(FacesContext context, PhaseId phaseId) { 089 broadcastForPhase(phaseId); 090 if (context.getRenderResponse() || context.getResponseComplete()) { 091 clearEvents(); 092 } 093 } 094 095 // ----------------------------------------------------------------------------- 096 // ----------------------------------------------------------------------------- 097 // 098 // The following code is copied from myfaces implementation! 099 // In suns jsf-api 1.1.01 are the events not cleared if renderResponse is true 100 // after processUpdates, seems to be a bug. This is fixed at least in 101 // Nightly Snapshot from 15.08.2005, but not in stable yet. 102 // Events are private member of UIViewRoot, so we have to copy anny code 103 // accessing them. 104 // 105 // TODO: remove if fixed in stable release! 106 107 public void queueEvent(FacesEvent event) { 108 if (event == null) { 109 throw new NullPointerException("event"); 110 } 111 if (events == null) { 112 events = new ArrayList(); 113 } 114 events.add(event); 115 } 116 117 118 private void broadcastForPhase(PhaseId phaseId) { 119 if (events == null) { 120 return; 121 } 122 123 boolean abort = false; 124 125 int phaseIdOrdinal = phaseId.getOrdinal(); 126 for (ListIterator listiterator = events.listIterator(); listiterator.hasNext();) { 127 FacesEvent event = (FacesEvent) listiterator.next(); 128 int ordinal = event.getPhaseId().getOrdinal(); 129 if (ordinal == ANY_PHASE_ORDINAL 130 || ordinal == phaseIdOrdinal) { 131 UIComponent source = event.getComponent(); 132 try { 133 source.broadcast(event); 134 } catch (FacesException e) { 135 Throwable fe = e; 136 while (fe != null) { 137 if (fe instanceof AbortProcessingException) { 138 if (LOG.isTraceEnabled()) { 139 LOG.trace("AbortProcessingException caught!"); 140 } 141 // abort event processing 142 // Page 3-30 of JSF 1.1 spec: "Throw an AbortProcessingException, to tell the JSF implementation 143 // that no further broadcast of this event, or any further events, should take place." 144 abort = true; 145 break; 146 } 147 fe = fe.getCause(); 148 } 149 if (!abort) { 150 throw e; 151 } else { 152 break; 153 } 154 } finally { 155 156 try { 157 listiterator.remove(); 158 } catch (ConcurrentModificationException cme) { 159 int eventIndex = listiterator.previousIndex(); 160 events.remove(eventIndex); 161 //listiterator = events.listIterator(); 162 } 163 } 164 } 165 } 166 167 if (abort) { 168 // TODO: abort processing of any event of any phase or just of any event of the current phase??? 169 clearEvents(); 170 } 171 } 172 173 174 private void clearEvents() { 175 events = null; 176 } 177 178 179 public void processDecodes(FacesContext context) { 180 if (context == null) { 181 throw new NullPointerException("context"); 182 } 183 super.processDecodes(context); 184 broadcastForPhase(PhaseId.APPLY_REQUEST_VALUES); 185 if (context.getRenderResponse() || context.getResponseComplete()) { 186 clearEvents(); 187 } 188 } 189 190 public void processValidators(FacesContext context) { 191 if (context == null) { 192 throw new NullPointerException("context"); 193 } 194 super.processValidators(context); 195 broadcastForPhase(PhaseId.PROCESS_VALIDATIONS); 196 if (context.getRenderResponse() || context.getResponseComplete()) { 197 clearEvents(); 198 } 199 } 200 201 public void processUpdates(FacesContext context) { 202 if (context == null) { 203 throw new NullPointerException("context"); 204 } 205 super.processUpdates(context); 206 broadcastForPhase(PhaseId.UPDATE_MODEL_VALUES); 207 if (context.getRenderResponse() || context.getResponseComplete()) { 208 clearEvents(); 209 } 210 } 211 212 public void processApplication(FacesContext context) { 213 if (context == null) { 214 throw new NullPointerException("context"); 215 } 216 broadcastForPhase(PhaseId.INVOKE_APPLICATION); 217 if (context.getRenderResponse() || context.getResponseComplete()) { 218 clearEvents(); 219 } 220 } 221 }