001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.util.artifact; 020 021import java.io.File; 022import java.util.Map; 023import java.util.Objects; 024 025import org.eclipse.aether.artifact.AbstractArtifact; 026import org.eclipse.aether.artifact.Artifact; 027 028import static java.util.Objects.requireNonNull; 029 030/** 031 * An artifact whose identity is derived from another artifact. <em>Note:</em> Instances of this class are immutable and 032 * the exposed mutators return new objects rather than changing the current instance. 033 */ 034public final class SubArtifact extends AbstractArtifact { 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 this(mainArtifact, classifier, extension, (File) null); 058 } 059 060 /** 061 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk 062 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier 063 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be 064 * used to refer to the GPG signature of an artifact. 065 * 066 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. 067 * @param classifier The classifier for this artifact, may be {@code null} if none. 068 * @param extension The extension for this artifact, may be {@code null} if none. 069 * @param file The file for this artifact, may be {@code null} if unresolved. 070 */ 071 public SubArtifact(Artifact mainArtifact, String classifier, String extension, File file) { 072 this(mainArtifact, classifier, extension, null, file); 073 } 074 075 /** 076 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk 077 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier 078 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be 079 * used to refer to the GPG signature of an artifact. 080 * 081 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. 082 * @param classifier The classifier for this artifact, may be {@code null} if none. 083 * @param extension The extension for this artifact, may be {@code null} if none. 084 * @param properties The properties of the artifact, may be {@code null}. 085 */ 086 public SubArtifact(Artifact mainArtifact, String classifier, String extension, Map<String, String> properties) { 087 this(mainArtifact, classifier, extension, properties, null); 088 } 089 090 /** 091 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk 092 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier 093 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be 094 * used to refer to the GPG signature of an artifact. 095 * 096 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. 097 * @param classifier The classifier for this artifact, may be {@code null} if none. 098 * @param extension The extension for this artifact, may be {@code null} if none. 099 * @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}