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.config.service; 017 018import java.io.File; 019import java.util.ArrayList; 020import java.util.List; 021import java.util.Properties; 022 023import org.apache.commons.lang3.StringUtils; 024import org.kuali.common.util.Assert; 025import org.kuali.common.util.CollectionUtils; 026import org.kuali.common.util.LocationUtils; 027import org.kuali.common.util.Mode; 028import org.kuali.common.util.ModeUtils; 029import org.kuali.common.util.PropertyUtils; 030import org.kuali.common.util.nullify.Nullifier; 031import org.kuali.common.util.project.ProjectService; 032import org.kuali.common.util.project.ProjectUtils; 033import org.kuali.common.util.project.model.Project; 034import org.kuali.common.util.property.Constants; 035import org.kuali.common.util.property.processor.OverrideProcessor; 036import org.kuali.common.util.xml.service.XmlService; 037import org.springframework.util.PropertyPlaceholderHelper; 038 039/** 040 * @deprecated 041 */ 042@Deprecated 043public abstract class AbstractCachingConfigService implements ConfigService { 044 045 public AbstractCachingConfigService(ProjectService projectService, XmlService xmlService) { 046 Assert.noNulls(projectService, xmlService); 047 this.projectService = projectService; 048 this.xmlService = xmlService; 049 } 050 051 private static final String METAINF = "META-INF"; 052 private static final String CLASSPATH = "classpath:"; 053 private static final String CLASSPATH_PREFIX_KEY = "classpath.prefix"; 054 private static final String CONFIG = "config"; 055 private static final String PROPS = "metadata.properties"; 056 private static final String DELIMITER = ":"; 057 private static final PropertyPlaceholderHelper HELPER = Constants.DEFAULT_PROPERTY_PLACEHOLDER_HELPER; 058 059 private final ProjectService projectService; 060 private final XmlService xmlService; 061 062 @Override 063 public Properties getProperties(String configId) { 064 return getProperties(configId, (Properties) null); 065 } 066 067 @Override 068 public Properties getProperties(List<String> configIds) { 069 return getProperties(configIds, null); 070 } 071 072 @Override 073 public Properties getProperties(String configId, Properties overrides) { 074 return getProperties(CollectionUtils.toEmptyList(configId), overrides); 075 } 076 077 @Override 078 public Properties getProperties(List<String> configIds, Properties overrides) { 079 List<org.kuali.common.util.config.ProjectConfig> requests = org.kuali.common.util.config.ConfigUtils.getProjectConfigs(CollectionUtils.toEmptyList(configIds)); 080 return loadProperties(requests, PropertyUtils.toEmpty(overrides)); 081 } 082 083 protected abstract org.kuali.common.util.config.ProjectConfigContainer getCachedConfig(String groupId, String artifactId); 084 085 protected abstract void clearCache(); 086 087 protected abstract org.kuali.common.util.config.ProjectConfigContainer getProjectConfig(String content, String encoding); 088 089 protected abstract String getFilename(); 090 091 protected Properties loadProperties(List<org.kuali.common.util.config.ProjectConfig> requests, Properties overrides) { 092 // Convert the ConfigRequest objects into Location objects 093 List<org.kuali.common.util.config.Location> locations = getLocations(requests); 094 // Allocate some storage 095 Properties properties = new Properties(); 096 // Get system/environment properties 097 Properties global = PropertyUtils.getGlobalProperties(); 098 // Cycle through our list of locations 099 for (org.kuali.common.util.config.Location location : locations) { 100 // Combine properties we've already loaded with overrides and global properties 101 Properties resolver = PropertyUtils.combine(properties, overrides, global); 102 // Use the combined properties to resolve any placeholders in the location 103 String resolvedLocation = HELPER.replacePlaceholders(location.getValue(), resolver); 104 // If the location exists, load it 105 if (LocationUtils.exists(resolvedLocation)) { 106 Properties loaded = PropertyUtils.load(resolvedLocation, location.getEncoding()); 107 new OverrideProcessor(Mode.INFORM, loaded, 2).process(properties); 108 } else { 109 // Take appropriate action for missing locations (ignore, inform, warn, or error out) 110 ModeUtils.validate(location.getMissingMode(), "Non-existent location [" + resolvedLocation + "]"); 111 } 112 } 113 // Override the loaded properties with overrides properties 114 new OverrideProcessor(Mode.INFORM, overrides, 2).process(properties); 115 // Override everything with system/environment properties 116 new OverrideProcessor(Mode.INFORM, global, 2).process(properties); 117 // Decrypt them 118 PropertyUtils.decrypt(properties); 119 // Resolve them, throwing an exception if any value cannot be fully resolved 120 PropertyUtils.resolve(properties); 121 // Return what we've found 122 return properties; 123 } 124 125 protected Properties getBaseFilterProperties() { 126 return new Properties(); 127 } 128 129 protected org.kuali.common.util.config.ProjectConfigContainer loadMetadata(String groupId, String artifactId) { 130 131 Assert.notNull(projectService, "projectService is null"); 132 133 Project project = projectService.getProject(groupId, artifactId); 134 String location = getMetadataConfigFilePath(project, getFilename()); 135 136 // Throw an exception if they are asking for config metadata that doesn't exist 137 Assert.exists(location, "[" + location + "] does not exist"); 138 Properties properties = getBaseFilterProperties(); 139 Properties projectProperties = getFilterProperties(project); 140 properties.putAll(projectProperties); 141 String encoding = ProjectUtils.getEncoding(project); 142 String content = getFilteredContent(location, properties, encoding); 143 return getProjectConfig(content, encoding); 144 } 145 146 protected List<org.kuali.common.util.config.Location> getLocations(List<org.kuali.common.util.config.ProjectConfig> configs) { 147 List<org.kuali.common.util.config.Location> locations = new ArrayList<org.kuali.common.util.config.Location>(); 148 for (org.kuali.common.util.config.ProjectConfig config : configs) { 149 List<org.kuali.common.util.config.Location> requestLocations = findLocations(config); 150 locations.addAll(requestLocations); 151 } 152 return locations; 153 } 154 155 protected List<org.kuali.common.util.config.Location> findLocations(org.kuali.common.util.config.ProjectConfig request) { 156 org.kuali.common.util.config.ProjectConfigContainer config = getCachedConfig(request.getGroupId(), request.getArtifactId()); 157 if (StringUtils.isBlank(request.getContextId())) { 158 return new ArrayList<org.kuali.common.util.config.Location>(CollectionUtils.toEmptyList(config.getLocations())); 159 } else { 160 String[] tokens = StringUtils.split(request.getContextId(), DELIMITER); 161 List<org.kuali.common.util.config.ContextConfig> contexts = config.getContexts(); 162 org.kuali.common.util.config.ContextConfig context = null; 163 for (String token : tokens) { 164 context = findContextConfig(contexts, token); 165 contexts = context.getContexts(); 166 } 167 return context.getLocations(); 168 } 169 } 170 171 protected org.kuali.common.util.config.ContextConfig findContextConfig(List<org.kuali.common.util.config.ContextConfig> contexts, String contextId) { 172 for (org.kuali.common.util.config.ContextConfig context : contexts) { 173 if (StringUtils.equals(contextId, context.getId())) { 174 return context; 175 } 176 } 177 throw new IllegalArgumentException("Unknown contextId [" + contextId + "]"); 178 } 179 180 protected String getMetadataConfigFilePath(Project project, String filename) { 181 String resourcePath = ProjectUtils.getResourcePath(project.getGroupId(), project.getArtifactId()); 182 return CLASSPATH + METAINF + "/" + resourcePath + "/" + CONFIG + "/" + filename; 183 } 184 185 protected String getFilteredContent(String location, Properties properties, String encoding) { 186 PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}", ":", true); 187 String originalContent = LocationUtils.toString(location, encoding); 188 String filteredContent = helper.replacePlaceholders(originalContent, properties); 189 return filteredContent; 190 } 191 192 protected Properties getFilterProperties(Project project) { 193 String classpathPrefix = ProjectUtils.getClasspathPrefix(project.getGroupId(), project.getArtifactId()); 194 Properties duplicate = PropertyUtils.duplicate(project.getProperties()); 195 duplicate.setProperty(CLASSPATH_PREFIX_KEY, classpathPrefix); 196 String location = getMetadataConfigFilePath(project, PROPS); 197 Properties metadata = new Properties(); 198 if (LocationUtils.exists(location)) { 199 String encoding = ProjectUtils.getEncoding(project); 200 metadata = PropertyUtils.load(location, encoding); 201 } 202 duplicate.putAll(metadata); 203 return duplicate; 204 } 205 206 protected void store(File file, org.kuali.common.util.config.ProjectConfigContainer config) { 207 208 Assert.notNull(file, "file is null"); 209 Assert.notNull(config, "config is null"); 210 211 org.kuali.common.util.config.ProjectConfigContainer clone = new org.kuali.common.util.config.ProjectConfigContainer(config); 212 213 Nullifier nullifier = new org.kuali.common.util.config.ProjectConfigContainerNullifier(); 214 nullifier.nullify(); 215 216 xmlService.write(file, clone); 217 } 218 219 public ProjectService getProjectService() { 220 return projectService; 221 } 222 223 public XmlService getXmlService() { 224 return xmlService; 225 } 226 227}