Java tutorial
/* * Exactly * Author: Nouman Tayyab (nouman@avpreserve.com) * Author: Rimsha Khalid (rimsha@avpreserve.com) * Version: 0.1 * Requires: JDK 1.7 or higher * Description: This tool transfers digital files to the UK Exactly * Support: info@avpreserve.com * License: Apache 2.0 * Copyright: University of Kentucky (http://www.uky.edu). All Rights Reserved * */ package uk.sipperfly.ui; import com.opencsv.CSVWriter; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.SwingWorker; import static uk.sipperfly.ui.Exactly.GACOM; // Bagit imports import gov.loc.repository.bagit.Bag; import gov.loc.repository.bagit.BagFactory; import gov.loc.repository.bagit.BagInfoTxt; import gov.loc.repository.bagit.Manifest; import gov.loc.repository.bagit.PreBag; import gov.loc.repository.bagit.utilities.SimpleResult; import gov.loc.repository.bagit.verify.impl.CompleteVerifierImpl; import gov.loc.repository.bagit.verify.impl.ParallelManifestChecksumVerifier; import gov.loc.repository.bagit.verify.impl.ValidVerifierImpl; import java.awt.Color; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.security.NoSuchAlgorithmException; import java.text.Normalizer; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; import javax.swing.BorderFactory; import javax.swing.border.Border; import uk.sipperfly.persistent.Configurations; import uk.sipperfly.persistent.Recipients; import uk.sipperfly.repository.BagInfoRepo; import uk.sipperfly.repository.ConfigurationsRepo; import uk.sipperfly.repository.RecipientsRepo; import uk.sipperfly.utils.CommonUtil; import uk.sipperfly.utils.ZipUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import uk.sipperfly.persistent.FTP; import uk.sipperfly.repository.FTPRepo; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import uk.sipperfly.persistent.BagInfo; /** * This class implements the background worker thread. * Work happens on this thread so that the MainFraim GUI remains responsive. * * @author Nouman Tayyab */ class BackgroundWorker extends SwingWorker<Integer, Void> { private final List<String> sources; private final Exactly parent; private int numberOfFiles; private final Configurations config; private final FTP ftp; private CommonUtil commonUtil; private ZipUtils zipUtil; private Path target; private String bagSize = ""; private int bagCount = 0; private String inputFolder = ""; private String destFolder = ""; private int process = 0; private int fileCounter = 1; private int ftpProcess = 0; private String unbagDestination = ""; private UIManager uIManager; String content = ""; String payLoad = ""; String bagDate = ""; String bagitSize = ""; String manifest = ""; /** * Constructor for BackgroundWorker * * @param sources * @param parent * @param process * @throws IOException */ public BackgroundWorker(final List<String> sources, Exactly parent, int process) throws IOException { if (sources == null || sources.isEmpty() || parent == null) { throw new IllegalArgumentException(); } ConfigurationsRepo configRepo = new ConfigurationsRepo(); FTPRepo ftpRepo = new FTPRepo(); this.sources = sources; this.parent = parent; this.config = configRepo.getOneOrCreateOne(); this.ftp = ftpRepo.getOneOrCreateOne(); numberOfFiles = 0; this.zipUtil = new ZipUtils(); this.commonUtil = new CommonUtil(); this.inputFolder = this.parent.inputLocationDir.getText(); this.destFolder = this.parent.destDirLocation.getText(); this.process = process; this.uIManager = new UIManager(parent); } /** * The main logic for the work that the background thread does. * This method is automatically called by the threading framework. * <p> * The following actions are performed: * 1. Recognize whether bag is organized in bagit structure or not. * 2. Validate bag. * 3. Validates the user can connect to the email server. * 4. Bags the input folder using the bagit Java library from the Library of Congress * 5. Transfer the folder and all subfolders to the target. * 6. Check ftp connection if file or folder is supposed to upload on ftp server * 7. upload files on ftp server * 8. Sends summary email to the UK Exactly * * @return 1 for success and -1 for failure * @see http://www.digitalpreservation.gov/documents/bagitspec.pdf */ @Override protected Integer doInBackground() { try { String workingPath; if (this.process == 2) { if (!this.inputFolder.isEmpty() || this.inputFolder != null) { if (!this.parent.editCurrentStatus.getText().isEmpty() && this.parent.editCurrentStatus.getText() != null) { this.parent.UpdateResult("Recognizing Bag...", 1); } else { this.parent.UpdateResult("Recognizing Bag...", 1); } Logger.getLogger(GACOM).log(Level.INFO, "Recognizing Bag"); if (this.BagRecognition(this.inputFolder) == 0) { this.parent.UpdateResult("Bag Recognition: Not organized in BagIt structure", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Bag Recognition: Not organized in BagIt structure."); return -1; } } } if (this.process == 3 || this.process == 4) { if (!this.inputFolder.isEmpty() || this.inputFolder != null) { if (this.process == 4) { this.parent.UpdateResult("Validating Bag Before Unbagging...", 1); Logger.getLogger(GACOM).log(Level.INFO, "Validating bag before Unbagging"); } else { this.parent.UpdateResult("Validating Bag...", 1); Logger.getLogger(GACOM).log(Level.INFO, "Validating Bag"); } if (this.ValidateBag(this.inputFolder) == 0) { Border border = BorderFactory.createLineBorder(Color.red, 2); this.parent.inputLocationDir.setBorder(border); this.parent.UpdateResult("Invalid bag.", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Invalid bag."); return -1; } } } if (this.process == 4) { int isExisted = 0; this.parent.unBaggingProgress.setMaximum(3); this.parent.UpdateResult("Copying data...", 0); Logger.getLogger(GACOM).log(Level.INFO, "Copying data..."); File folder = new File(inputFolder); String name = FilenameUtils.removeExtension(folder.getName()); workingPath = destFolder + File.separator + name; File dest = new File(destFolder + File.separator + FilenameUtils.removeExtension(folder.getName())); if (dest.exists()) { this.getFileSuffix(dest.toString()); name = name + "_" + fileCounter; this.fileCounter = 1; workingPath = destFolder + File.separator + name; isExisted = 1; } if (folder.getName().toLowerCase().endsWith(".zip")) { String zipPath = ""; Logger.getLogger(GACOM).log(Level.INFO, "Extracting files from zip folder"); if (isExisted == 1) { this.zipUtil.unZipIt(inputFolder, workingPath); zipPath = workingPath; workingPath = workingPath + File.separator + FilenameUtils.removeExtension(folder.getName()); } else { this.zipUtil.unZipIt(inputFolder, destFolder); } this.parent.unBaggingProgress.setValue(1); if (this.validateAndUnbag(workingPath, name, zipPath) == 0) { return -1; } } else { Logger.getLogger(GACOM).log(Level.INFO, "Copying data to destination"); File targetDir = new File(workingPath); FileUtils.copyDirectory(folder, targetDir); this.parent.unBaggingProgress.setValue(1); if (this.validateAndUnbag(workingPath, name, "") == 0) { return -1; } } this.resetFiles(); } if (this.process == 1) { if (this.validateBagName()) { this.parent.UpdateResult( "Folder already existed in destination with this title. Please change the title.", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Folder already existed in destination with this title. Please change the title."); this.parent.btnTransferFiles.setEnabled(true); return -1; } this.parent.UpdateResult("Verifying Transfer...", 1); if (this.config.getEmailNotifications()) { // validate email auth if (!ValidateCredentials()) { this.parent.UpdateResult("Credentials not valid. Please update Email Settings.", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Credentials not valid. Please update Email settings."); this.parent.btnTransferFiles.setEnabled(true); return -1; } } // check if drop location folder is not set. if (this.parent.editInputDir1.getText() == null || this.parent.editInputDir1.getText().isEmpty()) { this.parent.UpdateResult("Please select Transfer destination.", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Please select Transfer destination."); this.parent.btnTransferFiles.setEnabled(true); return -1; } // validate bag name. if (this.parent.bagNameField.getText() == null || this.parent.bagNameField.getText().isEmpty()) { this.parent.UpdateResult("Please provide Transfer name.", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Please provide Transfer name."); this.parent.btnTransferFiles.setEnabled(true); return -1; } if (this.config.getEmailNotifications()) { RecipientsRepo recipientsRepo = new RecipientsRepo(); List<Recipients> recipients = recipientsRepo.getAll(); if (recipients.size() < 1) { this.parent.UpdateResult("Please add at least one recipient.", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Please add at least one recipient."); this.parent.btnTransferFiles.setEnabled(true); return -1; } } if (this.parent.ftpDelivery.isSelected()) { String result = ValidateFTPCredentials(); if (!(result.equals("FTPES") || result.equals("FTP"))) { this.parent.UpdateResult("Credentials not valid. Please update FTP Settings.", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Credentials not valid. Please update FTP settings."); this.parent.btnTransferFiles.setEnabled(true); return -1; } } if (this.isCancelled()) { Logger.getLogger(GACOM).log(Level.INFO, "Transfer canceled."); this.parent.UpdateResult("Transfer canceled.", 0); return -1; } // Set the tragetPath of bag. this.setTragetPath(); //transfer this.parent.UpdateResult("Transfering files...", 0); Logger.getLogger(GACOM).log(Level.INFO, "Transfering files..."); Path target = TransferFiles(); if (this.isCancelled()) { Logger.getLogger(GACOM).log(Level.INFO, "Canceling Transfer Files task."); Logger.getLogger(GACOM).log(Level.INFO, "Transfer canceled."); this.parent.UpdateResult("Transfer canceled.", 0); return -1; } // bagit this.parent.UpdateResult("Preparing Bag...", 0); Logger.getLogger(GACOM).log(Level.INFO, "Preparing Bag..."); BagFolder(); if (this.isCancelled()) { Logger.getLogger(GACOM).log(Level.INFO, "Canceling Bagit task."); return -1; } this.parent.btnCancel.setVisible(false); if (this.parent.ftpDelivery.isSelected()) { if (this.isCancelled()) { Logger.getLogger(GACOM).log(Level.INFO, "Canceling Upload data to FTP"); return -1; } String result = ValidateFTPCredentials(); if (!(result.equals("FTPES") || result.equals("FTP"))) { this.parent.UpdateResult("Credentials not valid. Please update FTP Settings.", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Credentials not valid. Please update FTP settings."); this.parent.btnTransferFiles.setEnabled(true); return -1; } this.parent.jProgressBar2.setValue(this.parent.totalFiles + 1); if (this.isCancelled()) { Logger.getLogger(GACOM).log(Level.INFO, "Canceling Upload data to FTP"); return -1; } this.parent.UpdateResult("Uploading data on FTP ...", 0); Logger.getLogger(GACOM).log(Level.INFO, "Uploading data on FTP ..."); UploadFilesFTP(); // if (this.parent.serializeBag.isSelected()) { // this.parent.jProgressBar2.setValue(this.parent.totalFiles + 2); // } else { // this.parent.jProgressBar2.setValue(this.parent.totalFiles + 8); // } } if (this.isCancelled()) { Logger.getLogger(GACOM).log(Level.INFO, "Canceling send notification email(s)."); return -1; } // send email to GA if (this.config.getEmailNotifications()) { this.parent.UpdateResult("Preparing to send notification email(s)...", 0); Logger.getLogger(GACOM).log(Level.INFO, "Preparing to send notification email(s)..."); SendMail(target); if (this.isCancelled()) { Logger.getLogger(GACOM).log(Level.INFO, "Canceling send notification email(s)"); return -1; } if (this.parent.ftpDelivery.isSelected()) { this.parent.jProgressBar2.setValue(this.parent.totalFiles + 9); } else { this.parent.jProgressBar2.setValue(this.parent.totalFiles + 1); } } this.parent.jProgressBar2.setValue(this.parent.jProgressBar2.getMaximum()); Thread.sleep(2000); // update UI this.parent.list.resetEntryList(); this.resetTransferFiles(); this.parent.UpdateResult("Session complete.", 0); Logger.getLogger(GACOM).log(Level.INFO, "Session complete."); } return 1; } catch (Exception ex) { this.parent.btnTransferFiles.setEnabled(true); if (this.isCancelled()) { this.parent.UpdateResult("Transfer canceled. Clean up partially copied directories.", 0); Logger.getLogger(GACOM).log(Level.INFO, "Transfer canceled. Clean up partially copied directories."); return -1; } this.parent.UpdateResult("An error occurred. Please contact support.", 0); Logger.getLogger(GACOM).log(Level.INFO, "An error occurred. Please contact support.", ex); return -1; } } /** * Firstly validate bag. If bag is valid then unpack it at specified destination. * * @param workingPath * @param name * @param zipPath * @return 1 if valid bag and Unpack successfully, 0 otherwise */ private int validateAndUnbag(String workingPath, String name, String zipPath) { this.parent.UpdateResult("Validating bag after copying...", 0); Logger.getLogger(GACOM).log(Level.INFO, "Validating bag after copying"); if (this.ValidateBag(workingPath) != 0) { String newPath = ""; this.parent.unBaggingProgress.setValue(2); this.parent.UpdateResult("Unbagging Bagit Bag...", 0); Logger.getLogger(GACOM).log(Level.INFO, "Unbagging Bagit Bag"); if (zipPath != "") { newPath = zipPath; } else { newPath = destFolder + File.separator + "temp_data_folder"; } try { this.commonUtil.unBag(workingPath, newPath, name); } catch (IOException ex) { Logger.getLogger(BackgroundWorker.class.getName()).log(Level.SEVERE, null, ex); } this.parent.unBaggingProgress.setValue(3); try { Thread.sleep(300); } catch (InterruptedException ex) { Logger.getLogger(BackgroundWorker.class.getName()).log(Level.SEVERE, null, ex); } return 1; } else { this.parent.unBaggingProgress.setMaximum(0); this.parent.UpdateResult("Invalid bag after coping to destination.", 0); Logger.getLogger(GACOM).log(Level.SEVERE, "Invalid bag after coping to destination"); return 0; } } /** * add int suffix with file name. * * @param folderPath */ public void getFileSuffix(String folderPath) { File f = new File(folderPath + "_" + fileCounter); if (f.exists()) { fileCounter = fileCounter + 1; getFileSuffix(folderPath); } } /** * Reset the UI of transfer files */ public void resetTransferFiles() { this.parent.bagNameField.setText(""); this.parent.serializeBag.setSelected(false); this.parent.editInputDir.setText(""); this.parent.jProgressBar2.setMaximum(0); this.parent.UpdateProgressBar(0); this.parent.ftpDelivery.setSelected(false); this.parent.btnCancel.setVisible(false); this.parent.btnTransferFiles.setEnabled(true); this.parent.metadateUpdated = 0; // if (this.uIManager.isDefaultTemplate()) { // this.uIManager.resetMetadataValues(true); // } else { // this.uIManager.resetMetadata(true); // } } /** * Reset the UI of Unpack bag. */ public void resetFiles() { this.unbagDestination = this.parent.destDirLocation.getText(); this.parent.inputLocationDir.setText(""); this.parent.destDirLocation.setText(""); this.parent.unBaggingProgress.setMaximum(0); Border border = BorderFactory.createLineBorder(Color.lightGray, 1); this.parent.inputLocationDir.setBorder(border); } /** * Set Target path to place bag after successful transfer. * * @return Path target. * @throws Exception */ protected Path setTragetPath() throws Exception { // get the drop location path from database. Path targetDirPath = new File(this.config.getDropLocation()).toPath(); // create it if it doesn't exist if (!Files.exists(targetDirPath)) { Files.createDirectory(targetDirPath); } // use the bag name that User selected instead of Source directory/file name. String name = this.parent.bagNameField.getText(); File bagName = new File(name); this.target = this.commonUtil.combine(targetDirPath, bagName.toPath()); // create it if it doesn't exist if (!Files.exists(this.target)) { Files.createDirectory(this.target); } return target; } /** * check whether bag title is already existed in destination folder while file transfer. * * @return true if existed else false */ public boolean validateBagName() { Path targetDirPath = new File(this.config.getDropLocation()).toPath(); String name = this.parent.bagNameField.getText(); File bagName = new File(name); this.target = this.commonUtil.combine(targetDirPath, bagName.toPath()); if (Files.exists(this.target)) { return true; } return false; } /** * This is called when the thread has completed it's work or has been canceled. * This method is automatically called by the threading framework. */ @Override protected void done() { try { // Transfer result already updated in worker thread if (this.get() < 0) { return; } } catch (InterruptedException ex) { Logger.getLogger(GACOM).log(Level.SEVERE, "InterruptedException", ex); return; } catch (ExecutionException ex) { Logger.getLogger(GACOM).log(Level.SEVERE, "ExecutionException", ex); return; } if (this.isCancelled()) { this.parent.UpdateResult("Transfer canceled. Clean up partially copied directories.", 0); Logger.getLogger(GACOM).log(Level.WARNING, "Transfer canceled. Clean up partially copied directories."); } else if (this.process == 1 && this.ftpProcess == 0) { this.parent.UpdateResult("Transfer completed successfully.", 0); Logger.getLogger(GACOM).log(Level.INFO, "Transfer completed successfully."); } else if (this.process == 1 && this.ftpProcess == 1) { this.parent.UpdateResult("FTP transfer failed; local transfer completed successfully.", 0); Logger.getLogger(GACOM).log(Level.INFO, "FTP transfer failed; local transfer completed successfully."); } else if (this.process == 2) { this.parent.UpdateResult("Bag Recognition: organized in BagIt structure", 0); Logger.getLogger(GACOM).log(Level.INFO, "Bag Recognition: organized in BagIt structure"); } else if (this.process == 3) { Border border = BorderFactory.createLineBorder(Color.GREEN, 2); this.parent.inputLocationDir.setBorder(border); this.parent.UpdateResult("Valid Bag", 0); Logger.getLogger(GACOM).log(Level.INFO, "Valid Bag"); } else if (this.process == 4) { this.parent.UpdateResult("Successfully unpacked Bagit bag at " + this.unbagDestination, 0); Logger.getLogger(GACOM).log(Level.INFO, "Successfully unpacked Bagit bag at ".concat(this.unbagDestination)); } this.ftpProcess = 0; this.unbagDestination = ""; } /** * Bags the input folder using the bagit Java library from the Library of Congress. * Any errors are reported to the parent UI. * Creates a success semaphore in the source directory if the transfer succeeded. * * @see* http://www.digitalpreservation.gov/documents/bagitspec.pdf */ public void BagFolder() throws NoSuchAlgorithmException, FileNotFoundException, IOException { // String content; Charset charset; // bag the folder BagFactory bagFactory = new BagFactory(); // make the bag PreBag preBag = bagFactory.createPreBag(this.target.toFile()); // keep empty folders? Bag bag = preBag.makeBagInPlace(BagFactory.LATEST, false); BagInfoTxt bagInfoTxt = bag.getBagInfoTxt(); BagInfoRepo bagInfoRepo = new BagInfoRepo(); // String bagInfoText = ""; String bagInfoText = this.commonUtil.createBagInfoTxt(bagInfoRepo.getOneOrCreateOne()); String originalChecksum = this.commonUtil.checkSum(this.target.toString().concat("/bag-info.txt")); try { FileWriter fileWritter = new FileWriter(this.target.toString().concat("/bag-info.txt"), true); BufferedWriter bufferWritter = new BufferedWriter(fileWritter); bufferWritter.write(bagInfoText); bufferWritter.close(); } catch (IOException e) { e.printStackTrace(); Logger.getLogger(GACOM).log(Level.INFO, "Issue while writing file.", e); } this.bagCount = bag.getPayload().size(); String payloadOxum = bagInfoTxt.getPayloadOxum(); List<String> payload = Arrays.asList(payloadOxum.split("\\.")); if (payload.size() > 0) { this.bagSize = payload.get(0); } int zip = 0; if (this.parent.serializeBag.isSelected()) { zip = 1; } if (this.parent.ftpDelivery.isSelected()) { this.commonUtil.CreateSuccessSemaphore(this.config.getUsername(), this.parent.bagNameField.getText(), this.target, this.ftp.getDestination(), this.bagSize, bag.getPayload().size(), zip); } else { this.commonUtil.CreateSuccessSemaphore(this.config.getUsername(), this.parent.bagNameField.getText(), this.target, "", this.bagSize, bag.getPayload().size(), zip); } String newChecksum = this.commonUtil.checkSum(this.target.toString().concat("/bag-info.txt")); try { this.commonUtil.replaceTextInFile(this.target.toString().concat("/tagmanifest-md5.txt"), originalChecksum, newChecksum); } catch (IOException e) { Logger.getLogger(GACOM).log(Level.INFO, "Issue while updating tagmanifest-md5.txt", e); } this.payLoad = bagInfoTxt.getPayloadOxum(); this.bagDate = bagInfoTxt.getBaggingDate(); this.bagitSize = bagInfoTxt.getBagSize(); String payloadManifest = bag.getPayloadManifest(Manifest.Algorithm.MD5).toString(); this.manifest = payloadManifest.substring(1, payloadManifest.length() - 1); this.generateCsvFile(bagInfoTxt.getPayloadOxum(), bagInfoTxt.getBaggingDate(), bagInfoTxt.getBagSize()); this.createXML(bagInfoTxt.getPayloadOxum(), bagInfoTxt.getBaggingDate(), bagInfoTxt.getBagSize()); // this.parent.UpdateProgressBar(this.parent.tranferredFiles); // this.parent.UpdateProgressBar(this.parent.tranferredFiles); try { bag.makeComplete(); bag.close(); // verify the bag // CompleteVerifierImpl completeVerifier = new CompleteVerifierImpl(); // ParallelManifestChecksumVerifier manifestVerifier = new ParallelManifestChecksumVerifier(); // ValidVerifierImpl validVerifier = new ValidVerifierImpl(completeVerifier, manifestVerifier); // SimpleResult result = validVerifier.verify(bagFactory.createBag(bag)); numberOfFiles = bag.getPayload().size(); // get the number of payload files numberOfFiles += 4; // add the standard bagit files // ///if (result.isSuccess()) { Logger.getLogger(GACOM).log(Level.INFO, "Bag created. Number of files is {0}", numberOfFiles); // enable file transfer // this.parent.jProgressBar2.setMaximum(numberOfFiles); // } else { // this.parent.UpdateResult("Bag creation failed. Contact support."); // Logger.getLogger(GACOM).log(Level.SEVERE, "Bag creation failed. Contact support."); // } Path path = Paths.get(this.target + File.separator + "manifest-md5.txt"); charset = StandardCharsets.UTF_8; this.content = new String(Files.readAllBytes(path), charset); if (this.parent.serializeBag.isSelected()) { this.parent.UpdateResult("Serializing bag...", 0); Logger.getLogger(GACOM).log(Level.INFO, "Serializing bag..."); ZipUtils zipUtil = new ZipUtils(); zipUtil.setSourceFolder(this.target.toString()); zipUtil.setOutputZipFile(this.target.toString().concat(".zip")); zipUtil.setBagName(this.parent.bagNameField.getText()); zipUtil.zip(); FileUtils.deleteDirectory(this.target.toFile()); } } catch (IOException ex) { Logger.getLogger(GACOM).log(Level.SEVERE, "Error closing the bag", ex); File newManifest = new File(this.target.toString() + File.separator + "manifest-md5.txt"); Files.write(newManifest.toPath(), this.content.getBytes(StandardCharsets.UTF_8)); } if (this.parent.totalFiles > this.parent.tranferredFiles) { this.parent.UpdateProgressBar(this.parent.totalFiles); } } /** * Initiates the file transfer from the source to the target. * * @return The calculated target path * * @throws Exception If any errors occur */ public Path TransferFiles() throws Exception { FileTransfer ft = new FileTransfer(parent); int extra = 0; // if (this.parent.serializeBag.isSelected()) { // extra = 10; // } int totalFiles = this.parent.totalFiles; Logger.getLogger(GACOM).log(Level.INFO, "Max Progress bar count: ".concat(Integer.toString(this.parent.totalFiles))); if (this.parent.ftpDelivery.isSelected() && this.parent.serializeBag.isSelected()) { totalFiles = totalFiles + 2; } else { int newCount = totalFiles + 8; totalFiles = totalFiles + newCount; } if (this.config.getEmailNotifications()) { totalFiles = totalFiles + 1; } this.parent.jProgressBar2.setMaximum(totalFiles); for (String source : this.sources) { File sourceFile = new File(source); File folder = new File(sourceFile.getName()); Path folderTarget = this.commonUtil.combine(this.target, folder.toPath()); if (!Files.exists(folderTarget)) { Files.createDirectory(folderTarget); } ft.setTargetPath(folderTarget); this.parent.UpdateResult("Transfering files...", 0); Path inputSource = sourceFile.toPath(); ft.setSourcePath(inputSource); ft.Perform(); } return target; } /** * Validates that we can authenticate with the SMTP mail server over TLS. * * @return True if the validation was successful, false otherwise */ public boolean ValidateCredentials() { String password = this.config.getPassword(); String username = this.config.getUsername(); String mailHost = this.config.getServerName(); String port = this.config.getServerPort(); String protocol = this.config.getServerProtocol(); if (username == null) { return false; } MailSender ms = new MailSender(mailHost, username, password, false, port, protocol); return ms.Validate(); } /** * Transfer file to ftp server. * * @throws IOException */ public void UploadFilesFTP() throws IOException { String userName = this.ftp.getUsername(); String host = this.ftp.getHostName(); String destination = this.ftp.getDestination(); String password = this.ftp.getPassword(); String securityType = this.ftp.getSecurityType(); int port = this.ftp.getPort(); String mode = this.ftp.getMode(); String location = this.target.toString(); FTPConnection ftpCon = new FTPConnection(this.parent, host, userName, password, port, mode, destination, securityType); if (this.parent.serializeBag.isSelected()) { location = location.concat(".zip"); if (ftpCon.uploadFiles(location, "zip")) { this.parent.UpdateResult("File uploaded successfully.", 0); } else { this.ftpProcess = 1; this.parent.UpdateResult("An error occured while uploading on FTP. Cannot upload file.", 0); } } else { if (ftpCon.uploadFiles(location, "")) { this.parent.UpdateResult("File uploaded successfully.", 0); } else { this.ftpProcess = 1; this.parent.UpdateResult("An error occured while uploading on FTP. Cannot upload folder.", 0); } } } /** * Validate ftp Credentials * * @return * @throws IOException */ public String ValidateFTPCredentials() throws IOException { String userName = this.ftp.getUsername(); String host = this.ftp.getHostName(); String destination = this.ftp.getDestination(); String password = this.ftp.getPassword(); int port = this.ftp.getPort(); String mode = this.ftp.getMode(); String securityType = this.ftp.getSecurityType(); if (userName == null) { return "false"; } FTPConnection ftpCon = new FTPConnection(this.parent, host, userName, password, port, mode, destination, securityType); return ftpCon.validateCon(); } /** * Sends summary email to the UK Exactly. * The text of that email is defined here. * * @param target The destination of the file copy */ public void SendMail(Path target) { if (target == null) { throw new IllegalArgumentException(); } String host = this.config.getServerName(); String username = this.config.getUsername(); String password = this.config.getPassword(); String port = this.config.getServerPort(); String protocol = this.config.getServerProtocol(); MailSender ms = new MailSender(host, username, password, false, port, protocol); // Send email to current user. this.PrepareAndSendMail(ms, username); RecipientsRepo recipientsRepo = new RecipientsRepo(); List<Recipients> recipients = recipientsRepo.getAll(); if (!recipients.isEmpty()) { for (Recipients recipient : recipients) { this.PrepareAndSendMail(ms, recipient.getEmail()); } } } /** * Prepare text of the email and sent to recipient. * * @param ms MailSender * @param toEmail string */ public void PrepareAndSendMail(MailSender ms, String toEmail) { PrintWriter writer = null; try { String from = this.config.getUsername(); String transferName = this.parent.bagNameField.getText(); String targetS = this.target.toString(); if (this.parent.serializeBag.isSelected()) { transferName = transferName + ".zip"; targetS = targetS + ".zip"; } String msg = ""; String message = ""; BagInfoRepo bagInfoRepo = new BagInfoRepo(); List<BagInfo> bagInfo = bagInfoRepo.getOneOrCreateOne(); for (BagInfo b : bagInfo) { message = message + b.getLabel() + ": " + b.getValue() + "\n"; } if (this.ftpProcess == 1) { msg = "FTP transfer failed."; } // from, to, subject, body if (this.parent.ftpDelivery.isSelected()) { String ftpLocation = this.ftp.getDestination(); if (!ftpLocation.startsWith("/")) { ftpLocation = "/" + ftpLocation; } if (ftpLocation.endsWith("/")) { ftpLocation = ftpLocation + transferName; } else { ftpLocation = ftpLocation + "/" + transferName; } String whole_message = "Transfer completed: " + new Date() + "\nTransfer Name: " + transferName + "\nTarget: " + targetS + "\nFTP Target: " + ftpLocation + "\nApplication Used: Exactly" + "\nUser: " + this.parent.userNameField.getText() + "\nTotal File count: " + this.bagCount + "\nTotal Bytes: " + this.bagSize + "\nPayload Oxum: " + this.payLoad + "\nBagging Date: " + this.bagDate + "\nBag Size: " + this.bagitSize + "\n" + message + "\n" + msg; ms.SetMessage(from, toEmail, "Exactly Digital Transfer", whole_message); } else { String whole_message = "Transfer completed: " + new Date() + "\nTransfer Name: " + transferName + "\nTarget: " + targetS + "\nApplication Used: Exactly" + "\nUser: " + this.parent.userNameField.getText() + "\nTotal File count: " + this.bagCount + "\nTotal Bytes: " + this.bagSize + "\nPayload Oxum: " + this.payLoad + "\nBagging Date: " + this.bagDate + "\nBag Size: " + this.bagitSize + "\n" + message; ms.SetMessage(from, toEmail, "Exactly Digital Transfer", whole_message); } String name = this.target.getFileName().toString(); Date dNow = new Date(); SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd"); String myFile = name + "-" + ft.format(dNow) + "-manifest-md5.txt"; String myCopy = this.target.getParent().toString() + File.separator + myFile; File file = new File(this.target.getParent().toString() + File.separator + myFile); writer = new PrintWriter(myCopy, "UTF-8"); List<String> filterList = Arrays.asList(this.manifest.split(", ")); if (filterList.size() > 0) { for (String filter : filterList) { String[] data = filter.split("="); writer.println(data[1] + " " + data[0]); } } writer.close(); String result; ms.AttachFile(this.target.getParent().toString() + File.separator + myFile); result = ms.Send(); this.parent.UpdateResult(result, 0); file.delete(); Logger.getLogger(GACOM).log(Level.INFO, "Mail send result: {0}", result); } catch (FileNotFoundException ex) { Logger.getLogger(BackgroundWorker.class.getName()).log(Level.SEVERE, null, ex); } catch (UnsupportedEncodingException ex) { Logger.getLogger(BackgroundWorker.class.getName()).log(Level.SEVERE, null, ex); } } /** * validate input bag * * @param path * @return */ public int ValidateBag(String path) { BagFactory bagfactory = new BagFactory(); File file = new File(path); Bag cbag = bagfactory.createBag(file);//(Bag) file; CompleteVerifierImpl completeVerifier = new CompleteVerifierImpl(); ParallelManifestChecksumVerifier manifestVerifier = new ParallelManifestChecksumVerifier(); ValidVerifierImpl validVerifier = new ValidVerifierImpl(completeVerifier, manifestVerifier); SimpleResult result = validVerifier.verify(cbag); if (result.isSuccess()) { return 1; } else { this.parent.UpdateResult(result.getMessages().toString(), 0); return 0; } } /** * Recognize bag structure. * * @param path * @return */ public int BagRecognition(String path) { BagFactory bagfactory = new BagFactory(); boolean result = true; File file = new File(path); Bag cbag = bagfactory.createBag(file);//(Bag) file; List<String> errorMessages = cbag.verifyComplete().getMessages(); int index = errorMessages.size(); if (index != 0) { int _index = index - 1; if (errorMessages.get(_index).contains("Bag does not have any payload manifests.") || errorMessages.get(_index).contains("Bag does not have bagit.txt.")) { result = false; } } if (result) { return 1; } else { this.parent.UpdateResult(errorMessages.toString(), 0); return 0; } } /** * create bag-info.xml file at transfer destination */ public void createXML(String payload, String date, String size) { try { char[] charArray = { '<', '>', '&', '"', '\\', '!', '#', '$', '%', '\'', '(', ')', '*', '.', ':', '+', ',', '/', ';', '=', '?', '@', '[', ']', '^', '`', '{', '|', '}', '~' }; // List<char[]> asList = Arrays.asList(charArray); DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); Element rootElement = doc.createElement("transfer_metadata"); doc.appendChild(rootElement); Attr attr1 = doc.createAttribute("xmlns:xsi"); attr1.setValue("http://www.w3.org/2001/XMLSchema-instance"); rootElement.setAttributeNode(attr1); Element payLoad = doc.createElement("Payload-Oxum"); payLoad.appendChild(doc.createTextNode(payload)); rootElement.appendChild(payLoad); Element baggingDate = doc.createElement("Bagging-Date"); baggingDate.appendChild(doc.createTextNode(date)); rootElement.appendChild(baggingDate); Element bagsize = doc.createElement("Bag-Size"); bagsize.appendChild(doc.createTextNode(size)); rootElement.appendChild(bagsize); BagInfoRepo bagInfoRepo = new BagInfoRepo(); List<BagInfo> bagInfo = bagInfoRepo.getOneOrCreateOne(); for (BagInfo b : bagInfo) { StringBuilder stringBuilder = new StringBuilder(); char[] txt = Normalizer.normalize(b.getLabel(), Normalizer.Form.NFD).toCharArray(); for (int i = 0; i < b.getLabel().length(); i++) { int check = 0; for (int j = 0; j < charArray.length; j++) { if (txt[i] == charArray[j]) { check = 1; } } if (check == 0) { stringBuilder.append(txt[i]); } } Element firstname = doc.createElement(stringBuilder.toString().replace(" ", "-")); firstname.appendChild(doc.createTextNode(b.getValue().trim())); rootElement.appendChild(firstname); } // write the content into xml file TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult( new File(this.target.toString() + File.separator + "bag-info.xml")); transformer.transform(source, result); } catch (ParserConfigurationException ex) { Logger.getLogger(BackgroundWorker.class.getName()).log(Level.SEVERE, null, ex); } catch (TransformerConfigurationException ex) { Logger.getLogger(BackgroundWorker.class.getName()).log(Level.SEVERE, null, ex); } catch (TransformerException ex) { Logger.getLogger(BackgroundWorker.class.getName()).log(Level.SEVERE, null, ex); } catch (DOMException ex) { Logger.getLogger(BackgroundWorker.class.getName()).log(Level.SEVERE, null, ex); } } private void generateCsvFile(String payload, String date, String size) { BagInfoRepo bagInfoRepo = new BagInfoRepo(); List<String> labels = new ArrayList<String>(); List<String> values = new ArrayList<String>(); labels.add("Payload Oxum"); labels.add("Bagging Date"); labels.add("Bag Size"); values.add(payload); values.add(date); values.add(size); List<BagInfo> bagInfo = bagInfoRepo.getOneOrCreateOne(); try { CSVWriter writer = new CSVWriter( new FileWriter(this.target.toString() + File.separator + "bag-info.csv")); for (BagInfo b : bagInfo) { labels.add(b.getLabel().toString()); values.add(b.getValue().toString()); } labels.toArray(); String[] newLabels = new String[labels.size()]; newLabels = labels.toArray(newLabels); String[] newValues = new String[values.size()]; newValues = values.toArray(newValues); writer.writeNext(newLabels); writer.writeNext(newValues); writer.flush(); writer.close(); } catch (IOException e) { Logger.getLogger(BackgroundWorker.class.getName()).log(Level.SEVERE, null, e); } } }