| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * 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.android.builder.internal.utils; |
| |
| import com.android.annotations.NonNull; |
| import com.android.annotations.Nullable; |
| import com.google.common.base.Objects; |
| import com.google.common.hash.HashCode; |
| import com.google.common.hash.Hashing; |
| import com.google.common.io.Files; |
| |
| import java.io.File; |
| import java.io.IOException; |
| |
| /** |
| * A cache for file contents. The cache allows closing a file and saving in memory its contents |
| * (or some related information). It can then be used to check if the contents are still valid |
| * at some later time. Typical usage flow is: |
| * |
| * <p> |
| * <pre> |
| * Object fileRepresentation = // ... |
| * File toWrite = // ... |
| * // Write file contents and update in memory representation |
| * CachedFileContents<Object> contents = new CachedFileContents<Object>(toWrite); |
| * contents.closed(fileRepresentation); |
| * |
| * // Later, when data is needed: |
| * if (contents.isValid()) { |
| * fileRepresentation = contents.getCache(); |
| * } else { |
| * // Re-read the file and recreate the file representation |
| * } |
| * </pre> |
| * @param <T> the type of cached contents |
| */ |
| public class CachedFileContents<T> { |
| |
| /** |
| * The file. |
| */ |
| @NonNull |
| private File mFile; |
| |
| /** |
| * Time when last closed (time when {@link #closed(Object)} was invoked). |
| */ |
| private long mLastClosed; |
| |
| /** |
| * Size of the file when last closed. |
| */ |
| private long mSize; |
| |
| /** |
| * Hash of the file when closed. {@code null} if hashing failed for some reason. |
| */ |
| @Nullable |
| private HashCode mHash; |
| |
| /** |
| * Cached data associated with the file. |
| */ |
| @Nullable |
| private T mCache; |
| |
| /** |
| * Creates a new contents. When the file is written, {@link #closed(Object)} should be invoked |
| * to set the cache. |
| * |
| * @param file the file |
| */ |
| public CachedFileContents(@NonNull File file) { |
| mFile = file; |
| } |
| |
| /** |
| * Should be called when the file's contents are set and the file closed. This will save the |
| * cache and register the file's timestamp to later detect if it has been modified. |
| * <p> |
| * This method can be called as many times as the file has been written. |
| * |
| * @param cache an optional cache to save |
| */ |
| public void closed(@Nullable T cache) { |
| mCache = cache; |
| mLastClosed = mFile.lastModified(); |
| mSize = mFile.length(); |
| mHash = hashFile(); |
| } |
| |
| /** |
| * Are the cached contents still valid? If this method determines that the file has been |
| * modified since the last time {@link #closed(Object)} was invoked. |
| * |
| * @return are the cached contents still valid? If this method returns {@code false}, the |
| * cache is cleared |
| */ |
| public boolean isValid() { |
| boolean valid = true; |
| |
| if (!mFile.exists()) { |
| valid = false; |
| } |
| |
| if (valid && mFile.lastModified() != mLastClosed) { |
| valid = false; |
| } |
| |
| if (valid && mFile.length() != mSize) { |
| valid = false; |
| } |
| |
| if (valid && !Objects.equal(mHash, hashFile())) { |
| valid = false; |
| } |
| |
| if (!valid) { |
| mCache = null; |
| } |
| |
| return valid; |
| } |
| |
| /** |
| * Obtains the cached data set with {@link #closed(Object)} if the file has not been modified |
| * since {@link #closed(Object)} was invoked. |
| * |
| * @return the last cached data or {@code null} if the file has been modified since |
| * {@link #closed(Object)} has been invoked |
| */ |
| @Nullable |
| public T getCache() { |
| return mCache; |
| } |
| |
| /** |
| * Computes the hashcode of the cached file. |
| * |
| * @return the hash code |
| */ |
| @Nullable |
| private HashCode hashFile() { |
| try { |
| return Files.hash(mFile, Hashing.crc32()); |
| } catch (IOException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Obtains the file used for caching. |
| * |
| * @return the file; this file always exists and contains the old (cached) contents of the |
| * file |
| */ |
| @NonNull |
| public File getFile() { |
| return mFile; |
| } |
| } |