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.spi.connector.layout;
020
021import java.net.URI;
022import java.util.List;
023
024import org.eclipse.aether.artifact.Artifact;
025import org.eclipse.aether.metadata.Metadata;
026import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
027
028import static java.util.Objects.requireNonNull;
029
030/**
031 * The layout for a remote repository whose artifacts/metadata can be addressed via URIs.
032 * <p>
033 * <strong>Note:</strong> Implementations must be stateless.
034 */
035public interface RepositoryLayout {
036
037    /**
038     * A descriptor for a checksum location. This descriptor simply associates the location of a checksum file with the
039     * underlying checksum algorithm used to calculate/verify it.
040     */
041    final class ChecksumLocation {
042        private final URI location;
043
044        private final ChecksumAlgorithmFactory checksumAlgorithmFactory;
045
046        /**
047         * Creates a new checksum file descriptor with the specified algorithm and location. The method
048         * {@link #forLocation(URI, ChecksumAlgorithmFactory)} is usually more convenient though.
049         *
050         * @param location                 The relative URI to the checksum file within a repository, must not be {@code
051         *                                 null}.
052         * @param checksumAlgorithmFactory The checksum type used to calculate the checksum, must not be {@code null}.
053         */
054        public ChecksumLocation(URI location, ChecksumAlgorithmFactory checksumAlgorithmFactory) {
055            verify(location, checksumAlgorithmFactory);
056            this.location = location;
057            this.checksumAlgorithmFactory = checksumAlgorithmFactory;
058        }
059
060        /**
061         * Creates a checksum descriptor for the specified artifact/metadata location and algorithm. The location
062         * of the checksum file itself is derived from the supplied resource URI by appending the file extension
063         * specified by the algorithm factory. See {@link ChecksumAlgorithmFactory#getFileExtension()}.
064         *
065         * @param location                 The relative URI to the artifact/metadata whose checksum file is being
066         *                                 obtained, must not be
067         *                                 {@code null} and must not have a query or fragment part.
068         * @param checksumAlgorithmFactory The algorithm used to calculate the checksum, must not be {@code null}.
069         * @return The checksum file descriptor, never {@code null}.
070         */
071        public static ChecksumLocation forLocation(URI location, ChecksumAlgorithmFactory checksumAlgorithmFactory) {
072            verify(location, checksumAlgorithmFactory);
073            if (location.getRawQuery() != null) {
074                throw new IllegalArgumentException("resource location must not have query parameters: " + location);
075            }
076            if (location.getRawFragment() != null) {
077                throw new IllegalArgumentException("resource location must not have a fragment: " + location);
078            }
079            return new ChecksumLocation(
080                    URI.create(location + "." + checksumAlgorithmFactory.getFileExtension()), checksumAlgorithmFactory);
081        }
082
083        private static void verify(URI location, ChecksumAlgorithmFactory checksumAlgorithmFactory) {
084            requireNonNull(location, "checksum location cannot be null");
085            if (location.isAbsolute()) {
086                throw new IllegalArgumentException("checksum location must be relative");
087            }
088            requireNonNull(checksumAlgorithmFactory, "checksum algorithm factory cannot be null");
089        }
090
091        /**
092         * Gets the {@link ChecksumAlgorithmFactory} that is used to calculate the checksum.
093         *
094         * @return The checksum factory, never {@code null}.
095         */
096        public ChecksumAlgorithmFactory getChecksumAlgorithmFactory() {
097            return checksumAlgorithmFactory;
098        }
099
100        /**
101         * Gets the location of the checksum file with a remote repository. The URI is relative to the root directory of
102         * the repository.
103         *
104         * @return The relative URI to the checksum file, never {@code null}.
105         */
106        public URI getLocation() {
107            return location;
108        }
109
110        @Override
111        public String toString() {
112            return location + " (" + checksumAlgorithmFactory.getName() + ")";
113        }
114    }
115
116    /**
117     * Returns immutable list of {@link ChecksumAlgorithmFactory} this instance of layout uses, never {@code null}.
118     * The order also represents the order how remote external checksums are retrieved and validated.
119     *
120     * @see org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind
121     * @since 1.8.0
122     */
123    List<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories();
124
125    /**
126     * Tells whether given artifact have remote external checksums according to current layout or not. If it returns
127     * {@code true}, then layout configured checksums will be expected: on upload they will be calculated and deployed
128     * along artifact, on download they will be retrieved and validated.
129     *
130     * If it returns {@code false} the given artifacts will have checksums omitted: on upload they will not be
131     * calculated and deployed, and on download they will be not retrieved nor validated.
132     *
133     * The result affects only layout provided checksums. See
134     * {@link org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind#REMOTE_EXTERNAL}.
135     * On download, the {@link org.eclipse.aether.spi.connector.layout.RepositoryLayout#getChecksumAlgorithmFactories()}
136     * layout required checksums are calculated, and non layout-provided checksums are still utilized.
137     *
138     * Typical case to return {@code false} (to omit checksums) is for artifact signatures, that are already a
139     * "sub-artifact" of some main artifact (for example a JAR), and they can be validated by some other means.
140     *
141     * @see org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind
142     * @see #getChecksumAlgorithmFactories()
143     * @since 1.8.0
144     */
145    boolean hasChecksums(Artifact artifact);
146
147    /**
148     * Gets the location within a remote repository where the specified artifact resides. The URI is relative to the
149     * root directory of the repository.
150     *
151     * @param artifact The artifact to get the URI for, must not be {@code null}.
152     * @param upload   {@code false} if the artifact is being downloaded, {@code true} if the artifact is being
153     *                 uploaded.
154     * @return The relative URI to the artifact, never {@code null}.
155     */
156    URI getLocation(Artifact artifact, boolean upload);
157
158    /**
159     * Gets the location within a remote repository where the specified metadata resides. The URI is relative to the
160     * root directory of the repository.
161     *
162     * @param metadata The metadata to get the URI for, must not be {@code null}.
163     * @param upload   {@code false} if the metadata is being downloaded, {@code true} if the metadata is being
164     *                 uploaded.
165     * @return The relative URI to the metadata, never {@code null}.
166     */
167    URI getLocation(Metadata metadata, boolean upload);
168
169    /**
170     * Gets the checksums files that a remote repository keeps to help detect data corruption during transfers of the
171     * specified artifact.
172     *
173     * @param artifact The artifact to get the checksum files for, must not be {@code null}.
174     * @param upload   {@code false} if the checksums are being downloaded/verified, {@code true} if the checksums are
175     *                 being uploaded/created.
176     * @param location The relative URI to the artifact within the repository as previously obtained from
177     *                 {@link #getLocation(Artifact, boolean)}, must not be {@code null}.
178     * @return The checksum files for the given artifact, possibly empty but never {@code null}. If empty, that means
179     * that this layout does not provide checksums for given artifact.
180     */
181    List<ChecksumLocation> getChecksumLocations(Artifact artifact, boolean upload, URI location);
182
183    /**
184     * Gets the checksums files that a remote repository keeps to help detect data corruption during transfers of the
185     * specified metadata.
186     *
187     * @param metadata The metadata to get the checksum files for, must not be {@code null}.
188     * @param upload   {@code false} if the checksums are being downloaded/verified, {@code true} if the checksums are
189     *                 being uploaded/created.
190     * @param location The relative URI to the metadata within the repository as previously obtained from
191     *                 {@link #getLocation(Metadata, boolean)}, must not be {@code null}.
192     * @return The checksum files for the given metadata, possibly empty but never {@code null}. If empty, that means
193     * that this layout does not provide checksums for given artifact.
194     */
195    List<ChecksumLocation> getChecksumLocations(Metadata metadata, boolean upload, URI location);
196}