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, UIComponent component, String name) {
080        String family;
081        String rendererType;
082        if (component != null) {
083          family = component.getFamily();
084          rendererType = component.getRendererType();
085        } else {
086          family = UIInput.COMPONENT_FAMILY;
087          rendererType = RENDERER_TYPE_IN;
088        }
089        Renderer renderer = ComponentUtil.getRenderer(facesContext, family, rendererType);
090    
091        Class clazz = renderer.getClass();
092        if (LOG.isDebugEnabled()) {
093          LOG.debug("search for '" + name + "' in '" + clazz.getName() + "'");
094        }
095        ResourceManager resourceManager
096            = ResourceManagerFactory.getResourceManager(facesContext);
097        UIViewRoot viewRoot = facesContext.getViewRoot();
098        while (clazz != null) {
099          String tag = getTagName(clazz);
100          if (LOG.isDebugEnabled()) {
101            LOG.debug("try " + tag);
102          }
103    
104          String property = resourceManager.getThemeProperty(viewRoot, "tobago-theme-config", tag + "." + name);
105    
106          if (property != null && property.length() > 0) {
107            if (LOG.isDebugEnabled()) {
108              LOG.debug("found " + property);
109            }
110            return new Integer(property);
111          }
112          clazz = clazz.getSuperclass();
113        }
114        // todo: remove condition, is only temporary to ignore wml errors.
115        if (!ClientProperties.getInstance(viewRoot).getContentType().equals("wml")) {
116          LOG.error("Theme property '" + name + "' not found for renderer: " + renderer.getClass()
117              + " with clientProperties='" + ClientProperties.getInstance(viewRoot).getId() + "'"
118              + " and locale='" + viewRoot.getLocale() + "'");
119        }
120        return null;
121      }
122    
123      private static String getTagName(Class clazz) {
124        String className = ClassUtils.getShortClassName(clazz);
125        if (className.equals(ClassUtils.getShortClassName(RendererBase.class))) {
126          return "Tobago";
127        } else if (className.endsWith("Renderer")) {
128          return className.substring(0, className.lastIndexOf("Renderer"));
129        } else if (className.endsWith("RendererBase")) {
130          return className.substring(0, className.lastIndexOf("RendererBase")) + "Base";
131        }
132        return null;
133      }
134    
135    
136      private static class CacheKey {
137        private String clientProperties;
138        private Locale locale;
139        private String rendererType;
140        private String name;
141    
142        public CacheKey(UIViewRoot viewRoot, UIComponent component, String name) {
143          this.clientProperties = ClientProperties.getInstance(viewRoot).getId();
144          this.locale = viewRoot.getLocale();
145          if (component != null) {
146            rendererType = component.getRendererType();
147          } else {
148            rendererType = "DEFAULT";
149          }
150          this.name = name;
151        }
152    
153        public boolean equals(Object o) {
154          if (this == o) {
155            return true;
156          }
157          if (o == null || getClass() != o.getClass()) {
158            return false;
159          }
160    
161          final CacheKey cacheKey = (CacheKey) o;
162    
163          if (!clientProperties.equals(cacheKey.clientProperties)) {
164            return false;
165          }
166          if (!locale.equals(cacheKey.locale)) {
167            return false;
168          }
169          if (!name.equals(cacheKey.name)) {
170            return false;
171          }
172          if (!rendererType.equals(cacheKey.rendererType)) {
173            return false;
174          }
175    
176          return true;
177        }
178    
179        public int hashCode() {
180          int result;
181          result = clientProperties.hashCode();
182          result = 29 * result + locale.hashCode();
183          result = 29 * result + rendererType.hashCode();
184          result = 29 * result + name.hashCode();
185          return result;
186        }
187      }
188    
189    }