001    /**
002     * Copyright 2010 The Kuali Foundation Licensed under the
003     * Educational Community License, Version 2.0 (the "License"); you may
004     * not use this file except in compliance with the License. You may
005     * obtain a copy of the License at
006     *
007     * http://www.osedu.org/licenses/ECL-2.0
008     *
009     * Unless required by applicable law or agreed to in writing,
010     * software distributed under the License is distributed on an "AS IS"
011     * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
012     * or implied. See the License for the specific language governing
013     * permissions and limitations under the License.
014     */
015    
016    package org.kuali.student.common.util;
017    
018    import java.util.HashSet;
019    import java.util.Properties;
020    
021    import org.springframework.beans.BeansException;
022    import org.springframework.beans.factory.BeanDefinitionStoreException;
023    import org.springframework.beans.factory.BeanFactory;
024    import org.springframework.beans.factory.InitializingBean;
025    import org.springframework.beans.factory.config.BeanDefinition;
026    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
027    import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
028    import org.springframework.core.io.DefaultResourceLoader;
029    import org.springframework.core.io.Resource;
030    import org.springframework.util.StringValueResolver;
031    
032    public class ModPropertyPlaceholderConfigurer extends
033                    PropertyPlaceholderConfigurer implements InitializingBean  {
034            
035            private String customConfigSystemProperty;
036            private String customConfigFileLocation;
037            private Resource[] locations;   
038            
039            private String beanName;
040            private BeanFactory beanFactory;
041            private String nullValue;
042            
043            
044            public String getCustomConfigSystemProperty() {
045                    return customConfigSystemProperty;
046            }
047    
048            public void setCustomConfigSystemProperty(String customConfigSystemProperty) {
049                    this.customConfigSystemProperty = customConfigSystemProperty;
050            }
051    
052            @Override
053            public void setLocations(Resource[] locations) {
054                    this.locations=locations;
055                    super.setLocations(locations);
056                    
057            }
058    
059            @Override
060            public void afterPropertiesSet() throws Exception {
061                    if(customConfigSystemProperty!=null){
062                            String customConfigLocation = System.getProperty(customConfigSystemProperty);
063                            try{
064                                    customConfigLocation = this.parseStringValue(customConfigLocation, System.getProperties(), new HashSet<String>());
065    
066                                    Resource customConfigResource = new DefaultResourceLoader().getResource(customConfigLocation);
067                                    if(customConfigResource.exists()){
068                                            Resource[] finalLocations = new Resource[locations.length+1];
069                                            int i=0;
070                                            for(Resource resource:locations){
071                                                    finalLocations[i]=resource;
072                                                    i++;
073                                            }
074                                            finalLocations[i]=customConfigResource;
075                                            
076                                            super.setLocations(finalLocations);
077                                    }else{
078                                            logger.warn("File does not exist:"+customConfigLocation);
079                                    }
080                            }catch(Exception e){
081                                    logger.warn("Could not load custom properties from property:"+customConfigSystemProperty+" location:"+customConfigLocation);
082                            }
083                    }
084                    if(customConfigFileLocation!=null){
085                            String location = this.parseStringValue(customConfigFileLocation, System.getProperties(), new HashSet<String>());
086                            try{
087                                    Resource customConfigResource = new DefaultResourceLoader().getResource(location);
088                    
089                                    if(customConfigResource.exists()){
090                                            Resource[] finalLocations = new Resource[locations.length+1];
091                                            int i=0;
092                                            for(Resource resource:locations){
093                                                    finalLocations[i] = resource;
094                                                    i++;
095                                            }
096                                            finalLocations[i] = customConfigResource;
097                                            
098                                            super.setLocations(finalLocations);
099                                    }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    }