/*
* JSPUploadStep.java
*
* Version: $Revision: 4931 $
*
* Date: $Date: 2010-05-13 21:09:17 +0000 (Thu, 13 May 2010) $
*
* Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
* Institute of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.app.webui.submit.step;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.util.DCInputsReader;
import org.dspace.app.util.DCInputsReaderException;
import org.dspace.app.util.SubmissionInfo;
import org.dspace.app.webui.submit.JSPStep;
import org.dspace.app.webui.submit.JSPStepManager;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.app.webui.util.UIUtil;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.BitstreamFormat;
import org.dspace.content.Bundle;
import org.dspace.content.Collection;
import org.dspace.content.FormatIdentifier;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.submit.step.UploadStep;
/**
* Upload step for DSpace JSP-UI. Handles the pages that revolve around uploading files
* (and verifying a successful upload) for an item being submitted into DSpace.
* <P>
* This JSPStep class works with the SubmissionController servlet
* for the JSP-UI
* <P>
* The following methods are called in this order:
* <ul>
* <li>Call doPreProcessing() method</li>
* <li>If showJSP() was specified from doPreProcessing(), then the JSP
* specified will be displayed</li>
* <li>If showJSP() was not specified from doPreProcessing(), then the
* doProcessing() method is called an the step completes immediately</li>
* <li>Call doProcessing() method on appropriate AbstractProcessingStep after the user returns from the JSP, in order
* to process the user input</li>
* <li>Call doPostProcessing() method to determine if more user interaction is
* required, and if further JSPs need to be called.</li>
* <li>If there are more "pages" in this step then, the process begins again
* (for the new page).</li>
* <li>Once all pages are complete, control is forwarded back to the
* SubmissionController, and the next step is called.</li>
* </ul>
*
* @see org.dspace.app.webui.servlet.SubmissionController
* @see org.dspace.app.webui.submit.JSPStep
* @see org.dspace.submit.step.UploadStep
*
* @author Tim Donohue
* @version $Revision: 4931 $
*/
public class JSPUploadStep extends JSPStep
{
/** JSP to choose files to upload * */
private static final String CHOOSE_FILE_JSP = "/submit/choose-file.jsp";
/** JSP to show files that were uploaded * */
private static final String UPLOAD_LIST_JSP = "/submit/upload-file-list.jsp";
/** JSP to single file that was upload * */
private static final String UPLOAD_FILE_JSP = "/submit/show-uploaded-file.jsp";
/** JSP to edit file description * */
private static final String FILE_DESCRIPTION_JSP = "/submit/change-file-description.jsp";
/** JSP to edit file format * */
private static final String FILE_FORMAT_JSP = "/submit/get-file-format.jsp";
/** JSP to show any upload errors * */
private static final String UPLOAD_ERROR_JSP = "/submit/upload-error.jsp";
/** JSP to review uploaded files * */
private static final String REVIEW_JSP = "/submit/review-upload.jsp";
/** log4j logger */
private static Logger log = Logger.getLogger(JSPUploadStep.class);
/**
* Do any pre-processing to determine which JSP (if any) is used to generate
* the UI for this step. This method should include the gathering and
* validating of all data required by the JSP. In addition, if the JSP
* requires any variable to passed to it on the Request, this method should
* set those variables.
* <P>
* If this step requires user interaction, then this method must call the
* JSP to display, using the "showJSP()" method of the JSPStepManager class.
* <P>
* If this step doesn't require user interaction OR you are solely using
* Manakin for your user interface, then this method may be left EMPTY,
* since all step processing should occur in the doProcessing() method.
*
* @param context
* current DSpace context
* @param request
* current servlet request object
* @param response
* current servlet response object
* @param subInfo
* submission info object
*/
public void doPreProcessing(Context context, HttpServletRequest request,
HttpServletResponse response, SubmissionInfo subInfo)
throws ServletException, IOException, SQLException,
AuthorizeException
{
// pass on the fileupload setting
if (subInfo != null)
{
Collection c = subInfo.getSubmissionItem().getCollection();
try
{
DCInputsReader inputsReader = new DCInputsReader();
request.setAttribute("submission.inputs", inputsReader.getInputs(c
.getHandle()));
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
}
// show whichever upload page is appropriate
// (based on if this item already has files or not)
showUploadPage(context, request, response, subInfo, false);
}
/**
* Do any post-processing after the step's backend processing occurred (in
* the doProcessing() method).
* <P>
* It is this method's job to determine whether processing completed
* successfully, or display another JSP informing the users of any potential
* problems/errors.
* <P>
* If this step doesn't require user interaction OR you are solely using
* Manakin for your user interface, then this method may be left EMPTY,
* since all step processing should occur in the doProcessing() method.
*
* @param context
* current DSpace context
* @param request
* current servlet request object
* @param response
* current servlet response object
* @param subInfo
* submission info object
* @param status
* any status/errors reported by doProcessing() method
*/
public void doPostProcessing(Context context, HttpServletRequest request,
HttpServletResponse response, SubmissionInfo subInfo, int status)
throws ServletException, IOException, SQLException,
AuthorizeException
{
String buttonPressed = UIUtil.getSubmitButton(request, UploadStep.NEXT_BUTTON);
// Do we need to skip the upload entirely?
boolean fileRequired = ConfigurationManager.getBooleanProperty("webui.submit.upload.required", true);
if (buttonPressed.equalsIgnoreCase(UploadStep.SUBMIT_SKIP_BUTTON) ||
(buttonPressed.equalsIgnoreCase(UploadStep.SUBMIT_UPLOAD_BUTTON) && !fileRequired))
{
Bundle[] bundles = subInfo.getSubmissionItem().getItem()
.getBundles("ORIGINAL");
boolean fileAlreadyUploaded = false;
for (Bundle bnd : bundles)
{
fileAlreadyUploaded = bnd.getBitstreams().length > 0;
if (fileAlreadyUploaded)
{
break;
}
}
// if user already has uploaded at least one file
if (fileAlreadyUploaded)
{
// return to list of uploaded files
showUploadFileList(context, request, response, subInfo, true,
false);
}
return; // return immediately, since we are skipping upload
}
//If upload failed in JSPUI (just came from upload-error.jsp), user can retry the upload
if(buttonPressed.equalsIgnoreCase("submit_retry"))
{
showUploadPage(context, request, response, subInfo, false);
}
// ------------------------------
// Check for Errors!
// ------------------------------
// if an error or message was passed back, determine what to do!
if (status != UploadStep.STATUS_COMPLETE)
{
if (status == UploadStep.STATUS_INTEGRITY_ERROR)
{
// Some type of integrity error occurred
log.warn(LogManager.getHeader(context, "integrity_error",
UIUtil.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
}
else if (status == UploadStep.STATUS_UPLOAD_ERROR || status == UploadStep.STATUS_NO_FILES_ERROR)
{
// There was a problem uploading the file!
//First, check if we just removed our uploaded file
if(buttonPressed.startsWith("submit_remove_"))
{
//if file was just removed, go back to upload page
showUploadPage(context, request, response, subInfo, false);
}
else
{
// We need to show the file upload error page
if (subInfo != null)
{
try
{
Collection c = subInfo.getSubmissionItem().getCollection();
DCInputsReader inputsReader = new DCInputsReader();
request.setAttribute("submission.inputs", inputsReader
.getInputs(c.getHandle()));
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
}
JSPStepManager.showJSP(request, response, subInfo, UPLOAD_ERROR_JSP);
}
}
else if (status == UploadStep.STATUS_UNKNOWN_FORMAT)
{
// user uploaded a file where the format is unknown to DSpace
// forward user to page to request the file format
showGetFileFormat(context, request, response, subInfo);
}
}
// As long as there are no errors, clicking Next
// should immediately send them to the next step
if (status == UploadStep.STATUS_COMPLETE && buttonPressed.equals(UploadStep.NEXT_BUTTON))
{
// just return, so user will continue on to next step!
return;
}
// ------------------------------
// Check for specific buttons
// ------------------------------
if (buttonPressed.equals(UploadStep.SUBMIT_MORE_BUTTON))
{
// Upload another file (i.e. show the Choose File jsp again)
showChooseFile(context, request, response, subInfo);
}
else if (buttonPressed.equals("submit_show_checksums"))
{
// Show the checksums
showUploadFileList(context, request, response, subInfo, false, true);
}
else if (buttonPressed.startsWith("submit_describe_"))
{
// Change the description of a bitstream
Bitstream bitstream;
// Which bitstream does the user want to describe?
try
{
int id = Integer.parseInt(buttonPressed.substring(16));
bitstream = Bitstream.find(context, id);
}
catch (NumberFormatException nfe)
{
bitstream = null;
}
if (bitstream == null)
{
// Invalid or mangled bitstream ID
// throw an error and return immediately
log.warn(LogManager.getHeader(context, "integrity_error",
UIUtil.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
}
// save the bitstream
subInfo.setBitstream(bitstream);
// load the change file description page
showFileDescription(context, request, response, subInfo);
}
else if (buttonPressed.startsWith("submit_format_"))
{
// A "format is wrong" button must have been pressed
Bitstream bitstream;
// Which bitstream does the user want to describe?
try
{
int id = Integer.parseInt(buttonPressed.substring(14));
bitstream = Bitstream.find(context, id);
}
catch (NumberFormatException nfe)
{
bitstream = null;
}
if (bitstream == null)
{
// Invalid or mangled bitstream ID
// throw an error and return immediately
log.warn(LogManager.getHeader(context, "integrity_error",
UIUtil.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
}
subInfo.setBitstream(bitstream);
showGetFileFormat(context, request, response, subInfo);
}
else
{
// BY DEFAULT: just display either the first upload page or the
// upload file listing
String contentType = request.getContentType();
boolean fileUpload = false;
// if multipart form, then we just finished a file upload
if ((contentType != null)
&& (contentType.indexOf("multipart/form-data") != -1))
fileUpload = true;
// show the appropriate upload page
// (based on if a file has just been uploaded or not)
showUploadPage(context, request, response, subInfo, fileUpload);
}
}
/**
* Display the appropriate upload page in the file upload sequence. Which
* page this is depends on whether the user has uploaded any files in this
* item already.
*
* @param context
* the DSpace context object
* @param request
* the request object
* @param response
* the response object
* @param subInfo
* the SubmissionInfo object
* @param justUploaded
* true, if the user just finished uploading a file
*/
private void showUploadPage(Context context, HttpServletRequest request,
HttpServletResponse response, SubmissionInfo subInfo,
boolean justUploaded) throws SQLException, ServletException,
IOException
{
Bundle[] bundles = subInfo.getSubmissionItem().getItem().getBundles(
"ORIGINAL");
boolean fileAlreadyUploaded = false;
if (!justUploaded)
{
for (Bundle bnd : bundles)
{
fileAlreadyUploaded = bnd.getBitstreams().length > 0;
if (fileAlreadyUploaded)
{
break;
}
}
}
// if user already has uploaded at least one file
if (justUploaded || fileAlreadyUploaded)
{
// The item already has files associated with it.
showUploadFileList(context, request, response, subInfo,
justUploaded, false);
}
else
{
// show the page to choose a file to upload
showChooseFile(context, request, response, subInfo);
}
}
/**
* Show the page which allows the user to choose another file to upload
*
* @param context
* current DSpace context
* @param request
* the request object
* @param response
* the response object
* @param subInfo
* the SubmissionInfo object
*/
private void showChooseFile(Context context, HttpServletRequest request,
HttpServletResponse response, SubmissionInfo subInfo)
throws SQLException, ServletException, IOException
{
// set to null the bitstream in subInfo, we need to process a new file
// we don't need any info about previous files...
subInfo.setBitstream(null);
// load JSP which allows the user to select a file to upload
JSPStepManager.showJSP(request, response, subInfo, CHOOSE_FILE_JSP);
}
/**
* Show the page which lists all the currently uploaded files
*
* @param context
* current DSpace context
* @param request
* the request object
* @param response
* the response object
* @param subInfo
* the SubmissionInfo object
* @param justUploaded
* pass in true if the user just successfully uploaded a file
* @param showChecksums
* pass in true if checksums should be displayed
*/
private void showUploadFileList(Context context,
HttpServletRequest request, HttpServletResponse response,
SubmissionInfo subInfo, boolean justUploaded, boolean showChecksums)
throws SQLException, ServletException, IOException
{
// Set required attributes
request.setAttribute("just.uploaded", new Boolean(justUploaded));
request.setAttribute("show.checksums", new Boolean(showChecksums));
// Always go to advanced view in workflow mode
if (subInfo.isInWorkflow()
|| subInfo.getSubmissionItem().hasMultipleFiles())
{
// next, load JSP listing multiple files
JSPStepManager.showJSP(request, response, subInfo, UPLOAD_LIST_JSP);
}
else
{
// next, load JSP listing a single file
JSPStepManager.showJSP(request, response, subInfo, UPLOAD_FILE_JSP);
}
}
/**
* Show the page which allows the user to change the format of the file that
* was just uploaded
*
* @param context
* context object
* @param request
* the request object
* @param response
* the response object
* @param subInfo
* the SubmissionInfo object
*/
private void showGetFileFormat(Context context, HttpServletRequest request,
HttpServletResponse response, SubmissionInfo subInfo)
throws SQLException, ServletException, IOException
{
if (subInfo == null || subInfo.getBitstream() == null)
{
// We have an integrity error, since we seem to have lost
// which bitstream was just uploaded
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
}
BitstreamFormat[] formats = BitstreamFormat.findNonInternal(context);
request.setAttribute("bitstream.formats", formats);
// What does the system think it is?
BitstreamFormat guess = FormatIdentifier.guessFormat(context, subInfo
.getBitstream());
request.setAttribute("guessed.format", guess);
// display choose file format JSP next
JSPStepManager.showJSP(request, response, subInfo, FILE_FORMAT_JSP);
}
/**
* Show the page which allows the user to edit the description of already
* uploaded files
*
* @param context
* context object
* @param request
* the request object
* @param response
* the response object
* @param subInfo
* the SubmissionInfo object
*/
private void showFileDescription(Context context,
HttpServletRequest request, HttpServletResponse response,
SubmissionInfo subInfo) throws SQLException, ServletException,
IOException
{
// load JSP which allows the user to select a file to upload
JSPStepManager.showJSP(request, response, subInfo, FILE_DESCRIPTION_JSP);
}
/**
* Return the URL path (e.g. /submit/review-metadata.jsp) of the JSP
* which will review the information that was gathered in this Step.
* <P>
* This Review JSP is loaded by the 'Verify' Step, in order to dynamically
* generate a submission verification page consisting of the information
* gathered in all the enabled submission steps.
*
* @param context
* current DSpace context
* @param request
* current servlet request object
* @param response
* current servlet response object
* @param subInfo
* submission info object
*/
public String getReviewJSP(Context context, HttpServletRequest request,
HttpServletResponse response, SubmissionInfo subInfo)
{
return REVIEW_JSP;
}
}