View Javadoc

1   /**
2    * Copyright 2010-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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  package org.kuali.common.util.service;
17  
18  import java.io.File;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.kuali.common.util.CollectionUtils;
23  import org.kuali.common.util.LocationUtils;
24  import org.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
27  import org.springframework.context.support.AbstractApplicationContext;
28  import org.springframework.context.support.ClassPathXmlApplicationContext;
29  import org.springframework.util.Assert;
30  
31  public class DefaultSpringService implements SpringService {
32  
33  	private static final Logger logger = LoggerFactory.getLogger(DefaultSpringService.class);
34  
35  	@Override
36  	public void load(String location) {
37  		load(location, (String) null, (Object) null);
38  	}
39  
40  	@Override
41  	public void load(String location, String beanName, Object bean) {
42  		load(location, CollectionUtils.toEmptyList(beanName), CollectionUtils.toEmptyList(bean));
43  	}
44  
45  	@Override
46  	public void load(String location, List<String> beanNames, List<Object> beans) {
47  		load(CollectionUtils.toEmptyList(location), beanNames, beans);
48  	}
49  
50  	@Override
51  	public void load(List<String> locations) {
52  		load(locations, (String) null, (Object) null);
53  	}
54  
55  	@Override
56  	public void load(List<String> locations, String beanName, Object bean) {
57  		load(locations, CollectionUtils.toEmptyList(beanName), CollectionUtils.toEmptyList(bean));
58  	}
59  
60  	@Override
61  	public void load(List<String> locations, List<String> beanNames, List<Object> beans) {
62  		// Make sure we have at least one location to load
63  		Assert.isTrue(locations.size() > 0);
64  
65  		// Null-safe handling for non-required parameters
66  		beanNames = CollectionUtils.toEmptyList(beanNames);
67  		beans = CollectionUtils.toEmptyList(beans);
68  		Assert.isTrue(beanNames.size() == beans.size());
69  
70  		// Make sure all of the locations exist
71  		validate(locations);
72  
73  		// Convert any file names to fully qualified file system URL's
74  		List<String> convertedLocations = getConvertedLocations(locations);
75  
76  		// The Spring classes prefer array's
77  		String[] locationsArray = CollectionUtils.toStringArray(convertedLocations);
78  
79  		AbstractApplicationContext parent = null;
80  		AbstractApplicationContext context = null;
81  		try {
82  			// Get a parent context with any bean's they've provided us pre-registered in the context
83  			// Parent is null if there are no beans to register
84  			parent = getApplicationContext(beanNames, beans);
85  			// Load the locations they provided us, optionally wrapped in a parent context containing pre-registered beans
86  			context = new ClassPathXmlApplicationContext(locationsArray, parent);
87  		} finally {
88  			// cleanup
89  			closeQuietly(context);
90  			closeQuietly(parent);
91  		}
92  	}
93  
94  	/**
95  	 * Null safe close for a context
96  	 */
97  	protected void closeQuietly(AbstractApplicationContext context) {
98  		if (context != null) {
99  			context.close();
100 		}
101 	}
102 
103 	/**
104 	 * Return an <code>AbstractApplicationContext</code> with <code>beans</code> registered in the context under <code>beanNames</code>
105 	 */
106 	protected AbstractApplicationContext getApplicationContext(List<String> beanNames, List<Object> beans) {
107 		if (CollectionUtils.isEmpty(beanNames) && CollectionUtils.isEmpty(beans)) {
108 			return null;
109 		}
110 		Assert.isTrue(beanNames.size() == beans.size());
111 		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
112 		context.refresh();
113 		ConfigurableListableBeanFactory factory = context.getBeanFactory();
114 		for (int i = 0; i < beanNames.size(); i++) {
115 			String beanName = beanNames.get(i);
116 			Object bean = beans.get(i);
117 			logger.info("Registering [{}]", beanName);
118 			factory.registerSingleton(beanName, bean);
119 		}
120 		return context;
121 	}
122 
123 	/**
124 	 * Make sure all of the locations actually exist
125 	 */
126 	protected void validate(List<String> locations) {
127 		StringBuilder sb = new StringBuilder();
128 		for (String location : locations) {
129 			if (!LocationUtils.exists(location)) {
130 				sb.append("Location [" + location + "] does not exist\n");
131 			}
132 		}
133 		if (sb.length() > 0) {
134 			throw new IllegalArgumentException(sb.toString());
135 		}
136 	}
137 
138 	/**
139 	 * Format file names into fully qualified file system URL's
140 	 */
141 	protected List<String> getConvertedLocations(List<String> locations) {
142 		List<String> converted = new ArrayList<String>();
143 		for (String location : locations) {
144 			if (LocationUtils.isExistingFile(location)) {
145 				File file = new File(location);
146 				// ClassPathXmlApplicationContext needs a fully qualified URL, not a filename
147 				String url = LocationUtils.getCanonicalURLString(file);
148 				converted.add(url);
149 			} else {
150 				converted.add(location);
151 			}
152 		}
153 		return converted;
154 	}
155 
156 }