App Engine Python SDK version 1.7.4 (2)
[gae.git] / java / src / main / com / google / appengine / api / blobstore / BlobstoreServiceImpl.java
blobfc5c4fce661ea5c7eac278f0de9723fd167a6129
1 // Copyright 2009 Google Inc. All Rights Reserved.
3 package com.google.appengine.api.blobstore;
5 import com.google.appengine.api.blobstore.BlobstoreServicePb.BlobstoreServiceError;
6 import com.google.appengine.api.blobstore.BlobstoreServicePb.CreateEncodedGoogleStorageKeyRequest;
7 import com.google.appengine.api.blobstore.BlobstoreServicePb.CreateEncodedGoogleStorageKeyResponse;
8 import com.google.appengine.api.blobstore.BlobstoreServicePb.CreateUploadURLRequest;
9 import com.google.appengine.api.blobstore.BlobstoreServicePb.CreateUploadURLResponse;
10 import com.google.appengine.api.blobstore.BlobstoreServicePb.DeleteBlobRequest;
11 import com.google.appengine.api.blobstore.BlobstoreServicePb.FetchDataRequest;
12 import com.google.appengine.api.blobstore.BlobstoreServicePb.FetchDataResponse;
13 import com.google.apphosting.api.ApiProxy;
15 import java.util.ArrayList;
16 import java.util.Enumeration;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
21 import javax.servlet.http.HttpServletRequest;
22 import javax.servlet.http.HttpServletResponse;
24 /**
25 * {@code BlobstoreServiceImpl} is an implementation of {@link
26 * BlobstoreService} that makes API calls to {@link ApiProxy}.
29 class BlobstoreServiceImpl implements BlobstoreService {
30 static final String PACKAGE = "blobstore";
31 static final String SERVE_HEADER = "X-AppEngine-BlobKey";
32 static final String UPLOADED_BLOBKEY_ATTR = "com.google.appengine.api.blobstore.upload.blobkeys";
33 static final String BLOB_RANGE_HEADER = "X-AppEngine-BlobRange";
35 public String createUploadUrl(String successPath) {
36 return createUploadUrl(successPath, UploadOptions.Builder.withDefaults());
39 public String createUploadUrl(String successPath, UploadOptions uploadOptions) {
40 if (successPath == null) {
41 throw new NullPointerException("Success path must not be null.");
44 CreateUploadURLRequest request = new CreateUploadURLRequest();
45 request.setSuccessPath(successPath);
47 if (uploadOptions.hasMaxUploadSizeBytesPerBlob()) {
48 request.setMaxUploadSizePerBlobBytes(uploadOptions.getMaxUploadSizeBytesPerBlob());
51 if (uploadOptions.hasMaxUploadSizeBytes()) {
52 request.setMaxUploadSizeBytes(uploadOptions.getMaxUploadSizeBytes());
55 if (uploadOptions.hasGoogleStorageBucketName()) {
56 request.setGsBucketName(uploadOptions.getGoogleStorageBucketName());
59 byte[] responseBytes;
60 try {
61 responseBytes = ApiProxy.makeSyncCall(PACKAGE, "CreateUploadURL", request.toByteArray());
62 } catch (ApiProxy.ApplicationException ex) {
63 switch (BlobstoreServiceError.ErrorCode.valueOf(ex.getApplicationError())) {
64 case URL_TOO_LONG:
65 throw new IllegalArgumentException("The resulting URL was too long.");
66 case INTERNAL_ERROR:
67 throw new BlobstoreFailureException("An internal blobstore error occured.");
68 default:
69 throw new BlobstoreFailureException("An unexpected error occurred.", ex);
73 CreateUploadURLResponse response = new CreateUploadURLResponse();
74 response.mergeFrom(responseBytes);
75 return response.getUrl();
78 public void serve(BlobKey blobKey, HttpServletResponse response) {
79 serve(blobKey, (ByteRange) null, response);
82 public void serve(BlobKey blobKey, String rangeHeader, HttpServletResponse response) {
83 serve(blobKey, ByteRange.parse(rangeHeader), response);
86 public void serve(BlobKey blobKey, ByteRange byteRange, HttpServletResponse response) {
87 if (response.isCommitted()) {
88 throw new IllegalStateException("Response was already committed.");
91 response.setStatus(HttpServletResponse.SC_OK);
92 response.setHeader(SERVE_HEADER, blobKey.getKeyString());
93 if (byteRange != null) {
94 response.setHeader(BLOB_RANGE_HEADER, byteRange.toString());
98 public ByteRange getByteRange(HttpServletRequest request) {
99 @SuppressWarnings("unchecked")
100 Enumeration<String> rangeHeaders = request.getHeaders("range");
101 if (!rangeHeaders.hasMoreElements()) {
102 return null;
105 String rangeHeader = rangeHeaders.nextElement();
106 if (rangeHeaders.hasMoreElements()) {
107 throw new UnsupportedRangeFormatException("Cannot accept multiple range headers.");
110 return ByteRange.parse(rangeHeader);
113 public void delete(BlobKey... blobKeys) {
114 DeleteBlobRequest request = new DeleteBlobRequest();
115 for (BlobKey blobKey : blobKeys) {
116 request.addBlobKey(blobKey.getKeyString());
119 if (request.blobKeySize() == 0) {
120 return;
123 byte[] responseBytes;
124 try {
125 responseBytes = ApiProxy.makeSyncCall(PACKAGE, "DeleteBlob", request.toByteArray());
126 } catch (ApiProxy.ApplicationException ex) {
127 switch (BlobstoreServiceError.ErrorCode.valueOf(ex.getApplicationError())) {
128 case INTERNAL_ERROR:
129 throw new BlobstoreFailureException("An internal blobstore error occured.");
130 default:
131 throw new BlobstoreFailureException("An unexpected error occurred.", ex);
136 @Deprecated public Map<String, BlobKey> getUploadedBlobs(HttpServletRequest request) {
137 Map<String, List<BlobKey>> blobKeys = getUploads(request);
138 Map<String, BlobKey> result = new HashMap<String, BlobKey>(blobKeys.size());
140 for (Map.Entry<String, List<BlobKey>> entry : blobKeys.entrySet()) {
141 if (!entry.getValue().isEmpty()) {
142 result.put(entry.getKey(), entry.getValue().get(0));
145 return result;
148 public Map<String, List<BlobKey>> getUploads(HttpServletRequest request) {
149 @SuppressWarnings("unchecked")
150 Map<String, List<String>> attributes =
151 (Map<String, List<String>>) request.getAttribute(UPLOADED_BLOBKEY_ATTR);
152 if (attributes == null) {
153 throw new IllegalStateException("Must be called from a blob upload callback request.");
155 Map<String, List<BlobKey>> blobKeys = new HashMap<String, List<BlobKey>>(attributes.size());
156 for (Map.Entry<String, List<String>> attr : attributes.entrySet()) {
157 List<BlobKey> blobs = new ArrayList<BlobKey>(attr.getValue().size());
158 for (String key : attr.getValue()) {
159 blobs.add(new BlobKey(key));
161 blobKeys.put(attr.getKey(), blobs);
163 return blobKeys;
166 public byte[] fetchData(BlobKey blobKey, long startIndex, long endIndex) {
167 if (startIndex < 0) {
168 throw new IllegalArgumentException("Start index must be >= 0.");
171 if (endIndex < startIndex) {
172 throw new IllegalArgumentException("End index must be >= startIndex.");
175 long fetchSize = endIndex - startIndex + 1;
176 if (fetchSize > MAX_BLOB_FETCH_SIZE) {
177 throw new IllegalArgumentException("Blob fetch size " + fetchSize + " it larger " +
178 "than maximum size " + MAX_BLOB_FETCH_SIZE + " bytes.");
181 FetchDataRequest request = new FetchDataRequest();
182 request.setBlobKey(blobKey.getKeyString());
183 request.setStartIndex(startIndex);
184 request.setEndIndex(endIndex);
186 byte[] responseBytes;
187 try {
188 responseBytes = ApiProxy.makeSyncCall(PACKAGE, "FetchData", request.toByteArray());
189 } catch (ApiProxy.ApplicationException ex) {
190 switch (BlobstoreServiceError.ErrorCode.valueOf(ex.getApplicationError())) {
191 case PERMISSION_DENIED:
192 throw new SecurityException("This application does not have access to that blob.");
193 case BLOB_NOT_FOUND:
194 throw new IllegalArgumentException("Blob not found.");
195 case INTERNAL_ERROR:
196 throw new BlobstoreFailureException("An internal blobstore error occured.");
197 default:
198 throw new BlobstoreFailureException("An unexpected error occurred.", ex);
202 FetchDataResponse response = new FetchDataResponse();
203 response.mergeFrom(responseBytes);
204 return response.getDataAsBytes();
207 public BlobKey createGsBlobKey(String filename) {
209 if (!filename.startsWith("/gs/")) {
210 throw new IllegalArgumentException("Google storage filenames must be" +
211 " prefixed with /gs/");
213 CreateEncodedGoogleStorageKeyRequest request = new CreateEncodedGoogleStorageKeyRequest();
214 request.setFilename(filename);
216 byte[] responseBytes;
217 try {
218 responseBytes = ApiProxy.makeSyncCall(PACKAGE,
219 "CreateEncodedGoogleStorageKey", request.toByteArray());
220 } catch (ApiProxy.ApplicationException ex) {
221 switch (BlobstoreServiceError.ErrorCode.valueOf(ex.getApplicationError())) {
222 case INTERNAL_ERROR:
223 throw new BlobstoreFailureException("An internal blobstore error occured.");
224 default:
225 throw new BlobstoreFailureException("An unexpected error occurred.", ex);
229 CreateEncodedGoogleStorageKeyResponse response = new CreateEncodedGoogleStorageKeyResponse();
230 response.mergeFrom(responseBytes);
231 return new BlobKey(response.getBlobKey());