blob: cc9a1488bbdd2f14a4fc5ca44dde280cf9dbcc8d [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.libraries.mobiledatadownload;
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
/** Thrown when there is a download failure. */
public final class DownloadException extends Exception {
/** This error code is a representation of {@code MddDownloadResult.Code}. */
private final DownloadResultCode downloadResultCode;
/**
* This is the result of calling download, which should be identical to {@code
* MddDownloadResult.Code}.
*/
// LINT.IfChange
public enum DownloadResultCode {
UNSPECIFIED(0), // unset value
// File downloaded successfully.
// This is just a placeholder, we currently don't log for success case.
SUCCESS(1),
// The error we don't know.
UNKNOWN_ERROR(2),
// The errors from the android downloader outside MDD, which comes from:
// <internal>
ANDROID_DOWNLOADER_UNKNOWN(100),
ANDROID_DOWNLOADER_CANCELED(101),
ANDROID_DOWNLOADER_INVALID_REQUEST(102),
ANDROID_DOWNLOADER_HTTP_ERROR(103),
ANDROID_DOWNLOADER_REQUEST_ERROR(104),
ANDROID_DOWNLOADER_RESPONSE_OPEN_ERROR(105),
ANDROID_DOWNLOADER_RESPONSE_CLOSE_ERROR(106),
ANDROID_DOWNLOADER_NETWORK_IO_ERROR(107),
ANDROID_DOWNLOADER_DISK_IO_ERROR(108),
ANDROID_DOWNLOADER_FILE_SYSTEM_ERROR(109),
ANDROID_DOWNLOADER_UNKNOWN_IO_ERROR(110),
ANDROID_DOWNLOADER_OAUTH_ERROR(111),
// The errors from the android downloader v2 outside MDD, which comes from:
// <internal>
ANDROID_DOWNLOADER2_ERROR(200),
// The data file group has not been added to MDD by the time the caller
// makes download API call.
GROUP_NOT_FOUND_ERROR(300),
// The DownloadListener is present but the DownloadMonitor is not provided.
DOWNLOAD_MONITOR_NOT_PROVIDED_ERROR(301),
// Errors from unsatisfied download preconditions.
INSECURE_URL_ERROR(302),
LOW_DISK_ERROR(303),
// Errors from download preparation.
UNABLE_TO_CREATE_FILE_URI_ERROR(304),
SHARED_FILE_NOT_FOUND_ERROR(305),
MALFORMED_FILE_URI_ERROR(306),
UNABLE_TO_CREATE_MOBSTORE_RESPONSE_WRITER_ERROR(307),
// Errors from file validation.
UNABLE_TO_VALIDATE_DOWNLOAD_FILE_ERROR(308),
DOWNLOADED_FILE_NOT_FOUND_ERROR(309),
DOWNLOADED_FILE_CHECKSUM_MISMATCH_ERROR(310),
CUSTOM_FILEGROUP_VALIDATION_FAILED(330),
// Errors from download transforms.
UNABLE_TO_SERIALIZE_DOWNLOAD_TRANSFORM_ERROR(311),
DOWNLOAD_TRANSFORM_IO_ERROR(312),
FINAL_FILE_CHECKSUM_MISMATCH_ERROR(313),
// Errors from delta download.
DELTA_DOWNLOAD_BASE_FILE_NOT_FOUND_ERROR(314),
DELTA_DOWNLOAD_DECODE_IO_ERROR(315),
// The error occurs after the file is ready.
UNABLE_TO_UPDATE_FILE_STATE_ERROR(316),
// Fail to update the file group metadata.
UNABLE_TO_UPDATE_GROUP_METADATA_ERROR(317),
// Errors from sharing files with the blob storage.
// Failed to update the metadata max_expiration_date.
UNABLE_TO_UPDATE_FILE_MAX_EXPIRATION_DATE(318),
// Failed to share the file before SharedFileManager.startDownload is called.
UNABLE_SHARE_FILE_BEFORE_DOWNLOAD_ERROR(319),
// Failed to share the file after SharedFileManager.startDownload is called.
UNABLE_SHARE_FILE_AFTER_DOWNLOAD_ERROR(320),
// Download errors related to isolated file structure
UNABLE_TO_REMOVE_SYMLINK_STRUCTURE(321),
UNABLE_TO_CREATE_SYMLINK_STRUCTURE(322),
// Download errors related to importing inline files
// Failed to reserve file entries
UNABLE_TO_RESERVE_FILE_ENTRY(323),
// Invalid use of inlinefile url scheme
INVALID_INLINE_FILE_URL_SCHEME(324),
// Error performing inline file download
INLINE_FILE_IO_ERROR(327),
// Missing required inline download parms in FileDownloader's DownloadRequest
MISSING_INLINE_DOWNLOAD_PARAMS(328),
// Missing required inline file source in ImportFilesRequest
MISSING_INLINE_FILE_SOURCE(329),
// Download errors related to URL parsing
MALFORMED_DOWNLOAD_URL(325),
UNSUPPORTED_DOWNLOAD_URL_SCHEME(326),
// Download errors for manifest file group populator.
MANIFEST_FILE_GROUP_POPULATOR_INVALID_FLAG_ERROR(400),
MANIFEST_FILE_GROUP_POPULATOR_CONTENT_CHANGED_DURING_DOWNLOAD_ERROR(401),
MANIFEST_FILE_GROUP_POPULATOR_PARSE_MANIFEST_FILE_ERROR(402),
MANIFEST_FILE_GROUP_POPULATOR_DELETE_MANIFEST_FILE_ERROR(403),
MANIFEST_FILE_GROUP_POPULATOR_METADATA_IO_ERROR(404),
// GDD specific download errors, reserved from 2000-2999.
GDD_INVALID_ACCOUNT(2000),
GDD_INVALID_AUTH_TOKEN(2001),
GDD_FAIL_IN_SYNC_RUNNER(2002),
GDD_INVALID_ELEMENT_COMBINATION_RECEIVED(2003),
GDD_INVALID_INLINE_PAYLOAD_ELEMENT_DATA(2004),
GDD_INVALID_CURRENT_ACTIVE_ELEMENT_DATA(2005),
GDD_INVALID_NEXT_PENDING_ELEMENT_DATA(2006),
GDD_CURRENT_ACTIVE_GROUP_HAS_NO_INLINE_FILE(2007),
GDD_FAIL_TO_ADD_NEXT_PENDING_GROUP(2008),
GDD_MISSING_ACCOUNT_FOR_PRIVATE_SYNC(2009),
GDD_FAIL_IN_SYNC_RUNNER_PUBLIC(2010),
GDD_FAIL_IN_SYNC_RUNNER_PRIVATE(2011),
GDD_PUBLIC_SYNC_SUCCESS(2012),
GDD_PRIVATE_SYNC_SUCCESS(2013),
GDD_FAIL_TO_RETRIEVE_ZWIEBACK_TOKEN(2014);
private final int code;
DownloadResultCode(int code) {
this.code = code;
}
/** Returns the int code corresponding to this enum value. */
public int getCode() {
return code;
}
}
// LINT.ThenChange(<internal>)
/** Builder for {@link DownloadException}. */
public static final class Builder {
private DownloadResultCode downloadResultCode;
private String message;
private Throwable cause;
/** Sets the {@link DownloadResultCode}. */
public Builder setDownloadResultCode(DownloadResultCode downloadResultCode) {
this.downloadResultCode = downloadResultCode;
return this;
}
/** Sets the error message. */
public Builder setMessage(String message) {
this.message = message;
return this;
}
/** Sets the cause of the exception. */
public Builder setCause(Throwable cause) {
this.cause = cause;
return this;
}
/** Returns a {@link DownloadException} instance. */
public DownloadException build() {
Preconditions.checkNotNull(downloadResultCode);
if (message == null) {
message = "Download result code: " + downloadResultCode.name();
}
return new DownloadException(this);
}
}
/** Returns a Builder for {@link DownloadException}. */
public static Builder builder() {
return new Builder();
}
public DownloadResultCode getDownloadResultCode() {
return downloadResultCode;
}
/**
* Wraps the throwable with {@link DownloadException} and returns a failed future only if the
* input future fails.
*/
public static <T> ListenableFuture<T> wrapIfFailed(
ListenableFuture<T> future, DownloadResultCode code, String message) {
return Futures.catchingAsync(
future,
Throwable.class,
(Throwable t) -> immediateFailedFuture(wrap(t, code, message)),
MoreExecutors.directExecutor());
}
/** Wraps the throwable with {@link DownloadException}. */
private static DownloadException wrap(
Throwable throwable, DownloadResultCode code, String message) {
return DownloadException.builder()
.setDownloadResultCode(code)
.setMessage(message)
.setCause(throwable)
.build();
}
private DownloadException(Builder builder) {
super(builder.message, builder.cause);
this.downloadResultCode = builder.downloadResultCode;
}
}