Home » Struts-1.3.10 » org.apache.struts » tiles » [javadoc | source]

    1   /*
    2    * $Id: TilesPlugin.java 54929 2004-10-16 16:38:42Z germuska $ 
    3    *
    4    * Copyright 1999-2004 The Apache Software Foundation.
    5    * 
    6    * Licensed under the Apache License, Version 2.0 (the "License");
    7    * you may not use this file except in compliance with the License.
    8    * 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, software
   13    * distributed under the License is distributed on an "AS IS" BASIS,
   14    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15    * See the License for the specific language governing permissions and
   16    * limitations under the License.
   17    */
   18   
   19   package org.apache.struts.tiles;
   20   
   21   import java.util.Map;
   22   
   23   import javax.servlet.ServletContext;
   24   import javax.servlet.ServletException;
   25   import javax.servlet.UnavailableException;
   26   
   27   import org.apache.commons.logging.Log;
   28   import org.apache.commons.logging.LogFactory;
   29   import org.apache.struts.action.ActionServlet;
   30   import org.apache.struts.action.PlugIn;
   31   import org.apache.struts.action.RequestProcessor;
   32   import org.apache.struts.config.ControllerConfig;
   33   import org.apache.struts.config.ModuleConfig;
   34   import org.apache.struts.config.PlugInConfig;
   35   import org.apache.struts.util.RequestUtils;
   36   
   37   /**
   38    * Tiles Plugin used to initialize Tiles.
   39    * This plugin is to be used with Struts 1.1 in association with
   40    * {@link TilesRequestProcessor}.
   41    * <br>
   42    * This plugin creates one definition factory for each Struts-module. The definition factory
   43    * configuration is read first from 'web.xml' (backward compatibility), then it is
   44    * overloaded with values found in the plugin property values.
   45    * <br>
   46    * The plugin changes the Struts configuration by specifying a {@link TilesRequestProcessor} as
   47    * request processor. If you want to use your own RequestProcessor,
   48    * it should subclass TilesRequestProcessor.
   49    * <br>
   50    * This plugin can also be used to create one single factory for all modules.
   51    * This behavior is enabled by specifying <code>moduleAware=false</code> in each
   52    * plugin properties. In this case, the definition factory
   53    * configuration file is read by the first Tiles plugin to be initialized. The order is
   54    * determined by the order of modules declaration in web.xml. The first module
   55    * is always the default one if it exists.
   56    * The plugin should be declared in each struts-config.xml file in order to
   57    * properly initialize the request processor.
   58    * @since Struts 1.1
   59    */
   60   public class TilesPlugin implements PlugIn {
   61   
   62       /** 
   63        * Commons Logging instance. 
   64        */
   65       protected static Log log = LogFactory.getLog(TilesPlugin.class);
   66   
   67       /** 
   68        * Is the factory module aware? 
   69        */
   70       protected boolean moduleAware = false;
   71   
   72       /** 
   73        * Tiles util implementation classname. This property can be set
   74        * by user in the plugin declaration.
   75        */
   76       protected String tilesUtilImplClassname = null;
   77   
   78       /** 
   79        * Associated definition factory. 
   80        */
   81       protected DefinitionsFactory definitionFactory = null;
   82   
   83       /** 
   84        * The plugin config object provided by the ActionServlet initializing
   85        * this plugin.
   86        */
   87       protected PlugInConfig currentPlugInConfigObject=null;
   88   
   89       /**
   90        * Get the module aware flag.
   91        * @return <code>true</code>: user wants a single factory instance,
   92        * <code>false:</code> user wants multiple factory instances (one per module with Struts)
   93        */
   94       public boolean isModuleAware() {
   95           return moduleAware;
   96       }
   97   
   98       /**
   99        * Set the module aware flag.
  100        * This flag is only meaningful if the property <code>tilesUtilImplClassname</code> is not
  101        * set.
  102        * @param moduleAware <code>true</code>: user wants a single factory instance,
  103        * <code>false:</code> user wants multiple factory instances (one per module with Struts)
  104        */
  105       public void setModuleAware(boolean moduleAware) {
  106           this.moduleAware = moduleAware;
  107       }
  108   
  109       /**
  110        * <p>Receive notification that the specified module is being
  111        * started up.</p>
  112        *
  113        * @param servlet ActionServlet that is managing all the modules
  114        *  in this web application.
  115        * @param moduleConfig ModuleConfig for the module with which
  116        *  this plugin is associated.
  117        *
  118        * @exception ServletException if this <code>PlugIn</code> cannot
  119        *  be successfully initialized.
  120        */
  121       public void init(ActionServlet servlet, ModuleConfig moduleConfig)
  122           throws ServletException {
  123               
  124           // Create factory config object
  125           DefinitionsFactoryConfig factoryConfig =
  126               readFactoryConfig(servlet, moduleConfig);
  127               
  128           // Set the module name in the config. This name will be used to compute
  129           // the name under which the factory is stored.
  130           factoryConfig.setFactoryName(moduleConfig.getPrefix());
  131           
  132           // Set RequestProcessor class
  133           this.initRequestProcessorClass(moduleConfig);
  134   
  135           this.initTilesUtil();
  136   
  137           this.initDefinitionsFactory(servlet.getServletContext(), moduleConfig, factoryConfig);
  138       }
  139   
  140       /**
  141        * Set TilesUtil implementation according to properties 'tilesUtilImplClassname' 
  142        * and 'moduleAware'.  These properties are taken into account only once. A
  143        * side effect is that only the values set in the first initialized plugin are 
  144        * effectively taken into account.
  145        * @throws ServletException
  146        */
  147       private void initTilesUtil() throws ServletException {
  148   
  149           if (TilesUtil.isTilesUtilImplSet()) {
  150               return;
  151           }
  152   
  153           // Check if user has specified a TilesUtil implementation classname or not.
  154           // If no implementation is specified, check if user has specified one
  155           // shared single factory for all module, or one factory for each module.
  156   
  157           if (this.getTilesUtilImplClassname() == null) {
  158   
  159               if (isModuleAware()) {
  160                   TilesUtil.setTilesUtil(new TilesUtilStrutsModulesImpl());
  161               } else {
  162                   TilesUtil.setTilesUtil(new TilesUtilStrutsImpl());
  163               }
  164   
  165           } else { // A classname is specified for the tilesUtilImp, use it.
  166               try {
  167                   TilesUtilStrutsImpl impl =
  168                       (TilesUtilStrutsImpl) RequestUtils
  169                           .applicationClass(getTilesUtilImplClassname())
  170                           .newInstance();
  171                   TilesUtil.setTilesUtil(impl);
  172   
  173               } catch (ClassCastException ex) {
  174                   throw new ServletException(
  175                       "Can't set TilesUtil implementation to '"
  176                           + getTilesUtilImplClassname()
  177                           + "'. TilesUtil implementation should be a subclass of '"
  178                           + TilesUtilStrutsImpl.class.getName()
  179                           + "'");
  180   
  181               } catch (Exception ex) {
  182                   throw new ServletException(
  183                       "Can't set TilesUtil implementation.",
  184                       ex);
  185               }
  186           }
  187   
  188       }
  189   
  190       /**
  191        * Initialize the DefinitionsFactory this module will use.
  192        * @param servletContext
  193        * @param moduleConfig
  194        * @param factoryConfig
  195        * @throws ServletException
  196        */
  197       private void initDefinitionsFactory(
  198           ServletContext servletContext,
  199           ModuleConfig moduleConfig,
  200           DefinitionsFactoryConfig factoryConfig)
  201           throws ServletException {
  202               
  203           // Check if a factory already exist for this module
  204           definitionFactory =
  205               ((TilesUtilStrutsImpl) TilesUtil.getTilesUtil()).getDefinitionsFactory(
  206                   servletContext,
  207                   moduleConfig);
  208                   
  209           if (definitionFactory != null) {
  210               log.info(
  211                   "Factory already exists for module '"
  212                       + moduleConfig.getPrefix()
  213                       + "'. The factory found is from module '"
  214                       + definitionFactory.getConfig().getFactoryName()
  215                       + "'. No new creation.");
  216                       
  217               return;
  218           }
  219           
  220           // Create configurable factory
  221           try {
  222               definitionFactory =
  223                   TilesUtil.createDefinitionsFactory(
  224                       servletContext,
  225                       factoryConfig);
  226                       
  227           } catch (DefinitionsFactoryException ex) {
  228               log.error(
  229                   "Can't create Tiles definition factory for module '"
  230                       + moduleConfig.getPrefix()
  231                       + "'.");
  232                       
  233               throw new ServletException(ex);
  234           }
  235           
  236           log.info(
  237               "Tiles definition factory loaded for module '"
  238                   + moduleConfig.getPrefix()
  239                   + "'.");
  240       }
  241   
  242       /**
  243        * End plugin.
  244        */
  245       public void destroy() {
  246           definitionFactory.destroy();
  247           definitionFactory = null;
  248       }
  249   
  250       /**
  251        * Create FactoryConfig and initialize it from web.xml and struts-config.xml.
  252        *
  253        * @param servlet ActionServlet that is managing all the modules
  254        *  in this web application.
  255        * @param config ModuleConfig for the module with which
  256        *  this plugin is associated.
  257        * @exception ServletException if this <code>PlugIn</code> cannot
  258        *  be successfully initialized.
  259        */
  260       protected DefinitionsFactoryConfig readFactoryConfig(
  261           ActionServlet servlet,
  262           ModuleConfig config)
  263           throws ServletException {
  264               
  265           // Create tiles definitions config object
  266           DefinitionsFactoryConfig factoryConfig = new DefinitionsFactoryConfig();
  267           // Get init parameters from web.xml files
  268           try {
  269               DefinitionsUtil.populateDefinitionsFactoryConfig(
  270                   factoryConfig,
  271                   servlet.getServletConfig());
  272                   
  273           } catch (Exception ex) {
  274               if (log.isDebugEnabled()){
  275                   log.debug("", ex);
  276               }
  277               ex.printStackTrace();
  278               throw new UnavailableException(
  279                   "Can't populate DefinitionsFactoryConfig class from 'web.xml': "
  280                       + ex.getMessage());
  281           }
  282           
  283           // Get init parameters from struts-config.xml
  284           try {
  285               Map strutsProperties = findStrutsPlugInConfigProperties(servlet, config);
  286               factoryConfig.populate(strutsProperties);
  287               
  288           } catch (Exception ex) {
  289               if (log.isDebugEnabled()) {
  290                   log.debug("", ex);
  291               }
  292                   
  293               throw new UnavailableException(
  294                   "Can't populate DefinitionsFactoryConfig class from '"
  295                       + config.getPrefix()
  296                       + "/struts-config.xml':"
  297                       + ex.getMessage());
  298           }
  299           
  300           return factoryConfig;
  301       }
  302   
  303       /**
  304        * Find original properties set in the Struts PlugInConfig object.
  305        * First, we need to find the index of this plugin. Then we retrieve the array of configs
  306        * and then the object for this plugin.
  307        * @param servlet ActionServlet that is managing all the modules
  308        *  in this web application.
  309        * @param config ModuleConfig for the module with which
  310        *  this plug in is associated.
  311        *
  312        * @exception ServletException if this <code>PlugIn</code> cannot
  313        *  be successfully initialized.
  314        */
  315       protected Map findStrutsPlugInConfigProperties(
  316           ActionServlet servlet,
  317           ModuleConfig config)
  318           throws ServletException {
  319               
  320           return currentPlugInConfigObject.getProperties();
  321       }
  322   
  323       /**
  324        * Set RequestProcessor to appropriate Tiles {@link RequestProcessor}.
  325        * First, check if a RequestProcessor is specified. If yes, check if it extends
  326        * the appropriate {@link TilesRequestProcessor} class. If not, set processor class to
  327        * TilesRequestProcessor.
  328        *
  329        * @param config ModuleConfig for the module with which
  330        *  this plugin is associated.
  331        * @throws ServletException On errors.
  332        */
  333       protected void initRequestProcessorClass(ModuleConfig config)
  334           throws ServletException {
  335               
  336           String tilesProcessorClassname = TilesRequestProcessor.class.getName();
  337           ControllerConfig ctrlConfig = config.getControllerConfig();
  338           String configProcessorClassname = ctrlConfig.getProcessorClass();
  339   
  340           // Check if specified classname exist
  341           Class configProcessorClass;
  342           try {
  343               configProcessorClass =
  344                   RequestUtils.applicationClass(configProcessorClassname);
  345                   
  346           } catch (ClassNotFoundException ex) {
  347               log.fatal(
  348                   "Can't set TilesRequestProcessor: bad class name '"
  349                       + configProcessorClassname
  350                       + "'.");
  351               throw new ServletException(ex);
  352           }
  353   
  354           // Check if it is the default request processor or Tiles one.
  355           // If true, replace by Tiles' one.
  356           if (configProcessorClassname.equals(RequestProcessor.class.getName())
  357               || configProcessorClassname.endsWith(tilesProcessorClassname)) {
  358                   
  359               ctrlConfig.setProcessorClass(tilesProcessorClassname);
  360               return;
  361           }
  362   
  363           // Check if specified request processor is compatible with Tiles.
  364           Class tilesProcessorClass = TilesRequestProcessor.class;
  365           if (!tilesProcessorClass.isAssignableFrom(configProcessorClass)) {
  366               // Not compatible
  367               String msg =
  368                   "TilesPlugin : Specified RequestProcessor not compatible with TilesRequestProcessor";
  369               if (log.isFatalEnabled()) {
  370                   log.fatal(msg);
  371               }
  372               throw new ServletException(msg);
  373           }
  374       }
  375   
  376       /**
  377        * Set Tiles util implemention classname.
  378        * If this property is set, the flag <code>moduleAware</code> will not be used anymore.
  379        * @param tilesUtilImplClassname Classname.
  380        */
  381       public void setTilesUtilImplClassname(String tilesUtilImplClassname) {
  382           this.tilesUtilImplClassname = tilesUtilImplClassname;
  383       }
  384       
  385       /**
  386        * Get Tiles util implemention classname.
  387        * @return The classname or <code>null</code> if none is set.
  388        */
  389       public String getTilesUtilImplClassname() {
  390           return tilesUtilImplClassname;
  391       }
  392   
  393       /**
  394        * Method used by the ActionServlet initializing this plugin.
  395        * Set the plugin config object read from module config.
  396        * @param plugInConfigObject PlugInConfig.
  397        */
  398       public void setCurrentPlugInConfigObject(PlugInConfig plugInConfigObject) {
  399           this.currentPlugInConfigObject = plugInConfigObject;
  400       }
  401   
  402   }

Home » Struts-1.3.10 » org.apache.struts » tiles » [javadoc | source]