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.service;
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.List;
023
024 import org.apache.commons.lang3.StringUtils;
025 import org.kuali.common.util.Assert;
026 import org.kuali.common.util.CollectionUtils;
027 import org.kuali.common.util.LocationUtils;
028 import org.kuali.common.util.spring.SpringUtils;
029 import org.slf4j.Logger;
030 import org.slf4j.LoggerFactory;
031 import org.springframework.context.ApplicationContext;
032 import org.springframework.context.ConfigurableApplicationContext;
033 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
034 import org.springframework.context.support.ClassPathXmlApplicationContext;
035 import org.springframework.core.env.ConfigurableEnvironment;
036 import org.springframework.core.env.MutablePropertySources;
037 import org.springframework.core.env.PropertySource;
038
039 @Deprecated
040 public class DefaultSpringService implements SpringService {
041
042 private static final Logger logger = LoggerFactory.getLogger(DefaultSpringService.class);
043
044 @Override
045 public void load(Class<?> annotatedClass) {
046 load(annotatedClass, null, null);
047 }
048
049 @Override
050 public void load(Class<?> annotatedClass, String beanName, Object bean, PropertySource<?> propertySource) {
051 // Make sure the annotatedClass isn't null
052 Assert.notNull(annotatedClass, "annotatedClass is null");
053
054 // Setup a SpringContext
055 SpringContext context = new SpringContext();
056 context.setAnnotatedClasses(CollectionUtils.asList(annotatedClass));
057 context.setPropertySourceContext(new PropertySourceContext(SpringUtils.asList(propertySource)));
058
059 // Null safe handling for non-required parameters
060 context.setBeanNames(CollectionUtils.toEmptyList(beanName));
061 context.setBeans(CollectionUtils.toEmptyList(bean));
062
063 // Load the configuration from the annotated class
064 load(context);
065 }
066
067 @Override
068 public void load(Class<?> annotatedClass, String beanName, Object bean) {
069 load(annotatedClass, beanName, bean, null);
070 }
071
072 @Override
073 public void load(String location) {
074 load(location, null, null);
075 }
076
077 @Override
078 public void load(String location, String beanName, Object bean, PropertySource<?> propertySource) {
079 // Make sure the location isn't empty
080 Assert.hasText(location, "location is null");
081
082 // Setup a SpringContext
083 SpringContext context = new SpringContext();
084 context.setLocations(Arrays.asList(location));
085 context.setPropertySourceContext(new PropertySourceContext(SpringUtils.asList(propertySource)));
086
087 // Null safe handling for non-required parameters
088 context.setBeanNames(CollectionUtils.toEmptyList(beanName));
089 context.setBeans(CollectionUtils.toEmptyList(bean));
090
091 // Load the location using a SpringContext
092 load(context);
093 }
094
095 @Override
096 public void load(String location, String beanName, Object bean) {
097 load(location, beanName, bean, null);
098 }
099
100 @Override
101 public void load(SpringContext context) {
102
103 // Null-safe handling for parameters
104 context.setBeanNames(CollectionUtils.toEmptyList(context.getBeanNames()));
105 context.setBeans(CollectionUtils.toEmptyList(context.getBeans()));
106 context.setAnnotatedClasses(CollectionUtils.toEmptyList(context.getAnnotatedClasses()));
107 context.setLocations(CollectionUtils.toEmptyList(context.getLocations()));
108
109 // Make sure we have at least one location or annotated class
110 boolean empty = CollectionUtils.isEmpty(context.getLocations()) && CollectionUtils.isEmpty(context.getAnnotatedClasses());
111 Assert.isFalse(empty, "Both locations and annotatedClasses are empty");
112
113 // Make sure we have a name for every bean
114 Assert.isTrue(context.getBeanNames().size() == context.getBeans().size());
115
116 // Make sure all of the locations exist
117 SpringUtils.validateExists(context.getLocations());
118
119 // Convert any file names to fully qualified file system URL's
120 List<String> convertedLocations = getConvertedLocations(context.getLocations());
121
122 // The Spring classes prefer array's
123 String[] locationsArray = CollectionUtils.toStringArray(convertedLocations);
124
125 ConfigurableApplicationContext parent = null;
126 ClassPathXmlApplicationContext xmlChild = null;
127 AnnotationConfigApplicationContext annotationChild = null;
128 try {
129 if (isParentContextRequired(context)) {
130 // Construct a parent context if necessary
131 parent = SpringUtils.getContextWithPreRegisteredBeans(context.getId(), context.getDisplayName(), context.getBeanNames(), context.getBeans());
132 }
133
134 if (!CollectionUtils.isEmpty(context.getAnnotatedClasses())) {
135 // Create an annotation based application context wrapped in a parent context
136 annotationChild = getAnnotationContext(context, parent);
137 // Add custom property sources (if any)
138 addPropertySources(context, annotationChild);
139
140 }
141
142 if (!CollectionUtils.isEmpty(context.getLocations())) {
143 // Create an XML application context wrapped in a parent context
144 xmlChild = new ClassPathXmlApplicationContext(locationsArray, false, parent);
145 if (parent == null) {
146 addMetaInfo(xmlChild, context);
147 }
148 // Add custom property sources (if any)
149 addPropertySources(context, xmlChild);
150 }
151
152 // Invoke refresh to load the context
153 SpringUtils.refreshQuietly(annotationChild);
154 SpringUtils.refreshQuietly(xmlChild);
155 debugQuietly(parent, annotationChild, xmlChild);
156 } finally {
157 // cleanup
158 // closeQuietly(annotationChild);
159 // closeQuietly(xmlChild);
160 // closeQuietly(parent);
161 }
162 }
163
164 protected void debugQuietly(ApplicationContext parent, ApplicationContext child1, ApplicationContext child2) {
165 if (!logger.isDebugEnabled()) {
166 return;
167 }
168 if (parent != null) {
169 SpringUtils.debug(parent);
170 } else {
171 if (child1 != null) {
172 SpringUtils.debug(child1);
173 }
174 if (child2 != null) {
175 SpringUtils.debug(child2);
176 }
177 }
178 }
179
180 /**
181 * Add id and display name to the ApplicationContext if they are not blank
182 */
183 protected void addMetaInfo(AnnotationConfigApplicationContext ctx, SpringContext sc) {
184 if (!StringUtils.isBlank(sc.getId())) {
185 ctx.setId(sc.getId());
186 }
187 if (!StringUtils.isBlank(sc.getDisplayName())) {
188 ctx.setDisplayName(sc.getDisplayName());
189 }
190 }
191
192 /**
193 * Add id and display name to the ApplicationContext if they are not blank
194 */
195 protected void addMetaInfo(ClassPathXmlApplicationContext ctx, SpringContext sc) {
196 if (!StringUtils.isBlank(sc.getId())) {
197 ctx.setId(sc.getId());
198 }
199 if (!StringUtils.isBlank(sc.getDisplayName())) {
200 ctx.setDisplayName(sc.getDisplayName());
201 }
202 }
203
204 protected AnnotationConfigApplicationContext getAnnotationContext(SpringContext context, ConfigurableApplicationContext parent) {
205 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
206 if (parent != null) {
207 ctx.setParent(parent);
208 } else {
209 addMetaInfo(ctx, context);
210 }
211 for (Class<?> annotatedClass : context.getAnnotatedClasses()) {
212 ctx.register(annotatedClass);
213 }
214 return ctx;
215 }
216
217 protected void addPropertySources(SpringContext context, ConfigurableApplicationContext applicationContext) {
218 PropertySourceContext psc = context.getPropertySourceContext();
219 ConfigurableEnvironment env = applicationContext.getEnvironment();
220 if (psc.isRemoveExistingSources()) {
221 logger.debug("Removing all existing property sources");
222 SpringUtils.removeAllPropertySources(env);
223 }
224
225 if (CollectionUtils.isEmpty(psc.getSources())) {
226 return;
227 }
228 List<PropertySource<?>> propertySources = psc.getSources();
229 MutablePropertySources sources = env.getPropertySources();
230 if (psc.isLastOneInWins()) {
231 Collections.reverse(propertySources);
232 }
233 PropertySourceAddPriority priority = psc.getPriority();
234 for (PropertySource<?> propertySource : propertySources) {
235 Object[] args = { propertySource.getName(), propertySource.getClass().getName(), priority };
236 logger.debug("Adding property source - [{}] -> [{}] Priority=[{}]", args);
237 switch (priority) {
238 case FIRST:
239 sources.addFirst(propertySource);
240 break;
241 case LAST:
242 sources.addLast(propertySource);
243 break;
244 default:
245 throw new IllegalStateException(priority + " is an unknown priority");
246 }
247 }
248 }
249
250 /**
251 * Return true if the context contains any beans or beanNames, false otherwise.
252 */
253 protected boolean isParentContextRequired(SpringContext context) {
254 if (!CollectionUtils.isEmpty(context.getBeanNames())) {
255 return true;
256 } else if (!CollectionUtils.isEmpty(context.getBeans())) {
257 return true;
258 } else {
259 return false;
260 }
261 }
262
263 /**
264 * Convert any locations representing an existing file into a fully qualified file system url. Leave any locations that do not resolve to an existing file alone.
265 */
266 protected List<String> getConvertedLocations(List<String> locations) {
267 List<String> converted = new ArrayList<String>();
268 for (String location : locations) {
269 if (LocationUtils.isExistingFile(location)) {
270 File file = new File(location);
271 // ClassPathXmlApplicationContext needs a fully qualified URL, not a filename
272 String url = LocationUtils.getCanonicalURLString(file);
273 converted.add(url);
274 } else {
275 converted.add(location);
276 }
277 }
278 return converted;
279 }
280
281 }