Coverage Report - org.apache.shiro.web.env.EnvironmentLoader
 
Classes in this File Line Coverage Branch Coverage Complexity
EnvironmentLoader
3%
2/52
0%
0/16
4.8
 
 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.shiro.web.env;
 20  
 
 21  
 import org.apache.shiro.config.ConfigurationException;
 22  
 import org.apache.shiro.config.ResourceConfigurable;
 23  
 import org.apache.shiro.util.ClassUtils;
 24  
 import org.apache.shiro.util.LifecycleUtils;
 25  
 import org.apache.shiro.util.StringUtils;
 26  
 import org.apache.shiro.util.UnknownClassException;
 27  
 import org.slf4j.Logger;
 28  
 import org.slf4j.LoggerFactory;
 29  
 
 30  
 import javax.servlet.ServletContext;
 31  
 
 32  
 /**
 33  
  * An {@code EnvironmentLoader} is responsible for loading a web application's Shiro {@link WebEnvironment}
 34  
  * (which includes the web app's {@link org.apache.shiro.web.mgt.WebSecurityManager WebSecurityManager}) into the
 35  
  * {@code ServletContext} at application startup.
 36  
  * <p/>
 37  
  * In Shiro 1.1 and earlier, the Shiro ServletFilter was responsible for creating the {@code WebSecurityManager} and
 38  
  * any additional objects (security filters, etc).  However, any component not filtered by the Shiro Filter (such
 39  
  * as other context listeners) was not able to easily acquire the these objects to perform security operations.
 40  
  * <p/>
 41  
  * Due to this, in Shiro 1.2 and later, this {@code EnvironmentLoader} (or more likely, the
 42  
  * {@link EnvironmentLoaderListener} subclass) is the preferred mechanism to initialize
 43  
  * a Shiro environment.  The Shiro Filter, while still required for request filtering, will not perform this
 44  
  * initialization at startup if the {@code EnvironmentLoader} (or listener) runs first.
 45  
  * <h2>Usage</h2>
 46  
  * This implementation will look for two servlet context {@code context-param}s in {@code web.xml}:
 47  
  * {@code shiroEnvironmentClass} and {@code shiroConfigLocations} that customize how the {@code WebEnvironment} instance
 48  
  * will be initialized.
 49  
  * <h3>shiroEnvironmentClass</h3>
 50  
  * The {@code shiroEnvironmentClass} {@code context-param}, if it exists, allows you to specify the
 51  
  * fully-qualified implementation class name of the {@link WebEnvironment} to instantiate.  For example:
 52  
  * <pre>
 53  
  * &lt;context-param&gt;
 54  
  *     &lt;param-name&gt;shiroEnvironmentClass&lt;/param-name&gt;
 55  
  *     &lt;param-value&gt;com.foo.bar.shiro.MyWebEnvironment&lt;/param-value&gt;
 56  
  * &lt;/context-param&gt;
 57  
  * </pre>
 58  
  * If not specified, the default value is the {@link IniWebEnvironment} class, which assumes Shiro's default
 59  
  * <a href="http://shiro.apache.org/configuration.html">INI configuration format</a>
 60  
  * <h3>shiroConfigLocations</h3>
 61  
  * The {@code shiroConfigLocations} {@code context-param}, if it exists, allows you to specify the config location(s)
 62  
  * (resource path(s)) that will be relayed to the instantiated {@link WebEnvironment}.  For example:
 63  
  * <pre>
 64  
  * &lt;context-param&gt;
 65  
  *     &lt;param-name&gt;shiroConfigLocations&lt;/param-name&gt;
 66  
  *     &lt;param-value&gt;/WEB-INF/someLocation/shiro.ini&lt;/param-value&gt;
 67  
  * &lt;/context-param&gt;
 68  
  * </pre>
 69  
  * The {@code WebEnvironment} implementation must implement the {@link ResourceConfigurable} interface if it is to
 70  
  * acquire the {@code shiroConfigLocations} value.
 71  
  * <p/>
 72  
  * If this {@code context-param} is not specified, the {@code WebEnvironment} instance determines default resource
 73  
  * lookup behavior.  For example, the {@link IniWebEnvironment} will check the following two locations for INI config
 74  
  * by default (in order):
 75  
  * <ol>
 76  
  * <li>/WEB-INF/shiro.ini</li>
 77  
  * <li>classpath:shiro.ini</li>
 78  
  * </ol>
 79  
  * <h2>Web Security Enforcement</h2>
 80  
  * Using this loader will only initialize Shiro's environment in a web application - it will not filter web requests or
 81  
  * perform web-specific security operations.  To do this, you must ensure that you have also configured the
 82  
  * {@link org.apache.shiro.web.servlet.ShiroFilter ShiroFilter} in {@code web.xml}.
 83  
  * <p/>
 84  
  * Finally, it should be noted that this implementation was based on ideas in Spring 3's
 85  
  * {@code org.springframework.web.context.ContextLoader} implementation - no need to reinvent the wheel for this common
 86  
  * behavior.
 87  
  *
 88  
  * @see EnvironmentLoaderListener
 89  
  * @see org.apache.shiro.web.servlet.ShiroFilter ShiroFilter
 90  
  * @since 1.2
 91  
  */
 92  0
 public class EnvironmentLoader {
 93  
 
 94  
     /**
 95  
      * Servlet Context config param for specifying the {@link WebEnvironment} implementation class to use:
 96  
      * {@code shiroEnvironmentClass}
 97  
      */
 98  
     public static final String ENVIRONMENT_CLASS_PARAM = "shiroEnvironmentClass";
 99  
 
 100  
     /**
 101  
      * Servlet Context config param for the resource path to use for configuring the {@link WebEnvironment} instance:
 102  
      * {@code shiroConfigLocations}
 103  
      */
 104  
     public static final String CONFIG_LOCATIONS_PARAM = "shiroConfigLocations";
 105  
 
 106  1
     public static final String ENVIRONMENT_ATTRIBUTE_KEY = EnvironmentLoader.class.getName() + ".ENVIRONMENT_ATTRIBUTE_KEY";
 107  
 
 108  1
     private static final Logger log = LoggerFactory.getLogger(EnvironmentLoader.class);
 109  
 
 110  
     /**
 111  
      * Initializes Shiro's {@link WebEnvironment} instance for the specified {@code ServletContext} based on the
 112  
      * {@link #CONFIG_LOCATIONS_PARAM} value.
 113  
      *
 114  
      * @param servletContext current servlet context
 115  
      * @return the new Shiro {@code WebEnvironment} instance.
 116  
      * @throws IllegalStateException if an existing WebEnvironment has already been initialized and associated with
 117  
      *                               the specified {@code ServletContext}.
 118  
      */
 119  
     public WebEnvironment initEnvironment(ServletContext servletContext) throws IllegalStateException {
 120  
 
 121  0
         if (servletContext.getAttribute(ENVIRONMENT_ATTRIBUTE_KEY) != null) {
 122  0
             String msg = "There is already a Shiro environment associated with the current ServletContext.  " +
 123  
                     "Check if you have multiple EnvironmentLoader* definitions in your web.xml!";
 124  0
             throw new IllegalStateException(msg);
 125  
         }
 126  
 
 127  0
         servletContext.log("Initializing Shiro environment");
 128  0
         log.info("Starting Shiro environment initialization.");
 129  
 
 130  0
         long startTime = System.currentTimeMillis();
 131  
 
 132  
         try {
 133  0
             WebEnvironment environment = createEnvironment(servletContext);
 134  0
             servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, environment);
 135  
 
 136  0
             log.debug("Published WebEnvironment as ServletContext attribute with name [{}]",
 137  
                     ENVIRONMENT_ATTRIBUTE_KEY);
 138  
 
 139  0
             if (log.isInfoEnabled()) {
 140  0
                 long elapsed = System.currentTimeMillis() - startTime;
 141  0
                 log.info("Shiro environment initialized in {} ms.", elapsed);
 142  
             }
 143  
 
 144  0
             return environment;
 145  0
         } catch (RuntimeException ex) {
 146  0
             log.error("Shiro environment initialization failed", ex);
 147  0
             servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, ex);
 148  0
             throw ex;
 149  0
         } catch (Error err) {
 150  0
             log.error("Shiro environment initialization failed", err);
 151  0
             servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, err);
 152  0
             throw err;
 153  
         }
 154  
     }
 155  
 
 156  
     /**
 157  
      * Return the WebEnvironment implementation class to use, either the default
 158  
      * {@link IniWebEnvironment} or a custom class if specified.
 159  
      *
 160  
      * @param servletContext current servlet context
 161  
      * @return the WebEnvironment implementation class to use
 162  
      * @see #ENVIRONMENT_CLASS_PARAM
 163  
      * @see IniWebEnvironment
 164  
      */
 165  
     protected Class<?> determineWebEnvironmentClass(ServletContext servletContext) {
 166  0
         String className = servletContext.getInitParameter(ENVIRONMENT_CLASS_PARAM);
 167  0
         if (className != null) {
 168  
             try {
 169  0
                 return ClassUtils.forName(className);
 170  0
             } catch (UnknownClassException ex) {
 171  0
                 throw new ConfigurationException(
 172  
                         "Failed to load custom WebEnvironment class [" + className + "]", ex);
 173  
             }
 174  
         } else {
 175  0
             return IniWebEnvironment.class;
 176  
         }
 177  
     }
 178  
 
 179  
     /**
 180  
      * Instantiates a {@link WebEnvironment} based on the specified ServletContext.
 181  
      * <p/>
 182  
      * This implementation {@link #determineWebEnvironmentClass(javax.servlet.ServletContext) determines} a
 183  
      * {@link WebEnvironment} implementation class to use.  That class is instantiated, configured, and returned.
 184  
      * <p/>
 185  
      * This allows custom {@code WebEnvironment} implementations to be specified via a ServletContext init-param if
 186  
      * desired.  If not specified, the default {@link IniWebEnvironment} implementation will be used.
 187  
      *
 188  
      * @param sc current servlet context
 189  
      * @return the constructed Shiro WebEnvironment instance
 190  
      * @see MutableWebEnvironment
 191  
      * @see ResourceConfigurable
 192  
      */
 193  
     protected WebEnvironment createEnvironment(ServletContext sc) {
 194  
 
 195  0
         Class<?> clazz = determineWebEnvironmentClass(sc);
 196  0
         if (!MutableWebEnvironment.class.isAssignableFrom(clazz)) {
 197  0
             throw new ConfigurationException("Custom WebEnvironment class [" + clazz.getName() +
 198  
                     "] is not of required type [" + WebEnvironment.class.getName() + "]");
 199  
         }
 200  
 
 201  0
         String configLocations = sc.getInitParameter(CONFIG_LOCATIONS_PARAM);
 202  0
         boolean configSpecified = StringUtils.hasText(configLocations);
 203  
 
 204  0
         if (configSpecified && !(ResourceConfigurable.class.isAssignableFrom(clazz))) {
 205  0
             String msg = "WebEnvironment class [" + clazz.getName() + "] does not implement the " +
 206  
                     ResourceConfigurable.class.getName() + "interface.  This is required to accept any " +
 207  
                     "configured " + CONFIG_LOCATIONS_PARAM + "value(s).";
 208  0
             throw new ConfigurationException(msg);
 209  
         }
 210  
 
 211  0
         MutableWebEnvironment environment = (MutableWebEnvironment) ClassUtils.newInstance(clazz);
 212  
 
 213  0
         environment.setServletContext(sc);
 214  
 
 215  0
         if (configSpecified && (environment instanceof ResourceConfigurable)) {
 216  0
             ((ResourceConfigurable) environment).setConfigLocations(configLocations);
 217  
         }
 218  
 
 219  0
         customizeEnvironment(environment);
 220  
 
 221  0
         LifecycleUtils.init(environment);
 222  
 
 223  0
         return environment;
 224  
     }
 225  
 
 226  
     protected void customizeEnvironment(WebEnvironment environment) {
 227  0
     }
 228  
 
 229  
     /**
 230  
      * Destroys the {@link WebEnvironment} for the given servlet context.
 231  
      *
 232  
      * @param servletContext the ServletContext attributed to the WebSecurityManager
 233  
      */
 234  
     public void destroyEnvironment(ServletContext servletContext) {
 235  0
         servletContext.log("Cleaning up Shiro Environment");
 236  
         try {
 237  0
             Object environment = servletContext.getAttribute(ENVIRONMENT_ATTRIBUTE_KEY);
 238  0
             LifecycleUtils.destroy(environment);
 239  
         } finally {
 240  0
             servletContext.removeAttribute(ENVIRONMENT_ATTRIBUTE_KEY);
 241  0
         }
 242  0
     }
 243  
 }