001package org.eclipse.aether.artifact; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.Map; 026import java.util.regex.Matcher; 027import java.util.regex.Pattern; 028 029/** 030 * A skeleton class for artifacts. 031 */ 032public abstract class AbstractArtifact 033 implements Artifact 034{ 035 036 private static final String SNAPSHOT = "SNAPSHOT"; 037 038 private static final Pattern SNAPSHOT_TIMESTAMP = Pattern.compile( "^(.*-)?([0-9]{8}\\.[0-9]{6}-[0-9]+)$" ); 039 040 public boolean isSnapshot() 041 { 042 return isSnapshot( getVersion() ); 043 } 044 045 private static boolean isSnapshot( String version ) 046 { 047 return version.endsWith( SNAPSHOT ) || SNAPSHOT_TIMESTAMP.matcher( version ).matches(); 048 } 049 050 public String getBaseVersion() 051 { 052 return toBaseVersion( getVersion() ); 053 } 054 055 private static String toBaseVersion( String version ) 056 { 057 String baseVersion; 058 059 if ( version == null ) 060 { 061 baseVersion = version; 062 } 063 else if ( version.startsWith( "[" ) || version.startsWith( "(" ) ) 064 { 065 baseVersion = version; 066 } 067 else 068 { 069 Matcher m = SNAPSHOT_TIMESTAMP.matcher( version ); 070 if ( m.matches() ) 071 { 072 if ( m.group( 1 ) != null ) 073 { 074 baseVersion = m.group( 1 ) + SNAPSHOT; 075 } 076 else 077 { 078 baseVersion = SNAPSHOT; 079 } 080 } 081 else 082 { 083 baseVersion = version; 084 } 085 } 086 087 return baseVersion; 088 } 089 090 /** 091 * Creates a new artifact with the specified coordinates, properties and file. 092 * 093 * @param version The version of the artifact, may be {@code null}. 094 * @param properties The properties of the artifact, may be {@code null} if none. The method may assume immutability 095 * of the supplied map, i.e. need not copy it. 096 * @param file The resolved file of the artifact, may be {@code null}. 097 * @return The new artifact instance, never {@code null}. 098 */ 099 private Artifact newInstance( String version, Map<String, String> properties, File file ) 100 { 101 return new DefaultArtifact( getGroupId(), getArtifactId(), getClassifier(), getExtension(), version, file, 102 properties ); 103 } 104 105 public Artifact setVersion( String version ) 106 { 107 String current = getVersion(); 108 if ( current.equals( version ) || ( version == null && current.length() <= 0 ) ) 109 { 110 return this; 111 } 112 return newInstance( version, getProperties(), getFile() ); 113 } 114 115 public Artifact setFile( File file ) 116 { 117 File current = getFile(); 118 if ( ( current == null ) ? file == null : current.equals( file ) ) 119 { 120 return this; 121 } 122 return newInstance( getVersion(), getProperties(), file ); 123 } 124 125 public Artifact setProperties( Map<String, String> properties ) 126 { 127 Map<String, String> current = getProperties(); 128 if ( current.equals( properties ) || ( properties == null && current.isEmpty() ) ) 129 { 130 return this; 131 } 132 return newInstance( getVersion(), copyProperties( properties ), getFile() ); 133 } 134 135 public String getProperty( String key, String defaultValue ) 136 { 137 String value = getProperties().get( key ); 138 return ( value != null ) ? value : defaultValue; 139 } 140 141 /** 142 * Copies the specified artifact properties. This utility method should be used when creating new artifact instances 143 * with caller-supplied properties. 144 * 145 * @param properties The properties to copy, may be {@code null}. 146 * @return The copied and read-only properties, never {@code null}. 147 */ 148 protected static Map<String, String> copyProperties( Map<String, String> properties ) 149 { 150 if ( properties != null && !properties.isEmpty() ) 151 { 152 return Collections.unmodifiableMap( new HashMap<String, String>( properties ) ); 153 } 154 else 155 { 156 return Collections.emptyMap(); 157 } 158 } 159 160 @Override 161 public String toString() 162 { 163 StringBuilder buffer = new StringBuilder( 128 ); 164 buffer.append( getGroupId() ); 165 buffer.append( ':' ).append( getArtifactId() ); 166 buffer.append( ':' ).append( getExtension() ); 167 if ( getClassifier().length() > 0 ) 168 { 169 buffer.append( ':' ).append( getClassifier() ); 170 } 171 buffer.append( ':' ).append( getVersion() ); 172 return buffer.toString(); 173 } 174 175 /** 176 * Compares this artifact with the specified object. 177 * 178 * @param obj The object to compare this artifact against, may be {@code null}. 179 * @return {@code true} if and only if the specified object is another {@link Artifact} with equal coordinates, 180 * properties and file, {@code false} otherwise. 181 */ 182 @Override 183 public boolean equals( Object obj ) 184 { 185 if ( obj == this ) 186 { 187 return true; 188 } 189 else if ( !( obj instanceof Artifact ) ) 190 { 191 return false; 192 } 193 194 Artifact that = (Artifact) obj; 195 196 return getArtifactId().equals( that.getArtifactId() ) && getGroupId().equals( that.getGroupId() ) 197 && getVersion().equals( that.getVersion() ) && getExtension().equals( that.getExtension() ) 198 && getClassifier().equals( that.getClassifier() ) && eq( getFile(), that.getFile() ) 199 && getProperties().equals( that.getProperties() ); 200 } 201 202 private static <T> boolean eq( T s1, T s2 ) 203 { 204 return s1 != null ? s1.equals( s2 ) : s2 == null; 205 } 206 207 /** 208 * Returns a hash code for this artifact. 209 * 210 * @return A hash code for the artifact. 211 */ 212 @Override 213 public int hashCode() 214 { 215 int hash = 17; 216 hash = hash * 31 + getGroupId().hashCode(); 217 hash = hash * 31 + getArtifactId().hashCode(); 218 hash = hash * 31 + getExtension().hashCode(); 219 hash = hash * 31 + getClassifier().hashCode(); 220 hash = hash * 31 + getVersion().hashCode(); 221 hash = hash * 31 + hash( getFile() ); 222 return hash; 223 } 224 225 private static int hash( Object obj ) 226 { 227 return ( obj != null ) ? obj.hashCode() : 0; 228 } 229 230}