001package org.eclipse.aether.util.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.Map;
024
025import org.eclipse.aether.artifact.AbstractArtifact;
026import org.eclipse.aether.artifact.Artifact;
027
028/**
029 * An artifact whose identity is derived from another artifact. <em>Note:</em> Instances of this class are immutable and
030 * the exposed mutators return new objects rather than changing the current instance.
031 */
032public final class SubArtifact
033    extends AbstractArtifact
034{
035
036    private final Artifact mainArtifact;
037
038    private final String classifier;
039
040    private final String extension;
041
042    private final File file;
043
044    private final Map<String, String> properties;
045
046    /**
047     * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
048     * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
049     * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
050     * used to refer to the GPG signature of an artifact.
051     * 
052     * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
053     * @param classifier The classifier for this artifact, may be {@code null} if none.
054     * @param extension The extension for this artifact, may be {@code null} if none.
055     */
056    public SubArtifact( Artifact mainArtifact, String classifier, String extension )
057    {
058        this( mainArtifact, classifier, extension, (File) null );
059    }
060
061    /**
062     * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
063     * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
064     * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
065     * used to refer to the GPG signature of an artifact.
066     * 
067     * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
068     * @param classifier The classifier for this artifact, may be {@code null} if none.
069     * @param extension The extension for this artifact, may be {@code null} if none.
070     * @param file The file for this artifact, may be {@code null} if unresolved.
071     */
072    public SubArtifact( Artifact mainArtifact, String classifier, String extension, File file )
073    {
074        this( mainArtifact, classifier, extension, null, file );
075    }
076
077    /**
078     * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
079     * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
080     * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
081     * used to refer to the GPG signature of an artifact.
082     * 
083     * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
084     * @param classifier The classifier for this artifact, may be {@code null} if none.
085     * @param extension The extension for this artifact, may be {@code null} if none.
086     * @param properties The properties of the artifact, may be {@code null}.
087     */
088    public SubArtifact( Artifact mainArtifact, String classifier, String extension, Map<String, String> properties )
089    {
090        this( mainArtifact, classifier, extension, properties, null );
091    }
092
093    /**
094     * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
095     * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
096     * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
097     * used to refer to the GPG signature of an artifact.
098     * 
099     * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
100     * @param classifier The classifier for this artifact, may be {@code null} if none.
101     * @param extension The extension for this artifact, may be {@code null} if none.
102     * @param properties The properties of the artifact, may be {@code null}.
103     * @param file The file for this artifact, may be {@code null} if unresolved.
104     */
105    public SubArtifact( Artifact mainArtifact, String classifier, String extension, Map<String, String> properties,
106                        File file )
107    {
108        if ( mainArtifact == null )
109        {
110            throw new IllegalArgumentException( "no artifact specified" );
111        }
112        this.mainArtifact = mainArtifact;
113        this.classifier = classifier;
114        this.extension = extension;
115        this.file = file;
116        this.properties = copyProperties( properties );
117    }
118
119    private SubArtifact( Artifact mainArtifact, String classifier, String extension, File file,
120                         Map<String, String> properties )
121    {
122        // NOTE: This constructor assumes immutability of the provided properties, for internal use only
123        this.mainArtifact = mainArtifact;
124        this.classifier = classifier;
125        this.extension = extension;
126        this.file = file;
127        this.properties = properties;
128    }
129
130    public String getGroupId()
131    {
132        return mainArtifact.getGroupId();
133    }
134
135    public String getArtifactId()
136    {
137        return mainArtifact.getArtifactId();
138    }
139
140    public String getVersion()
141    {
142        return mainArtifact.getVersion();
143    }
144
145    public String getBaseVersion()
146    {
147        return mainArtifact.getBaseVersion();
148    }
149
150    public boolean isSnapshot()
151    {
152        return mainArtifact.isSnapshot();
153    }
154
155    public String getClassifier()
156    {
157        return expand( classifier, mainArtifact.getClassifier() );
158    }
159
160    public String getExtension()
161    {
162        return expand( extension, mainArtifact.getExtension() );
163    }
164
165    public File getFile()
166    {
167        return file;
168    }
169
170    public Artifact setFile( File file )
171    {
172        if ( ( this.file == null ) ? file == null : this.file.equals( file ) )
173        {
174            return this;
175        }
176        return new SubArtifact( mainArtifact, classifier, extension, file, properties );
177    }
178
179    public Map<String, String> getProperties()
180    {
181        return properties;
182    }
183
184    public Artifact setProperties( Map<String, String> properties )
185    {
186        if ( this.properties.equals( properties ) || ( properties == null && this.properties.isEmpty() ) )
187        {
188            return this;
189        }
190        return new SubArtifact( mainArtifact, classifier, extension, properties, file );
191    }
192
193    private static String expand( String pattern, String replacement )
194    {
195        String result = "";
196        if ( pattern != null )
197        {
198            result = pattern.replace( "*", replacement );
199
200            if ( replacement.length() <= 0 )
201            {
202                if ( pattern.startsWith( "*" ) )
203                {
204                    int i = 0;
205                    for ( ; i < result.length(); i++ )
206                    {
207                        char c = result.charAt( i );
208                        if ( c != '-' && c != '.' )
209                        {
210                            break;
211                        }
212                    }
213                    result = result.substring( i );
214                }
215                if ( pattern.endsWith( "*" ) )
216                {
217                    int i = result.length() - 1;
218                    for ( ; i >= 0; i-- )
219                    {
220                        char c = result.charAt( i );
221                        if ( c != '-' && c != '.' )
222                        {
223                            break;
224                        }
225                    }
226                    result = result.substring( 0, i + 1 );
227                }
228            }
229        }
230        return result;
231    }
232
233}