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}