View Javadoc

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  
20  package org.apache.myfaces.tobago.internal.config;
21  
22  import org.apache.commons.beanutils.PropertyUtils;
23  import org.apache.myfaces.tobago.application.ProjectStage;
24  import org.apache.myfaces.tobago.config.TobagoConfig;
25  import org.apache.myfaces.tobago.context.Theme;
26  import org.apache.myfaces.tobago.internal.util.Deprecation;
27  import org.apache.myfaces.tobago.internal.util.JndiUtils;
28  import org.apache.myfaces.tobago.util.FacesVersion;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  import javax.faces.application.Application;
33  import javax.faces.context.FacesContext;
34  import javax.naming.Context;
35  import javax.naming.InitialContext;
36  import javax.naming.NamingException;
37  import javax.servlet.ServletContext;
38  import java.net.URL;
39  import java.util.ArrayList;
40  import java.util.Collections;
41  import java.util.HashSet;
42  import java.util.List;
43  import java.util.Map;
44  import java.util.Set;
45  
46  public class TobagoConfigImpl extends TobagoConfig {
47  
48    private static final Logger LOG = LoggerFactory.getLogger(TobagoConfigImpl.class);
49  
50    public static final String TOBAGO_CONFIG = "org.apache.myfaces.tobago.config.TobagoConfig";
51  
52    private List<Theme> supportedThemes;
53    private List<String> supportedThemeNames;
54    private Theme defaultTheme;
55    private String defaultThemeName;
56    private List<String> resourceDirs;
57    private Map<String, Theme> availableThemes;
58    private RenderersConfig renderersConfig;
59    private ProjectStage projectStage;
60    private boolean createSessionSecret;
61    private boolean checkSessionSecret;
62    private boolean preventFrameAttacks = true;
63    private List<String> contentSecurityPolicy;
64    private URL url;
65    private Map<String, String> defaultValidatorInfo;
66  
67    public TobagoConfigImpl() {
68      supportedThemeNames = new ArrayList<String>();
69      supportedThemes = new ArrayList<Theme>();
70      resourceDirs = new ArrayList<String>();
71      createSessionSecret = true;
72      checkSessionSecret = true;
73      contentSecurityPolicy = new ArrayList<String>();
74    }
75  
76    public void addSupportedThemeName(String name) {
77      supportedThemeNames.add(name);
78    }
79    // TODO one init method
80    public void resolveThemes() {
81      if (defaultThemeName != null) {
82        defaultTheme = availableThemes.get(defaultThemeName);
83        checkThemeIsAvailable(defaultThemeName, defaultTheme);
84        if (LOG.isDebugEnabled()) {
85          LOG.debug("name = '{}'", defaultThemeName);
86          LOG.debug("defaultTheme = '{}'", defaultTheme);
87        }
88      } else {
89        int deep = 0;
90        for (Map.Entry<String, Theme> entry : availableThemes.entrySet()) {
91          Theme theme = entry.getValue();
92          if (theme.getFallbackList().size() > deep) {
93            defaultTheme = theme;
94            deep = theme.getFallbackList().size();
95          }
96        }
97        if (defaultTheme == null) {
98          String error = "Did not found any theme! "
99              + "Please ensure you have a tobago-theme.xml file in your "
100             + "theme jar. Please add a theme jar to your WEB-INF/lib";
101         LOG.error(error);
102         throw new RuntimeException(error);
103       } else {
104         if (LOG.isInfoEnabled()) {
105           LOG.info("Using default Theme {}", defaultTheme.getName());
106         }
107       }
108     }
109     if (!supportedThemeNames.isEmpty()) {
110       for (String name : supportedThemeNames) {
111         Theme theme = availableThemes.get(name);
112         checkThemeIsAvailable(name, theme);
113         supportedThemes.add(theme);
114         if (LOG.isDebugEnabled()) {
115           LOG.debug("name = '{}'",  name);
116           LOG.debug("supportedThemes.last() = '{}'", supportedThemes.get(supportedThemes.size() - 1));
117         }
118       }
119     }
120   }
121 
122   private void checkThemeIsAvailable(String name, Theme theme) {
123     if (theme == null) {
124       String error = "Theme not found! name: '" + name + "'. "
125           + "Please ensure you have a tobago-theme.xml file in your "
126           + "theme jar. Found the following themes: " + availableThemes.keySet();
127       LOG.error(error);
128       throw new RuntimeException(error);
129     }
130   }
131 
132   public Theme getTheme(String name) {
133     if (name == null) {
134       LOG.debug("searching theme: null");
135       return defaultTheme;
136     }
137     if (defaultTheme.getName().equals(name)) {
138       return defaultTheme;
139     }
140     for (Theme theme : supportedThemes) {
141       if (theme.getName().equals(name)) {
142         return theme;
143       }
144     }
145     LOG.debug("searching theme '{}' not found. Using default: {}", name, defaultTheme);
146     return defaultTheme;
147   }
148 
149   public void setDefaultThemeName(String defaultThemeName) {
150     this.defaultThemeName = defaultThemeName;
151   }
152 
153   public List<Theme> getSupportedThemes() {
154     return Collections.unmodifiableList(supportedThemes);
155   }
156 
157   public void addResourceDir(String resourceDir) {
158     if (!resourceDirs.contains(resourceDir)) {
159       if (LOG.isInfoEnabled()) {
160         LOG.info("adding resourceDir = '{}'", resourceDir);
161       }
162       resourceDirs.add(0, resourceDir);
163     }
164   }
165 
166   public List<String> getResourceDirs() {
167     return resourceDirs;
168   }
169 
170   /** @deprecated since 1.5.0 */
171   @Deprecated
172   public boolean isAjaxEnabled() {
173     Deprecation.LOG.warn("Ajax is always enabled!");
174     return true;
175   }
176 
177   public Theme getDefaultTheme() {
178     return defaultTheme;
179   }
180 
181   public void setAvailableThemes(Map<String, Theme> availableThemes) {
182     this.availableThemes = availableThemes;
183     for (Theme theme : this.availableThemes.values()) {
184       addResourceDir(theme.getResourcePath());
185     }
186   }
187 
188   public RenderersConfig getRenderersConfig() {
189     return renderersConfig;
190   }
191 
192   public void setRenderersConfig(RenderersConfig renderersConfig) {
193     this.renderersConfig = renderersConfig;
194   }
195 
196   public ProjectStage getProjectStage() {
197     return projectStage;
198   }
199   // TODO one init method
200   public void initProjectState(ServletContext servletContext) {
201     String stageName = null;
202     try {
203       Context ctx = new InitialContext();
204       Object obj = JndiUtils.getJndiProperty(ctx, "jsf", "ProjectStage");
205       if (obj != null) {
206         if (obj instanceof String) {
207           stageName = (String) obj;
208         } else {
209           LOG.warn("JNDI lookup for key {} should return a java.lang.String value",
210               ProjectStage.PROJECT_STAGE_JNDI_NAME);
211         }
212       }
213     } catch (NamingException e) {
214       // ignore
215     }
216 
217     if (stageName == null) {
218       stageName = servletContext.getInitParameter(ProjectStage.PROJECT_STAGE_PARAM_NAME);
219     }
220 
221     if (stageName == null) {
222       stageName = System.getProperty("org.apache.myfaces.PROJECT_STAGE");
223     }
224 
225     if (stageName != null) {
226       try {
227         projectStage = ProjectStage.valueOf(stageName);
228       } catch (IllegalArgumentException e) {
229         LOG.error("Couldn't discover the current project stage", e);
230       }
231     }
232     if (projectStage == null) {
233       if (LOG.isInfoEnabled()) {
234         LOG.info("Couldn't discover the current project stage, using {}", ProjectStage.Production);
235       }
236       projectStage = ProjectStage.Production;
237     }
238   }
239 
240   public synchronized void initDefaultValidatorInfo() {
241     if (FacesVersion.supports20()) {
242       final FacesContext facesContext = FacesContext.getCurrentInstance();
243       if (facesContext != null) {
244         try {
245           final Application application = facesContext.getApplication();
246           final Map<String, String> map;
247           map = (Map<String, String>) PropertyUtils.getProperty(application, "defaultValidatorInfo");
248           if (application != null && map.size() > 0) {
249             defaultValidatorInfo = Collections.unmodifiableMap(map);
250           } else {
251             defaultValidatorInfo = Collections.emptyMap();
252           }
253         } catch (Exception e) {
254           // should not happen
255           LOG.error("Can't initialize default validators.", e);
256           defaultValidatorInfo = Collections.emptyMap();
257         }
258       }
259     } else {
260       defaultValidatorInfo = Collections.emptyMap();
261     }
262   }
263 
264   public boolean isCreateSessionSecret() {
265     return createSessionSecret;
266   }
267 
268   public void setCreateSessionSecret(boolean createSessionSecret) {
269     this.createSessionSecret = createSessionSecret;
270   }
271 
272   public boolean isCheckSessionSecret() {
273     return checkSessionSecret;
274   }
275 
276   public void setCheckSessionSecret(boolean checkSessionSecret) {
277     this.checkSessionSecret = checkSessionSecret;
278   }
279 
280 
281   public boolean isPreventFrameAttacks() {
282     return preventFrameAttacks;
283   }
284 
285   public void setPreventFrameAttacks(boolean preventFrameAttacks) {
286     this.preventFrameAttacks = preventFrameAttacks;
287   }
288 
289   public List<String> getContentSecurityPolicy() {
290     return contentSecurityPolicy;
291   }
292 
293   public void addContentSecurityPolicy(String directive) {
294     contentSecurityPolicy.add(directive);
295   }
296 
297   public Map<String, String> getDefaultValidatorInfo() {
298 
299     // TODO: if the startup hasn't found a FacesContext and Application, this may depend on the order of the listeners.
300     if (defaultValidatorInfo == null) {
301       initDefaultValidatorInfo();
302     }
303     return defaultValidatorInfo;
304   }
305 
306   @Override
307   public String toString() {
308     final StringBuilder builder = new StringBuilder();
309     builder.append("TobagoConfigImpl{");
310     builder.append("\nsupportedThemes=[");
311     for (Theme supportedTheme : supportedThemes) {
312       builder.append(supportedTheme.getName());
313       builder.append(", ");
314     }
315     builder.append("], \ndefaultTheme=");
316     builder.append(defaultTheme.getName());
317     builder.append(", \nresourceDirs=");
318     builder.append(resourceDirs);
319     builder.append(", \navailableThemes=");
320     builder.append(availableThemes.keySet());
321     builder.append(", \nprojectStage=");
322     builder.append(projectStage);
323     builder.append(", \ncreateSessionSecret=");
324     builder.append(createSessionSecret);
325     builder.append(", \ncheckSessionSecret=");
326     builder.append(checkSessionSecret);
327     builder.append(", \nurl=");
328     builder.append(url);
329     // to see only different (ignore alternative names for the same theme)
330     builder.append(", \nthemes=");
331     Set<Theme> all = new HashSet<Theme>(availableThemes.values());
332     builder.append(all);
333     builder.append('}');
334     return builder.toString();
335   }
336 }