net.shibboleth.ext.spring.util.SpringSupport Maven / Gradle / Ivy
/*
* 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 net.shibboleth.ext.spring.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Collection;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.xml.namespace.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.GenericApplicationContext;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import com.google.common.base.Strings;
import net.shibboleth.ext.spring.context.FilesystemGenericApplicationContext;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
import net.shibboleth.utilities.java.support.xml.SerializeSupport;
import net.shibboleth.utilities.java.support.xml.XMLConstants;
/**
* Helper class for performing some common Spring-related functions.
*/
public final class SpringSupport {
/** Spring beans element name. */
@Nonnull public static final QName SPRING_BEANS_ELEMENT_NAME = new QName(
"http://www.springframework.org/schema/beans", "beans");
/** Logger. */
@Nonnull static final Logger LOG = LoggerFactory.getLogger(SpringSupport.class);
/** Constructor. */
private SpringSupport() {
}
/**
* Parse list of elements into bean definitions which are inserted into the parent context.
*
* @param elements list of elements to parse
* @param parserContext current parsing context
*
*/
@Nullable public static void parseCustomElements(
@Nullable @NonnullElements final Collection elements, @Nonnull final ParserContext parserContext) {
if (elements == null) {
return;
}
for (final Element e : elements) {
if (e != null) {
parseCustomElement(e, parserContext, null, false);
}
}
}
/**
* Parse list of elements into bean definitions.
*
* @param elements list of elements to parse
* @param parserContext current parsing context
* @param parentBuilder the builder we are going to insert into
*
* @return list of bean definitions
*/
@Nullable public static ManagedList parseCustomElements(
@Nullable @NonnullElements final Collection elements,
@Nonnull final ParserContext parserContext,
@Nonnull final BeanDefinitionBuilder parentBuilder) {
if (elements == null) {
return null;
}
Constraint.isNotNull(parentBuilder, "parentBuilder must not be null");
final ManagedList definitions = new ManagedList<>(elements.size());
for (final Element e : elements) {
if (e != null) {
definitions.add(parseCustomElement(e, parserContext, parentBuilder, false));
}
}
return definitions;
}
/**
* Parse list of elements into bean definitions and set the lazy-init flag.
*
* @param elements list of elements to parse
* @param parserContext current parsing context
*
* @since 6.0.0
*/
@Nullable public static void parseLazyInitCustomElements(
@Nullable @NonnullElements final Collection elements, @Nonnull final ParserContext parserContext) {
if (elements == null) {
return;
}
for (final Element e : elements) {
if (e != null) {
parseLazyInitCustomElement(e, parserContext);
}
}
}
/**
* Root method for all parsing.
*
* @param element the element to parse.
* This works in two scoping modes. If the parent builder is
* null then this bean is to be inserted into the provided parser context, in this case the parent builder is null.
* If the parent builder is provided then the scope is limited and the bean definition is returned.
* @param parserContext current parsing context
* @param parentBuilder the parent builder (for nested building).
* @param lazyInit whether this is lazy initialized;
* @return the bean definition, unless this is for a parent scoped bean
*/
@Nullable public static BeanDefinition parseCustomElement(@Nullable final Element element,
@Nonnull final ParserContext parserContext,
@Nullable final BeanDefinitionBuilder parentBuilder,
final boolean lazyInit) {
if (element == null) {
return null;
}
final AbstractBeanDefinition containingBd;
if (parentBuilder != null) {
containingBd = parentBuilder.getRawBeanDefinition();
} else {
containingBd = null;
}
final BeanDefinition def = parserContext.getDelegate().parseCustomElement(element, containingBd);
if (lazyInit) {
def.setLazyInit(true);
}
if (null == parentBuilder) {
return null;
}
return def;
}
/**
* Parse an element into a bean definition and set the lazy-init flag.
*
* @param element the element to parse
* @param parserContext current parsing context
*
* @since 6.0.0
*/
@Nullable public static void parseLazyInitCustomElement(@Nullable final Element element,
@Nonnull final ParserContext parserContext) {
if (element == null) {
return;
}
parseCustomElement(element, parserContext, null, true);
}
/**
* Parse the provided Element into the provided registry.
*
* @param springBeans the element to parse
* @param registry the registry to populate
*/
public static void
parseNativeElement(@Nonnull final Element springBeans, @Nullable final BeanDefinitionRegistry registry) {
final XmlBeanDefinitionReader definitionReader = new XmlBeanDefinitionReader(registry);
definitionReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
definitionReader.setNamespaceAware(true);
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
SerializeSupport.writeNode(springBeans, outputStream);
definitionReader.loadBeanDefinitions(new InputSource(new ByteArrayInputStream(outputStream.toByteArray())));
}
/**
* Creates a Spring bean factory from the supplied Spring beans element.
*
* @param springBeans to create bean factory from
*
* @return bean factory
*/
@Nonnull public static BeanFactory createBeanFactory(@Nonnull final Element springBeans) {
// Pull in the closest xsi:schemaLocation attribute we can find.
if (!springBeans.hasAttributeNS(XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME.getNamespaceURI(),
XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME.getLocalPart())) {
Node parent = springBeans.getParentNode();
while (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
final String schemaLoc =
((Element) parent).getAttributeNS(
XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME.getNamespaceURI(),
XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME.getLocalPart());
if (!Strings.isNullOrEmpty(schemaLoc)) {
springBeans.setAttributeNS(XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME.getNamespaceURI(),
XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME.getPrefix() + ':'
+ XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME.getLocalPart(), schemaLoc);
break;
}
parent = parent.getParentNode();
}
}
final GenericApplicationContext ctx = new FilesystemGenericApplicationContext();
parseNativeElement(springBeans, ctx);
ctx.refresh();
return ctx.getBeanFactory();
}
/**
* Retrieves the bean of the supplied type from the supplied bean factory. Returns null if no bean definition is
* found.
*
* @param type of bean to return
* @param beanFactory to get the bean from
* @param clazz type of the bean to retrieve
*
* @return spring bean
*/
@Nullable public static T getBean(@Nonnull final BeanFactory beanFactory, @Nonnull final Class clazz) {
T bean = null;
try {
bean = beanFactory.getBean(clazz);
LOG.debug("created spring bean {}", bean);
} catch (final NoSuchBeanDefinitionException e) {
LOG.debug("no spring bean configured of type {}", clazz);
}
return bean;
}
/**
* Gets the value of a list-type attribute as a {@link BeanDefinitionBuilder}.
*
* @param attribute attribute whose value will be turned into a list
* @return a bean which will generate a list of the values.
*/
@Nonnull public static AbstractBeanDefinition getAttributeValueAsList(@Nonnull final Attr attribute) {
final BeanDefinitionBuilder result =
BeanDefinitionBuilder.rootBeanDefinition(StringSupport.class, "stringToList");
result.addConstructorArgValue(attribute.getValue());
result.addConstructorArgValue(XMLConstants.LIST_DELIMITERS);
return result.getBeanDefinition();
}
/**
* Gets the value of a boolean-type string as a (ptentially null) {@link Boolean}.
*
* @param string value will be turned into a boolean (or null) (after property replacement)
* @return a bean which will generate a list of the values.
*/
@Nullable public static AbstractBeanDefinition getStringValueAsBoolean(@Nullable final String string) {
final BeanDefinitionBuilder result =
BeanDefinitionBuilder.rootBeanDefinition(StringSupport.class, "booleanOf");
result.addConstructorArgValue(string);
return result.getBeanDefinition();
}
/**
* Gets the text content of a list of {@link Element}s as a {@link ManagedList}.
*
* @param elements the elements whose values will be turned into a list
*
* @return list of values, never null
*/
@Nonnull public static ManagedList getElementTextContentAsManagedList(
@Nullable final Collection elements) {
if (null == elements || elements.isEmpty()) {
return new ManagedList<>(0);
}
final ManagedList result = new ManagedList<>(elements.size());
for (final Element element : elements) {
final String textContent = StringSupport.trimOrNull(element.getTextContent());
if (null != textContent) {
result.add(textContent);
}
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy