View Javadoc
1   /**
2    * Copyright 2005-2014 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.rice.xml.ingest;
17  
18  import java.io.IOException;
19  import java.util.Properties;
20  import java.util.SortedSet;
21  
22  import javax.servlet.ServletContext;
23  
24  import org.kuali.common.util.PropertyUtils;
25  import org.kuali.common.util.Str;
26  import org.kuali.common.util.log.LoggerUtils;
27  import org.kuali.common.util.property.ImmutableProperties;
28  import org.kuali.rice.core.api.config.property.Config;
29  import org.kuali.rice.core.api.config.property.ConfigContext;
30  import org.kuali.rice.core.impl.config.property.ConfigLogger;
31  import org.kuali.rice.core.impl.config.property.JAXBConfigImpl;
32  import org.kuali.rice.core.web.util.PropertySources;
33  import org.slf4j.Logger;
34  
35  import com.google.common.base.Preconditions;
36  import com.google.common.collect.Sets;
37  
38  /**
39   * Utility class to handle {@link PropertySources} and Rice config files.
40   * 
41   * @author Kuali Rice Team (rice.collab@kuali.org)
42   */
43  public class RiceConfigUtils {
44  
45  	private static final Logger logger = LoggerUtils.make();
46  
47  	public static Config getRootConfig(Properties loaded, String location, ServletContext servletContext) {
48  		// Get the Rice config object the listener created
49  		Config config = ConfigContext.getCurrentContextConfig();
50  		Preconditions.checkNotNull(config, "'config' cannot be null");
51  		Properties listenerProperties = getProperties(config);
52  
53  		// Parse config from the location indicated, using listener properties in the process of doing so
54  		JAXBConfigImpl parsed = parseConfig(location, listenerProperties);
55  
56  		// Add and override loaded properties with parsed properties
57  		addAndOverride(loaded, parsed.getRawProperties());
58  
59  		// Priority is servlet -> env -> system
60  		// Override anything we've loaded with servlet, env, and system properties
61  		Properties servlet = PropertySources.convert(servletContext);
62  		Properties global = PropertyUtils.getGlobalProperties(servlet);
63  		addAndOverride(loaded, global);
64  		logger.info("Using {} distinct properties", loaded.size());
65  
66  		// Use JAXBConfigImpl in order to perform Rice's custom placeholder resolution logic now that everything is loaded
67  		return new JAXBConfigImpl(loaded);
68  
69  	}
70  
71  	/**
72  	 * Iterate over the list of key/value pairs from {@code properties} and invoke {@code config.putProperty(key,value)}
73  	 */
74  	public static void putProperties(Config config, Properties properties) {
75  		SortedSet<String> keys = Sets.newTreeSet(properties.stringPropertyNames());
76  		for (String key : keys) {
77  			config.putProperty(key, properties.getProperty(key));
78  		}
79  	}
80  
81  	/**
82  	 * Parse the configuration stored at {@code location}
83  	 */
84  	public static JAXBConfigImpl parseConfig(String location) {
85  		return parseConfig(location, ImmutableProperties.of());
86  	}
87  
88  	/**
89  	 * Parse the configuration stored at {@code location}
90  	 */
91  	public static JAXBConfigImpl parseConfig(String location, Properties properties) {
92  		try {
93  			JAXBConfigImpl config = new JAXBConfigImpl(location, properties);
94  			config.parseConfig();
95  			return config;
96  		} catch (IOException e) {
97  			throw new IllegalStateException("Unexpected error parsing config", e);
98  		}
99  	}
100 
101 	/**
102 	 * Parse the configuration stored at {@code location} AND invoke {@code ConfigContext.init(config)}
103 	 */
104 	public static JAXBConfigImpl parseAndInit(String location) {
105 		JAXBConfigImpl config = parseConfig(location);
106 		ConfigContext.init(config);
107 		return config;
108 	}
109 
110 	public static Properties getProperties(Config config) {
111 		if (config instanceof JAXBConfigImpl) {
112 			JAXBConfigImpl jci = (JAXBConfigImpl) config;
113 			return jci.getRawProperties();
114 		} else {
115 			logger.warn("Unable to access raw Rice config properties.");
116 			return config.getProperties();
117 		}
118 	}
119 
120 	public static void addAndOverride(Properties oldProps, Properties newProps) {
121 		add(oldProps, newProps);
122 		override(oldProps, newProps);
123 	}
124 
125 	public static void override(Properties oldProps, Properties newProps) {
126 		SortedSet<String> commonKeys = Sets.newTreeSet(Sets.intersection(newProps.stringPropertyNames(), oldProps.stringPropertyNames()));
127 		if (commonKeys.size() == 0) {
128 			return;
129 		}
130 		logger.debug("{} keys in common", commonKeys.size());
131 		for (String commonKey : commonKeys) {
132 			String oldValue = oldProps.getProperty(commonKey);
133 			String newValue = newProps.getProperty(commonKey);
134 			if (!newValue.equals(oldValue)) {
135 				Object[] args = { commonKey, toLogMsg(commonKey, oldValue), toLogMsg(commonKey, newValue) };
136 				logger.info("Overriding - [{}]=[{}]->[{}]", args);
137 				oldProps.setProperty(commonKey, newValue);
138 			}
139 		}
140 	}
141 
142 	public static void add(Properties oldProps, Properties newProps) {
143 		SortedSet<String> newKeys = Sets.newTreeSet(Sets.difference(newProps.stringPropertyNames(), oldProps.stringPropertyNames()));
144 		if (newKeys.size() == 0) {
145 			return;
146 		}
147 		logger.info("Adding {} properties", newKeys.size());
148 		for (String newKey : newKeys) {
149 			String value = newProps.getProperty(newKey);
150 			logger.debug("Adding - [{}]=[{}]", newKey, toLogMsg(newKey, value));
151 			oldProps.setProperty(newKey, value);
152 		}
153 	}
154 
155 	protected static String toLogMsg(String key, String value) {
156 		return Str.flatten(ConfigLogger.getDisplaySafeValue(key, value));
157 	}
158 }