1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.common.util.config.service;
17
18 import java.io.File;
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Properties;
22
23 import org.apache.commons.lang3.StringUtils;
24 import org.kuali.common.util.Assert;
25 import org.kuali.common.util.CollectionUtils;
26 import org.kuali.common.util.JAXBUtil;
27 import org.kuali.common.util.LocationUtils;
28 import org.kuali.common.util.Mode;
29 import org.kuali.common.util.ModeUtils;
30 import org.kuali.common.util.Project;
31 import org.kuali.common.util.ProjectUtils;
32 import org.kuali.common.util.PropertyUtils;
33 import org.kuali.common.util.config.ConfigUtils;
34 import org.kuali.common.util.config.ContextConfig;
35 import org.kuali.common.util.config.Location;
36 import org.kuali.common.util.config.ProjectConfig;
37 import org.kuali.common.util.config.ProjectConfigContainer;
38 import org.kuali.common.util.config.ProjectConfigContainerNullifier;
39 import org.kuali.common.util.nullify.Nullifier;
40 import org.kuali.common.util.property.Constants;
41 import org.kuali.common.util.property.processor.OverrideProcessor;
42 import org.springframework.util.PropertyPlaceholderHelper;
43
44 public abstract class AbstractCachingConfigService implements ConfigService {
45
46 private static final String METAINF = "META-INF";
47 private static final String CLASSPATH = "classpath:";
48 private static final String CLASSPATH_PREFIX_KEY = "classpath.prefix";
49 private static final String CONFIG = "config";
50 private static final String PROPS = "metadata.properties";
51 private static final String DELIMITER = ":";
52 private static final PropertyPlaceholderHelper HELPER = Constants.DEFAULT_PROPERTY_PLACEHOLDER_HELPER;
53
54 @Override
55 public Properties getProperties(String configId) {
56 return getProperties(configId, (Properties) null);
57 }
58
59 @Override
60 public Properties getProperties(List<String> configIds) {
61 return getProperties(configIds, null);
62 }
63
64 @Override
65 public Properties getProperties(String configId, Properties overrides) {
66 return getProperties(CollectionUtils.toEmptyList(configId), overrides);
67 }
68
69 @Override
70 public Properties getProperties(List<String> configIds, Properties overrides) {
71 List<ProjectConfig> requests = ConfigUtils.getProjectConfigs(CollectionUtils.toEmptyList(configIds));
72 return loadProperties(requests, PropertyUtils.toEmpty(overrides));
73 }
74
75 protected abstract ProjectConfigContainer getCachedConfig(String groupId, String artifactId);
76
77 protected abstract void clearCache();
78
79 protected abstract ProjectConfigContainer getProjectConfig(String content, String encoding);
80
81 protected abstract String getFilename();
82
83 protected Properties loadProperties(List<ProjectConfig> requests, Properties overrides) {
84
85 List<Location> locations = getLocations(requests);
86
87 Properties properties = new Properties();
88
89 Properties global = PropertyUtils.getGlobalProperties();
90
91 for (Location location : locations) {
92
93 Properties resolver = PropertyUtils.combine(properties, overrides, global);
94
95 String resolvedLocation = HELPER.replacePlaceholders(location.getValue(), resolver);
96
97 if (LocationUtils.exists(resolvedLocation)) {
98 Properties loaded = PropertyUtils.load(resolvedLocation, location.getEncoding());
99 new OverrideProcessor(Mode.INFORM, loaded, 2).process(properties);
100 } else {
101
102 ModeUtils.validate(location.getMissingMode(), "Non-existent location [" + resolvedLocation + "]");
103 }
104 }
105
106 new OverrideProcessor(Mode.INFORM, overrides, 2).process(properties);
107
108 new OverrideProcessor(Mode.INFORM, global, 2).process(properties);
109
110 PropertyUtils.decrypt(properties);
111
112 PropertyUtils.resolve(properties);
113
114 return properties;
115 }
116
117 protected Properties getBaseFilterProperties() {
118 return new Properties();
119 }
120
121 protected ProjectConfigContainer loadMetadata(String groupId, String artifactId) {
122 Project project = ProjectUtils.loadProject(groupId, artifactId);
123 String location = getMetadataConfigFilePath(project, getFilename());
124
125
126 Assert.exists(location, "[" + location + "] does not exist");
127 Properties properties = getBaseFilterProperties();
128 Properties projectProperties = getFilterProperties(project);
129 properties.putAll(projectProperties);
130 String content = getFilteredContent(location, properties, project.getEncoding());
131 return getProjectConfig(content, project.getEncoding());
132 }
133
134 protected List<Location> getLocations(List<ProjectConfig> configs) {
135 List<Location> locations = new ArrayList<Location>();
136 for (ProjectConfig config : configs) {
137 List<Location> requestLocations = findLocations(config);
138 locations.addAll(requestLocations);
139 }
140 return locations;
141 }
142
143 protected List<Location> findLocations(ProjectConfig request) {
144 ProjectConfigContainer config = getCachedConfig(request.getGroupId(), request.getArtifactId());
145 if (StringUtils.isBlank(request.getContextId())) {
146 return new ArrayList<Location>(CollectionUtils.toEmptyList(config.getLocations()));
147 } else {
148 String[] tokens = StringUtils.split(request.getContextId(), DELIMITER);
149 List<ContextConfig> contexts = config.getContexts();
150 ContextConfig context = null;
151 for (String token : tokens) {
152 context = findContextConfig(contexts, token);
153 contexts = context.getContexts();
154 }
155 return context.getLocations();
156 }
157 }
158
159 protected ContextConfig findContextConfig(List<ContextConfig> contexts, String contextId) {
160 for (ContextConfig context : contexts) {
161 if (StringUtils.equals(contextId, context.getId())) {
162 return context;
163 }
164 }
165 throw new IllegalArgumentException("Unknown contextId [" + contextId + "]");
166 }
167
168 protected String getMetadataConfigFilePath(Project project, String filename) {
169 String resourcePath = ProjectUtils.getResourcePath(project);
170 return CLASSPATH + METAINF + "/" + resourcePath + "/" + CONFIG + "/" + filename;
171 }
172
173 protected String getFilteredContent(String location, Properties properties, String encoding) {
174 PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}", ":", true);
175 String originalContent = LocationUtils.toString(location, encoding);
176 String filteredContent = helper.replacePlaceholders(originalContent, properties);
177 return filteredContent;
178 }
179
180 protected Properties getFilterProperties(Project project) {
181 String classpathPrefix = ProjectUtils.getClassPathPrefix(project);
182 Properties duplicate = PropertyUtils.duplicate(project.getProperties());
183 duplicate.setProperty(CLASSPATH_PREFIX_KEY, classpathPrefix);
184 String location = getMetadataConfigFilePath(project, PROPS);
185 Properties metadata = new Properties();
186 if (LocationUtils.exists(location)) {
187 metadata = PropertyUtils.load(location, project.getEncoding());
188 }
189 duplicate.putAll(metadata);
190 return duplicate;
191 }
192
193 protected void store(File file, ProjectConfigContainer config) {
194
195 Assert.notNull(file, "file is null");
196 Assert.notNull(config, "config is null");
197
198 ProjectConfigContainer clone = new ProjectConfigContainer(config);
199
200 Nullifier nullifier = new ProjectConfigContainerNullifier(clone);
201 nullifier.nullify();
202
203 JAXBUtil.write(clone, file);
204 }
205
206 }