View Javadoc
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.internal.impl.synccontext.named;
20  
21  import java.util.Collection;
22  import java.util.Comparator;
23  import java.util.TreeSet;
24  
25  import org.eclipse.aether.RepositorySystemSession;
26  import org.eclipse.aether.artifact.Artifact;
27  import org.eclipse.aether.metadata.Metadata;
28  import org.eclipse.aether.named.NamedLockKey;
29  import org.eclipse.aether.util.PathUtils;
30  import org.eclipse.aether.util.artifact.ArtifactIdUtils;
31  
32  import static java.util.Objects.requireNonNull;
33  
34  /**
35   * Artifact GAV {@link NameMapper}, uses artifact and metadata coordinates to name their corresponding locks. Is not
36   * considering local repository, only the artifact coordinates. May use custom prefixes and suffixes and separators,
37   * hence this instance may or may not be filesystem friendly (depends on strings used).
38   * <p>
39   * Note: in earlier Resolver 1.9.x versions this mapper was the default, but it changed to {@link GAECVNameMapper}
40   * in 1.9.25.
41   */
42  public class GAVNameMapper implements NameMapper {
43      protected final boolean fileSystemFriendly;
44  
45      protected final String artifactPrefix;
46  
47      protected final String artifactSuffix;
48  
49      protected final String metadataPrefix;
50  
51      protected final String metadataSuffix;
52  
53      protected final String fieldSeparator;
54  
55      public GAVNameMapper(
56              boolean fileSystemFriendly,
57              String artifactPrefix,
58              String artifactSuffix,
59              String metadataPrefix,
60              String metadataSuffix,
61              String fieldSeparator) {
62          this.fileSystemFriendly = fileSystemFriendly;
63          this.artifactPrefix = requireNonNull(artifactPrefix);
64          this.artifactSuffix = requireNonNull(artifactSuffix);
65          this.metadataPrefix = requireNonNull(metadataPrefix);
66          this.metadataSuffix = requireNonNull(metadataSuffix);
67          this.fieldSeparator = requireNonNull(fieldSeparator);
68      }
69  
70      @Override
71      public boolean isFileSystemFriendly() {
72          return fileSystemFriendly;
73      }
74  
75      @Override
76      public Collection<NamedLockKey> nameLocks(
77              final RepositorySystemSession session,
78              final Collection<? extends Artifact> artifacts,
79              final Collection<? extends Metadata> metadatas) {
80          // Deadlock prevention: https://stackoverflow.com/a/16780988/696632
81          // We must acquire multiple locks always in the same order!
82          TreeSet<NamedLockKey> keys = new TreeSet<>(Comparator.comparing(NamedLockKey::name));
83          if (artifacts != null) {
84              for (Artifact artifact : artifacts) {
85                  keys.add(NamedLockKey.of(getArtifactName(artifact), ArtifactIdUtils.toBaseId(artifact)));
86              }
87          }
88  
89          if (metadatas != null) {
90              for (Metadata metadata : metadatas) {
91                  keys.add(NamedLockKey.of(getMetadataName(metadata), toMetadataId(metadata)));
92              }
93          }
94          return keys;
95      }
96  
97      protected String getArtifactName(Artifact artifact) {
98          return artifactPrefix
99                  + 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 }