001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license 003 * agreements. See the NOTICE file distributed with this work for additional information regarding 004 * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the 005 * "License"); you may not use this file except in compliance with the License. You may obtain a 006 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable 007 * law or agreed to in writing, software distributed under the License is distributed on an "AS IS" 008 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License 009 * for the specific language governing permissions and limitations under the License. 010 */ 011 package javax.portlet.faces.component; 012 013 import java.io.Serializable; 014 015 import javax.faces.context.FacesContext; 016 import javax.faces.component.NamingContainer; 017 import javax.faces.component.UIViewRoot; 018 import javax.faces.context.ExternalContext; 019 020 import javax.portlet.faces.Bridge; 021 import javax.portlet.faces.BridgeUtil; 022 import javax.portlet.faces.annotation.PortletNamingContainer; 023 024 /** 025 * <code>UIViewRoot</code> that implements portlet specific <code>NamingContainer</code> 026 * that ensures the consumer's unique portlet Id is encoded in all tree components. 027 * The class is annotated by <code>javax.portlet.faces.annotation.PortletNamingContainer</code> 028 * allowing the bridge to recognize that this specific <code>UIViewRoot</code> 029 * implements the behavior. 030 */ 031 @PortletNamingContainer 032 public class PortletNamingContainerUIViewRoot extends UIViewRoot implements Serializable, NamingContainer 033 { 034 035 //TODO: This should be regenerated each time this is modified. Can this be added to maven? 036 private static final long serialVersionUID = -4524288011655837711L; 037 private static final String PORTLET_ENCODED_NAMESPACE_ID = Bridge.BRIDGE_PACKAGE_PREFIX + "PortletEncodedNamespaceId"; 038 039 // Assumes that first use of the UIViewRoot always occurs in a render as portlet namespace 040 // is only available during a render. If this isn't the case we disable use of the 041 // NamingContainer 042 public PortletNamingContainerUIViewRoot() 043 { 044 super(); 045 046 getAttributes().put(PORTLET_ENCODED_NAMESPACE_ID, Boolean.FALSE); 047 } 048 049 /** 050 * NamingContainer semantics worked generically (serviced by subclasses) as long as the class 051 * is marked as implementing NamingContainer and we use the portletNamespace Id as 052 * (part of) the component's id. 053 */ 054 055 @Override 056 public String getContainerClientId(FacesContext context) 057 { 058 if (BridgeUtil.isPortletRequest() && ((Boolean) this.getAttributes().get(PORTLET_ENCODED_NAMESPACE_ID)).equals(Boolean.TRUE)) 059 { 060 return super.getContainerClientId(context); 061 } 062 else 063 { 064 return null; 065 } 066 } 067 068 @Override 069 public void setId(String id) 070 { 071 if (BridgeUtil.isPortletRequest()) 072 { 073 Boolean encoded = Boolean.FALSE; 074 /* Can only calculate the namespace during a render (in portlet 1.0) */ 075 if (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RENDER_PHASE) 076 { 077 // Turns out some Faces impls (the RI) , on restoreView, manually sets the id from 078 // the extracted state prior to telling the component to restore itself from this state. 079 // (At which point the self restore overwrites any id set prior.). As this manual 080 // set is using the already encoded (saved) value we could end up with a doubly 081 // encoded id until the restore overwrites. To avoid this -- first test if 082 // its already encoded and don't re-encode. 083 ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); 084 String namespace = ec.encodeNamespace(""); 085 if (!id.startsWith(namespace)) 086 { 087 id = namespace + "_" + id; 088 } 089 // now indicate that this id is encoded 090 encoded = Boolean.TRUE; 091 } 092 093 getAttributes().put(PORTLET_ENCODED_NAMESPACE_ID, encoded); 094 } 095 super.setId(id); 096 } 097 098 }