001: /**
002: * $Id: NetFileUploadServlet.java,v 1.34 2005/11/30 11:26:35 ss150821 Exp $
003: * Copyright 2002 Sun Microsystems, Inc. All
004: * rights reserved. Use of this product is subject
005: * to license terms. Federal Acquisitions:
006: * Commercial Software -- Government Users
007: * Subject to Standard License Terms and
008: * Conditions.
009: *
010: * Sun, Sun Microsystems, the Sun logo, and Sun ONE
011: * are trademarks or registered trademarks of Sun Microsystems,
012: * Inc. in the United States and other countries.
013: */package com.sun.portal.netfile.servlet.java1;
014:
015: import java.io.*;
016: import com.sun.portal.log.common.PortalLogger;
017: import java.util.*;
018: import java.util.logging.*;
019: import javax.servlet.*;
020: import javax.servlet.http.*;
021: import com.iplanet.sso.*;
022: import com.iplanet.am.util.*;
023:
024: public class NetFileUploadServlet extends HttpServlet {
025:
026: private static Logger logger = PortalLogger
027: .getLogger(NetFileUploadServlet.class);
028: private static HashMap uploadCache = null;
029: String tokenID = "";
030:
031: public void init(ServletConfig config) throws ServletException {
032: super .init(config);
033:
034: uploadCache = new HashMap();
035: }
036:
037: public void doPost(HttpServletRequest request,
038: HttpServletResponse response) {
039: handleRequest(request, response);
040: }
041:
042: public void doGet(HttpServletRequest request,
043: HttpServletResponse response) {
044: handleRequest(request, response);
045: }
046:
047: public void handleRequest(HttpServletRequest request,
048: HttpServletResponse response) {
049: String queryString = request.getQueryString();
050: Hashtable queryData = HttpUtils.parseQueryString(queryString);
051: String id[] = (String[]) queryData.get("id");
052:
053: FileUploadHandler ufh = (FileUploadHandler) uploadCache
054: .get(id[0]);
055: tokenID = id[0];
056: if (ufh == null) {
057: ufh = new FileUploadHandler(id[0]);
058: uploadCache.put(id[0], ufh);
059: }
060:
061: ufh.handleUpload(request, response);
062: }
063:
064: /*
065: *
066: * The request to the server when uploading a file will be of the following
067: * format:
068: *
069: * -------------------------------
070: * | identifier = 128 bytes. |
071: * -------------------------------
072: * | |
073: * | meta data |
074: * | |
075: * -------------------------------
076: * | |
077: * | |
078: * | upload file contents |
079: * | |
080: * -------------------------------
081: *
082: * First read 128 bytes from the stream which will be identifier. It also
083: * contains the "metaDataSize".
084: *
085: * Next read "metaDataSize" bytes from the stream which will be meta data.
086: *
087: * After this read the upload file contents and send it to the destination
088: * server.
089: *
090: * So 2 things are taken here:
091: * 1. Reduce the no. of request comes from the client when uploading a file (bug#4843657).
092: * 2. No need of temporary files when uploading a file (bug#4843653).
093: *
094: */
095:
096: class FileUploadHandler {
097:
098: private String uploadIdentifier = "";
099: private HashMap storedMetaData = null;
100:
101: byte[] buffer = new byte[1024 * 8];
102: private OutputStream uploadStream = null;
103: private Object fileObject = null;
104:
105: NetFileResource resourceBundle = null;
106: NetFileLogManager logManager = null;
107:
108: private static final String RESP_STR = "OK.";
109: private static final String SNO_STR = "SNo";
110:
111: public FileUploadHandler(String id) {
112: tokenID = id;
113: }
114:
115: public void handleUpload(HttpServletRequest request,
116: HttpServletResponse response) {
117:
118: SSOTokenManager manager = null;
119: SSOToken ssoToken = null;
120: NetFileContext nfContext = null;
121:
122: InputStream inputStream = null;
123: OutputStream outputStream = null;
124: String output = "";
125:
126: try {
127: manager = SSOTokenManager.getInstance();
128: ssoToken = manager
129: .createSSOToken(extractSession(request));
130: nfContext = new NetFileContextImpl(ssoToken);
131:
132: inputStream = request.getInputStream();
133: outputStream = getOutputStream(response);
134:
135: if (!validateSession(request, response, ssoToken,
136: nfContext))
137: return;
138:
139: if (logManager == null) {
140: logManager = createLogManager(ssoToken);
141: }
142:
143: readUploadIdentifier(inputStream);
144: HashMap getData = readMetaData(inputStream);
145:
146: int sequenceNo = new Integer((String) getData
147: .get(SNO_STR)).intValue();
148: if (sequenceNo == 1) {
149: storedMetaData = getData;
150: String locale = (String) storedMetaData
151: .get("locale");
152: String machineEncoding = (String) storedMetaData
153: .get("machine_encoding");
154: resourceBundle = getUserLocaleBundle(locale,
155: machineEncoding);
156: } else if (sequenceNo == -888) {
157: /*
158: * User pressed cancel when uploading a file.
159: * Clean up the resources allocated.
160: */
161: writeOutputMessage(outputStream, RESP_STR);
162: doClose(sequenceNo);
163: return;
164: } else {
165: storedMetaData.remove(SNO_STR);
166: storedMetaData.put(SNO_STR, getData.get(SNO_STR));
167: }
168:
169: output = uploadFile(storedMetaData, inputStream,
170: resourceBundle, ssoToken);
171: writeOutputMessage(outputStream, output);
172:
173: } catch (Exception e) {
174: writeErrorDebug("Exception while uploading file - ", e);
175: if (e instanceof NetFileException) {
176: output = ((NetFileException) e)
177: .getMessage(resourceBundle);
178: } else {
179: output = "ERROR: "
180: + resourceBundle.getString("error18");
181: }
182: writeOutputMessage(outputStream, output);
183:
184: } finally {
185: try {
186: if (outputStream != null) {
187: outputStream.close();
188: }
189: if (inputStream != null) {
190: inputStream.close();
191: }
192: } catch (IOException ioe) {
193: }
194: inputStream = null;
195: outputStream = null;
196: }
197: }
198:
199: private OutputStream getOutputStream(
200: HttpServletResponse response) throws IOException {
201: response.setContentType("application/octet-stream");
202: return response.getOutputStream();
203: }
204:
205: private void writeOutputMessage(OutputStream outputStream,
206: String output) {
207: /*
208: * Write status message to the client. Status message can be either
209: * success or error message. Since the error messages are obtained from
210: * resource bundle based on user's locale, get the bytes based on "ISO-8859-1" charset
211: * and write it to the client.
212: */
213: try {
214: ObjectOutputStream ois = new ObjectOutputStream(
215: outputStream);
216: ois.writeObject(output);
217: ois.flush();
218: ois.close();
219: } catch (Exception e) {
220: writeErrorDebug(
221: "Exception while writing status to client, ", e);
222: }
223: }
224:
225: private void readUploadIdentifier(InputStream inputStream)
226: throws IOException {
227: byte[] uploadIdBytes = new byte[128];
228: inputStream.read(uploadIdBytes);
229: uploadIdentifier = new String(uploadIdBytes);
230: }
231:
232: private HashMap readMetaData(InputStream inputStream)
233: throws IOException {
234: int metaDataSizeStart = uploadIdentifier.indexOf("NFUP")
235: + "NFUP".length();
236: int metaDataSizeEnd = uploadIdentifier.indexOf("END");
237: String metaDataSizeString = uploadIdentifier.substring(
238: metaDataSizeStart, metaDataSizeEnd);
239: int metaDataSize = Integer.parseInt(metaDataSizeString);
240:
241: HashMap metaDataHashMap = new HashMap();
242: byte[] metaDataBytes = new byte[metaDataSize + 1];
243: inputStream.read(metaDataBytes);
244: String metaDataString = new String(metaDataBytes, "UTF-8");
245:
246: StringTokenizer stok = new StringTokenizer(metaDataString,
247: "\n");
248: NetFileURLDecoder decoder = new NetFileURLDecoder();
249:
250: String token = "";
251: String name = "";
252: String value = "";
253: int index;
254:
255: while (stok.hasMoreTokens()) {
256: token = stok.nextToken();
257: index = token.indexOf("=");
258: if (index != -1) {
259: name = token.substring(0, index);
260: value = token.substring(index + 1);
261: value = decoder.decode(value, "UTF8");
262: metaDataHashMap.put(name, value);
263: }
264: }
265:
266: return metaDataHashMap;
267: }
268:
269: String uploadFile(HashMap metaData, InputStream inputStream,
270: NetFileResource nfRes, SSOToken ssoToken)
271: throws NetFileException {
272: String returnStr = "";
273: Integer seqNo = new Integer((String) metaData.get(SNO_STR));
274: OutputStream streamToServer = null;
275:
276: try {
277: streamToServer = getOutputStream(metaData, nfRes,
278: ssoToken);
279: readWriteBytes(inputStream, streamToServer);
280: returnStr = RESP_STR;
281:
282: // Check if last block. Write to log and close streams.
283: if (seqNo.intValue() == -999) {
284: doLog(nfRes.getString("successLog.4"));
285: writeDebug("Upload file result = " + returnStr);
286: }
287: doClose(seqNo.intValue());
288:
289: } catch (Exception e) {
290: if (e instanceof NetFileException) {
291: returnStr = "ERROR:"
292: + ((NetFileException) e).getMessage(nfRes);
293: } else {
294: returnStr = "ERROR:" + nfRes.getString("error18");
295: }
296:
297: writeErrorDebug("Error uploading file - ", e);
298: doLog(nfRes.getString("failureLog.4"));
299:
300: doClose(-777);
301: throw new NetFileException(returnStr);
302: }
303: return returnStr;
304: }
305:
306: private OutputStream getOutputStream(HashMap metaData,
307: NetFileResource nfRes, SSOToken ssoToken)
308: throws NetFileException {
309: String machineType = (String) metaData.get("type");
310: if (machineType.equals("FTP")
311: || machineType.equals("NETWARE")) {
312: /*
313: * Create new FTP/NETWARE stream for each request because FTP
314: * servers are connection based and WIN/NETWARE are stream based.
315: * So for each request open the FTP streams, write the data and
316: * close the streams.
317: */
318: return createOutputStream(metaData, nfRes, ssoToken);
319: } else {
320: if (uploadStream == null) {
321: writeDebug("Stream not available in cache.");
322: uploadStream = createOutputStream(metaData, nfRes,
323: ssoToken);
324: }
325: return uploadStream;
326: }
327: }
328:
329: private OutputStream createOutputStream(HashMap metaData,
330: NetFileResource nfRes, SSOToken ssoToken)
331: throws NetFileException {
332:
333: String remoteFileName = (String) metaData.get("filename");
334: String userName = (String) metaData.get("username");
335: String share = (String) metaData.get("VMS");
336: String password = (String) metaData.get("pass");
337: String machine = (String) metaData.get("machine");
338: String machineType = (String) metaData.get("type");
339: String domain = (String) metaData.get("domain");
340: String directory = (String) metaData.get("dir");
341: String machineEncoding = (String) metaData
342: .get("machine_encoding");
343: Integer seqNo = new Integer((String) metaData.get(SNO_STR));
344:
345: OutputStream outputStream = null;
346:
347: if ((machineType.indexOf("WIN", 0) >= 0)
348: || (machineType.indexOf("NT", 0) >= 0)) {
349: XFileInterface winFileInterface = null;
350: if (fileObject == null) {
351: winFileInterface = XFileFactory.getInstance()
352: .newXFileInstance(logManager,
353: machineEncoding, ssoToken);
354: fileObject = winFileInterface;
355: } else {
356: winFileInterface = (XFileInterface) fileObject;
357: }
358: if (seqNo.intValue() != 1) {
359: writeDebug("Creating the output stream in append mode.");
360: outputStream = winFileInterface.getOutputStream(
361: userName, password, domain, machine, share,
362: directory, remoteFileName, nfRes);
363: } else {
364: writeDebug("Creating the output stream.");
365: outputStream = winFileInterface.getOutputStream(
366: userName, password, domain, machine, share,
367: directory, remoteFileName, nfRes);
368: }
369:
370: } else if ((machineType.indexOf("FTP", 0) >= 0)
371: || (machineType.indexOf("NETWARE", 0) >= 0)) {
372: FtpFile ftpFile = new FtpFile(logManager,
373: machineEncoding);
374: fileObject = ftpFile;
375: if (seqNo.intValue() != 1) {
376: writeDebug("Creating the output stream in append mode.");
377: outputStream = ftpFile.getOutputFTPStream(userName,
378: password, machine, share, remoteFileName,
379: directory, true);
380: } else {
381: writeDebug("Creating the output stream.");
382: outputStream = ftpFile.getOutputFTPStream(userName,
383: password, machine, share, remoteFileName,
384: directory);
385: }
386:
387: } else if (machineType.indexOf("NFS", 0) >= 0) {
388: NfsFile nfsFile = null;
389: if (fileObject == null) {
390: nfsFile = new NfsFile(logManager, machineEncoding);
391: fileObject = nfsFile;
392: } else {
393: nfsFile = (NfsFile) fileObject;
394: }
395: if (seqNo.intValue() != 1) {
396: writeDebug("Creating the output stream in append mode.");
397: outputStream = nfsFile.getNFSOutputStream(userName,
398: password, machine, share, remoteFileName,
399: directory, true);
400: } else {
401: writeDebug("Creating the output stream.");
402: outputStream = nfsFile.getNFSOutputStream(userName,
403: password, machine, share, remoteFileName,
404: directory);
405: }
406: }
407: return outputStream;
408: }
409:
410: private void doClose(int sequenceNo) {
411: // Close stream to destination server (for FTP and Netware)
412: if ((fileObject instanceof FtpFile)
413: || (fileObject instanceof NetWareFile)) {
414: try {
415: if (uploadStream != null) {
416: BufferedOutputStream outStream = (BufferedOutputStream) uploadStream;
417: outStream.flush();
418: outStream.close();
419: }
420:
421: FtpFile ftpFile = (FtpFile) fileObject;
422: ftpFile.ffc.closeDataConnection();
423: ftpFile.ffc.quit();
424:
425: fileObject = null;
426:
427: writeDebug("Output stream closed to server.");
428: } catch (IOException ioe) {
429: writeErrorDebug(
430: "Exception in closing stream to server on sequence "
431: + sequenceNo, ioe);
432: }
433: }
434:
435: // Only in -777/-888/-999 cases, close stream to destination server (for Win and NFS)
436: if (sequenceNo == -777 || sequenceNo == -888
437: || sequenceNo == -999) {
438: if (fileObject != null) {
439: if ((fileObject instanceof WinFile)
440: || (fileObject instanceof NfsFile)) {
441: try {
442: if (uploadStream != null) {
443: uploadStream.flush();
444: uploadStream.close();
445: }
446: writeDebug("Output stream closed to server.");
447: } catch (Exception ex) {
448: writeErrorDebug("Exception deleting file ",
449: ex);
450: }
451: }
452: }
453: }
454:
455: // Delete file on destination server, if cancel(-888) or exception(-777)
456: if (sequenceNo == -888 || sequenceNo == -777) {
457: Object obj = storedMetaData.get("filename");
458: if (obj != null) {
459: deleteFile();
460: }
461: }
462:
463: if (sequenceNo == -777 || sequenceNo == -888
464: || sequenceNo == -999) {
465: uploadCache.remove(tokenID);
466: }
467: }
468:
469: private void readWriteBytes(InputStream inputStream,
470: OutputStream outputStream) throws IOException {
471: int len = 0;
472: try {
473: while ((len = inputStream.read(buffer)) != -1) {
474: outputStream.write(buffer, 0, len);
475: }
476: outputStream.flush();
477: } catch (IOException ioe) {
478: throw ioe;
479: } finally {
480: try {
481: if (inputStream != null)
482: inputStream.close();
483: } catch (IOException ioe) {
484: }
485: }
486: }
487:
488: private void deleteFile() {
489: String fileName = (String) storedMetaData.get("filename");
490: String userName = (String) storedMetaData.get("username");
491: String share = (String) storedMetaData.get("VMS");
492: String password = (String) storedMetaData.get("pass");
493: String machine = (String) storedMetaData.get("machine");
494: String machineType = (String) storedMetaData.get("type");
495: String domain = (String) storedMetaData.get("domain");
496: String directory = (String) storedMetaData.get("dir");
497: String machineEncoding = (String) storedMetaData
498: .get("machine_encoding");
499:
500: try {
501: if (machineType.equals("FTP")
502: || machineType.equals("NETWARE")) {
503: FtpFile ftpFile = new FtpFile(logManager,
504: machineEncoding);
505: ftpFile.delFTPFile(userName, password, machine,
506: share, fileName, directory, resourceBundle);
507: } else if (machineType.equals("NFS")) {
508: NfsFile nfsFile = (NfsFile) fileObject;
509: nfsFile.delNFSFile(userName, password, share,
510: machine, fileName, directory, "",
511: resourceBundle);
512: } else if (machineType.equals("WIN")
513: || machineType.equals("NT")) {
514: XFileInterface fileInterface = (XFileInterface) fileObject;
515: fileInterface.doDeleteFile(userName, password,
516: machine, share, fileName, directory,
517: domain, resourceBundle);
518: }
519: } catch (NetFileException e) {
520: writeErrorDebug("Exception while deleting File. ", e);
521: }
522: }
523:
524: private NetFileResource getUserLocaleBundle(String locale,
525: String machineEncoding) throws Exception {
526: NetFileResource resourceBundle = null;
527: if (locale == null) {
528: FileOption file_option = new FileOption(logManager,
529: machineEncoding);
530: resourceBundle = file_option
531: .getPlatformLocalisedBundle();
532: } else {
533: resourceBundle = NetFileResource.getInstance(
534: FileOption.APPLET_PROPERTIES, locale);
535: }
536: return resourceBundle;
537: }
538:
539: private boolean validateSession(HttpServletRequest req,
540: HttpServletResponse res, SSOToken ssoToken,
541: NetFileContext nfContext) {
542: try {
543: if (nfContext.isSessionValid(ssoToken)
544: && nfContext.isExecutable(ssoToken)) {
545: return true;
546: } else {
547: return false;
548: }
549: } catch (Exception e) {
550: writeErrorDebug(
551: "General Exception in NetFileUploadServlet", e);
552: return false;
553: }
554: }
555:
556: private String extractSession(HttpServletRequest req) {
557: String session = null;
558: session = req.getHeader("iPSsessionID");
559: Cookie[] cookie = req.getCookies();
560:
561: if (cookie != null) {
562: for (int i = 0; i < cookie.length; i++) {
563: if (cookie[i].getName().equalsIgnoreCase(
564: SystemProperties.get(
565: "com.iplanet.am.cookie.name",
566: "iPlanetDirectoryPro"))) {
567: session = cookie[i].getValue();
568: if (NetFileServlet.isEncoded)
569: session = java.net.URLDecoder
570: .decode(session);
571: }
572: }
573: }
574: return session;
575: }
576:
577: protected void writeDebug(String szMsg) {
578: writeDebug(szMsg, null);
579: }
580:
581: protected void writeDebug(String szMsg, Exception e) {
582: if (e != null) {
583: // logger.log(Level.INFO, szMsg, e);
584: logger.log(Level.INFO, "PSSRNF_CSPNSJ1187");
585: } else {
586: // logger.info(szMsg);
587: logger.info("PSSRNF_CSPNSJ1188");
588: }
589: }
590:
591: protected void writeErrorDebug(String szError, Exception e) {
592: if (e != null)
593: // logger.log(Level.SEVERE, szError, e);
594: logger.log(Level.SEVERE, "PSSRNF_CSPNSJ1189");
595: else
596: // logger.severe(szError);
597: logger.severe("PSSRNF_CSPNSJ1190");
598: }
599:
600: private NetFileLogManager createLogManager(SSOToken ssoToken) {
601: String tokenId = ssoToken.getTokenID().toString();
602: try {
603: Object obj = NetFileServlet.logManagerCache
604: .get(tokenId);
605: if (obj == null) {
606: NetFileLogManager logMgr = new NetFileLogManager(
607: ssoToken);
608: NetFileServlet.logManagerCache.put(tokenId, logMgr);
609: return logMgr;
610: } else {
611: return (NetFileLogManager) obj;
612: }
613: } catch (Exception e) {
614: // logger.severe("Unable to create LogManager for ssoToken - " + tokenId);
615: Object[] params4 = { tokenId };
616: logger.log(Level.SEVERE, "PSSRNF_CSPNSJ1191", params4);
617: return null;
618: }
619: }
620:
621: private void doLog(String msg) {
622: if (this .logManager == null)
623: return;
624:
625: String functionName = resourceBundle
626: .getString("uploadFileLog");
627: String remoteFileName = (String) storedMetaData
628: .get("filename");
629: String userName = (String) storedMetaData.get("username");
630: String share = (String) storedMetaData.get("VMS");
631: String machine = (String) storedMetaData.get("machine");
632: String directory = (String) storedMetaData.get("dir");
633:
634: Object[] obj = new Object[] { functionName, remoteFileName,
635: userName, machine, share, directory };
636:
637: logManager.doLog(msg + " "
638: + resourceBundle.getString("successLog.5", obj));
639: }
640:
641: } // end of inner class.
642: }
|