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.transfer;
020
021import java.io.File;
022import java.nio.file.Path;
023
024import org.eclipse.aether.RequestTrace;
025
026/**
027 * Describes a resource being uploaded or downloaded by the repository system.
028 */
029public final class TransferResource {
030
031    private final String repositoryId;
032
033    private final String repositoryUrl;
034
035    private final String resourceName;
036
037    private final Path path;
038
039    private final long startTime;
040
041    private final RequestTrace trace;
042
043    private long contentLength = -1L;
044
045    private long resumeOffset;
046
047    /**
048     * Creates a new transfer resource with the specified properties.
049     *
050     * @param repositoryId The ID of the repository used to transfer the resource, may be {@code null} or
051     *                     empty if unknown.
052     * @param repositoryUrl The base URL of the repository, may be {@code null} or empty if unknown. If not empty, a
053     *            trailing slash will automatically be added if missing.
054     * @param resourceName The relative path to the resource within the repository, may be {@code null}. A leading slash
055     *            (if any) will be automatically removed.
056     * @param file The source/target file involved in the transfer, may be {@code null}.
057     * @param trace The trace information, may be {@code null}.
058     *
059     * @since 1.1.0
060     * @deprecated Use {@link TransferResource(String, String, String, Path, RequestTrace)} instead.
061     */
062    @Deprecated
063    public TransferResource(
064            String repositoryId, String repositoryUrl, String resourceName, File file, RequestTrace trace) {
065        this(repositoryId, repositoryUrl, resourceName, file != null ? file.toPath() : null, trace);
066    }
067
068    /**
069     * Creates a new transfer resource with the specified properties.
070     *
071     * @param repositoryId The ID of the repository used to transfer the resource, may be {@code null} or
072     *                     empty if unknown.
073     * @param repositoryUrl The base URL of the repository, may be {@code null} or empty if unknown. If not empty, a
074     *            trailing slash will automatically be added if missing.
075     * @param resourceName The relative path to the resource within the repository, may be {@code null}. A leading slash
076     *            (if any) will be automatically removed.
077     * @param path The source/target file involved in the transfer, may be {@code null}.
078     * @param trace The trace information, may be {@code null}.
079     *
080     * @since 2.0.0
081     */
082    public TransferResource(
083            String repositoryId, String repositoryUrl, String resourceName, Path path, RequestTrace trace) {
084        if (repositoryId == null || repositoryId.isEmpty()) {
085            this.repositoryId = "";
086        } else {
087            this.repositoryId = repositoryId;
088        }
089
090        if (repositoryUrl == null || repositoryUrl.isEmpty()) {
091            this.repositoryUrl = "";
092        } else if (repositoryUrl.endsWith("/")) {
093            this.repositoryUrl = repositoryUrl;
094        } else {
095            this.repositoryUrl = repositoryUrl + '/';
096        }
097
098        if (resourceName == null || resourceName.isEmpty()) {
099            this.resourceName = "";
100        } else if (resourceName.startsWith("/")) {
101            this.resourceName = resourceName.substring(1);
102        } else {
103            this.resourceName = resourceName;
104        }
105
106        this.path = path;
107
108        this.trace = trace;
109
110        startTime = System.currentTimeMillis();
111    }
112
113    /**
114     * The ID of the repository, e.g., "central".
115     *
116     * @return The ID of the repository or an empty string if unknown, never {@code null}.
117     *
118     * @since 1.1.0
119     */
120    public String getRepositoryId() {
121        return repositoryId;
122    }
123
124    /**
125     * The base URL of the repository, e.g. "https://repo1.maven.org/maven2/". Unless the URL is unknown, it will be
126     * terminated by a trailing slash.
127     *
128     * @return The base URL of the repository or an empty string if unknown, never {@code null}.
129     */
130    public String getRepositoryUrl() {
131        return repositoryUrl;
132    }
133
134    /**
135     * The path of the resource relative to the repository's base URL, e.g. "org/apache/maven/maven/3.0/maven-3.0.pom".
136     *
137     * @return The path of the resource, never {@code null}.
138     */
139    public String getResourceName() {
140        return resourceName;
141    }
142
143    /**
144     * Gets the local file being uploaded or downloaded. When the repository system merely checks for the existence of a
145     * remote resource, no local file will be involved in the transfer.
146     *
147     * @return The source/target file involved in the transfer or {@code null} if none.
148     * @deprecated Use {@link #getPath()} instead.
149     */
150    @Deprecated
151    public File getFile() {
152        return path != null ? path.toFile() : null;
153    }
154
155    /**
156     * Gets the local file being uploaded or downloaded. When the repository system merely checks for the existence of a
157     * remote resource, no local file will be involved in the transfer.
158     *
159     * @return The source/target file involved in the transfer or {@code null} if none.
160     * @since 2.0.0
161     */
162    public Path getPath() {
163        return path;
164    }
165
166    /**
167     * The size of the resource in bytes. Note that the size of a resource during downloads might be unknown to the
168     * client which is usually the case when transfers employ compression like gzip. In general, the content length is
169     * not known until the transfer has {@link TransferListener#transferStarted(TransferEvent) started}.
170     *
171     * @return The size of the resource in bytes or a negative value if unknown.
172     */
173    public long getContentLength() {
174        return contentLength;
175    }
176
177    /**
178     * Sets the size of the resource in bytes.
179     *
180     * @param contentLength The size of the resource in bytes or a negative value if unknown.
181     * @return This resource for chaining, never {@code null}.
182     */
183    public TransferResource setContentLength(long contentLength) {
184        this.contentLength = contentLength;
185        return this;
186    }
187
188    /**
189     * Gets the byte offset within the resource from which the download starts. A positive offset indicates a previous
190     * download attempt is being resumed, {@code 0} means the transfer starts at the first byte.
191     *
192     * @return The zero-based index of the first byte being transferred, never negative.
193     */
194    public long getResumeOffset() {
195        return resumeOffset;
196    }
197
198    /**
199     * Sets the byte offset within the resource at which the download starts.
200     *
201     * @param resumeOffset The zero-based index of the first byte being transferred, must not be negative.
202     * @return This resource for chaining, never {@code null}.
203     */
204    public TransferResource setResumeOffset(long resumeOffset) {
205        if (resumeOffset < 0L) {
206            throw new IllegalArgumentException("resume offset cannot be negative");
207        }
208        this.resumeOffset = resumeOffset;
209        return this;
210    }
211
212    /**
213     * Gets the timestamp when the transfer of this resource was started.
214     *
215     * @return The timestamp when the transfer of this resource was started.
216     */
217    public long getTransferStartTime() {
218        return startTime;
219    }
220
221    /**
222     * Gets the trace information that describes the higher level request/operation during which this resource is
223     * transferred.
224     *
225     * @return The trace information about the higher level operation or {@code null} if none.
226     */
227    public RequestTrace getTrace() {
228        return trace;
229    }
230
231    @Override
232    public String toString() {
233        return getRepositoryUrl() + getResourceName() + " <> " + getPath();
234    }
235}