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.annotation.PortletNamingContainer;
021    
022    /**
023     * <code>UIViewRoot</code> that implements portlet specific <code>NamingContainer</code>
024     * that ensures the consumer's unique portlet Id is encoded in all tree components.
025     * The class is annotated by <code>javax.portlet.faces.annotation.PortletNamingContainer</code>
026     * allowing the bridge to recognize that this specific <code>UIViewRoot</code>
027     * implements the behavior.
028     */
029    @PortletNamingContainer
030    public class PortletNamingContainerUIViewRoot extends UIViewRoot implements Serializable
031    {
032    
033      //TODO: This should be regenerated each time this is modified.  Can this be added to maven?
034      private static final long   serialVersionUID = -4524288011655837711L;
035      private static final String SEPARATOR        = (new Character(NamingContainer.SEPARATOR_CHAR))
036                                                                                                    .toString();
037    
038      public PortletNamingContainerUIViewRoot()
039      {
040        super();
041      }
042    
043      public PortletNamingContainerUIViewRoot(UIViewRoot viewRootToReplace)
044      {
045        super();
046        setViewId(viewRootToReplace.getViewId());
047        setLocale(viewRootToReplace.getLocale());
048        setRenderKitId(viewRootToReplace.getRenderKitId());
049      }
050    
051      /**
052       * Static method that implements NamingContainer semantics.  Ensures that the
053       * returned identifier contains the consumer (portal) provided unique portlet id.
054       * This ensures that those components in this NamingContainer generate ids which
055       * will not collide in the consumer page.<p>
056       * This method is provided for existing <code>UIViewRoot</code> implementations
057       * that prefer not to subclass <code>PortletNamingContainerUIViewRoot</code>
058       */
059      public static String getContainerClientId(FacesContext context, String additionalId)
060      {
061        ExternalContext ec = context.getExternalContext();
062        String namespace = ec.encodeNamespace(SEPARATOR);
063    
064        /*
065         * In servlet world encodeNamespace does nothing -- so if we get back what we sent in then do
066         * not perturn the NamingContainer Id
067         */
068        if (namespace.length() > 1)
069        {
070          if (additionalId != null)
071          {
072            return namespace + additionalId;
073          }
074          else
075          {
076            return namespace;
077          }
078        }
079        else
080        {
081          return null;
082        }
083      }
084    
085      /**
086       * Implements NamingContainer semantics.  Ensures that the returned identifier
087       * contains the consumer (portal) provided unique portlet id.  This ensures that
088       * those components in this NamingContainer generate ids which will not collide
089       * in the consumer page.  Implementation merely calls the static form of this
090       * method.
091       */
092    
093      @Override
094      public String getContainerClientId(FacesContext context)
095      {
096        return PortletNamingContainerUIViewRoot
097                                               .getContainerClientId(
098                                                                     context,
099                                                                     super
100                                                                          .getContainerClientId(context));
101      }
102    
103    }