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.nio.file.Path;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.Objects;
27  import java.util.regex.Matcher;
28  import java.util.regex.Pattern;
29  
30  /**
31   * A skeleton class for artifacts.
32   */
33  public abstract class AbstractArtifact implements Artifact {
34  
35      private static final String SNAPSHOT = "SNAPSHOT";
36  
37      private static final Pattern SNAPSHOT_TIMESTAMP = Pattern.compile("^(.*-)?([0-9]{8}\\.[0-9]{6}-[0-9]+)$");
38  
39      @Override
40      public boolean isSnapshot() {
41          return isSnapshot(getVersion());
42      }
43  
44      private static boolean isSnapshot(String version) {
45          return version.endsWith(SNAPSHOT) || SNAPSHOT_TIMESTAMP.matcher(version).matches();
46      }
47  
48      @Override
49      public String getBaseVersion() {
50          return toBaseVersion(getVersion());
51      }
52  
53      private static String toBaseVersion(String version) {
54          String baseVersion;
55  
56          if (version == null) {
57              baseVersion = null;
58          } else if (version.startsWith("[") || version.startsWith("(")) {
59              baseVersion = version;
60          } else {
61              Matcher m = SNAPSHOT_TIMESTAMP.matcher(version);
62              if (m.matches()) {
63                  if (m.group(1) != null) {
64                      baseVersion = m.group(1) + SNAPSHOT;
65                  } else {
66                      baseVersion = SNAPSHOT;
67                  }
68              } else {
69                  baseVersion = version;
70              }
71          }
72  
73          return baseVersion;
74      }
75  
76      /**
77       * Creates a new artifact with the specified coordinates, properties and file.
78       *
79       * @param version The version of the artifact, may be {@code null}.
80       * @param properties The properties of the artifact, may be {@code null} if none. The method may assume immutability
81       *            of the supplied map, i.e. need not copy it.
82       * @param path The resolved file of the artifact, may be {@code null}.
83       * @return The new artifact instance, never {@code null}.
84       */
85      private Artifact newInstance(String version, Map<String, String> properties, Path path) {
86          return new DefaultArtifact(
87                  getGroupId(), getArtifactId(), getClassifier(), getExtension(), version, path, properties);
88      }
89  
90      @Override
91      public Artifact setVersion(String version) {
92          String current = getVersion();
93          if (current.equals(version) || (version == null && current.isEmpty())) {
94              return this;
95          }
96          return newInstance(version, getProperties(), getPath());
97      }
98  
99      @Deprecated
100     @Override
101     public Artifact setFile(File file) {
102         return setPath(file != null ? file.toPath() : null);
103     }
104 
105     @Override
106     public Artifact setPath(Path path) {
107         Path current = getPath();
108         if (Objects.equals(current, path)) {
109             return this;
110         }
111         return newInstance(getVersion(), getProperties(), path);
112     }
113 
114     public Artifact setProperties(Map<String, String> properties) {
115         Map<String, String> current = getProperties();
116         if (current.equals(properties) || (properties == null && current.isEmpty())) {
117             return this;
118         }
119         return newInstance(getVersion(), copyProperties(properties), getPath());
120     }
121 
122     public String getProperty(String key, String defaultValue) {
123         String value = getProperties().get(key);
124         return (value != null) ? value : defaultValue;
125     }
126 
127     /**
128      * Copies the specified artifact properties. This utility method should be used when creating new artifact instances
129      * with caller-supplied properties.
130      *
131      * @param properties The properties to copy, may be {@code null}.
132      * @return The copied and read-only properties, never {@code null}.
133      */
134     protected static Map<String, String> copyProperties(Map<String, String> properties) {
135         if (properties != null && !properties.isEmpty()) {
136             return Collections.unmodifiableMap(new HashMap<>(properties));
137         } else {
138             return Collections.emptyMap();
139         }
140     }
141 
142     @Override
143     public String toString() {
144         StringBuilder buffer = new StringBuilder(128);
145         buffer.append(getGroupId());
146         buffer.append(':').append(getArtifactId());
147         buffer.append(':').append(getExtension());
148         if (!getClassifier().isEmpty()) {
149             buffer.append(':').append(getClassifier());
150         }
151         buffer.append(':').append(getVersion());
152         return buffer.toString();
153     }
154 
155     /**
156      * Compares this artifact with the specified object.
157      *
158      * @param obj The object to compare this artifact against, may be {@code null}.
159      * @return {@code true} if and only if the specified object is another {@link Artifact} with equal coordinates,
160      *         properties and file, {@code false} otherwise.
161      */
162     @Override
163     public boolean equals(Object obj) {
164         if (obj == this) {
165             return true;
166         } else if (!(obj instanceof Artifact)) {
167             return false;
168         }
169 
170         Artifact that = (Artifact) obj;
171 
172         return Objects.equals(getArtifactId(), that.getArtifactId())
173                 && Objects.equals(getGroupId(), that.getGroupId())
174                 && Objects.equals(getVersion(), that.getVersion())
175                 && Objects.equals(getExtension(), that.getExtension())
176                 && Objects.equals(getClassifier(), that.getClassifier())
177                 && Objects.equals(getPath(), that.getPath())
178                 && Objects.equals(getProperties(), that.getProperties());
179     }
180 
181     /**
182      * Returns a hash code for this artifact.
183      *
184      * @return A hash code for the artifact.
185      */
186     @Override
187     public int hashCode() {
188         int hash = 17;
189         hash = hash * 31 + getGroupId().hashCode();
190         hash = hash * 31 + getArtifactId().hashCode();
191         hash = hash * 31 + getExtension().hashCode();
192         hash = hash * 31 + getClassifier().hashCode();
193         hash = hash * 31 + getVersion().hashCode();
194         hash = hash * 31 + hash(getPath());
195         return hash;
196     }
197 
198     private static int hash(Object obj) {
199         return (obj != null) ? obj.hashCode() : 0;
200     }
201 }