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