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.transport;
020
021import java.io.*;
022import java.net.URI;
023import java.nio.charset.StandardCharsets;
024import java.nio.file.Files;
025import java.nio.file.Path;
026
027/**
028 * A task to upload a resource to the remote repository.
029 *
030 * @see Transporter#put(PutTask)
031 */
032public final class PutTask extends TransportTask {
033
034    private Path dataPath;
035
036    private byte[] dataBytes = EMPTY;
037
038    /**
039     * Creates a new task for the specified remote resource.
040     *
041     * @param location The relative location of the resource in the remote repository, must not be {@code null}.
042     */
043    public PutTask(URI location) {
044        setLocation(location);
045    }
046
047    /**
048     * Opens an input stream for the data to be uploaded. The length of the stream can be queried via
049     * {@link #getDataLength()}. It's the responsibility of the caller to close the provided stream.
050     *
051     * @return The input stream for the data, never {@code null}. The stream is unbuffered.
052     * @throws IOException If the stream could not be opened.
053     */
054    public InputStream newInputStream() throws IOException {
055        if (dataPath != null) {
056            return Files.newInputStream(dataPath);
057        }
058        return new ByteArrayInputStream(dataBytes);
059    }
060
061    /**
062     * Gets the total number of bytes to be uploaded.
063     *
064     * @return The total number of bytes to be uploaded.
065     */
066    public long getDataLength() {
067        if (dataPath != null) {
068            try {
069                return Files.size(dataPath);
070            } catch (IOException e) {
071                throw new UncheckedIOException(e);
072            }
073        }
074        return dataBytes.length;
075    }
076
077    /**
078     * Gets the file (if any) with the data to be uploaded.
079     *
080     * @return The data file or {@code null} if the data resides in memory.
081     * @deprecated Use {@link #getDataPath()} instead.
082     */
083    @Deprecated
084    public File getDataFile() {
085        return dataPath != null ? dataPath.toFile() : null;
086    }
087
088    /**
089     * Gets the file (if any) with the data to be uploaded.
090     *
091     * @return The data file or {@code null} if the data resides in memory.
092     * @since 2.0.0
093     */
094    public Path getDataPath() {
095        return dataPath;
096    }
097
098    /**
099     * Sets the file with the data to be uploaded. To upload some data residing already in memory, use
100     * {@link #setDataString(String)} or {@link #setDataBytes(byte[])}.
101     *
102     * @param dataFile The data file, may be {@code null} if the resource data is provided directly from memory.
103     * @return This task for chaining, never {@code null}.
104     * @deprecated Use {@link #setDataPath(Path)} instead.
105     */
106    @Deprecated
107    public PutTask setDataFile(File dataFile) {
108        return setDataPath(dataFile.toPath());
109    }
110
111    /**
112     * Sets the file with the data to be uploaded. To upload some data residing already in memory, use
113     * {@link #setDataString(String)} or {@link #setDataBytes(byte[])}.
114     *
115     * @param dataPath The data file, may be {@code null} if the resource data is provided directly from memory.
116     * @return This task for chaining, never {@code null}.
117     * @since 2.0.0
118     */
119    public PutTask setDataPath(Path dataPath) {
120        this.dataPath = dataPath;
121        dataBytes = EMPTY;
122        return this;
123    }
124
125    /**
126     * Sets the binary data to be uploaded.
127     *
128     * @param bytes The binary data, may be {@code null}.
129     * @return This task for chaining, never {@code null}.
130     */
131    public PutTask setDataBytes(byte[] bytes) {
132        this.dataBytes = (bytes != null) ? bytes : EMPTY;
133        dataPath = null;
134        return this;
135    }
136
137    /**
138     * Sets the textual data to be uploaded. The text is encoded using UTF-8 before transmission.
139     *
140     * @param str The textual data, may be {@code null}.
141     * @return This task for chaining, never {@code null}.
142     */
143    public PutTask setDataString(String str) {
144        return setDataBytes((str != null) ? str.getBytes(StandardCharsets.UTF_8) : null);
145    }
146
147    /**
148     * Sets the listener that is to be notified during the transfer.
149     *
150     * @param listener The listener to notify of progress, may be {@code null}.
151     * @return This task for chaining, never {@code null}.
152     */
153    public PutTask setListener(TransportListener listener) {
154        super.setListener(listener);
155        return this;
156    }
157
158    @Override
159    public String toString() {
160        return ">> " + getLocation();
161    }
162}