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.internal.impl.synccontext.named; 020 021import java.util.Collection; 022import java.util.Comparator; 023import java.util.TreeSet; 024 025import org.eclipse.aether.RepositorySystemSession; 026import org.eclipse.aether.artifact.Artifact; 027import org.eclipse.aether.metadata.Metadata; 028import org.eclipse.aether.named.NamedLockKey; 029import org.eclipse.aether.util.PathUtils; 030import org.eclipse.aether.util.artifact.ArtifactIdUtils; 031 032import static java.util.Objects.requireNonNull; 033 034/** 035 * Artifact GAV {@link NameMapper}, uses artifact and metadata coordinates to name their corresponding locks. Is not 036 * considering local repository, only the artifact coordinates. May use custom prefixes and suffixes and separators, 037 * hence this instance may or may not be filesystem friendly (depends on strings used). 038 * <p> 039 * Note: in earlier Resolver 1.9.x versions this mapper was the default, but it changed to {@link GAECVNameMapper} 040 * in 1.9.25. 041 */ 042public class GAVNameMapper implements NameMapper { 043 protected final boolean fileSystemFriendly; 044 045 protected final String artifactPrefix; 046 047 protected final String artifactSuffix; 048 049 protected final String metadataPrefix; 050 051 protected final String metadataSuffix; 052 053 protected final String fieldSeparator; 054 055 public GAVNameMapper( 056 boolean fileSystemFriendly, 057 String artifactPrefix, 058 String artifactSuffix, 059 String metadataPrefix, 060 String metadataSuffix, 061 String fieldSeparator) { 062 this.fileSystemFriendly = fileSystemFriendly; 063 this.artifactPrefix = requireNonNull(artifactPrefix); 064 this.artifactSuffix = requireNonNull(artifactSuffix); 065 this.metadataPrefix = requireNonNull(metadataPrefix); 066 this.metadataSuffix = requireNonNull(metadataSuffix); 067 this.fieldSeparator = requireNonNull(fieldSeparator); 068 } 069 070 @Override 071 public boolean isFileSystemFriendly() { 072 return fileSystemFriendly; 073 } 074 075 @Override 076 public Collection<NamedLockKey> nameLocks( 077 final RepositorySystemSession session, 078 final Collection<? extends Artifact> artifacts, 079 final Collection<? extends Metadata> metadatas) { 080 // Deadlock prevention: https://stackoverflow.com/a/16780988/696632 081 // We must acquire multiple locks always in the same order! 082 TreeSet<NamedLockKey> keys = new TreeSet<>(Comparator.comparing(NamedLockKey::name)); 083 if (artifacts != null) { 084 for (Artifact artifact : artifacts) { 085 keys.add(NamedLockKey.of(getArtifactName(artifact), ArtifactIdUtils.toBaseId(artifact))); 086 } 087 } 088 089 if (metadatas != null) { 090 for (Metadata metadata : metadatas) { 091 keys.add(NamedLockKey.of(getMetadataName(metadata), toMetadataId(metadata))); 092 } 093 } 094 return keys; 095 } 096 097 protected String getArtifactName(Artifact artifact) { 098 return artifactPrefix 099 + artifact.getGroupId() 100 + fieldSeparator 101 + artifact.getArtifactId() 102 + fieldSeparator 103 + artifact.getBaseVersion() 104 + artifactSuffix; 105 } 106 107 protected static final String MAVEN_METADATA = "maven-metadata.xml"; 108 109 protected String getMetadataName(Metadata metadata) { 110 String name = metadataPrefix; 111 if (!metadata.getGroupId().isEmpty()) { 112 name += metadata.getGroupId(); 113 if (!metadata.getArtifactId().isEmpty()) { 114 name += fieldSeparator + metadata.getArtifactId(); 115 if (!metadata.getVersion().isEmpty()) { 116 name += fieldSeparator + metadata.getVersion(); 117 } 118 } 119 if (!MAVEN_METADATA.equals(metadata.getType())) { 120 name += fieldSeparator 121 + (fileSystemFriendly ? PathUtils.stringToPathSegment(metadata.getType()) : metadata.getType()); 122 } 123 } else { 124 if (!MAVEN_METADATA.equals(metadata.getType())) { 125 name += (fileSystemFriendly ? PathUtils.stringToPathSegment(metadata.getType()) : metadata.getType()); 126 } 127 } 128 return name + metadataSuffix; 129 } 130 131 protected String toMetadataId(Metadata metadata) { 132 String name = ""; 133 if (!metadata.getGroupId().isEmpty()) { 134 name += metadata.getGroupId(); 135 if (!metadata.getArtifactId().isEmpty()) { 136 name += ":" + metadata.getArtifactId(); 137 if (!metadata.getVersion().isEmpty()) { 138 name += ":" + metadata.getVersion(); 139 } 140 } 141 } 142 if (!metadata.getType().isEmpty()) { 143 name += (name.isEmpty() ? "" : ":") + metadata.getType(); 144 } 145 return name; 146 } 147 148 /** 149 * @deprecated Use {@link NameMappers} to create name mappers instead. 150 */ 151 @Deprecated 152 public static NameMapper gav() { 153 return new GAVNameMapper(false, "artifact:", "", "metadata:", "", ":"); 154 } 155 156 /** 157 * @deprecated Use {@link NameMappers} to create name mappers instead. 158 */ 159 @Deprecated 160 public static NameMapper fileGav() { 161 return new GAVNameMapper(true, "artifact~", ".lock", "metadata~", ".lock", "~"); 162 } 163}