001    package org.apache.myfaces.tobago.config;
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.commons.lang.ClassUtils;
021    import org.apache.commons.logging.Log;
022    import org.apache.commons.logging.LogFactory;
023    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_IN;
024    import org.apache.myfaces.tobago.component.ComponentUtil;
025    import org.apache.myfaces.tobago.context.ClientProperties;
026    import org.apache.myfaces.tobago.context.ResourceManager;
027    import org.apache.myfaces.tobago.context.ResourceManagerFactory;
028    import org.apache.myfaces.tobago.renderkit.RendererBase;
029    
030    import javax.faces.component.UIComponent;
031    import javax.faces.component.UIInput;
032    import javax.faces.component.UIViewRoot;
033    import javax.faces.context.FacesContext;
034    import javax.faces.render.Renderer;
035    import java.util.Locale;
036    import java.util.Map;
037    
038    public class ThemeConfig {
039    
040      private static final Log LOG = LogFactory.getLog(ThemeConfig.class);
041    
042      public static final String THEME_CONFIG_CACHE
043          = "org.apache.myfaces.tobago.config.ThemeConfig.CACHE";
044    
045      public static int getValue(FacesContext facesContext, UIComponent component,
046          String name) {
047    
048        CacheKey key = new CacheKey(facesContext.getViewRoot(), component, name);
049        Map<CacheKey, Integer> cache
050            = (Map<CacheKey, Integer>) facesContext.getExternalContext().getApplicationMap().get(THEME_CONFIG_CACHE);
051    
052        Integer value = cache.get(key);
053        if (value == null) {
054          value = createValue(facesContext, component, name);
055          cache.put(key, value);
056        }
057        if (value != null) {
058          return value;
059        } else {
060          // todo: remove condition, is only temporary to ignore wml errors.
061          if (!ClientProperties.getInstance(facesContext.getViewRoot()).getContentType().equals("wml")) {
062            throw new NullPointerException("No value configured");
063          }
064          // todo: remove, is only temporary to ignore wml errors.
065          return 0;
066        }
067      }
068    
069      public static boolean hasValue(FacesContext facesContext, UIComponent component,
070          String name) {
071        try {
072          getValue(facesContext, component, name);
073          return true;
074        } catch (NullPointerException e) {
075          return false;
076        }
077      }
078    
079      private static Integer createValue(FacesContext facesContext,
080          UIComponent component, String name) {
081        String family;
082        String rendererType;
083        if (component != null) {
084          family = component.getFamily();
085          rendererType = component.getRendererType();
086        } else {
087          family = UIInput.COMPONENT_FAMILY;
088          rendererType = RENDERER_TYPE_IN;
089        }
090        Renderer renderer = ComponentUtil.getRenderer(facesContext, family, rendererType);
091    
092        Class clazz = renderer.getClass();
093        if (LOG.isDebugEnabled()) {
094          LOG.debug("search for '" + name + "' in '" + clazz.getName() + "'");
095        }
096        ResourceManager resourceManager
097            = ResourceManagerFactory.getResourceManager(facesContext);
098        UIViewRoot viewRoot = facesContext.getViewRoot();
099        while (clazz != null) {
100          String tag = getTagName(clazz);
101          if (LOG.isDebugEnabled()) {
102            LOG.debug("try " + tag);
103          }
104    
105          String property = resourceManager.getThemeProperty(viewRoot,
106              "tobago-theme-config", tag + "." + name);
107    
108          if (property != null && property.length() > 0) {
109            if (LOG.isDebugEnabled()) {
110              LOG.debug("found " + property);
111            }
112            return new Integer(property);
113          }
114          clazz = clazz.getSuperclass();
115        }
116        // todo: remove condition, is only temporary to ignore wml errors.
117        if (!ClientProperties.getInstance(viewRoot).getContentType().equals("wml")) {
118          LOG.error("Theme property not found for renderer: " + renderer.getClass()
119              + " with clientProperties='" + ClientProperties.getInstance(viewRoot).getId() + "'"
120              + " and locale='" + viewRoot.getLocale() + "'");
121        }
122        return null;
123      }
124    
125      private static String getTagName(Class clazz) {
126        String className = ClassUtils.getShortClassName(clazz);
127        if (className.equals(ClassUtils.getShortClassName(RendererBase.class))) {
128          return "Tobago";
129        } else if (className.endsWith("Renderer")) {
130          return className.substring(0, className.lastIndexOf("Renderer"));
131        } else if (className.endsWith("RendererBase")) {
132          return className.substring(0, className.lastIndexOf("RendererBase")) + "Base";
133        }
134        return null;
135      }
136    
137    
138      private static class CacheKey {
139        private String clientProperties;
140        private Locale locale;
141        private String rendererType;
142        private String name;
143    
144        public CacheKey(UIViewRoot viewRoot, UIComponent component, String name) {
145          this.clientProperties = ClientProperties.getInstance(viewRoot).getId();
146          this.locale = viewRoot.getLocale();
147          if (component != null) {
148            rendererType = component.getRendererType();
149          } else {
150            rendererType = "DEFAULT";
151          }
152          this.name = name;
153        }
154    
155        public boolean equals(Object o) {
156          if (this == o) {
157            return true;
158          }
159          if (o == null || getClass() != o.getClass()) {
160            return false;
161          }
162    
163          final CacheKey cacheKey = (CacheKey) o;
164    
165          if (!clientProperties.equals(cacheKey.clientProperties)) {
166            return false;
167          }
168          if (!locale.equals(cacheKey.locale)) {
169            return false;
170          }
171          if (!name.equals(cacheKey.name)) {
172            return false;
173          }
174          if (!rendererType.equals(cacheKey.rendererType)) {
175            return false;
176          }
177    
178          return true;
179        }
180    
181        public int hashCode() {
182          int result;
183          result = clientProperties.hashCode();
184          result = 29 * result + locale.hashCode();
185          result = 29 * result + rendererType.hashCode();
186          result = 29 * result + name.hashCode();
187          return result;
188        }
189      }
190    
191    }