View Javadoc
1   /*******************************************************************************
2    * Copyright (c) 2010, 2012 Sonatype, Inc.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *    Sonatype, Inc. - initial API and implementation
10   *******************************************************************************/
11  package org.eclipse.aether.artifact;
12  
13  import java.io.File;
14  import java.util.Collections;
15  import java.util.HashMap;
16  import java.util.Map;
17  import java.util.regex.Matcher;
18  import java.util.regex.Pattern;
19  
20  /**
21   * A skeleton class for artifacts.
22   */
23  public abstract class AbstractArtifact
24      implements Artifact
25  {
26  
27      private static final String SNAPSHOT = "SNAPSHOT";
28  
29      private static final Pattern SNAPSHOT_TIMESTAMP = Pattern.compile( "^(.*-)?([0-9]{8}\\.[0-9]{6}-[0-9]+)$" );
30  
31      public boolean isSnapshot()
32      {
33          return isSnapshot( getVersion() );
34      }
35  
36      private static boolean isSnapshot( String version )
37      {
38          return version.endsWith( SNAPSHOT ) || SNAPSHOT_TIMESTAMP.matcher( version ).matches();
39      }
40  
41      public String getBaseVersion()
42      {
43          return toBaseVersion( getVersion() );
44      }
45  
46      private static String toBaseVersion( String version )
47      {
48          String baseVersion;
49  
50          if ( version == null )
51          {
52              baseVersion = version;
53          }
54          else if ( version.startsWith( "[" ) || version.startsWith( "(" ) )
55          {
56              baseVersion = version;
57          }
58          else
59          {
60              Matcher m = SNAPSHOT_TIMESTAMP.matcher( version );
61              if ( m.matches() )
62              {
63                  if ( m.group( 1 ) != null )
64                  {
65                      baseVersion = m.group( 1 ) + SNAPSHOT;
66                  }
67                  else
68                  {
69                      baseVersion = SNAPSHOT;
70                  }
71              }
72              else
73              {
74                  baseVersion = version;
75              }
76          }
77  
78          return baseVersion;
79      }
80  
81      /**
82       * Creates a new artifact with the specified coordinates, properties and file.
83       * 
84       * @param version The version of the artifact, may be {@code null}.
85       * @param properties The properties of the artifact, may be {@code null} if none. The method may assume immutability
86       *            of the supplied map, i.e. need not copy it.
87       * @param file The resolved file of the artifact, may be {@code null}.
88       * @return The new artifact instance, never {@code null}.
89       */
90      private Artifact newInstance( String version, Map<String, String> properties, File file )
91      {
92          return new DefaultArtifact( getGroupId(), getArtifactId(), getClassifier(), getExtension(), version, file,
93                                      properties );
94      }
95  
96      public Artifact setVersion( String version )
97      {
98          String current = getVersion();
99          if ( current.equals( version ) || ( version == null && current.length() <= 0 ) )
100         {
101             return this;
102         }
103         return newInstance( version, getProperties(), getFile() );
104     }
105 
106     public Artifact setFile( File file )
107     {
108         File current = getFile();
109         if ( ( current == null ) ? file == null : current.equals( file ) )
110         {
111             return this;
112         }
113         return newInstance( getVersion(), getProperties(), file );
114     }
115 
116     public Artifact setProperties( Map<String, String> properties )
117     {
118         Map<String, String> current = getProperties();
119         if ( current.equals( properties ) || ( properties == null && current.isEmpty() ) )
120         {
121             return this;
122         }
123         return newInstance( getVersion(), copyProperties( properties ), getFile() );
124     }
125 
126     public String getProperty( String key, String defaultValue )
127     {
128         String value = getProperties().get( key );
129         return ( value != null ) ? value : defaultValue;
130     }
131 
132     /**
133      * Copies the specified artifact properties. This utility method should be used when creating new artifact instances
134      * with caller-supplied properties.
135      * 
136      * @param properties The properties to copy, may be {@code null}.
137      * @return The copied and read-only properties, never {@code null}.
138      */
139     protected static Map<String, String> copyProperties( Map<String, String> properties )
140     {
141         if ( properties != null && !properties.isEmpty() )
142         {
143             return Collections.unmodifiableMap( new HashMap<String, String>( properties ) );
144         }
145         else
146         {
147             return Collections.emptyMap();
148         }
149     }
150 
151     @Override
152     public String toString()
153     {
154         StringBuilder buffer = new StringBuilder( 128 );
155         buffer.append( getGroupId() );
156         buffer.append( ':' ).append( getArtifactId() );
157         buffer.append( ':' ).append( getExtension() );
158         if ( getClassifier().length() > 0 )
159         {
160             buffer.append( ':' ).append( getClassifier() );
161         }
162         buffer.append( ':' ).append( getVersion() );
163         return buffer.toString();
164     }
165 
166     /**
167      * Compares this artifact with the specified object.
168      * 
169      * @param obj The object to compare this artifact against, may be {@code null}.
170      * @return {@code true} if and only if the specified object is another {@link Artifact} with equal coordinates,
171      *         properties and file, {@code false} otherwise.
172      */
173     @Override
174     public boolean equals( Object obj )
175     {
176         if ( obj == this )
177         {
178             return true;
179         }
180         else if ( !( obj instanceof Artifact ) )
181         {
182             return false;
183         }
184 
185         Artifact that = (Artifact) obj;
186 
187         return getArtifactId().equals( that.getArtifactId() ) && getGroupId().equals( that.getGroupId() )
188             && getVersion().equals( that.getVersion() ) && getExtension().equals( that.getExtension() )
189             && getClassifier().equals( that.getClassifier() ) && eq( getFile(), that.getFile() )
190             && getProperties().equals( that.getProperties() );
191     }
192 
193     private static <T> boolean eq( T s1, T s2 )
194     {
195         return s1 != null ? s1.equals( s2 ) : s2 == null;
196     }
197 
198     /**
199      * Returns a hash code for this artifact.
200      * 
201      * @return A hash code for the artifact.
202      */
203     @Override
204     public int hashCode()
205     {
206         int hash = 17;
207         hash = hash * 31 + getGroupId().hashCode();
208         hash = hash * 31 + getArtifactId().hashCode();
209         hash = hash * 31 + getExtension().hashCode();
210         hash = hash * 31 + getClassifier().hashCode();
211         hash = hash * 31 + getVersion().hashCode();
212         hash = hash * 31 + hash( getFile() );
213         return hash;
214     }
215 
216     private static int hash( Object obj )
217     {
218         return ( obj != null ) ? obj.hashCode() : 0;
219     }
220 
221 }