001    package 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    
022    import java.io.File;
023    import java.util.Collection;
024    import java.util.Collections;
025    import java.util.HashMap;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.regex.Matcher;
029    
030    import org.apache.maven.artifact.handler.ArtifactHandler;
031    import org.apache.maven.artifact.metadata.ArtifactMetadata;
032    import org.apache.maven.artifact.repository.ArtifactRepository;
033    import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
034    import org.apache.maven.artifact.versioning.ArtifactVersion;
035    import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
036    import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
037    import org.apache.maven.artifact.versioning.VersionRange;
038    import org.codehaus.plexus.util.StringUtils;
039    
040    /**
041     * @author Jason van Zyl
042     */
043    public 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    }