/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at * * http://www.dspace.org/license/ */ package org.dspace.submit.step; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; import java.util.Date; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.time.DateUtils; import org.apache.log4j.Logger; import org.dspace.app.util.SubmissionInfo; import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeManager; import org.dspace.authorize.ResourcePolicy; import org.dspace.content.*; import org.dspace.core.Context; import org.dspace.core.ConfigurationManager; import org.dspace.curate.Curator; import org.dspace.handle.HandleManager; /** * Upload step with the advanced embargo system for DSpace. Processes the actual * upload of files for an item being submitted into DSpace. * <P> * This class performs all the behind-the-scenes processing that * this particular step requires. This class's methods are utilized * by both the JSP-UI and the Manakin XML-UI * * @see org.dspace.app.util.SubmissionConfig * @see org.dspace.app.util.SubmissionStepConfig * @see org.dspace.submit.step.UploadStep * @see org.dspace.submit.AbstractProcessingStep * * @author Tim Donohue * @author Keiji Suzuki * @version $Revision$ */ public class UploadWithEmbargoStep extends UploadStep { public static final int STATUS_EDIT_POLICIES = 30; public static final int STATUS_EDIT_POLICIES_ERROR_SELECT_GROUP = 31; public static final int STATUS_EDIT_POLICIES_DUPLICATED_POLICY = 32; public static final int STATUS_EDIT_POLICY_ERROR_SELECT_GROUP = 33; public static final int STATUS_EDIT_POLICY_DUPLICATED_POLICY = 34; /** log4j logger */ private static Logger log = Logger.getLogger(UploadWithEmbargoStep.class); /** * 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 appropriate user interface (JSP-UI or XML-UI) * <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 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); // get reference to item Item item = subInfo.getSubmissionItem().getItem(); // ----------------------------------- // Step #0: Upload new files (if any) // ----------------------------------- String contentType = request.getContentType(); // if multipart form, then we are uploading a file if ((contentType != null) && (contentType.indexOf("multipart/form-data") != -1)) { // This is a multipart request, so it's a file upload // (return any status messages or errors reported) int status = processUploadFile(context, request, response, subInfo); // if error occurred, return immediately if (status != STATUS_COMPLETE) { return status; } } // if user pressed jump-to button in process bar, // return success (so that jump will occur) if (buttonPressed.startsWith(PROGRESS_BAR_PREFIX) || buttonPressed.startsWith(PREVIOUS_BUTTON)) { // check if a file is required to be uploaded if (fileRequired && !item.hasUploadedFiles()) { return STATUS_NO_FILES_ERROR; } else { return STATUS_COMPLETE; } } // POLICIES FORM MANAGEMENT int result = editBitstreamPolicies(request, context, subInfo, buttonPressed); if(result != -1) return result; // --------------------------------------------- // Step #1: Check if this was just a request to // edit file information. // (or canceled editing information) // --------------------------------------------- // check if we're already editing a specific bitstream if (request.getParameter("bitstream_id") != null) { if (buttonPressed.equals(CANCEL_EDIT_BUTTON)) { // canceled an edit bitstream request subInfo.setBitstream(null); // this flag will just return us to the normal upload screen return STATUS_EDIT_COMPLETE; } else { // load info for bitstream we are editing Bitstream b = Bitstream.find(context, Integer.parseInt(request .getParameter("bitstream_id"))); // save bitstream to submission info subInfo.setBitstream(b); } } else if (buttonPressed.startsWith("submit_edit_")) { // get ID of bitstream that was requested for editing String bitstreamID = buttonPressed.substring("submit_edit_" .length()); Bitstream b = Bitstream .find(context, Integer.parseInt(bitstreamID)); // save bitstream to submission info subInfo.setBitstream(b); // return appropriate status flag to say we are now editing the // bitstream return STATUS_EDIT_BITSTREAM; } // --------------------------------------------- // Step #2: Process any remove file request(s) // --------------------------------------------- // Remove-selected requests come from Manakin if (buttonPressed.equalsIgnoreCase("submit_remove_selected")) { // this is a remove multiple request! if (request.getParameter("remove") != null) { // get all files to be removed String[] removeIDs = request.getParameterValues("remove"); // remove each file in the list for (int i = 0; i < removeIDs.length; i++) { int id = Integer.parseInt(removeIDs[i]); int status = processRemoveFile(context, item, id); // if error occurred, return immediately if (status != STATUS_COMPLETE) { return status; } } // remove current bitstream from Submission Info subInfo.setBitstream(null); } } else if (buttonPressed.startsWith("submit_remove_")) { // A single file "remove" button must have been pressed int id = Integer.parseInt(buttonPressed.substring(14)); int status = processRemoveFile(context, item, id); // if error occurred, return immediately if (status != STATUS_COMPLETE) { return status; } // remove current bitstream from Submission Info subInfo.setBitstream(null); } // ------------------------------------------------- // Step #3: Check for a change in file description // ------------------------------------------------- String fileDescription = request.getParameter("description"); if (fileDescription != null && fileDescription.length() > 0) { // save this file description int status = processSaveFileDescription(context, request, response, subInfo); // if error occurred, return immediately if (status != STATUS_COMPLETE) { return status; } } // ------------------------------------------ // Step #4: Check for a file format change // (if user had to manually specify format) // ------------------------------------------ int formatTypeID = Util.getIntParameter(request, "format"); String formatDesc = request.getParameter("format_description"); // if a format id or description was found, then save this format! if (formatTypeID >= 0 || (formatDesc != null && formatDesc.length() > 0)) { // save this specified format int status = processSaveFileFormat(context, request, response, subInfo); // if error occurred, return immediately if (status != STATUS_COMPLETE) { return status; } } // execute only if comes from EditBitstreamStep if(buttonPressed.equals("submit_save")){ processAccessFields(context, request, subInfo, subInfo.getBitstream()); } // --------------------------------------------------- // Step #5: Check if primary bitstream has changed // ------------------------------------------------- if (request.getParameter("primary_bitstream_id") != null) { Bundle[] bundles = item.getBundles("ORIGINAL"); if (bundles.length > 0) { bundles[0].setPrimaryBitstreamID(Integer.valueOf(request .getParameter("primary_bitstream_id")).intValue()); bundles[0].update(); } } // --------------------------------------------------- // Step #6: Determine if there is an error because no // files have been uploaded. // --------------------------------------------------- //check if a file is required to be uploaded if (fileRequired && !item.hasUploadedFiles()) { return STATUS_NO_FILES_ERROR; } return STATUS_COMPLETE; } /** * Process the upload of a new file! * * @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 * UI-related code! (if STATUS_COMPLETE or 0 is returned, * no errors occurred!) */ public int processUploadFile(Context context, HttpServletRequest request, HttpServletResponse response, SubmissionInfo subInfo) throws ServletException, IOException, SQLException, AuthorizeException { boolean formatKnown = true; boolean fileOK = false; BitstreamFormat bf = null; Bitstream b = null; //NOTE: File should already be uploaded. //Manakin does this automatically via Cocoon. //For JSP-UI, the SubmissionController.uploadFiles() does the actual upload Enumeration attNames = request.getAttributeNames(); //loop through our request attributes while(attNames.hasMoreElements()) { String attr = (String) attNames.nextElement(); //if this ends with "-path", this attribute //represents a newly uploaded file if(attr.endsWith("-path")) { //strip off the -path to get the actual parameter //that the file was uploaded as String param = attr.replace("-path", ""); // Load the file's path and input stream and description String filePath = (String) request.getAttribute(param + "-path"); InputStream fileInputStream = (InputStream) request.getAttribute(param + "-inputstream"); //attempt to get description from attribute first, then direct from a parameter String fileDescription = (String) request.getAttribute(param + "-description"); if(fileDescription==null ||fileDescription.length()==0) { request.getParameter("description"); } // if information wasn't passed by User Interface, we had a problem // with the upload if (filePath == null || fileInputStream == null) { return STATUS_UPLOAD_ERROR; } if (subInfo == null) { // In any event, if we don't have the submission info, the request // was malformed return STATUS_INTEGRITY_ERROR; } // Create the bitstream Item item = subInfo.getSubmissionItem().getItem(); // do we already have a bundle? Bundle[] bundles = item.getBundles("ORIGINAL"); if (bundles.length < 1) { // set bundle's name to ORIGINAL b = item.createSingleBitstream(fileInputStream, "ORIGINAL"); } else { // we have a bundle already, just add bitstream b = bundles[0].createBitstream(fileInputStream); } // Strip all but the last filename. It would be nice // to know which OS the file came from. String noPath = filePath; while (noPath.indexOf('/') > -1) { noPath = noPath.substring(noPath.indexOf('/') + 1); } while (noPath.indexOf('\\') > -1) { noPath = noPath.substring(noPath.indexOf('\\') + 1); } b.setName(noPath); b.setSource(filePath); b.setDescription(fileDescription); // Identify the format bf = FormatIdentifier.guessFormat(context, b); b.setFormat(bf); // Update to DB b.update(); item.update(); processAccessFields(context, request, subInfo, b); // commit all changes to database context.commit(); if ((bf != null) && (bf.isInternal())) { log.warn("Attempt to upload file format marked as internal system use only"); backoutBitstream(subInfo, b, item); return STATUS_UPLOAD_ERROR; } // Check for virus if (ConfigurationManager.getBooleanProperty("submission-curation", "virus-scan")) { Curator curator = new Curator(); curator.addTask("vscan").curate(item); int status = curator.getStatus("vscan"); if (status == Curator.CURATE_ERROR) { backoutBitstream(subInfo, b, item); return STATUS_VIRUS_CHECKER_UNAVAILABLE; } else if (status == Curator.CURATE_FAIL) { backoutBitstream(subInfo, b, item); return STATUS_CONTAINS_VIRUS; } } // If we got this far then everything is more or less ok. // Comment - not sure if this is the right place for a commit here // but I'm not brave enough to remove it - Robin. context.commit(); // save this bitstream to the submission info, as the // bitstream we're currently working with subInfo.setBitstream(b); //if format was not identified if (bf == null) { return STATUS_UNKNOWN_FORMAT; } }//end if attribute ends with "-path" }//end while return STATUS_COMPLETE; } private void processAccessFields(Context context, HttpServletRequest request, SubmissionInfo subInfo, Bitstream b) throws SQLException, AuthorizeException { // ResourcePolicy Management boolean isAdvancedFormEnabled= ConfigurationManager.getBooleanProperty("webui.submission.restrictstep.enableAdvancedForm", false); // if it is a simple form we should create the policy for Anonymous // if Anonymous does not have right on this collection, create policies for any other groups with // DEFAULT_ITEM_READ specified. if(!isAdvancedFormEnabled){ Date startDate = null; try { startDate = DateUtils.parseDate(request.getParameter("embargo_until_date"), new String[]{"yyyy-MM-dd", "yyyy-MM", "yyyy"}); } catch (Exception e) { //Ignore start date already null } String reason = request.getParameter("reason"); AuthorizeManager.generateAutomaticPolicies(context, startDate, reason, b, (Collection) HandleManager.resolveToObject(context, subInfo.getCollectionHandle())); } } private int editBitstreamPolicies(HttpServletRequest request, Context context, SubmissionInfo subInfo, String buttonPressed) throws SQLException, AuthorizeException { // FORM: EditBitstreamPolicies SELECTED OPERATION: Return if (buttonPressed.equals("bitstream_list_submit_return")){ return STATUS_COMPLETE; } // FORM: UploadStep SELECTED OPERATION: go to EditBitstreamPolicies else if (buttonPressed.startsWith("submit_editPolicy_")){ String bitstreamID = buttonPressed.substring("submit_editPolicy_".length()); Bitstream b = Bitstream.find(context, Integer.parseInt(bitstreamID)); subInfo.setBitstream(b); return STATUS_EDIT_POLICIES; } // FORM: EditBitstreamPolicies SELECTED OPERATION: Add New Policy. else if (buttonPressed.startsWith(AccessStep.FORM_ACCESS_BUTTON_ADD)){ Bitstream b = Bitstream.find(context, Integer.parseInt(request.getParameter("bitstream_id"))); subInfo.setBitstream(b); int result=-1; if( (result = AccessStep.checkForm(request))!=0){ return result; } Date dateStartDate = AccessStep.getEmbargoUntil(request); String reason = request.getParameter("reason"); String name = request.getParameter("name"); int groupID = 0; if(request.getParameter("group_id")!=null){ try{ groupID=Integer.parseInt(request.getParameter("group_id")); }catch (NumberFormatException nfe){ return STATUS_EDIT_POLICIES_ERROR_SELECT_GROUP; } } ResourcePolicy rp = null; if( (rp= AuthorizeManager.createOrModifyPolicy(null, context, name, groupID, null, dateStartDate, org.dspace.core.Constants.READ, reason, b))==null){ return STATUS_EDIT_POLICIES_DUPLICATED_POLICY; } rp.update(); context.commit(); return STATUS_EDIT_POLICIES; } // FORM: EditBitstreamPolicies SELECTED OPERATION: go to EditPolicyForm else if(org.dspace.submit.step.AccessStep.wasEditPolicyPressed(context, buttonPressed, subInfo)){ Bitstream b = Bitstream.find(context, Integer.parseInt(request.getParameter("bitstream_id"))); subInfo.setBitstream(b); return org.dspace.submit.step.AccessStep.STATUS_EDIT_POLICY; } // FORM: EditPolicy SELECTED OPERATION: Save or Cancel. else if(org.dspace.submit.step.AccessStep.comeFromEditPolicy(request)) { Bitstream b = Bitstream.find(context, Integer.parseInt(request.getParameter("bitstream_id"))); subInfo.setBitstream(b); String reason = request.getParameter("reason"); String name = request.getParameter("name"); int groupID = 0; if(request.getParameter("group_id")!=null){ try{ groupID=Integer.parseInt(request.getParameter("group_id")); }catch (NumberFormatException nfe){ return STATUS_EDIT_POLICIES_ERROR_SELECT_GROUP; } } if(org.dspace.submit.step.AccessStep.saveOrCancelEditPolicy(context, request, subInfo, buttonPressed, b, name, groupID, reason)==org.dspace.submit.step.AccessStep.EDIT_POLICY_STATUS_DUPLICATED_POLICY) return STATUS_EDIT_POLICY_DUPLICATED_POLICY; return STATUS_EDIT_POLICIES; } // FORM: EditBitstreamPolicies SELECTED OPERATION: Remove Policies if(org.dspace.submit.step.AccessStep.wasRemovePolicyPressed(buttonPressed)){ Bitstream b = Bitstream.find(context, Integer.parseInt(request.getParameter("bitstream_id"))); subInfo.setBitstream(b); org.dspace.submit.step.AccessStep.removePolicy(context, buttonPressed); context.commit(); return STATUS_EDIT_POLICIES; } return -1; } }