/*
* AbstractProcessingStep.java
*
* Version: $Revision: 3738 $
*
* Date: $Date: 2009-04-24 04:32:12 +0000 (Fri, 24 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. 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 DSpace Foundation nor the names of its
* 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.submit;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.app.util.SubmissionInfo;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
/**
* Abstract processing class for DSpace Submission Steps. This defines the base
* methods which are required for any Step processing class.
* <P>
* This abstract class defines the base methods which are used by both the
* Manakin XML UI and the JSP UI to perform submission step processing.
* <P>
* This includes the following methods:
* <ul>
* <li>doProcessing() method - called to perform any step processing</li>
* <li>getErrorFields() method - called to determine the fields which errored
* out during processing</li>
* <li>getErrorMessage() method - called to determine any error message
* returned after processing</li>
* </ul>
* <P>
* If you are using the JSP UI (with the SubmissionController servlet) you
* should extend the org.dspace.submit.SubmissionStep class, which defines
* additional methods used to maintain the context of the submission within a
* JSP environment!
*
* @see org.dspace.app.webui.submit.JSPStepManager
* @see org.dspace.app.webui.servlet.SubmissionController
* @see org.dspace.app.util.SubmissionConfig
* @see org.dspace.app.util.SubmissionStepConfig
*
* @author Tim Donohue
* @version $Revision: 3738 $
*/
public abstract class AbstractProcessingStep
{
/***************************************************************************
* Constant - Name of the "<-Previous" button
**************************************************************************/
public static String PREVIOUS_BUTTON = "submit_prev";
/***************************************************************************
* Constant - Name of the "Next->" button
**************************************************************************/
public static String NEXT_BUTTON = "submit_next";
/***************************************************************************
* Constant - Name of the "Cancel/Save" button
**************************************************************************/
public static String CANCEL_BUTTON = "submit_cancel";
/***************************************************************************
* Constant - Prefix of all buttons in the Progress Bar
**************************************************************************/
public static String PROGRESS_BAR_PREFIX = "submit_jump_";
/***************************************************************************
* Flag which specifies that the LAST PAGE of a step has been reached. This
* flag is used when a Workflow Item is rejected (and returned to the
* workspace) to specify that the LAST PAGE of the LAST STEP has already
* been reached
**************************************************************************/
public static int LAST_PAGE_REACHED = Integer.MAX_VALUE;
/***************************************************************************
* STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or
* additional user interaction may be required)
**************************************************************************/
public static int STATUS_COMPLETE = 0;
/** Maps each status/error flag to a textual, human understandable message * */
private Map errorMessages = null;
/** List of all user interface fields which had errors during processing * */
private List errorFields = null;
private static String ERROR_FIELDS_ATTRIBUTE = "dspace.submit.error_fields";
/**
* Do any processing of the information input by the user, and/or perform
* step processing (if no user interaction required)
* <P>
* It is this method's job to save any data to the underlying database, as
* necessary, and return error messages (if any) which can then be processed
* by the doPostProcessing() method.
* <P>
* NOTE: If this step is a non-interactive step (i.e. requires no UI), then
* it should perform *all* of its processing in this method!
*
* @param context
* current DSpace context
* @param request
* current servlet request object
* @param response
* current servlet response object
* @param subInfo
* submission info object
* @return Status or error flag which will be processed by
* doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned,
* no errors occurred!)
*/
public abstract int doProcessing(Context context,
HttpServletRequest request, HttpServletResponse response,
SubmissionInfo subInfo) throws ServletException, IOException,
SQLException, AuthorizeException;
/**
* Return a list of all UI fields which had errors that occurred during the
* step processing. This list is for usage in generating the appropriate
* error message(s) in the UI.
* <P>
* The list of fields which had errors should be set by the AbstractProcessingStep's
* doProcessing() method, so that it can be accessed later by whatever UI is
* generated.
*
* @param request
* current servlet request object
* @return List of error fields (as Strings)
*/
public static final List getErrorFields(HttpServletRequest request)
{
return (List) request.getAttribute(ERROR_FIELDS_ATTRIBUTE);
}
/**
* Sets th list of all UI fields which had errors that occurred during the
* step processing. This list is for usage in generating the appropriate
* error message(s) in the UI.
* <P>
* The list of fields which had errors should be set by the AbstractProcessingStep's
* doProcessing() method, so that it can be accessed later by whatever UI is
* generated.
*
* @param request
* current servlet request object
* @param errorFields
* List of all fields (as Strings) which had errors
*/
private static final void setErrorFields(HttpServletRequest request, List errorFields)
{
if(errorFields==null)
request.removeAttribute(ERROR_FIELDS_ATTRIBUTE);
else
request.setAttribute(ERROR_FIELDS_ATTRIBUTE, errorFields);
}
/**
* Add a single UI field to the list of all error fields (which can
* later be retrieved using getErrorFields())
* <P>
* The list of fields which had errors should be set by the AbstractProcessingStep's
* doProcessing() method, so that it can be accessed later by whatever UI is
* generated.
*
* @param fieldName
* the name of the field which had an error
*/
protected static final void addErrorField(HttpServletRequest request, String fieldName)
{
//get current list
List errorFields = getErrorFields(request);
if (errorFields == null)
{
errorFields = new ArrayList();
}
//add this field
errorFields.add(fieldName);
//save updated list
setErrorFields(request, errorFields);
}
/**
* Clears the list of all fields that errored out during the previous step's
* processing.
*
* @param request
* current servlet request object
*
*/
protected static final void clearErrorFields(HttpServletRequest request)
{
//get current list
List errorFields = getErrorFields(request);
if (errorFields != null)
setErrorFields(request,null);
}
/**
* Return the text of an error message based on the passed in error flag.
* These error messages are used for non-interactive steps (so that they can
* log something more specific than just an error flag)
* <P>
* Since each step can define its own error messages and flags, this method
* depends on all the error messages being initialized by using the
* "addErrorMessage()" method within the constructor for the step class!
*
* @param errorFlag
* The error flag defined in this step which represents an error
* message.
* @return String which contains the text of the error message, or null if
* error message not found
*/
public final String getErrorMessage(int errorFlag)
{
if (this.errorMessages == null || this.errorMessages.size() == 0)
return null;
else
return (String) this.errorMessages.get(Integer.valueOf(errorFlag));
}
/**
* Add an error message to the internal map for this step.
* <P>
* This method associates a specific error message with an error flag
* defined in this step.
* <P>
* This is extremely useful to define the error message which will be logged
* for a non-interactive step.
*
* @param fieldName
* the name of the field which had an error
*/
protected final void addErrorMessage(int errorFlag, String errorMessage)
{
if (this.errorMessages == null)
this.errorMessages = new HashMap();
errorMessages.put(Integer.valueOf(errorFlag), errorMessage);
}
/**
* Retrieves the number of pages that this "step" extends over. This method
* is used by the SubmissionController to build the progress bar.
* <P>
* This method may just return 1 for most steps (since most steps consist of
* a single page). But, it should return a number greater than 1 for any
* "step" which spans across a number of HTML pages. For example, the
* configurable "Describe" step (configured using input-forms.xml) overrides
* this method to return the number of pages that are defined by its
* configuration file.
* <P>
* Steps which are non-interactive (i.e. they do not display an interface to
* the user) should return a value of 1, so that they are only processed
* once!
*
* @param request
* The HTTP Request
* @param subInfo
* The current submission information object
*
* @return the number of pages in this step
*/
public abstract int getNumberOfPages(HttpServletRequest request,
SubmissionInfo subInfo) throws ServletException;
/**
* Find out which page a user is currently viewing
*
* @param request
* HTTP request
*
* @return current page
*/
public static final int getCurrentPage(HttpServletRequest request)
{
int pageNum = -1;
// try to retrieve cached page from request attribute
Integer currentPage = (Integer) request.getAttribute("submission.page");
if (currentPage == null)
{
// try and get it as a 'page' parameter
String val = request.getParameter("page");
try
{
pageNum = Integer.parseInt(val.trim());
}
catch (Exception e)
{
// Problem with parameter
pageNum = -1;
}
// if couldn't find page in request parameter
if (pageNum < 0)
{
// default to page #1, since no other optionsc
pageNum = 1;
setCurrentPage(request, pageNum);
}
else
{
// save to request attribute
setCurrentPage(request, pageNum);
}
}
else
{
pageNum = currentPage.intValue();
}
return pageNum;
}
/**
* Set which page a user is currently viewing
*
* @param request
* HTTP request
* @param pageNumber
* new current page
*/
public static final void setCurrentPage(HttpServletRequest request,
int pageNumber)
{
// set info to request
request.setAttribute("submission.page", new Integer(pageNumber));
}
}