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