001 /**
002 * Copyright 2010-2013 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 */
016 package org.kuali.common.util;
017
018 import java.util.ArrayList;
019 import java.util.Arrays;
020 import java.util.HashMap;
021 import java.util.List;
022 import java.util.Map;
023 import java.util.Properties;
024 import java.util.Set;
025
026 import org.apache.commons.lang3.StringUtils;
027 import org.kuali.common.util.property.Constants;
028 import org.kuali.common.util.property.ProjectProperties;
029 import org.kuali.common.util.property.PropertiesContext;
030 import org.slf4j.Logger;
031 import org.slf4j.LoggerFactory;
032 import org.springframework.util.PropertyPlaceholderHelper;
033
034 /**
035 *
036 */
037 public class ProjectUtils {
038
039 private static final Logger logger = LoggerFactory.getLogger(ProjectUtils.class);
040 private static final PropertyPlaceholderHelper PPH = Constants.DEFAULT_PROPERTY_PLACEHOLDER_HELPER;
041
042 public static final String KUALI_COMMON_GROUP_ID = "org.kuali.common";
043
044 private static final Map<String, Properties> PROJECT_PROPERTIES_CACHE = new HashMap<String, Properties>();
045
046 /**
047 *
048 */
049 public static ProjectProperties loadProjectProperties(ProjectContext context) {
050
051 // Get a project object based on the context information
052 Project project = loadProject(context);
053
054 // Create a properties context object from the project.properties file from META-INF
055 PropertiesContext propertiesContext = new PropertiesContext(project.getProperties());
056 propertiesContext.setEncoding(project.getEncoding());
057 propertiesContext.setLocations(context.getPropertyLocations());
058
059 // Return a project properties object
060 return new ProjectProperties(project, propertiesContext);
061 }
062
063 /**
064 * Create a <code>Project</code> object from the <code>context</code>. This includes loading the corresponding <code>project.properties</code> file from disk.
065 */
066 public static Project loadProject(ProjectContext context) {
067 return loadProject(getGav(context));
068 }
069
070 public static String getGav(ProjectContext context) {
071 return getGav(context.getGroupId(), context.getArtifactId());
072 }
073
074 public static String getGav(Project project) {
075 return getGav(project.getGroupId(), project.getArtifactId());
076 }
077
078 public static String getGav(String groupId, String artifactId) {
079 return groupId + ":" + artifactId;
080 }
081
082 /**
083 * Create a <code>Project</code> object from the <code>gav</code>. This includes loading the corresponding <code>project.properties</code> file from disk.
084 */
085 public static Project loadProject(String gav) {
086 // Convert the gav into a Project
087 Project project = getProject(gav);
088
089 // Load properties from a .properties file for this project
090 Properties properties = loadProperties(project);
091
092 // Return a fully configured project object based on the properties
093 return getProject(properties);
094 }
095
096 /**
097 * Provide a way to clear the cache
098 */
099 public synchronized static void clearProjectPropertiesCache() {
100 PROJECT_PROPERTIES_CACHE.clear();
101 }
102
103 /**
104 * Create a skeleton <code>Project</code> object from the <code>gav</code>. Nothing but the GAV info gets filled in. Does not read <code>project.properties</code> from disk.
105 */
106 public static Project getProject(String gav) {
107 logger.debug("Processing [{}]", gav);
108 String[] tokens = StringUtils.split(gav, ":");
109
110 Project project = new Project();
111 if (tokens.length > 0) {
112 project.setGroupId(RepositoryUtils.toNull(tokens[0]));
113 }
114 if (tokens.length > 1) {
115 project.setArtifactId(RepositoryUtils.toNull(tokens[1]));
116 }
117 if (tokens.length > 2) {
118 project.setPackaging(RepositoryUtils.toNull(tokens[2]));
119 }
120 if (tokens.length > 3) {
121 project.setVersion(RepositoryUtils.toNull(tokens[3]));
122 }
123 if (tokens.length > 4) {
124 project.setClassifier(RepositoryUtils.toNull(tokens[4]));
125 }
126 return project;
127 }
128
129 public static List<Dependency> getDependencies(String csv) {
130 List<String> tokens = CollectionUtils.getTrimmedListFromCSV(csv);
131 List<Dependency> dependencies = new ArrayList<Dependency>();
132 for (String token : tokens) {
133 Dependency dependency = RepositoryUtils.parseDependency(token);
134 dependencies.add(dependency);
135 }
136 return dependencies;
137 }
138
139 /**
140 * Return a <code>Project</code> object by copying values from the <code>properties</code> object into a <code>Project</code> object.
141 */
142 public static Project getProject(Properties properties) {
143 List<String> skipKeys = Arrays.asList("project.dependencies");
144 String startsWith = "project.";
145 List<String> keys = PropertyUtils.getStartsWithKeys(properties, startsWith);
146 Project project = new Project();
147 project.setProperties(properties);
148 Map<String, Object> description = ReflectionUtils.describe(project);
149 Set<String> beanProperties = description.keySet();
150 for (String key : keys) {
151 if (skipKeys.contains(key)) {
152 continue;
153 }
154 String value = properties.getProperty(key);
155 String beanProperty = getBeanProperty(key, startsWith);
156 if (beanProperties.contains(beanProperty)) {
157 ReflectionUtils.copyProperty(project, beanProperty, value);
158 }
159 }
160 String csv = RepositoryUtils.toNull(properties.getProperty("project.dependencies"));
161 List<Dependency> dependencies = getDependencies(csv);
162 project.setDependencies(dependencies);
163 return project;
164 }
165
166 protected static String getBeanProperty(String key, String startsWith) {
167 String s = StringUtils.substring(key, startsWith.length());
168 String[] tokens = StringUtils.split(s, ".");
169 StringBuilder sb = new StringBuilder();
170 for (int i = 0; i < tokens.length; i++) {
171 String token = tokens[i];
172 if (i == 0) {
173 sb.append(token);
174 } else {
175 sb.append(StringUtils.capitalize(token));
176 }
177 }
178 return sb.toString();
179 }
180
181 public static Properties loadProperties(String gav) {
182 return loadProperties(getProject(gav));
183 }
184
185 public static synchronized Properties loadProperties(Project project) {
186 String gav = getGav(project.getGroupId(), project.getArtifactId());
187 Properties properties = PROJECT_PROPERTIES_CACHE.get(gav);
188 if (properties != null) {
189 return properties;
190 } else {
191 return loadAndCache(project, gav);
192 }
193 }
194
195 protected static Properties loadAndCache(Project project, String gav) {
196 String location = getPropertiesFileLocation(project);
197 if (!LocationUtils.exists(location)) {
198 throw new IllegalArgumentException("[" + location + "] does not exist");
199 }
200 Properties properties = PropertyUtils.load(location);
201 PROJECT_PROPERTIES_CACHE.put(gav, properties);
202 return properties;
203 }
204
205 public static String getPropertiesFileLocation(Project project) {
206 Assert.hasText(project.getGroupId(), "groupId has no text");
207 Assert.hasText(project.getArtifactId(), "artifactId has no text");
208
209 Properties properties = new Properties();
210 properties.setProperty("project.groupId.path", Str.getPath(project.getGroupId()));
211 properties.setProperty("project.artifactId", project.getArtifactId());
212
213 return PPH.replacePlaceholders(Constants.PROJECT_PROPERTIES_LOCATION, properties);
214 }
215
216 }