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