Coverage report

  %line %branch
org.apache.turbine.Turbine
41% 
83% 

 1  
 package org.apache.turbine;
 2  
 
 3  
 /*
 4  
  * Copyright 2001-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  
 import java.io.File;
 20  
 import java.io.FileInputStream;
 21  
 import java.io.FileNotFoundException;
 22  
 import java.io.IOException;
 23  
 import java.util.Properties;
 24  
 
 25  
 import javax.servlet.ServletConfig;
 26  
 import javax.servlet.ServletContext;
 27  
 import javax.servlet.ServletException;
 28  
 import javax.servlet.http.HttpServlet;
 29  
 import javax.servlet.http.HttpServletRequest;
 30  
 import javax.servlet.http.HttpServletResponse;
 31  
 
 32  
 import org.apache.commons.configuration.Configuration;
 33  
 import org.apache.commons.configuration.ConfigurationFactory;
 34  
 import org.apache.commons.configuration.PropertiesConfiguration;
 35  
 
 36  
 import org.apache.commons.lang.StringUtils;
 37  
 
 38  
 import org.apache.commons.lang.exception.ExceptionUtils;
 39  
 
 40  
 import org.apache.commons.logging.Log;
 41  
 import org.apache.commons.logging.LogFactory;
 42  
 
 43  
 import org.apache.log4j.PropertyConfigurator;
 44  
 
 45  
 import org.apache.turbine.modules.ActionLoader;
 46  
 import org.apache.turbine.modules.PageLoader;
 47  
 
 48  
 import org.apache.turbine.services.ServiceManager;
 49  
 import org.apache.turbine.services.TurbineServices;
 50  
 import org.apache.turbine.services.avaloncomponent.AvalonComponentService;
 51  
 import org.apache.turbine.services.component.ComponentService;
 52  
 import org.apache.turbine.services.template.TemplateService;
 53  
 import org.apache.turbine.services.template.TurbineTemplate;
 54  
 import org.apache.turbine.services.rundata.RunDataService;
 55  
 import org.apache.turbine.services.rundata.TurbineRunDataFacade;
 56  
 import org.apache.turbine.services.velocity.VelocityService;
 57  
 
 58  
 import org.apache.turbine.util.RunData;
 59  
 import org.apache.turbine.util.ServerData;
 60  
 import org.apache.turbine.util.TurbineConfig;
 61  
 import org.apache.turbine.util.TurbineException;
 62  
 import org.apache.turbine.util.security.AccessControlList;
 63  
 import org.apache.turbine.util.template.TemplateInfo;
 64  
 import org.apache.turbine.util.uri.URIConstants;
 65  
 
 66  
 /**
 67  
  * Turbine is the main servlet for the entire system. It is <code>final</code>
 68  
  * because you should <i>not</i> ever need to subclass this servlet.  If you
 69  
  * need to perform initialization of a service, then you should implement the
 70  
  * Services API and let your code be initialized by it.
 71  
  * If you need to override something in the <code>doGet()</code> or
 72  
  * <code>doPost()</code> methods, edit the TurbineResources.properties file and
 73  
  * specify your own classes there.
 74  
  * <p>
 75  
  * Turbine servlet recognizes the following initialization parameters.
 76  
  * <ul>
 77  
  * <li><code>properties</code> the path to TurbineResources.properties file
 78  
  * used by the default implementation of <code>ResourceService</code>, relative
 79  
  * to the application root.</li>
 80  
  * <li><code>basedir</code> this parameter is used <strong>only</strong> if your
 81  
  * application server does not support web applications, or the or does not
 82  
  * support <code>ServletContext.getRealPath(String)</code> method correctly.
 83  
  * You can use this parameter to specify the directory within the server's
 84  
  * filesystem, that is the base of your web application.</li>
 85  
  * </ul>
 86  
  *
 87  
  * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
 88  
  * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
 89  
  * @author <a href="mailto:greg@shwoop.com">Greg Ritter</a>
 90  
  * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
 91  
  * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
 92  
  * @author <a href="mailto:krzewski@e-point.pl">Rafal Krzewski</a>
 93  
  * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
 94  
  * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
 95  
  * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
 96  
  * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 97  
  * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
 98  
  * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
 99  
  * @version $Id: Turbine.java,v 1.45.2.3 2004/08/16 23:31:59 henning Exp $
 100  
  */
 101  19
 public class Turbine
 102  
         extends HttpServlet
 103  
         implements TurbineConstants
 104  
 {
 105  
     /**
 106  
      * Name of path info parameter used to indicate the redirected stage of
 107  
      * a given user's initial Turbine request
 108  
      */
 109  
     public static final String REDIRECTED_PATHINFO_NAME = "redirected";
 110  
 
 111  
     /** The base directory key */
 112  
     public static final String BASEDIR_KEY = "basedir";
 113  
 
 114  
     /**
 115  
      * In certain situations the init() method is called more than once,
 116  
      * somtimes even concurrently. This causes bad things to happen,
 117  
      * so we use this flag to prevent it.
 118  
      */
 119  19
     private static boolean firstInit = true;
 120  
 
 121  
     /** Whether init succeeded or not. */
 122  19
     private static Throwable initFailure = null;
 123  
 
 124  
     /**
 125  
      * Should initialization activities be performed during doGet() execution?
 126  
      */
 127  19
     private static boolean firstDoGet = true;
 128  
 
 129  
     /**
 130  
      * Keep all the properties of the web server in a convenient data
 131  
      * structure
 132  
      */
 133  19
     private static ServerData serverData = null;
 134  
 
 135  
     /** The base from which the Turbine application will operate. */
 136  
     private static String applicationRoot;
 137  
 
 138  
     /** Servlet config for this Turbine webapp. */
 139  
     private static ServletConfig servletConfig;
 140  
 
 141  
     /** Servlet context for this Turbine webapp. */
 142  
     private static ServletContext servletContext;
 143  
 
 144  
     /**
 145  
      * The webapp root where the Turbine application
 146  
      * is running in the servlet container.
 147  
      * This might differ from the application root.
 148  
      */
 149  
     private static String webappRoot;
 150  
 
 151  
     /** Our internal configuration object */
 152  19
     private static Configuration configuration = null;
 153  
 
 154  
     /** A reference to the Template Service */
 155  19
     private TemplateService templateService = null;
 156  
 
 157  
     /** A reference to the RunData Service */
 158  19
     private RunDataService rundataService = null;
 159  
 
 160  
     /** Logging class from commons.logging */
 161  38
     private static Log log = LogFactory.getLog(Turbine.class);
 162  
 
 163  
     /**
 164  
      * This init method will load the default resources from a
 165  
      * properties file.
 166  
      *
 167  
      * This method is called by init(ServletConfig config)
 168  
      *
 169  
      * @exception ServletException a servlet exception.
 170  
      */
 171  
     public final void init() throws ServletException
 172  
     {
 173  18
         synchronized (this.getClass())
 174  
         {
 175  18
             super.init();
 176  18
             ServletConfig config = getServletConfig();
 177  
 
 178  18
             if (!firstInit)
 179  
             {
 180  0
                 log.info("Double initialization of Turbine was attempted!");
 181  0
                 return;
 182  
             }
 183  
             // executing init will trigger some static initializers, so we have
 184  
             // only one chance.
 185  18
             firstInit = false;
 186  
 
 187  
             try
 188  
             {
 189  18
                 ServletContext context = config.getServletContext();
 190  
 
 191  18
                 configure(config, context);
 192  
 
 193  18
                 templateService = TurbineTemplate.getService();
 194  18
                 rundataService = TurbineRunDataFacade.getService();
 195  
 
 196  18
                 if (rundataService == null)
 197  
                 {
 198  0
                     throw new TurbineException(
 199  
                             "No RunData Service configured!");
 200  
                 }
 201  
 
 202  
             }
 203  0
             catch (Exception e)
 204  
             {
 205  
                 // save the exception to complain loudly later :-)
 206  0
                 initFailure = e;
 207  0
                 log.fatal("Turbine: init() failed: ", e);
 208  0
                 throw new ServletException("Turbine: init() failed", e);
 209  18
             }
 210  18
             log.info("Turbine: init() Ready to Rumble!");
 211  18
         }
 212  18
     }
 213  
 
 214  
     /**
 215  
      * Read the master configuration file in, configure logging
 216  
      * and start up any early services.
 217  
      *
 218  
      * @param config The Servlet Configuration supplied by the container
 219  
      * @param context The Servlet Context supplied by the container
 220  
      *
 221  
      * @throws Exception A problem occured while reading the configuration or performing early startup
 222  
      */
 223  
 
 224  
     private void configure(ServletConfig config, ServletContext context)
 225  
             throws Exception
 226  
     {
 227  
         // Set the application root. This defaults to the webapp
 228  
         // context if not otherwise set. This is to allow 2.1 apps
 229  
         // to be developed from CVS. This feature will carry over
 230  
         // into 3.0.
 231  18
         applicationRoot = findInitParameter(context, config,
 232  
                 APPLICATION_ROOT_KEY,
 233  
                 APPLICATION_ROOT_DEFAULT);
 234  
 
 235  18
         webappRoot = config.getServletContext().getRealPath("/");
 236  
         // log.info("Web Application root is " + webappRoot);
 237  
         // log.info("Application root is "     + applicationRoot);
 238  
 
 239  18
         if (applicationRoot == null || applicationRoot.equals(WEB_CONTEXT))
 240  
         {
 241  18
             applicationRoot = webappRoot;
 242  
             // log.info("got empty or 'webContext' Application root. Application root now: " + applicationRoot);
 243  
         }
 244  
 
 245  
         // Set the applicationRoot for this webapp.
 246  18
         setApplicationRoot(applicationRoot);
 247  
 
 248  
         // Create any directories that need to be setup for
 249  
         // a running Turbine application.
 250  18
         createRuntimeDirectories(context, config);
 251  
 
 252  
         //
 253  
         // Now we run the Turbine configuration code. There are two ways
 254  
         // to configure Turbine:
 255  
         //
 256  
         // a) By supplying an web.xml init parameter called "configuration"
 257  
         //
 258  
         // <init-param>
 259  
         //   <param-name>configuration</param-name>
 260  
         //   <param-value>/WEB-INF/conf/turbine.xml</param-value>
 261  
         // </init-param>
 262  
         //
 263  
         // This loads an XML based configuration file.
 264  
         //
 265  
         // b) By supplying an web.xml init parameter called "properties"
 266  
         //
 267  
         // <init-param>
 268  
         //   <param-name>properties</param-name>
 269  
         //   <param-value>/WEB-INF/conf/TurbineResources.properties</param-value>
 270  
         // </init-param>
 271  
         //
 272  
         // This loads a Properties based configuration file. Actually, these are
 273  
         // extended properties as provided by commons-configuration
 274  
         //
 275  
         // If neither a) nor b) is supplied, Turbine will fall back to the
 276  
         // known behaviour of loading a properties file called
 277  
         // /WEB-INF/conf/TurbineResources.properties relative to the
 278  
         // web application root.
 279  
 
 280  18
         String confFile= findInitParameter(context, config, 
 281  
                 TurbineConfig.CONFIGURATION_PATH_KEY, 
 282  
                 null);
 283  
 
 284  
         String confPath;
 285  18
         String confStyle = "unset";
 286  
 
 287  18
         if (StringUtils.isNotEmpty(confFile))
 288  
         {
 289  1
             confPath = getRealPath(confFile);
 290  1
             ConfigurationFactory configurationFactory = new ConfigurationFactory(confPath);
 291  1
             configurationFactory.setBasePath(getApplicationRoot());
 292  1
             configuration = configurationFactory.getConfiguration();
 293  1
             confStyle = "XML";
 294  
         }
 295  
         else
 296  
         {
 297  17
             confFile = findInitParameter(context, config,
 298  
                     TurbineConfig.PROPERTIES_PATH_KEY,
 299  
                     TurbineConfig.PROPERTIES_PATH_DEFAULT);
 300  
 
 301  17
             confPath = getRealPath(confFile);
 302  
 
 303  
             // This should eventually be a Configuration
 304  
             // interface so that service and app configuration
 305  
             // can be stored anywhere.
 306  17
             configuration = (Configuration) new PropertiesConfiguration(confPath);
 307  17
             confStyle = "Properties";
 308  
         }
 309  
 
 310  
 
 311  
         //
 312  
         // Set up logging as soon as possible
 313  
         //
 314  18
         String log4jFile = configuration.getString(LOG4J_CONFIG_FILE,
 315  
                                                    LOG4J_CONFIG_FILE_DEFAULT);
 316  
 
 317  18
         if (StringUtils.isNotEmpty(log4jFile) &&
 318  
                 !log4jFile.equalsIgnoreCase("none"))
 319  
         {
 320  18
             log4jFile = getRealPath(log4jFile);
 321  
 
 322  
             //
 323  
             // Load the config file above into a Properties object and
 324  
             // fix up the Application root
 325  
             //
 326  18
             Properties p = new Properties();
 327  
             try
 328  
             {
 329  18
                 p.load(new FileInputStream(log4jFile));
 330  18
                 p.setProperty(APPLICATION_ROOT_KEY, getApplicationRoot());
 331  18
                 PropertyConfigurator.configure(p);
 332  
             
 333  18
                 log.info("Configured log4j from " + log4jFile);
 334  
             }
 335  0
             catch (FileNotFoundException fnf)
 336  
             {
 337  0
                 System.err.println("Could not open Log4J configuration file "
 338  
                         + log4jFile + ": ");
 339  0
                 fnf.printStackTrace();
 340  18
             }
 341  
         }
 342  
 
 343  
         // Now report our successful configuration to the world
 344  18
         log.info("Loaded configuration  (" + confStyle + ") from " + confFile + " (" + confPath + ")");
 345  
 
 346  
         
 347  18
         setTurbineServletConfig(config);
 348  18
         setTurbineServletContext(context);
 349  
 
 350  18
         getServiceManager().setApplicationRoot(applicationRoot);
 351  
 
 352  
         // We want to set a few values in the configuration so
 353  
         // that ${variable} interpolation will work for
 354  
         //
 355  
         // ${applicationRoot}
 356  
         // ${webappRoot}
 357  18
         configuration.setProperty(APPLICATION_ROOT_KEY, applicationRoot);
 358  18
         configuration.setProperty(WEBAPP_ROOT_KEY, webappRoot);
 359  
 
 360  
 
 361  
         //
 362  
         // Be sure, that our essential services get run early
 363  
         //
 364  18
         configuration.setProperty(TurbineServices.SERVICE_PREFIX +
 365  
                                   ComponentService.SERVICE_NAME + ".earlyInit",
 366  
                                   Boolean.TRUE);
 367  
 
 368  18
         configuration.setProperty(TurbineServices.SERVICE_PREFIX +
 369  
                                   AvalonComponentService.SERVICE_NAME + ".earlyInit",
 370  
                                   Boolean.TRUE);
 371  
 
 372  18
         getServiceManager().setConfiguration(configuration);
 373  
 
 374  
         // Initialize the service manager. Services
 375  
         // that have its 'earlyInit' property set to
 376  
         // a value of 'true' will be started when
 377  
         // the service manager is initialized.
 378  18
         getServiceManager().init();
 379  18
     }
 380  
 
 381  
     /**
 382  
      * Create any directories that might be needed during
 383  
      * runtime. Right now this includes:
 384  
      *
 385  
      * <ul>
 386  
      *
 387  
      * <li>The directory to write the log files to (relative to the
 388  
      * web application root), or <code>null</code> for the default of
 389  
      * <code>/logs</code>.  The directory is specified via the {@link
 390  
      * TurbineConstants#LOGGING_ROOT} parameter.</li>
 391  
      *
 392  
      * </ul>
 393  
      *
 394  
      * @param context Global initialization parameters.
 395  
      * @param config Initialization parameters specific to the Turbine
 396  
      * servlet.
 397  
      */
 398  
     private static void createRuntimeDirectories(ServletContext context,
 399  
                                                  ServletConfig config)
 400  
     {
 401  18
         String path = findInitParameter(context, config,
 402  
                                         LOGGING_ROOT_KEY,
 403  
                                         LOGGING_ROOT_DEFAULT);
 404  
 
 405  18
         File logDir = new File(getRealPath(path));
 406  18
         if (!logDir.exists())
 407  
         {
 408  
             // Create the logging directory
 409  0
             if (!logDir.mkdirs())
 410  
             {
 411  0
                 System.err.println("Cannot create directory for logs!");
 412  
             }
 413  
         }
 414  18
     }
 415  
 
 416  
     /**
 417  
      * Finds the specified servlet configuration/initialization
 418  
      * parameter, looking first for a servlet-specific parameter, then
 419  
      * for a global parameter, and using the provided default if not
 420  
      * found.
 421  
      */
 422  
     protected static final String findInitParameter(ServletContext context,
 423  
             ServletConfig config, String name, String defaultValue)
 424  
     {
 425  73
         String path = null;
 426  
 
 427  
         // Try the name as provided first.
 428  73
         boolean usingNamespace = name.startsWith(CONFIG_NAMESPACE);
 429  
         while (true)
 430  
         {
 431  113
             path = config.getInitParameter(name);
 432  113
             if (StringUtils.isEmpty(path))
 433  
             {
 434  80
                 path = context.getInitParameter(name);
 435  80
                 if (StringUtils.isEmpty(path))
 436  
                 {
 437  
                     // The named parameter didn't yield a value.
 438  80
                     if (usingNamespace)
 439  
                     {
 440  40
                         path = defaultValue;
 441  
                     }
 442  
                     else
 443  
                     {
 444  
                         // Try again using Turbine's namespace.
 445  40
                         name = CONFIG_NAMESPACE + '.' + name;
 446  40
                         usingNamespace = true;
 447  40
                         continue;
 448  
                     }
 449  
                 }
 450  
             }
 451  
             break;
 452  
         }
 453  
 
 454  73
         return path;
 455  
     }
 456  
 
 457  
     /**
 458  
      * Initializes the services which need <code>RunData</code> to
 459  
      * initialize themselves (post startup).
 460  
      *
 461  
      * @param data The first <code>GET</code> request.
 462  
      */
 463  
     public final void init(RunData data)
 464  
     {
 465  0
         synchronized (Turbine.class)
 466  
         {
 467  0
             if (firstDoGet)
 468  
             {
 469  
                 // All we want to do here is save some servlet
 470  
                 // information so that services and processes
 471  
                 // that don't have direct access to a RunData
 472  
                 // object can still know something about
 473  
                 // the servlet environment.
 474  0
                 saveServletInfo(data);
 475  
 
 476  
                 // Mark that we're done.
 477  0
                 firstDoGet = false;
 478  0
                 log.info("Turbine: first Request successful");
 479  
             }
 480  0
         }
 481  0
     }
 482  
 
 483  
     /**
 484  
      * Return the current configuration with all keys included
 485  
      *
 486  
      * @return a Configuration Object
 487  
      */
 488  
     public static Configuration getConfiguration()
 489  
     {
 490  246
         return configuration;
 491  
     }
 492  
 
 493  
     /**
 494  
      * Return the server name.
 495  
      *
 496  
      * @return String server name
 497  
      */
 498  
     public static String getServerName()
 499  
     {
 500  0
         return getDefaultServerData().getServerName();
 501  
     }
 502  
 
 503  
     /**
 504  
      * Return the server scheme.
 505  
      *
 506  
      * @return String server scheme
 507  
      */
 508  
     public static String getServerScheme()
 509  
     {
 510  0
         return getDefaultServerData().getServerScheme();
 511  
     }
 512  
 
 513  
     /**
 514  
      * Return the server port.
 515  
      *
 516  
      * @return String server port
 517  
      */
 518  
     public static String getServerPort()
 519  
     {
 520  0
         return Integer.toString(getDefaultServerData().getServerPort());
 521  
     }
 522  
 
 523  
     /**
 524  
      * Get the script name. This is the initial script name.
 525  
      * Actually this is probably not needed any more. I'll
 526  
      * check. jvz.
 527  
      *
 528  
      * @return String initial script name.
 529  
      */
 530  
     public static String getScriptName()
 531  
     {
 532  0
         return getDefaultServerData().getScriptName();
 533  
     }
 534  
 
 535  
     /**
 536  
      * Return the context path.
 537  
      *
 538  
      * @return String context path
 539  
      */
 540  
     public static String getContextPath()
 541  
     {
 542  0
         return getDefaultServerData().getContextPath();
 543  
     }
 544  
 
 545  
     /**
 546  
      * Return all the Turbine Servlet information (Server Name, Port,
 547  
      * Scheme in a ServerData structure. This is generated from the
 548  
      * values set when initializing the Turbine and may not be correct
 549  
      * if you're running in a clustered structure. This might be used
 550  
      * if you need a DataURI and have no RunData object handy-
 551  
      *
 552  
      * @return An initialized ServerData object
 553  
      */
 554  
     public static ServerData getDefaultServerData()
 555  
     {
 556  0
         if(serverData == null)
 557  
         {
 558  0
             log.error("ServerData Information requested from Turbine before first request!");
 559  
             // Will be overwritten once the first request is run;
 560  0
             serverData = new ServerData(null, URIConstants.HTTP_PORT,
 561  
                     URIConstants.HTTP, null, class="keyword">null);
 562  
         }
 563  0
         return serverData;
 564  
     }
 565  
 
 566  
     /**
 567  
      * Set the servlet config for this turbine webapp.
 568  
      *
 569  
      * @param config New servlet config
 570  
      */
 571  
     public static void setTurbineServletConfig(ServletConfig config)
 572  
     {
 573  18
         servletConfig = config;
 574  18
     }
 575  
 
 576  
     /**
 577  
      * Get the servlet config for this turbine webapp.
 578  
      *
 579  
      * @return ServletConfig
 580  
      */
 581  
     public static ServletConfig getTurbineServletConfig()
 582  
     {
 583  1
         return servletConfig;
 584  
     }
 585  
 
 586  
     /**
 587  
      * Set the servlet context for this turbine webapp.
 588  
      *
 589  
      * @param context New servlet context.
 590  
      */
 591  
     public static void setTurbineServletContext(ServletContext context)
 592  
     {
 593  18
         servletContext = context;
 594  18
     }
 595  
 
 596  
     /**
 597  
      * Get the servlet context for this turbine webapp.
 598  
      *
 599  
      * @return ServletContext
 600  
      */
 601  
     public static ServletContext getTurbineServletContext()
 602  
     {
 603  0
         return servletContext;
 604  
     }
 605  
 
 606  
     /**
 607  
      * The <code>Servlet</code> destroy method.  Invokes
 608  
      * <code>ServiceBroker</code> tear down method.
 609  
      */
 610  
     public final void destroy()
 611  
     {
 612  
         // Shut down all Turbine Services.
 613  5
         getServiceManager().shutdownServices();
 614  5
         System.gc();
 615  
 
 616  5
         firstInit = true;
 617  5
         firstDoGet = true;
 618  5
         log.info("Turbine: Done shutting down!");
 619  5
     }
 620  
 
 621  
     /**
 622  
      * The primary method invoked when the Turbine servlet is executed.
 623  
      *
 624  
      * @param req Servlet request.
 625  
      * @param res Servlet response.
 626  
      * @exception IOException a servlet exception.
 627  
      * @exception ServletException a servlet exception.
 628  
      */
 629  
     public final void doGet(HttpServletRequest req, HttpServletResponse res)
 630  
             throws IOException, ServletException
 631  
     {
 632  
         // set to true if the request is to be redirected by the page
 633  0
         boolean requestRedirected = false;
 634  
 
 635  
         // Placeholder for the RunData object.
 636  0
         RunData data = null;
 637  
         try
 638  
         {
 639  
             // Check to make sure that we started up properly.
 640  0
             if (initFailure != null)
 641  
             {
 642  0
                 throw initFailure;
 643  
             }
 644  
 
 645  
             // Get general RunData here...
 646  
             // Perform turbine specific initialization below.
 647  0
             data = rundataService.getRunData(req, res, getServletConfig());
 648  
 
 649  
             // If this is the first invocation, perform some
 650  
             // initialization.  Certain services need RunData to initialize
 651  
             // themselves.
 652  0
             if (firstDoGet)
 653  
             {
 654  0
                 init(data);
 655  
             }
 656  
 
 657  
             // set the session timeout if specified in turbine's properties
 658  
             // file if this is a new session
 659  0
             if (data.getSession().isNew())
 660  
             {
 661  0
                 int timeout = configuration.getInt(SESSION_TIMEOUT_KEY,
 662  
                                                    SESSION_TIMEOUT_DEFAULT);
 663  
 
 664  0
                 if (timeout != SESSION_TIMEOUT_DEFAULT)
 665  
                 {
 666  0
                     data.getSession().setMaxInactiveInterval(timeout);
 667  
                 }
 668  
             }
 669  
 
 670  
             // Fill in the screen and action variables.
 671  0
             data.setScreen(data.getParameters().getString(URIConstants.CGI_SCREEN_PARAM));
 672  0
             data.setAction(data.getParameters().getString(URIConstants.CGI_ACTION_PARAM));
 673  
 
 674  
             // Special case for login and logout, this must happen before the
 675  
             // session validator is executed in order either to allow a user to
 676  
             // even login, or to ensure that the session validator gets to
 677  
             // mandate its page selection policy for non-logged in users
 678  
             // after the logout has taken place.
 679  0
             if (data.hasAction())
 680  
             {
 681  0
                 String action = data.getAction();
 682  0
                 log.debug("action = " + action);
 683  
 
 684  0
                 if (action.equalsIgnoreCase(
 685  
                         configuration.getString(ACTION_LOGIN_KEY,
 686  
                                                 ACTION_LOGIN_DEFAULT)))
 687  
                 {
 688  0
                     loginAction(data);
 689  
                 }
 690  0
                 else if (action.equalsIgnoreCase(
 691  
                         configuration.getString(ACTION_LOGOUT_KEY,
 692  
                                                 ACTION_LOGOUT_DEFAULT)))
 693  
                 {
 694  0
                    logoutAction(data);
 695  
                 }
 696  
             }
 697  
 
 698  
             // This is where the validation of the Session information
 699  
             // is performed if the user has not logged in yet, then
 700  
             // the screen is set to be Login. This also handles the
 701  
             // case of not having a screen defined by also setting the
 702  
             // screen to Login. If you want people to go to another
 703  
             // screen other than Login, you need to change that within
 704  
             // TurbineResources.properties...screen.homepage; or, you
 705  
             // can specify your own SessionValidator action.
 706  0
             ActionLoader.getInstance().exec(
 707  
                     data, configuration.getString(ACTION_SESSION_VALIDATOR_KEY,
 708  
                         ACTION_SESSION_VALIDATOR_DEFAULT));
 709  
 
 710  
             // Put the Access Control List into the RunData object, so
 711  
             // it is easily available to modules.  It is also placed
 712  
             // into the session for serialization.  Modules can null
 713  
             // out the ACL to force it to be rebuilt based on more
 714  
             // information.
 715  0
             ActionLoader.getInstance().exec(
 716  
                     data, configuration.getString(ACTION_ACCESS_CONTROLLER_KEY,
 717  
                         ACTION_ACCESS_CONTROLLER_DEFAULT));
 718  
 
 719  
             // Start the execution phase. DefaultPage will execute the
 720  
             // appropriate action as well as get the Layout from the
 721  
             // Screen and then execute that. The Layout is then
 722  
             // responsible for executing the Navigation and Screen
 723  
             // modules.
 724  
             //
 725  
             // Note that by default, this cannot be overridden from
 726  
             // parameters passed in via post/query data. This is for
 727  
             // security purposes.  You should really never need more
 728  
             // than just the default page.  If you do, add logic to
 729  
             // DefaultPage to do what you want.
 730  
 
 731  0
             String defaultPage = (templateService == null)
 732  
                     ? null :templateService.getDefaultPageName(data);
 733  
 
 734  0
             if (defaultPage == null)
 735  
             {
 736  
                 /*
 737  
                  * In this case none of the template services are running.
 738  
                  * The application may be using ECS for views, or a
 739  
                  * decendent of RawScreen is trying to produce output.
 740  
                  * If there is a 'page.default' property in the TR.props
 741  
                  * then use that, otherwise return DefaultPage which will
 742  
                  * handle ECS view scenerios and RawScreen scenerios. The
 743  
                  * app developer can still specify the 'page.default'
 744  
                  * if they wish but the DefaultPage should work in
 745  
                  * most cases.
 746  
                  */
 747  0
                 defaultPage = configuration.getString(PAGE_DEFAULT_KEY,
 748  
                         PAGE_DEFAULT_DEFAULT);
 749  
             }
 750  
 
 751  0
             PageLoader.getInstance().exec(data, defaultPage);
 752  
 
 753  
             // If a module has set data.acl = null, remove acl from
 754  
             // the session.
 755  0
             if (data.getACL() == null)
 756  
             {
 757  
                 try
 758  
                 {
 759  0
                     data.getSession().removeAttribute(
 760  
                             AccessControlList.SESSION_KEY);
 761  
                 }
 762  0
                 catch (IllegalStateException ignored)
 763  
                 {
 764  0
                 }
 765  
             }
 766  
 
 767  
             // handle a redirect request
 768  0
             requestRedirected = ((data.getRedirectURI() != null)
 769  
                                  && (data.getRedirectURI().length() > 0));
 770  0
             if (requestRedirected)
 771  
             {
 772  0
                 if (data.getResponse().isCommitted())
 773  
                 {
 774  0
                     requestRedirected = false;
 775  0
                     log.warn("redirect requested, response already committed: " +
 776  
                              data.getRedirectURI());
 777  
                 }
 778  
                 else
 779  
                 {
 780  0
                     data.getResponse().sendRedirect(data.getRedirectURI());
 781  
                 }
 782  
             }
 783  
 
 784  0
             if (!requestRedirected)
 785  
             {
 786  
                 try
 787  
                 {
 788  0
                     if (data.isPageSet() == false && data.isOutSet() == false)
 789  
                     {
 790  0
                         throw new Exception("Nothing to output");
 791  
                     }
 792  
 
 793  
                     // We are all done! if isPageSet() output that way
 794  
                     // otherwise, data.getOut() has already been written
 795  
                     // to the data.getOut().close() happens below in the
 796  
                     // finally.
 797  0
                     if (data.isPageSet() && data.isOutSet() == false)
 798  
                     {
 799  
                         // Modules can override these.
 800  0
                         data.getResponse().setLocale(data.getLocale());
 801  0
                         data.getResponse().setContentType(
 802  
                                 data.getContentType());
 803  
 
 804  
                         // Set the status code.
 805  0
                         data.getResponse().setStatus(data.getStatusCode());
 806  
                         // Output the Page.
 807  0
                         data.getPage().output(data.getOut());
 808  
                     }
 809  
                 }
 810  0
                 catch (Exception e)
 811  
                 {
 812  
                     // The output stream was probably closed by the client
 813  
                     // end of things ie: the client clicked the Stop
 814  
                     // button on the browser, so ignore any errors that
 815  
                     // result.
 816  0
                     log.debug("Output stream closed? ", e);
 817  0
                 }
 818  
             }
 819  
         }
 820  0
         catch (Exception e)
 821  
         {
 822  0
             handleException(data, res, e);
 823  
         }
 824  0
         catch (Throwable t)
 825  
         {
 826  0
             handleException(data, res, t);
 827  
         }
 828  
         finally
 829  
         {
 830  
             // Return the used RunData to the factory for recycling.
 831  0
             rundataService.putRunData(data);
 832  0
         }
 833  0
     }
 834  
 
 835  
     /**
 836  
      * In this application doGet and doPost are the same thing.
 837  
      *
 838  
      * @param req Servlet request.
 839  
      * @param res Servlet response.
 840  
      * @exception IOException a servlet exception.
 841  
      * @exception ServletException a servlet exception.
 842  
      */
 843  
     public final void doPost(HttpServletRequest req, HttpServletResponse res)
 844  
             throws IOException, ServletException
 845  
     {
 846  0
         doGet(req, res);
 847  0
     }
 848  
 
 849  
     /**
 850  
      * This method is executed if the configured Login action should be
 851  
      * executed by Turbine.
 852  
      * <p>
 853  
      * This Action must be performed before the Session validation or we
 854  
      * get sent in an endless loop back to the Login screen before
 855  
      * the action can be performed
 856  
      *
 857  
      * @param data a RunData object
 858  
      *
 859  
      * @throws Exception A problem while logging in occured.
 860  
      */
 861  
     private void loginAction(RunData data)
 862  
             throws Exception
 863  
     {
 864  0
         ActionLoader.getInstance().exec(data, data.getAction());
 865  0
         cleanupTemplateContext(data);
 866  0
         data.setAction(null);
 867  0
     }
 868  
 
 869  
     /**
 870  
      * This method is executed if the configured Logout action should be
 871  
      * executed by Turbine.
 872  
      * <p>
 873  
      * This Action must be performed before the Session validation for the
 874  
      * session validator to send us back to the Login screen.
 875  
      * <p>
 876  
      * The existing session is invalidated before the logout action is
 877  
      * executed.
 878  
      *
 879  
      * @param data a RunData object
 880  
      *
 881  
      * @throws Exception A problem while logging out occured.
 882  
      */
 883  
     private void logoutAction(RunData data)
 884  
             throws Exception
 885  
     {
 886  0
         ActionLoader.getInstance().exec(data, data.getAction());
 887  0
         cleanupTemplateContext(data);
 888  0
         data.setAction(null);
 889  0
         data.getSession().invalidate();
 890  0
     }
 891  
 
 892  
     /**
 893  
      * cleans the Velocity Context if available.
 894  
      *
 895  
      * @param data A RunData Object
 896  
      *
 897  
      * @throws Exception A problem while cleaning out the Template Context occured.
 898  
      */
 899  
     private void cleanupTemplateContext(RunData data)
 900  
             throws Exception
 901  
     {
 902  
         // This is Velocity specific and shouldn't be done here.
 903  
         // But this is a band aid until we get real listeners
 904  
         // here.
 905  0
         TemplateInfo ti = data.getTemplateInfo();
 906  0
         if (ti != null)
 907  
         {
 908  0
             ti.removeTemp(VelocityService.CONTEXT);
 909  
         }
 910  0
     }
 911  
 
 912  
     /**
 913  
      * Return the servlet info.
 914  
      *
 915  
      * @return a string with the servlet information.
 916  
      */
 917  
     public final String getServletInfo()
 918  
     {
 919  0
         return "Turbine Servlet";
 920  
     }
 921  
 
 922  
     /**
 923  
      * This method is about making sure that we catch and display
 924  
      * errors to the screen in one fashion or another. What happens is
 925  
      * that it will attempt to show the error using your user defined
 926  
      * Error Screen. If that fails, then it will resort to just
 927  
      * displaying the error and logging it all over the place
 928  
      * including the servlet engine log file, the Turbine log file and
 929  
      * on the screen.
 930  
      *
 931  
      * @param data A Turbine RunData object.
 932  
      * @param res Servlet response.
 933  
      * @param t The exception to report.
 934  
      */
 935  
     private final void handleException(RunData data, HttpServletResponse res,
 936  
                                        Throwable t)
 937  
     {
 938  
         // make sure that the stack trace makes it the log
 939  0
         log.error("Turbine.handleException: ", t);
 940  
 
 941  0
         String mimeType = "text/plain";
 942  
         try
 943  
         {
 944  
             // This is where we capture all exceptions and show the
 945  
             // Error Screen.
 946  0
             data.setStackTrace(ExceptionUtils.getStackTrace(t), t);
 947  
 
 948  
             // setup the screen
 949  0
             data.setScreen(configuration.getString(SCREEN_ERROR_KEY,
 950  
                     SCREEN_ERROR_DEFAULT));
 951  
 
 952  
             // do more screen setup for template execution if needed
 953  0
             if (data.getTemplateInfo() != null)
 954  
             {
 955  0
                 data.getTemplateInfo()
 956  
                     .setScreenTemplate(configuration.getString(
 957  
                             TEMPLATE_ERROR_KEY, TEMPLATE_ERROR_VM));
 958  
             }
 959  
 
 960  
             // Make sure to not execute an action.
 961  0
             data.setAction("");
 962  
 
 963  0
             PageLoader.getInstance().exec(data,
 964  
                     configuration.getString(PAGE_DEFAULT_KEY,
 965  
                             PAGE_DEFAULT_DEFAULT));
 966  
 
 967  0
             data.getResponse().setContentType(data.getContentType());
 968  0
             data.getResponse().setStatus(data.getStatusCode());
 969  0
             if (data.isPageSet())
 970  
             {
 971  0
                 data.getOut().print(data.getPage().toString());
 972  
             }
 973  
         }
 974  
         // Catch this one because it occurs if some code hasn't been
 975  
         // completely re-compiled after a change..
 976  0
         catch (java.lang.NoSuchFieldError e)
 977  
         {
 978  
             try
 979  
             {
 980  0
                 data.getResponse().setContentType(mimeType);
 981  0
                 data.getResponse().setStatus(200);
 982  
             }
 983  0
             catch (Exception ignored)
 984  
             {
 985  0
             }
 986  
 
 987  
             try
 988  
             {
 989  0
                 data.getOut().print("java.lang.NoSuchFieldError: "
 990  
                         + "Please recompile all of your source code.");
 991  
             }
 992  0
             catch (IOException ignored)
 993  
             {
 994  0
             }
 995  
 
 996  0
             log.error(data.getStackTrace(), e);
 997  
         }
 998  
         // Attempt to do *something* at this point...
 999  0
         catch (Throwable reallyScrewedNow)
 1000  
         {
 1001  0
             StringBuffer msg = new StringBuffer();
 1002  0
             msg.append("Horrible Exception: ");
 1003  0
             if (data != null)
 1004  
             {
 1005  0
                 msg.append(data.getStackTrace());
 1006  
             }
 1007  
             else
 1008  
             {
 1009  0
                 msg.append(t);
 1010  
             }
 1011  
             try
 1012  
             {
 1013  0
                 res.setContentType(mimeType);
 1014  0
                 res.setStatus(200);
 1015  0
                 res.getWriter().print(msg.toString());
 1016  
             }
 1017  0
             catch (Exception ignored)
 1018  
             {
 1019  0
             }
 1020  
 
 1021  0
             log.error(reallyScrewedNow.getMessage(), reallyScrewedNow);
 1022  0
         }
 1023  0
     }
 1024  
 
 1025  
     /**
 1026  
      * Save some information about this servlet so that
 1027  
      * it can be utilized by object instances that do not
 1028  
      * have direct access to RunData.
 1029  
      *
 1030  
      * @param data
 1031  
      */
 1032  
     public static synchronized void saveServletInfo(RunData data)
 1033  
     {
 1034  
         // Store the context path for tools like ContentURI and
 1035  
         // the UIManager that use webapp context path information
 1036  
         // for constructing URLs.
 1037  
 
 1038  
         //
 1039  
         // Bundle all the information above up into a convenient structure
 1040  
         //
 1041  0
         serverData = (ServerData) data.getServerData().clone();
 1042  0
     }
 1043  
 
 1044  
     /**
 1045  
      * Set the application root for the webapp.
 1046  
      *
 1047  
      * @param val New app root.
 1048  
      */
 1049  
     public static void setApplicationRoot(String val)
 1050  
     {
 1051  18
         applicationRoot = val;
 1052  18
     }
 1053  
 
 1054  
     /**
 1055  
      * Get the application root for this Turbine webapp. This
 1056  
      * concept was started in 3.0 and will allow an app to be
 1057  
      * developed from a standard CVS layout. With a simple
 1058  
      * switch the app will work fully within the servlet
 1059  
      * container for deployment.
 1060  
      *
 1061  
      * @return String applicationRoot
 1062  
      */
 1063  
     public static String getApplicationRoot()
 1064  
     {
 1065  195
         return applicationRoot;
 1066  
     }
 1067  
 
 1068  
     /**
 1069  
      * Used to get the real path of configuration and resource
 1070  
      * information. This can be used by an app being
 1071  
      * developed in a standard CVS layout.
 1072  
      *
 1073  
      * @param path path translated to the application root
 1074  
      * @return the real path
 1075  
      */
 1076  
     public static String getRealPath(String path)
 1077  
     {
 1078  176
         if (path.startsWith("/"))
 1079  
         {
 1080  51
             path = path.substring(1);
 1081  
         }
 1082  
 
 1083  176
         return new File(getApplicationRoot(), path).getAbsolutePath();
 1084  
     }
 1085  
 
 1086  
     /**
 1087  
      * Return an instance of the currently configured Service Manager
 1088  
      *
 1089  
      * @return A service Manager instance
 1090  
      */
 1091  
     private ServiceManager getServiceManager()
 1092  
     {
 1093  59
         return TurbineServices.getInstance();
 1094  
     }
 1095  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.