blob: 2a5011f849775cde0f9a48991db8e5f1597bcba0 [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>ReflectionBuilder.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 :: All (aggregate jar)</a> &gt; <a href="../index.html" class="el_bundle">shiro-config-ogdl</a> &gt; <a href="index.source.html" class="el_package">org.apache.shiro.config</a> &gt; <span class="el_source">ReflectionBuilder.java</span></div><h1>ReflectionBuilder.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.config;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.SuppressPropertiesBeanIntrospector;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.config.event.BeanEvent;
import org.apache.shiro.config.event.ConfiguredBeanEvent;
import org.apache.shiro.config.event.DestroyedBeanEvent;
import org.apache.shiro.config.event.InitializedBeanEvent;
import org.apache.shiro.config.event.InstantiatedBeanEvent;
import org.apache.shiro.event.EventBus;
import org.apache.shiro.event.EventBusAware;
import org.apache.shiro.event.Subscribe;
import org.apache.shiro.event.support.DefaultEventBus;
import org.apache.shiro.util.Assert;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.ClassUtils;
import org.apache.shiro.util.Factory;
import org.apache.shiro.util.LifecycleUtils;
import org.apache.shiro.util.Nameable;
import org.apache.shiro.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Object builder that uses reflection and Apache Commons BeanUtils to build objects given a
* map of &quot;property values&quot;. Typically these come from the Shiro INI configuration and are used
* to construct or modify the SecurityManager, its dependencies, and web-based security filters.
* &lt;p/&gt;
* Recognizes {@link Factory} implementations and will call
* {@link org.apache.shiro.util.Factory#getInstance() getInstance} to satisfy any reference to this bean.
*
* @since 0.9
*/
public class ReflectionBuilder {
//TODO - complete JavaDoc
<span class="fc" id="L70"> private static final Logger log = LoggerFactory.getLogger(ReflectionBuilder.class);</span>
private static final String OBJECT_REFERENCE_BEGIN_TOKEN = &quot;$&quot;;
private static final String ESCAPED_OBJECT_REFERENCE_BEGIN_TOKEN = &quot;\\$&quot;;
private static final String GLOBAL_PROPERTY_PREFIX = &quot;shiro&quot;;
private static final char MAP_KEY_VALUE_DELIMITER = ':';
private static final String HEX_BEGIN_TOKEN = &quot;0x&quot;;
private static final String NULL_VALUE_TOKEN = &quot;null&quot;;
private static final String EMPTY_STRING_VALUE_TOKEN = &quot;\&quot;\&quot;&quot;;
private static final char STRING_VALUE_DELIMETER = '&quot;';
private static final char MAP_PROPERTY_BEGIN_TOKEN = '[';
private static final char MAP_PROPERTY_END_TOKEN = ']';
private static final String EVENT_BUS_NAME = &quot;eventBus&quot;;
private final Map&lt;String, Object&gt; objects;
/**
* Interpolation allows for ${key} substitution of values.
* @since 1.4
*/
private Interpolator interpolator;
/**
* @since 1.3
*/
private EventBus eventBus;
/**
* Keeps track of event subscribers that were automatically registered by this ReflectionBuilder during
* object construction. This is used in case a new EventBus is discovered during object graph
* construction: upon discovery of the new EventBus, the existing subscribers will be unregistered from the
* old EventBus and then re-registered with the new EventBus.
*
* @since 1.3
*/
private final Map&lt;String,Object&gt; registeredEventSubscribers;
/**
* @since 1.4
*/
private final BeanUtilsBean beanUtilsBean;
//@since 1.3
private Map&lt;String,Object&gt; createDefaultObjectMap() {
<span class="fc" id="L114"> Map&lt;String,Object&gt; map = new LinkedHashMap&lt;String, Object&gt;();</span>
<span class="fc" id="L115"> map.put(EVENT_BUS_NAME, new DefaultEventBus());</span>
<span class="fc" id="L116"> return map;</span>
}
public ReflectionBuilder() {
<span class="fc" id="L120"> this(null);</span>
<span class="fc" id="L121"> }</span>
<span class="fc" id="L123"> public ReflectionBuilder(Map&lt;String, ?&gt; defaults) {</span>
// SHIRO-619
<span class="fc" id="L126"> beanUtilsBean = new BeanUtilsBean();</span>
<span class="fc" id="L127"> beanUtilsBean.getPropertyUtils().addBeanIntrospector(SuppressPropertiesBeanIntrospector.SUPPRESS_CLASS);</span>
<span class="fc" id="L129"> this.interpolator = createInterpolator();</span>
<span class="fc" id="L131"> this.objects = createDefaultObjectMap();</span>
<span class="fc" id="L132"> this.registeredEventSubscribers = new LinkedHashMap&lt;String,Object&gt;();</span>
<span class="fc" id="L133"> apply(defaults);</span>
<span class="fc" id="L134"> }</span>
private void apply(Map&lt;String, ?&gt; objects) {
<span class="fc bfc" id="L137" title="All 2 branches covered."> if(!isEmpty(objects)) {</span>
<span class="fc" id="L138"> this.objects.putAll(objects);</span>
}
<span class="fc" id="L140"> EventBus found = findEventBus(this.objects);</span>
<span class="fc" id="L141"> Assert.notNull(found, &quot;An &quot; + EventBus.class.getName() + &quot; instance must be present in the object defaults&quot;);</span>
<span class="fc" id="L142"> enableEvents(found);</span>
<span class="fc" id="L143"> }</span>
public Map&lt;String, ?&gt; getObjects() {
<span class="fc" id="L146"> return objects;</span>
}
/**
* @param objects
*/
public void setObjects(Map&lt;String, ?&gt; objects) {
<span class="fc" id="L153"> this.objects.clear();</span>
<span class="fc" id="L154"> this.objects.putAll(createDefaultObjectMap());</span>
<span class="fc" id="L155"> apply(objects);</span>
<span class="fc" id="L156"> }</span>
//@since 1.3
private void enableEvents(EventBus eventBus) {
<span class="fc" id="L160"> Assert.notNull(eventBus, &quot;EventBus argument cannot be null.&quot;);</span>
//clean up old auto-registered subscribers:
<span class="pc bpc" id="L162" title="1 of 2 branches missed."> for (Object subscriber : this.registeredEventSubscribers.values()) {</span>
<span class="nc" id="L163"> this.eventBus.unregister(subscriber);</span>
<span class="nc" id="L164"> }</span>
<span class="fc" id="L165"> this.registeredEventSubscribers.clear();</span>
<span class="fc" id="L167"> this.eventBus = eventBus;</span>
<span class="fc bfc" id="L169" title="All 2 branches covered."> for(Map.Entry&lt;String,Object&gt; entry : this.objects.entrySet()) {</span>
<span class="fc" id="L170"> enableEventsIfNecessary(entry.getValue(), entry.getKey());</span>
<span class="fc" id="L171"> }</span>
<span class="fc" id="L172"> }</span>
//@since 1.3
private void enableEventsIfNecessary(Object bean, String name) {
<span class="fc" id="L176"> boolean applied = applyEventBusIfNecessary(bean);</span>
<span class="fc bfc" id="L177" title="All 2 branches covered."> if (!applied) {</span>
//if the event bus is applied, and the bean wishes to be a subscriber as well (not just a publisher),
// we assume that the implementation registers itself with the event bus, i.e. eventBus.register(this);
//if the event bus isn't applied, only then do we need to check to see if the bean is an event subscriber,
// and if so, register it on the event bus automatically since it has no ability to do so itself:
<span class="fc bfc" id="L183" title="All 2 branches covered."> if (isEventSubscriber(bean, name)) {</span>
//found an event subscriber, so register them with the EventBus:
<span class="fc" id="L185"> this.eventBus.register(bean);</span>
<span class="fc" id="L186"> this.registeredEventSubscribers.put(name, bean);</span>
}
}
<span class="fc" id="L189"> }</span>
//@since 1.3
private boolean isEventSubscriber(Object bean, String name) {
<span class="fc" id="L193"> List annotatedMethods = ClassUtils.getAnnotatedMethods(bean.getClass(), Subscribe.class);</span>
<span class="fc bfc" id="L194" title="All 2 branches covered."> return !isEmpty(annotatedMethods);</span>
}
//@since 1.3
protected EventBus findEventBus(Map&lt;String,?&gt; objects) {
<span class="pc bpc" id="L200" title="1 of 2 branches missed."> if (isEmpty(objects)) {</span>
<span class="nc" id="L201"> return null;</span>
}
//prefer a named object first:
<span class="fc" id="L205"> Object value = objects.get(EVENT_BUS_NAME);</span>
<span class="pc bpc" id="L206" title="2 of 4 branches missed."> if (value != null &amp;&amp; value instanceof EventBus) {</span>
<span class="fc" id="L207"> return (EventBus)value;</span>
}
//couldn't find a named 'eventBus' EventBus object. Try to find the first typed value we can:
<span class="nc bnc" id="L211" title="All 2 branches missed."> for( Object v : objects.values()) {</span>
<span class="nc bnc" id="L212" title="All 2 branches missed."> if (v instanceof EventBus) {</span>
<span class="nc" id="L213"> return (EventBus)v;</span>
}
<span class="nc" id="L215"> }</span>
<span class="nc" id="L217"> return null;</span>
}
private boolean applyEventBusIfNecessary(Object value) {
<span class="fc bfc" id="L221" title="All 2 branches covered."> if (value instanceof EventBusAware) {</span>
<span class="fc" id="L222"> ((EventBusAware)value).setEventBus(this.eventBus);</span>
<span class="fc" id="L223"> return true;</span>
}
<span class="fc" id="L225"> return false;</span>
}
public Object getBean(String id) {
<span class="fc" id="L229"> return objects.get(id);</span>
}
@SuppressWarnings({&quot;unchecked&quot;})
public &lt;T&gt; T getBean(String id, Class&lt;T&gt; requiredType) {
<span class="pc bpc" id="L234" title="1 of 2 branches missed."> if (requiredType == null) {</span>
<span class="nc" id="L235"> throw new NullPointerException(&quot;requiredType argument cannot be null.&quot;);</span>
}
<span class="fc" id="L237"> Object bean = getBean(id);</span>
<span class="pc bpc" id="L238" title="1 of 2 branches missed."> if (bean == null) {</span>
<span class="nc" id="L239"> return null;</span>
}
<span class="fc" id="L241"> Assert.state(requiredType.isAssignableFrom(bean.getClass()),</span>
<span class="fc" id="L242"> &quot;Bean with id [&quot; + id + &quot;] is not of the required type [&quot; + requiredType.getName() + &quot;].&quot;);</span>
<span class="fc" id="L243"> return (T) bean;</span>
}
private String parseBeanId(String lhs) {
<span class="fc" id="L247"> Assert.notNull(lhs);</span>
<span class="fc bfc" id="L248" title="All 2 branches covered."> if (lhs.indexOf('.') &lt; 0) {</span>
<span class="fc" id="L249"> return lhs;</span>
}
<span class="fc" id="L251"> String classSuffix = &quot;.class&quot;;</span>
<span class="fc" id="L252"> int index = lhs.indexOf(classSuffix);</span>
<span class="pc bpc" id="L253" title="1 of 2 branches missed."> if (index &gt;= 0) {</span>
<span class="nc" id="L254"> return lhs.substring(0, index);</span>
}
<span class="fc" id="L256"> return null;</span>
}
@SuppressWarnings({&quot;unchecked&quot;})
public Map&lt;String, ?&gt; buildObjects(Map&lt;String, String&gt; kvPairs) {
<span class="pc bpc" id="L262" title="1 of 4 branches missed."> if (kvPairs != null &amp;&amp; !kvPairs.isEmpty()) {</span>
<span class="fc" id="L264"> BeanConfigurationProcessor processor = new BeanConfigurationProcessor();</span>
<span class="fc bfc" id="L266" title="All 2 branches covered."> for (Map.Entry&lt;String, String&gt; entry : kvPairs.entrySet()) {</span>
<span class="fc" id="L267"> String lhs = entry.getKey();</span>
<span class="fc" id="L268"> String rhs = interpolator.interpolate(entry.getValue());</span>
<span class="fc" id="L270"> String beanId = parseBeanId(lhs);</span>
<span class="fc bfc" id="L271" title="All 2 branches covered."> if (beanId != null) { //a beanId could be parsed, so the line is a bean instance definition</span>
<span class="fc" id="L272"> processor.add(new InstantiationStatement(beanId, rhs));</span>
} else { //the line must be a property configuration
<span class="fc" id="L274"> processor.add(new AssignmentStatement(lhs, rhs));</span>
}
<span class="fc" id="L276"> }</span>
<span class="fc" id="L278"> processor.execute();</span>
}
//SHIRO-413: init method must be called for constructed objects that are Initializable
<span class="fc" id="L282"> LifecycleUtils.init(objects.values());</span>
<span class="fc" id="L284"> return objects;</span>
}
public void destroy() {
<span class="fc" id="L288"> final Map&lt;String, Object&gt; immutableObjects = Collections.unmodifiableMap(objects);</span>
//destroy objects in the opposite order they were initialized:
<span class="fc" id="L291"> List&lt;Map.Entry&lt;String,?&gt;&gt; entries = new ArrayList&lt;Map.Entry&lt;String,?&gt;&gt;(objects.entrySet());</span>
<span class="fc" id="L292"> Collections.reverse(entries);</span>
<span class="fc bfc" id="L294" title="All 2 branches covered."> for(Map.Entry&lt;String, ?&gt; entry: entries) {</span>
<span class="fc" id="L295"> String id = entry.getKey();</span>
<span class="fc" id="L296"> Object bean = entry.getValue();</span>
//don't destroy the eventbus until the end - we need it to still be 'alive' while publishing destroy events:
<span class="fc bfc" id="L299" title="All 2 branches covered."> if (bean != this.eventBus) { //memory equality check (not .equals) on purpose</span>
<span class="fc" id="L300"> LifecycleUtils.destroy(bean);</span>
<span class="fc" id="L301"> BeanEvent event = new DestroyedBeanEvent(id, bean, immutableObjects);</span>
<span class="fc" id="L302"> eventBus.publish(event);</span>
<span class="fc" id="L303"> this.eventBus.unregister(bean); //bean is now destroyed - it should not receive any other events</span>
}
<span class="fc" id="L305"> }</span>
//only now destroy the event bus:
<span class="fc" id="L307"> LifecycleUtils.destroy(this.eventBus);</span>
<span class="fc" id="L308"> }</span>
protected void createNewInstance(Map&lt;String, Object&gt; objects, String name, String value) {
<span class="fc" id="L312"> Object currentInstance = objects.get(name);</span>
<span class="pc bpc" id="L313" title="1 of 2 branches missed."> if (currentInstance != null) {</span>
<span class="nc" id="L314"> log.info(&quot;An instance with name '{}' already exists. &quot; +</span>
&quot;Redefining this object as a new instance of type {}&quot;, name, value);
}
Object instance;//name with no property, assume right hand side of equals sign is the class name:
try {
<span class="fc" id="L320"> instance = ClassUtils.newInstance(value);</span>
<span class="fc bfc" id="L321" title="All 2 branches covered."> if (instance instanceof Nameable) {</span>
<span class="fc" id="L322"> ((Nameable) instance).setName(name);</span>
}
<span class="nc" id="L324"> } catch (Exception e) {</span>
<span class="nc" id="L325"> String msg = &quot;Unable to instantiate class [&quot; + value + &quot;] for object named '&quot; + name + &quot;'. &quot; +</span>
&quot;Please ensure you've specified the fully qualified class name correctly.&quot;;
<span class="nc" id="L327"> throw new ConfigurationException(msg, e);</span>
<span class="fc" id="L328"> }</span>
<span class="fc" id="L329"> objects.put(name, instance);</span>
<span class="fc" id="L330"> }</span>
protected void applyProperty(String key, String value, Map objects) {
<span class="fc" id="L334"> int index = key.indexOf('.');</span>
<span class="pc bpc" id="L336" title="1 of 2 branches missed."> if (index &gt;= 0) {</span>
<span class="fc" id="L337"> String name = key.substring(0, index);</span>
<span class="fc" id="L338"> String property = key.substring(index + 1, key.length());</span>
<span class="pc bpc" id="L340" title="1 of 2 branches missed."> if (GLOBAL_PROPERTY_PREFIX.equalsIgnoreCase(name)) {</span>
<span class="nc" id="L341"> applyGlobalProperty(objects, property, value);</span>
} else {
<span class="fc" id="L343"> applySingleProperty(objects, name, property, value);</span>
}
<span class="fc" id="L346"> } else {</span>
<span class="nc" id="L347"> throw new IllegalArgumentException(&quot;All property keys must contain a '.' character. &quot; +</span>
&quot;(e.g. myBean.property = value) These should already be separated out by buildObjects().&quot;);
}
<span class="fc" id="L350"> }</span>
protected void applyGlobalProperty(Map objects, String property, String value) {
<span class="nc bnc" id="L353" title="All 2 branches missed."> for (Object instance : objects.values()) {</span>
try {
<span class="nc" id="L355"> PropertyDescriptor pd = beanUtilsBean.getPropertyUtils().getPropertyDescriptor(instance, property);</span>
<span class="nc bnc" id="L356" title="All 2 branches missed."> if (pd != null) {</span>
<span class="nc" id="L357"> applyProperty(instance, property, value);</span>
}
<span class="nc" id="L359"> } catch (Exception e) {</span>
<span class="nc" id="L360"> String msg = &quot;Error retrieving property descriptor for instance &quot; +</span>
<span class="nc" id="L361"> &quot;of type [&quot; + instance.getClass().getName() + &quot;] &quot; +</span>
&quot;while setting property [&quot; + property + &quot;]&quot;;
<span class="nc" id="L363"> throw new ConfigurationException(msg, e);</span>
<span class="nc" id="L364"> }</span>
<span class="nc" id="L365"> }</span>
<span class="nc" id="L366"> }</span>
protected void applySingleProperty(Map objects, String name, String property, String value) {
<span class="fc" id="L369"> Object instance = objects.get(name);</span>
<span class="pc bpc" id="L370" title="1 of 2 branches missed."> if (property.equals(&quot;class&quot;)) {</span>
<span class="nc" id="L371"> throw new IllegalArgumentException(&quot;Property keys should not contain 'class' properties since these &quot; +</span>
&quot;should already be separated out by buildObjects().&quot;);
<span class="pc bpc" id="L374" title="1 of 2 branches missed."> } else if (instance == null) {</span>
<span class="nc" id="L375"> String msg = &quot;Configuration error. Specified object [&quot; + name + &quot;] with property [&quot; +</span>
property + &quot;] without first defining that object's class. Please first &quot; +
&quot;specify the class property first, e.g. myObject = fully_qualified_class_name &quot; +
&quot;and then define additional properties.&quot;;
<span class="nc" id="L379"> throw new IllegalArgumentException(msg);</span>
} else {
<span class="fc" id="L382"> applyProperty(instance, property, value);</span>
}
<span class="fc" id="L384"> }</span>
protected boolean isReference(String value) {
<span class="pc bpc" id="L387" title="1 of 4 branches missed."> return value != null &amp;&amp; value.startsWith(OBJECT_REFERENCE_BEGIN_TOKEN);</span>
}
protected String getId(String referenceToken) {
<span class="fc" id="L391"> return referenceToken.substring(OBJECT_REFERENCE_BEGIN_TOKEN.length());</span>
}
protected Object getReferencedObject(String id) {
<span class="pc bpc" id="L395" title="2 of 4 branches missed."> Object o = objects != null &amp;&amp; !objects.isEmpty() ? objects.get(id) : null;</span>
<span class="fc bfc" id="L396" title="All 2 branches covered."> if (o == null) {</span>
<span class="fc" id="L397"> String msg = &quot;The object with id [&quot; + id + &quot;] has not yet been defined and therefore cannot be &quot; +</span>
&quot;referenced. Please ensure objects are defined in the order in which they should be &quot; +
&quot;created and made available for future reference.&quot;;
<span class="fc" id="L400"> throw new UnresolveableReferenceException(msg);</span>
}
<span class="fc" id="L402"> return o;</span>
}
protected String unescapeIfNecessary(String value) {
<span class="pc bpc" id="L406" title="1 of 4 branches missed."> if (value != null &amp;&amp; value.startsWith(ESCAPED_OBJECT_REFERENCE_BEGIN_TOKEN)) {</span>
<span class="fc" id="L407"> return value.substring(ESCAPED_OBJECT_REFERENCE_BEGIN_TOKEN.length() - 1);</span>
}
<span class="fc" id="L409"> return value;</span>
}
protected Object resolveReference(String reference) {
<span class="fc" id="L413"> String id = getId(reference);</span>
<span class="fc" id="L414"> log.debug(&quot;Encountered object reference '{}'. Looking up object with id '{}'&quot;, reference, id);</span>
<span class="fc" id="L415"> final Object referencedObject = getReferencedObject(id);</span>
<span class="fc bfc" id="L416" title="All 2 branches covered."> if (referencedObject instanceof Factory) {</span>
<span class="fc" id="L417"> return ((Factory) referencedObject).getInstance();</span>
}
<span class="fc" id="L419"> return referencedObject;</span>
}
protected boolean isTypedProperty(Object object, String propertyName, Class clazz) {
<span class="pc bpc" id="L423" title="1 of 2 branches missed."> if (clazz == null) {</span>
<span class="nc" id="L424"> throw new NullPointerException(&quot;type (class) argument cannot be null.&quot;);</span>
}
try {
<span class="fc" id="L427"> PropertyDescriptor descriptor = beanUtilsBean.getPropertyUtils().getPropertyDescriptor(object, propertyName);</span>
<span class="pc bpc" id="L428" title="1 of 2 branches missed."> if (descriptor == null) {</span>
<span class="nc" id="L429"> String msg = &quot;Property '&quot; + propertyName + &quot;' does not exist for object of &quot; +</span>
<span class="nc" id="L430"> &quot;type &quot; + object.getClass().getName() + &quot;.&quot;;</span>
<span class="nc" id="L431"> throw new ConfigurationException(msg);</span>
}
<span class="fc" id="L433"> Class propertyClazz = descriptor.getPropertyType();</span>
<span class="fc" id="L434"> return clazz.isAssignableFrom(propertyClazz);</span>
<span class="nc" id="L435"> } catch (ConfigurationException ce) {</span>
//let it propagate:
<span class="nc" id="L437"> throw ce;</span>
<span class="nc" id="L438"> } catch (Exception e) {</span>
<span class="nc" id="L439"> String msg = &quot;Unable to determine if property [&quot; + propertyName + &quot;] represents a &quot; + clazz.getName();</span>
<span class="nc" id="L440"> throw new ConfigurationException(msg, e);</span>
}
}
protected Set&lt;?&gt; toSet(String sValue) {
<span class="fc" id="L445"> String[] tokens = StringUtils.split(sValue);</span>
<span class="pc bpc" id="L446" title="2 of 4 branches missed."> if (tokens == null || tokens.length &lt;= 0) {</span>
<span class="nc" id="L447"> return null;</span>
}
//SHIRO-423: check to see if the value is a referenced Set already, and if so, return it immediately:
<span class="pc bpc" id="L451" title="1 of 4 branches missed."> if (tokens.length == 1 &amp;&amp; isReference(tokens[0])) {</span>
<span class="fc" id="L452"> Object reference = resolveReference(tokens[0]);</span>
<span class="pc bpc" id="L453" title="1 of 2 branches missed."> if (reference instanceof Set) {</span>
<span class="fc" id="L454"> return (Set)reference;</span>
}
}
<span class="fc" id="L458"> Set&lt;String&gt; setTokens = new LinkedHashSet&lt;String&gt;(Arrays.asList(tokens));</span>
//now convert into correct values and/or references:
<span class="fc" id="L461"> Set&lt;Object&gt; values = new LinkedHashSet&lt;Object&gt;(setTokens.size());</span>
<span class="fc bfc" id="L462" title="All 2 branches covered."> for (String token : setTokens) {</span>
<span class="fc" id="L463"> Object value = resolveValue(token);</span>
<span class="fc" id="L464"> values.add(value);</span>
<span class="fc" id="L465"> }</span>
<span class="fc" id="L466"> return values;</span>
}
protected Map&lt;?, ?&gt; toMap(String sValue) {
<span class="fc" id="L470"> String[] tokens = StringUtils.split(sValue, StringUtils.DEFAULT_DELIMITER_CHAR,</span>
StringUtils.DEFAULT_QUOTE_CHAR, StringUtils.DEFAULT_QUOTE_CHAR, true, true);
<span class="pc bpc" id="L472" title="2 of 4 branches missed."> if (tokens == null || tokens.length &lt;= 0) {</span>
<span class="nc" id="L473"> return null;</span>
}
//SHIRO-423: check to see if the value is a referenced Map already, and if so, return it immediately:
<span class="pc bpc" id="L477" title="1 of 4 branches missed."> if (tokens.length == 1 &amp;&amp; isReference(tokens[0])) {</span>
<span class="fc" id="L478"> Object reference = resolveReference(tokens[0]);</span>
<span class="pc bpc" id="L479" title="1 of 2 branches missed."> if (reference instanceof Map) {</span>
<span class="fc" id="L480"> return (Map)reference;</span>
}
}
<span class="fc" id="L484"> Map&lt;String, String&gt; mapTokens = new LinkedHashMap&lt;String, String&gt;(tokens.length);</span>
<span class="fc bfc" id="L485" title="All 2 branches covered."> for (String token : tokens) {</span>
<span class="fc" id="L486"> String[] kvPair = StringUtils.split(token, MAP_KEY_VALUE_DELIMITER);</span>
<span class="pc bpc" id="L487" title="2 of 4 branches missed."> if (kvPair == null || kvPair.length != 2) {</span>
<span class="nc" id="L488"> String msg = &quot;Map property value [&quot; + sValue + &quot;] contained key-value pair token [&quot; +</span>
token + &quot;] that does not properly split to a single key and pair. This must be the &quot; +
&quot;case for all map entries.&quot;;
<span class="nc" id="L491"> throw new ConfigurationException(msg);</span>
}
<span class="fc" id="L493"> mapTokens.put(kvPair[0], kvPair[1]);</span>
}
//now convert into correct values and/or references:
<span class="fc" id="L497"> Map&lt;Object, Object&gt; map = new LinkedHashMap&lt;Object, Object&gt;(mapTokens.size());</span>
<span class="fc bfc" id="L498" title="All 2 branches covered."> for (Map.Entry&lt;String, String&gt; entry : mapTokens.entrySet()) {</span>
<span class="fc" id="L499"> Object key = resolveValue(entry.getKey());</span>
<span class="fc" id="L500"> Object value = resolveValue(entry.getValue());</span>
<span class="fc" id="L501"> map.put(key, value);</span>
<span class="fc" id="L502"> }</span>
<span class="fc" id="L503"> return map;</span>
}
// @since 1.2.2
protected Collection&lt;?&gt; toCollection(String sValue) {
<span class="fc" id="L509"> String[] tokens = StringUtils.split(sValue);</span>
<span class="pc bpc" id="L510" title="2 of 4 branches missed."> if (tokens == null || tokens.length &lt;= 0) {</span>
<span class="nc" id="L511"> return null;</span>
}
//SHIRO-423: check to see if the value is a referenced Collection already, and if so, return it immediately:
<span class="pc bpc" id="L515" title="1 of 4 branches missed."> if (tokens.length == 1 &amp;&amp; isReference(tokens[0])) {</span>
<span class="fc" id="L516"> Object reference = resolveReference(tokens[0]);</span>
<span class="fc bfc" id="L517" title="All 2 branches covered."> if (reference instanceof Collection) {</span>
<span class="fc" id="L518"> return (Collection)reference;</span>
}
}
//now convert into correct values and/or references:
<span class="fc" id="L523"> List&lt;Object&gt; values = new ArrayList&lt;Object&gt;(tokens.length);</span>
<span class="fc bfc" id="L524" title="All 2 branches covered."> for (String token : tokens) {</span>
<span class="fc" id="L525"> Object value = resolveValue(token);</span>
<span class="fc" id="L526"> values.add(value);</span>
}
<span class="fc" id="L528"> return values;</span>
}
protected List&lt;?&gt; toList(String sValue) {
<span class="fc" id="L532"> String[] tokens = StringUtils.split(sValue);</span>
<span class="pc bpc" id="L533" title="2 of 4 branches missed."> if (tokens == null || tokens.length &lt;= 0) {</span>
<span class="nc" id="L534"> return null;</span>
}
//SHIRO-423: check to see if the value is a referenced List already, and if so, return it immediately:
<span class="pc bpc" id="L538" title="1 of 4 branches missed."> if (tokens.length == 1 &amp;&amp; isReference(tokens[0])) {</span>
<span class="fc" id="L539"> Object reference = resolveReference(tokens[0]);</span>
<span class="pc bpc" id="L540" title="1 of 2 branches missed."> if (reference instanceof List) {</span>
<span class="fc" id="L541"> return (List)reference;</span>
}
}
//now convert into correct values and/or references:
<span class="fc" id="L546"> List&lt;Object&gt; values = new ArrayList&lt;Object&gt;(tokens.length);</span>
<span class="fc bfc" id="L547" title="All 2 branches covered."> for (String token : tokens) {</span>
<span class="fc" id="L548"> Object value = resolveValue(token);</span>
<span class="fc" id="L549"> values.add(value);</span>
}
<span class="fc" id="L551"> return values;</span>
}
protected byte[] toBytes(String sValue) {
<span class="pc bpc" id="L555" title="1 of 2 branches missed."> if (sValue == null) {</span>
<span class="nc" id="L556"> return null;</span>
}
byte[] bytes;
<span class="fc bfc" id="L559" title="All 2 branches covered."> if (sValue.startsWith(HEX_BEGIN_TOKEN)) {</span>
<span class="fc" id="L560"> String hex = sValue.substring(HEX_BEGIN_TOKEN.length());</span>
<span class="fc" id="L561"> bytes = Hex.decode(hex);</span>
<span class="fc" id="L562"> } else {</span>
//assume base64 encoded:
<span class="fc" id="L564"> bytes = Base64.decode(sValue);</span>
}
<span class="fc" id="L566"> return bytes;</span>
}
protected Object resolveValue(String stringValue) {
Object value;
<span class="fc bfc" id="L571" title="All 2 branches covered."> if (isReference(stringValue)) {</span>
<span class="fc" id="L572"> value = resolveReference(stringValue);</span>
} else {
<span class="fc" id="L574"> value = unescapeIfNecessary(stringValue);</span>
}
<span class="fc" id="L576"> return value;</span>
}
protected String checkForNullOrEmptyLiteral(String stringValue) {
<span class="pc bpc" id="L580" title="1 of 2 branches missed."> if (stringValue == null) {</span>
<span class="nc" id="L581"> return null;</span>
}
//check if the value is the actual literal string 'null' (expected to be wrapped in quotes):
<span class="fc bfc" id="L584" title="All 2 branches covered."> if (stringValue.equals(&quot;\&quot;null\&quot;&quot;)) {</span>
<span class="fc" id="L585"> return NULL_VALUE_TOKEN;</span>
}
//or the actual literal string of two quotes '&quot;&quot;' (expected to be wrapped in quotes):
<span class="fc bfc" id="L588" title="All 2 branches covered."> else if (stringValue.equals(&quot;\&quot;\&quot;\&quot;\&quot;&quot;)) {</span>
<span class="fc" id="L589"> return EMPTY_STRING_VALUE_TOKEN;</span>
} else {
<span class="fc" id="L591"> return stringValue;</span>
}
}
protected void applyProperty(Object object, String propertyPath, Object value) {
<span class="fc" id="L597"> int mapBegin = propertyPath.indexOf(MAP_PROPERTY_BEGIN_TOKEN);</span>
<span class="fc" id="L598"> int mapEnd = -1;</span>
<span class="fc" id="L599"> String mapPropertyPath = null;</span>
<span class="fc" id="L600"> String keyString = null;</span>
<span class="fc" id="L602"> String remaining = null;</span>
<span class="fc bfc" id="L604" title="All 2 branches covered."> if (mapBegin &gt;= 0) {</span>
//a map is being referenced in the overall property path. Find just the map's path:
<span class="fc" id="L606"> mapPropertyPath = propertyPath.substring(0, mapBegin);</span>
//find the end of the map reference:
<span class="fc" id="L608"> mapEnd = propertyPath.indexOf(MAP_PROPERTY_END_TOKEN, mapBegin);</span>
//find the token in between the [ and the ] (the map/array key or index):
<span class="fc" id="L610"> keyString = propertyPath.substring(mapBegin+1, mapEnd);</span>
//find out if there is more path reference to follow. If not, we're at a terminal of the OGNL expression
<span class="fc bfc" id="L613" title="All 2 branches covered."> if (propertyPath.length() &gt; (mapEnd+1)) {</span>
<span class="fc" id="L614"> remaining = propertyPath.substring(mapEnd+1);</span>
<span class="pc bpc" id="L615" title="1 of 2 branches missed."> if (remaining.startsWith(&quot;.&quot;)) {</span>
<span class="fc" id="L616"> remaining = StringUtils.clean(remaining.substring(1));</span>
}
}
}
<span class="fc bfc" id="L621" title="All 2 branches covered."> if (remaining == null) {</span>
//we've terminated the OGNL expression. Check to see if we're assigning a property or a map entry:
<span class="fc bfc" id="L623" title="All 2 branches covered."> if (keyString == null) {</span>
//not a map or array value assignment - assign the property directly:
<span class="fc" id="L625"> setProperty(object, propertyPath, value);</span>
} else {
//we're assigning a map or array entry. Check to see which we should call:
<span class="fc bfc" id="L628" title="All 2 branches covered."> if (isTypedProperty(object, mapPropertyPath, Map.class)) {</span>
<span class="fc" id="L629"> Map map = (Map)getProperty(object, mapPropertyPath);</span>
<span class="fc" id="L630"> Object mapKey = resolveValue(keyString);</span>
//noinspection unchecked
<span class="fc" id="L632"> map.put(mapKey, value);</span>
<span class="fc" id="L633"> } else {</span>
//must be an array property. Convert the key string to an index:
<span class="fc" id="L635"> int index = Integer.valueOf(keyString);</span>
<span class="fc" id="L636"> setIndexedProperty(object, mapPropertyPath, index, value);</span>
<span class="fc" id="L637"> }</span>
}
} else {
//property is being referenced as part of a nested path. Find the referenced map/array entry and
//recursively call this method with the remaining property path
<span class="fc" id="L642"> Object referencedValue = null;</span>
<span class="fc bfc" id="L643" title="All 2 branches covered."> if (isTypedProperty(object, mapPropertyPath, Map.class)) {</span>
<span class="fc" id="L644"> Map map = (Map)getProperty(object, mapPropertyPath);</span>
<span class="fc" id="L645"> Object mapKey = resolveValue(keyString);</span>
<span class="fc" id="L646"> referencedValue = map.get(mapKey);</span>
<span class="fc" id="L647"> } else {</span>
//must be an array property:
<span class="fc" id="L649"> int index = Integer.valueOf(keyString);</span>
<span class="fc" id="L650"> referencedValue = getIndexedProperty(object, mapPropertyPath, index);</span>
}
<span class="pc bpc" id="L653" title="1 of 2 branches missed."> if (referencedValue == null) {</span>
<span class="nc" id="L654"> throw new ConfigurationException(&quot;Referenced map/array value '&quot; + mapPropertyPath + &quot;[&quot; +</span>
keyString + &quot;]' does not exist.&quot;);
}
<span class="fc" id="L658"> applyProperty(referencedValue, remaining, value);</span>
}
<span class="fc" id="L660"> }</span>
private void setProperty(Object object, String propertyPath, Object value) {
try {
<span class="fc bfc" id="L664" title="All 2 branches covered."> if (log.isTraceEnabled()) {</span>
<span class="fc" id="L665"> log.trace(&quot;Applying property [{}] value [{}] on object of type [{}]&quot;,</span>
<span class="fc" id="L666"> new Object[]{propertyPath, value, object.getClass().getName()});</span>
}
<span class="fc" id="L668"> beanUtilsBean.setProperty(object, propertyPath, value);</span>
<span class="fc" id="L669"> } catch (Exception e) {</span>
<span class="pc bpc" id="L670" title="1 of 2 branches missed."> String msg = &quot;Unable to set property '&quot; + propertyPath + &quot;' with value [&quot; + value + &quot;] on object &quot; +</span>
<span class="pc" id="L671"> &quot;of type &quot; + (object != null ? object.getClass().getName() : null) + &quot;. If &quot; +</span>
&quot;'&quot; + value + &quot;' is a reference to another (previously defined) object, prefix it with &quot; +
&quot;'&quot; + OBJECT_REFERENCE_BEGIN_TOKEN + &quot;' to indicate that the referenced &quot; +
&quot;object should be used as the actual value. &quot; +
&quot;For example, &quot; + OBJECT_REFERENCE_BEGIN_TOKEN + value;
<span class="fc" id="L676"> throw new ConfigurationException(msg, e);</span>
<span class="fc" id="L677"> }</span>
<span class="fc" id="L678"> }</span>
private Object getProperty(Object object, String propertyPath) {
try {
<span class="fc" id="L682"> return beanUtilsBean.getPropertyUtils().getProperty(object, propertyPath);</span>
<span class="nc" id="L683"> } catch (Exception e) {</span>
<span class="nc" id="L684"> throw new ConfigurationException(&quot;Unable to access property '&quot; + propertyPath + &quot;'&quot;, e);</span>
}
}
private void setIndexedProperty(Object object, String propertyPath, int index, Object value) {
try {
<span class="fc" id="L690"> beanUtilsBean.getPropertyUtils().setIndexedProperty(object, propertyPath, index, value);</span>
<span class="nc" id="L691"> } catch (Exception e) {</span>
<span class="nc" id="L692"> throw new ConfigurationException(&quot;Unable to set array property '&quot; + propertyPath + &quot;'&quot;, e);</span>
<span class="fc" id="L693"> }</span>
<span class="fc" id="L694"> }</span>
private Object getIndexedProperty(Object object, String propertyPath, int index) {
try {
<span class="fc" id="L698"> return beanUtilsBean.getPropertyUtils().getIndexedProperty(object, propertyPath, index);</span>
<span class="nc" id="L699"> } catch (Exception e) {</span>
<span class="nc" id="L700"> throw new ConfigurationException(&quot;Unable to acquire array property '&quot; + propertyPath + &quot;'&quot;, e);</span>
}
}
protected boolean isIndexedPropertyAssignment(String propertyPath) {
<span class="fc" id="L705"> return propertyPath.endsWith(&quot;&quot; + MAP_PROPERTY_END_TOKEN);</span>
}
protected void applyProperty(Object object, String propertyName, String stringValue) {
Object value;
<span class="fc bfc" id="L712" title="All 2 branches covered."> if (NULL_VALUE_TOKEN.equals(stringValue)) {</span>
<span class="fc" id="L713"> value = null;</span>
<span class="fc bfc" id="L714" title="All 2 branches covered."> } else if (EMPTY_STRING_VALUE_TOKEN.equals(stringValue)) {</span>
<span class="fc" id="L715"> value = StringUtils.EMPTY_STRING;</span>
<span class="fc bfc" id="L716" title="All 2 branches covered."> } else if (isIndexedPropertyAssignment(propertyName)) {</span>
<span class="fc" id="L717"> String checked = checkForNullOrEmptyLiteral(stringValue);</span>
<span class="fc" id="L718"> value = resolveValue(checked);</span>
<span class="fc bfc" id="L719" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, Set.class)) {</span>
<span class="fc" id="L720"> value = toSet(stringValue);</span>
<span class="fc bfc" id="L721" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, Map.class)) {</span>
<span class="fc" id="L722"> value = toMap(stringValue);</span>
<span class="fc bfc" id="L723" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, List.class)) {</span>
<span class="fc" id="L724"> value = toList(stringValue);</span>
<span class="fc bfc" id="L725" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, Collection.class)) {</span>
<span class="fc" id="L726"> value = toCollection(stringValue);</span>
<span class="fc bfc" id="L727" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, byte[].class)) {</span>
<span class="fc" id="L728"> value = toBytes(stringValue);</span>
<span class="pc bpc" id="L729" title="1 of 2 branches missed."> } else if (isTypedProperty(object, propertyName, ByteSource.class)) {</span>
<span class="nc" id="L730"> byte[] bytes = toBytes(stringValue);</span>
<span class="nc" id="L731"> value = ByteSource.Util.bytes(bytes);</span>
<span class="nc" id="L732"> } else {</span>
<span class="fc" id="L733"> String checked = checkForNullOrEmptyLiteral(stringValue);</span>
<span class="fc" id="L734"> value = resolveValue(checked);</span>
}
<span class="fc" id="L737"> applyProperty(object, propertyName, value);</span>
<span class="fc" id="L738"> }</span>
private Interpolator createInterpolator() {
<span class="fc bfc" id="L742" title="All 2 branches covered."> if (ClassUtils.isAvailable(&quot;org.apache.commons.configuration2.interpol.ConfigurationInterpolator&quot;)) {</span>
<span class="fc" id="L743"> return new CommonsInterpolator();</span>
}
<span class="fc" id="L746"> return new DefaultInterpolator();</span>
}
/**
* Sets the {@link Interpolator} used when evaluating the right side of the expressions.
* @since 1.4
*/
public void setInterpolator(Interpolator interpolator) {
<span class="nc" id="L754"> this.interpolator = interpolator;</span>
<span class="nc" id="L755"> }</span>
<span class="fc" id="L757"> private class BeanConfigurationProcessor {</span>
<span class="fc" id="L759"> private final List&lt;Statement&gt; statements = new ArrayList&lt;Statement&gt;();</span>
<span class="fc" id="L760"> private final List&lt;BeanConfiguration&gt; beanConfigurations = new ArrayList&lt;BeanConfiguration&gt;();</span>
public void add(Statement statement) {
<span class="fc" id="L764"> statements.add(statement); //we execute bean configuration statements in the order they are declared.</span>
<span class="fc bfc" id="L766" title="All 2 branches covered."> if (statement instanceof InstantiationStatement) {</span>
<span class="fc" id="L767"> InstantiationStatement is = (InstantiationStatement)statement;</span>
<span class="fc" id="L768"> beanConfigurations.add(new BeanConfiguration(is));</span>
<span class="fc" id="L769"> } else {</span>
<span class="fc" id="L770"> AssignmentStatement as = (AssignmentStatement)statement;</span>
//statements always apply to the most recently defined bean configuration with the same name, so we
//have to traverse the configuration list starting at the end (most recent elements are appended):
<span class="fc" id="L773"> boolean addedToConfig = false;</span>
<span class="fc" id="L774"> String beanName = as.getRootBeanName();</span>
<span class="fc bfc" id="L775" title="All 2 branches covered."> for( int i = beanConfigurations.size()-1; i &gt;= 0; i--) {</span>
<span class="fc" id="L776"> BeanConfiguration mostRecent = beanConfigurations.get(i);</span>
<span class="fc" id="L777"> String mostRecentBeanName = mostRecent.getBeanName();</span>
<span class="fc bfc" id="L778" title="All 2 branches covered."> if (beanName.equals(mostRecentBeanName)) {</span>
<span class="fc" id="L779"> mostRecent.add(as);</span>
<span class="fc" id="L780"> addedToConfig = true;</span>
<span class="fc" id="L781"> break;</span>
}
}
<span class="fc bfc" id="L785" title="All 2 branches covered."> if (!addedToConfig) {</span>
// the AssignmentStatement must be for an existing bean that does not yet have a corresponding
// configuration object (this would happen if the bean is in the default objects map). Because
// BeanConfiguration instances don't exist for default (already instantiated) beans,
// we simulate a creation of one to satisfy this processors implementation:
<span class="fc" id="L790"> beanConfigurations.add(new BeanConfiguration(as));</span>
}
}
<span class="fc" id="L793"> }</span>
public void execute() {
<span class="fc bfc" id="L797" title="All 2 branches covered."> for( Statement statement : statements) {</span>
<span class="fc" id="L799"> statement.execute();</span>
<span class="fc" id="L801"> BeanConfiguration bd = statement.getBeanConfiguration();</span>
<span class="fc bfc" id="L803" title="All 2 branches covered."> if (bd.isExecuted()) { //bean is fully configured, no more statements to execute for it:</span>
//bean configured overrides the 'eventBus' bean - replace the existing eventBus with the one configured:
<span class="pc bpc" id="L806" title="1 of 2 branches missed."> if (bd.getBeanName().equals(EVENT_BUS_NAME)) {</span>
<span class="nc" id="L807"> EventBus eventBus = (EventBus)bd.getBean();</span>
<span class="nc" id="L808"> enableEvents(eventBus);</span>
}
//ignore global 'shiro.' shortcut mechanism:
<span class="pc bpc" id="L812" title="1 of 2 branches missed."> if (!bd.isGlobalConfig()) {</span>
<span class="fc" id="L813"> BeanEvent event = new ConfiguredBeanEvent(bd.getBeanName(), bd.getBean(),</span>
<span class="fc" id="L814"> Collections.unmodifiableMap(objects));</span>
<span class="fc" id="L815"> eventBus.publish(event);</span>
}
//initialize the bean if necessary:
<span class="fc" id="L819"> LifecycleUtils.init(bd.getBean());</span>
//ignore global 'shiro.' shortcut mechanism:
<span class="pc bpc" id="L822" title="1 of 2 branches missed."> if (!bd.isGlobalConfig()) {</span>
<span class="fc" id="L823"> BeanEvent event = new InitializedBeanEvent(bd.getBeanName(), bd.getBean(),</span>
<span class="fc" id="L824"> Collections.unmodifiableMap(objects));</span>
<span class="fc" id="L825"> eventBus.publish(event);</span>
}
}
<span class="fc" id="L828"> }</span>
<span class="fc" id="L829"> }</span>
}
private class BeanConfiguration {
private final InstantiationStatement instantiationStatement;
<span class="fc" id="L835"> private final List&lt;AssignmentStatement&gt; assignments = new ArrayList&lt;AssignmentStatement&gt;();</span>
private final String beanName;
private Object bean;
<span class="fc" id="L839"> private BeanConfiguration(InstantiationStatement statement) {</span>
<span class="fc" id="L840"> statement.setBeanConfiguration(this);</span>
<span class="fc" id="L841"> this.instantiationStatement = statement;</span>
<span class="fc" id="L842"> this.beanName = statement.lhs;</span>
<span class="fc" id="L843"> }</span>
<span class="fc" id="L845"> private BeanConfiguration(AssignmentStatement as) {</span>
<span class="fc" id="L846"> this.instantiationStatement = null;</span>
<span class="fc" id="L847"> this.beanName = as.getRootBeanName();</span>
<span class="fc" id="L848"> add(as);</span>
<span class="fc" id="L849"> }</span>
public String getBeanName() {
<span class="fc" id="L852"> return this.beanName;</span>
}
public boolean isGlobalConfig() { //BeanConfiguration instance representing the global 'shiro.' properties
// (we should remove this concept).
<span class="fc" id="L857"> return GLOBAL_PROPERTY_PREFIX.equals(getBeanName());</span>
}
public void add(AssignmentStatement as) {
<span class="fc" id="L861"> as.setBeanConfiguration(this);</span>
<span class="fc" id="L862"> assignments.add(as);</span>
<span class="fc" id="L863"> }</span>
/**
* When this configuration is parsed sufficiently to create (or find) an actual bean instance, that instance
* will be associated with its configuration by setting it via this method.
*
* @param bean the bean instantiated (or found) that corresponds to this BeanConfiguration instance.
*/
public void setBean(Object bean) {
<span class="fc" id="L872"> this.bean = bean;</span>
<span class="fc" id="L873"> }</span>
public Object getBean() {
<span class="fc" id="L876"> return this.bean;</span>
}
/**
* Returns true if all configuration statements have been executed.
* @return true if all configuration statements have been executed.
*/
public boolean isExecuted() {
<span class="pc bpc" id="L884" title="1 of 4 branches missed."> if (instantiationStatement != null &amp;&amp; !instantiationStatement.isExecuted()) {</span>
<span class="nc" id="L885"> return false;</span>
}
<span class="fc bfc" id="L887" title="All 2 branches covered."> for (AssignmentStatement as : assignments) {</span>
<span class="fc bfc" id="L888" title="All 2 branches covered."> if (!as.isExecuted()) {</span>
<span class="fc" id="L889"> return false;</span>
}
<span class="fc" id="L891"> }</span>
<span class="fc" id="L892"> return true;</span>
}
}
private abstract class Statement {
protected final String lhs;
protected final String rhs;
protected Object bean;
private Object result;
private boolean executed;
private BeanConfiguration beanConfiguration;
<span class="fc" id="L905"> private Statement(String lhs, String rhs) {</span>
<span class="fc" id="L906"> this.lhs = lhs;</span>
<span class="fc" id="L907"> this.rhs = rhs;</span>
<span class="fc" id="L908"> this.executed = false;</span>
<span class="fc" id="L909"> }</span>
public void setBeanConfiguration(BeanConfiguration bd) {
<span class="fc" id="L912"> this.beanConfiguration = bd;</span>
<span class="fc" id="L913"> }</span>
public BeanConfiguration getBeanConfiguration() {
<span class="fc" id="L916"> return this.beanConfiguration;</span>
}
public Object execute() {
<span class="pc bpc" id="L920" title="1 of 2 branches missed."> if (!isExecuted()) {</span>
<span class="fc" id="L921"> this.result = doExecute();</span>
<span class="fc" id="L922"> this.executed = true;</span>
}
<span class="pc bpc" id="L924" title="1 of 2 branches missed."> if (!getBeanConfiguration().isGlobalConfig()) {</span>
<span class="fc" id="L925"> Assert.notNull(this.bean, &quot;Implementation must set the root bean for which it executed.&quot;);</span>
}
<span class="fc" id="L927"> return this.result;</span>
}
public Object getBean() {
<span class="nc" id="L931"> return this.bean;</span>
}
protected void setBean(Object bean) {
<span class="fc" id="L935"> this.bean = bean;</span>
<span class="fc bfc" id="L936" title="All 2 branches covered."> if (this.beanConfiguration.getBean() == null) {</span>
<span class="fc" id="L937"> this.beanConfiguration.setBean(bean);</span>
}
<span class="fc" id="L939"> }</span>
public Object getResult() {
<span class="nc" id="L942"> return result;</span>
}
protected abstract Object doExecute();
public boolean isExecuted() {
<span class="fc" id="L948"> return executed;</span>
}
}
private class InstantiationStatement extends Statement {
<span class="fc" id="L954"> private InstantiationStatement(String lhs, String rhs) {</span>
<span class="fc" id="L955"> super(lhs, rhs);</span>
<span class="fc" id="L956"> }</span>
@Override
protected Object doExecute() {
<span class="fc" id="L960"> String beanName = this.lhs;</span>
<span class="fc" id="L961"> createNewInstance(objects, beanName, this.rhs);</span>
<span class="fc" id="L962"> Object instantiated = objects.get(beanName);</span>
<span class="fc" id="L963"> setBean(instantiated);</span>
//also ensure the instantiated bean has access to the event bus or is subscribed to events if necessary:
//Note: because events are being enabled on this bean here (before the instantiated event below is
//triggered), beans can react to their own instantiation events.
<span class="fc" id="L968"> enableEventsIfNecessary(instantiated, beanName);</span>
<span class="fc" id="L970"> BeanEvent event = new InstantiatedBeanEvent(beanName, instantiated, Collections.unmodifiableMap(objects));</span>
<span class="fc" id="L971"> eventBus.publish(event);</span>
<span class="fc" id="L973"> return instantiated;</span>
}
}
private class AssignmentStatement extends Statement {
private final String rootBeanName;
<span class="fc" id="L981"> private AssignmentStatement(String lhs, String rhs) {</span>
<span class="fc" id="L982"> super(lhs, rhs);</span>
<span class="fc" id="L983"> int index = lhs.indexOf('.');</span>
<span class="fc" id="L984"> this.rootBeanName = lhs.substring(0, index);</span>
<span class="fc" id="L985"> }</span>
@Override
protected Object doExecute() {
<span class="fc" id="L989"> applyProperty(lhs, rhs, objects);</span>
<span class="fc" id="L990"> Object bean = objects.get(this.rootBeanName);</span>
<span class="fc" id="L991"> setBean(bean);</span>
<span class="fc" id="L992"> return null;</span>
}
public String getRootBeanName() {
<span class="fc" id="L996"> return this.rootBeanName;</span>
}
}
//////////////////////////
// From CollectionUtils //
//////////////////////////
// CollectionUtils cannot be removed from shiro-core until 2.0 as it has a dependency on PrincipalCollection
private static boolean isEmpty(Map m) {
<span class="pc bpc" id="L1006" title="1 of 4 branches missed."> return m == null || m.isEmpty();</span>
}
private static boolean isEmpty(Collection c) {
<span class="pc bpc" id="L1010" title="1 of 4 branches missed."> return c == null || c.isEmpty();</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.3.201901230119</span></div></body></html>