View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.artifact;
20  
21  import java.io.File;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.Objects;
26  import java.util.regex.Matcher;
27  import java.util.regex.Pattern;
28  
29  /**
30   * A skeleton class for artifacts.
31   */
32  public abstract class AbstractArtifact implements Artifact {
33  
34      private static final String SNAPSHOT = "SNAPSHOT";
35  
36      private static final Pattern SNAPSHOT_TIMESTAMP = Pattern.compile("^(.*-)?([0-9]{8}\\.[0-9]{6}-[0-9]+)$");
37  
38      public boolean isSnapshot() {
39          return isSnapshot(getVersion());
40      }
41  
42      private static boolean isSnapshot(String version) {
43          return version.endsWith(SNAPSHOT) || SNAPSHOT_TIMESTAMP.matcher(version).matches();
44      }
45  
46      public String getBaseVersion() {
47          return toBaseVersion(getVersion());
48      }
49  
50      private static String toBaseVersion(String version) {
51          String baseVersion;
52  
53          if (version == null) {
54              baseVersion = null;
55          } else if (version.startsWith("[") || version.startsWith("(")) {
56              baseVersion = version;
57          } else {
58              Matcher m = SNAPSHOT_TIMESTAMP.matcher(version);
59              if (m.matches()) {
60                  if (m.group(1) != null) {
61                      baseVersion = m.group(1) + SNAPSHOT;
62                  } else {
63                      baseVersion = SNAPSHOT;
64                  }
65              } else {
66                  baseVersion = version;
67              }
68          }
69  
70          return baseVersion;
71      }
72  
73      /**
74       * Creates a new artifact with the specified coordinates, properties and file.
75       *
76       * @param version The version of the artifact, may be {@code null}.
77       * @param properties The properties of the artifact, may be {@code null} if none. The method may assume immutability
78       *            of the supplied map, i.e. need not copy it.
79       * @param file The resolved file of the artifact, may be {@code null}.
80       * @return The new artifact instance, never {@code null}.
81       */
82      private Artifact newInstance(String version, Map<String, String> properties, File file) {
83          return new DefaultArtifact(
84                  getGroupId(), getArtifactId(), getClassifier(), getExtension(), version, file, properties);
85      }
86  
87      public Artifact setVersion(String version) {
88          String current = getVersion();
89          if (current.equals(version) || (version == null && current.isEmpty())) {
90              return this;
91          }
92          return newInstance(version, getProperties(), getFile());
93      }
94  
95      public Artifact setFile(File file) {
96          File current = getFile();
97          if (Objects.equals(current, file)) {
98              return this;
99          }
100         return newInstance(getVersion(), getProperties(), file);
101     }
102 
103     public Artifact setProperties(Map<String, String> properties) {
104         Map<String, String> current = getProperties();
105         if (current.equals(properties) || (properties == null && current.isEmpty())) {
106             return this;
107         }
108         return newInstance(getVersion(), copyProperties(properties), getFile());
109     }
110 
111     public String getProperty(String key, String defaultValue) {
112         String value = getProperties().get(key);
113         return (value != null) ? value : defaultValue;
114     }
115 
116     /**
117      * Copies the specified artifact properties. This utility method should be used when creating new artifact instances
118      * with caller-supplied properties.
119      *
120      * @param properties The properties to copy, may be {@code null}.
121      * @return The copied and read-only properties, never {@code null}.
122      */
123     protected static Map<String, String> copyProperties(Map<String, String> properties) {
124         if (properties != null && !properties.isEmpty()) {
125             return Collections.unmodifiableMap(new HashMap<>(properties));
126         } else {
127             return Collections.emptyMap();
128         }
129     }
130 
131     @Override
132     public String toString() {
133         StringBuilder buffer = new StringBuilder(128);
134         buffer.append(getGroupId());
135         buffer.append(':').append(getArtifactId());
136         buffer.append(':').append(getExtension());
137         if (!getClassifier().isEmpty()) {
138             buffer.append(':').append(getClassifier());
139         }
140         buffer.append(':').append(getVersion());
141         return buffer.toString();
142     }
143 
144     /**
145      * Compares this artifact with the specified object.
146      *
147      * @param obj The object to compare this artifact against, may be {@code null}.
148      * @return {@code true} if and only if the specified object is another {@link Artifact} with equal coordinates,
149      *         properties and file, {@code false} otherwise.
150      */
151     @Override
152     public boolean equals(Object obj) {
153         if (obj == this) {
154             return true;
155         } else if (!(obj instanceof Artifact)) {
156             return false;
157         }
158 
159         Artifact that = (Artifact) obj;
160 
161         return Objects.equals(getArtifactId(), that.getArtifactId())
162                 && Objects.equals(getGroupId(), that.getGroupId())
163                 && Objects.equals(getVersion(), that.getVersion())
164                 && Objects.equals(getExtension(), that.getExtension())
165                 && Objects.equals(getClassifier(), that.getClassifier())
166                 && Objects.equals(getFile(), that.getFile())
167                 && Objects.equals(getProperties(), that.getProperties());
168     }
169 
170     /**
171      * Returns a hash code for this artifact.
172      *
173      * @return A hash code for the artifact.
174      */
175     @Override
176     public int hashCode() {
177         int hash = 17;
178         hash = hash * 31 + getGroupId().hashCode();
179         hash = hash * 31 + getArtifactId().hashCode();
180         hash = hash * 31 + getExtension().hashCode();
181         hash = hash * 31 + getClassifier().hashCode();
182         hash = hash * 31 + getVersion().hashCode();
183         hash = hash * 31 + hash(getFile());
184         return hash;
185     }
186 
187     private static int hash(Object obj) {
188         return (obj != null) ? obj.hashCode() : 0;
189     }
190 }