edu.internet2.middleware.shibboleth.common.config.SpringConfigurationUtils.java Source code

Java tutorial

Introduction

Here is the source code for edu.internet2.middleware.shibboleth.common.config.SpringConfigurationUtils.java

Source

/*
 * Licensed to the University Corporation for Advanced Internet Development, 
 * Inc. (UCAID) under one or more contributor license agreements.  See the 
 * NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The UCAID 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 edu.internet2.middleware.shibboleth.common.config;

import java.util.Date;
import java.util.List;

import javax.xml.datatype.Duration;

import org.opensaml.util.resource.Resource;
import org.opensaml.util.resource.ResourceException;
import org.opensaml.xml.util.DatatypeHelper;
import org.opensaml.xml.util.XMLHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.InputStreamResource;
import org.w3c.dom.Element;

/**
 * Utilities to help configure Spring beans.
 */
public final class SpringConfigurationUtils {

    /** Log4j logger. */
    private static Logger log = LoggerFactory.getLogger(SpringConfigurationUtils.class);

    /** Private Constructor. */
    private SpringConfigurationUtils() {
    }

    /**
     * Loads a set of spring configuration resources into a given application context.
     * 
     * @param beanRegistry registry of spring beans to be populated with information from the given configurations
     * @param configurationResources list of spring configuration resources
     * 
     * @throws ResourceException thrown if there is a problem reading the spring configuration resources into the
     *             registry
     */
    public static void populateRegistry(BeanDefinitionRegistry beanRegistry, List<Resource> configurationResources)
            throws ResourceException {
        XmlBeanDefinitionReader configReader = new XmlBeanDefinitionReader(beanRegistry);
        configReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
        configReader.setDocumentLoader(new SpringDocumentLoader());

        int numOfResources = configurationResources.size();
        Resource configurationResource;
        org.springframework.core.io.Resource[] configSources = new org.springframework.core.io.Resource[numOfResources];
        for (int i = 0; i < numOfResources; i++) {
            configurationResource = configurationResources.get(i);
            if (configurationResource != null && configurationResource.exists()) {
                configSources[i] = new InputStreamResource(configurationResources.get(i).getInputStream(),
                        configurationResource.getLocation());
            } else {
                log.warn("Configuration resource not loaded because it does not exist: {}",
                        configurationResource.getLocation());
            }
        }

        try {
            configReader.loadBeanDefinitions(configSources);
        } catch (BeanDefinitionStoreException e) {
            throw new ResourceException("Unable to load Spring bean registry with configuration resources", e);
        }
    }

    /**
     * Parses a bean definition using an xsi:type aware version of
     * {@link BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element)}.
     * 
     * @param element configuration element
     * @param parserContext current parser context
     * 
     * @return bean definition
     */
    public static BeanDefinition parseInnerCustomElement(Element element, ParserContext parserContext) {
        return createBeanDefinition(element, parserContext);
    }

    /**
     * Parser a list of bean definitions using an xsi:type aware version of
     * {@link BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element)}.
     * 
     * @param elements configuration elements
     * @param parserContext current parser context
     * 
     * @return list of bean definition
     */
    public static ManagedList parseInnerCustomElements(List<Element> elements, ParserContext parserContext) {
        ManagedList beans = new ManagedList();
        if (elements != null) {
            for (Element element : elements) {
                beans.add(parseInnerCustomElement(element, parserContext));
            }
        }

        return beans;
    }

    /**
     * Parses a bean definition using an xsi:type aware version of
     * BeanDefinitionParserDelegate.parseCustomElement(Element). Assumes the element has an attribute 'id' that provides
     * a unique identifier for the bean.
     * 
     * @param element element to parse
     * @param parserContext current parser context
     * 
     * @return bean definition reference
     */
    public static RuntimeBeanReference parseCustomElement(Element element, ParserContext parserContext) {
        return parseCustomElement(element, "id", parserContext);
    }

    /**
     * Parses a bean definition using an xsi:type aware version of
     * BeanDefinitionParserDelegate.parseCustomElement(Element).
     * 
     * @param element element to parse
     * @param idAttribute attribute that carries the unique ID for the bean
     * @param parserContext current parser context
     * 
     * @return bean definition reference
     */
    public static RuntimeBeanReference parseCustomElement(Element element, String idAttribute,
            ParserContext parserContext) {
        createBeanDefinition(element, parserContext);
        RuntimeBeanReference beanRef = new RuntimeBeanReference(element.getAttributeNS(null, idAttribute));
        beanRef.setSource(element);
        return beanRef;
    }

    /**
     * Creates a {@link BeanDefinition} from a custom element.
     * 
     * @param element configuration element
     * @param parserContext currently parser context
     * 
     * @return the bean definition
     */
    private static BeanDefinition createBeanDefinition(Element element, ParserContext parserContext) {
        BeanDefinitionParserDelegate delegate = parserContext.getDelegate();
        String namespaceUri = element.getNamespaceURI();

        if (XMLHelper.hasXSIType(element)) {
            namespaceUri = XMLHelper.getXSIType(element).getNamespaceURI();
        }

        NamespaceHandler handler = delegate.getReaderContext().getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            log.error("Unable to locate NamespaceHandler for namespace [" + namespaceUri + "]");
            return null;
        }
        return handler.parse(element, new ParserContext(delegate.getReaderContext(), delegate));
    }

    /**
     * Parses a custom element that is a reference to a bean declared elsewhere.
     * 
     * @param element the element that references the bean
     * @param refAttribute the name of the attribute that contains the referenced bean's name
     * @param parserContext current parsing context
     * 
     * @return reference to the bean or null if the element did not contain the reference attribute
     */
    public static RuntimeBeanReference parseCustomElementReference(Element element, String refAttribute,
            ParserContext parserContext) {
        String reference = DatatypeHelper.safeTrimOrNullString(element.getAttributeNS(null, refAttribute));
        if (reference != null) {
            return new RuntimeBeanReference(reference);
        }

        return null;
    }

    /**
     * Parse list of elements into bean definitions. The list is populated with bean references. Each configuration
     * element is expected to contain an 'id' attribute that provides a unique ID for each bean.
     * 
     * @param elements list of elements to parse
     * @param parserContext current parsing context
     * 
     * @return list of bean references
     */
    public static ManagedList parseCustomElements(List<Element> elements, ParserContext parserContext) {
        return parseCustomElements(elements, "id", parserContext);
    }

    /**
     * Parse list of elements into bean definitions.
     * 
     * @param elements list of elements to parse
     * @param idAttribute attribute that carries the unique ID for the bean
     * @param parserContext current parsing context
     * 
     * @return list of bean references
     */
    public static ManagedList parseCustomElements(List<Element> elements, String idAttribute,
            ParserContext parserContext) {
        if (elements == null) {
            return null;
        }

        ManagedList definitions = new ManagedList(elements.size());
        for (Element e : elements) {
            definitions.add(parseCustomElement(e, idAttribute, parserContext));
        }

        return definitions;
    }

    /**
     * Converts a duration, either expressed as numerical time or or ISO8601 duration. If a numerical form is used a
     * warning message indicating that the new IS08601 duration form should be used will be written to the logs.
     * 
     * This method will be removed once the deprecated numerical duration form is no longer allowed.
     * 
     * @param propertyName Name of the property carrying the duration. This is used in the warning log message if the
     *            duration is in numerical form.
     * @param duration the duration to be parsed
     * @param toMillisFactor used to convert a numerical duration to milliseconds, 0 indicates no conversion
     * 
     * @return the duration in milliseconds
     * 
     * @throws IllegalArgumentException thrown if the given duration is either an invalid number or ISO8601 duration or
     *             if the duration is negative
     */
    @Deprecated
    public static long parseDurationToMillis(String propertyName, String duration, int toMillisFactor)
            throws IllegalArgumentException {
        if (duration.startsWith("-")) {
            throw new IllegalArgumentException("Negative durations are not supported");
        }

        long millis = 0;
        if (duration.startsWith("P")) {
            Duration xmlDuration = XMLHelper.getDataTypeFactory().newDuration(duration);
            millis = xmlDuration.getTimeInMillis(new Date());
        } else {
            try {
                millis = Long.parseLong(duration);
                if (millis < 0) {
                    throw new IllegalArgumentException("Negative durations are not supported");
                }
                if (toMillisFactor > 0) {
                    millis *= toMillisFactor;
                }
                Duration xmlDuration = XMLHelper.getDataTypeFactory().newDuration(millis);
                log.warn(
                        "Numerical duration form is deprecated. The property {} should use the duration notation: {}",
                        propertyName, xmlDuration.toString());
            } catch (NumberFormatException e) {

            }
        }

        return millis;
    }
}