Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / files / AppEngineFile.java
blob83a21fe0793a77ebeda292587a67c115698a4911
1 // Copyright 2010 Google Inc. All Rights Reserved.
3 package com.google.appengine.api.files;
5 import com.google.appengine.api.blobstore.BlobKey;
6 import com.google.common.base.Preconditions;
8 import java.io.Serializable;
9 import java.util.regex.Matcher;
10 import java.util.regex.Pattern;
12 /**
13 * An {@code AppEngineFile} represents a file in one of the Google App Engine
14 * file systems.
15 * <p>
16 * A file has a <b>path</b> of the form {@code /<fileSystem>/<namePart> }. The
17 * path consists of a <b>file system</b> which is one of several identifiers for
18 * a Google App Engine file system, and a <b>name part</b> wich is an arbitrary
19 * String. For example "/blobstore/Aie7uHVwtvM" is a path in which "blobstore"
20 * is the file system and "Aie7uHVwtvM" is the name part.
21 * <p>
22 * The enum {@link FileSystem} represents the available file systems. Each file
23 * system has particular attributes regarding permanence, reliability
24 * availability, and cost.
25 * <p>
26 * In the current release of Google App Engine, {@link FileSystem#BLOBSTORE
27 * BLOBSTORE} and {@link FileSystem#GS GS} are the only available file systems.
28 * These file systems store files as blobs in the BlobStore and in Google Storage
29 * respectively.
30 * <p>
31 * App Engine files may only be accessed using a particular access pattern:
32 * Newly created files may be <b>appended</b> to until they are
33 * <b>finalized</b>. After a file is finalized it may be read, but it may no
34 * longer be written.
35 * <p>
36 * To create a new {@code BLOBSTORE} file use
37 * {@link FileService#createNewBlobFile(String)}. This returns an instance of
38 * {@code AppEngineFile} with a {@code FileSystem} of {@code BLOBSTORE}.
40 * <p>
41 * To create a new {@code GS} file use
42 * {@link FileService#createNewGSFile(GSFileOptions)}. This returns an
43 * instance of {@code AppEngineFile} with a {@code FileSystem} of {@code GS}.
44 * This instance cannot be used for reading. For a full file lifecycle
45 * example, see {@link FileService}.
48 @Deprecated
49 public class AppEngineFile implements Serializable {
51 private static final String fullPathRegex = "^/([^/]+)/(.+)$";
52 private static final Pattern fullPathPattern = Pattern.compile(fullPathRegex);
54 /**
55 * Represents the back-end storage location of a file.
57 public static enum FileSystem {
58 /**
59 * This file system stores files as blobs in the App Engine BlobStore. The
60 * full path of a file from this file system is of the form
61 * {@code /blobstore/<identifier>} where {@code <identifier>} is an opaque String
62 * generated by the BlobStore.
64 BLOBSTORE("blobstore"),
66 /**
67 * This file system stores files in Google Storage.
68 * Files in this file system use one path for writing and one path for
69 * reading. The full path for a writable GS file is {@code /gs/<identifier>}
70 * where {@code <identifier>} is an opaque String generated by Google Storage. The
71 * full path for a readable GS file is {@code /gs/<bucket>/<key>} where
72 * {@code <bucket>} and {@code <key>} are user-specified names. See comments at
73 * the top of {@link FileService}.
75 GS("gs");
77 private String name;
79 private FileSystem(String fsn) {
80 this.name = fsn;
83 /**
84 * Returns the name of the file system.
86 public String getName() {
87 return name;
90 /**
91 * Returns the {@code FileSystem} with the given name.
93 * @throws IllegalArgumentException if the given name is not the name of any
94 * of the file systems.
96 public static FileSystem fromName(String name) {
97 for (FileSystem fs : FileSystem.values()) {
98 if (fs.getName().equals(name)) {
99 return fs;
102 throw new IllegalArgumentException(name + " is not the name of a file system.");
106 private String namePart;
107 private String fullPath;
108 private FileSystem fileSystem;
110 private BlobKey cachedBlobKey;
113 * Constructs an {@code AppEngineFile} from the given data
115 * @param fileSystem a {@code non-null FileSystem}.
116 * @param namePart a {@code non-null} name part. Warning: Do not use the full
117 * path here.
119 public AppEngineFile(FileSystem fileSystem, String namePart) {
120 this("/" + fileSystem.getName() + "/" + checkNamePart(namePart), fileSystem, namePart);
123 private static String checkNamePart(String namePart) {
124 Preconditions.checkNotNull(namePart, "namePart");
125 namePart = namePart.trim();
126 Preconditions.checkArgument(!namePart.isEmpty(), "namePart is empty");
127 return namePart;
131 * Constructs an {@code AppEngineFile} from the given data
133 * @param fullPath a {@code non-null} full path. Warning: Do not use a name
134 * part here.
136 public AppEngineFile(String fullPath) {
137 this(fullPath, null, null);
141 * Constructs an {@code AppEngineFile} from the given data.
143 * @param fullPath the {@code non-null} full path.
144 * @param fileSystem if this is {@code null} it will be parsed from {@code
145 * fullPath} and an {@code IllegalArgumentException} will be thrown if
146 * the parsing fails. If this is not {@code null} it is the caller's
147 * responsibility to ensure that it matches {@code fullPath}, no
148 * checking will be done.
149 * @param namePart The same comment from {@code fileSystem} applies to this
150 * parameter.
152 private AppEngineFile(String fullPath, FileSystem fileSystem, String namePart) {
153 Preconditions.checkNotNull(fullPath, "fullPath");
154 fullPath = fullPath.trim();
155 Preconditions.checkArgument(!fullPath.isEmpty(), "fullPath is empty");
156 this.namePart = namePart;
157 this.fullPath = fullPath;
158 this.fileSystem = fileSystem;
159 if (null == fileSystem || null == namePart) {
160 parseFullPath();
165 * Throws {@code IllegalArgumentException} if {@code fullPath} cannot be
166 * parsed into a file system and a name part.
168 private void parseFullPath() {
169 Matcher m = fullPathPattern.matcher(fullPath);
170 if (!m.matches()) {
171 throw new IllegalArgumentException(fullPath + " is not a valid path");
173 String fileSystemString = m.group(1);
174 fileSystem = FileSystem.fromName(fileSystemString);
175 namePart = m.group(2);
179 * Returns the name part of the file.
181 public String getNamePart() {
182 return namePart;
186 * Returns the full path of the file.
188 public String getFullPath() {
189 return fullPath;
193 * Returns the file system of the file.
195 public FileSystem getFileSystem() {
196 return fileSystem;
199 @Override
200 public String toString() {
201 return fullPath;
204 BlobKey getCachedBlobKey(){
205 return cachedBlobKey;
208 void setCachedBlobKey(BlobKey key){
209 this.cachedBlobKey = key;
213 * Returns a boolean indicating whether or not this instance can be used for
214 * writing.
216 public boolean isWritable() {
217 if (fileSystem == FileSystem.GS) {
218 return namePart.startsWith(FileServiceImpl.GS_CREATION_HANDLE_PREFIX);
220 return true;
224 * Returns a boolean indicating whether or not this instance can be used for
225 * reading.
227 public boolean isReadable() {
228 if (fileSystem == FileSystem.GS) {
229 return !namePart.startsWith(FileServiceImpl.GS_CREATION_HANDLE_PREFIX);
231 return true;
235 * @return a boolean indicating whether or not this instance has a finalized
236 * filename.
238 public boolean hasFinalizedName() {
239 return !namePart.startsWith(FileServiceImpl.CREATION_HANDLE_PREFIX) &&
240 !namePart.startsWith(FileServiceImpl.GS_CREATION_HANDLE_PREFIX);