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