/* * #%L * Alfresco Records Management Module * %% * Copyright (C) 2005 - 2016 Alfresco Software Limited * %% * This file is part of the Alfresco software. * - * If the software was purchased under a paid Alfresco license, the terms of * the paid license agreement will prevail. Otherwise, the software is * provided under the following open source license terms: * - * Alfresco is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * - * Alfresco is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * #L% */ package org.alfresco.module.org_alfresco_module_rm.script; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Serializable; import java.io.Writer; import java.nio.charset.Charset; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.TempFileProvider; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import org.springframework.extensions.surf.util.ParameterCheck; import org.springframework.extensions.webscripts.Cache; import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; /** * Files a transfer report as a record. * * @author Gavin Cornwell */ @Deprecated public class TransferReportPost extends BaseTransferWebScript { /** Logger */ private static Log logger = LogFactory.getLog(TransferReportPost.class); protected static final String REPORT_FILE_PREFIX = "report_"; protected static final String REPORT_FILE_SUFFIX = ".html"; protected static final String PARAM_DESTINATION = "destination"; protected static final String RESPONSE_SUCCESS = "success"; protected static final String RESPONSE_RECORD = "record"; protected static final String RESPONSE_RECORD_NAME = "recordName"; protected DictionaryService ddService; protected RecordsManagementActionService rmActionService; protected DispositionService dispositionService; protected ContentService contentService; /** * Sets the DictionaryService instance * * @param ddService The DictionaryService instance */ public void setDictionaryService(DictionaryService ddService) { this.ddService = ddService; } /** * Sets the disposition service * * @param dispositionService disposition service */ public void setDispositionService(DispositionService dispositionService) { this.dispositionService = dispositionService; } /** * Sets the RecordsManagementActionService instance * * @param rmActionService RecordsManagementActionService instance */ public void setRecordsManagementActionService(RecordsManagementActionService rmActionService) { this.rmActionService = rmActionService; } /** * Sets the ContentSerivce instance * * @param contentService ContentService instance */ public void setContentService(ContentService contentService) { this.contentService = contentService; } @Override protected File executeTransfer(NodeRef transferNode, WebScriptRequest req, WebScriptResponse res, Status status, Cache cache) throws IOException { File report = null; // retrieve requested format String format = req.getFormat(); Map<String, Object> model = new HashMap<String, Object>(); model.put("status", status); model.put("cache", cache); try { // extract the destination parameter, ensure it's present and it is // a record folder JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent())); if (!json.has(PARAM_DESTINATION)) { status.setCode(HttpServletResponse.SC_BAD_REQUEST, "Mandatory '" + PARAM_DESTINATION + "' parameter has not been supplied"); Map<String, Object> templateModel = createTemplateParameters(req, res, model); sendStatus(req, res, status, cache, format, templateModel); return null; } String destinationParam = json.getString(PARAM_DESTINATION); NodeRef destination = new NodeRef(destinationParam); if (!this.nodeService.exists(destination)) { status.setCode(HttpServletResponse.SC_NOT_FOUND, "Node " + destination.toString() + " does not exist"); Map<String, Object> templateModel = createTemplateParameters(req, res, model); sendStatus(req, res, status, cache, format, templateModel); return null; } // ensure the node is a filePlan object if (!RecordsManagementModel.TYPE_RECORD_FOLDER.equals(this.nodeService.getType(destination))) { status.setCode(HttpServletResponse.SC_BAD_REQUEST, "Node " + destination.toString() + " is not a record folder"); Map<String, Object> templateModel = createTemplateParameters(req, res, model); sendStatus(req, res, status, cache, format, templateModel); return null; } if (logger.isDebugEnabled()) { logger.debug("Filing transfer report as record in record folder: " + destination); } // generate the report (will be in JSON format) report = generateHTMLTransferReport(transferNode); // file the report as a record NodeRef record = fileTransferReport(report, destination); if (logger.isDebugEnabled()) { logger.debug("Filed transfer report as new record: " + record); } // return success flag and record noderef as JSON JSONObject responseJSON = new JSONObject(); responseJSON.put(RESPONSE_SUCCESS, (record != null)); if (record != null) { responseJSON.put(RESPONSE_RECORD, record.toString()); responseJSON.put(RESPONSE_RECORD_NAME, (String)nodeService.getProperty(record, ContentModel.PROP_NAME)); } // setup response String jsonString = responseJSON.toString(); res.setContentType(MimetypeMap.MIMETYPE_JSON); res.setContentEncoding("UTF-8"); res.setHeader("Content-Length", Long.toString(jsonString.length())); // write the JSON response res.getWriter().write(jsonString); } catch (JSONException je) { throw createStatusException(je, req, res); } // return the file for deletion return report; } /** * Generates a File containing the JSON representation of a transfer report. * * @param transferNode The transfer node * @return File containing JSON representation of a transfer report * @throws IOException */ File generateHTMLTransferReport(NodeRef transferNode) throws IOException { File report = TempFileProvider.createTempFile(REPORT_FILE_PREFIX, REPORT_FILE_SUFFIX); Writer writer = null; try { // get all 'transferred' nodes NodeRef[] itemsToTransfer = getTransferNodes(transferNode); if (logger.isDebugEnabled()) { logger.debug("Generating HTML transfer report for " + itemsToTransfer.length + " items into file: " + report.getAbsolutePath()); } // create the writer writer = new OutputStreamWriter(new FileOutputStream(report), Charset.forName("UTF-8")); // use RMService to get disposition authority String dispositionAuthority = null; if (itemsToTransfer.length > 0) { // use the first transfer item to get to disposition schedule DispositionSchedule ds = dispositionService.getDispositionSchedule(itemsToTransfer[0]); if (ds != null) { dispositionAuthority = ds.getDispositionAuthority(); } } // write the HTML header writer.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"); writer.write("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n"); Boolean isAccession = (Boolean)this.nodeService.getProperty(transferNode, PROP_TRANSFER_ACCESSION_INDICATOR); if (isAccession) { writer.write("<title>Accession Report</title></head>\n"); } else { writer.write("<title>Transfer Report</title></head>\n"); } writer.write("<style>\n"); writer.write("body { font-family: arial,verdana; font-size: 81%; color: #333; }\n"); writer.write(".records { margin-left: 20px; margin-top: 10px; }\n"); writer.write(".record { padding: 5px; }\n"); writer.write(".label { color: #111; }\n"); writer.write(".nodeName { font-weight: bold; }\n"); writer.write(".transferred-item { background-color: #eee; padding: 10px; margin-bottom: 15px; }\n"); writer.write("</style>\n"); if (isAccession) { writer.write("<body>\n<h1>Accession Report</h1>\n"); } else { writer.write("<body>\n<h1>Transfer Report</h1>\n"); } writer.write("<table cellpadding=\"3\" cellspacing=\"3\">"); writer.write("<tr><td class=\"label\">Transfer Date:</td><td>"); Date transferDate = (Date)this.nodeService.getProperty(transferNode, ContentModel.PROP_CREATED); writer.write(StringEscapeUtils.escapeHtml(transferDate.toString())); writer.write("</td></tr>"); writer.write("<tr><td class=\"label\">Transfer Location:</td><td>"); if (isAccession) { writer.write("NARA"); } else { writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(transferNode, RecordsManagementModel.PROP_TRANSFER_LOCATION))); } writer.write("</td></tr>"); writer.write("<tr><td class=\"label\">Performed By:</td><td>"); writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(transferNode, ContentModel.PROP_CREATOR))); writer.write("</td></tr>"); writer.write("<tr><td class=\"label\">Disposition Authority:</td><td>"); writer.write(dispositionAuthority != null ? StringEscapeUtils.escapeHtml(dispositionAuthority) : ""); writer.write("</td></tr></table>\n"); writer.write("<h2>Transferred Items</h2>\n"); // write out HTML representation of items to transfer generateTransferItemsHTML(writer, itemsToTransfer); // write the HTML footer writer.write("</body></html>"); } finally { if (writer != null) { try { writer.close(); } catch (IOException ioe) {} } } return report; } /** * Generates the JSON to represent the given NodeRefs * * @param writer Writer to write to * @param itemsToTransfer NodeRefs being transferred * @throws IOException */ protected void generateTransferItemsHTML(Writer writer, NodeRef[] itemsToTransfer) throws IOException { for (NodeRef item : itemsToTransfer) { writer.write("<div class=\"transferred-item\">\n"); if (ddService.isSubClass(nodeService.getType(item), ContentModel.TYPE_FOLDER)) { generateTransferFolderHTML(writer, item); } else { generateTransferRecordHTML(writer, item); } writer.write("</div>\n"); } } /** * Generates the JSON to represent the given folder. * * @param writer Writer to write to * @param folderNode Folder being transferred * @throws IOException */ protected void generateTransferFolderHTML(Writer writer, NodeRef folderNode) throws IOException { writer.write("<span class=\"nodeName\">"); writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(folderNode, ContentModel.PROP_NAME))); writer.write("</span> (Unique Folder Identifier: "); writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(folderNode, RecordsManagementModel.PROP_IDENTIFIER))); writer.write(")\n"); writer.write("<div class=\"records\">\n"); // NOTE: we don't expect any nested folder structures so just render // the records contained in the folder. List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(folderNode, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); for (ChildAssociationRef child : assocs) { NodeRef childRef = child.getChildRef(); if (this.nodeService.hasAspect(childRef, RecordsManagementModel.ASPECT_RECORD)) { generateTransferRecordHTML(writer, childRef); } } writer.write("\n</div>\n"); } /** * Generates the JSON to represent the given record. * * @param writer Writer to write to * @param recordNode Record being transferred * @throws IOException */ protected void generateTransferRecordHTML(Writer writer, NodeRef recordNode) throws IOException { writer.write("<div class=\"record\">\n"); writer.write(" <span class=\"nodeName\">"); writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(recordNode, ContentModel.PROP_NAME))); writer.write("</span> (Unique Record Identifier: "); writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(recordNode, RecordsManagementModel.PROP_IDENTIFIER))); writer.write(")"); if (this.nodeService.hasAspect(recordNode, RecordsManagementModel.ASPECT_DECLARED_RECORD)) { Date declaredOn = (Date)this.nodeService.getProperty(recordNode, RecordsManagementModel.PROP_DECLARED_AT); writer.write(" declared by "); writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(recordNode, RecordsManagementModel.PROP_DECLARED_BY))); writer.write(" on "); writer.write(StringEscapeUtils.escapeHtml(declaredOn.toString())); } writer.write("\n</div>\n"); } /** * Files the given transfer report as a record in the given record folder. * * @param report Report to file * @param destination The destination record folder * @return NodeRef of the created record */ protected NodeRef fileTransferReport(File report, NodeRef destination) { ParameterCheck.mandatory("report", report); ParameterCheck.mandatory("destination", destination); NodeRef record = null; Map<QName, Serializable> properties = new HashMap<QName, Serializable>(1); properties.put(ContentModel.PROP_NAME, report.getName()); // file the transfer report as an undeclared record record = this.nodeService.createNode(destination, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(report.getName())), ContentModel.TYPE_CONTENT, properties).getChildRef(); // Set the content ContentWriter writer = contentService.getWriter(record, ContentModel.PROP_CONTENT, true); writer.setMimetype(MimetypeMap.MIMETYPE_HTML); writer.setEncoding("UTF-8"); writer.putContent(report); return record; } }