001package org.apache.maven.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.Collection;
024import java.util.Collections;
025import java.util.HashMap;
026import java.util.List;
027import java.util.Map;
028import java.util.regex.Matcher;
029
030import org.apache.maven.artifact.handler.ArtifactHandler;
031import org.apache.maven.artifact.metadata.ArtifactMetadata;
032import org.apache.maven.artifact.repository.ArtifactRepository;
033import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
034import org.apache.maven.artifact.versioning.ArtifactVersion;
035import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
036import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
037import org.apache.maven.artifact.versioning.VersionRange;
038import org.codehaus.plexus.util.StringUtils;
039
040/**
041 * @author Jason van Zyl
042 */
043public class DefaultArtifact
044    implements Artifact
045{
046    private String groupId;
047
048    private String artifactId;
049
050    private String baseVersion;
051
052    private final String type;
053
054    private final String classifier;
055
056    private volatile String scope;
057
058    private volatile File file;
059
060    private ArtifactRepository repository;
061
062    private String downloadUrl;
063
064    private ArtifactFilter dependencyFilter;
065
066    private ArtifactHandler artifactHandler;
067
068    private List<String> dependencyTrail;
069
070    private volatile String version;
071
072    private VersionRange versionRange;
073
074    private volatile boolean resolved;
075
076    private boolean release;
077
078    private List<ArtifactVersion> availableVersions;
079
080    private Map<Object, ArtifactMetadata> metadataMap;
081
082    private boolean optional;
083
084    public DefaultArtifact( String groupId, String artifactId, String version, String scope, String type,
085                            String classifier, ArtifactHandler artifactHandler )
086    {
087        this( groupId, artifactId, VersionRange.createFromVersion( version ), scope, type, classifier, artifactHandler,
088              false );
089    }
090
091    public DefaultArtifact( String groupId, String artifactId, VersionRange versionRange, String scope, String type,
092                            String classifier, ArtifactHandler artifactHandler )
093    {
094        this( groupId, artifactId, versionRange, scope, type, classifier, artifactHandler, false );
095    }
096
097    public DefaultArtifact( String groupId, String artifactId, VersionRange versionRange, String scope, String type,
098                            String classifier, ArtifactHandler artifactHandler, boolean optional )
099    {
100        this.groupId = groupId;
101
102        this.artifactId = artifactId;
103
104        this.versionRange = versionRange;
105
106        selectVersionFromNewRangeIfAvailable();
107
108        this.artifactHandler = artifactHandler;
109
110        this.scope = scope;
111
112        this.type = type;
113
114        if ( classifier == null )
115        {
116            classifier = artifactHandler.getClassifier();
117        }
118
119        this.classifier = classifier;
120
121        this.optional = optional;
122
123        validateIdentity();
124    }
125
126    private void validateIdentity()
127    {
128        if ( empty( groupId ) )
129        {
130            throw new InvalidArtifactRTException( groupId, artifactId, getVersion(), type,
131                "The groupId cannot be empty." );
132        }
133
134        if ( artifactId == null )
135        {
136            throw new InvalidArtifactRTException( groupId, artifactId, getVersion(), type,
137                "The artifactId cannot be empty." );
138        }
139
140        if ( type == null )
141        {
142            throw new InvalidArtifactRTException( groupId, artifactId, getVersion(), type,
143                "The type cannot be empty." );
144        }
145
146        if ( ( version == null ) && ( versionRange == null ) )
147        {
148            throw new InvalidArtifactRTException( groupId, artifactId, getVersion(), type,
149                "The version cannot be empty." );
150        }
151    }
152
153    private boolean empty( String value )
154    {
155        return ( value == null ) || ( value.trim().length() < 1 );
156    }
157
158    public String getClassifier()
159    {
160        return classifier;
161    }
162
163    public boolean hasClassifier()
164    {
165        return StringUtils.isNotEmpty( classifier );
166    }
167
168    public String getScope()
169    {
170        return scope;
171    }
172
173    public String getGroupId()
174    {
175        return groupId;
176    }
177
178    public String getArtifactId()
179    {
180        return artifactId;
181    }
182
183    public String getVersion()
184    {
185        return version;
186    }
187
188    public void setVersion( String version )
189    {
190        this.version = version;
191        setBaseVersionInternal( version );
192        versionRange = null;
193    }
194
195    public String getType()
196    {
197        return type;
198    }
199
200    public void setFile( File file )
201    {
202        this.file = file;
203    }
204
205    public File getFile()
206    {
207        return file;
208    }
209
210    public ArtifactRepository getRepository()
211    {
212        return repository;
213    }
214
215    public void setRepository( ArtifactRepository repository )
216    {
217        this.repository = repository;
218    }
219
220    // ----------------------------------------------------------------------
221    //
222    // ----------------------------------------------------------------------
223
224    public String getId()
225    {
226        return getDependencyConflictId() + ":" + getBaseVersion();
227    }
228
229    public String getDependencyConflictId()
230    {
231        StringBuilder sb = new StringBuilder( 128 );
232        sb.append( getGroupId() );
233        sb.append( ":" );
234        appendArtifactTypeClassifierString( sb );
235        return sb.toString();
236    }
237
238    private void appendArtifactTypeClassifierString( StringBuilder sb )
239    {
240        sb.append( getArtifactId() );
241        sb.append( ":" );
242        sb.append( getType() );
243        if ( hasClassifier() )
244        {
245            sb.append( ":" );
246            sb.append( getClassifier() );
247        }
248    }
249
250    public void addMetadata( ArtifactMetadata metadata )
251    {
252        if ( metadataMap == null )
253        {
254            metadataMap = new HashMap<Object, ArtifactMetadata>();
255        }
256
257        ArtifactMetadata m = metadataMap.get( metadata.getKey() );
258        if ( m != null )
259        {
260            m.merge( metadata );
261        }
262        else
263        {
264            metadataMap.put( metadata.getKey(), metadata );
265        }
266    }
267
268    public Collection<ArtifactMetadata> getMetadataList()
269    {
270        if ( metadataMap == null )
271        {
272            return Collections.emptyList();
273        }
274
275        return metadataMap.values();
276    }
277
278    // ----------------------------------------------------------------------
279    // Object overrides
280    // ----------------------------------------------------------------------
281
282    public String toString()
283    {
284        StringBuilder sb = new StringBuilder();
285        if ( getGroupId() != null )
286        {
287            sb.append( getGroupId() );
288            sb.append( ":" );
289        }
290        appendArtifactTypeClassifierString( sb );
291        sb.append( ":" );
292        if ( getBaseVersionInternal() != null )
293        {
294            sb.append( getBaseVersionInternal() );
295        }
296        else
297        {
298            sb.append( versionRange.toString() );
299        }
300        if ( scope != null )
301        {
302            sb.append( ":" );
303            sb.append( scope );
304        }
305        return sb.toString();
306    }
307
308    public int hashCode()
309    {
310        int result = 17;
311        result = 37 * result + groupId.hashCode();
312        result = 37 * result + artifactId.hashCode();
313        result = 37 * result + type.hashCode();
314        if ( version != null )
315        {
316            result = 37 * result + version.hashCode();
317        }
318        result = 37 * result + ( classifier != null ? classifier.hashCode() : 0 );
319        return result;
320    }
321
322    public boolean equals( Object o )
323    {
324        if ( o == this )
325        {
326            return true;
327        }
328
329        if ( !( o instanceof Artifact ) )
330        {
331            return false;
332        }
333
334        Artifact a = (Artifact) o;
335
336        if ( !a.getGroupId().equals( groupId ) )
337        {
338            return false;
339        }
340        else if ( !a.getArtifactId().equals( artifactId ) )
341        {
342            return false;
343        }
344        else if ( !a.getVersion().equals( version ) )
345        {
346            return false;
347        }
348        else if ( !a.getType().equals( type ) )
349        {
350            return false;
351        }
352        else if ( a.getClassifier() == null ? classifier != null : !a.getClassifier().equals( classifier ) )
353        {
354            return false;
355        }
356
357        // We don't consider the version range in the comparison, just the resolved version
358
359        return true;
360    }
361
362    public String getBaseVersion()
363    {
364        if ( baseVersion == null && version != null )
365        {
366            setBaseVersionInternal( version );
367        }
368
369        return baseVersion;
370    }
371
372    protected String getBaseVersionInternal()
373    {
374        if ( ( baseVersion == null ) && ( version != null ) )
375        {
376            setBaseVersionInternal( version );
377        }
378
379        return baseVersion;
380    }
381
382    public void setBaseVersion( String baseVersion )
383    {
384        setBaseVersionInternal( baseVersion );
385    }
386
387    protected void setBaseVersionInternal( String baseVersion )
388    {
389        Matcher m = VERSION_FILE_PATTERN.matcher( baseVersion );
390
391        if ( m.matches() )
392        {
393            this.baseVersion = m.group( 1 ) + "-" + SNAPSHOT_VERSION;
394        }
395        else
396        {
397            this.baseVersion = baseVersion;
398        }
399    }
400
401    public int compareTo( Artifact a )
402    {
403        int result = groupId.compareTo( a.getGroupId() );
404        if ( result == 0 )
405        {
406            result = artifactId.compareTo( a.getArtifactId() );
407            if ( result == 0 )
408            {
409                result = type.compareTo( a.getType() );
410                if ( result == 0 )
411                {
412                    if ( classifier == null )
413                    {
414                        if ( a.getClassifier() != null )
415                        {
416                            result = 1;
417                        }
418                    }
419                    else
420                    {
421                        if ( a.getClassifier() != null )
422                        {
423                            result = classifier.compareTo( a.getClassifier() );
424                        }
425                        else
426                        {
427                            result = -1;
428                        }
429                    }
430                    if ( result == 0 )
431                    {
432                        // We don't consider the version range in the comparison, just the resolved version
433                        result = new DefaultArtifactVersion( version ).compareTo(
434                            new DefaultArtifactVersion( a.getVersion() ) );
435                    }
436                }
437            }
438        }
439        return result;
440    }
441
442    public void updateVersion( String version, ArtifactRepository localRepository )
443    {
444        setResolvedVersion( version );
445        setFile( new File( localRepository.getBasedir(), localRepository.pathOf( this ) ) );
446    }
447
448    public String getDownloadUrl()
449    {
450        return downloadUrl;
451    }
452
453    public void setDownloadUrl( String downloadUrl )
454    {
455        this.downloadUrl = downloadUrl;
456    }
457
458    public ArtifactFilter getDependencyFilter()
459    {
460        return dependencyFilter;
461    }
462
463    public void setDependencyFilter( ArtifactFilter artifactFilter )
464    {
465        dependencyFilter = artifactFilter;
466    }
467
468    public ArtifactHandler getArtifactHandler()
469    {
470        return artifactHandler;
471    }
472
473    public List<String> getDependencyTrail()
474    {
475        return dependencyTrail;
476    }
477
478    public void setDependencyTrail( List<String> dependencyTrail )
479    {
480        this.dependencyTrail = dependencyTrail;
481    }
482
483    public void setScope( String scope )
484    {
485        this.scope = scope;
486    }
487
488    public VersionRange getVersionRange()
489    {
490        return versionRange;
491    }
492
493    public void setVersionRange( VersionRange versionRange )
494    {
495        this.versionRange = versionRange;
496        selectVersionFromNewRangeIfAvailable();
497    }
498
499    private void selectVersionFromNewRangeIfAvailable()
500    {
501        if ( ( versionRange != null ) && ( versionRange.getRecommendedVersion() != null ) )
502        {
503            selectVersion( versionRange.getRecommendedVersion().toString() );
504        }
505        else
506        {
507            version = null;
508            baseVersion = null;
509        }
510    }
511
512    public void selectVersion( String version )
513    {
514        this.version = version;
515        setBaseVersionInternal( version );
516    }
517
518    public void setGroupId( String groupId )
519    {
520        this.groupId = groupId;
521    }
522
523    public void setArtifactId( String artifactId )
524    {
525        this.artifactId = artifactId;
526    }
527
528    public boolean isSnapshot()
529    {
530        return getBaseVersion() != null
531            && ( getBaseVersion().endsWith( SNAPSHOT_VERSION ) || getBaseVersion().equals( LATEST_VERSION ) );
532    }
533
534    public void setResolved( boolean resolved )
535    {
536        this.resolved = resolved;
537    }
538
539    public boolean isResolved()
540    {
541        return resolved;
542    }
543
544    public void setResolvedVersion( String version )
545    {
546        this.version = version;
547        // retain baseVersion
548    }
549
550    public void setArtifactHandler( ArtifactHandler artifactHandler )
551    {
552        this.artifactHandler = artifactHandler;
553    }
554
555    public void setRelease( boolean release )
556    {
557        this.release = release;
558    }
559
560    public boolean isRelease()
561    {
562        return release;
563    }
564
565    public List<ArtifactVersion> getAvailableVersions()
566    {
567        return availableVersions;
568    }
569
570    public void setAvailableVersions( List<ArtifactVersion> availableVersions )
571    {
572        this.availableVersions = availableVersions;
573    }
574
575    public boolean isOptional()
576    {
577        return optional;
578    }
579
580    public ArtifactVersion getSelectedVersion()
581        throws OverConstrainedVersionException
582    {
583        return versionRange.getSelectedVersion( this );
584    }
585
586    public boolean isSelectedVersionKnown()
587        throws OverConstrainedVersionException
588    {
589        return versionRange.isSelectedVersionKnown( this );
590    }
591
592    public void setOptional( boolean optional )
593    {
594        this.optional = optional;
595    }
596
597}