| <?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 :: Jar Bundle</a> > <a href="../index.html" class="el_bundle">shiro-core</a> > <a href="index.source.html" class="el_package">org.apache.shiro.config</a> > <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 |
| * "License"); 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 |
| * "AS IS" 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.BeanUtils; |
| import org.apache.commons.beanutils.PropertyUtils; |
| 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.CollectionUtils; |
| 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 "property values". Typically these come from the Shiro INI configuration and are used |
| * to construct or modify the SecurityManager, its dependencies, and web-based security filters. |
| * <p/> |
| * 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="L71"> private static final Logger log = LoggerFactory.getLogger(ReflectionBuilder.class);</span> |
| |
| private static final String OBJECT_REFERENCE_BEGIN_TOKEN = "$"; |
| private static final String ESCAPED_OBJECT_REFERENCE_BEGIN_TOKEN = "\\$"; |
| private static final String GLOBAL_PROPERTY_PREFIX = "shiro"; |
| private static final char MAP_KEY_VALUE_DELIMITER = ':'; |
| private static final String HEX_BEGIN_TOKEN = "0x"; |
| private static final String NULL_VALUE_TOKEN = "null"; |
| private static final String EMPTY_STRING_VALUE_TOKEN = "\"\""; |
| private static final char STRING_VALUE_DELIMETER = '"'; |
| private static final char MAP_PROPERTY_BEGIN_TOKEN = '['; |
| private static final char MAP_PROPERTY_END_TOKEN = ']'; |
| |
| private static final String EVENT_BUS_NAME = "eventBus"; |
| |
| private final Map<String, Object> objects; |
| /** |
| * @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<String,Object> registeredEventSubscribers; |
| |
| //@since 1.3 |
| private Map<String,Object> createDefaultObjectMap() { |
| <span class="fc" id="L103"> Map<String,Object> map = new LinkedHashMap<String, Object>();</span> |
| <span class="fc" id="L104"> map.put(EVENT_BUS_NAME, new DefaultEventBus());</span> |
| <span class="fc" id="L105"> return map;</span> |
| } |
| |
| public ReflectionBuilder() { |
| <span class="fc" id="L109"> this(null);</span> |
| <span class="fc" id="L110"> }</span> |
| |
| <span class="fc" id="L112"> public ReflectionBuilder(Map<String, ?> defaults) {</span> |
| <span class="fc" id="L113"> this.objects = createDefaultObjectMap();</span> |
| <span class="fc" id="L114"> this.registeredEventSubscribers = new LinkedHashMap<String,Object>();</span> |
| <span class="fc" id="L115"> apply(defaults);</span> |
| <span class="fc" id="L116"> }</span> |
| |
| private void apply(Map<String, ?> objects) { |
| <span class="fc bfc" id="L119" title="All 2 branches covered."> if(!CollectionUtils.isEmpty(objects)) {</span> |
| <span class="fc" id="L120"> this.objects.putAll(objects);</span> |
| } |
| <span class="fc" id="L122"> EventBus found = findEventBus(this.objects);</span> |
| <span class="fc" id="L123"> Assert.notNull(found, "An " + EventBus.class.getName() + " instance must be present in the object defaults");</span> |
| <span class="fc" id="L124"> enableEvents(found);</span> |
| <span class="fc" id="L125"> }</span> |
| |
| public Map<String, ?> getObjects() { |
| <span class="fc" id="L128"> return objects;</span> |
| } |
| |
| /** |
| * @param objects |
| */ |
| public void setObjects(Map<String, ?> objects) { |
| <span class="nc" id="L135"> this.objects.clear();</span> |
| <span class="nc" id="L136"> this.objects.putAll(createDefaultObjectMap());</span> |
| <span class="nc" id="L137"> apply(objects);</span> |
| <span class="nc" id="L138"> }</span> |
| |
| //@since 1.3 |
| private void enableEvents(EventBus eventBus) { |
| <span class="fc" id="L142"> Assert.notNull(eventBus, "EventBus argument cannot be null.");</span> |
| //clean up old auto-registered subscribers: |
| <span class="pc bpc" id="L144" title="1 of 2 branches missed."> for (Object subscriber : this.registeredEventSubscribers.values()) {</span> |
| <span class="nc" id="L145"> this.eventBus.unregister(subscriber);</span> |
| <span class="nc" id="L146"> }</span> |
| <span class="fc" id="L147"> this.registeredEventSubscribers.clear();</span> |
| |
| <span class="fc" id="L149"> this.eventBus = eventBus;</span> |
| |
| <span class="fc bfc" id="L151" title="All 2 branches covered."> for(Map.Entry<String,Object> entry : this.objects.entrySet()) {</span> |
| <span class="fc" id="L152"> enableEventsIfNecessary(entry.getValue(), entry.getKey());</span> |
| <span class="fc" id="L153"> }</span> |
| <span class="fc" id="L154"> }</span> |
| |
| //@since 1.3 |
| private void enableEventsIfNecessary(Object bean, String name) { |
| <span class="fc" id="L158"> boolean applied = applyEventBusIfNecessary(bean);</span> |
| <span class="fc bfc" id="L159" 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="L165" title="All 2 branches covered."> if (isEventSubscriber(bean, name)) {</span> |
| //found an event subscriber, so register them with the EventBus: |
| <span class="fc" id="L167"> this.eventBus.register(bean);</span> |
| <span class="fc" id="L168"> this.registeredEventSubscribers.put(name, bean);</span> |
| } |
| } |
| <span class="fc" id="L171"> }</span> |
| |
| //@since 1.3 |
| private boolean isEventSubscriber(Object bean, String name) { |
| <span class="fc" id="L175"> List annotatedMethods = ClassUtils.getAnnotatedMethods(bean.getClass(), Subscribe.class);</span> |
| <span class="fc bfc" id="L176" title="All 2 branches covered."> return !CollectionUtils.isEmpty(annotatedMethods);</span> |
| } |
| |
| //@since 1.3 |
| protected EventBus findEventBus(Map<String,?> objects) { |
| |
| <span class="pc bpc" id="L182" title="1 of 2 branches missed."> if (CollectionUtils.isEmpty(objects)) {</span> |
| <span class="nc" id="L183"> return null;</span> |
| } |
| |
| //prefer a named object first: |
| <span class="fc" id="L187"> Object value = objects.get(EVENT_BUS_NAME);</span> |
| <span class="pc bpc" id="L188" title="2 of 4 branches missed."> if (value != null && value instanceof EventBus) {</span> |
| <span class="fc" id="L189"> 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="L193" title="All 2 branches missed."> for( Object v : objects.values()) {</span> |
| <span class="nc bnc" id="L194" title="All 2 branches missed."> if (v instanceof EventBus) {</span> |
| <span class="nc" id="L195"> return (EventBus)v;</span> |
| } |
| <span class="nc" id="L197"> }</span> |
| |
| <span class="nc" id="L199"> return null;</span> |
| } |
| |
| private boolean applyEventBusIfNecessary(Object value) { |
| <span class="fc bfc" id="L203" title="All 2 branches covered."> if (value instanceof EventBusAware) {</span> |
| <span class="fc" id="L204"> ((EventBusAware)value).setEventBus(this.eventBus);</span> |
| <span class="fc" id="L205"> return true;</span> |
| } |
| <span class="fc" id="L207"> return false;</span> |
| } |
| |
| public Object getBean(String id) { |
| <span class="fc" id="L211"> return objects.get(id);</span> |
| } |
| |
| @SuppressWarnings({"unchecked"}) |
| public <T> T getBean(String id, Class<T> requiredType) { |
| <span class="pc bpc" id="L216" title="1 of 2 branches missed."> if (requiredType == null) {</span> |
| <span class="nc" id="L217"> throw new NullPointerException("requiredType argument cannot be null.");</span> |
| } |
| <span class="fc" id="L219"> Object bean = getBean(id);</span> |
| <span class="pc bpc" id="L220" title="1 of 2 branches missed."> if (bean == null) {</span> |
| <span class="nc" id="L221"> return null;</span> |
| } |
| <span class="fc" id="L223"> Assert.state(requiredType.isAssignableFrom(bean.getClass()),</span> |
| <span class="fc" id="L224"> "Bean with id [" + id + "] is not of the required type [" + requiredType.getName() + "].");</span> |
| <span class="fc" id="L225"> return (T) bean;</span> |
| } |
| |
| private String parseBeanId(String lhs) { |
| <span class="fc" id="L229"> Assert.notNull(lhs);</span> |
| <span class="fc bfc" id="L230" title="All 2 branches covered."> if (lhs.indexOf('.') < 0) {</span> |
| <span class="fc" id="L231"> return lhs;</span> |
| } |
| <span class="fc" id="L233"> String classSuffix = ".class";</span> |
| <span class="fc" id="L234"> int index = lhs.indexOf(classSuffix);</span> |
| <span class="pc bpc" id="L235" title="1 of 2 branches missed."> if (index >= 0) {</span> |
| <span class="nc" id="L236"> return lhs.substring(0, index);</span> |
| } |
| <span class="fc" id="L238"> return null;</span> |
| } |
| |
| @SuppressWarnings({"unchecked"}) |
| public Map<String, ?> buildObjects(Map<String, String> kvPairs) { |
| |
| <span class="pc bpc" id="L244" title="1 of 4 branches missed."> if (kvPairs != null && !kvPairs.isEmpty()) {</span> |
| |
| <span class="fc" id="L246"> BeanConfigurationProcessor processor = new BeanConfigurationProcessor();</span> |
| |
| <span class="fc bfc" id="L248" title="All 2 branches covered."> for (Map.Entry<String, String> entry : kvPairs.entrySet()) {</span> |
| <span class="fc" id="L249"> String lhs = entry.getKey();</span> |
| <span class="fc" id="L250"> String rhs = entry.getValue();</span> |
| |
| <span class="fc" id="L252"> String beanId = parseBeanId(lhs);</span> |
| <span class="fc bfc" id="L253" 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="L254"> processor.add(new InstantiationStatement(beanId, rhs));</span> |
| } else { //the line must be a property configuration |
| <span class="fc" id="L256"> processor.add(new AssignmentStatement(lhs, rhs));</span> |
| } |
| <span class="fc" id="L258"> }</span> |
| |
| <span class="fc" id="L260"> processor.execute();</span> |
| } |
| |
| //SHIRO-413: init method must be called for constructed objects that are Initializable |
| <span class="fc" id="L264"> LifecycleUtils.init(objects.values());</span> |
| |
| <span class="fc" id="L266"> return objects;</span> |
| } |
| |
| public void destroy() { |
| <span class="fc" id="L270"> final Map<String, Object> immutableObjects = Collections.unmodifiableMap(objects);</span> |
| |
| //destroy objects in the opposite order they were initialized: |
| <span class="fc" id="L273"> List<Map.Entry<String,?>> entries = new ArrayList<Map.Entry<String,?>>(objects.entrySet());</span> |
| <span class="fc" id="L274"> Collections.reverse(entries);</span> |
| |
| <span class="fc bfc" id="L276" title="All 2 branches covered."> for(Map.Entry<String, ?> entry: entries) {</span> |
| <span class="fc" id="L277"> String id = entry.getKey();</span> |
| <span class="fc" id="L278"> 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="L281" title="All 2 branches covered."> if (bean != this.eventBus) { //memory equality check (not .equals) on purpose</span> |
| <span class="fc" id="L282"> LifecycleUtils.destroy(bean);</span> |
| <span class="fc" id="L283"> BeanEvent event = new DestroyedBeanEvent(id, bean, immutableObjects);</span> |
| <span class="fc" id="L284"> eventBus.publish(event);</span> |
| <span class="fc" id="L285"> this.eventBus.unregister(bean); //bean is now destroyed - it should not receive any other events</span> |
| } |
| <span class="fc" id="L287"> }</span> |
| //only now destroy the event bus: |
| <span class="fc" id="L289"> LifecycleUtils.destroy(this.eventBus);</span> |
| <span class="fc" id="L290"> }</span> |
| |
| protected void createNewInstance(Map<String, Object> objects, String name, String value) { |
| |
| <span class="fc" id="L294"> Object currentInstance = objects.get(name);</span> |
| <span class="pc bpc" id="L295" title="1 of 2 branches missed."> if (currentInstance != null) {</span> |
| <span class="nc" id="L296"> log.info("An instance with name '{}' already exists. " +</span> |
| "Redefining this object as a new instance of type {}", name, value); |
| } |
| |
| Object instance;//name with no property, assume right hand side of equals sign is the class name: |
| try { |
| <span class="fc" id="L302"> instance = ClassUtils.newInstance(value);</span> |
| <span class="fc bfc" id="L303" title="All 2 branches covered."> if (instance instanceof Nameable) {</span> |
| <span class="fc" id="L304"> ((Nameable) instance).setName(name);</span> |
| } |
| <span class="nc" id="L306"> } catch (Exception e) {</span> |
| <span class="nc" id="L307"> String msg = "Unable to instantiate class [" + value + "] for object named '" + name + "'. " +</span> |
| "Please ensure you've specified the fully qualified class name correctly."; |
| <span class="nc" id="L309"> throw new ConfigurationException(msg, e);</span> |
| <span class="fc" id="L310"> }</span> |
| <span class="fc" id="L311"> objects.put(name, instance);</span> |
| <span class="fc" id="L312"> }</span> |
| |
| protected void applyProperty(String key, String value, Map objects) { |
| |
| <span class="fc" id="L316"> int index = key.indexOf('.');</span> |
| |
| <span class="pc bpc" id="L318" title="1 of 2 branches missed."> if (index >= 0) {</span> |
| <span class="fc" id="L319"> String name = key.substring(0, index);</span> |
| <span class="fc" id="L320"> String property = key.substring(index + 1, key.length());</span> |
| |
| <span class="pc bpc" id="L322" title="1 of 2 branches missed."> if (GLOBAL_PROPERTY_PREFIX.equalsIgnoreCase(name)) {</span> |
| <span class="nc" id="L323"> applyGlobalProperty(objects, property, value);</span> |
| } else { |
| <span class="fc" id="L325"> applySingleProperty(objects, name, property, value);</span> |
| } |
| |
| <span class="fc" id="L328"> } else {</span> |
| <span class="nc" id="L329"> throw new IllegalArgumentException("All property keys must contain a '.' character. " +</span> |
| "(e.g. myBean.property = value) These should already be separated out by buildObjects()."); |
| } |
| <span class="fc" id="L332"> }</span> |
| |
| protected void applyGlobalProperty(Map objects, String property, String value) { |
| <span class="nc bnc" id="L335" title="All 2 branches missed."> for (Object instance : objects.values()) {</span> |
| try { |
| <span class="nc" id="L337"> PropertyDescriptor pd = PropertyUtils.getPropertyDescriptor(instance, property);</span> |
| <span class="nc bnc" id="L338" title="All 2 branches missed."> if (pd != null) {</span> |
| <span class="nc" id="L339"> applyProperty(instance, property, value);</span> |
| } |
| <span class="nc" id="L341"> } catch (Exception e) {</span> |
| <span class="nc" id="L342"> String msg = "Error retrieving property descriptor for instance " +</span> |
| <span class="nc" id="L343"> "of type [" + instance.getClass().getName() + "] " +</span> |
| "while setting property [" + property + "]"; |
| <span class="nc" id="L345"> throw new ConfigurationException(msg, e);</span> |
| <span class="nc" id="L346"> }</span> |
| <span class="nc" id="L347"> }</span> |
| <span class="nc" id="L348"> }</span> |
| |
| protected void applySingleProperty(Map objects, String name, String property, String value) { |
| <span class="fc" id="L351"> Object instance = objects.get(name);</span> |
| <span class="pc bpc" id="L352" title="1 of 2 branches missed."> if (property.equals("class")) {</span> |
| <span class="nc" id="L353"> throw new IllegalArgumentException("Property keys should not contain 'class' properties since these " +</span> |
| "should already be separated out by buildObjects()."); |
| |
| <span class="pc bpc" id="L356" title="1 of 2 branches missed."> } else if (instance == null) {</span> |
| <span class="nc" id="L357"> String msg = "Configuration error. Specified object [" + name + "] with property [" +</span> |
| property + "] without first defining that object's class. Please first " + |
| "specify the class property first, e.g. myObject = fully_qualified_class_name " + |
| "and then define additional properties."; |
| <span class="nc" id="L361"> throw new IllegalArgumentException(msg);</span> |
| |
| } else { |
| <span class="fc" id="L364"> applyProperty(instance, property, value);</span> |
| } |
| <span class="fc" id="L366"> }</span> |
| |
| protected boolean isReference(String value) { |
| <span class="pc bpc" id="L369" title="1 of 4 branches missed."> return value != null && value.startsWith(OBJECT_REFERENCE_BEGIN_TOKEN);</span> |
| } |
| |
| protected String getId(String referenceToken) { |
| <span class="fc" id="L373"> return referenceToken.substring(OBJECT_REFERENCE_BEGIN_TOKEN.length());</span> |
| } |
| |
| protected Object getReferencedObject(String id) { |
| <span class="pc bpc" id="L377" title="2 of 4 branches missed."> Object o = objects != null && !objects.isEmpty() ? objects.get(id) : null;</span> |
| <span class="fc bfc" id="L378" title="All 2 branches covered."> if (o == null) {</span> |
| <span class="fc" id="L379"> String msg = "The object with id [" + id + "] has not yet been defined and therefore cannot be " +</span> |
| "referenced. Please ensure objects are defined in the order in which they should be " + |
| "created and made available for future reference."; |
| <span class="fc" id="L382"> throw new UnresolveableReferenceException(msg);</span> |
| } |
| <span class="fc" id="L384"> return o;</span> |
| } |
| |
| protected String unescapeIfNecessary(String value) { |
| <span class="pc bpc" id="L388" title="1 of 4 branches missed."> if (value != null && value.startsWith(ESCAPED_OBJECT_REFERENCE_BEGIN_TOKEN)) {</span> |
| <span class="fc" id="L389"> return value.substring(ESCAPED_OBJECT_REFERENCE_BEGIN_TOKEN.length() - 1);</span> |
| } |
| <span class="fc" id="L391"> return value;</span> |
| } |
| |
| protected Object resolveReference(String reference) { |
| <span class="fc" id="L395"> String id = getId(reference);</span> |
| <span class="fc" id="L396"> log.debug("Encountered object reference '{}'. Looking up object with id '{}'", reference, id);</span> |
| <span class="fc" id="L397"> final Object referencedObject = getReferencedObject(id);</span> |
| <span class="fc bfc" id="L398" title="All 2 branches covered."> if (referencedObject instanceof Factory) {</span> |
| <span class="fc" id="L399"> return ((Factory) referencedObject).getInstance();</span> |
| } |
| <span class="fc" id="L401"> return referencedObject;</span> |
| } |
| |
| protected boolean isTypedProperty(Object object, String propertyName, Class clazz) { |
| <span class="pc bpc" id="L405" title="1 of 2 branches missed."> if (clazz == null) {</span> |
| <span class="nc" id="L406"> throw new NullPointerException("type (class) argument cannot be null.");</span> |
| } |
| try { |
| <span class="fc" id="L409"> PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(object, propertyName);</span> |
| <span class="pc bpc" id="L410" title="1 of 2 branches missed."> if (descriptor == null) {</span> |
| <span class="nc" id="L411"> String msg = "Property '" + propertyName + "' does not exist for object of " +</span> |
| <span class="nc" id="L412"> "type " + object.getClass().getName() + ".";</span> |
| <span class="nc" id="L413"> throw new ConfigurationException(msg);</span> |
| } |
| <span class="fc" id="L415"> Class propertyClazz = descriptor.getPropertyType();</span> |
| <span class="fc" id="L416"> return clazz.isAssignableFrom(propertyClazz);</span> |
| <span class="nc" id="L417"> } catch (ConfigurationException ce) {</span> |
| //let it propagate: |
| <span class="nc" id="L419"> throw ce;</span> |
| <span class="nc" id="L420"> } catch (Exception e) {</span> |
| <span class="nc" id="L421"> String msg = "Unable to determine if property [" + propertyName + "] represents a " + clazz.getName();</span> |
| <span class="nc" id="L422"> throw new ConfigurationException(msg, e);</span> |
| } |
| } |
| |
| protected Set<?> toSet(String sValue) { |
| <span class="fc" id="L427"> String[] tokens = StringUtils.split(sValue);</span> |
| <span class="pc bpc" id="L428" title="2 of 4 branches missed."> if (tokens == null || tokens.length <= 0) {</span> |
| <span class="nc" id="L429"> 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="L433" title="3 of 4 branches missed."> if (tokens.length == 1 && isReference(tokens[0])) {</span> |
| <span class="nc" id="L434"> Object reference = resolveReference(tokens[0]);</span> |
| <span class="nc bnc" id="L435" title="All 2 branches missed."> if (reference instanceof Set) {</span> |
| <span class="nc" id="L436"> return (Set)reference;</span> |
| } |
| } |
| |
| <span class="fc" id="L440"> Set<String> setTokens = new LinkedHashSet<String>(Arrays.asList(tokens));</span> |
| |
| //now convert into correct values and/or references: |
| <span class="fc" id="L443"> Set<Object> values = new LinkedHashSet<Object>(setTokens.size());</span> |
| <span class="fc bfc" id="L444" title="All 2 branches covered."> for (String token : setTokens) {</span> |
| <span class="fc" id="L445"> Object value = resolveValue(token);</span> |
| <span class="fc" id="L446"> values.add(value);</span> |
| <span class="fc" id="L447"> }</span> |
| <span class="fc" id="L448"> return values;</span> |
| } |
| |
| protected Map<?, ?> toMap(String sValue) { |
| <span class="fc" id="L452"> 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="L454" title="2 of 4 branches missed."> if (tokens == null || tokens.length <= 0) {</span> |
| <span class="nc" id="L455"> 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="L459" title="3 of 4 branches missed."> if (tokens.length == 1 && isReference(tokens[0])) {</span> |
| <span class="nc" id="L460"> Object reference = resolveReference(tokens[0]);</span> |
| <span class="nc bnc" id="L461" title="All 2 branches missed."> if (reference instanceof Map) {</span> |
| <span class="nc" id="L462"> return (Map)reference;</span> |
| } |
| } |
| |
| <span class="fc" id="L466"> Map<String, String> mapTokens = new LinkedHashMap<String, String>(tokens.length);</span> |
| <span class="fc bfc" id="L467" title="All 2 branches covered."> for (String token : tokens) {</span> |
| <span class="fc" id="L468"> String[] kvPair = StringUtils.split(token, MAP_KEY_VALUE_DELIMITER);</span> |
| <span class="pc bpc" id="L469" title="2 of 4 branches missed."> if (kvPair == null || kvPair.length != 2) {</span> |
| <span class="nc" id="L470"> String msg = "Map property value [" + sValue + "] contained key-value pair token [" +</span> |
| token + "] that does not properly split to a single key and pair. This must be the " + |
| "case for all map entries."; |
| <span class="nc" id="L473"> throw new ConfigurationException(msg);</span> |
| } |
| <span class="fc" id="L475"> mapTokens.put(kvPair[0], kvPair[1]);</span> |
| } |
| |
| //now convert into correct values and/or references: |
| <span class="fc" id="L479"> Map<Object, Object> map = new LinkedHashMap<Object, Object>(mapTokens.size());</span> |
| <span class="fc bfc" id="L480" title="All 2 branches covered."> for (Map.Entry<String, String> entry : mapTokens.entrySet()) {</span> |
| <span class="fc" id="L481"> Object key = resolveValue(entry.getKey());</span> |
| <span class="fc" id="L482"> Object value = resolveValue(entry.getValue());</span> |
| <span class="fc" id="L483"> map.put(key, value);</span> |
| <span class="fc" id="L484"> }</span> |
| <span class="fc" id="L485"> return map;</span> |
| } |
| |
| // @since 1.2.2 |
| // TODO: make protected in 1.3+ |
| private Collection<?> toCollection(String sValue) { |
| |
| <span class="fc" id="L492"> String[] tokens = StringUtils.split(sValue);</span> |
| <span class="pc bpc" id="L493" title="2 of 4 branches missed."> if (tokens == null || tokens.length <= 0) {</span> |
| <span class="nc" id="L494"> 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="L498" title="1 of 4 branches missed."> if (tokens.length == 1 && isReference(tokens[0])) {</span> |
| <span class="fc" id="L499"> Object reference = resolveReference(tokens[0]);</span> |
| <span class="pc bpc" id="L500" title="1 of 2 branches missed."> if (reference instanceof Collection) {</span> |
| <span class="nc" id="L501"> return (Collection)reference;</span> |
| } |
| } |
| |
| //now convert into correct values and/or references: |
| <span class="fc" id="L506"> List<Object> values = new ArrayList<Object>(tokens.length);</span> |
| <span class="fc bfc" id="L507" title="All 2 branches covered."> for (String token : tokens) {</span> |
| <span class="fc" id="L508"> Object value = resolveValue(token);</span> |
| <span class="fc" id="L509"> values.add(value);</span> |
| } |
| <span class="fc" id="L511"> return values;</span> |
| } |
| |
| protected List<?> toList(String sValue) { |
| <span class="fc" id="L515"> String[] tokens = StringUtils.split(sValue);</span> |
| <span class="pc bpc" id="L516" title="2 of 4 branches missed."> if (tokens == null || tokens.length <= 0) {</span> |
| <span class="nc" id="L517"> 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="L521" title="3 of 4 branches missed."> if (tokens.length == 1 && isReference(tokens[0])) {</span> |
| <span class="nc" id="L522"> Object reference = resolveReference(tokens[0]);</span> |
| <span class="nc bnc" id="L523" title="All 2 branches missed."> if (reference instanceof List) {</span> |
| <span class="nc" id="L524"> return (List)reference;</span> |
| } |
| } |
| |
| //now convert into correct values and/or references: |
| <span class="fc" id="L529"> List<Object> values = new ArrayList<Object>(tokens.length);</span> |
| <span class="fc bfc" id="L530" title="All 2 branches covered."> for (String token : tokens) {</span> |
| <span class="fc" id="L531"> Object value = resolveValue(token);</span> |
| <span class="fc" id="L532"> values.add(value);</span> |
| } |
| <span class="fc" id="L534"> return values;</span> |
| } |
| |
| protected byte[] toBytes(String sValue) { |
| <span class="pc bpc" id="L538" title="1 of 2 branches missed."> if (sValue == null) {</span> |
| <span class="nc" id="L539"> return null;</span> |
| } |
| byte[] bytes; |
| <span class="fc bfc" id="L542" title="All 2 branches covered."> if (sValue.startsWith(HEX_BEGIN_TOKEN)) {</span> |
| <span class="fc" id="L543"> String hex = sValue.substring(HEX_BEGIN_TOKEN.length());</span> |
| <span class="fc" id="L544"> bytes = Hex.decode(hex);</span> |
| <span class="fc" id="L545"> } else {</span> |
| //assume base64 encoded: |
| <span class="fc" id="L547"> bytes = Base64.decode(sValue);</span> |
| } |
| <span class="fc" id="L549"> return bytes;</span> |
| } |
| |
| protected Object resolveValue(String stringValue) { |
| Object value; |
| <span class="fc bfc" id="L554" title="All 2 branches covered."> if (isReference(stringValue)) {</span> |
| <span class="fc" id="L555"> value = resolveReference(stringValue);</span> |
| } else { |
| <span class="fc" id="L557"> value = unescapeIfNecessary(stringValue);</span> |
| } |
| <span class="fc" id="L559"> return value;</span> |
| } |
| |
| protected String checkForNullOrEmptyLiteral(String stringValue) { |
| <span class="pc bpc" id="L563" title="1 of 2 branches missed."> if (stringValue == null) {</span> |
| <span class="nc" id="L564"> return null;</span> |
| } |
| //check if the value is the actual literal string 'null' (expected to be wrapped in quotes): |
| <span class="fc bfc" id="L567" title="All 2 branches covered."> if (stringValue.equals("\"null\"")) {</span> |
| <span class="fc" id="L568"> return NULL_VALUE_TOKEN;</span> |
| } |
| //or the actual literal string of two quotes '""' (expected to be wrapped in quotes): |
| <span class="fc bfc" id="L571" title="All 2 branches covered."> else if (stringValue.equals("\"\"\"\"")) {</span> |
| <span class="fc" id="L572"> return EMPTY_STRING_VALUE_TOKEN;</span> |
| } else { |
| <span class="fc" id="L574"> return stringValue;</span> |
| } |
| } |
| |
| protected void applyProperty(Object object, String propertyPath, Object value) { |
| |
| <span class="fc" id="L580"> int mapBegin = propertyPath.indexOf(MAP_PROPERTY_BEGIN_TOKEN);</span> |
| <span class="fc" id="L581"> int mapEnd = -1;</span> |
| <span class="fc" id="L582"> String mapPropertyPath = null;</span> |
| <span class="fc" id="L583"> String keyString = null;</span> |
| |
| <span class="fc" id="L585"> String remaining = null;</span> |
| |
| <span class="fc bfc" id="L587" title="All 2 branches covered."> if (mapBegin >= 0) {</span> |
| //a map is being referenced in the overall property path. Find just the map's path: |
| <span class="fc" id="L589"> mapPropertyPath = propertyPath.substring(0, mapBegin);</span> |
| //find the end of the map reference: |
| <span class="fc" id="L591"> 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="L593"> 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="L596" title="All 2 branches covered."> if (propertyPath.length() > (mapEnd+1)) {</span> |
| <span class="fc" id="L597"> remaining = propertyPath.substring(mapEnd+1);</span> |
| <span class="pc bpc" id="L598" title="1 of 2 branches missed."> if (remaining.startsWith(".")) {</span> |
| <span class="fc" id="L599"> remaining = StringUtils.clean(remaining.substring(1));</span> |
| } |
| } |
| } |
| |
| <span class="fc bfc" id="L604" 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="L606" title="All 2 branches covered."> if (keyString == null) {</span> |
| //not a map or array value assignment - assign the property directly: |
| <span class="fc" id="L608"> 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="L611" title="All 2 branches covered."> if (isTypedProperty(object, mapPropertyPath, Map.class)) {</span> |
| <span class="fc" id="L612"> Map map = (Map)getProperty(object, mapPropertyPath);</span> |
| <span class="fc" id="L613"> Object mapKey = resolveValue(keyString);</span> |
| //noinspection unchecked |
| <span class="fc" id="L615"> map.put(mapKey, value);</span> |
| <span class="fc" id="L616"> } else {</span> |
| //must be an array property. Convert the key string to an index: |
| <span class="fc" id="L618"> int index = Integer.valueOf(keyString);</span> |
| <span class="fc" id="L619"> setIndexedProperty(object, mapPropertyPath, index, value);</span> |
| <span class="fc" id="L620"> }</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="L625"> Object referencedValue = null;</span> |
| <span class="fc bfc" id="L626" title="All 2 branches covered."> if (isTypedProperty(object, mapPropertyPath, Map.class)) {</span> |
| <span class="fc" id="L627"> Map map = (Map)getProperty(object, mapPropertyPath);</span> |
| <span class="fc" id="L628"> Object mapKey = resolveValue(keyString);</span> |
| <span class="fc" id="L629"> referencedValue = map.get(mapKey);</span> |
| <span class="fc" id="L630"> } else {</span> |
| //must be an array property: |
| <span class="fc" id="L632"> int index = Integer.valueOf(keyString);</span> |
| <span class="fc" id="L633"> referencedValue = getIndexedProperty(object, mapPropertyPath, index);</span> |
| } |
| |
| <span class="pc bpc" id="L636" title="1 of 2 branches missed."> if (referencedValue == null) {</span> |
| <span class="nc" id="L637"> throw new ConfigurationException("Referenced map/array value '" + mapPropertyPath + "[" +</span> |
| keyString + "]' does not exist."); |
| } |
| |
| <span class="fc" id="L641"> applyProperty(referencedValue, remaining, value);</span> |
| } |
| <span class="fc" id="L643"> }</span> |
| |
| private void setProperty(Object object, String propertyPath, Object value) { |
| try { |
| <span class="pc bpc" id="L647" title="1 of 2 branches missed."> if (log.isTraceEnabled()) {</span> |
| <span class="fc" id="L648"> log.trace("Applying property [{}] value [{}] on object of type [{}]",</span> |
| <span class="fc" id="L649"> new Object[]{propertyPath, value, object.getClass().getName()});</span> |
| } |
| <span class="fc" id="L651"> BeanUtils.setProperty(object, propertyPath, value);</span> |
| <span class="fc" id="L652"> } catch (Exception e) {</span> |
| <span class="pc bpc" id="L653" title="1 of 2 branches missed."> String msg = "Unable to set property '" + propertyPath + "' with value [" + value + "] on object " +</span> |
| <span class="pc" id="L654"> "of type " + (object != null ? object.getClass().getName() : null) + ". If " +</span> |
| "'" + value + "' is a reference to another (previously defined) object, prefix it with " + |
| "'" + OBJECT_REFERENCE_BEGIN_TOKEN + "' to indicate that the referenced " + |
| "object should be used as the actual value. " + |
| "For example, " + OBJECT_REFERENCE_BEGIN_TOKEN + value; |
| <span class="fc" id="L659"> throw new ConfigurationException(msg, e);</span> |
| <span class="fc" id="L660"> }</span> |
| <span class="fc" id="L661"> }</span> |
| |
| private Object getProperty(Object object, String propertyPath) { |
| try { |
| <span class="fc" id="L665"> return PropertyUtils.getProperty(object, propertyPath);</span> |
| <span class="nc" id="L666"> } catch (Exception e) {</span> |
| <span class="nc" id="L667"> throw new ConfigurationException("Unable to access property '" + propertyPath + "'", e);</span> |
| } |
| } |
| |
| private void setIndexedProperty(Object object, String propertyPath, int index, Object value) { |
| try { |
| <span class="fc" id="L673"> PropertyUtils.setIndexedProperty(object, propertyPath, index, value);</span> |
| <span class="nc" id="L674"> } catch (Exception e) {</span> |
| <span class="nc" id="L675"> throw new ConfigurationException("Unable to set array property '" + propertyPath + "'", e);</span> |
| <span class="fc" id="L676"> }</span> |
| <span class="fc" id="L677"> }</span> |
| |
| private Object getIndexedProperty(Object object, String propertyPath, int index) { |
| try { |
| <span class="fc" id="L681"> return PropertyUtils.getIndexedProperty(object, propertyPath, index);</span> |
| <span class="nc" id="L682"> } catch (Exception e) {</span> |
| <span class="nc" id="L683"> throw new ConfigurationException("Unable to acquire array property '" + propertyPath + "'", e);</span> |
| } |
| } |
| |
| protected boolean isIndexedPropertyAssignment(String propertyPath) { |
| <span class="fc" id="L688"> return propertyPath.endsWith("" + MAP_PROPERTY_END_TOKEN);</span> |
| } |
| |
| protected void applyProperty(Object object, String propertyName, String stringValue) { |
| |
| Object value; |
| |
| <span class="fc bfc" id="L695" title="All 2 branches covered."> if (NULL_VALUE_TOKEN.equals(stringValue)) {</span> |
| <span class="fc" id="L696"> value = null;</span> |
| <span class="fc bfc" id="L697" title="All 2 branches covered."> } else if (EMPTY_STRING_VALUE_TOKEN.equals(stringValue)) {</span> |
| <span class="fc" id="L698"> value = StringUtils.EMPTY_STRING;</span> |
| <span class="fc bfc" id="L699" title="All 2 branches covered."> } else if (isIndexedPropertyAssignment(propertyName)) {</span> |
| <span class="fc" id="L700"> String checked = checkForNullOrEmptyLiteral(stringValue);</span> |
| <span class="fc" id="L701"> value = resolveValue(checked);</span> |
| <span class="fc bfc" id="L702" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, Set.class)) {</span> |
| <span class="fc" id="L703"> value = toSet(stringValue);</span> |
| <span class="fc bfc" id="L704" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, Map.class)) {</span> |
| <span class="fc" id="L705"> value = toMap(stringValue);</span> |
| <span class="fc bfc" id="L706" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, List.class)) {</span> |
| <span class="fc" id="L707"> value = toList(stringValue);</span> |
| <span class="fc bfc" id="L708" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, Collection.class)) {</span> |
| <span class="fc" id="L709"> value = toCollection(stringValue);</span> |
| <span class="fc bfc" id="L710" title="All 2 branches covered."> } else if (isTypedProperty(object, propertyName, byte[].class)) {</span> |
| <span class="fc" id="L711"> value = toBytes(stringValue);</span> |
| <span class="pc bpc" id="L712" title="1 of 2 branches missed."> } else if (isTypedProperty(object, propertyName, ByteSource.class)) {</span> |
| <span class="nc" id="L713"> byte[] bytes = toBytes(stringValue);</span> |
| <span class="nc" id="L714"> value = ByteSource.Util.bytes(bytes);</span> |
| <span class="nc" id="L715"> } else {</span> |
| <span class="fc" id="L716"> String checked = checkForNullOrEmptyLiteral(stringValue);</span> |
| <span class="fc" id="L717"> value = resolveValue(checked);</span> |
| } |
| |
| <span class="fc" id="L720"> applyProperty(object, propertyName, value);</span> |
| <span class="fc" id="L721"> }</span> |
| |
| <span class="fc" id="L723"> private class BeanConfigurationProcessor {</span> |
| |
| <span class="fc" id="L725"> private final List<Statement> statements = new ArrayList<Statement>();</span> |
| <span class="fc" id="L726"> private final List<BeanConfiguration> beanConfigurations = new ArrayList<BeanConfiguration>();</span> |
| |
| public void add(Statement statement) { |
| |
| <span class="fc" id="L730"> statements.add(statement); //we execute bean configuration statements in the order they are declared.</span> |
| |
| <span class="fc bfc" id="L732" title="All 2 branches covered."> if (statement instanceof InstantiationStatement) {</span> |
| <span class="fc" id="L733"> InstantiationStatement is = (InstantiationStatement)statement;</span> |
| <span class="fc" id="L734"> beanConfigurations.add(new BeanConfiguration(is));</span> |
| <span class="fc" id="L735"> } else {</span> |
| <span class="fc" id="L736"> 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="L739"> boolean addedToConfig = false;</span> |
| <span class="fc" id="L740"> String beanName = as.getRootBeanName();</span> |
| <span class="fc bfc" id="L741" title="All 2 branches covered."> for( int i = beanConfigurations.size()-1; i >= 0; i--) {</span> |
| <span class="fc" id="L742"> BeanConfiguration mostRecent = beanConfigurations.get(i);</span> |
| <span class="fc" id="L743"> String mostRecentBeanName = mostRecent.getBeanName();</span> |
| <span class="fc bfc" id="L744" title="All 2 branches covered."> if (beanName.equals(mostRecentBeanName)) {</span> |
| <span class="fc" id="L745"> mostRecent.add(as);</span> |
| <span class="fc" id="L746"> addedToConfig = true;</span> |
| <span class="fc" id="L747"> break;</span> |
| } |
| } |
| |
| <span class="fc bfc" id="L751" 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="L756"> beanConfigurations.add(new BeanConfiguration(as));</span> |
| } |
| } |
| <span class="fc" id="L759"> }</span> |
| |
| public void execute() { |
| |
| <span class="fc bfc" id="L763" title="All 2 branches covered."> for( Statement statement : statements) {</span> |
| |
| <span class="fc" id="L765"> statement.execute();</span> |
| |
| <span class="fc" id="L767"> BeanConfiguration bd = statement.getBeanConfiguration();</span> |
| |
| <span class="fc bfc" id="L769" 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="L772" title="1 of 2 branches missed."> if (bd.getBeanName().equals(EVENT_BUS_NAME)) {</span> |
| <span class="nc" id="L773"> EventBus eventBus = (EventBus)bd.getBean();</span> |
| <span class="nc" id="L774"> enableEvents(eventBus);</span> |
| } |
| |
| //ignore global 'shiro.' shortcut mechanism: |
| <span class="pc bpc" id="L778" title="1 of 2 branches missed."> if (!bd.isGlobalConfig()) {</span> |
| <span class="fc" id="L779"> BeanEvent event = new ConfiguredBeanEvent(bd.getBeanName(), bd.getBean(),</span> |
| <span class="fc" id="L780"> Collections.unmodifiableMap(objects));</span> |
| <span class="fc" id="L781"> eventBus.publish(event);</span> |
| } |
| |
| //initialize the bean if necessary: |
| <span class="fc" id="L785"> LifecycleUtils.init(bd.getBean());</span> |
| |
| //ignore global 'shiro.' shortcut mechanism: |
| <span class="pc bpc" id="L788" title="1 of 2 branches missed."> if (!bd.isGlobalConfig()) {</span> |
| <span class="fc" id="L789"> BeanEvent event = new InitializedBeanEvent(bd.getBeanName(), bd.getBean(),</span> |
| <span class="fc" id="L790"> Collections.unmodifiableMap(objects));</span> |
| <span class="fc" id="L791"> eventBus.publish(event);</span> |
| } |
| } |
| <span class="fc" id="L794"> }</span> |
| <span class="fc" id="L795"> }</span> |
| } |
| |
| private class BeanConfiguration { |
| |
| private final InstantiationStatement instantiationStatement; |
| <span class="fc" id="L801"> private final List<AssignmentStatement> assignments = new ArrayList<AssignmentStatement>();</span> |
| private final String beanName; |
| private Object bean; |
| |
| <span class="fc" id="L805"> private BeanConfiguration(InstantiationStatement statement) {</span> |
| <span class="fc" id="L806"> statement.setBeanConfiguration(this);</span> |
| <span class="fc" id="L807"> this.instantiationStatement = statement;</span> |
| <span class="fc" id="L808"> this.beanName = statement.lhs;</span> |
| <span class="fc" id="L809"> }</span> |
| |
| <span class="fc" id="L811"> private BeanConfiguration(AssignmentStatement as) {</span> |
| <span class="fc" id="L812"> this.instantiationStatement = null;</span> |
| <span class="fc" id="L813"> this.beanName = as.getRootBeanName();</span> |
| <span class="fc" id="L814"> add(as);</span> |
| <span class="fc" id="L815"> }</span> |
| |
| public String getBeanName() { |
| <span class="fc" id="L818"> return this.beanName;</span> |
| } |
| |
| public boolean isGlobalConfig() { //BeanConfiguration instance representing the global 'shiro.' properties |
| // (we should remove this concept). |
| <span class="fc" id="L823"> return GLOBAL_PROPERTY_PREFIX.equals(getBeanName());</span> |
| } |
| |
| public void add(AssignmentStatement as) { |
| <span class="fc" id="L827"> as.setBeanConfiguration(this);</span> |
| <span class="fc" id="L828"> assignments.add(as);</span> |
| <span class="fc" id="L829"> }</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="L838"> this.bean = bean;</span> |
| <span class="fc" id="L839"> }</span> |
| |
| public Object getBean() { |
| <span class="fc" id="L842"> 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="L850" title="1 of 4 branches missed."> if (instantiationStatement != null && !instantiationStatement.isExecuted()) {</span> |
| <span class="nc" id="L851"> return false;</span> |
| } |
| <span class="fc bfc" id="L853" title="All 2 branches covered."> for (AssignmentStatement as : assignments) {</span> |
| <span class="fc bfc" id="L854" title="All 2 branches covered."> if (!as.isExecuted()) {</span> |
| <span class="fc" id="L855"> return false;</span> |
| } |
| <span class="fc" id="L857"> }</span> |
| <span class="fc" id="L858"> 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="L871"> private Statement(String lhs, String rhs) {</span> |
| <span class="fc" id="L872"> this.lhs = lhs;</span> |
| <span class="fc" id="L873"> this.rhs = rhs;</span> |
| <span class="fc" id="L874"> this.executed = false;</span> |
| <span class="fc" id="L875"> }</span> |
| |
| public void setBeanConfiguration(BeanConfiguration bd) { |
| <span class="fc" id="L878"> this.beanConfiguration = bd;</span> |
| <span class="fc" id="L879"> }</span> |
| |
| public BeanConfiguration getBeanConfiguration() { |
| <span class="fc" id="L882"> return this.beanConfiguration;</span> |
| } |
| |
| public Object execute() { |
| <span class="pc bpc" id="L886" title="1 of 2 branches missed."> if (!isExecuted()) {</span> |
| <span class="fc" id="L887"> this.result = doExecute();</span> |
| <span class="fc" id="L888"> this.executed = true;</span> |
| } |
| <span class="pc bpc" id="L890" title="1 of 2 branches missed."> if (!getBeanConfiguration().isGlobalConfig()) {</span> |
| <span class="fc" id="L891"> Assert.notNull(this.bean, "Implementation must set the root bean for which it executed.");</span> |
| } |
| <span class="fc" id="L893"> return this.result;</span> |
| } |
| |
| public Object getBean() { |
| <span class="nc" id="L897"> return this.bean;</span> |
| } |
| |
| protected void setBean(Object bean) { |
| <span class="fc" id="L901"> this.bean = bean;</span> |
| <span class="fc bfc" id="L902" title="All 2 branches covered."> if (this.beanConfiguration.getBean() == null) {</span> |
| <span class="fc" id="L903"> this.beanConfiguration.setBean(bean);</span> |
| } |
| <span class="fc" id="L905"> }</span> |
| |
| public Object getResult() { |
| <span class="nc" id="L908"> return result;</span> |
| } |
| |
| protected abstract Object doExecute(); |
| |
| public boolean isExecuted() { |
| <span class="fc" id="L914"> return executed;</span> |
| } |
| } |
| |
| private class InstantiationStatement extends Statement { |
| |
| <span class="fc" id="L920"> private InstantiationStatement(String lhs, String rhs) {</span> |
| <span class="fc" id="L921"> super(lhs, rhs);</span> |
| <span class="fc" id="L922"> }</span> |
| |
| @Override |
| protected Object doExecute() { |
| <span class="fc" id="L926"> String beanName = this.lhs;</span> |
| <span class="fc" id="L927"> createNewInstance(objects, beanName, this.rhs);</span> |
| <span class="fc" id="L928"> Object instantiated = objects.get(beanName);</span> |
| <span class="fc" id="L929"> 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="L934"> enableEventsIfNecessary(instantiated, beanName);</span> |
| |
| <span class="fc" id="L936"> BeanEvent event = new InstantiatedBeanEvent(beanName, instantiated, Collections.unmodifiableMap(objects));</span> |
| <span class="fc" id="L937"> eventBus.publish(event);</span> |
| |
| <span class="fc" id="L939"> return instantiated;</span> |
| } |
| } |
| |
| private class AssignmentStatement extends Statement { |
| |
| private final String rootBeanName; |
| |
| <span class="fc" id="L947"> private AssignmentStatement(String lhs, String rhs) {</span> |
| <span class="fc" id="L948"> super(lhs, rhs);</span> |
| <span class="fc" id="L949"> int index = lhs.indexOf('.');</span> |
| <span class="fc" id="L950"> this.rootBeanName = lhs.substring(0, index);</span> |
| <span class="fc" id="L951"> }</span> |
| |
| @Override |
| protected Object doExecute() { |
| <span class="fc" id="L955"> applyProperty(lhs, rhs, objects);</span> |
| <span class="fc" id="L956"> Object bean = objects.get(this.rootBeanName);</span> |
| <span class="fc" id="L957"> setBean(bean);</span> |
| <span class="fc" id="L958"> return null;</span> |
| } |
| |
| public String getRootBeanName() { |
| <span class="fc" id="L962"> return this.rootBeanName;</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> |