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.maven;
017
018 import java.io.File;
019 import java.util.ArrayList;
020 import java.util.List;
021
022 import org.apache.commons.io.FileUtils;
023 import org.apache.commons.lang3.StringUtils;
024 import org.kuali.common.util.Assert;
025 import org.kuali.common.util.LocationUtils;
026 import org.kuali.common.util.Str;
027 import org.kuali.common.util.maven.model.Artifact;
028 import org.kuali.common.util.maven.model.Dependency;
029 import org.kuali.common.util.nullify.NullUtils;
030
031 public class RepositoryUtils {
032
033 private static final String FS = File.separator;
034 private static final String GAV_DELIMITER = ":";
035 private static final String DEFAULT_MAVEN_REPO_PATH = ".m2" + FS + "repository";
036
037 public static File getDefaultLocalRepository() {
038 return new File(FileUtils.getUserDirectoryPath() + FS + DEFAULT_MAVEN_REPO_PATH);
039 }
040
041 /**
042 * Copy an artifact from <code>repository</code> into a local repository.
043 */
044 public static final void copyArtifactToDirectory(String repository, Artifact artifact, File localRepository) {
045 String filename = getFilename(artifact);
046 File file = new File(localRepository, filename);
047 copyArtifactToFile(repository, artifact, file);
048 }
049
050 /**
051 * Copy an artifact from <code>repository</code> to a specific file on the local file system.
052 */
053 public static final void copyArtifactToFile(String repository, Artifact artifact, File file) {
054 String location = repository + getRepositoryPath(artifact);
055 LocationUtils.copyLocationToFile(location, file);
056 }
057
058 /**
059 * <p>
060 * Order is <code>groupId:artifactId:version:classifier:type</code>. The ordering here matches the order Maven uses to create actual files. Which is different from what the
061 * toString() method on Maven's Artifact object produces.
062 * </p>
063 *
064 * <p>
065 * Trailing <code>:</code>'s are omitted.
066 * </p>
067 *
068 * <p>
069 * If every field is left blank, <code>::::</code> is returned.
070 * </p>
071 *
072 * <pre>
073 * org.kuali.common:kuali-jdbc:1.0.0:webapp:jar - groupId + artifactId + version + classifier + type
074 * org.kuali.common:kuali-jdbc:1.0.0::jar - no classifier
075 * :::: - Every field is blank
076 * org.kuali.common - groupId only
077 * ::::jar - type only
078 * :kuali-jdbc:::jar - no groupId, version, classifier, or type
079 * org.kuali.common:kuali-jdbc - groupId + artifactId
080 * org.kuali.common:kuali-jdbc:1.0.0 - groupId + artifactId + version
081 * org.kuali.common:kuali-jdbc:1.0.0:webapp - no type
082 * org.kuali.common:kuali-jdbc:1.0.0 - no classifier or type
083 * org.kuali.common:kuali-jdbc::webapp:jar - no version
084 * </pre>
085 */
086 public static final String toString(Artifact artifact) {
087 List<String> tokens = new ArrayList<String>();
088 tokens.add(toEmpty(artifact.getGroupId()));
089 tokens.add(toEmpty(artifact.getArtifactId()));
090 tokens.add(toEmpty(artifact.getVersion()));
091 tokens.add(toEmpty(artifact.getClassifier().orNull()));
092 tokens.add(toEmpty(artifact.getType()));
093 int delimiterCount = getDelimiterCount(tokens);
094 return getDelimitedString(tokens, delimiterCount, GAV_DELIMITER);
095 }
096
097 /**
098 * <p>
099 * Order is <code>groupId:artifactId:version:classifier:type:scope</code>. The ordering here matches the order Maven uses to create actual files. As opposed to what the
100 * toString() method on Maven's Dependency object produces.
101 * </p>
102 *
103 * <p>
104 * Trailing <code>:</code>'s are omitted.
105 * </p>
106 *
107 * <p>
108 * If every field is left blank, <code>:::::</code> is returned.
109 * </p>
110 *
111 * <pre>
112 * org.kuali.common:kuali-jdbc:1.0.0:webapp:jar:compile - groupId + artifactId + version + classifier + type + scope
113 * org.kuali.common:kuali-jdbc:1.0.0::jar:compile - no classifier
114 * org.kuali.common:kuali-jdbc:1.0.0:webapp:jar: - no scope
115 * ::::: - Every field is blank
116 * org.kuali.common - groupId only
117 * :::::compile - scope only
118 * :kuali-jdbc:::jar - artifactId + type
119 * org.kuali.common:kuali-jdbc - groupId + artifactId
120 * org.kuali.common:kuali-jdbc:1.0.0 - groupId + artifactId + version
121 * org.kuali.common:kuali-jdbc:1.0.0:webapp - groupId + artifactId + version + classifier
122 * org.kuali.common:kuali-jdbc:1.0.0:::compile - no classifier or type
123 * org.kuali.common:kuali-jdbc::webapp:jar:compile - no version
124 * </pre>
125 */
126 public static final String toString(Dependency dependency) {
127 List<String> tokens = new ArrayList<String>();
128 tokens.add(toEmpty(dependency.getGroupId()));
129 tokens.add(toEmpty(dependency.getArtifactId()));
130 tokens.add(toEmpty(dependency.getVersion()));
131 tokens.add(toEmpty(dependency.getClassifier().orNull()));
132 tokens.add(toEmpty(dependency.getType()));
133 tokens.add(toEmpty(dependency.getScope()));
134 int delimiterCount = getDelimiterCount(tokens);
135 return getDelimitedString(tokens, delimiterCount, GAV_DELIMITER);
136 }
137
138 /**
139 * <p>
140 * Order is <code>groupId:artifactId:version:classifier:type:scope</code>.
141 * </p>
142 */
143 public static final Artifact parseArtifact(String gav) {
144 Assert.noBlanks(gav);
145
146 String[] tokens = StringUtils.splitPreserveAllTokens(gav, GAV_DELIMITER);
147 int len = tokens.length;
148 Assert.isTrue(len >= 2, "groupId, artifactId, and version are required");
149 for (int i = 0; i < len; i++) {
150 tokens[i] = NullUtils.trimToNull(tokens[i]);
151 }
152
153 String groupId = tokens[0];
154 String artifactId = tokens[1];
155 String version = tokens[2];
156 String classifier = (len > 3) ? tokens[3] : NullUtils.NONE;
157 String type = (len > 4) ? tokens[4] : Artifact.Builder.DEFAULT_TYPE;
158
159 return new Artifact.Builder(groupId, artifactId, version).classifier(classifier).type(type).build();
160 }
161
162 /**
163 * <p>
164 * Order is <code>groupId:artifactId:version:classifier:type:scope</code>.
165 * </p>
166 */
167 public static final Dependency parseDependency(String gav) {
168 Assert.noBlanks(gav);
169
170 String[] tokens = StringUtils.splitPreserveAllTokens(gav, GAV_DELIMITER);
171 int len = tokens.length;
172 Assert.isTrue(len >= 2, "groupId, artifactId, and version are required");
173 for (int i = 0; i < len; i++) {
174 tokens[i] = NullUtils.trimToNull(tokens[i]);
175 }
176
177 String groupId = tokens[0];
178 String artifactId = tokens[1];
179 String version = tokens[2];
180 String classifier = (len > 3) ? tokens[3] : NullUtils.NONE;
181 String type = (len > 4) ? tokens[4] : Dependency.Builder.DEFAULT_TYPE;
182 String scope = (len > 5) ? tokens[5] : Dependency.Builder.DEFAULT_SCOPE;
183
184 return new Dependency.Builder(groupId, artifactId, version).classifier(classifier).type(type).scope(scope).build();
185 }
186
187 protected static final String getDelimitedString(List<String> tokens, int delimiterCount, String delimiter) {
188 StringBuilder sb = new StringBuilder();
189 for (int i = 0; i < tokens.size(); i++) {
190 if (i != 0 && i < delimiterCount) {
191 sb.append(delimiter);
192 }
193 sb.append(tokens.get(i));
194 }
195 return sb.toString();
196 }
197
198 protected static final int getDelimiterCount(List<String> tokens) {
199 int count = 0;
200 for (int i = 0; i < tokens.size(); i++) {
201 String token = toEmpty(tokens.get(i));
202 if (!StringUtils.isEmpty(token)) {
203 count = i + 1;
204 }
205 }
206 return count == 0 ? tokens.size() : count;
207 }
208
209 /**
210 * Return null if token is blank, "NULL", or "NONE"
211 *
212 * @deprecated Use NullUtils.isNullOrNone() instead
213 */
214 @Deprecated
215 public static String toNull(String token) {
216 if (StringUtils.isBlank(token)) {
217 return null;
218 }
219 if (NullUtils.isNullOrNone(token)) {
220 return null;
221 }
222 return token;
223 }
224
225 /**
226 * Return the empty string if token is blank, "NULL", or "NONE"
227 */
228 public static String toEmpty(String token) {
229 if (StringUtils.isBlank(token)) {
230 return "";
231 }
232 if (NullUtils.isNullOrNone(token)) {
233 return "";
234 }
235 return token;
236 }
237
238 /**
239 * <pre>
240 * org.kuali.common:kuali-util:2.0.1 -> org/kuali/common/kuali-util/2.0.1
241 * </pre>
242 */
243 public static final String getRepositoryPath(Artifact artifact) {
244 StringBuilder sb = new StringBuilder();
245 sb.append(Str.getPath(artifact.getGroupId()));
246 sb.append(FS);
247 sb.append(artifact.getArtifactId());
248 sb.append(FS);
249 sb.append(artifact.getVersion());
250 return sb.toString();
251 }
252
253 /**
254 * <pre>
255 * org.kuali.common:kuali-util:2.0.1::jar -> kuali-util-2.0.1.jar
256 * org.kuali.common:kuali-util:2.0.1:sql:jar -> kuali-util-2.0.1-sql.jar
257 * </pre>
258 */
259 public static final String getFilename(Artifact artifact) {
260 StringBuilder sb = new StringBuilder();
261 sb.append(artifact.getArtifactId());
262 sb.append("-");
263 sb.append(artifact.getVersion());
264 if (artifact.getClassifier().isPresent()) {
265 sb.append("-");
266 sb.append(artifact.getClassifier());
267 }
268 sb.append(".");
269 sb.append(artifact.getType());
270 return sb.toString();
271 }
272
273 public static final File getFile(File localRepositoryDir, Artifact artifact) {
274 String path = getRepositoryPath(artifact);
275 String filename = getFilename(artifact);
276 return new File(localRepositoryDir.getAbsolutePath() + FS + path, filename);
277 }
278
279 }