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