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 package org.apache.myfaces.view;
20
21 import java.util.logging.Level;
22 import java.util.logging.Logger;
23
24 import javax.faces.context.FacesContext;
25 import javax.faces.view.ViewDeclarationLanguage;
26 import javax.faces.view.ViewDeclarationLanguageFactory;
27
28 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
29 import org.apache.myfaces.shared.config.MyfacesConfig;
30 import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguageStrategy;
31 import org.apache.myfaces.view.jsp.JspViewDeclarationLanguageStrategy;
32
33 /**
34 * This is the default PDL factory used as of JSF 2.0, it tries to use Facelet PDL whenever possible,
35 * but fallback on JSP if required.
36 *
37 * @author Simon Lessard (latest modification by $Author: lu4242 $)
38 * @version $Revision: 1409476 $ $Date: 2012-11-14 17:14:40 -0500 (Wed, 14 Nov 2012) $
39 *
40 * @since 2.0
41 */
42 public class ViewDeclarationLanguageFactoryImpl extends ViewDeclarationLanguageFactory
43 {
44 /**
45 * Disable facelets VDL from the current application project.
46 */
47 @JSFWebConfigParam(since="2.0", defaultValue="false", expectedValues="true,false", group="viewhandler")
48 public static final String PARAM_DISABLE_JSF_FACELET = "javax.faces.DISABLE_FACELET_JSF_VIEWHANDLER";
49
50 private static final String FACELETS_1_VIEW_HANDLER = "com.sun.facelets.FaceletViewHandler";
51
52 private static final Logger LOGGER = Logger.getLogger(ViewDeclarationLanguageFactoryImpl.class.getName());
53
54 private volatile boolean _initialized;
55 private volatile ViewDeclarationLanguageStrategy[] _supportedLanguages;
56
57 /**
58 *
59 */
60 public ViewDeclarationLanguageFactoryImpl()
61 {
62 _initialized = false;
63 }
64
65 /**
66 * {@inheritDoc}
67 */
68 @Override
69 public ViewDeclarationLanguage getViewDeclarationLanguage(String viewId)
70 {
71 //if (viewId == null)
72 //{
73 // throw new NullPointerException("viewId");
74 //}
75
76 // TODO: It would be nice to be able to preinitialize the factory. However, since it requires
77 // access to the ExternalContext it may not be possible, depending on the loading order
78 // in the FactoryFinder. Could use ideas here. -= SL =-
79 if (!_initialized)
80 {
81 initialize();
82 }
83
84 for (ViewDeclarationLanguageStrategy strategy : _supportedLanguages)
85 {
86 if (strategy.handles(viewId))
87 {
88 return strategy.getViewDeclarationLanguage();
89 }
90 }
91
92 // throw new FacesException("Cannot find a valid PDL for view id " + viewId);
93 // It does not have sense to throw an exception in this point. Instead
94 // just return null, to indicate that no VDL can handle the viewId.
95 // For example, in org.apache.myfaces.shared.application.DefaultViewHandlerSupport
96 // first getViewDeclarationLanguage(String viewId) is called and if returns null
97 // try the default strategy (look for a file in web folder).
98 return null;
99 }
100
101 /**
102 * Initialize the supported view declaration languages.
103 */
104 private synchronized void initialize()
105 {
106 if (!_initialized)
107 {
108 FacesContext context = FacesContext.getCurrentInstance();
109
110 if (isFacelets2Enabled(context))
111 {
112 logWarningIfLegacyFaceletViewHandlerIsPresent(context);
113
114 if (MyfacesConfig.getCurrentInstance(
115 context.getExternalContext()).isSupportJSPAndFacesEL())
116 {
117 _supportedLanguages = new ViewDeclarationLanguageStrategy[2];
118 _supportedLanguages[0] = new FaceletViewDeclarationLanguageStrategy();
119 _supportedLanguages[1] = new JspViewDeclarationLanguageStrategy();
120 }
121 else
122 {
123 _supportedLanguages = new ViewDeclarationLanguageStrategy[1];
124 _supportedLanguages[0] = new FaceletViewDeclarationLanguageStrategy();
125 }
126 }
127 else
128 {
129 // Support JSP only
130 _supportedLanguages = new ViewDeclarationLanguageStrategy[1];
131 _supportedLanguages[0] = new JspViewDeclarationLanguageStrategy();
132 }
133
134 _initialized = true;
135 }
136 }
137
138 /**
139 * Determines if the current application uses Facelets-2.
140 * To accomplish that it looks at the init param javax.faces.DISABLE_FACELET_JSF_VIEWHANDLER,
141 *
142 * @param context the <code>FacesContext</code>
143 * @return <code>true</code> if the current application uses the built in Facelets-2,
144 * <code>false</code> otherwise (e.g. it uses Facelets-1 or only JSP).
145 */
146 private boolean isFacelets2Enabled(FacesContext context)
147 {
148 String param = context.getExternalContext().getInitParameter(PARAM_DISABLE_JSF_FACELET);
149 boolean facelets2ParamDisabled = (param != null && Boolean.parseBoolean(param.toLowerCase()));
150
151 return !facelets2ParamDisabled;
152 }
153
154 /**
155 * If the Facelets-1 ViewHandler com.sun.facelets.FaceletViewHandler is present <b>AND</b>
156 * the new Facelets-2 is <b>NOT</b> disabled, we log a <code>WARNING</code>.
157 *
158 * @param context the <code>FacesContext</code>
159 */
160 private void logWarningIfLegacyFaceletViewHandlerIsPresent(FacesContext context)
161 {
162 boolean facelets1ViewHandlerPresent
163 = context.getApplication().getViewHandler().getClass().getName().equals(FACELETS_1_VIEW_HANDLER);
164
165 if (facelets1ViewHandlerPresent)
166 {
167 if (LOGGER.isLoggable(Level.WARNING))
168 {
169 LOGGER.log(Level.WARNING, "Your faces-config.xml contains the " + FACELETS_1_VIEW_HANDLER + " class."
170 + "\nYou need to remove it since you have not disabled the \"new\" Facelets-2 version with the "
171 + PARAM_DISABLE_JSF_FACELET + " context parameter");
172 }
173 }
174 }
175 }