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; 030 031import static java.util.Objects.requireNonNull; 032 033/** 034 * Artifact GAV {@link NameMapper}, uses artifact and metadata coordinates to name their corresponding locks. Is not 035 * considering local repository, only the artifact coordinates. May use custom prefixes and suffixes and separators, 036 * hence this instance may or may not be filesystem friendly (depends on strings used). 037 */ 038public class GAVNameMapper implements NameMapper { 039 private final boolean fileSystemFriendly; 040 041 private final String artifactPrefix; 042 043 private final String artifactSuffix; 044 045 private final String metadataPrefix; 046 047 private final String metadataSuffix; 048 049 private final String fieldSeparator; 050 051 public GAVNameMapper( 052 boolean fileSystemFriendly, 053 String artifactPrefix, 054 String artifactSuffix, 055 String metadataPrefix, 056 String metadataSuffix, 057 String fieldSeparator) { 058 this.fileSystemFriendly = fileSystemFriendly; 059 this.artifactPrefix = requireNonNull(artifactPrefix); 060 this.artifactSuffix = requireNonNull(artifactSuffix); 061 this.metadataPrefix = requireNonNull(metadataPrefix); 062 this.metadataSuffix = requireNonNull(metadataSuffix); 063 this.fieldSeparator = requireNonNull(fieldSeparator); 064 } 065 066 @Override 067 public boolean isFileSystemFriendly() { 068 return fileSystemFriendly; 069 } 070 071 @Override 072 public Collection<NamedLockKey> nameLocks( 073 final RepositorySystemSession session, 074 final Collection<? extends Artifact> artifacts, 075 final Collection<? extends Metadata> metadatas) { 076 // Deadlock prevention: https://stackoverflow.com/a/16780988/696632 077 // We must acquire multiple locks always in the same order! 078 TreeSet<NamedLockKey> keys = new TreeSet<>(Comparator.comparing(NamedLockKey::name)); 079 if (artifacts != null) { 080 for (Artifact artifact : artifacts) { 081 keys.add(NamedLockKey.of( 082 getArtifactName(artifact, artifactPrefix, fieldSeparator, artifactSuffix), 083 getArtifactName(artifact, "", ":", ""))); 084 } 085 } 086 087 if (metadatas != null) { 088 for (Metadata metadata : metadatas) { 089 keys.add(NamedLockKey.of( 090 getMetadataName(metadata, metadataPrefix, fieldSeparator, metadataSuffix), 091 getMetadataName(metadata, "", ":", ""))); 092 } 093 } 094 return keys; 095 } 096 097 private static String getArtifactName(Artifact artifact, String prefix, String separator, String suffix) { 098 return prefix 099 + artifact.getGroupId() 100 + separator 101 + artifact.getArtifactId() 102 + separator 103 + artifact.getBaseVersion() 104 + suffix; 105 } 106 107 private static final String MAVEN_METADATA = "maven-metadata.xml"; 108 109 private static String getMetadataName(Metadata metadata, String prefix, String separator, String suffix) { 110 String name = prefix; 111 if (!metadata.getGroupId().isEmpty()) { 112 name += metadata.getGroupId(); 113 if (!metadata.getArtifactId().isEmpty()) { 114 name += separator + metadata.getArtifactId(); 115 if (!metadata.getVersion().isEmpty()) { 116 name += separator + metadata.getVersion(); 117 } 118 } 119 if (!MAVEN_METADATA.equals(metadata.getType())) { 120 name += separator + PathUtils.stringToPathSegment(metadata.getType()); 121 } 122 } else { 123 if (!MAVEN_METADATA.equals(metadata.getType())) { 124 name += PathUtils.stringToPathSegment(metadata.getType()); 125 } 126 } 127 return name + suffix; 128 } 129 130 public static NameMapper gav() { 131 return new GAVNameMapper(false, "artifact:", "", "metadata:", "", ":"); 132 } 133 134 public static NameMapper fileGav() { 135 return new GAVNameMapper(true, "artifact~", ".lock", "metadata~", ".lock", "~"); 136 } 137}