View Javadoc

1   /*
2    * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package edu.internet2.middleware.shibboleth.common.config;
18  
19  import java.util.List;
20  
21  import org.opensaml.util.resource.Resource;
22  import org.opensaml.util.resource.ResourceException;
23  import org.opensaml.xml.util.DatatypeHelper;
24  import org.opensaml.xml.util.XMLHelper;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  import org.springframework.beans.factory.BeanDefinitionStoreException;
28  import org.springframework.beans.factory.config.BeanDefinition;
29  import org.springframework.beans.factory.config.RuntimeBeanReference;
30  import org.springframework.beans.factory.support.BeanDefinitionRegistry;
31  import org.springframework.beans.factory.support.ManagedList;
32  import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
33  import org.springframework.beans.factory.xml.NamespaceHandler;
34  import org.springframework.beans.factory.xml.ParserContext;
35  import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
36  import org.springframework.core.io.InputStreamResource;
37  import org.w3c.dom.Element;
38  
39  /**
40   * Utilities to help configure Spring beans.
41   */
42  public final class SpringConfigurationUtils {
43  
44      /** Log4j logger. */
45      private static Logger log = LoggerFactory.getLogger(SpringConfigurationUtils.class);
46  
47      /** Private Constructor. */
48      private SpringConfigurationUtils() {
49      }
50  
51      /**
52       * Loads a set of spring configuration resources into a given application context.
53       * 
54       * @param beanRegistry registry of spring beans to be populated with information from the given configurations
55       * @param configurationResources list of spring configuration resources
56       * 
57       * @throws ResourceException thrown if there is a problem reading the spring configuration resources into the
58       *             registry
59       */
60      public static void populateRegistry(BeanDefinitionRegistry beanRegistry, List<Resource> configurationResources)
61              throws ResourceException {
62          XmlBeanDefinitionReader configReader = new XmlBeanDefinitionReader(beanRegistry);
63          configReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
64          configReader.setDocumentLoader(new SpringDocumentLoader());
65  
66          int numOfResources = configurationResources.size();
67          Resource configurationResource;
68          org.springframework.core.io.Resource[] configSources = new org.springframework.core.io.Resource[numOfResources];
69          for (int i = 0; i < numOfResources; i++) {
70              configurationResource = configurationResources.get(i);
71              if (configurationResource != null && configurationResource.exists()) {
72                  configSources[i] = new InputStreamResource(configurationResources.get(i).getInputStream(),
73                          configurationResource.getLocation());
74              } else {
75                  log.warn("Configuration resource not loaded because it does not exist: {}", configurationResource
76                          .getLocation());
77              }
78          }
79  
80          try {
81              configReader.loadBeanDefinitions(configSources);
82          } catch (BeanDefinitionStoreException e) {
83              throw new ResourceException("Unable to load Spring bean registry with configuration resources", e);
84          }
85      }
86  
87      /**
88       * Parses a bean definition using an xsi:type aware version of
89       * {@link BeanDefinitionParserDelegate#parseCustomElement(Element)}.
90       * 
91       * @param element configuration element
92       * @param parserContext current parser context
93       * 
94       * @return bean definition
95       */
96      public static BeanDefinition parseInnerCustomElement(Element element, ParserContext parserContext) {
97          return createBeanDefinition(element, parserContext);
98      }
99  
100     /**
101      * Parser a list of bean definitions using an xsi:type aware version of
102      * {@link BeanDefinitionParserDelegate#parseCustomElement(Element)}.
103      * 
104      * @param elements configuration elements
105      * @param parserContext current parser context
106      * 
107      * @return list of bean definition
108      */
109     public static ManagedList parseInnerCustomElements(List<Element> elements, ParserContext parserContext) {
110         ManagedList beans = new ManagedList();
111         if (elements != null) {
112             for (Element element : elements) {
113                 beans.add(parseInnerCustomElement(element, parserContext));
114             }
115         }
116 
117         return beans;
118     }
119 
120     /**
121      * Parses a bean definition using an xsi:type aware version of
122      * BeanDefinitionParserDelegate.parseCustomElement(Element). Assumes the element has an attribute 'id' that provides
123      * a unique identifier for the bean.
124      * 
125      * @param element element to parse
126      * @param parserContext current parser context
127      * 
128      * @return bean definition reference
129      */
130     public static RuntimeBeanReference parseCustomElement(Element element, ParserContext parserContext) {
131         return parseCustomElement(element, "id", parserContext);
132     }
133 
134     /**
135      * Parses a bean definition using an xsi:type aware version of
136      * BeanDefinitionParserDelegate.parseCustomElement(Element).
137      * 
138      * @param element element to parse
139      * @param idAttribute attribute that carries the unique ID for the bean
140      * @param parserContext current parser context
141      * 
142      * @return bean definition reference
143      */
144     public static RuntimeBeanReference parseCustomElement(Element element, String idAttribute,
145             ParserContext parserContext) {
146         createBeanDefinition(element, parserContext);
147         RuntimeBeanReference beanRef = new RuntimeBeanReference(element.getAttributeNS(null, idAttribute));
148         beanRef.setSource(element);
149         return beanRef;
150     }
151 
152     /**
153      * Creates a {@link BeanDefinition} from a custom element.
154      * 
155      * @param element configuration element
156      * @param parserContext currently parser context
157      * 
158      * @return the bean definition
159      */
160     private static BeanDefinition createBeanDefinition(Element element, ParserContext parserContext) {
161         BeanDefinitionParserDelegate delegate = parserContext.getDelegate();
162         String namespaceUri = element.getNamespaceURI();
163 
164         if (XMLHelper.hasXSIType(element)) {
165             namespaceUri = XMLHelper.getXSIType(element).getNamespaceURI();
166         }
167 
168         NamespaceHandler handler = delegate.getReaderContext().getNamespaceHandlerResolver().resolve(namespaceUri);
169         if (handler == null) {
170             log.error("Unable to locate NamespaceHandler for namespace [" + namespaceUri + "]");
171             return null;
172         }
173         return handler.parse(element, new ParserContext(delegate.getReaderContext(), delegate));
174     }
175 
176     /**
177      * Parses a custom element that is a reference to a bean declared elsewhere.
178      * 
179      * @param element the element that references the bean
180      * @param refAttribute the name of the attribute that contains the referenced bean's name
181      * @param parserContext current parsing context
182      * 
183      * @return reference to the bean or null if the element did not contain the reference attribute
184      */
185     public static RuntimeBeanReference parseCustomElementReference(Element element, String refAttribute,
186             ParserContext parserContext) {
187         String reference = DatatypeHelper.safeTrimOrNullString(element.getAttributeNS(null, refAttribute));
188         if (reference != null) {
189             return new RuntimeBeanReference(reference);
190         }
191 
192         return null;
193     }
194 
195     /**
196      * Parse list of elements into bean definitions. The list is populated with bean references. Each configuration
197      * element is expected to contain an 'id' attribute that provides a unique ID for each bean.
198      * 
199      * @param elements list of elements to parse
200      * @param parserContext current parsing context
201      * 
202      * @return list of bean references
203      */
204     public static ManagedList parseCustomElements(List<Element> elements, ParserContext parserContext) {
205         return parseCustomElements(elements, "id", parserContext);
206     }
207 
208     /**
209      * Parse list of elements into bean definitions.
210      * 
211      * @param elements list of elements to parse
212      * @param idAttribute attribute that carries the unique ID for the bean
213      * @param parserContext current parsing context
214      * 
215      * @return list of bean references
216      */
217     public static ManagedList parseCustomElements(List<Element> elements, String idAttribute,
218             ParserContext parserContext) {
219         if (elements == null) {
220             return null;
221         }
222 
223         ManagedList definitions = new ManagedList(elements.size());
224         for (Element e : elements) {
225             definitions.add(parseCustomElement(e, idAttribute, parserContext));
226         }
227 
228         return definitions;
229     }
230 }