1 // Copyright 2011 Google Inc. All Rights Reserved.
3 package com
.google
.appengine
.tools
.admin
;
5 import com
.google
.appengine
.tools
.admin
.ServerConnection
;
6 import com
.google
.appengine
.tools
.admin
.UpdateFailureEvent
;
7 import com
.google
.appengine
.tools
.admin
.UpdateListener
;
8 import com
.google
.appengine
.tools
.admin
.UpdateProgressEvent
;
9 import com
.google
.appengine
.tools
.admin
.UpdateSuccessEvent
;
11 import java
.io
.BufferedInputStream
;
13 import java
.io
.FileNotFoundException
;
14 import java
.io
.FileOutputStream
;
15 import java
.io
.IOException
;
16 import java
.util
.HashMap
;
20 * Class to download application code.
23 public class AppDownload
{
25 private ServerConnection connection
;
26 private UpdateListener listener
;
27 private int downloadProgress
;
28 private static final char NEWLINE
= '\n';
30 public AppDownload(ServerConnection connection
, UpdateListener listener
) {
31 this.connection
= connection
;
32 this.listener
= listener
;
35 private void reportProgress(String message
) {
36 if (listener
!= null) {
37 listener
.onProgress(new UpdateProgressEvent(
38 Thread
.currentThread(), message
, downloadProgress
));
42 private void reportSuccess(String message
) {
43 if (listener
!= null) {
44 listener
.onSuccess(new UpdateSuccessEvent(message
));
48 private void reportFailure(String message
) {
49 reportFailure(message
, "");
52 private void reportFailure(String message
, String details
) {
53 if (listener
!= null) {
54 listener
.onFailure(new UpdateFailureEvent(null, message
, details
));
58 private boolean downloadFile(File outDir
, String appId
, String appVersion
, String fileId
,
59 int fileSize
, String filePath
) {
60 BufferedInputStream fileStream
;
62 fileStream
= new BufferedInputStream(
63 connection
.postAndGetInputStream("/api/files/get", "", "app_id", appId
,
64 "version", appVersion
, "id", fileId
));
65 } catch (IOException ioe
) {
66 reportFailure("Unable to download file " + filePath
, ioe
.getMessage());
70 File outFile
= new File(outDir
, filePath
);
71 File parentDir
= outFile
.getParentFile();
72 if (parentDir
!= null) {
75 } catch (SecurityException se
) {
76 reportFailure("Could not create directory " + parentDir
.getPath(), se
.getMessage());
81 int downloadedFileSize
= 0;
83 byte[] b
= new byte[4096];
84 FileOutputStream outStream
= new FileOutputStream(outFile
);
86 while ((len
= fileStream
.read(b
)) != -1) {
87 outStream
.write(b
, 0, len
);
88 downloadedFileSize
+= len
;
91 } catch (FileNotFoundException fnfe
) {
92 reportFailure("Could not create file " + outFile
.getPath(), fnfe
.getMessage());
94 } catch (IOException ioe
) {
95 reportFailure("Could not write to file " + outFile
.getPath(), ioe
.getMessage());
99 if (downloadedFileSize
!= fileSize
) {
100 reportFailure("File " + filePath
+ ": server listed as " + fileSize
101 + " bytes but served " + downloadedFileSize
+ " bytes.");
108 public boolean download(String appId
, String server
, String appVersion
, File outDir
) {
109 downloadProgress
= 0;
111 if (outDir
.exists()) {
112 if (outDir
.isFile()) {
113 reportFailure("Cannot download to path \"" + outDir
.getPath()
114 + "\": there's a file in the way.");
117 if (outDir
.list().length
> 0) {
118 reportFailure("Cannot download to path \"" + outDir
.getPath()
119 + "\": directory already exists and it isn't empty.");
124 reportProgress("Fetching file list...");
125 Map
<String
, String
> urlArgs
= new HashMap
<String
, String
>();
126 urlArgs
.put("app_id", appId
);
127 if (server
!= null) {
128 urlArgs
.put("server", server
);
130 if (appVersion
!= null) {
131 urlArgs
.put("version_match", appVersion
);
135 response
= connection
.post("/api/files/list", "", urlArgs
);
136 } catch (IOException ioe
) {
137 reportFailure("Unable to fetch file list.", ioe
.getMessage());
140 String
[] lines
= response
.split("" + NEWLINE
);
141 if (lines
.length
< 1) {
142 reportFailure("Invalid response from server: empty");
145 String fullAppVersion
= lines
[0];
147 reportProgress("Fetching files...");
148 for (int i
= 1; i
< lines
.length
; i
++) {
149 String
[] parts
= lines
[i
].split("\\|");
150 if (parts
.length
!= 3) {
151 reportFailure("Invalid response from server: expecting \"<id>|<size>|<path>\", "
152 + "found: " + lines
[i
]);
155 String fileId
= parts
[0];
158 fileSize
= Integer
.parseInt(parts
[1]);
159 } catch (NumberFormatException nfe
) {
160 reportFailure("Invalid file list entry from server: invalid size: " + parts
[1],
164 String filePath
= parts
[2];
166 reportProgress("[" + i
+ "/" + (lines
.length
- 1) + "] " + filePath
);
167 if (!downloadFile(outDir
, appId
, fullAppVersion
, fileId
, fileSize
, filePath
)) {
170 downloadProgress
= (100 * i
) / (lines
.length
- 1);