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 }