From 80356f5c2ec031e5d7df2eec7a55b6bd67105fda Mon Sep 17 00:00:00 2001
From: Tim Donohue
- * E.g. for a value of "XMLUI", uses the config file named
- * item-submission-XMLUI.xml
- *
- * @param UIName
- * the name of the UI to load the Submission configuration for
- */
- public SubmissionConfigReader(String UIName) throws ServletException
- {
- this.UIName = UIName;
- buildInputs(configDir + SUBMIT_DEF_FILE_PREFIX + "-" + UIName + SUBMIT_DEF_FILE_SUFFIX);
+ buildInputs(configDir + SUBMIT_DEF_FILE_PREFIX + SUBMIT_DEF_FILE_SUFFIX);
}
/**
@@ -218,7 +200,7 @@ public class SubmissionConfigReader
if (submitName == null)
{
throw new ServletException(
- "No item submission process configuration designated as 'default' in 'submission-map' section of 'item-submission-" + getUIName() + ".xml'.");
+ "No item submission process configuration designated as 'default' in 'submission-map' section of 'item-submission.xml'.");
}
log.debug("Loading submission process config named '" + submitName
@@ -242,7 +224,7 @@ public class SubmissionConfigReader
{
throw new ServletException(
"Missing the Item Submission process config '" + submitName
- + "' (or unable to load) from 'item-submission-" + getUIName() + ".xml'.");
+ + "' (or unable to load) from 'item-submission.xml'.");
}
log.debug("Submission process config '" + submitName
@@ -332,16 +314,16 @@ public class SubmissionConfigReader
if (!foundMap)
{
throw new ServletException(
- "No collection to item submission map ('submission-map') found in 'item-submission-" + getUIName() + ".xml'");
+ "No collection to item submission map ('submission-map') found in 'item-submission.xml'");
}
if (!foundStepDefs)
{
- throw new ServletException("No 'step-definitions' section found in 'item-submission-" + getUIName() + ".xml'");
+ throw new ServletException("No 'step-definitions' section found in 'item-submission.xml'");
}
if (!foundSubmitDefs)
{
throw new ServletException(
- "No 'submission-definitions' section found in 'item-submission-" + getUIName() + ".xml'");
+ "No 'submission-definitions' section found in 'item-submission.xml'");
}
}
@@ -366,17 +348,17 @@ public class SubmissionConfigReader
if (id == null)
{
throw new SAXException(
- "name-map element is missing collection-handle attribute in 'item-submission-" + getUIName() + ".xml'");
+ "name-map element is missing collection-handle attribute in 'item-submission.xml'");
}
if (value == null)
{
throw new SAXException(
- "name-map element is missing submission-name attribute in 'item-submission-" + getUIName() + ".xml'");
+ "name-map element is missing submission-name attribute in 'item-submission.xml'");
}
if (content != null && content.length() > 0)
{
throw new SAXException(
- "name-map element has content in 'item-submission-" + getUIName() + ".xml', it should be empty.");
+ "name-map element has content in 'item-submission.xml', it should be empty.");
}
collectionToSubmissionConfig.put(id, value);
} // ignore any child node that isn't a "name-map"
@@ -410,12 +392,12 @@ public class SubmissionConfigReader
if (stepID == null)
{
throw new SAXException(
- "step element has no 'id' attribute in 'item-submission-" + getUIName() + ".xml', which is required in the 'step-definitions' section");
+ "step element has no 'id' attribute in 'item-submission.xml', which is required in the 'step-definitions' section");
}
else if (stepDefns.containsKey(stepID))
{
throw new SAXException(
- "There are two step elements with the id '" + stepID + "' in 'item-submission-" + getUIName() + ".xml'");
+ "There are two step elements with the id '" + stepID + "' in 'item-submission.xml'");
}
HashMap stepInfo = processStepChildNodes("step-definition", nd);
@@ -428,7 +410,7 @@ public class SubmissionConfigReader
if (stepDefns.size() < 1)
{
throw new ServletException(
- "step-definition section has no steps! A step with id='collection' is required in 'item-submission-" + getUIName() + ".xml'!");
+ "step-definition section has no steps! A step with id='collection' is required in 'item-submission.xml'!");
}
// Sanity check to see that the required "collection" step is defined
@@ -437,7 +419,7 @@ public class SubmissionConfigReader
throw new ServletException(
"The step-definition section is REQUIRED to have a step with id='"
+ SubmissionStepConfig.SELECT_COLLECTION_STEP
- + "' in 'item-submission-" + getUIName() + ".xml'! This step is used to ensure that a new item submission is assigned to a collection.");
+ + "' in 'item-submission.xml'! This step is used to ensure that a new item submission is assigned to a collection.");
}
// Sanity check to see that the required "complete" step is defined
@@ -446,7 +428,7 @@ public class SubmissionConfigReader
throw new ServletException(
"The step-definition section is REQUIRED to have a step with id='"
+ SubmissionStepConfig.COMPLETE_STEP
- + "' in 'item-submission-" + getUIName() + ".xml'! This step is used to perform all processing necessary at the completion of the submission (e.g. starting workflow).");
+ + "' in 'item-submission.xml'! This step is used to perform all processing necessary at the completion of the submission (e.g. starting workflow).");
}
}
@@ -482,13 +464,13 @@ public class SubmissionConfigReader
if (submitName == null)
{
throw new SAXException(
- "'submission-process' element has no 'name' attribute in 'item-submission-" + getUIName() + ".xml'");
+ "'submission-process' element has no 'name' attribute in 'item-submission.xml'");
}
else if (submitNames.contains(submitName))
{
throw new SAXException(
"There are two 'submission-process' elements with the name '"
- + submitName + "' in 'item-submission-" + getUIName() + ".xml'.");
+ + submitName + "' in 'item-submission.xml'.");
}
submitNames.add(submitName);
@@ -530,7 +512,7 @@ public class SubmissionConfigReader
+ submitName
+ " contains a step with id="
+ stepID
- + ". There is no step with this 'id' defined in the 'step-definition' section of 'item-submission-" + getUIName() + ".xml'.");
+ + ". There is no step with this 'id' defined in the 'step-definition' section of 'item-submission.xml'.");
}
// Ignore all children of a step element with an
@@ -554,7 +536,7 @@ public class SubmissionConfigReader
{
throw new ServletException(
"Item Submission process config named "
- + submitName + " has no steps defined in 'item-submission-" + getUIName() + ".xml'");
+ + submitName + " has no steps defined in 'item-submission.xml'");
}
// ALL Item Submission processes MUST BEGIN with selecting a
@@ -579,7 +561,7 @@ public class SubmissionConfigReader
if (numSubmitProcesses == 0)
{
throw new ServletException(
- "No 'submission-process' elements/definitions found in 'item-submission-" + getUIName() + ".xml'");
+ "No 'submission-process' elements/definitions found in 'item-submission.xml'");
}
}
@@ -627,7 +609,7 @@ public class SubmissionConfigReader
{
String msg = "Required field " + missing
+ " missing in a 'step' in the " + configSection
- + " of the item submission configuration file ('item-submission-" + getUIName() + ".xml')";
+ + " of the item submission configuration file ('item-submission.xml')";
throw new SAXException(msg);
}
@@ -706,12 +688,4 @@ public class SubmissionConfigReader
// Didn't find a text node
return null;
}
-
- public String getUIName() {
- return UIName;
- }
-
- private void setUIName(String name) {
- UIName = name;
- }
}
diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionInfo.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionInfo.java
index bb15bec032..153c2c8f51 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionInfo.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionInfo.java
@@ -127,11 +127,7 @@ public class SubmissionInfo
* for a new submission.
*
* @param request
- * The HTTP Servlet Request object
- * @param briefUIName
- * The brief name of the User Interface to
- * load the Submission Configuration and Information for
- * (e.g. "jspui" or "xmlui")
+ * The HTTP Servlet Request object
* @param subItem
* The in-progress submission we are loading information for
*
@@ -140,19 +136,16 @@ public class SubmissionInfo
* @throws ServletException
* if an error occurs
*/
- public static SubmissionInfo load(HttpServletRequest request,
- String briefUIName, InProgressSubmission subItem) throws ServletException
+ public static SubmissionInfo load(HttpServletRequest request, InProgressSubmission subItem) throws ServletException
{
boolean forceReload = false;
SubmissionInfo subInfo = new SubmissionInfo();
// load SubmissionConfigReader only the first time
// or if we're using a different UI now.
- if (submissionConfigReader == null ||
- submissionConfigReader.getUIName() == null ||
- !submissionConfigReader.getUIName().equals(briefUIName))
+ if (submissionConfigReader == null)
{
- submissionConfigReader = new SubmissionConfigReader(briefUIName);
+ submissionConfigReader = new SubmissionConfigReader();
forceReload=true;
}
@@ -223,7 +216,7 @@ public class SubmissionInfo
/**
* Causes the SubmissionConfig to be completely reloaded from the XML
- * configuration file (item-submission-[UI Name].xml).
+ * configuration file (item-submission.xml).
*
* Note: This also reloads the progress bar info, since the progress bar
* depends entirely on the submission process (and its steps).
diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionStepConfig.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionStepConfig.java
index b52886f1c1..e415d2fe94 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionStepConfig.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionStepConfig.java
@@ -48,7 +48,7 @@ import org.apache.log4j.Logger;
* Class representing configuration for a single step within an Item Submission
* Process. In other words, this is a single step in the SubmissionConfig class.
* This class represents the structure of a single 'step' node in the
- * item-submission-[UI Name].xml configuration file.
+ * item-submission.xml configuration file.
*
* @see org.dspace.app.util.SubmissionConfigReader
* @see org.dspace.app.util.SubmissionConfig
@@ -79,19 +79,22 @@ public class SubmissionStepConfig
/** the name of the java processing class for this step */
private String processingClassName = null;
-
- /** the review-jsp for this step */
- private String reviewJSP = null;
-
+
/** whether or not this step is editable during workflow (default=true) */
private boolean workflowEditable = true;
+ /**
+ * The full name of the JSP-UI binding class for this step. This field is
+ * ONLY used by the JSP-UI.
+ **/
+ private String jspBindingClassName = null;
+
/**
* The full name of the Manakin XML-UI Transformer class which will generate
* the necessary DRI for displaying this class in Manakin. This field is
* ONLY used by the Manakin XML-UI.
*/
- private String xmlUIClassName = null;
+ private String xmlBindingClassName = null;
/** The number of this step in the current SubmissionConfig */
private int number = -1;
@@ -119,8 +122,8 @@ public class SubmissionStepConfig
id = (String) stepMap.get("id");
heading = (String) stepMap.get("heading");
processingClassName = (String) stepMap.get("processing-class");
- reviewJSP = (String) stepMap.get("review-jsp");
- xmlUIClassName = (String) stepMap.get("xml-ui-class");
+ jspBindingClassName = (String) stepMap.get("jspui-binding");
+ xmlBindingClassName = (String) stepMap.get("xmlui-binding");
String wfEditString = (String) stepMap.get("workflow-editable");
if (wfEditString != null && wfEditString.length() > 0)
@@ -156,9 +159,8 @@ public class SubmissionStepConfig
/**
* Get the class which handles all processing for this step.
*
- * This class must extend either the org.dspace.submit.SubmissionStep class
- * (for JSP UI) or org.dspace.submit.AbstractProcessingStep class (for
- * Manakin XML UI).
+ * This class must extend the org.dspace.submit.AbstractProcessingStep class,
+ * and provide processing for BOTH the JSP-UI and XML-UI
*
* @return the class's full class path (e.g.
* "org.dspace.submit.step.MySampleStep")
@@ -168,36 +170,38 @@ public class SubmissionStepConfig
return processingClassName;
}
- /**
- * Get the review jsp for this step. The "review jsp" is a JSP page which
- * will load all the user's answers given for this step to allow the user to
- * review his/her answers.
- *
- * This "review jsp" is used by the "Verify" step to allow the user to
- * verify/review all of his/her answers.
- *
- * @return the JSPs full path
- */
- public String getReviewJSP()
- {
- return reviewJSP;
- }
-
/**
* Retrieve the full class name of the Manakin Transformer which will
* generate this step's DRI, for display in Manakin XML-UI.
*
* This class must extend the
- * org.dspace.app.xmlui.submit.step.SubmissionStep class.
+ * org.dspace.app.xmlui.aspect.submission.StepTransformer class.
*
* This property is only used by the Manakin XML-UI, and therefore is not
- * relevant if you are using JSPs.
+ * relevant if you are using the JSP-UI.
*
- * @return the full java class name of the Transformer for this class
+ * @return the full java class name of the Transformer to use for this step
*/
public String getXMLUIClassName()
{
- return xmlUIClassName;
+ return xmlBindingClassName;
+ }
+
+ /**
+ * Retrieve the full class name of the JSP-UI "binding" class which will
+ * initialize and call the necessary JSPs for display in the JSP-UI
+ *
+ * This class must extend the
+ * org.dspace.app.webui.submit.JSPStep class.
+ *
+ * This property is only used by the JSP-UI, and therefore is not
+ * relevant if you are using the XML-UI (aka. Manakin).
+ *
+ * @return the full java class name of the JSPStep to use for this step
+ */
+ public String getJSPUIClassName()
+ {
+ return jspBindingClassName;
}
/**
diff --git a/dspace-api/src/main/java/org/dspace/submit/AbstractProcessingStep.java b/dspace-api/src/main/java/org/dspace/submit/AbstractProcessingStep.java
index 328d44e08a..2d21d8cc84 100644
--- a/dspace-api/src/main/java/org/dspace/submit/AbstractProcessingStep.java
+++ b/dspace-api/src/main/java/org/dspace/submit/AbstractProcessingStep.java
@@ -125,6 +125,9 @@ public abstract class AbstractProcessingStep
/** 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
@@ -159,47 +162,84 @@ public abstract class AbstractProcessingStep
* step processing. This list is for usage in generating the appropriate
* error message(s) in the UI.
*
- * The list of fields which had errors should be set by the step's
+ * 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 final List getErrorFields()
+ public static final List getErrorFields(HttpServletRequest request)
{
- return this.errorFields;
+ 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.
+ *
+ * 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 internal list of all error fields (which can
+ * Add a single UI field to the list of all error fields (which can
* later be retrieved using getErrorFields())
*
- * The list of fields which had errors should be set by the step's
+ * 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 final void addErrorField(String fieldName)
+ protected static final void addErrorField(HttpServletRequest request, String fieldName)
{
- if (this.errorFields == null)
+ //get current list
+ List errorFields = getErrorFields(request);
+
+ if (errorFields == null)
{
- this.errorFields = new ArrayList();
+ errorFields = new ArrayList();
}
- this.errorFields.add(fieldName);
+ //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 final void clearErrorFields()
+ protected static final void clearErrorFields(HttpServletRequest request)
{
- if (this.errorFields != null)
- this.errorFields.clear();
+ //get current list
+ List errorFields = getErrorFields(request);
+
+ if (errorFields != null)
+ setErrorFields(request,null);
}
/**
diff --git a/dspace-api/src/main/java/org/dspace/submit/step/DescribeStep.java b/dspace-api/src/main/java/org/dspace/submit/step/DescribeStep.java
index 465794a1bd..04d3083117 100644
--- a/dspace-api/src/main/java/org/dspace/submit/step/DescribeStep.java
+++ b/dspace-api/src/main/java/org/dspace/submit/step/DescribeStep.java
@@ -106,12 +106,8 @@ public class DescribeStep extends AbstractProcessingStep
/** Constructor */
public DescribeStep() throws ServletException
{
- // load inputsReader only the first time
- if (inputsReader == null)
- {
- // read configurable submissions forms data
- inputsReader = new DCInputsReader();
- }
+ //load the DCInputsReader
+ getInputsReader();
}
@@ -268,7 +264,7 @@ public class DescribeStep extends AbstractProcessingStep
// Step 3:
// Check to see if any fields are missing
- clearErrorFields();
+ clearErrorFields(request);
for (int i = 0; i < inputs.length; i++)
{
DCValue[] values = item.getMetadata(inputs[i].getSchema(),
@@ -277,7 +273,7 @@ public class DescribeStep extends AbstractProcessingStep
if (inputs[i].isRequired() && values.length == 0)
{
// since this field is missing add to list of error fields
- addErrorField(getFieldName(inputs[i]));
+ addErrorField(request, getFieldName(inputs[i]));
}
}
@@ -294,7 +290,7 @@ public class DescribeStep extends AbstractProcessingStep
return STATUS_MORE_INPUT_REQUESTED;
}
// if one or more fields errored out, return
- else if (getErrorFields() != null && getErrorFields().size() > 0)
+ else if (getErrorFields(request) != null && getErrorFields(request).size() > 0)
{
return STATUS_MISSING_REQUIRED_FIELDS;
}
@@ -353,8 +349,15 @@ public class DescribeStep extends AbstractProcessingStep
*
* @return the current DCInputsReader
*/
- public static DCInputsReader getInputsReader()
+ public static DCInputsReader getInputsReader() throws ServletException
{
+ // load inputsReader only the first time
+ if (inputsReader == null)
+ {
+ // read configurable submissions forms data
+ inputsReader = new DCInputsReader();
+ }
+
return inputsReader;
}
diff --git a/dspace-api/src/main/java/org/dspace/submit/step/InitialQuestionsStep.java b/dspace-api/src/main/java/org/dspace/submit/step/InitialQuestionsStep.java
index 7b835ff312..603993ba0d 100644
--- a/dspace-api/src/main/java/org/dspace/submit/step/InitialQuestionsStep.java
+++ b/dspace-api/src/main/java/org/dspace/submit/step/InitialQuestionsStep.java
@@ -232,6 +232,11 @@ public class InitialQuestionsStep extends AbstractProcessingStep
// to inform the user and make sure that's OK, before saving!
if (willRemoveTitles || willRemoveDate || willRemoveFiles)
{
+ //save what we will need to prune to request (for UI to process)
+ request.setAttribute("will.remove.titles", new Boolean(willRemoveTitles));
+ request.setAttribute("will.remove.date", new Boolean(willRemoveDate));
+ request.setAttribute("will.remove.files", new Boolean(willRemoveFiles));
+
return STATUS_VERIFY_PRUNE; // we will need to do pruning!
}
}
diff --git a/dspace-api/src/main/java/org/dspace/submit/step/UploadStep.java b/dspace-api/src/main/java/org/dspace/submit/step/UploadStep.java
index 3b7cafd675..b9f6d3b5a2 100644
--- a/dspace-api/src/main/java/org/dspace/submit/step/UploadStep.java
+++ b/dspace-api/src/main/java/org/dspace/submit/step/UploadStep.java
@@ -59,6 +59,7 @@ import org.dspace.content.Bundle;
import org.dspace.content.FormatIdentifier;
import org.dspace.content.Item;
import org.dspace.core.Context;
+import org.dspace.core.ConfigurationManager;
import org.dspace.submit.AbstractProcessingStep;
/**
@@ -465,8 +466,8 @@ public class UploadStep extends AbstractProcessingStep
Bitstream b = null;
//NOTE: File should already be uploaded.
- //Manakin does this automatically.
- //For JSP-UI, the JSPUploadStep.doProcessing() does the actual upload
+ //Manakin does this automatically via Cocoon.
+ //For JSP-UI, the SubmissionController.uploadFiles() does the actual upload
Enumeration attNames = request.getAttributeNames();
diff --git a/dspace-api/src/main/resources/Messages.properties b/dspace-api/src/main/resources/Messages.properties
index 1004793644..168fd71468 100644
--- a/dspace-api/src/main/resources/Messages.properties
+++ b/dspace-api/src/main/resources/Messages.properties
@@ -855,6 +855,7 @@ jsp.submit.no-theses.info5 = Thank you for
jsp.submit.no-theses.title = Theses Not Accepted in DSpace
jsp.submit.progressbar.complete = Complete
jsp.submit.progressbar.describe = Describe
+jsp.submit.progressbar.initial-questions = Describe
jsp.submit.progressbar.license = License
jsp.submit.progressbar.select = Select
jsp.submit.progressbar.upload = Upload
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/servlet/MyDSpaceServlet.java b/dspace-jspui/src/main/java/org/dspace/app/webui/servlet/MyDSpaceServlet.java
index b10f8c683c..2fae1e4146 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/servlet/MyDSpaceServlet.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/servlet/MyDSpaceServlet.java
@@ -553,7 +553,7 @@ public class MyDSpaceServlet extends DSpaceServlet
// Load the Submission Process for the collection this WSI is
// associated with
Collection c = wsi.getCollection();
- SubmissionConfigReader subConfigReader = new SubmissionConfigReader(SubmissionController.UI_NAME);
+ SubmissionConfigReader subConfigReader = new SubmissionConfigReader();
SubmissionConfig subConfig = subConfigReader.getSubmissionConfig(c
.getHandle(), false);
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/servlet/SubmissionController.java b/dspace-jspui/src/main/java/org/dspace/app/webui/servlet/SubmissionController.java
index cf1bf8edfb..4d5e885d2e 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/servlet/SubmissionController.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/servlet/SubmissionController.java
@@ -39,8 +39,13 @@
*/
package org.dspace.app.webui.servlet;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.sql.SQLException;
+import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -50,6 +55,7 @@ import org.apache.log4j.Logger;
import org.dspace.app.util.SubmissionInfo;
import org.dspace.app.util.SubmissionStepConfig;
+import org.dspace.app.util.Util;
import org.dspace.app.webui.submit.JSPStepManager;
import org.dspace.app.webui.util.FileUploadRequest;
import org.dspace.app.webui.util.JSPManager;
@@ -62,6 +68,7 @@ import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.workflow.WorkflowItem;
import org.dspace.submit.AbstractProcessingStep;
+import org.dspace.submit.step.UploadStep;
/**
* Submission Manager servlet for DSpace. Handles the initial submission of
@@ -124,9 +131,6 @@ public class SubmissionController extends DSpaceServlet
/** First step after "select collection" */
public static int FIRST_STEP = 1;
- /** "Name" of the JSP User Interface - Used to load SubmissionInfo **/
- public static String UI_NAME = "JSPUI";
-
/** path to the JSP shown once the submission is completed */
private static String COMPLETE_JSP = "/submit/complete.jsp";
@@ -170,7 +174,7 @@ public class SubmissionController extends DSpaceServlet
.parseInt(workspaceID));
//load submission information
- SubmissionInfo si = SubmissionInfo.load(request, UI_NAME, wi);
+ SubmissionInfo si = SubmissionInfo.load(request, wi);
//TD: Special case - If a user is resuming a submission
//where the submission process now has less steps, then
@@ -214,7 +218,7 @@ public class SubmissionController extends DSpaceServlet
.parseInt(workflowID));
//load submission information
- SubmissionInfo si = SubmissionInfo.load(request, UI_NAME, wi);
+ SubmissionInfo si = SubmissionInfo.load(request, wi);
//For workflows, first step is step #0
//(since Select Collection is already filtered out)
@@ -254,6 +258,9 @@ public class SubmissionController extends DSpaceServlet
&& (contentType.indexOf("multipart/form-data") != -1))
{
request = wrapMultipartRequest(request);
+
+ //also, upload any files and save their contents to Request (for later processing by UploadStep)
+ uploadFiles(context, request);
}
// Reload submission info from request parameters
@@ -394,7 +401,7 @@ public class SubmissionController extends DSpaceServlet
try
{
- JSPStepManager stepManager = JSPStepManager.loadStep(currentStepConfig.getProcessingClassName());
+ JSPStepManager stepManager = JSPStepManager.loadStep(currentStepConfig);
//tell the step class to do its processing
boolean stepFinished = stepManager.processStep(context, request, response, subInfo);
@@ -482,20 +489,7 @@ public class SubmissionController extends DSpaceServlet
else
{
// The Submission is COMPLETE!!
- /*
- log.info(LogManager.getHeader(context, "submission_complete",
- "Completed submission with id="
- + subInfo.getSubmissionItem().getID()));
-
- // save that user has reached last step
- userHasReached(subInfo, currentStepNum + 1);
-
- // Start the workflow
- WorkflowManager.start(context, (WorkspaceItem)subInfo.getSubmissionItem());
-
- // commit changes to database & close context
- context.complete();
- */
+
// save our current Submission information into the Request object
saveSubmissionInfo(request, subInfo);
@@ -905,19 +899,19 @@ public class SubmissionController extends DSpaceServlet
{
int workflowID = UIUtil.getIntParameter(request, "workflow_id");
- info = SubmissionInfo.load(request, UI_NAME, WorkflowItem.find(context, workflowID));
+ info = SubmissionInfo.load(request, WorkflowItem.find(context, workflowID));
}
else if(request.getParameter("workspace_item_id") != null)
{
int workspaceID = UIUtil.getIntParameter(request,
"workspace_item_id");
- info = SubmissionInfo.load(request, UI_NAME, WorkspaceItem.find(context, workspaceID));
+ info = SubmissionInfo.load(request, WorkspaceItem.find(context, workspaceID));
}
else
{
//by default, initialize Submission Info with no item
- info = SubmissionInfo.load(request, UI_NAME, null);
+ info = SubmissionInfo.load(request, null);
}
// We must have a submission object if after the first step,
@@ -1297,4 +1291,70 @@ public class SubmissionController extends DSpaceServlet
throw new ServletException(e);
}
}
+
+
+ /**
+ * Upload any files found on the Request, and save them back as
+ * Request attributes, for further processing by the appropriate user interface.
+ *
+ * @param context
+ * current DSpace context
+ * @param request
+ * current servlet request object
+ */
+ public void uploadFiles(Context context, HttpServletRequest request)
+ throws ServletException
+ {
+ FileUploadRequest wrapper = null;
+ String filePath = null;
+ InputStream fileInputStream = null;
+
+ try
+ {
+ // if we already have a FileUploadRequest, use it
+ if (Class.forName("org.dspace.app.webui.util.FileUploadRequest")
+ .isInstance(request))
+ {
+ wrapper = (FileUploadRequest) request;
+ }
+ else
+ {
+ // Wrap multipart request to get the submission info
+ wrapper = new FileUploadRequest(request);
+ }
+
+ Enumeration fileParams = wrapper.getFileParameterNames();
+ while(fileParams.hasMoreElements())
+ {
+ String fileName = (String) fileParams.nextElement();
+
+ File temp = wrapper.getFile(fileName);
+
+ //if file exists and has a size greater than zero
+ if (temp != null && temp.length() > 0)
+ {
+ // Read the temp file into an inputstream
+ fileInputStream = new BufferedInputStream(
+ new FileInputStream(temp));
+
+ filePath = wrapper.getFilesystemName(fileName);
+
+ // cleanup our temp file
+ temp.delete();
+
+ //save this file's info to request (for UploadStep class)
+ request.setAttribute(fileName + "-path", filePath);
+ request.setAttribute(fileName + "-inputstream", fileInputStream);
+ request.setAttribute(fileName + "-description", wrapper.getParameter("description"));
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ // Problem with uploading
+ log.warn(LogManager.getHeader(context, "upload_error", ""), e);
+ throw new ServletException(e);
+ }
+ }
+
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/JSPStep.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/JSPStep.java
index 840577f13d..23118e849c 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/JSPStep.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/JSPStep.java
@@ -60,10 +60,10 @@ import org.dspace.core.Context;
import org.dspace.submit.AbstractProcessingStep;
/**
- * Interface for DSpace Submission Steps which use the JSP UI.
+ * Abstract 'binding' class for DSpace Submission Steps which use the JSP-UI.
*
* These methods revolve around the following: (1) pre-processing of data to
- * prepare for display, (2) displaying data on JSP, and (3) processing of any
+ * prepare for display, (2) displaying the JSP, and (3) post-processing of any
* user input (or alternatively backend processing, for non-interactive steps).
*
* For the JSP UI, the job of this class is to maintain the context of where the
@@ -78,7 +78,7 @@ import org.dspace.submit.AbstractProcessingStep;
* specified will be displayed
*
+ * 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 abstract String getReviewJSP(Context context, HttpServletRequest request,
+ HttpServletResponse response, SubmissionInfo subInfo);
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/JSPStepManager.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/JSPStepManager.java
index 926bc71687..f971d7ec67 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/JSPStepManager.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/JSPStepManager.java
@@ -60,33 +60,10 @@ import org.dspace.core.Context;
import org.dspace.submit.AbstractProcessingStep;
/**
- * Abstract class for DSpace Submission Steps which use the JSP UI.
+ * Manages and processes all JSP-UI classes for DSpace Submission steps.
*
- * These methods revolve around the following: (1) pre-processing of data to
- * prepare for display, (2) displaying data on JSP, and (3) processing of any
- * user input (or alternatively backend processing, for non-interactive steps).
- *
- * For the JSP UI, the job of this class is to maintain the context of where the
- * user is within the current "step" of the submission process. Each "step" can
- * consist of multiple "pages" (which roughly correspond to HTML displays), so
- * this class helps manage which page the user should see next.
- *
- * The methods of the JSPStepManager are called in this order:
- *
+ * 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 stepJSPUI.getReviewJSP(context, request, response, subInfo);
+ }
+
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPCompleteStep.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPCompleteStep.java
index 1d37755942..495e4b6919 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPCompleteStep.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPCompleteStep.java
@@ -55,7 +55,7 @@ import org.dspace.core.Context;
import org.dspace.submit.step.CompleteStep;
/**
- * This is the class which defines what happens once a submission completes!
+ * This is the JSP binding class which defines what happens once a submission completes!
*
* This JSPCompleteStep class works with the SubmissionController servlet and
* when using the JSP-UI
@@ -68,12 +68,11 @@ import org.dspace.submit.step.CompleteStep;
*
* @see org.dspace.app.webui.servlet.SubmissionController
* @see org.dspace.app.webui.submit.JSPStep
- * @see org.dspace.submit.step.CompleteStep
*
* @author Tim Donohue
* @version $Revision$
*/
-public class JSPCompleteStep extends CompleteStep implements JSPStep
+public class JSPCompleteStep extends JSPStep
{
/** log4j logger */
private static Logger log = Logger.getLogger(JSPCompleteStep.class);
@@ -142,5 +141,28 @@ public class JSPCompleteStep extends CompleteStep implements JSPStep
//No post-processing necessary, since submission is complete!
}
+ /**
+ * Return the URL path (e.g. /submit/review-metadata.jsp) of the JSP
+ * which will review the information that was gathered in this Step.
+ *
+ * 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 NO_JSP; //no need to return a Review JSP as we are completed!
+ }
+
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPDescribeStep.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPDescribeStep.java
index ba779f93e6..0b1653a524 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPDescribeStep.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPDescribeStep.java
@@ -61,12 +61,12 @@ import org.dspace.core.LogManager;
import org.dspace.submit.step.DescribeStep;
/**
- * Describe step for DSpace submission process. Handles the pages that gather
+ * Describe step for DSpace JSP-UI submission process. Handles the pages that gather
* descriptive information (i.e. metadata) for an item being submitted into
* DSpace.
*
- * This JSPStepManager class works with the SubmissionController servlet
- * for the JSP-UI
+ * This JSPStep class works with the SubmissionController servlet
+ * for the JSP-UI.
*
* The following methods are called in this order:
*
+ * 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;
+ }
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPInitialQuestionsStep.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPInitialQuestionsStep.java
index 42f7a7a2a8..4f55c6fbbb 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPInitialQuestionsStep.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPInitialQuestionsStep.java
@@ -59,11 +59,11 @@ import org.dspace.core.Context;
import org.dspace.submit.step.InitialQuestionsStep;
/**
- * Initial Submission servlet for DSpace. Handles the initial questions which
+ * Initial Submission servlet for DSpace JSP-UI. Handles the initial questions which
* are asked to users to gather information regarding what metadata needs to be
* gathered.
*
- * This JSPStepManager class works with the SubmissionController servlet
+ * This JSPStep class works with the SubmissionController servlet
* for the JSP-UI
*
* The following methods are called in this order:
@@ -73,7 +73,7 @@ import org.dspace.submit.step.InitialQuestionsStep;
* specified will be displayed
*
+ * 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;
+ }
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPLicenseStep.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPLicenseStep.java
index ca38b861ef..de3d978173 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPLicenseStep.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPLicenseStep.java
@@ -64,10 +64,10 @@ import org.dspace.license.CreativeCommons;
import org.dspace.submit.step.LicenseStep;
/**
- * License servlet for DSpace. Presents the user with license information
+ * License step for DSpace JSP-UI. Presents the user with license information
* required for all items submitted into DSpace.
*
- * This JSPStepManager class works with the SubmissionController servlet
+ * This JSPStep class works with the SubmissionController servlet
* for the JSP-UI
*
* The following methods are called in this order:
@@ -77,7 +77,7 @@ import org.dspace.submit.step.LicenseStep;
* specified will be displayed
*
+ * 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 NO_JSP; //signing off on license does not require reviewing
+ }
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPSampleStep.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPSampleStep.java
index 3c52979bb1..50b833eb86 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPSampleStep.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPSampleStep.java
@@ -68,11 +68,12 @@ import org.dspace.submit.step.SampleStep;
*
* This step can be added to any Submission process (for testing purposes) by
* adding the following to the appropriate
+ * 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;
+ }
+
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPSelectCollectionStep.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPSelectCollectionStep.java
index 82fc1813dc..478bd2a3c3 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPSelectCollectionStep.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPSelectCollectionStep.java
@@ -62,9 +62,9 @@ import org.dspace.submit.step.SelectCollectionStep;
/**
* Step which controls selecting a Collection for the Item Submission process
- * for DSpace.
+ * for DSpace JSP-UI
*
- * This JSPStepManager class works with the SubmissionController servlet
+ * This JSPStep class works with the SubmissionController servlet
* for the JSP-UI
*
* The following methods are called in this order:
@@ -74,7 +74,7 @@ import org.dspace.submit.step.SelectCollectionStep;
* specified will be displayed
*
+ * 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 NO_JSP; //at this time, you cannot review what collection you selected.
+ }
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPUploadStep.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPUploadStep.java
index 109044cc0d..bcee7357eb 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPUploadStep.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPUploadStep.java
@@ -72,10 +72,10 @@ import org.dspace.core.LogManager;
import org.dspace.submit.step.UploadStep;
/**
- * Upload step for DSpace. Handles the pages that revolve around uploading files
+ * 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.
*
- * This JSPStepManager class works with the SubmissionController servlet
+ * This JSPStep class works with the SubmissionController servlet
* for the JSP-UI
*
* The following methods are called in this order:
@@ -85,7 +85,7 @@ import org.dspace.submit.step.UploadStep;
* specified will be displayed
*
- * 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 appropriate user interface (JSP-UI or XML-UI)
- *
- * 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 int doProcessing(Context context, HttpServletRequest request,
- HttpServletResponse response, SubmissionInfo subInfo)
- throws ServletException, IOException, SQLException,
- AuthorizeException
- {
- //get button user pressed
- String buttonPressed = Util.getSubmitButton(request, NEXT_BUTTON);
-
- //JSP UI has to upload the file before it can do other UI-generic processing
- FileUploadRequest wrapper = null;
- String filePath = null;
- InputStream fileInputStream = null;
- String contentType = request.getContentType();
-
- if (buttonPressed.equalsIgnoreCase(SUBMIT_UPLOAD_BUTTON))
- {
- // if multipart form, then we are uploading a file
- if ((contentType != null)
- && (contentType.indexOf("multipart/form-data") != -1))
- {
- try
- {
- // if we already have a FileUploadRequest, use it
- if (Class.forName("org.dspace.app.webui.util.FileUploadRequest")
- .isInstance(request))
- {
- wrapper = (FileUploadRequest) request;
- }
- else
- {
- // Wrap multipart request to get the submission info
- wrapper = new FileUploadRequest(request);
- }
-
- File temp = wrapper.getFile("file");
-
- //if file exists and has a size greater than zero
- if (temp != null && temp.length() > 0)
- {
- // Read the temp file into an inputstream
- fileInputStream = new BufferedInputStream(
- new FileInputStream(temp));
-
- filePath = wrapper.getFilesystemName("file");
-
- // cleanup our temp file
- temp.delete();
- }
-
- //save file info to request (for UploadStep class)
- request.setAttribute("file-path", filePath);
- request.setAttribute("file-inputstream", fileInputStream);
- request.setAttribute("file-description", wrapper.getParameter("description"));
- }
- catch (IOException ie)
- {
- // Problem with uploading
- log.warn(LogManager.getHeader(context, "upload_error", ""), ie);
- }
- catch (Exception e)
- {
- throw new ServletException(e);
- }
- }
- }
-
- //call super method to finish UploadStep processing
- return super.doProcessing(context, request, response, subInfo);
- }
/**
* Do any post-processing after the step's backend processing occurred (in
@@ -288,10 +198,10 @@ public class JSPUploadStep extends UploadStep implements JSPStep
throws ServletException, IOException, SQLException,
AuthorizeException
{
- String buttonPressed = UIUtil.getSubmitButton(request, NEXT_BUTTON);
+ String buttonPressed = UIUtil.getSubmitButton(request, UploadStep.NEXT_BUTTON);
// Do we need to skip the upload entirely?
- if (buttonPressed.equalsIgnoreCase(SUBMIT_SKIP_BUTTON))
+ if (buttonPressed.equalsIgnoreCase(UploadStep.SUBMIT_SKIP_BUTTON))
{
Bundle[] bundles = subInfo.getSubmissionItem().getItem()
.getBundles("ORIGINAL");
@@ -317,16 +227,16 @@ public class JSPUploadStep extends UploadStep implements JSPStep
// Check for Errors!
// ------------------------------
// if an error or message was passed back, determine what to do!
- if (status != STATUS_COMPLETE)
+ if (status != UploadStep.STATUS_COMPLETE)
{
- if (status == STATUS_INTEGRITY_ERROR)
+ 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 == STATUS_UPLOAD_ERROR || status == STATUS_NO_FILES_ERROR)
+ else if (status == UploadStep.STATUS_UPLOAD_ERROR || status == UploadStep.STATUS_NO_FILES_ERROR)
{
// There was a problem uploading the file!
@@ -349,7 +259,7 @@ public class JSPUploadStep extends UploadStep implements JSPStep
JSPStepManager.showJSP(request, response, subInfo, UPLOAD_ERROR_JSP);
}
}
- else if (status == STATUS_UNKNOWN_FORMAT)
+ else if (status == UploadStep.STATUS_UNKNOWN_FORMAT)
{
// user uploaded a file where the format is unknown to DSpace
@@ -360,7 +270,7 @@ public class JSPUploadStep extends UploadStep implements JSPStep
// As long as there are no errors, clicking Next
// should immediately send them to the next step
- if (status == STATUS_COMPLETE && buttonPressed.equals(NEXT_BUTTON))
+ if (status == UploadStep.STATUS_COMPLETE && buttonPressed.equals(UploadStep.NEXT_BUTTON))
{
// just return, so user will continue on to next step!
return;
@@ -369,7 +279,7 @@ public class JSPUploadStep extends UploadStep implements JSPStep
// ------------------------------
// Check for specific buttons
// ------------------------------
- if (buttonPressed.equals(SUBMIT_MORE_BUTTON))
+ if (buttonPressed.equals(UploadStep.SUBMIT_MORE_BUTTON))
{
// Upload another file (i.e. show the Choose File jsp again)
showChooseFile(context, request, response, subInfo);
@@ -614,4 +524,27 @@ public class JSPUploadStep extends UploadStep implements JSPStep
// 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.
+ *
+ * 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;
+ }
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPVerifyStep.java b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPVerifyStep.java
index 26ff4245d2..0301ab61ff 100644
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPVerifyStep.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/submit/step/JSPVerifyStep.java
@@ -94,7 +94,7 @@ import org.dspace.submit.step.VerifyStep;
* @author Tim Donohue
* @version $Revision$
*/
-public class JSPVerifyStep extends VerifyStep implements JSPStep
+public class JSPVerifyStep extends JSPStep
{
/** JSP which displays initial questions * */
public static final String VERIFY_JSP = "/submit/review.jsp";
@@ -173,14 +173,25 @@ public class JSPVerifyStep extends VerifyStep implements JSPStep
// load this step's information
SubmissionStepConfig s = subProcessConfig.getStep(stepNum);
- // get this step's review JSP
- String reviewJSP = s.getReviewJSP();
-
- if ((reviewJSP != null) && (reviewJSP.length() > 0))
+ try
{
- // save the path to this steps JSP to our reviewData Hashmap
- // (with the key = stepNum.pageNum)
- reviewData.put(stepAndPage, reviewJSP);
+ JSPStepManager stepManager = JSPStepManager.loadStep(s);
+
+ // get this step's review JSP
+ String reviewJSP = stepManager.getReviewJSP(context, request, response, subInfo);
+
+ if ((reviewJSP != null) && (reviewJSP.length() > 0))
+ {
+ // save the path to this steps JSP to our reviewData Hashmap
+ // (with the key = stepNum.pageNum)
+ reviewData.put(stepAndPage, reviewJSP);
+ }
+ }
+ catch(Exception e)
+ {
+ log.error("Problem loading Review JSP for step #" + s.getStepNumber() + ". ", e);
+ JSPManager.showIntegrityError(request, response);
+ return;
}
}
}
@@ -233,4 +244,27 @@ public class JSPVerifyStep extends VerifyStep implements JSPStep
{
// nothing to do from the Verify Step.
}
+
+ /**
+ * Return the URL path (e.g. /submit/review-metadata.jsp) of the JSP
+ * which will review the information that was gathered in this Step.
+ *
+ * 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 NO_JSP; //no review JSP, since this is the verification step
+ }
}
diff --git a/dspace-jspui/src/main/java/org/dspace/app/webui/util/FileUploadRequest.java b/dspace-jspui/src/main/java/org/dspace/app/webui/util/FileUploadRequest.java
index 078fcdb618..74db970c5d 100755
--- a/dspace-jspui/src/main/java/org/dspace/app/webui/util/FileUploadRequest.java
+++ b/dspace-jspui/src/main/java/org/dspace/app/webui/util/FileUploadRequest.java
@@ -181,8 +181,9 @@ public class FileUploadRequest extends HttpServletRequestWrapper
public File getFile(String name)
{
- String filename = getFilename(((FileItem) fileitems.get(name))
- .getName());
+ FileItem temp = (FileItem) fileitems.get(name);
+ String tempName = temp.getName();
+ String filename = getFilename(tempName);
if ("".equals(filename.trim()))
{
return null;
@@ -190,6 +191,12 @@ public class FileUploadRequest extends HttpServletRequestWrapper
return new File(tempDir + File.separator + filename);
}
+ public Enumeration getFileParameterNames()
+ {
+ Collection c = fileitems.keySet();
+ return Collections.enumeration(c);
+ }
+
public Enumeration getFileNames()
{
return filenames.elements();
diff --git a/dspace-jspui/src/main/webapp/submit/progressbar.jsp b/dspace-jspui/src/main/webapp/submit/progressbar.jsp
index 39041bc42f..ef2bab0592 100644
--- a/dspace-jspui/src/main/webapp/submit/progressbar.jsp
+++ b/dspace-jspui/src/main/webapp/submit/progressbar.jsp
@@ -122,10 +122,11 @@
String heading = (String) progressBarInfo.get(stepAndPage);
//if the heading contains a period (.), then assume
- //it is referencing a property in Messages.properties
+ //it is referencing a key in Messages.properties
if(heading.indexOf(".") >= 0)
{
- heading = LocaleSupport.getLocalizedMessage(pageContext, heading);
+ //prepend the existing key with "jsp." since we are using JSP-UI
+ heading = LocaleSupport.getLocalizedMessage(pageContext, "jsp." + heading);
}
//split into stepNum and pageNum
diff --git a/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/submission/AbstractStep.java b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/submission/AbstractStep.java
index ee4e94a591..4b392a75ff 100644
--- a/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/submission/AbstractStep.java
+++ b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/submission/AbstractStep.java
@@ -281,7 +281,9 @@ abstract public class AbstractStep extends AbstractDSpaceTransformer
while(i.hasNext())
{
String entryNum = (String) i.next();
- String entryNameKey = (String) progBarInfo.get(entryNum);
+
+ //Since we are using XML-UI, we need to prepend the heading key with "xmlui.Submission."
+ String entryNameKey = "xmlui.Submission." + (String) progBarInfo.get(entryNum);
//the value of entryNum is current step & page
//(e.g. 1.2 is page 2 of step 1)
diff --git a/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/submission/FlowUtils.java b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/submission/FlowUtils.java
index 0bb3bd2d63..c0d552c1c4 100644
--- a/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/submission/FlowUtils.java
+++ b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/submission/FlowUtils.java
@@ -43,8 +43,6 @@ package org.dspace.app.xmlui.aspect.submission;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.ServletException;
@@ -78,8 +76,8 @@ import org.dspace.workflow.WorkflowManager;
* Since data validation is cumbersome inside a flow script this
* is a collection of methods to preform processing at each step
* of the flow, the flow script will ties these operations
- * together in a meaningfull order but all actualy processing
- * is done through these variaus processes.
+ * together in a meaningful order but all actually processing
+ * is done through these various processes.
*
* @author Scott Phillips
* @author Tim Donohue (modified for Configurable Submission)
@@ -89,10 +87,6 @@ public class FlowUtils {
private static Logger log = Logger.getLogger(FlowUtils.class);
- /** "Name" of the XML-based User Interface - Used to load SubmissionInfo **/
- private static String UI_NAME = "XMLUI";
-
-
/** Where the submissionInfo is stored on an HTTP Request object */
private final static String DSPACE_SUBMISSION_INFO = "dspace.submission.info";
@@ -190,7 +184,7 @@ public class FlowUtils {
.get(HttpEnvironment.HTTP_REQUEST_OBJECT);
// load submission info
- subInfo = SubmissionInfo.load(httpRequest, UI_NAME, submission);
+ subInfo = SubmissionInfo.load(httpRequest, submission);
// Set the session ID
context.setExtraLogInfo("session_id="
@@ -456,7 +450,7 @@ public class FlowUtils {
//Load the Submission Process for the collection this WSI is associated with
Collection c = wsi.getCollection();
- SubmissionConfigReader subConfigReader = new SubmissionConfigReader(UI_NAME);
+ SubmissionConfigReader subConfigReader = new SubmissionConfigReader();
SubmissionConfig subConfig = subConfigReader.getSubmissionConfig(c.getHandle(), false);
// Set the "stage_reached" column on the workspace item
diff --git a/dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Submission/submission.js b/dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Submission/submission.js
index aa254fc259..0a964e6dc1 100644
--- a/dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Submission/submission.js
+++ b/dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Submission/submission.js
@@ -535,7 +535,7 @@ function processPage(workspaceID, stepConfig, page)
{
//save error fields to global ERROR_FIELDS variable,
//for step-specific post-processing
- saveErrorFields(stepClass.getErrorFields());
+ saveErrorFields(stepClass.getErrorFields(getHttpRequest()));
}
else //otherwise, no errors at all
{
diff --git a/dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml b/dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml
index 41e29556d8..9e588a1780 100644
--- a/dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml
+++ b/dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml
@@ -489,15 +489,6 @@
PLEASE NOTE: There are separate submission configuration files based on whether
- you plan to use the DSpace JSP User Interface (JSP-UI) or the DSpace XML User Interface (XML-UI, aka. Manakin)
- The DSpace will automatically know which Each of the This section decribes how Steps of the Submission Process are defined within the This section describes how Steps of the Submission Process are defined within the
- *
+ * This manager is utilized by the SubmissionController to appropriately
+ * load each JSP-UI step, and process any information returned by each step
*
* @see org.dspace.submit.AbstractProcessingStep
* @see org.dspace.app.webui.servlet.SubmissionController
@@ -101,9 +78,17 @@ public class JSPStepManager
private static Logger log = Logger.getLogger(JSPStepManager.class);
/**
- * Current JSP step that is being processed by the JSPStepManager
+ * Current Processing class for step that is being processed by the JSPStepManager
+ * This is the class that performs processing of information entered in during a step
*/
- private JSPStep step = null;
+ private AbstractProcessingStep stepProcessing = null;
+
+ /**
+ * Current JSP-UI binding class for step that is being processed by the JSPStepManager
+ * This is the class that manages calling all JSPs, and determines if additional processing
+ * of information (or confirmation) is necessary.
+ */
+ private JSPStep stepJSPUI = null;
/**
* The SubmissionStepConfig object describing the current step
@@ -114,36 +99,62 @@ public class JSPStepManager
* Initialize the current JSPStepManager object, by loading the
* specified step class.
*
- * @param JSPStepClassName
- * the full class name of the JSPStep which
- * this JSPStepManager should initialize with
+ * @param stepConfig
+ * the SubmissionStepConfig object which describes
+ * this step's configuration in the item-submission.xml
*
* @throws Exception
* if the JSPStep cannot be loaded or the class
* specified doesn't implement the JSPStep interface
*/
- public static JSPStepManager loadStep(String JSPStepClassName) throws Exception
+ public static JSPStepManager loadStep(SubmissionStepConfig stepConfig) throws Exception
{
+
JSPStepManager stepManager = new JSPStepManager();
- // load the step class (using the current class loader)
+ //save step configuration
+ stepManager.stepConfig = stepConfig;
+
+
+ /*
+ * First, load the step processing class (using the current class loader)
+ */
ClassLoader loader = stepManager.getClass().getClassLoader();
Class stepClass = loader
- .loadClass(JSPStepClassName);
+ .loadClass(stepConfig.getProcessingClassName());
Object stepInstance = stepClass.newInstance();
- if(stepInstance instanceof JSPStep &&
- stepInstance instanceof AbstractProcessingStep)
+ if(stepInstance instanceof AbstractProcessingStep)
{
// load the JSPStep interface for this step
- stepManager.step = (JSPStep) stepClass.newInstance();
+ stepManager.stepProcessing = (AbstractProcessingStep) stepClass.newInstance();
}
else
{
- throw new Exception("The submission step class specified by '" + JSPStepClassName +
- "' EITHER does not implement the interface org.dspace.app.webui.JSPStep" +
- " OR does not extend the class org.dspace.submit.AbstractProcessingStep!" +
+ throw new Exception("The submission step class specified by '" + stepConfig.getProcessingClassName() +
+ "' does not extend the class org.dspace.submit.AbstractProcessingStep!" +
+ " Therefore it cannot be used by the Configurable Submission as the
@@ -75,7 +75,7 @@ import org.dspace.submit.step.DescribeStep;
* specified will be displayed
*
Understanding the Submission Configuration File
-
-
+ [dspace]/config/item-submission-JSPUI.xml
- This is the JSP-UI configuration file[dspace]/config/item-submission-XMLUI.xml
- This is the XML-UI configuration file[dspace]/config/item-submission.xml
contains the submission configurations for both the DSpace JSP user interface (JSP-UI) or the DSpace XML user interface
+ (XML-UI or Manakin). This configuration file contains detailed documentation within the file itself,
+ which should help you better understand how to best utilize it.
item-submission.xml
to utilize based on the DSpace user interface being used.
- However, should you wish to make configuration changes, you must make sure to do so in the correct item-submission.xml
- file based on the DSpace user interface you are using!item-submission.xml
configuration files contains detailed documentation within the file itself,
- which should help you better undertand how to best utilize it.The Structure of
item-submission.xml
<item-submission>
@@ -91,14 +81,14 @@
Defining Steps (
- <step>
) within the item-submission.xml
item-submission.xml
.item-submission.xml
.Where to place your
<step>
definitions<step>
definitions can appear in one of two places within the item-submission.xml
configuration file.
<step-definitions>
section
-
<step>
definitions
+ <step>
definitions
(i.e. steps which are used in multiple <submission-process>
definitions). Steps defined in this section must define
a unique id
which can be used to reference this step.
For example, the following defines a Submission Process where the - License step directly precedes the Describe step + License step directly precedes the Initial Questions step (more information about the structure of the information under each <step> tag can be found in the section on Structure of the <step> Definition below):
-(PLEASE NOTE: This example uses some syntax that is specific to the DSpace JSP user interface.) -
<submission-process>
<!--Step 1 will be to Sign off on the License-->
<step>
- <heading>jsp.submit.progressbar.license</heading>
- <processing-class>org.dspace.app.webui.submit.step.JSPLicenseStep</processing-class>
+ <heading>submit.progressbar.license</heading>
+ <processing-class>org.dspace.submit.step.LicenseStep</processing-class>
+ <jspui-binding>org.dspace.app.webui.submit.step.JSPLicenseStep</jspui-binding>
+ <xmlui-binding>org.dspace.app.xmlui.aspect.submission.submit.LicenseStep</xmlui-binding>
<workflow-editable>false</workflow-editable>
</step>
- <!--Step 2 will be to Describe the Item-->
+ <!--Step 2 will be to Ask Initial Questions-->
<step>
- <heading>jsp.submit.progressbar.describe</heading>
- <processing-class>org.dspace.app.webui.submit.step.JSPDescribeStep</processing-class>
- <review-jsp>/submit/review-metadata.jsp</review-jsp>
+ <heading>submit.progressbar.initial-questions</heading>
+ <processing-class>org.dspace.submit.step.InitialQuestionsStep</processing-class>
+ <jspui-binding>org.dspace.app.webui.submit.step.JSPInitialQuestionsStep</jspui-binding>
+ <xmlui-binding>org.dspace.app.xmlui.aspect.submission.submit.InitialQuestionsStep</xmlui-binding>
<workflow-editable>true</workflow-editable>
</step>
- ...
+
+ ...[other steps]...
</submission-process>
@@ -167,59 +159,65 @@
The actual structure of the <step> definition differs slightly, based on whether - you are using the DSpace JSP user interface (JSP-UI) or the DSpace XML user interface - (XML-UI or Manakin). Unfortunately the same structure cannot be shared between - these user interfaces, since they each use different manners of generating the user interface.
-The same <step> definition is used by both the DSpace JSP user interface (JSP-UI) an the DSpace XML user interface + (XML-UI or Manakin). Therefore, you will notice each <step> definition contains information + specific to each of these two interfaces.
- -The structure of the <step> Definition for the JSP UI is as follows: +
The structure of the <step> Definition is as follows:
<step>
- <heading>jsp.submit.progressbar.describe</heading>
- <processing-class>org.dspace.app.webui.submit.step.JSPDescribeStep</processing-class>
- <review-jsp>/submit/review-metadata.jsp</review-jsp>
+ <heading>submit.progressbar.describe</heading>
+ <processing-class>org.dspace.submit.step.DescribeStep</processing-class>
+ <jspui-binding>org.dspace.app.webui.submit.step.JSPDescribeStep</jspui-binding>
+ <xmlui-binding>org.dspace.app.xmlui.aspect.submission.submit.DescribeStep</xmlui-binding>
<workflow-editable>true</workflow-editable>
- </step>
+ </step>
- Each step
contains the following elements, for the JSP UI. The required elements are so marked:
Each step
contains the following elements. The required elements are so marked:
heading
Messages.properties
) which corresponds to
- the text that should be displayed in the Submission Progress Bar for this step.
- This need not be defined, if the step should not appear in the progress bar
- (e.g. steps which are automatic and require no user interaction should not appear
- in the progress bar).Messages.properties
for JSP-UI or messages.xml
for XML-UI) which corresponds to
+ the text that should be displayed in the submission Progress Bar for this step.
+ This partial I18N key is prefixed within either the Messages.properties or messages.xml file, depending on the interface you are using.
+ Therefore, to find the actual key, you will need to search for the partial key with the following prefix:
+ xmlui.Submission.
(e.g. "xmlui.Submission.submit.progressbar.describe" for 'Describe' step)jsp.
(e.g. "jsp.submit.progressbar.describe" for 'Describe' step)processing-class
(Required)org.dspace.app.webui.submit.JSPStep
` AND
- extend the abstract `org.dspace.submit.AbstractProcessingStep
` class
- (or alternatively, extend one of the existing step processing classes in
+ org.dspace.submit.AbstractProcessingStep
` class
+ (or alternatively, extend one of the pre-existing step processing classes in
org.dspace.submit.step.*
)review-jsp
jspui-binding
review-
- that exist within the /jsp/submit
directory of DSpace.
- This need not be defined if the step has no information that should be later reviewed
- (e.g. The License step doesn't need a review JSP as the act of
- agreeing to a submission license is not considered reviewable)org.dspace.app.webui.submit.JSPStep
` class.
+ This property need not be defined if you are using the XML-UI interface, or for steps which
+ only perform automated processing, i.e. non-interactive steps.
+ xmlui-binding
org.dspace.app.xmlui.submission.AbstractSubmissionStep
` class.
+ This property need not be defined if you are using the JSP-UI interface, or for steps which
+ only perform automated processing, i.e. non-interactive steps.
+ workflow-editable
The structure of the <step> Definition for the XML UI is as follows: -
- <step>
- <heading>jsp.submit.progressbar.describe</heading>
- <processing-class>org.dspace.submit.step.DescribeStep</processing-class>
- <xml-ui-class>org.dspace.app.xmlui.submission.submit.DescribeStep</xml-ui-class>
- <workflow-editable>true</workflow-editable>
- </step>
-
-
-
- Each step
contains the following elements, for the XML UI. The required elements are so marked:
heading
config/i18n/messages.xml
) which corresponds to
- the text that should be displayed in the Submission Progress Bar for this step.
- This need not be defined, if the step should not appear in the progress bar
- (e.g. steps which are automatic and require no user interaction should not appear
- in the progress bar).processing-class
(Required)org.dspace.submit.AbstractProcessingStep
` class,
- and implement all necessary methods in that class.xml-ui-class
org.dspace.app.xmlui.submission.AbstractSubmissionStep
` class,
- and implement all necessary methods in that class.
- Note: This need not be defined if the step is automated and requires no user interaction (i.e. requires no user interface)workflow-editable
true
- and false
. If undefined, defaults to true
(which
- means that workflow reviewers would be allowed to edit information gathered
- during that step).First, a warning: Creating a new Submission Step requires some Java knowledge,
+ First, a brief warning: Creating a new Submission Step requires some Java knowledge,
and is therefore recommended to be undertaken by a Java programmer whenever possible That being said, at a higher level, creating a new Submission Step
@@ -686,51 +634,38 @@
+ Non-interactive steps are ones that have no user interface and only perform backend processing.
+ You may find a need to create non-interactive steps which perform further processing of previously entered information.
+ To create a non-interactive step, do the following:
+
+
+
-
org.dspace.app.webui.submit.JSPStep
- AND extend the abstract
- org.dspace.submit.AbstractProcessingStep
class.org.dspace.submit.AbstractProcessingStep
class.
-
- org.dspace.submit.AbstractProcessingStep
class, which
- will perform the backend processing for both the
- JSP-UI and the XML-UI.
- org.dspace.app.webui.submit.JSPStep
, and extends the
- generic processing class you just created in #1 above.org.dspace.submit.AbstractProcessingStep
class and
+ implement all methods defined by that abstract class.
-
- org.dspace.app.webui.submit.JSPStep
+ and implement all methods defined there. It's recommended to use one
+ of the classes in org.dspace.app.webui.submit.step.*
as a reference.org.dspace.app.webui.submit.JSPStepManager
classreview-[step].jsp
) in the
[dspace-source]/jsp/submit
directory.
org.dspace.app.xmlui.submission.AbstractSubmissionStep
class.org.dspace.app.xmlui.submission.AbstractSubmissionStep
org.dspace.app.xmlui.submission.submit.*
as referencesitem-submission.xml
configuration file.
@@ -747,6 +682,37 @@
Creating a Non-Interactive Step
+
+
+
+ org.dspace.submit.AbstractProcessingStep
class. In this class
+ add any processing which this step will perform.item-submission.xml
at
+ the place where you wish this step to be called during the submission process.
+ For example, if you want it to be called immediately after the
+ existing 'Upload File' step, then place its configuration immediately after
+ the configuration for that 'Upload File' step. The configuration should look
+ similar to the following:
+ <step>
+ <processing-class>org.dspace.submit.step.MyNonInteractveStep</processing-class>
+ <workflow-editable>false</workflow-editable>
+</step>
+ Note: Non-interactive steps will not appear in the Progress Bar! Therefore, + your submitters will not even know they are there. However, because they are not + visible to your users, you should make sure that your non-interactive step does not + take a large amount of time to finish its processing and return control to the next step + (otherwise there will be a visible time delay in the user interface).