de.uzk.hki.da.sb.SIPFactory.java Source code

Java tutorial

Introduction

Here is the source code for de.uzk.hki.da.sb.SIPFactory.java

Source

/*
  DA-NRW Software Suite | SIP-Builder
  Copyright (C) 2014 Historisch-Kulturwissenschaftliche Informationsverarbeitung
  Universitt zu Kln
    
  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 de.uzk.hki.da.sb;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;

import javax.swing.JOptionPane;

import org.apache.commons.io.FileExistsException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.input.SAXBuilder;

import de.uzk.hki.da.metadata.ContractRights;
import de.uzk.hki.da.metadata.FileExtensions;
import de.uzk.hki.da.metadata.LidoLicense;
import de.uzk.hki.da.metadata.LidoParser;
import de.uzk.hki.da.metadata.MetsLicense;
import de.uzk.hki.da.metadata.MetsParser;
import de.uzk.hki.da.metadata.PremisXmlWriter;
import de.uzk.hki.da.pkg.CopyUtility;
import de.uzk.hki.da.pkg.NestedContentStructure;
import de.uzk.hki.da.pkg.SipArchiveBuilder;
import de.uzk.hki.da.utils.C;
import de.uzk.hki.da.utils.FolderUtils;
import de.uzk.hki.da.utils.FormatDetectionService;
import de.uzk.hki.da.utils.Utilities;
import de.uzk.hki.da.utils.XMLUtils;
import gov.loc.repository.bagit.Bag;
import gov.loc.repository.bagit.BagFactory;
import gov.loc.repository.bagit.PreBag;
import gov.loc.repository.bagit.utilities.SimpleResult;
import de.uzk.hki.da.metadata.NullLastComparator;

/**
 * The central SIP production class
 * 
 * @author Trebunski Eugen
 * @author Thomas Kleinke
 */

public class SIPFactory {

    private static Logger logger = Logger.getLogger(SIPFactory.class);

    private String sourcePath = null;
    private String destinationPath = null;
    private String workingPath = null;
    private KindOfSIPBuilding kindofSIPBuilding = null;
    private String name = null;
    private boolean createCollection;
    private String collectionName = null;
    private File collectionFolder = null;
    private ContractRights contractRights = new ContractRights();
    // DANRW-1515
    private FileExtensions fileExtensions = new FileExtensions();
    private HashMap<String, List<String>> fileExtensionsList = new HashMap<String, List<String>>();

    private File rightsSourcePremisFile = null;
    private SipBuildingProcess sipBuildingProcess;

    private boolean alwaysOverwrite;
    private boolean skippedFiles;
    private boolean ignoreZeroByteFiles = false;
    private boolean compress;

    // DANRW-1416: Extension for disable tar - function
    private boolean tar = true;
    private String destDir = null;

    // DANRW-1352: to disable bagit creation
    private boolean bagit = true;

    // DANRW-1515: Extension for allowDuplicateFilename
    private boolean allowDuplicateFilename = false;
    private boolean checkFileExtensionOff = false;

    private List<String> forbiddenFileExtensions = null;

    private File listCreationTempFolder = null;

    private MessageWriter messageWriter;
    private ProgressManager progressManager;

    private Feedback returnCode;

    public enum KindOfSIPBuilding {
        MULTIPLE_FOLDERS, SINGLE_FOLDER, NESTED_FOLDERS
    };

    /**
     * Creates and starts a new SIP building process
     */
    public void startSIPBuilding() {
        sipBuildingProcess = new SipBuildingProcess();
        sipBuildingProcess.start();
    }

    /**
     * Creates a list of source folders
     * 
     * @param folderPath
     *            The main source folder path
     * @throws Exception
     */

    HashMap<File, String> createFolderList(String folderPath) throws Exception {

        HashMap<File, String> folderListWithFolderNames = new HashMap<File, String>();
        File sourceFolder = new File(folderPath);

        switch (kindofSIPBuilding) {
        case MULTIPLE_FOLDERS:
            List<File> folderContent = Arrays.asList(sourceFolder.listFiles());
            for (File file : folderContent) {
                if (!file.isHidden() && file.isDirectory())
                    folderListWithFolderNames.put(file, null);
            }
            break;

        case SINGLE_FOLDER:
            folderListWithFolderNames.put(sourceFolder, null);
            break;

        case NESTED_FOLDERS:
            NestedContentStructure ncs;
            try {
                TreeMap<File, String> metadataFileWithType = new FormatDetectionService(sourceFolder)
                        .getMetadataFileWithType();
                if (!metadataFileWithType.isEmpty() && (!metadataFileWithType.get(metadataFileWithType.firstKey())
                        .equals(C.CB_PACKAGETYPE_METS))) {
                    messageWriter.showMessage("Es wurde eine Metadatendatei des Typs "
                            + metadataFileWithType.get(metadataFileWithType.firstKey())
                            + " auf der obersten Ebene gefunden. "
                            + "\nBitte whlen Sie diese Option ausschlielich fr die Erstellung von SIPs des Typs METS.");
                } else {
                    ncs = new NestedContentStructure(sourceFolder);
                    folderListWithFolderNames = ncs.getSipCandidates();
                    if (folderListWithFolderNames.isEmpty()) {
                        messageWriter.showMessage(
                                "Es wurde kein Unterverzeichnis mit einer METS-Metadatendatei gefunden.");
                    }
                    break;
                }
            } catch (IOException e) {
                throw new Exception(e);
            }
        default:
            break;
        }

        return folderListWithFolderNames;
    }

    /**
     * Starts the progress manager and creates a progress manager job for each
     * SIP to build
     * 
     * @param folderList
     *            The source folder list
     * @return The method result as a Feedback enum
     */
    private Feedback initializeProgressManager(List<File> folderList) {

        progressManager.reset();

        if (createCollection)
            progressManager.addJob(-1, collectionName, 0);

        int i = 0;
        for (File folder : folderList) {
            if (!folder.exists()) {
                logger.error("Folder " + folder.getAbsolutePath() + " does not exist anymore.");
                return Feedback.COPY_ERROR;
            }

            progressManager.addJob(i, folder.getName(), FileUtils.sizeOfDirectory(folder));
            i++;
        }

        progressManager.calculateProgressParts(createCollection);
        progressManager.createStartMessage();

        return Feedback.SUCCESS;
    }

    private String getTempFolderPath() {
        if (workingPath == null || workingPath.length() == 0) {
            return destinationPath + File.separator + getTempFolderName();
        } else
            return workingPath + File.separator + getTempFolderName();
    }

    /**
     * Creates a SIP out of the given source folder
     * 
     * @param jobId
     *            The job ID
     * @param sourceFolder
     *            The source folder
     * @return The method result as a Feedback enum
     */
    private Feedback buildSIP(int jobId, File sourceFolder, String newPackageName) {

        progressManager.startJob(jobId);
        Feedback feedback;

        String packageName = "";
        if (newPackageName != null) {
            packageName = newPackageName;
        } else {
            packageName = getPackageName(sourceFolder);
        }
        File tempFolder = new File(getTempFolderPath());
        File packageFolder = new File(tempFolder, packageName);

        if ((feedback = copyFolder(jobId, sourceFolder, packageFolder)) != Feedback.SUCCESS) {
            rollback(tempFolder);
            return feedback;
        }

        if ((feedback = checkMetadataForLicense(jobId, sourceFolder, packageFolder)) != Feedback.SUCCESS) {
            rollback(tempFolder);
            return feedback;
        }

        if ((feedback = createPremisFile(jobId, packageFolder, packageName)) != Feedback.SUCCESS) {
            rollback(tempFolder);
            return feedback;
        }

        // DANRW-1352
        if (bagit) {
            if ((feedback = createBag(jobId, packageFolder)) != Feedback.SUCCESS) {
                rollback(tempFolder);
                return feedback;
            }
        }

        return packageFolder(jobId, sourceFolder, packageFolder, tempFolder, packageName);
    }

    public Feedback packageFolder(int jobId, File sourceFolder, File packageFolder, File tempFolder,
            String packageName) {// DANRW-1416
        Feedback feedback;
        if (tar) {
            String archiveFileName = packageName;
            if (compress)
                archiveFileName += ".tgz";
            else
                archiveFileName += ".tar";

            File archiveFile = new File(destinationPath + File.separator + archiveFileName);

            if (!checkForExistingSip(archiveFile)) {
                progressManager.skipJob(jobId);
                skippedFiles = true;
                return Feedback.SUCCESS;
            }
            File tmpArchiveFile = null;
            tmpArchiveFile = new File(workingPath + File.separator + archiveFileName);

            if (tmpArchiveFile.exists())
                tmpArchiveFile.delete();

            if (Utilities.checkForZeroByteFiles(sourceFolder, packageName, messageWriter)) {
                if (!ignoreZeroByteFiles) {
                    String message = "WARNING: Found zero byte files in folder " + sourceFolder + ":\n";
                    for (String s : messageWriter.getZeroByteFiles()) {
                        message += s;
                        message += "\n";
                    }
                    logger.info(message);
                    return Feedback.ZERO_BYTES_ERROR;
                }
            }

            if ((feedback = buildArchive(jobId, packageFolder, tmpArchiveFile)) != Feedback.SUCCESS) {
                rollback(tempFolder, tmpArchiveFile);
                return feedback;
            }

            if (!getWorkingPath().equals(getDestinationPath())) {
                if ((feedback = moveFile(tmpArchiveFile, archiveFile)) != Feedback.SUCCESS) {
                    rollback(tmpArchiveFile);
                    rollback(archiveFile);
                    return feedback;
                }
            }

            if ((feedback = deleteTempFolder(jobId, tempFolder)) != Feedback.SUCCESS)
                return feedback;

            if (createCollection) {
                if ((feedback = moveSipToCollectionFolder(jobId, archiveFile)) != Feedback.SUCCESS)
                    return feedback;
            }
        } else {
            logger.debug("TempFolder : " + tempFolder + "   --  destinationPath  :  " + getDestinationPath());
            if ((feedback = copyFolder(jobId, tempFolder, new File(getDestinationPath()))) != Feedback.SUCCESS)
                return feedback;

            if ((feedback = deleteTempFolder(jobId, tempFolder)) != Feedback.SUCCESS)
                return feedback;
        }
        return feedback;

    }

    private Feedback moveFile(File tmpArchiveFile, File archiveFile) {
        try {
            try {
                FileUtils.moveFile(tmpArchiveFile, archiveFile);
            } catch (FileExistsException e) {
                archiveFile.delete();
                FileUtils.moveFile(tmpArchiveFile, archiveFile);
            }
        } catch (IOException e) {
            logger.error("Failed to copy " + tmpArchiveFile + " to " + archiveFile);
            return Feedback.ARCHIVE_ERROR;
        }
        return Feedback.SUCCESS;
    }

    /**
     * Copies the contents of the given source folder to a newly created temp
     * folder
     * 
     * @param jobId
     *            The job ID
     * @param sourceFolder
     *            The source folder
     * @param tempFolder
     *            The temp folder
     * @return The method result as a Feedback enum
     */
    private Feedback copyFolder(int jobId, File sourceFolder, File tempFolder) {

        progressManager.copyProgress(jobId, 0);
        File dataFolder = new File(tempFolder, "data");
        dataFolder.mkdirs();

        CopyUtility copyUtility = new CopyUtility();
        copyUtility.setProgressManager(progressManager);
        copyUtility.setJobId(jobId);
        copyUtility.setSipBuildingProcess(sipBuildingProcess);

        try {
            if (!copyUtility.copyDirectory(sourceFolder, dataFolder, forbiddenFileExtensions))
                return Feedback.ABORT;
        } catch (Exception e) {
            logger.error("Failed to copy folder " + sourceFolder.getAbsolutePath() + " to "
                    + tempFolder.getAbsolutePath(), e);
            return Feedback.COPY_ERROR;
        }

        return Feedback.SUCCESS;
    }

    private Feedback checkMetadataForLicense(int jobId, File sourceFolder, File packageFolder) {
        boolean premisLicenseBool = contractRights.getCclincense() != null;
        boolean metsLicenseBool = false;
        boolean lidoLicenseBool = false;
        boolean publicationBool = contractRights.getPublicRights().getAllowPublication();

        TreeMap<File, String> metadataFileWithType;
        try {
            metadataFileWithType = new FormatDetectionService(sourceFolder).getMetadataFileWithType();

            if (metadataFileWithType.containsValue(C.CB_PACKAGETYPE_METS)) {
                ArrayList<File> metsFiles = new ArrayList<File>();

                ArrayList<MetsLicense> licenseMetsFile = new ArrayList<MetsLicense>();
                for (File f : metadataFileWithType.keySet())
                    if (metadataFileWithType.get(f).equals(C.CB_PACKAGETYPE_METS))
                        metsFiles.add(f);
                for (File f : metsFiles) {// assuming more as usual mets is allowed (check is done by FormatDetectionService) e.g. publicMets for testcase-creation
                    SAXBuilder builder = XMLUtils.createNonvalidatingSaxBuilder();
                    Document metsDoc = builder.build(f);
                    MetsParser mp = new MetsParser(metsDoc);
                    licenseMetsFile.add(mp.getLicenseForWholeMets());
                }
                Collections.sort(licenseMetsFile, new NullLastComparator<MetsLicense>());
                if (licenseMetsFile.get(0) == null) // all licenses are null
                    metsLicenseBool = false;
                else if (!licenseMetsFile.get(0).equals(licenseMetsFile.get(licenseMetsFile.size() - 1))) // first and last lic have to be same in sorted array
                    return Feedback.INVALID_LICENSE_DATA_IN_METADATA;
                else
                    metsLicenseBool = true;
            } else if (metadataFileWithType.containsValue(C.CB_PACKAGETYPE_LIDO)) {
                ArrayList<File> lidoFiles = new ArrayList<File>();

                ArrayList<LidoLicense> licenseLidoFile = new ArrayList<LidoLicense>();
                for (File f : metadataFileWithType.keySet())
                    if (metadataFileWithType.get(f).equals(C.CB_PACKAGETYPE_LIDO))
                        lidoFiles.add(f);
                for (File f : lidoFiles) {// assuming more as one metadata is allowed (check is done by FormatDetectionService) 
                    SAXBuilder builder = XMLUtils.createNonvalidatingSaxBuilder();
                    Document metsDoc = builder.build(f);
                    LidoParser lp = new LidoParser(metsDoc);
                    licenseLidoFile.add(lp.getLicenseForWholeLido());
                }
                Collections.sort(licenseLidoFile, new NullLastComparator<LidoLicense>());
                if (licenseLidoFile.get(0) == null) // all licenses are null
                    lidoLicenseBool = false;
                else if (!licenseLidoFile.get(0).equals(licenseLidoFile.get(licenseLidoFile.size() - 1))) // first and last lic have to be same in sorted array
                    return Feedback.INVALID_LICENSE_DATA_IN_METADATA;
                else
                    lidoLicenseBool = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Feedback.INVALID_LICENSE_DATA_IN_METADATA;
        }
        //activate to be able to create non licensed test sips
        //publicationBool=false;
        //premisLicenseBool=false;
        //publicationBool=false;
        if (premisLicenseBool && (metsLicenseBool || lidoLicenseBool)) {
            return Feedback.DUPLICATE_LICENSE_DATA;
        }

        if (publicationBool && !premisLicenseBool && !metsLicenseBool && !lidoLicenseBool) {
            return Feedback.PUBLICATION_NO_LICENSE;
        }

        logger.info(
                "License is satisfiable: Premis-License:" + premisLicenseBool + " Mets-License:" + metsLicenseBool
                        + " Lido-License:" + lidoLicenseBool + " Publication-Decision:" + publicationBool);

        return Feedback.SUCCESS;
    }

    /**
     * Creates the premis.xml file
     * 
     * @param jobId
     *            The job ID
     * @param folder
     *            The temp folder
     * @param packageName
     *            The package name
     * @return The method result as a Feedback enum
     */
    private Feedback createPremisFile(int jobId, File folder, String packageName) {

        progressManager.premisProgress(jobId, 0.0);
        File premisFile = null;
        // DANRW-1416
        if (tar) {
            premisFile = new File(folder, "data" + File.separator + "premis.xml");
        } else {
            premisFile = new File(folder, "data" + File.separator + "premis.xml");
        }
        // ENDE DANRW-1416

        PremisXmlWriter premisWriter = new PremisXmlWriter();
        try {
            if (rightsSourcePremisFile != null)
                premisWriter.createPremisFile(this, premisFile, rightsSourcePremisFile, packageName);
            else
                premisWriter.createPremisFile(this, premisFile, packageName);
        } catch (Exception e) {
            logger.error("Failed to create premis file " + premisFile.getAbsolutePath(), e);
            return Feedback.PREMIS_ERROR;
        }

        progressManager.premisProgress(jobId, 100.0);

        if (sipBuildingProcess.isAborted())
            return Feedback.ABORT;

        return Feedback.SUCCESS;
    }

    /**
     * Creates BagIt checksums and metadata for the files in the given folder
     * 
     * @param jobId
     *            The job ID
     * @param folder
     *            The temp folder
     * @return The method result as a Feedback enum
     */
    public Feedback createBag(int jobId, File folder) {

        progressManager.bagitProgress(jobId, 0.0);

        BagFactory bagFactory = new BagFactory();
        PreBag preBag = bagFactory.createPreBag(folder);
        preBag.makeBagInPlace(BagFactory.LATEST, false);
        progressManager.bagitProgress(jobId, 10.0);

        if (sipBuildingProcess.isAborted())
            return Feedback.ABORT;

        Bag bag = bagFactory.createBag(folder);
        progressManager.bagitProgress(jobId, 40.0);

        if (sipBuildingProcess.isAborted())
            return Feedback.ABORT;

        SimpleResult result = bag.verifyValid();
        if (result.isSuccess()) {
            progressManager.bagitProgress(jobId, 50.0);
            return Feedback.SUCCESS;
        } else {
            logger.error(
                    "Bag in folder " + folder.getAbsolutePath() + " is not valid.\n" + result.getErrorMessages());
            return Feedback.BAGIT_ERROR;
        }
    }

    /**
     * Creates a tar oder tgz archive file out of the given folder. The value of
     * the field 'compress' determines if a tar or tgz file is created.
     * 
     * @param jobId
     *            The job ID
     * @param folder
     *            The folder to archive
     * @param archiveFile
     *            The target archive file
     * @return The method result as a Feedback enum
     */
    public Feedback buildArchive(int jobId, File folder, File archiveFile) {

        progressManager.setJobFolderSize(jobId, FileUtils.sizeOfDirectory(folder));
        progressManager.archiveProgress(jobId, 0);

        SipArchiveBuilder archiveBuilder = null;
        try {
            archiveBuilder = new SipArchiveBuilder();
            archiveBuilder.setProgressManager(progressManager);
            archiveBuilder.setJobId(jobId);
            archiveBuilder.setSipBuildingProcess(sipBuildingProcess);
        } catch (Exception e) {
            logger.error("Failed to instantiate the ArchiveBuilder ", e);
            return Feedback.ABORT;
        }

        try {
            if (!archiveBuilder.archiveFolder(folder, archiveFile, true, compress))
                return Feedback.ABORT;
        } catch (Exception e) {
            logger.error("Failed to archive folder " + folder.getAbsolutePath() + " to archive "
                    + archiveFile.getAbsolutePath(), e);
            return Feedback.ARCHIVE_ERROR;
        }

        return Feedback.SUCCESS;
    }

    /**
     * Deletes the temp folder and its contents
     * 
     * @param jobId
     *            The job ID
     * @param folder
     *            The temp folder to delete
     * @return The method result as a Feedback enum
     */
    private Feedback deleteTempFolder(int jobId, File folder) {

        progressManager.deleteTempProgress(jobId, 0.0);

        try {
            FolderUtils.deleteDirectorySafe(folder);
        } catch (IOException e) {
            logger.warn("Failed to delete temp folder " + folder.getAbsolutePath(), e);
            return Feedback.DELETE_TEMP_FOLDER_WARNING;
        }

        progressManager.deleteTempProgress(jobId, 100.0);

        return Feedback.SUCCESS;
    }

    /**
     * Moves the given archived SIP file to the collection folder
     * 
     * @param jobId
     *            The job ID
     * @param archiveFile
     *            The SIP file
     * @return The method result as a Feedback enum
     */
    private Feedback moveSipToCollectionFolder(int jobId, File archiveFile) {

        try {
            FileUtils.moveFileToDirectory(archiveFile, new File(collectionFolder, "data"), false);
        } catch (IOException e) {
            logger.error("Failed to move file " + archiveFile.getAbsolutePath() + " to folder "
                    + collectionFolder.getAbsolutePath(), e);
            return Feedback.MOVE_TO_COLLECTION_FOLDER_ERROR;
        }

        return Feedback.SUCCESS;
    }

    /**
     * Checks if the given SIP file already exists at the destination path. If
     * an existing SIP is found, the user may decide to overwrite it or abort
     * the process.
     * 
     * @param archiveFileName
     *            The name of the folder to check
     * @return true if no existing SIP for the given folderName is found or the
     *         user decides to overwrite the existing SIP
     * @return false if a SIP for the given folderName already exists and the
     *         user decides to abort the SIP creation process
     */
    private boolean checkForExistingSip(File sip) {

        if (alwaysOverwrite)
            return true;

        if (sip.exists()) {
            MessageWriter.UserInput userInput = messageWriter
                    .showOverwriteDialog("Im Ordner \"" + destinationPath + "\" existiert bereits ein SIP mit\n"
                            + "dem Namen \"" + FilenameUtils.getBaseName(sip.getAbsolutePath()) + "\".\n\n"
                            + "Mchten Sie das bestehende SIP berschreiben?");
            switch (userInput) {
            case YES:
                return true;
            case NO:
                return false;
            case ALWAYS_OVERWRITE:
                alwaysOverwrite = true;
                return true;
            }
        }

        return true;
    }

    private String getPackageName(File folder) {

        String packageName;

        if (name != null && !name.equals(""))
            packageName = name;
        else
            packageName = folder.getName();

        return packageName;
    }

    private String getTempFolderName() {

        String baseName = "temp";

        if (!new File(destinationPath + File.separator + baseName).exists())
            return baseName;

        String tempFolderName;
        int i = 0;
        do {
            tempFolderName = baseName + "_" + i++;
        } while (new File(destinationPath + File.separator + tempFolderName).exists());

        return tempFolderName;
    }

    private void rollback(File folder) {

        rollback(folder, null);
    }

    private void rollback(File folder, File archiveFile) {

        FolderUtils.deleteQuietlySafe(folder);

        if (archiveFile != null)
            FolderUtils.deleteQuietlySafe(archiveFile);
    }

    /**
     * This method is called by the SIP building process. It deletes partially
     * created collections and aborts the progress manager.
     */
    private void abortSipBuilding() {

        if (listCreationTempFolder != null && listCreationTempFolder.exists())
            FolderUtils.deleteQuietlySafe(listCreationTempFolder);

        FolderUtils.deleteQuietlySafe(collectionFolder);
        progressManager.abort();
    }

    /**
     * Aborts the SIP building process
     */
    public void abort() {
        sipBuildingProcess.abort();
    }

    /**
     * @return true if the SIP building process is working, otherwise false
     */
    public boolean isWorking() {

        if (sipBuildingProcess == null || !sipBuildingProcess.isAlive())
            return false;
        else
            return true;
    }

    public String getSourcePath() {
        return sourcePath;
    }

    public void setSourcePath(String sourcePath) {
        this.sourcePath = sourcePath;
    }

    public String getDestinationPath() {
        return destinationPath;
    }

    public void setDestinationPath(String destinationPath) {
        this.destinationPath = destinationPath;
    }

    public KindOfSIPBuilding getKindofSIPBuilding() {
        return kindofSIPBuilding;
    }

    public void setKindofSIPBuilding(KindOfSIPBuilding kindofSIPBuilding) {
        this.kindofSIPBuilding = kindofSIPBuilding;
    }

    public void setKindofSIPBuilding(String kindofSIPBuildingName) {
        this.kindofSIPBuilding = Utilities.translateKindOfSIPBuilding(kindofSIPBuildingName);
    }

    public ContractRights getContractRights() {
        return contractRights;
    }

    public void setContractRights(ContractRights contractRights) {
        this.contractRights = contractRights;
    }

    public void setProgressManager(ProgressManager progressManager) {
        this.progressManager = progressManager;
    }

    public void setMessageWriter(MessageWriter messageWriter) {
        this.messageWriter = messageWriter;
    }

    public boolean getCreateCollection() {
        return createCollection;
    }

    public void setCreateCollection(boolean createCollection) {
        this.createCollection = createCollection;
    }

    public String getCollectionName() {
        return collectionName;
    }

    public void setCollectionName(String collectionName) {
        this.collectionName = collectionName;
    }

    public File getRightsSourcePremisFile() {
        return rightsSourcePremisFile;
    }

    public void setRightsSourcePremisFile(File rightsSourcePremisFile) {
        this.rightsSourcePremisFile = rightsSourcePremisFile;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getForbiddenFileExtensions() {
        return forbiddenFileExtensions;
    }

    public void setForbiddenFileExtensions(List<String> forbiddenFileExtensions) {
        this.forbiddenFileExtensions = forbiddenFileExtensions;
    }

    public File getListCreationTempFolder() {
        return listCreationTempFolder;
    }

    public void setListCreationTempFolder(File listCreationTempFolder) {
        this.listCreationTempFolder = listCreationTempFolder;
    }

    public void setIgnoreZeroByteFiles(boolean ignoreZeroByteFiles) {
        this.ignoreZeroByteFiles = ignoreZeroByteFiles;
    }

    public void setLogger(Logger logger) {
        this.logger = logger;
    }

    public Feedback getReturnCode() {
        return returnCode;
    }

    public ProgressManager getProgressManager() {
        return progressManager;
    }

    public boolean getCompress() {
        return compress;
    }

    public void setCompress(boolean compress) {
        this.compress = compress;
    }

    public String getWorkingPath() {
        return workingPath;
    }

    public void setWorkingPath(String workingPath) {
        this.workingPath = workingPath;
    }

    public boolean isTar() {
        return tar;
    }

    public void setTar(boolean tar) {
        this.tar = tar;
    }

    public String getDestDir() {
        return destDir;
    }

    public void setDestDir(String destDir) {
        this.destDir = destDir;
    }

    // DANRW-1515
    public boolean isAllowDuplicateFilename() {
        return allowDuplicateFilename;
    }

    public void setAllowDuplicateFilename(boolean allowDuplicateFilename) {
        this.allowDuplicateFilename = allowDuplicateFilename;
    }

    public boolean isCheckFileExtensionOff() {
        return checkFileExtensionOff;
    }

    public void setCheckFileExtensionOff(boolean checkFileExtensionOff) {
        this.checkFileExtensionOff = checkFileExtensionOff;
    }

    public FileExtensions getFileExtensions() {
        return fileExtensions;
    }

    public void setFileExtensions(FileExtensions fileExtensions) {
        this.fileExtensions = fileExtensions;
    }

    public HashMap<String, List<String>> getFileExtensionsList() {
        return fileExtensionsList;
    }

    public void setFileExtensionsList(HashMap<String, List<String>> hashMap) {
        this.fileExtensionsList = hashMap;
    }

    // End of DANRW-1515

    public boolean isBagit() {
        return bagit;
    }

    public void setBagit(boolean bagit) {
        this.bagit = bagit;
    }

    /**
     * The SIP building procedure is run in its own thread to prevent GUI
     * freezing
     * 
     * @author Thomas Kleinke
     */
    public class SipBuildingProcess extends Thread {

        private boolean abortRequested = false;

        /**
         * Creates one ore more SIPs as specified by the user
         */
        public void run() {

            alwaysOverwrite = false;
            skippedFiles = false;
            messageWriter.resetZeroByteFiles();
            progressManager.reset();

            if (createCollection) {
                collectionFolder = new File(new File(destinationPath), collectionName);

                if (collectionFolder.exists()) {
                    MessageWriter.UserInput answer = messageWriter.showCollectionOverwriteDialog(
                            "Eine Lieferung mit dem Namen \"" + collectionName + "\"" + "existiert bereits.\n"
                                    + "Mchten Sie die bestehende Lieferung berschreiben?");

                    switch (answer) {
                    case YES:
                        FolderUtils.deleteQuietlySafe(collectionFolder);
                        break;
                    case NO:
                        progressManager.abort();
                        return;
                    default:
                        break;
                    }
                }

                new File(collectionFolder, "data").mkdirs();
            }

            HashMap<File, String> folderListWithNames = null;
            try {
                folderListWithNames = createFolderList(sourcePath);
                @SuppressWarnings("unchecked")
                HashMap<File, String> tmpFolderListWithNames = (HashMap<File, String>) folderListWithNames.clone();
                for (File f : folderListWithNames.keySet()) {
                    String metadataType = "";
                    try {
                        TreeMap<File, String> metadataFileWithType = new FormatDetectionService(f)
                                .getMetadataFileWithType();
                        if (!metadataFileWithType.isEmpty()) {
                            File file = metadataFileWithType.firstKey();
                            metadataType = metadataFileWithType.get(file);
                            if (!duplicateFileNames(f, tmpFolderListWithNames)) {
                                Utilities.validateFileReferencesInMetadata(file, metadataType);
                            }
                        } else {
                            duplicateFileNames(f, tmpFolderListWithNames);
                        }
                    } catch (Error e) {
                        if (metadataType.equals(C.CB_PACKAGETYPE_EAD)) {
                            String msg = "Aus dem Verzeichnis " + f + " wird kein SIP erstellt. \n"
                                    + e.getMessage();
                            messageWriter.showLongErrorMessage(msg);
                            tmpFolderListWithNames.remove(f);
                            returnCode = Feedback.WRONG_REFERENCES_IN_METADATA;
                        } else {
                            String msg = e.getMessage() + " \nMchten Sie die SIP-Erstellung dennoch fortsetzen?";
                            logger.error(msg);
                            MessageWriter.UserInput answer = messageWriter.showWrongReferencesInMetadataDialog(msg);
                            returnCode = Feedback.WRONG_REFERENCES_IN_METADATA;
                            switch (answer) {
                            case YES:
                                break;
                            case NO:
                                messageWriter.showMessage("Aus dem Verzeichnis " + f + " wird kein SIP erstellt.");
                                tmpFolderListWithNames.remove(f);
                                break;
                            default:
                                break;
                            }
                        }
                    }
                }
                folderListWithNames = tmpFolderListWithNames;
                if (folderListWithNames.isEmpty()) {
                    abortSipBuilding();
                    return;
                }
            } catch (Exception e) {
                messageWriter.showLongErrorMessage("Das SIP konnte nicht erstellt werden.\n\n"
                        + "Ihre Daten sind mglicherweise nicht valide. \n\n" + e.getMessage());
                returnCode = Feedback.INVALID_METADATA;
                abortSipBuilding();
                return;
            }
            List<File> folderList = new ArrayList<File>();
            for (File f : folderListWithNames.keySet()) {
                folderList.add(f);
            }
            if (initializeProgressManager(folderList) != Feedback.SUCCESS) {
                messageWriter.showMessage("Das SIP konnte nicht erstellt werden.\n\n"
                        + "Der angegebene Ordner existiert nicht mehr. ", JOptionPane.ERROR_MESSAGE);
                abortSipBuilding();
                return;
            }

            int id = 0;
            for (File folder : folderListWithNames.keySet()) {
                returnCode = buildSIP(id, folder, folderListWithNames.get(folder));

                if (returnCode != Feedback.SUCCESS && returnCode != Feedback.DELETE_TEMP_FOLDER_WARNING)
                    abortSipBuilding();

                switch (returnCode) {
                case COPY_ERROR:
                    messageWriter.showMessage(
                            "Das SIP \"" + folder.getName() + "\" konnte nicht erstellt werden.\n\n"
                                    + "Whrend des Kopiervorgangs ist ein Fehler aufgetreten.",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                case ZERO_BYTES_ERROR:
                    messageWriter.showZeroByteFileMessage();
                    return;
                case PREMIS_ERROR:
                    messageWriter.showMessage(
                            "Das SIP \"" + folder.getName() + "\" konnte nicht erstellt werden.\n\n"
                                    + "Whrend der Erstellung der Premis-Datei ist ein Fehler aufgetreten.",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                case BAGIT_ERROR:
                    messageWriter.showMessage(
                            "Das SIP \"" + folder.getName() + "\" konnte nicht erstellt werden.\n\n"
                                    + "Whrend der Erzeugung des Bags ist ein Fehler aufgetreten.",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                case ARCHIVE_ERROR:
                    messageWriter.showMessage(
                            "Das SIP \"" + folder.getName() + "\" konnte nicht erstellt werden.\n\n"
                                    + "Whrend der tgz-Archivierung ist ein Fehler aufgetreten.",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                case DELETE_TEMP_FOLDER_WARNING:
                    messageWriter
                            .showMessage(
                                    "Whrend der Bereinigung temporrer Daten ist ein Fehler aufgetreten.\n\n"
                                            + "Bitte lschen Sie nicht bentigte verbleibende Verzeichnisse\n"
                                            + "im Ordner \"" + destinationPath + "\" manuell.",
                                    JOptionPane.ERROR_MESSAGE);
                    break;
                case MOVE_TO_COLLECTION_FOLDER_ERROR:
                    messageWriter.showMessage(
                            "Das SIP \"" + folder.getName() + "\" konnte der Lieferung nicht hinzugefgt werden.",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                case INVALID_LICENSE_DATA_IN_METADATA:
                    messageWriter.showMessage("Das SIP \"" + folder.getName()
                            + "\" konnte der Lieferung nicht hinzugefgt werden.\n"
                            + "Die Lizenzangaben in den Metadaten sind ungltig: Lizenzen nicht eindeutig interpretierbar.",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                case DUPLICATE_LICENSE_DATA:
                    messageWriter.showMessage("Das SIP \"" + folder.getName()
                            + "\" konnte der Lieferung nicht hinzugefgt werden.\n"
                            + "Die Lizenzangaben sind nicht eindeutig: Lizenangaben drfen nicht gleichzeitig im SIP-Builder und in den Metadaten angegeben werden.",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                case PUBLICATION_NO_LICENSE:
                    messageWriter.showMessage("Das SIP \"" + folder.getName()
                            + "\" konnte der Lieferung nicht hinzugefgt werden.\n"
                            + "Die Lizenzangaben sind nicht vorhanden: Um publizieren zu knnen, muss eine gltige Lizenz angegeben werden.",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                case ABORT:
                    return;
                default:
                    break;
                }

                id++;
            }

            if (listCreationTempFolder != null && listCreationTempFolder.exists())
                FolderUtils.deleteQuietlySafe(listCreationTempFolder);

            if (createCollection) {
                progressManager.startJob(-1);
                if (createBag(-1, collectionFolder) == Feedback.BAGIT_ERROR)
                    messageWriter.showMessage(
                            "Die Lieferung \"" + collectionName + "\" konnte nicht erstellt werden.\n\n"
                                    + "Whrend der Erzeugung des Bags ist ein Fehler aufgetreten.",
                            JOptionPane.ERROR_MESSAGE);
            }

            progressManager.createSuccessMessage(skippedFiles);

            if (ignoreZeroByteFiles && messageWriter.getZeroByteFiles().size() > 0) {
                String message = "WARNING: Found zero byte files:";
                for (String s : messageWriter.getZeroByteFiles()) {
                    message += "\n";
                    message += s;
                }
                logger.info(message);
                messageWriter.showZeroByteFileMessage();
            }
        }

        public void abort() {
            abortRequested = true;
        }

        public boolean isAborted() {
            return abortRequested;
        }

        /**
         * duplicateFileNames:
         * @param f
         * @param tmpFolderListWithNames
         * @return
         */
        private boolean duplicateFileNames(File f, HashMap<File, String> tmpFolderListWithNames) {
            HashMap<String, List<File>> duplicateFileNames = getFilesWithDuplicateFileNames(f);
            if (!duplicateFileNames.isEmpty()) {
                if (!allowDuplicateFilename) {
                    String msg = "Aus dem Verzeichnis " + f
                            + " wird kein SIP erstellt. \nDer Ordner enthlt gleichnamige Dateien: \n"
                            + duplicateFileNames;
                    messageWriter.showLongErrorMessage(msg);
                    tmpFolderListWithNames.remove(f);
                    returnCode = Feedback.DUPLICATE_FILENAMES;
                    return true;
                } else {
                    // DANRW-1515: erlauben von doppelten Dateiname fr unterschiedliche Formate (z.B. xml und Image)
                    Iterator<String> it = duplicateFileNames.keySet().iterator();
                    while (it.hasNext()) {
                        List<String> oldKeysExtension = new ArrayList<String>();
                        String key = (it.next());
                        List<File> listDupFileNames = duplicateFileNames.get(key);
                        for (int i = 0; listDupFileNames.size() > i; i++) {
                            String extOfFile = FilenameUtils
                                    .getExtension(listDupFileNames.get(i).getAbsolutePath());
                            if (!checkFileExtensionOff) {
                                Iterator<String> itExtensions = getFileExtensionsList().keySet().iterator();
                                while (itExtensions.hasNext()) {
                                    String keyExtensions = (itExtensions.next());
                                    if (getFileExtensionsList().get(keyExtensions).contains(extOfFile)) {
                                        if (oldKeysExtension.contains(keyExtensions)) {
                                            String msg = "Aus dem Verzeichnis " + f
                                                    + " wird kein SIP erstellt. \nDer Ordner enthlt gleichnamige Dateien: \n"
                                                    + duplicateFileNames.get(key);
                                            messageWriter.showLongErrorMessage(msg);
                                            tmpFolderListWithNames.remove(f);
                                            returnCode = Feedback.DUPLICATE_FILENAMES;
                                            return true;
                                        } else {
                                            oldKeysExtension.add(keyExtensions);
                                            break;
                                        }
                                    }
                                }
                                //                     } else {
                                //                        String msg = "Aus dem Verzeichnis "
                                //                              + f
                                //                              + " wird kein SIP erstellt. \nDer Ordner enthlt gleichnamige Dateien: \n"
                                //                              +  duplicateFileNames.get(key);
                                //                        messageWriter.showLongErrorMessage(msg);
                                //                        tmpFolderListWithNames.remove(f);
                                //                        returnCode = Feedback.DUPLICATE_FILENAMES;
                                //                        return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        private HashMap<String, List<File>> getFilesWithDuplicateFileNames(File folder) {
            logger.debug("Search for duplicate file names in folder " + folder);

            HashMap<String, List<File>> duplicateFilenamesWithFiles = new HashMap<String, List<File>>();
            HashMap<String, File> filenamesWithFiles = new HashMap<String, File>();

            for (File f : folder.listFiles()) {
                logger.debug("getFilesWithDuplicateFileNames: Check file " + f);
                if (f.isDirectory()) {
                    HashMap<String, List<File>> rekursivResult = getFilesWithDuplicateFileNames(f);
                    for (String rekf : rekursivResult.keySet())
                        if (duplicateFilenamesWithFiles.containsKey(rekf))
                            duplicateFilenamesWithFiles.get(rekf).addAll(rekursivResult.get(rekf));
                        else
                            duplicateFilenamesWithFiles.put(rekf, rekursivResult.get(rekf));

                } else {

                    File file = new File(f.getAbsolutePath());
                    String ext = FilenameUtils.getExtension(file.getAbsolutePath());
                    String relFilePathWithoutExtension = new File(f.getAbsolutePath()).getAbsolutePath().toString()
                            .replace(new File(f.getParent()).getAbsolutePath() + File.separator, "")
                            .replace(ext, "");
                    logger.debug("relFilePathWithoutExtension: " + relFilePathWithoutExtension);

                    if (filenamesWithFiles.get(relFilePathWithoutExtension) == null) {
                        logger.debug("New file name " + relFilePathWithoutExtension);
                        filenamesWithFiles.put(relFilePathWithoutExtension, f);
                    } else {
                        if (duplicateFilenamesWithFiles.get(relFilePathWithoutExtension) != null) {
                            logger.debug("One more file with file name " + relFilePathWithoutExtension
                                    + "\nFirst file is "
                                    + duplicateFilenamesWithFiles.get(relFilePathWithoutExtension));
                            duplicateFilenamesWithFiles.get(relFilePathWithoutExtension).add(f);
                        } else {
                            List<File> duplicateFilenames = new ArrayList<File>();
                            logger.debug("Second file with the same file name. " + "\n First file is "
                                    + filenamesWithFiles.get(relFilePathWithoutExtension));
                            duplicateFilenames.add(filenamesWithFiles.get(relFilePathWithoutExtension));
                            duplicateFilenames.add(f);
                            duplicateFilenamesWithFiles.put(relFilePathWithoutExtension, duplicateFilenames);
                        }
                    }
                }
            }
            return duplicateFilenamesWithFiles;
        }
    }

    public void setSipBuildingProcess(SipBuildingProcess sipBuildingProcess2) {
        this.sipBuildingProcess = sipBuildingProcess2;
    };

}