1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.myfaces.view.facelets.tag.composite; 20 21 import java.beans.BeanDescriptor; 22 import java.beans.IntrospectionException; 23 import java.beans.PropertyDescriptor; 24 import java.io.IOException; 25 import java.util.ArrayList; 26 import java.util.HashMap; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.logging.Level; 30 import java.util.logging.Logger; 31 32 import javax.faces.component.UIComponent; 33 import javax.faces.view.facelets.FaceletContext; 34 import javax.faces.view.facelets.TagAttribute; 35 import javax.faces.view.facelets.TagConfig; 36 import javax.faces.view.facelets.TagException; 37 import javax.faces.view.facelets.TagHandler; 38 39 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute; 40 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag; 41 import org.apache.myfaces.view.facelets.AbstractFaceletContext; 42 import org.apache.myfaces.view.facelets.FaceletCompositionContext; 43 44 /** 45 * Insert or move the facet from the composite component body to the expected location. 46 * 47 * @author Leonardo Uribe (latest modification by $Author: lu4242 $) 48 * @version $Revision: 1159313 $ $Date: 2011-08-18 11:55:54 -0500 (Thu, 18 Aug 2011) $ 49 */ 50 @JSFFaceletTag(name="composite:insertFacet") 51 public class InsertFacetHandler extends TagHandler 52 { 53 //public static String USES_INSERT_FACET = "org.apache.myfaces.USES_INSERT_FACET"; 54 //public static String INSERT_FACET_TARGET_ID = "org.apache.myfaces.INSERT_FACET_TARGET_ID."; 55 //public static String INSERT_FACET_ORDERING = "org.apache.myfaces.INSERT_FACET_ORDERING."; 56 57 public static String INSERT_FACET_USED = "org.apache.myfaces.INSERT_FACET_USED"; 58 59 /** 60 * Key used to save on bean descriptor a map containing the metadata 61 * information related to this tag. It will be used later to check "required" property. 62 */ 63 public static String INSERT_FACET_KEYS = "org.apache.myfaces.INSERT_FACET_KEYS"; 64 65 private static final Logger log = Logger.getLogger(InsertFacetHandler.class.getName()); 66 67 /** 68 * The name that identify the current facet. 69 */ 70 @JSFFaceletAttribute(name="name", 71 className="javax.el.ValueExpression", 72 deferredValueType="java.lang.String", 73 required=true) 74 protected final TagAttribute _name; 75 76 /** 77 * Define if the facet to be inserted is required or not for every instance of 78 * this composite component. 79 */ 80 @JSFFaceletAttribute(name="required", 81 className="javax.el.ValueExpression", 82 deferredValueType="boolean") 83 protected final TagAttribute _required; 84 85 public InsertFacetHandler(TagConfig config) 86 { 87 super(config); 88 _name = getRequiredAttribute("name"); 89 _required = getAttribute("required"); 90 } 91 92 public String getFacetName(FaceletContext ctx) 93 { 94 return _name.getValue(ctx); 95 } 96 97 @SuppressWarnings("unchecked") 98 public void apply(FaceletContext ctx, UIComponent parent) 99 throws IOException 100 { 101 if (((AbstractFaceletContext)ctx).isBuildingCompositeComponentMetadata()) 102 { 103 String facetName = _name.getValue(ctx); 104 105 UIComponent compositeBaseParent = FaceletCompositionContext.getCurrentInstance(ctx).getCompositeComponentFromStack(); 106 107 CompositeComponentBeanInfo beanInfo = 108 (CompositeComponentBeanInfo) compositeBaseParent.getAttributes() 109 .get(UIComponent.BEANINFO_KEY); 110 111 if (beanInfo == null) 112 { 113 if (log.isLoggable(Level.SEVERE)) 114 { 115 log.severe("Cannot find composite bean descriptor UIComponent.BEANINFO_KEY "); 116 } 117 return; 118 } 119 120 BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor(); 121 122 List<String> facetList = (List<String>) beanDescriptor.getValue(INSERT_FACET_USED); 123 124 if (facetList == null) 125 { 126 //2. If not found create it and set 127 facetList = new ArrayList<String>(); 128 beanDescriptor.setValue( 129 INSERT_FACET_USED, 130 facetList); 131 } 132 133 facetList.add(facetName); 134 135 Map<String, PropertyDescriptor> insertFacetPropertyDescriptorMap = (Map<String, PropertyDescriptor>) 136 beanDescriptor.getValue(INSERT_FACET_KEYS); 137 138 if (insertFacetPropertyDescriptorMap == null) 139 { 140 insertFacetPropertyDescriptorMap = new HashMap<String, PropertyDescriptor>(); 141 beanDescriptor.setValue(INSERT_FACET_KEYS, insertFacetPropertyDescriptorMap); 142 } 143 144 PropertyDescriptor facetDescriptor = _createFacetPropertyDescriptor(facetName, ctx, parent); 145 insertFacetPropertyDescriptorMap.put(facetName, facetDescriptor); 146 } 147 else 148 { 149 String facetName = _name.getValue(ctx); 150 151 AbstractFaceletContext actx = (AbstractFaceletContext) ctx; 152 153 UIComponent parentCompositeComponent = FaceletCompositionContext.getCurrentInstance(ctx).getCompositeComponentFromStack(); 154 155 actx.includeCompositeComponentDefinition(parent, facetName); 156 157 //parentCompositeComponent.getAttributes().put(INSERT_FACET_USED+facetName, Boolean.TRUE); 158 } 159 160 } 161 162 private PropertyDescriptor _createFacetPropertyDescriptor(String facetName, FaceletContext ctx, UIComponent parent) 163 throws TagException, IOException 164 { 165 try 166 { 167 CompositeComponentPropertyDescriptor facetPropertyDescriptor = 168 new CompositeComponentPropertyDescriptor(facetName); 169 170 if (_required != null) 171 { 172 facetPropertyDescriptor.setValue("required", _required.getValueExpression(ctx, Boolean.class)); 173 } 174 175 return facetPropertyDescriptor; 176 } 177 catch (IntrospectionException e) 178 { 179 if (log.isLoggable(Level.SEVERE)) 180 { 181 log.log(Level.SEVERE, "Cannot create PropertyDescriptor for attribute ",e); 182 } 183 throw new TagException(tag,e); 184 } 185 } 186 187 /* 188 public void apply(FaceletContext ctx, UIComponent parent) 189 throws IOException 190 { 191 String facetName = _name.getValue(ctx); 192 193 UIComponent parentCompositeComponent = FaceletCompositionContext.getCurrentInstance(ctx).getCompositeComponentFromStack(); 194 195 if (_required != null && _required.getBoolean(ctx) && parentCompositeComponent.getFacet(facetName) == null) 196 { 197 throw new TagException(this.tag, "Cannot find facet with name "+facetName+" in composite component " 198 +parentCompositeComponent.getClientId(ctx.getFacesContext())); 199 } 200 201 if (!ComponentHandler.isNew(parentCompositeComponent)) 202 { 203 UIComponent facet = parent.getFacet(facetName); 204 if (facet != null) 205 { 206 if (facet.getAttributes().containsKey(ComponentSupport.FACET_CREATED_UIPANEL_MARKER)) 207 { 208 ComponentSupport.markForDeletion(facet); 209 for (UIComponent child : facet.getChildren()) 210 { 211 if (child.getAttributes().remove(USES_INSERT_FACET) != null) 212 { 213 ComponentSupport.finalizeForDeletion(child); 214 } 215 } 216 } 217 ComponentSupport.finalizeForDeletion(facet); 218 } 219 return; 220 } 221 222 parentCompositeComponent.subscribeToEvent(PostAddToViewEvent.class, 223 new RelocateFacetListener(parent, facetName)); 224 parentCompositeComponent.subscribeToEvent(PostBuildComponentTreeOnRestoreViewEvent.class, 225 new RelocateFacetListener(parent, facetName)); 226 */ 227 /* 228 if (ctx.getFacesContext().getAttributes().containsKey( 229 FaceletViewDeclarationLanguage.MARK_INITIAL_STATE_KEY)) 230 { 231 parentCompositeComponent.subscribeToEvent(PostBuildComponentTreeOnRestoreViewEvent.class, 232 new RelocateFacetListener(parent, facetName)); 233 }*/ 234 /* 235 } 236 */ 237 /* 238 public static final class RelocateFacetListener 239 implements ComponentSystemEventListener, StateHolder 240 { 241 private UIComponent _targetComponent; 242 private String _targetClientId; 243 private String _facetName; 244 245 public RelocateFacetListener() 246 { 247 } 248 249 public RelocateFacetListener(UIComponent targetComponent, String facetName) 250 { 251 _targetComponent = targetComponent; 252 _facetName = facetName; 253 } 254 255 public void processEvent(ComponentSystemEvent event) 256 { 257 UIComponent parentCompositeComponent = event.getComponent(); 258 259 UIComponent facetComponent = parentCompositeComponent.getFacet(_facetName); 260 261 if (_targetComponent == null) 262 { 263 //All composite components are NamingContainer and the target is inside it, so we can remove the prefix. 264 _targetComponent = parentCompositeComponent.findComponent(_targetClientId.substring(parentCompositeComponent.getClientId().length()+1)); 265 266 if (_targetComponent == null) 267 { 268 //Could happen in no org.apache.myfaces.REFRESH_TRANSIENT_BUILD_ON_PSS_PRESERVE_STATE 269 //In this case we cannot relocate, just return; 270 return; 271 } 272 } 273 274 if (facetComponent != null) 275 { 276 Map<String, Object> ccAttributes = parentCompositeComponent.getAttributes(); 277 UIComponent oldFacet = _targetComponent.getFacets().get(_facetName); 278 String insertFacetKey = INSERT_FACET_TARGET_ID+_facetName; 279 280 if (!ccAttributes.containsKey(insertFacetKey)) 281 { 282 ccAttributes.put(insertFacetKey, _targetComponent.getClientId()); 283 } 284 285 if (oldFacet != null && Boolean.TRUE.equals(oldFacet.getAttributes().get(ComponentSupport.FACET_CREATED_UIPANEL_MARKER))) 286 { 287 List<UIComponent> childList = new ArrayList<UIComponent>(facetComponent.getChildren()); 288 289 List<UIComponent> targetChildrenList = oldFacet.getChildren(); 290 291 List<String> ids = (List<String>) ccAttributes.get(INSERT_FACET_ORDERING+_facetName); 292 if (ids != null && targetChildrenList.size() > 0) 293 { 294 int i = 0; 295 int j = 0; 296 int k = 0; 297 while (i < ids.size() && j < targetChildrenList.size() && k < childList.size()) 298 { 299 if (ids.get(i) != null) 300 { 301 if (ids.get(i).equals(childList.get(k).getAttributes().get(ComponentSupport.MARK_CREATED))) 302 { 303 if (!ids.get(i).equals(targetChildrenList.get(j).getAttributes().get(ComponentSupport.MARK_CREATED))) 304 { 305 targetChildrenList.add(j, childList.get(k)); 306 k++; 307 } 308 j++; 309 } 310 else if (ids.get(i).equals(targetChildrenList.get(j).getAttributes().get(ComponentSupport.MARK_CREATED))) 311 { 312 j++; 313 } 314 } 315 i++; 316 } 317 while (k < childList.size()) 318 { 319 targetChildrenList.add(j, childList.get(k)); 320 k++; 321 j++; 322 } 323 } 324 else 325 { 326 _targetComponent.getFacets().put(_facetName, facetComponent); 327 } 328 } 329 else 330 { 331 _targetComponent.getFacets().put(_facetName, facetComponent); 332 } 333 334 } 335 } 336 337 public Object saveState(FacesContext context) 338 { 339 return new Object[]{_targetComponent != null ? _targetComponent.getClientId() : _targetClientId , _facetName}; 340 } 341 342 public void restoreState(FacesContext context, Object state) 343 { 344 Object[] values = (Object[])state; 345 _targetClientId = (String) values[0]; 346 _facetName = (String) values[1]; 347 } 348 349 public boolean isTransient() 350 { 351 return false; 352 } 353 354 public void setTransient(boolean newTransientValue) 355 { 356 // no-op as listener is transient 357 } 358 } 359 */ 360 }