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