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