1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.eclipse.aether.util.artifact; 20 21 import java.io.File; 22 import java.util.Map; 23 import java.util.Objects; 24 25 import org.eclipse.aether.artifact.AbstractArtifact; 26 import org.eclipse.aether.artifact.Artifact; 27 28 import static java.util.Objects.requireNonNull; 29 30 /** 31 * An artifact whose identity is derived from another artifact. <em>Note:</em> Instances of this class are immutable and 32 * the exposed mutators return new objects rather than changing the current instance. 33 */ 34 public final class SubArtifact extends AbstractArtifact { 35 36 private final Artifact mainArtifact; 37 38 private final String classifier; 39 40 private final String extension; 41 42 private final File file; 43 44 private final Map<String, String> properties; 45 46 /** 47 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk 48 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier 49 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be 50 * used to refer to the GPG signature of an artifact. 51 * 52 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. 53 * @param classifier The classifier for this artifact, may be {@code null} if none. 54 * @param extension The extension for this artifact, may be {@code null} if none. 55 */ 56 public SubArtifact(Artifact mainArtifact, String classifier, String extension) { 57 this(mainArtifact, classifier, extension, (File) null); 58 } 59 60 /** 61 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk 62 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier 63 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be 64 * used to refer to the GPG signature of an artifact. 65 * 66 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. 67 * @param classifier The classifier for this artifact, may be {@code null} if none. 68 * @param extension The extension for this artifact, may be {@code null} if none. 69 * @param file The file for this artifact, may be {@code null} if unresolved. 70 */ 71 public SubArtifact(Artifact mainArtifact, String classifier, String extension, File file) { 72 this(mainArtifact, classifier, extension, null, file); 73 } 74 75 /** 76 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk 77 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier 78 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be 79 * used to refer to the GPG signature of an artifact. 80 * 81 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. 82 * @param classifier The classifier for this artifact, may be {@code null} if none. 83 * @param extension The extension for this artifact, may be {@code null} if none. 84 * @param properties The properties of the artifact, may be {@code null}. 85 */ 86 public SubArtifact(Artifact mainArtifact, String classifier, String extension, Map<String, String> properties) { 87 this(mainArtifact, classifier, extension, properties, null); 88 } 89 90 /** 91 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk 92 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier 93 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be 94 * used to refer to the GPG signature of an artifact. 95 * 96 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. 97 * @param classifier The classifier for this artifact, may be {@code null} if none. 98 * @param extension The extension for this artifact, may be {@code null} if none. 99 * @param properties The properties of the artifact, may be {@code null}. 100 * @param file The file for this artifact, may be {@code null} if unresolved. 101 */ 102 public SubArtifact( 103 Artifact mainArtifact, String classifier, String extension, Map<String, String> properties, File file) { 104 this.mainArtifact = requireNonNull(mainArtifact, "main artifact cannot be null"); 105 this.classifier = classifier; 106 this.extension = extension; 107 this.file = file; 108 this.properties = copyProperties(properties); 109 } 110 111 private SubArtifact( 112 Artifact mainArtifact, String classifier, String extension, File file, Map<String, String> properties) { 113 // NOTE: This constructor assumes immutability of the provided properties, for internal use only 114 this.mainArtifact = mainArtifact; 115 this.classifier = classifier; 116 this.extension = extension; 117 this.file = file; 118 this.properties = properties; 119 } 120 121 public String getGroupId() { 122 return mainArtifact.getGroupId(); 123 } 124 125 public String getArtifactId() { 126 return mainArtifact.getArtifactId(); 127 } 128 129 public String getVersion() { 130 return mainArtifact.getVersion(); 131 } 132 133 public String getBaseVersion() { 134 return mainArtifact.getBaseVersion(); 135 } 136 137 public boolean isSnapshot() { 138 return mainArtifact.isSnapshot(); 139 } 140 141 public String getClassifier() { 142 return expand(classifier, mainArtifact.getClassifier()); 143 } 144 145 public String getExtension() { 146 return expand(extension, mainArtifact.getExtension()); 147 } 148 149 public File getFile() { 150 return file; 151 } 152 153 public Artifact setFile(File file) { 154 if (Objects.equals(this.file, file)) { 155 return this; 156 } 157 return new SubArtifact(mainArtifact, classifier, extension, file, properties); 158 } 159 160 public Map<String, String> getProperties() { 161 return properties; 162 } 163 164 public Artifact setProperties(Map<String, String> properties) { 165 if (this.properties.equals(properties) || (properties == null && this.properties.isEmpty())) { 166 return this; 167 } 168 return new SubArtifact(mainArtifact, classifier, extension, properties, file); 169 } 170 171 private static String expand(String pattern, String replacement) { 172 String result = ""; 173 if (pattern != null) { 174 result = pattern.replace("*", replacement); 175 176 if (replacement.isEmpty()) { 177 if (pattern.startsWith("*")) { 178 int i = 0; 179 for (; i < result.length(); i++) { 180 char c = result.charAt(i); 181 if (c != '-' && c != '.') { 182 break; 183 } 184 } 185 result = result.substring(i); 186 } 187 if (pattern.endsWith("*")) { 188 int i = result.length() - 1; 189 for (; i >= 0; i--) { 190 char c = result.charAt(i); 191 if (c != '-' && c != '.') { 192 break; 193 } 194 } 195 result = result.substring(0, i + 1); 196 } 197 } 198 } 199 return result; 200 } 201 }