001    /**
002     * Copyright 2010-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.common.util.spring;
017    
018    import java.io.File;
019    import java.util.ArrayList;
020    import java.util.Arrays;
021    import java.util.Collections;
022    import java.util.Comparator;
023    import java.util.Iterator;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.Properties;
027    
028    import org.codehaus.plexus.util.StringUtils;
029    import org.kuali.common.util.Assert;
030    import org.kuali.common.util.CollectionUtils;
031    import org.kuali.common.util.FormatUtils;
032    import org.kuali.common.util.LocationUtils;
033    import org.kuali.common.util.LoggerLevel;
034    import org.kuali.common.util.LoggerUtils;
035    import org.kuali.common.util.Project;
036    import org.kuali.common.util.ProjectContext;
037    import org.kuali.common.util.ProjectUtils;
038    import org.kuali.common.util.PropertyUtils;
039    import org.kuali.common.util.ReflectionUtils;
040    import org.kuali.common.util.Str;
041    import org.kuali.common.util.execute.Executable;
042    import org.kuali.common.util.execute.SpringExecutable;
043    import org.kuali.common.util.nullify.NullUtils;
044    import org.kuali.common.util.property.Constants;
045    import org.kuali.common.util.property.ProjectProperties;
046    import org.kuali.common.util.property.PropertiesContext;
047    import org.kuali.common.util.service.DefaultSpringService;
048    import org.kuali.common.util.service.PropertySourceContext;
049    import org.kuali.common.util.service.SpringContext;
050    import org.kuali.common.util.service.SpringService;
051    import org.slf4j.Logger;
052    import org.slf4j.LoggerFactory;
053    import org.springframework.beans.factory.BeanFactoryUtils;
054    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
055    import org.springframework.context.ApplicationContext;
056    import org.springframework.context.ConfigurableApplicationContext;
057    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
058    import org.springframework.context.support.ClassPathXmlApplicationContext;
059    import org.springframework.context.support.GenericXmlApplicationContext;
060    import org.springframework.core.env.ConfigurableEnvironment;
061    import org.springframework.core.env.EnumerablePropertySource;
062    import org.springframework.core.env.Environment;
063    import org.springframework.core.env.MutablePropertySources;
064    import org.springframework.core.env.PropertiesPropertySource;
065    import org.springframework.core.env.PropertySource;
066    
067    public class SpringUtils {
068    
069            private static final Logger logger = LoggerFactory.getLogger(SpringUtils.class);
070    
071            private static final String GLOBAL_SPRING_PROPERTY_SOURCE_NAME = "springPropertySource";
072    
073            public static SpringContext getSpringContext(List<Class<?>> annotatedClasses, ProjectContext project, List<ProjectContext> others) {
074                    // This PropertySource object is backed by a set of properties that has been
075                    // 1 - fully resolved
076                    // 2 - contains all properties needed by Spring
077                    // 3 - contains system/environment properties where system/env properties override loaded properties
078                    PropertySource<?> source = getGlobalPropertySource(project, others);
079    
080                    // Setup a property source context such that our single property source is the only one registered with Spring
081                    // This will make it so our PropertySource is the ONLY thing used to resolve placeholders
082                    PropertySourceContext psc = new PropertySourceContext(source, true);
083    
084                    // Setup a Spring context
085                    SpringContext context = new SpringContext();
086    
087                    // Supply Spring with our PropertySource
088                    context.setPropertySourceContext(psc);
089    
090                    // Supply Spring with java classes containing annotated config
091                    context.setAnnotatedClasses(annotatedClasses);
092    
093                    // Return a Spring context configured with a single property source
094                    return context;
095            }
096    
097            public static SpringContext getSpringContext(Class<?> annotatedClass, ProjectContext project, List<ProjectContext> others) {
098                    return getSpringContext(CollectionUtils.asList(annotatedClass), project, others);
099            }
100    
101            /**
102             * <code>project</code> needs to be a top level project eg rice-sampleapp, olefs-webapp. <code>others</code> is projects for submodules organized into a list where the last one
103             * in wins.
104             */
105            public static PropertySource<?> getGlobalPropertySource(ProjectContext project, ProjectContext other) {
106                    return getGlobalPropertySource(project, Arrays.asList(other));
107            }
108    
109            /**
110             * <code>project</code> needs to be a top level project eg rice-sampleapp, olefs-webapp. <code>others</code> is projects for submodules organized into a list where the last one
111             * in wins.
112             */
113            public static PropertySource<?> getGlobalPropertySource(ProjectContext project, List<ProjectContext> others) {
114                    return getGlobalPropertySource(project, others, null);
115            }
116    
117            /**
118             * <code>project</code> needs to be a top level project eg rice-sampleapp, olefs-webapp. <code>others</code> is projects for submodules organized into a list where the last one
119             * in wins.
120             */
121            public static PropertySource<?> getGlobalPropertySource(ProjectContext project, List<ProjectContext> others, Properties properties) {
122    
123                    ProjectProperties projectProperties = ProjectUtils.loadProjectProperties(project);
124    
125                    Properties existing = projectProperties.getPropertiesContext().getProperties();
126                    Properties combined = PropertyUtils.combine(existing, properties);
127                    projectProperties.getPropertiesContext().setProperties(combined);
128    
129                    List<ProjectProperties> otherProjectProperties = new ArrayList<ProjectProperties>();
130                    for (ProjectContext other : CollectionUtils.toEmptyList(others)) {
131                            ProjectProperties opp = ProjectUtils.loadProjectProperties(other);
132                            otherProjectProperties.add(opp);
133                    }
134    
135                    // Get a PropertySource object backed by the properties loaded from the list as well as system/environment properties
136                    return getGlobalPropertySource(projectProperties, otherProjectProperties);
137            }
138    
139            /**
140             * <code>project</code> needs to be a top level project eg rice-sampleapp, olefs-webapp. <code>others</code> is projects for submodules organized into a list where the last one
141             * in wins.
142             */
143            public static PropertySource<?> getGlobalPropertySource(ProjectProperties project) {
144                    return getGlobalPropertySource(project, null);
145            }
146    
147            /**
148             * <code>project</code> needs to be a top level project eg rice-sampleapp, olefs-webapp. <code>others</code> is projects for submodules organized into a list where the last one
149             * in wins.
150             */
151            public static PropertySource<?> getGlobalPropertySource(ProjectProperties project, List<ProjectProperties> others) {
152                    // Property loading uses a "last one in wins" strategy
153                    List<ProjectProperties> list = new ArrayList<ProjectProperties>();
154    
155                    // Add project properties first so they can be used to resolve locations
156                    list.add(project);
157    
158                    if (!CollectionUtils.isEmpty(others)) {
159                            // Load in other project properties
160                            list.addAll(others);
161    
162                            // Add project properties last so they override loaded properties
163                            list.add(project);
164                    }
165    
166                    // Get a PropertySource object backed by the properties loaded from the list as well as system/environment properties
167                    return getGlobalPropertySource(GLOBAL_SPRING_PROPERTY_SOURCE_NAME, list);
168            }
169    
170            public static List<String> getIncludes(Environment env, String key, String defaultValue) {
171                    String includes = SpringUtils.getProperty(env, key, defaultValue);
172                    if (NullUtils.isNull(includes) || StringUtils.equals(includes, Constants.WILDCARD)) {
173                            return new ArrayList<String>();
174                    } else {
175                            return CollectionUtils.getTrimmedListFromCSV(includes);
176                    }
177            }
178    
179            public static List<String> getIncludes(Environment env, String key) {
180                    return getIncludes(env, key, null);
181            }
182    
183            public static List<String> getExcludes(Environment env, String key, String defaultValue) {
184                    String excludes = SpringUtils.getProperty(env, key, defaultValue);
185                    if (NullUtils.isNullOrNone(excludes)) {
186                            return new ArrayList<String>();
187                    } else {
188                            return CollectionUtils.getTrimmedListFromCSV(excludes);
189                    }
190            }
191    
192            public static List<String> getExcludes(Environment env, String key) {
193                    return getExcludes(env, key, null);
194            }
195    
196            /**
197             * Given a property holding the name of a class, return an instance of that class
198             */
199            public static <T> T getInstance(Environment env, String key, Class<T> defaultValue) {
200                    String className = getProperty(env, key, defaultValue.getCanonicalName());
201                    return ReflectionUtils.newInstance(className);
202            }
203    
204            /**
205             * Given a property holding the name of a class, return an instance of that class
206             */
207            public static <T> T getInstance(Environment env, String key) {
208                    String className = getProperty(env, key, null);
209                    return ReflectionUtils.newInstance(className);
210            }
211    
212            public static List<String> getListFromCSV(Environment env, String key, String defaultValue) {
213                    String csv = SpringUtils.getProperty(env, key, defaultValue);
214                    return CollectionUtils.getTrimmedListFromCSV(csv);
215            }
216    
217            @Deprecated
218            public static List<PropertySource<?>> getPropertySources(SpringService service, Class<?> annotatedClass, String propertiesBeanName, Properties properties) {
219                    return getPropertySources(annotatedClass, propertiesBeanName, properties);
220            }
221    
222            /**
223             * Scan the annotated class to find the single bean registered in the context that implements <code>PropertySource</code>. If more than one bean is located, throw
224             * <code>IllegalStateException</code>.
225             */
226            public static PropertySource<?> getSinglePropertySource(Class<?> annotatedClass) {
227                    return getSinglePropertySource(annotatedClass, null, null);
228            }
229    
230            /**
231             * Scan the annotated class to find the single bean registered in the context that implements <code>PropertySource</code>. If more than one bean is located, throw
232             * <code>IllegalStateException</code>.
233             */
234            public static PropertySource<?> getSinglePropertySource(Class<?> annotatedClass, String propertiesBeanName, Properties properties) {
235                    List<PropertySource<?>> sources = getPropertySources(annotatedClass, propertiesBeanName, properties);
236                    if (sources.size() > 1) {
237                            throw new IllegalStateException("More than one PropertySource was registered in the context");
238                    } else {
239                            return sources.get(0);
240                    }
241            }
242    
243            public static List<PropertySource<?>> getPropertySources(Class<?> annotatedClass, String propertiesBeanName, Properties properties) {
244                    ConfigurableApplicationContext parent = null;
245                    if (properties == null) {
246                            parent = getConfigurableApplicationContext();
247                    } else {
248                            parent = getContextWithPreRegisteredBean(propertiesBeanName, properties);
249                    }
250                    AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
251                    child.setParent(parent);
252                    child.register(annotatedClass);
253                    child.refresh();
254                    return getPropertySources(child);
255            }
256    
257            @Deprecated
258            public static List<PropertySource<?>> getPropertySources(SpringService service, String location, String mavenPropertiesBeanName, Properties mavenProperties) {
259                    return getPropertySources(location, mavenPropertiesBeanName, mavenProperties);
260            }
261    
262            public static List<PropertySource<?>> getPropertySources(String location, String mavenPropertiesBeanName, Properties mavenProperties) {
263                    String[] locationsArray = { location };
264                    ConfigurableApplicationContext parent = getContextWithPreRegisteredBean(mavenPropertiesBeanName, mavenProperties);
265                    ConfigurableApplicationContext child = new ClassPathXmlApplicationContext(locationsArray, parent);
266                    return SpringUtils.getPropertySources(child);
267            }
268    
269            public static Executable getSpringExecutable(Environment env, boolean skip, PropertySource<?> ps, List<Class<?>> annotatedClasses) {
270                    /**
271                     * This line creates a property source containing 100% of the properties needed by Spring to resolve any/all placeholders. It will be the only property source available to
272                     * Spring so it needs to include system properties and environment variables
273                     */
274                    PropertySourceContext psc = new PropertySourceContext(ps, true);
275    
276                    // Setup the Spring context
277                    SpringContext context = new SpringContext();
278                    context.setAnnotatedClasses(annotatedClasses);
279                    context.setPropertySourceContext(psc);
280    
281                    // Load the context
282                    SpringExecutable se = new SpringExecutable();
283                    se.setService(new DefaultSpringService());
284                    se.setContext(context);
285                    se.setSkip(skip);
286                    return se;
287            }
288    
289            public static int getInteger(Environment env, String key) {
290                    String value = getProperty(env, key);
291                    return Integer.parseInt(value);
292            }
293    
294            public static int getInteger(Environment env, String key, int defaultValue) {
295                    String value = getProperty(env, key, Integer.toString(defaultValue));
296                    return Integer.parseInt(value);
297            }
298    
299            public static long getLong(Environment env, String key) {
300                    String value = getProperty(env, key);
301                    return Long.parseLong(value);
302            }
303    
304            public static long getLong(Environment env, String key, long defaultValue) {
305                    String value = getProperty(env, key, Long.toString(defaultValue));
306                    return Long.parseLong(value);
307            }
308    
309            public static double getDouble(Environment env, String key) {
310                    String value = getProperty(env, key);
311                    return Double.parseDouble(value);
312            }
313    
314            public static double getDouble(Environment env, String key, double defaultValue) {
315                    String value = getProperty(env, key, Double.toString(defaultValue));
316                    return Double.parseDouble(value);
317            }
318    
319            /**
320             * Parse milliseconds from a time string that ends with a unit of measure. If no unit of measure is provided, milliseconds is assumed. Unit of measure is case insensitive.
321             * 
322             * @see FormatUtils.getMillis(String time)
323             */
324            public static long getMillis(Environment env, String key, String defaultValue) {
325                    String value = getProperty(env, key, defaultValue);
326                    return FormatUtils.getMillis(value);
327            }
328    
329            /**
330             * Parse bytes from a size string that ends with a unit of measure. If no unit of measure is provided, bytes is assumed. Unit of measure is case insensitive.
331             * 
332             * @see FormatUtils.getBytes(String size)
333             */
334            public static long getBytes(Environment env, String key, String defaultValue) {
335                    String value = getProperty(env, key, defaultValue);
336                    return FormatUtils.getBytes(value);
337            }
338    
339            /**
340             * Parse bytes from a size string that ends with a unit of measure. If no unit of measure is provided, bytes is assumed. Unit of measure is case insensitive.
341             * 
342             * @see FormatUtils.getBytes(String size)
343             */
344            public static long getBytes(Environment env, String key) {
345                    String value = getProperty(env, key);
346                    return FormatUtils.getBytes(value);
347            }
348    
349            public static File getFile(Environment env, String key) {
350                    String value = getProperty(env, key);
351                    return new File(value);
352            }
353    
354            public static boolean getBoolean(Environment env, String key, boolean defaultValue) {
355                    String value = getProperty(env, key, Boolean.toString(defaultValue));
356                    return Boolean.parseBoolean(value);
357            }
358    
359            public static boolean getBoolean(Environment env, String key) {
360                    String value = getProperty(env, key);
361                    return Boolean.parseBoolean(value);
362            }
363    
364            public static PropertySource<?> getGlobalPropertySource(String name, List<ProjectProperties> pps) {
365                    // Load them from disk
366                    Properties source = PropertyUtils.load(pps);
367    
368                    // Add in system/environment properties
369                    Properties globalSource = PropertyUtils.getGlobalProperties(source);
370    
371                    logger.debug("Before prepareContextProperties()");
372                    PropertyUtils.debug(globalSource);
373    
374                    // Prepare them so they are ready for use
375                    PropertyUtils.prepareContextProperties(globalSource);
376    
377                    logger.debug("After prepareContextProperties()");
378                    PropertyUtils.debug(globalSource);
379    
380                    // Return a PropertySource backed by the properties
381                    return new PropertiesPropertySource(name, globalSource);
382            }
383    
384            /**
385             * Return a SpringContext that resolves all placeholders from the PropertySource passed in
386             */
387            public static PropertySource<?> getGlobalPropertySource(List<String> locations, String encoding) {
388                    Properties loaded = PropertyUtils.load(locations, encoding);
389                    Properties global = PropertyUtils.getGlobalProperties(loaded);
390                    PropertyUtils.prepareContextProperties(global);
391                    return new PropertiesPropertySource(GLOBAL_SPRING_PROPERTY_SOURCE_NAME, global);
392            }
393    
394            /**
395             * Return a SpringContext that resolves all placeholders from the list of property locations passed in + System/Environment properties
396             */
397            public static SpringContext getSinglePropertySourceContext(ProjectContext context, String location) {
398                    PropertySource<?> source = getGlobalPropertySource(context, location);
399                    return getSinglePropertySourceContext(source);
400            }
401    
402            /**
403             * Return a SpringExecutable for the project, properties location, and config passed in.
404             */
405            public static SpringExecutable getSpringExecutable(ProjectContext project, String location, List<Class<?>> annotatedClasses) {
406                    SpringContext context = getSinglePropertySourceContext(project, location);
407                    context.setAnnotatedClasses(annotatedClasses);
408    
409                    SpringExecutable executable = new SpringExecutable();
410                    executable.setContext(context);
411                    return executable;
412            }
413    
414            /**
415             * Return a SpringExecutable for the project, properties location, and config passed in.
416             */
417            public static SpringExecutable getSpringExecutable(ProjectContext project, String location, Class<?> annotatedClass) {
418                    List<Class<?>> classes = new ArrayList<Class<?>>();
419                    classes.add(annotatedClass);
420    
421                    return getSpringExecutable(project, location, classes);
422            }
423    
424            /**
425             * Return a SpringContext that resolves all placeholders from the list of property locations passed in + System/Environment properties
426             */
427            public static SpringContext getSinglePropertySourceContext(List<String> locations, String encoding) {
428                    PropertySource<?> source = getGlobalPropertySource(locations, encoding);
429                    return getSinglePropertySourceContext(source);
430            }
431    
432            /**
433             * Return a SpringContext that resolves all placeholders from the PropertySource passed in
434             */
435            public static SpringContext getSinglePropertySourceContext(PropertySource<?> source) {
436                    // Setup a property source context such that our single property source is the only one registered with Spring
437                    // This will make it so our PropertySource is the ONLY thing used to resolve placeholders
438                    PropertySourceContext psc = new PropertySourceContext(source, true);
439    
440                    // Setup a Spring context
441                    SpringContext context = new SpringContext();
442    
443                    // Supply Spring with our PropertySource
444                    context.setPropertySourceContext(psc);
445    
446                    // Return a Spring context configured with a single property source
447                    return context;
448            }
449    
450            public static PropertySource<?> getGlobalPropertySource(ProjectContext context, String... locations) {
451                    ProjectProperties pp = ProjectUtils.loadProjectProperties(context);
452                    PropertiesContext pc = pp.getPropertiesContext();
453                    List<String> existingLocations = CollectionUtils.toEmptyList(pc.getLocations());
454                    if (locations != null) {
455                            for (String location : locations) {
456                                    existingLocations.add(location);
457                            }
458                    }
459                    pc.setLocations(existingLocations);
460                    return getGlobalPropertySource(pp);
461            }
462    
463            public static PropertySource<?> getPropertySource(String name, List<ProjectProperties> pps) {
464                    // Load them from disk
465                    Properties source = PropertyUtils.load(pps);
466    
467                    // Prepare them so they are ready for use
468                    PropertyUtils.prepareContextProperties(source);
469    
470                    // Return a PropertySource backed by the properties
471                    return new PropertiesPropertySource(name, source);
472            }
473    
474            /**
475             * Converts a GAV into Spring's classpath style notation for the default project properties context.
476             * 
477             * <pre>
478             *  org.kuali.common:kuali-jdbc -> classpath:org/kuali/common/kuali-jdbc-properties-context.xml
479             * </pre>
480             */
481            public static String getDefaultPropertyContextLocation(String gav) {
482                    Assert.hasText(gav, "gav has no text");
483                    Project p = ProjectUtils.getProject(gav);
484                    return "classpath:" + Str.getPath(p.getGroupId()) + "/" + p.getArtifactId() + "-properties-context.xml";
485            }
486    
487            /**
488             * Make sure all of the locations actually exist
489             */
490            public static void validateExists(List<String> locations) {
491                    StringBuilder sb = new StringBuilder();
492                    for (String location : locations) {
493                            if (!LocationUtils.exists(location)) {
494                                    sb.append("Location [" + location + "] does not exist\n");
495                            }
496                    }
497                    if (sb.length() > 0) {
498                            throw new IllegalArgumentException(sb.toString());
499                    }
500            }
501    
502            public static ConfigurableApplicationContext getContextWithPreRegisteredBeans(String id, String displayName, List<String> beanNames, List<Object> beans) {
503                    Assert.isTrue(beanNames.size() == beans.size());
504                    GenericXmlApplicationContext appContext = new GenericXmlApplicationContext();
505                    if (!StringUtils.isBlank(id)) {
506                            appContext.setId(id);
507                    }
508                    if (!StringUtils.isBlank(displayName)) {
509                            appContext.setDisplayName(displayName);
510                    }
511                    appContext.refresh();
512                    ConfigurableListableBeanFactory factory = appContext.getBeanFactory();
513                    for (int i = 0; i < beanNames.size(); i++) {
514                            String beanName = beanNames.get(i);
515                            Object bean = beans.get(i);
516                            logger.debug("Registering bean - [{}] -> [{}]", beanName, bean.getClass().getName());
517                            factory.registerSingleton(beanName, bean);
518                    }
519                    return appContext;
520            }
521    
522            public static ConfigurableApplicationContext getConfigurableApplicationContext() {
523                    return new GenericXmlApplicationContext();
524            }
525    
526            public static ConfigurableApplicationContext getContextWithPreRegisteredBeans(List<String> beanNames, List<Object> beans) {
527                    return getContextWithPreRegisteredBeans(null, null, beanNames, beans);
528            }
529    
530            /**
531             * Null safe refresh for a context
532             */
533            public static void refreshQuietly(ConfigurableApplicationContext context) {
534                    if (context != null) {
535                            context.refresh();
536                    }
537            }
538    
539            /**
540             * Null safe close for a context
541             */
542            public static void closeQuietly(ConfigurableApplicationContext context) {
543                    if (context != null) {
544                            context.close();
545                    }
546            }
547    
548            public static ConfigurableApplicationContext getContextWithPreRegisteredBean(String beanName, Object bean) {
549                    return getContextWithPreRegisteredBeans(Arrays.asList(beanName), Arrays.asList(bean));
550            }
551    
552            public static List<PropertySource<?>> getPropertySourcesFromAnnotatedClass(String annotatedClassName) {
553                    Class<?> annotatedClass = ReflectionUtils.getClass(annotatedClassName);
554                    return getPropertySources(annotatedClass);
555            }
556    
557            public static List<PropertySource<?>> getPropertySources(Class<?> annotatedClass) {
558                    ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(annotatedClass);
559                    return extractPropertySourcesAndClose(context);
560            }
561    
562            public static List<PropertySource<?>> extractPropertySourcesAndClose(ConfigurableApplicationContext context) {
563                    // Extract PropertySources (if any)
564                    List<PropertySource<?>> sources = getPropertySources(context);
565    
566                    // Close the context
567                    closeQuietly(context);
568    
569                    // Return the list
570                    return sources;
571            }
572    
573            /**
574             * Scan the XML Spring context for any beans that implement <code>PropertySource</code>
575             */
576            public static List<PropertySource<?>> getPropertySources(String location) {
577                    ConfigurableApplicationContext context = new GenericXmlApplicationContext(location);
578                    return extractPropertySourcesAndClose(context);
579            }
580    
581            /**
582             * This method returns a list of any PropertySource objects registered in the indicated context. They are sorted by property source name.
583             */
584            public static List<PropertySource<?>> getPropertySources(ConfigurableApplicationContext context) {
585                    // Sort them by name
586                    return getPropertySources(context, new PropertySourceNameComparator());
587            }
588    
589            public static <T> Map<String, T> getAllBeans(List<String> locations, Class<T> type) {
590                    String[] locationsArray = locations.toArray(new String[locations.size()]);
591                    ConfigurableApplicationContext ctx = new GenericXmlApplicationContext(locationsArray);
592                    Map<String, T> map = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, type);
593                    ctx.close();
594                    return map;
595            }
596    
597            public static <T> Map<String, T> getAllBeans(String location, Class<T> type) {
598                    ConfigurableApplicationContext ctx = new GenericXmlApplicationContext(location);
599                    Map<String, T> map = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, type);
600                    ctx.close();
601                    return map;
602            }
603    
604            public static <T> Map<String, T> getAllBeans(ConfigurableApplicationContext ctx, Class<T> type) {
605                    return BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, type);
606            }
607    
608            /**
609             * This method returns a list of any PropertySource objects registered in the indicated context. The comparator is responsible for putting them in correct order.
610             */
611            public static List<PropertySource<?>> getPropertySources(ConfigurableApplicationContext context, Comparator<PropertySource<?>> comparator) {
612                    // Extract all beans that implement the PropertySource interface
613                    @SuppressWarnings("rawtypes")
614                    Map<String, PropertySource> map = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, PropertySource.class);
615    
616                    // Extract the PropertySource beans into a list
617                    List<PropertySource<?>> list = new ArrayList<PropertySource<?>>();
618                    for (PropertySource<?> source : map.values()) {
619                            list.add(source);
620                    }
621    
622                    // Sort them using the provided comparator
623                    Collections.sort(list, comparator);
624    
625                    // Return the list
626                    return list;
627            }
628    
629            /**
630             * Null safe method for converting an untyped array of property sources into a list. Never returns null.
631             */
632            public static List<PropertySource<?>> asList(PropertySource<?>... sources) {
633                    List<PropertySource<?>> list = new ArrayList<PropertySource<?>>();
634                    if (sources == null) {
635                            return list;
636                    }
637                    for (PropertySource<?> element : sources) {
638                            if (element != null) {
639                                    list.add(element);
640                            }
641                    }
642                    return list;
643            }
644    
645            public static void debug(ApplicationContext ctx) {
646                    logger.debug("------------------------ Spring Context ------------------------------");
647                    logger.debug("Id: [{}]", ctx.getId());
648                    logger.debug("Display Name: [{}]", ctx.getDisplayName());
649                    logger.debug("Application Name: [{}]", ctx.getApplicationName());
650                    logger.debug("----------------------------------------------------------------------");
651                    List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesIncludingAncestors(ctx));
652                    List<String> columns = Arrays.asList("Name", "Type", "Hashcode");
653                    List<Object[]> rows = new ArrayList<Object[]>();
654                    Collections.sort(names);
655                    for (String name : names) {
656                            Object bean = ctx.getBean(name);
657                            String instance = (bean == null) ? Constants.NULL : bean.getClass().getSimpleName();
658                            String hashcode = (bean == null) ? Constants.NULL : Integer.toHexString(bean.hashCode());
659                            Object[] row = { name, instance, hashcode };
660                            rows.add(row);
661                    }
662                    LoggerUtils.logTable(columns, rows, LoggerLevel.DEBUG, logger, true);
663                    logger.debug("----------------------------------------------------------------------");
664            }
665    
666            public static void showPropertySources(List<PropertySource<?>> propertySources) {
667                    List<String> columns = Arrays.asList("Name", "Impl", "Source");
668                    List<Object[]> rows = new ArrayList<Object[]>();
669                    for (PropertySource<?> propertySource : propertySources) {
670                            String name = propertySource.getName();
671                            String impl = propertySource.getClass().getName();
672                            String source = propertySource.getSource().getClass().getName();
673                            Object[] row = { name, impl, source };
674                            rows.add(row);
675                    }
676                    LoggerUtils.logTable(columns, rows, LoggerLevel.INFO, logger, true);
677            }
678    
679            public static void showPropertySources(ConfigurableEnvironment env) {
680                    showPropertySources(getPropertySources(env));
681            }
682    
683            /**
684             * Get a fully resolved property value from the environment. If the property is not found or contains unresolvable placeholders an exception is thrown.
685             */
686            public static String getProperty(Environment env, String key) {
687                    String value = env.getRequiredProperty(key);
688                    return env.resolveRequiredPlaceholders(value);
689            }
690    
691            /**
692             * Return true if the environment value for key is not null.
693             */
694            public static boolean exists(Environment env, String key) {
695                    return env.getProperty(key) != null;
696            }
697    
698            /**
699             * Always return a fully resolved value. Use <code>defaultValue</code> if a value cannot be located in the environment. Throw an exception if the return value contains
700             * unresolvable placeholders.
701             */
702            public static String getProperty(Environment env, String key, String defaultValue) {
703                    if (defaultValue == null) {
704                            // No default value supplied, we must be able to locate this property in the environment
705                            return getProperty(env, key);
706                    } else {
707                            // Look up a value from the environment
708                            String value = env.getProperty(key);
709                            if (value == null) {
710                                    // Resolve the default value against the environment
711                                    return env.resolveRequiredPlaceholders(defaultValue);
712                            } else {
713                                    // Resolve the located value against the environment
714                                    return env.resolveRequiredPlaceholders(value);
715                            }
716                    }
717            }
718    
719            /**
720             * Examine <code>ConfigurableEnvironment</code> for <code>PropertySource</code>'s that extend <code>EnumerablePropertySource</code> and aggregate them into a single
721             * <code>Properties</code> object
722             */
723            public static Properties getAllEnumerableProperties(ConfigurableEnvironment env) {
724    
725                    // Extract the list of PropertySources from the environment
726                    List<PropertySource<?>> sources = getPropertySources(env);
727    
728                    // Spring provides PropertySource objects ordered from highest priority to lowest priority
729                    // We reverse the order here so things follow the typical "last one in wins" strategy
730                    Collections.reverse(sources);
731    
732                    // Convert the list of PropertySource's to a list of Properties objects
733                    PropertySourceConversionResult result = convertEnumerablePropertySources(sources);
734    
735                    // Combine them into a single Properties object
736                    return PropertyUtils.combine(result.getPropertiesList());
737            }
738    
739            /**
740             * Remove any existing property sources and add one property source backed by the properties passed in
741             */
742            public static void reconfigurePropertySources(ConfigurableEnvironment env, String name, Properties properties) {
743                    // Remove all existing property sources
744                    removeAllPropertySources(env);
745    
746                    // MutablePropertySources allow us to manipulate the list of property sources
747                    MutablePropertySources mps = env.getPropertySources();
748    
749                    // Make sure there are no existing property sources
750                    Assert.isTrue(mps.size() == 0);
751    
752                    // Create a property source backed by the properties object passed in
753                    PropertiesPropertySource pps = new PropertiesPropertySource(name, properties);
754    
755                    // Add it to the environment
756                    mps.addFirst(pps);
757            }
758    
759            /**
760             * Remove any existing property sources
761             */
762            public static void removeAllPropertySources(ConfigurableEnvironment env) {
763                    MutablePropertySources mps = env.getPropertySources();
764                    List<PropertySource<?>> sources = getPropertySources(env);
765                    for (PropertySource<?> source : sources) {
766                            String name = source.getName();
767                            mps.remove(name);
768                    }
769            }
770    
771            /**
772             * Get all PropertySource objects from the environment as a List.
773             */
774            public static List<PropertySource<?>> getPropertySources(ConfigurableEnvironment env) {
775                    MutablePropertySources mps = env.getPropertySources();
776                    List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>();
777                    Iterator<PropertySource<?>> itr = mps.iterator();
778                    while (itr.hasNext()) {
779                            PropertySource<?> source = itr.next();
780                            sources.add(source);
781                    }
782                    return sources;
783            }
784    
785            /**
786             * Convert any PropertySources that extend EnumerablePropertySource into Properties object's
787             */
788            public static PropertySourceConversionResult convertEnumerablePropertySources(List<PropertySource<?>> sources) {
789                    PropertySourceConversionResult result = new PropertySourceConversionResult();
790                    List<Properties> list = new ArrayList<Properties>();
791                    List<PropertySource<?>> converted = new ArrayList<PropertySource<?>>();
792                    List<PropertySource<?>> skipped = new ArrayList<PropertySource<?>>();
793                    // Extract property values from the sources and place them in a Properties object
794                    for (PropertySource<?> source : sources) {
795                            logger.debug("Adding [{}]", source.getName());
796                            if (source instanceof EnumerablePropertySource) {
797                                    EnumerablePropertySource<?> eps = (EnumerablePropertySource<?>) source;
798                                    Properties sourceProperties = convert(eps);
799                                    list.add(sourceProperties);
800                                    converted.add(source);
801                            } else {
802                                    logger.debug("Unable to obtain properties from property source [{}] -> [{}]", source.getName(), source.getClass().getName());
803                                    skipped.add(source);
804                            }
805                    }
806                    result.setConverted(converted);
807                    result.setSkipped(skipped);
808                    result.setPropertiesList(list);
809                    return result;
810            }
811    
812            /**
813             * Convert an EnumerablePropertySource into a Properties object.
814             */
815            public static Properties convert(EnumerablePropertySource<?> source) {
816                    Properties properties = new Properties();
817                    String[] names = source.getPropertyNames();
818                    for (String name : names) {
819                            Object object = source.getProperty(name);
820                            if (object != null) {
821                                    String value = object.toString();
822                                    properties.setProperty(name, value);
823                            } else {
824                                    logger.warn("Property [{}] is null", name);
825                            }
826                    }
827                    return properties;
828            }
829    
830            /**
831             * Return true if, and only if, <code>property</code> is set in the environment and evaluates to true.
832             */
833            public static boolean isTrue(Environment env, String property) {
834                    String value = env.getProperty(property);
835                    if (StringUtils.isBlank(value)) {
836                            return false;
837                    } else {
838                            return new Boolean(value);
839                    }
840            }
841    
842    }