001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.deployment.remote;
017:
018: import javax.servlet.http.HttpServlet;
019: import javax.servlet.http.HttpServletRequest;
020: import javax.servlet.http.HttpServletResponse;
021: import javax.servlet.ServletException;
022: import java.io.DataOutputStream;
023: import java.io.DataInputStream;
024: import java.io.File;
025: import java.io.IOException;
026: import java.io.BufferedOutputStream;
027: import java.io.FileOutputStream;
028:
029: /**
030: * A servlet that accepts file uploads. It takes only POST requests, which should
031: * contain a Java "DataOutput" formatted stream from RemoteDeployUtil containing:
032: *
033: * RemoteDeployer data stream format:
034: * 0) an int, the version of this datastream format - REMOTE_DEPLOY_REQUEST_VER
035: * 1) an int, the number of files being uploaded
036: * 2) for each file:
037: * 2.0) a UTF String, the filename of the file being uploaded
038: * 2.1) a long, the length of the file in bytes
039: * 2.2) byte[], byte count equal to the number above for the file
040: *
041: * RemoteDeployer response stream format:
042: * It returns a serialized stream containing:
043: * 0) an int, the version of this datastream format - REMOTE_DEPLOY_RESPONSE_VER
044: * 1) a UTF string, the status (should be "OK")
045: * 2) an int, the number of files received
046: * 3) for each file:
047: * 3.1) a UTF String, the path to the file as saved to the server's filesystem
048: *
049: * The file positions in the response will be the same as in the request.
050: * That is, a name for upload file #2 will be in response position #2.
051: *
052: * @version $Rev: 567944 $ $Date: 2007-08-20 21:22:33 -0700 (Mon, 20 Aug 2007) $
053: */
054: public class FileUploadServlet extends HttpServlet {
055:
056: /** Note: The below versions should be kept in sync with those in RemoteDeployUtil.java **/
057: // Starting RemoteDeploy datastream versions
058: public static final int REMOTE_DEPLOY_REQUEST_VER_0 = 0;
059: public static final int REMOTE_DEPLOY_RESPONSE_VER_0 = 0;
060: // Current RemoteDeploy datastream versions
061: public static final int REMOTE_DEPLOY_REQUEST_VER = 0;
062: public static final int REMOTE_DEPLOY_RESPONSE_VER = 0;
063:
064: protected void doPost(HttpServletRequest request,
065: HttpServletResponse response) throws ServletException,
066: IOException {
067: int fileCount = 0, filesCreated = 0;
068: String names[] = null;
069: String status = "OK";
070:
071: /* --------------------
072: * RemoteDeploy Request
073: * --------------------
074: *
075: * Note: The below code has to match RemoteDeployUtil.java
076: *
077: * RemoteDeployer data stream format:
078: * 0) an int, the version of this datastream format - REMOTE_DEPLOY_REQUEST_VER
079: * 1) an int, the number of files being uploaded
080: * 2) for each file:
081: * 2.0) a UTF String, the filename of the file being uploaded
082: * 2.1) a long, the length of the file in bytes
083: * 2.2) byte[], byte count equal to the number above for the file
084: */
085: DataInputStream in = null;
086: try {
087: String fileName;
088: in = new DataInputStream(request.getInputStream());
089: // 0) an int, the version of this datastream format - REMOTE_DEPLOY_REQUEST_VER
090: int reqVer = in.readInt();
091: // whenever we update the stream version, the next line needs to
092: // be changed to just - (reqVer >= REMOTE_DEPLOY_REQUEST_VER_0)
093: // but until then, be more restrictive so we can handle old deployers
094: // that don't send a version as the first thing, but a file count instead...
095: if ((reqVer >= REMOTE_DEPLOY_REQUEST_VER_0)
096: && (reqVer <= REMOTE_DEPLOY_REQUEST_VER)) {
097: // 1) an int, the number of files being uploaded
098: fileCount = in.readInt();
099: names = new String[fileCount];
100: // 2) for each file:
101: for (int i = 0; i < fileCount; i++) {
102: // 2.0) a UTF String, the filename of the file being uploaded
103: fileName = in.readUTF();
104: // 2.1) a long, the length of the file in bytes
105: long length = in.readLong();
106: // create the local temp file
107: //File temp = File.createTempFile("remote-deploy", "");
108: // Note: Doing this because WAR files have to be their original names to
109: // handle the case where no web.xml or context root was provided
110: File temp = new File(System
111: .getProperty("java.io.tmpdir"), fileName
112: .trim());
113: temp.createNewFile();
114: temp.deleteOnExit();
115: names[i] = temp.getAbsolutePath();
116: // 2.2) raw bytes, equal to the number above for the file
117: readToFile(in, temp, length);
118: filesCreated++;
119: }
120: }
121: } catch (IOException e) {
122: status = "ERROR: " + e.getMessage();
123: } finally {
124: if (in != null) {
125: in.close();
126: in = null;
127: }
128: }
129:
130: /* ---------------------
131: * RemoteDeploy Response
132: * ---------------------
133: *
134: * Note: The below code has to match RemoteDeployUtil.java
135: *
136: * RemoteDeployer response stream format:
137: * It returns a serialized stream containing:
138: * 0) an int, the version of this datastream format - REMOTE_DEPLOY_RESPONSE_VER
139: * 1) a UTF string, the status (should be "OK")
140: * 2) an int, the number of files received
141: * 3) for each file:
142: * 3.1) a UTF String, the path to the file as saved to the server's filesystem
143: * x) new data would be added here
144: *
145: * The file positions in the response will be the same as in the request.
146: * That is, a name for upload file #2 will be in response position #2.
147: */
148: DataOutputStream out = null;
149: try {
150: out = new DataOutputStream(response.getOutputStream());
151: // 0) an int, the version of this datastream format - REMOTE_DEPLOY_RESPONSE_VER
152: out.writeInt(REMOTE_DEPLOY_RESPONSE_VER);
153: // 1) a UTF string, the status (should be "OK")
154: out.writeUTF(status);
155: if (filesCreated == fileCount) {
156: // 2) an int, the number of files received
157: out.writeInt(fileCount);
158: // 3) for each file:
159: for (int i = 0; i < names.length; i++) {
160: // 3.1) a UTF String, the path to the file as saved to the server's filesystem
161: out.writeUTF(names[i]);
162: }
163: // x) new data would be added here
164: // only send newer data depending on the REQUEST_VER that came in
165: } else {
166: // error occurred, so don't send back any filenames, just a zero count
167: // 2) an int, the number of files received
168: out.writeInt(0);
169: }
170: } finally {
171: if (out != null) {
172: out.flush();
173: out.close();
174: out = null;
175: }
176: }
177: }
178:
179: private static void readToFile(DataInputStream in, File temp,
180: long length) throws IOException {
181: BufferedOutputStream out = new BufferedOutputStream(
182: new FileOutputStream(temp));
183: int read;
184: long total;
185: try {
186: byte[] buf = new byte[8192];
187: total = 0;
188: while ((read = in.read(buf, 0, (int) Math.min(buf.length,
189: length - total))) > -1) {
190: out.write(buf, 0, read);
191: total += read;
192: if (total == length) {
193: break;
194: }
195: }
196: } finally {
197: try {
198: out.flush();
199: } catch (IOException e) {
200: }
201: out.close();
202: out = null;
203: }
204: if (total != length) {
205: throw new IOException("Unable to read entire upload file ("
206: + total + "B expecting " + length + "B)");
207: }
208: }
209: }
|