/** * CopyTasks.java * Author: Francesco Rosso (rosso@eurix.it) * * This file is part of PrestoPRIME Preservation Platform (P4). * * Copyright (C) 2012 EURIX Srl, Torino, Italy * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.prestoprime.plugin.p4; import it.eurix.archtools.data.DataException; import it.eurix.archtools.data.model.DIP; import it.eurix.archtools.data.model.IPException; import it.eurix.archtools.data.model.SIP; import it.eurix.archtools.tool.ToolException; import it.eurix.archtools.tool.ToolOutput; import it.eurix.archtools.tool.impl.MessageDigestExtractor; import it.eurix.archtools.workflow.exceptions.TaskExecutionFailedException; import it.eurix.archtools.workflow.plugin.WfPlugin; import it.eurix.archtools.workflow.plugin.WfPlugin.WfService; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.nio.channels.FileChannel; import java.util.List; import java.util.Map; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.prestoprime.conf.ConfigurationManager; import eu.prestoprime.conf.P4PropertyManager.P4Property; import eu.prestoprime.datamanagement.P4DataManager; @WfPlugin(name = "P4Plugin") public class CopyTasks { private static final Logger logger = LoggerFactory.getLogger(CopyTasks.class); @WfService(name = "configure_storage", version = "1.0.0") public void configureStorage(Map<String, String> sParams, Map<String, String> dParamsString, Map<String, File> dParamsFile) throws TaskExecutionFailedException { String sipID = dParamsString.get("sipID"); if (sipID == null) sipID = dParamsString.get("aipID"); String p4storeFolder = ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_STORAGE_VOLUME) + File.separator + ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_STORAGE_FOLDER) + File.separator + sipID; dParamsString.put("p4storeFolder", p4storeFolder); String videosFolder = p4storeFolder + File.separator + ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_VIDEOS_FOLDER); new File(videosFolder).mkdirs(); dParamsString.put("videosFolder", videosFolder); String framesFolder = p4storeFolder + File.separator + ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_FRAMES_FOLDER); new File(framesFolder).mkdirs(); dParamsString.put("framesFolder", framesFolder); String graphFolder = p4storeFolder + File.separator + ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_GRAPH_FOLDER); new File(graphFolder).mkdirs(); dParamsString.put("graphFolder", graphFolder); } @WfService(name = "master_file_first_copy", version = "2.0.0") public void masterFileFirstCopy(Map<String, String> sParams, Map<String, String> dParamsString, Map<String, File> dParamsFile) throws TaskExecutionFailedException { // get sipID String sipID = dParamsString.get("sipID"); SIP sip = null; try { // get sip sip = P4DataManager.getInstance().getSIPByID(sipID); String inputVideo = null; // get MQ file String[] formats = sParams.get("MQformats").split(","); for (String format : formats) { List<String> videoFileList = sip.getAVMaterial(format, "FILE"); if (videoFileList.size() > 0) { inputVideo = videoFileList.get(0); String outputVideoName = inputVideo.substring(inputVideo.lastIndexOf(File.separator) + 1); String outputVideo = dParamsString.get("videosFolder") + File.separator + outputVideoName; File inputFile = new File(inputVideo); File outputFile = new File(outputVideo); if (!outputFile.exists()) { outputFile.createNewFile(); } FileChannel source = new FileInputStream(inputFile).getChannel(); FileChannel destination = new FileOutputStream(outputFile).getChannel(); destination.transferFrom(source, 0, source.size()); // MD5 MessageDigestExtractor mde = new MessageDigestExtractor(); ToolOutput<MessageDigestExtractor.AttributeType> output = mde.extract(outputVideo); String md5sum = output.getAttribute(MessageDigestExtractor.AttributeType.MD5); // update SIP sip.addFile(format, "FILE", outputVideo, md5sum, new File(outputVideo).length()); break; } } if (inputVideo == null) { throw new TaskExecutionFailedException("Unable to find supported MQ format..."); } } catch (DataException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to retrieve the SIP..."); } catch (IPException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to retrieve MQ file from SIP..."); } catch (IOException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to copy MQ file..."); } catch (ToolException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to compute MD5 for WebM video file..."); } finally { P4DataManager.getInstance().releaseIP(sip); } } @WfService(name = "master_file_second_copy", version = "2.0.0") public void masterFileSecondCopy(Map<String, String> sParams, Map<String, String> dParamsString, Map<String, File> dParamsFile) throws TaskExecutionFailedException { // get sipID String sipID = dParamsString.get("sipID"); SIP sip = null; try { // get sip sip = P4DataManager.getInstance().getSIPByID(sipID); String inputVideo = null; // get MQ file String[] formats = sParams.get("MQformats").split(","); for (String format : formats) { List<String> videoFileList = sip.getAVMaterial(format, "FILE"); if (videoFileList.size() > 0) { inputVideo = videoFileList.get(0); String outputFolder = sParams.get("second.local.copy.folder") + File.separator + sipID; new File(outputFolder).mkdirs(); String outputVideoName = inputVideo.substring(inputVideo.lastIndexOf(File.separator) + 1); String outputVideo = outputFolder + File.separator + outputVideoName; File inputFile = new File(inputVideo); File outputFile = new File(outputVideo); if (!outputFile.exists()) { outputFile.createNewFile(); } FileChannel source = new FileInputStream(inputFile).getChannel(); FileChannel destination = new FileOutputStream(outputFile).getChannel(); destination.transferFrom(source, 0, source.size()); // MD5 MessageDigestExtractor mde = new MessageDigestExtractor(); ToolOutput<MessageDigestExtractor.AttributeType> output = mde.extract(outputVideo); String md5sum = output.getAttribute(MessageDigestExtractor.AttributeType.MD5); // update SIP sip.addFile(format, "FILE-BCK", outputVideo, md5sum, new File(outputVideo).length()); break; } } if (inputVideo == null) { throw new TaskExecutionFailedException("Unable to find supported MQ format..."); } } catch (DataException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to retrieve the SIP..."); } catch (IPException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to retrieve MQ file from SIP..."); } catch (IOException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to copy MQ file..."); } catch (ToolException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to compute MD5 for WebM video file..."); } finally { P4DataManager.getInstance().releaseIP(sip); } } @WfService(name = "find_local_master_file", version = "2.2.0") public void findLocalMasterFile(Map<String, String> sParams, Map<String, String> dParamsString, Map<String, File> dParamsFile) throws TaskExecutionFailedException { String sourceFilePath = dParamsString.get("source.file.path"); if (sourceFilePath == null) { // not set yet, find local master quality FILE String dipID = dParamsString.get("dipID"); DIP dip = null; try { dip = P4DataManager.getInstance().getDIPByID(dipID); String[] MQFormats = sParams.get("MQformats").split(","); for (String MQFormat : MQFormats) { List<String> AVMaterialList = dip.getAVMaterial(MQFormat, "FILE"); if (AVMaterialList.size() > 0) { String AVMaterial = AVMaterialList.get(0); AVMaterial = AVMaterial.replace(ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_PLACEHOLDER), ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_STORAGE_VOLUME)); logger.debug("Found local MQ file: " + AVMaterial + "..."); dParamsString.put("source.file.path", AVMaterial); dParamsString.put("source.file.type", "FILE"); dParamsString.put("source.file.mimetype", MQFormat); break; } } } catch (DataException e) { e.printStackTrace(); } catch (IPException e) { e.printStackTrace(); } } } @WfService(name = "make_consumer_copy", version = "2.0.0") public void makeConsumerCopy(Map<String, String> sParams, Map<String, String> dParamsString, Map<String, File> dParamFile) throws TaskExecutionFailedException { if (!Boolean.parseBoolean(dParamsString.get("isCopied"))) { // retrieve static params String destVolume = sParams.get("dest.path.volume").trim(); String destFolder = sParams.get("dest.path.folder").trim(); // retrieve dynamic params String dipID = dParamsString.get("id"); String mimetype = dParamsString.get("mimetype"); String outputFolder = destVolume + File.separator + destFolder; try { DIP dip = P4DataManager.getInstance().getDIPByID(dipID); // get MQ file String videoFile = null; if (mimetype != null) { List<String> videoFileList = dip.getAVMaterial(mimetype, "FILE"); if (videoFileList.size() > 0) { videoFile = videoFileList.get(0); File sourceFile = new File(videoFile); if (!sourceFile.canRead() || !sourceFile.isFile()) throw new TaskExecutionFailedException("Unable to read source video file..."); File targetDir = new File(outputFolder); targetDir.mkdirs(); if (!targetDir.canWrite()) throw new TaskExecutionFailedException("Unable to write to output dir " + outputFolder); String targetFileName = dipID + videoFile.substring(videoFile.lastIndexOf(".")); File targetFile = new File(outputFolder, targetFileName); FileInputStream in = new FileInputStream(sourceFile); FileOutputStream out = new FileOutputStream(targetFile); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) out.write(buffer, 0, bytesRead); in.close(); out.close(); dParamsString.put("isCopied", "true"); dParamsString.put("target.file.name", targetFileName); logger.debug("Consumer copy available at: " + targetFile.getAbsolutePath()); } } } catch (DataException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to retrieve DIP with id: " + dipID); } catch (IPException | FileNotFoundException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to retrieve MQ file"); } catch (IOException e) { e.printStackTrace(); throw new TaskExecutionFailedException("Unable to create consumer copy"); } } } @WfService(name = "check_consumer_copy", version = "2.0.5") public void checkConsumerCopy(Map<String, String> sParams, Map<String, String> dParamsString, Map<String, File> dParamsFile) throws TaskExecutionFailedException { if (Boolean.parseBoolean(dParamsString.get("isCopied"))) { String dipID = dParamsString.get("id"); String mimeType = dParamsString.get("mimetype"); String p4url = ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_URL); String targetFileName = dParamsString.get("target.file.name"); String destVolume = sParams.get("dest.path.volume").trim(); String destFolder = sParams.get("dest.path.folder").trim(); String outputFolder = destVolume + File.separator + destFolder; try { DIP dip = P4DataManager.getInstance().getDIPByID(dipID); JSONObject json = new JSONObject(); json.put("file", targetFileName); json.put("CIFS", "//" + new URL(p4url).getHost() + "/" + destFolder); json.put("URL", p4url + "/" + destFolder + "/" + targetFileName); String MD5 = dip.getChecksum(mimeType, "MD5"); if (MD5 != null) { File targetFile = new File(outputFolder, targetFileName); MessageDigestExtractor mde = new MessageDigestExtractor(); ToolOutput<MessageDigestExtractor.AttributeType> output = mde.extract(targetFile.getAbsolutePath()); String currentMD5 = output.getAttribute(MessageDigestExtractor.AttributeType.MD5); if (!currentMD5.equals(MD5)) throw new TaskExecutionFailedException("MD5 doesn't correspond..."); else json.put("MD5", MD5); } dParamsString.put("result", json.toString()); } catch (JSONException e) { dParamsString.put("result", "Unable to print output file information..."); } catch (DataException | IPException e) { throw new TaskExecutionFailedException("Unable to retrieve the DIP..."); } catch (MalformedURLException e) { throw new TaskExecutionFailedException("Malformed URL..."); } catch (ToolException e) { throw new TaskExecutionFailedException("Unable to extract the checksum..."); } } else { throw new TaskExecutionFailedException("Unable to find any file with requested mimetype..."); } } }