package org.ngbw.web.actions; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.ngbw.sdk.database.SourceDocument; import org.ngbw.sdk.database.Task; import org.ngbw.sdk.database.UserDataItem; @SuppressWarnings("serial") public class ArchiveManager extends DataManager { private static final Log logger = LogFactory.getLog(ArchiveManager.class.getName()); public static final String ARCHIVE_CONTENT_TYPE = "application/zip"; public static final int BUFFER_SIZE = 2048; @Override public String getFilename () { String filename = null; Task task = (Task) getSessionAttribute("currentTask"); if (task != null) { filename = task.getLabel(); if (filename != null) { filename += ".zip"; } } // In case the "currentTask" is not found in session, roll back to defaultl filename. return (filename != null)? filename : "CIPRES_DATA.zip"; } @Override public String getContentType () { return ARCHIVE_CONTENT_TYPE; } @Override public long getDataLength () { return 0; } /** * * @return @modified Mona - added checking for duplicate filename and will not add any duplicate * entry found to the zip archive */ @Override public InputStream getInputStream () { logger.debug("BEGIN: getInputStream()::InputStream"); // set up piped input/output streams PipedInputStream input = new PipedInputStream(); final PipedOutputStream pipedOutStream; try { pipedOutStream = new PipedOutputStream(input); } catch ( IOException error ) { logger.error("Error opening archive file output stream"); return null; } // have to set up piped output stream in a separate thread new Thread(new Runnable() { @Override public void run () { logger.debug("BEGIN: Thread.Runnable().run()"); // get selected data items logger.debug("Thread.Runnable().run() -> Getting selected documents ..."); List documents = getSelectedDocuments(); logger.debug("Thread.Runnable().run() -> Getting selected documents ... done."); if (documents == null || documents.isEmpty()) { reportUserError("Error retrieving documents to be archived: No documents were selected."); } else { // read selected data items into zip archive BufferedInputStream buffInputStream = null; // Exclude duplicate files... List finalDocuments = new ArrayList<>(); for (SourceDocument document : documents) { if (!finalDocuments.contains(document)) { finalDocuments.add(document); } } byte[] buffer = new byte[BUFFER_SIZE]; // set up zip output stream logger.debug("Thread.Runnable().run() -> Setting up ZipOutputStream ..."); ZipOutputStream zipOutStream = new ZipOutputStream(new BufferedOutputStream(pipedOutStream)); logger.debug("Thread.Runnable().run() -> Setting up ZipOutputStream ... done."); for (SourceDocument document : finalDocuments) { logger.debug("Thread.Runnable().run() -> Getting filename from document ..."); String filename = (document instanceof UserDataItem)? ((UserDataItem) document).getLabel() : document.getName(); try { filename = URLEncoder.encode(filename, "UTF-8"); } catch ( UnsupportedEncodingException uee ) {} logger.debug("Thread.Runnable().run() -> Getting filename from document ... filename: " + filename); try { logger.debug("Thread.Runnable().run() -> Creating ZipEntry and adding to ZipOutputStream ..."); zipOutStream.putNextEntry(new ZipEntry(filename)); logger.debug("Thread.Runnable().run() -> Creating ZipEntry and adding to ZipOutputStream ... done."); logger.debug("Thread.Runnable().run() -> InputStream to BufferedInputStream for SrcDoc: " + document.getName() + " ..."); buffInputStream = new BufferedInputStream(document.getDataAsStream(), BUFFER_SIZE); logger.debug("Thread.Runnable().run() -> InputStream to BufferedInputStream for SrcDoc: " + document.getName() + " ... done."); logger.debug("Thread.Runnable().run() -> Reading BufferedInputStream to ZipOutputStream ..."); int count; while ((count = buffInputStream.read(buffer, 0, BUFFER_SIZE)) != -1) { zipOutStream.write(buffer, 0, count); } logger.debug("Thread.Runnable().run() -> Reading BufferedInputStream to ZipOutputStream ... done."); logger.debug(String.format("SourceDocument [%d, %s] successfully added to zip archive.", document.getSourceDocumentId(), document.getName())); } catch ( IOException | SQLException error ) { logger.error("Error inserting zip entry for document with ID " + document.getSourceDocumentId()); closeSource(buffInputStream); closeArchive(zipOutStream); return; } } closeSource(buffInputStream); closeArchive(zipOutStream); } logger.debug("END: Thread.Runnable().run()"); } }).start(); logger.debug("END: getInputStream()::InputStream"); return input; } protected void closeArchive ( ZipOutputStream zipOutputStream ) { if (zipOutputStream != null) { try { zipOutputStream.close(); } catch ( IOException ioe ) { logger.error("Error closing ZipOutputStream.", ioe); } } } protected void closeSource ( InputStream source ) { if (source != null) { try { source.close(); } catch ( IOException ioe ) { logger.error("Error closing inputstream source.", ioe); } } } // public InputStream getInputStream_v1 () // { // logger.debug("BEGIN: getInputStream()::InputStream"); // // // set up piped input/output streams // PipedInputStream input = new PipedInputStream(); // final PipedOutputStream output; // try // { // output = new PipedOutputStream(input); // } // catch ( IOException error ) // { // logger.error("Error opening archive file output stream"); // return null; // } // // // have to set up piped output stream in a separate thread // new Thread(new Runnable() // { // @Override // public void run () // { // logger.debug("BEGIN: Thread.Runnable().run()"); // // // set up zip output stream // logger.debug("Thread.Runnable().run() -> Setting up ZipOutputStream ..."); // ZipOutputStream zipOutStream = new ZipOutputStream(new BufferedOutputStream(output)); // byte[] buffer = new byte[BUFFER_SIZE]; // // get selected data items // List documents = null; // try // { // documents = getSelectedDocuments(); // } // catch ( Throwable error ) // { // reportUserError(error, "Error retrieving data items to be archived"); // closeArchive(zipOutStream); // return; // } // finally // { // if (documents == null || documents.size() < 1) // { // reportUserError("Error retrieving documents to " + "be archived: No documents were selected."); // closeArchive(zipOutStream); // return; // } // } // // logger.debug("Thread.Runnable().run() -> Setting up ZipOutputStream ... done."); // // // read selected data items into zip archive // BufferedInputStream buffInputStream = null; // List filenames_list = new ArrayList(); // List duplicate_filenames = new ArrayList(); // // logger.debug("Thread.Runnable().run() -> Reading selected data items into Zip archive ..."); // // for (SourceDocument document : documents) // { // InputStream dataStream = null; // // try // { // logger.debug("Thread.Runnable().run() -> InputStream to BufferedInputStream for SrcDoc: " + document.getName() + " ..."); // dataStream = document.getDataAsStream(); // buffInputStream = new BufferedInputStream(dataStream, BUFFER_SIZE); // logger.debug("Thread.Runnable().run() -> InputStream to BufferedInputStream for SrcDoc: " + document.getName() + " ... done."); // } // catch ( IOException | SQLException error ) // { // logger.error("Error retrieving data input " + "stream from document with ID " // + document.getSourceDocumentId()); // closeSource(dataStream); // closeArchive(zipOutStream); // return; // } // // logger.debug("Thread.Runnable().run() -> Getting filename from document ..."); // String filename = null; // if (document instanceof UserDataItem) // { // filename = ((UserDataItem) document).getLabel(); // } // else // { // filename = document.getName(); // } // logger.debug("Thread.Runnable().run() -> Getting filename from document ... filename: " + filename); // // // If filename already exists, don't add it to the archive // if (filenames_list.contains(filename)) // { // duplicate_filenames.add(filename); // continue; // } // else // { // filenames_list.add(filename); // } // // try // { // filename = URLEncoder.encode(filename, "UTF-8"); // } // catch ( UnsupportedEncodingException error ) // {} // // // try // { // logger.debug("Thread.Runnable().run() -> Creating ZipEntry and adding to ZipOutputStream ..."); // ZipEntry entry = new ZipEntry(filename); // zipOutStream.putNextEntry(entry); // logger.debug("Thread.Runnable().run() -> Creating ZipEntry and adding to ZipOutputStream ... done."); // } // catch ( IOException error ) // { // logger.error("Error inserting zip entry for document with ID " // + document.getSourceDocumentId()); // closeSource(buffInputStream); // closeArchive(zipOutStream); // return; // } // // // try // { // logger.debug("Thread.Runnable().run() -> Finalizing ZipOutputStream ..."); // int count; // while ((count = buffInputStream.read(buffer, 0, BUFFER_SIZE)) != -1) // { // zipOutStream.write(buffer, 0, count); // } // logger.debug("Thread.Runnable().run() -> Finalizing ZipOutputStream ... done."); // } // catch ( IOException error ) // { // logger.error("Error copying contents of " + "document with ID " // + document.getSourceDocumentId() // + " into zip entry"); // closeArchive(zipOutStream); // return; // } // finally // { // closeSource(buffInputStream); // } // // logger.debug(String.format("SourceDocument [%d, %s] successfully added to zip archive.", // document.getSourceDocumentId(), document.getName())); // } // // logger.debug("Thread.Runnable().run() -> Reading selected data items into Zip archive ... done."); // // closeArchive(zipOutStream); // // /* // * Decided not to show message; see FogBugz // * http://phylo-bugz.sdsc.edu/fogbugz/default.asp?359071#BugEvent.841311 if ( // * duplicate_filenames.size() > 0 ) reportUserError ( "Duplicate files are not // * included in the archive." ); // */ // // logger.debug("END: Thread.Runnable().run()"); // } // }).start(); // // logger.debug("END: getInputStream()::InputStream"); // // return input; // } }