blob: ff221052a0ed5e34051284b60d914b426b12ebe1 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../../jacoco-resources/report.gif" type="image/gif"/><title>EnvironmentLoader.java</title><link rel="stylesheet" href="../../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../../index.html" class="el_report">Apache Shiro :: Test Coverage</a> &gt; <a href="../index.html" class="el_bundle">shiro-web</a> &gt; <a href="index.source.html" class="el_package">org.apache.shiro.web.env</a> &gt; <span class="el_source">EnvironmentLoader.java</span></div><h1>EnvironmentLoader.java</h1><pre class="source lang-java linenums">/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* &quot;License&quot;); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.shiro.web.env;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.config.ResourceConfigurable;
import org.apache.shiro.util.ClassUtils;
import org.apache.shiro.util.LifecycleUtils;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.util.UnknownClassException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
/**
* An {@code EnvironmentLoader} is responsible for loading a web application's Shiro {@link WebEnvironment}
* (which includes the web app's {@link org.apache.shiro.web.mgt.WebSecurityManager WebSecurityManager}) into the
* {@code ServletContext} at application startup.
* &lt;p/&gt;
* In Shiro 1.1 and earlier, the Shiro ServletFilter was responsible for creating the {@code WebSecurityManager} and
* any additional objects (security filters, etc). However, any component not filtered by the Shiro Filter (such
* as other context listeners) was not able to easily acquire the these objects to perform security operations.
* &lt;p/&gt;
* Due to this, in Shiro 1.2 and later, this {@code EnvironmentLoader} (or more likely, the
* {@link EnvironmentLoaderListener} subclass) is the preferred mechanism to initialize
* a Shiro environment. The Shiro Filter, while still required for request filtering, will not perform this
* initialization at startup if the {@code EnvironmentLoader} (or listener) runs first.
* &lt;h2&gt;Usage&lt;/h2&gt;
* This implementation will look for two servlet context {@code context-param}s in {@code web.xml}:
* {@code shiroEnvironmentClass} and {@code shiroConfigLocations} that customize how the {@code WebEnvironment} instance
* will be initialized.
* &lt;h3&gt;shiroEnvironmentClass&lt;/h3&gt;
* The {@code shiroEnvironmentClass} {@code context-param}, if it exists, allows you to specify the
* fully-qualified implementation class name of the {@link WebEnvironment} to instantiate. For example:
* &lt;pre&gt;
* &amp;lt;context-param&amp;gt;
* &amp;lt;param-name&amp;gt;shiroEnvironmentClass&amp;lt;/param-name&amp;gt;
* &amp;lt;param-value&amp;gt;com.foo.bar.shiro.MyWebEnvironment&amp;lt;/param-value&amp;gt;
* &amp;lt;/context-param&amp;gt;
* &lt;/pre&gt;
* If not specified, the default value is the {@link IniWebEnvironment} class, which assumes Shiro's default
* &lt;a href=&quot;http://shiro.apache.org/configuration.html&quot;&gt;INI configuration format&lt;/a&gt;
* &lt;h3&gt;shiroConfigLocations&lt;/h3&gt;
* The {@code shiroConfigLocations} {@code context-param}, if it exists, allows you to specify the config location(s)
* (resource path(s)) that will be relayed to the instantiated {@link WebEnvironment}. For example:
* &lt;pre&gt;
* &amp;lt;context-param&amp;gt;
* &amp;lt;param-name&amp;gt;shiroConfigLocations&amp;lt;/param-name&amp;gt;
* &amp;lt;param-value&amp;gt;/WEB-INF/someLocation/shiro.ini&amp;lt;/param-value&amp;gt;
* &amp;lt;/context-param&amp;gt;
* &lt;/pre&gt;
* The {@code WebEnvironment} implementation must implement the {@link ResourceConfigurable} interface if it is to
* acquire the {@code shiroConfigLocations} value.
* &lt;p/&gt;
* If this {@code context-param} is not specified, the {@code WebEnvironment} instance determines default resource
* lookup behavior. For example, the {@link IniWebEnvironment} will check the following two locations for INI config
* by default (in order):
* &lt;ol&gt;
* &lt;li&gt;/WEB-INF/shiro.ini&lt;/li&gt;
* &lt;li&gt;classpath:shiro.ini&lt;/li&gt;
* &lt;/ol&gt;
* &lt;h2&gt;Web Security Enforcement&lt;/h2&gt;
* Using this loader will only initialize Shiro's environment in a web application - it will not filter web requests or
* perform web-specific security operations. To do this, you must ensure that you have also configured the
* {@link org.apache.shiro.web.servlet.ShiroFilter ShiroFilter} in {@code web.xml}.
* &lt;p/&gt;
* Finally, it should be noted that this implementation was based on ideas in Spring 3's
* {@code org.springframework.web.context.ContextLoader} implementation - no need to reinvent the wheel for this common
* behavior.
*
* @see EnvironmentLoaderListener
* @see org.apache.shiro.web.servlet.ShiroFilter ShiroFilter
* @since 1.2
*/
<span class="fc" id="L97">public class EnvironmentLoader {</span>
/**
* Servlet Context config param for specifying the {@link WebEnvironment} implementation class to use:
* {@code shiroEnvironmentClass}
*/
public static final String ENVIRONMENT_CLASS_PARAM = &quot;shiroEnvironmentClass&quot;;
/**
* Servlet Context config param for the resource path to use for configuring the {@link WebEnvironment} instance:
* {@code shiroConfigLocations}
*/
public static final String CONFIG_LOCATIONS_PARAM = &quot;shiroConfigLocations&quot;;
<span class="fc" id="L111"> public static final String ENVIRONMENT_ATTRIBUTE_KEY = EnvironmentLoader.class.getName() + &quot;.ENVIRONMENT_ATTRIBUTE_KEY&quot;;</span>
<span class="fc" id="L113"> private static final Logger log = LoggerFactory.getLogger(EnvironmentLoader.class);</span>
/**
* Initializes Shiro's {@link WebEnvironment} instance for the specified {@code ServletContext} based on the
* {@link #CONFIG_LOCATIONS_PARAM} value.
*
* @param servletContext current servlet context
* @return the new Shiro {@code WebEnvironment} instance.
* @throws IllegalStateException if an existing WebEnvironment has already been initialized and associated with
* the specified {@code ServletContext}.
*/
public WebEnvironment initEnvironment(ServletContext servletContext) throws IllegalStateException {
<span class="pc bpc" id="L126" title="1 of 2 branches missed."> if (servletContext.getAttribute(ENVIRONMENT_ATTRIBUTE_KEY) != null) {</span>
<span class="nc" id="L127"> String msg = &quot;There is already a Shiro environment associated with the current ServletContext. &quot; +</span>
&quot;Check if you have multiple EnvironmentLoader* definitions in your web.xml!&quot;;
<span class="nc" id="L129"> throw new IllegalStateException(msg);</span>
}
<span class="fc" id="L132"> servletContext.log(&quot;Initializing Shiro environment&quot;);</span>
<span class="fc" id="L133"> log.info(&quot;Starting Shiro environment initialization.&quot;);</span>
<span class="fc" id="L135"> long startTime = System.currentTimeMillis();</span>
try {
<span class="fc" id="L139"> WebEnvironment environment = createEnvironment(servletContext);</span>
<span class="fc" id="L140"> servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY,environment);</span>
<span class="fc" id="L142"> log.debug(&quot;Published WebEnvironment as ServletContext attribute with name [{}]&quot;,</span>
ENVIRONMENT_ATTRIBUTE_KEY);
<span class="pc bpc" id="L145" title="1 of 2 branches missed."> if (log.isInfoEnabled()) {</span>
<span class="fc" id="L146"> long elapsed = System.currentTimeMillis() - startTime;</span>
<span class="fc" id="L147"> log.info(&quot;Shiro environment initialized in {} ms.&quot;, elapsed);</span>
}
<span class="fc" id="L150"> return environment;</span>
<span class="nc" id="L151"> } catch (RuntimeException ex) {</span>
<span class="nc" id="L152"> log.error(&quot;Shiro environment initialization failed&quot;, ex);</span>
<span class="nc" id="L153"> servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, ex);</span>
<span class="nc" id="L154"> throw ex;</span>
<span class="nc" id="L155"> } catch (Error err) {</span>
<span class="nc" id="L156"> log.error(&quot;Shiro environment initialization failed&quot;, err);</span>
<span class="nc" id="L157"> servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, err);</span>
<span class="nc" id="L158"> throw err;</span>
}
}
/**
* Return the WebEnvironment implementation class to use, either the default
* {@link IniWebEnvironment} or a custom class if specified.
*
* @param servletContext current servlet context
* @return the WebEnvironment implementation class to use
* @see #ENVIRONMENT_CLASS_PARAM
* @see IniWebEnvironment
* @see #determineWebEnvironment(ServletContext)
* @see #getDefaultWebEnvironmentClass()
* @deprecated This method is not longer used by Shiro, and will be removed in future versions,
* use {@link #determineWebEnvironment(ServletContext)} or {@link #determineWebEnvironment(ServletContext)}
*/
@Deprecated
protected Class&lt;?&gt; determineWebEnvironmentClass(ServletContext servletContext) {
<span class="nc" id="L177"> Class&lt;? extends WebEnvironment&gt; webEnvironmentClass = webEnvironmentClassFromServletContext(servletContext);</span>
<span class="nc bnc" id="L178" title="All 2 branches missed."> if( webEnvironmentClass != null) {</span>
<span class="nc" id="L179"> return webEnvironmentClass;</span>
} else {
<span class="nc" id="L182"> return getDefaultWebEnvironmentClass();</span>
}
}
private Class&lt;? extends WebEnvironment&gt; webEnvironmentClassFromServletContext(ServletContext servletContext) {
<span class="fc" id="L188"> Class&lt;? extends WebEnvironment&gt; webEnvironmentClass = null;</span>
<span class="fc" id="L189"> String className = servletContext.getInitParameter(ENVIRONMENT_CLASS_PARAM);</span>
<span class="fc bfc" id="L190" title="All 2 branches covered."> if (className != null) {</span>
try {
<span class="fc" id="L192"> webEnvironmentClass = ClassUtils.forName(className);</span>
<span class="nc" id="L193"> } catch (UnknownClassException ex) {</span>
<span class="nc" id="L194"> throw new ConfigurationException(</span>
&quot;Failed to load custom WebEnvironment class [&quot; + className + &quot;]&quot;, ex);
<span class="fc" id="L196"> }</span>
}
<span class="fc" id="L198"> return webEnvironmentClass;</span>
}
private WebEnvironment webEnvironmentFromServiceLoader() {
<span class="fc" id="L203"> WebEnvironment webEnvironment = null;</span>
// try to load WebEnvironment as a service
<span class="fc" id="L205"> ServiceLoader&lt;WebEnvironment&gt; serviceLoader = ServiceLoader.load(WebEnvironment.class);</span>
<span class="fc" id="L206"> Iterator&lt;WebEnvironment&gt; iterator = serviceLoader.iterator();</span>
// Use the first one
<span class="pc bpc" id="L209" title="1 of 2 branches missed."> if (iterator.hasNext()) {</span>
<span class="nc" id="L210"> webEnvironment = iterator.next();</span>
}
// if there are others, throw an error
<span class="pc bpc" id="L213" title="1 of 2 branches missed."> if (iterator.hasNext()) {</span>
<span class="nc" id="L214"> List&lt;String&gt; allWebEnvironments = new ArrayList&lt;String&gt;();</span>
<span class="nc" id="L215"> allWebEnvironments.add(webEnvironment.getClass().getName());</span>
<span class="nc bnc" id="L216" title="All 2 branches missed."> while (iterator.hasNext()) {</span>
<span class="nc" id="L217"> allWebEnvironments.add(iterator.next().getClass().getName());</span>
}
<span class="nc" id="L219"> throw new ConfigurationException(&quot;ServiceLoader for class [&quot; + WebEnvironment.class + &quot;] returned more then one &quot; +</span>
&quot;result. ServiceLoader must return zero or exactly one result for this class. Select one using the &quot; +
&quot;servlet init parameter '&quot;+ ENVIRONMENT_CLASS_PARAM +&quot;'. Found: &quot; + allWebEnvironments);
}
<span class="fc" id="L223"> return webEnvironment;</span>
}
/**
* Returns the default WebEnvironment class, which is unless overridden: {@link IniWebEnvironment}.
* @return the default WebEnvironment class.
*/
protected Class&lt;? extends WebEnvironment&gt; getDefaultWebEnvironmentClass() {
<span class="fc" id="L231"> return IniWebEnvironment.class;</span>
}
/**
* Return the WebEnvironment implementation class to use, based on the order of:
* &lt;ul&gt;
* &lt;li&gt;A custom WebEnvironment class - specified in the {@code servletContext} {@link #ENVIRONMENT_ATTRIBUTE_KEY} property&lt;/li&gt;
* &lt;li&gt;{@code ServiceLoader.load(WebEnvironment.class)} - (if more then one instance is found a {@link ConfigurationException} will be thrown&lt;/li&gt;
* &lt;li&gt;A call to {@link #getDefaultWebEnvironmentClass()} (default: {@link IniWebEnvironment})&lt;/li&gt;
* &lt;/ul&gt;
*
* @param servletContext current servlet context
* @return the WebEnvironment implementation class to use
* @see #ENVIRONMENT_CLASS_PARAM
* @param servletContext the {@code servletContext} to query the {@code ENVIRONMENT_ATTRIBUTE_KEY} property from
* @return the {@code WebEnvironment} to be used
*/
protected WebEnvironment determineWebEnvironment(ServletContext servletContext) {
<span class="fc" id="L250"> Class&lt;? extends WebEnvironment&gt; webEnvironmentClass = webEnvironmentClassFromServletContext(servletContext);</span>
<span class="fc" id="L251"> WebEnvironment webEnvironment = null;</span>
// try service loader next
<span class="fc bfc" id="L254" title="All 2 branches covered."> if (webEnvironmentClass == null) {</span>
<span class="fc" id="L255"> webEnvironment = webEnvironmentFromServiceLoader();</span>
}
// if webEnvironment is not set, and ENVIRONMENT_CLASS_PARAM prop was not set, use the default
<span class="pc bpc" id="L259" title="1 of 4 branches missed."> if (webEnvironmentClass == null &amp;&amp; webEnvironment == null) {</span>
<span class="fc" id="L260"> webEnvironmentClass = getDefaultWebEnvironmentClass();</span>
}
// at this point, we anything is set for the webEnvironmentClass, load it.
<span class="pc bpc" id="L264" title="1 of 2 branches missed."> if (webEnvironmentClass != null) {</span>
<span class="fc" id="L265"> webEnvironment = (WebEnvironment) ClassUtils.newInstance(webEnvironmentClass);</span>
}
<span class="fc" id="L268"> return webEnvironment;</span>
}
/**
* Instantiates a {@link WebEnvironment} based on the specified ServletContext.
* &lt;p/&gt;
* This implementation {@link #determineWebEnvironmentClass(javax.servlet.ServletContext) determines} a
* {@link WebEnvironment} implementation class to use. That class is instantiated, configured, and returned.
* &lt;p/&gt;
* This allows custom {@code WebEnvironment} implementations to be specified via a ServletContext init-param if
* desired. If not specified, the default {@link IniWebEnvironment} implementation will be used.
*
* @param sc current servlet context
* @return the constructed Shiro WebEnvironment instance
* @see MutableWebEnvironment
* @see ResourceConfigurable
*/
protected WebEnvironment createEnvironment(ServletContext sc) {
<span class="fc" id="L287"> WebEnvironment webEnvironment = determineWebEnvironment(sc);</span>
<span class="pc bpc" id="L288" title="1 of 2 branches missed."> if (!MutableWebEnvironment.class.isInstance(webEnvironment)) {</span>
<span class="nc" id="L289"> throw new ConfigurationException(&quot;Custom WebEnvironment class [&quot; + webEnvironment.getClass().getName() +</span>
<span class="nc" id="L290"> &quot;] is not of required type [&quot; + MutableWebEnvironment.class.getName() + &quot;]&quot;);</span>
}
<span class="fc" id="L293"> String configLocations = sc.getInitParameter(CONFIG_LOCATIONS_PARAM);</span>
<span class="fc" id="L294"> boolean configSpecified = StringUtils.hasText(configLocations);</span>
<span class="pc bpc" id="L296" title="3 of 4 branches missed."> if (configSpecified &amp;&amp; !(ResourceConfigurable.class.isInstance(webEnvironment))) {</span>
<span class="nc" id="L297"> String msg = &quot;WebEnvironment class [&quot; + webEnvironment.getClass().getName() + &quot;] does not implement the &quot; +</span>
<span class="nc" id="L298"> ResourceConfigurable.class.getName() + &quot;interface. This is required to accept any &quot; +</span>
&quot;configured &quot; + CONFIG_LOCATIONS_PARAM + &quot;value(s).&quot;;
<span class="nc" id="L300"> throw new ConfigurationException(msg);</span>
}
<span class="fc" id="L303"> MutableWebEnvironment environment = (MutableWebEnvironment) webEnvironment;</span>
<span class="fc" id="L305"> environment.setServletContext(sc);</span>
<span class="pc bpc" id="L307" title="3 of 4 branches missed."> if (configSpecified &amp;&amp; (environment instanceof ResourceConfigurable)) {</span>
<span class="nc" id="L308"> ((ResourceConfigurable) environment).setConfigLocations(configLocations);</span>
}
<span class="fc" id="L311"> customizeEnvironment(environment);</span>
<span class="fc" id="L313"> LifecycleUtils.init(environment);</span>
<span class="fc" id="L315"> return environment;</span>
}
/**
* Any additional customization of the Environment can be by overriding this method. For example setup shared
* resources, etc. By default this method does nothing.
* @param environment
*/
protected void customizeEnvironment(WebEnvironment environment) {
<span class="fc" id="L324"> }</span>
/**
* Destroys the {@link WebEnvironment} for the given servlet context.
*
* @param servletContext the ServletContext attributed to the WebSecurityManager
*/
public void destroyEnvironment(ServletContext servletContext) {
<span class="fc" id="L332"> servletContext.log(&quot;Cleaning up Shiro Environment&quot;);</span>
try {
<span class="fc" id="L334"> Object environment = servletContext.getAttribute(ENVIRONMENT_ATTRIBUTE_KEY);</span>
<span class="pc bpc" id="L335" title="1 of 2 branches missed."> if (environment instanceof WebEnvironment) {</span>
<span class="fc" id="L336"> finalizeEnvironment((WebEnvironment) environment);</span>
}
<span class="fc" id="L338"> LifecycleUtils.destroy(environment);</span>
} finally {
<span class="pc" id="L340"> servletContext.removeAttribute(ENVIRONMENT_ATTRIBUTE_KEY);</span>
<span class="fc" id="L341"> }</span>
<span class="fc" id="L342"> }</span>
/**
* Any additional cleanup of the Environment can be done by overriding this method. For example clean up shared
* resources, etc. By default this method does nothing.
* @param environment
* @since 1.3
*/
protected void finalizeEnvironment(WebEnvironment environment) {
<span class="fc" id="L351"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.eclemma.org/jacoco">JaCoCo</a> 0.7.7.201606060606</span></div></body></html>