View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.common.util;
17  
18  import java.util.HashSet;
19  import java.util.Properties;
20  
21  import org.springframework.beans.BeansException;
22  import org.springframework.beans.factory.BeanDefinitionStoreException;
23  import org.springframework.beans.factory.BeanFactory;
24  import org.springframework.beans.factory.InitializingBean;
25  import org.springframework.beans.factory.config.BeanDefinition;
26  import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
27  import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
28  import org.springframework.core.io.DefaultResourceLoader;
29  import org.springframework.core.io.Resource;
30  import org.springframework.util.StringValueResolver;
31  
32  public class ModPropertyPlaceholderConfigurer extends
33  		PropertyPlaceholderConfigurer implements InitializingBean  {
34  	
35  	private String customConfigSystemProperty;
36  	private String customConfigFileLocation;
37  	private Resource[] locations;	
38  	
39  	private String beanName;
40  	private BeanFactory beanFactory;
41  	private String nullValue;
42  	
43  	
44  	public String getCustomConfigSystemProperty() {
45  		return customConfigSystemProperty;
46  	}
47  
48  	public void setCustomConfigSystemProperty(String customConfigSystemProperty) {
49  		this.customConfigSystemProperty = customConfigSystemProperty;
50  	}
51  
52  	@Override
53  	public void setLocations(Resource[] locations) {
54  		this.locations=locations;
55  		super.setLocations(locations);
56  		
57  	}
58  
59  	@Override
60  	public void afterPropertiesSet() throws Exception {
61  		if(customConfigSystemProperty!=null){
62  			String customConfigLocation = System.getProperty(customConfigSystemProperty);
63  			try{
64  				customConfigLocation = this.parseStringValue(customConfigLocation, System.getProperties(), new HashSet<String>());
65  
66  				Resource customConfigResource = new DefaultResourceLoader().getResource(customConfigLocation);
67  				if(customConfigResource.exists()){
68  					Resource[] finalLocations = new Resource[locations.length+1];
69  					int i=0;
70  					for(Resource resource:locations){
71  						finalLocations[i]=resource;
72  						i++;
73  					}
74  					finalLocations[i]=customConfigResource;
75  					
76  					super.setLocations(finalLocations);
77  				}else{
78  					logger.warn("File does not exist:"+customConfigLocation);
79  				}
80  			}catch(Exception e){
81  				logger.warn("Could not load custom properties from property:"+customConfigSystemProperty+" location:"+customConfigLocation);
82  			}
83  		}
84  		if(customConfigFileLocation!=null){
85  			String location = this.parseStringValue(customConfigFileLocation, System.getProperties(), new HashSet<String>());
86  			try{
87  				Resource customConfigResource = new DefaultResourceLoader().getResource(location);
88  		
89  				if(customConfigResource.exists()){
90  					Resource[] finalLocations = new Resource[locations.length+1];
91  					int i=0;
92  					for(Resource resource:locations){
93  						finalLocations[i] = resource;
94  						i++;
95  					}
96  					finalLocations[i] = customConfigResource;
97  					
98  					super.setLocations(finalLocations);
99  				}else{
100 					logger.warn("File does not exist:"+location);
101 				}
102 			}catch(Exception e){
103 				logger.warn("Could not load custom properties from file:"+location);
104 			}
105 		}
106 	}
107 
108 	@Override
109 	public void setBeanName(String beanName) {
110 		this.beanName = beanName;
111 		super.setBeanName(beanName);
112 	}
113 
114 	@Override
115 	public void setBeanFactory(BeanFactory beanFactory) {
116 		this.beanFactory = beanFactory;
117 		super.setBeanFactory(beanFactory);
118 	}
119 	
120 	@Override
121 	public void setNullValue(String nullValue) {
122 		this.nullValue = nullValue;
123 		super.setNullValue(nullValue);
124 	}
125 	
126 	@Override
127 	protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
128 			throws BeansException {
129 
130 		StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
131 		ModBeanDefinitionVisitor visitor = new ModBeanDefinitionVisitor(valueResolver);
132 		
133 		String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
134 		for (int i = 0; i < beanNames.length; i++) {
135 			// Check that we're not parsing our own bean definition,
136 			// to avoid failing on unresolvable placeholders in properties file locations.
137 			if (!(beanNames[i].equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
138 				BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(beanNames[i]);
139 				try {
140 					visitor.visitBeanDefinition(bd);
141 				}
142 				catch (BeanDefinitionStoreException ex) {
143 					throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanNames[i], ex.getMessage());
144 				}
145 			}
146 		}
147 		
148 		// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
149 		beanFactoryToProcess.resolveAliases(valueResolver);
150 	}
151 	
152 	/**
153 	 * BeanDefinitionVisitor that resolves placeholders in String values,
154 	 * delegating to the <code>parseStringValue</code> method of the
155 	 * containing class.
156 	 */
157 	public class PlaceholderResolvingStringValueResolver implements StringValueResolver {
158 
159 		private final Properties props;
160 
161 		public PlaceholderResolvingStringValueResolver(Properties props) {
162 			this.props = props;
163 		}
164 
165 		public String resolveStringValue(String strVal) throws BeansException {
166 			String value = parseStringValue(strVal, this.props, new HashSet<String>());
167 			return (value.equals(nullValue) ? null : value);
168 		}
169 		
170 		public Properties resolvePropertyValue(String strVal){
171 			Properties prefixedProps = new Properties();
172 			
173 			for(Object key:props.keySet()){
174 				String keyStr = (String)key; 
175 				if(keyStr.startsWith(strVal)){
176 					String newKeyStr = keyStr.substring(strVal.length()+1);
177 					prefixedProps.put(newKeyStr, resolveStringValue((String)props.get(key)));
178 				}
179 			}
180 			
181 			return prefixedProps;
182 		}
183 		
184 	}
185 
186 	public String getCustomConfigFileLocation() {
187 		return customConfigFileLocation;
188 	}
189 
190 	public void setCustomConfigFileLocation(String customConfigFileLocation) {
191 		this.customConfigFileLocation = customConfigFileLocation;
192 	}
193 }