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