Package eu.planets_project.services.utils

Source Code of eu.planets_project.services.utils.DigitalObjectUtils

/*******************************************************************************
* Copyright (c) 2007, 2010 The Planets Project Partners.
*
* All rights reserved. This program and the accompanying
* materials are made available under the terms of the
* Apache License, Version 2.0 which accompanies
* this distribution, and is available at
* http://www.apache.org/licenses/LICENSE-2.0
*
*******************************************************************************/
/**
*
*/
package eu.planets_project.services.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;

import eu.planets_project.ifr.core.techreg.formats.FormatRegistry;
import eu.planets_project.ifr.core.techreg.formats.FormatRegistryFactory;
import eu.planets_project.services.datatypes.Checksum;
import eu.planets_project.services.datatypes.Content;
import eu.planets_project.services.datatypes.DigitalObject;
import eu.planets_project.services.datatypes.Event;
import eu.planets_project.services.datatypes.Metadata;

/**
* Utils for handling digital objects.
* @author <a href="mailto:Andrew.Jackson@bl.uk">Andy Jackson</a>
*/
public final class DigitalObjectUtils {
    static final String SYSTEM_TEMP_DIR = System.getProperty("java.io.tmpdir");

    private DigitalObjectUtils() {/* Util classes are not instantiated */}

    private static final Logger log = Logger.getLogger(DigitalObjectUtils.class.getName());

    private final static FormatRegistry format = FormatRegistryFactory
            .getFormatRegistry();
   
    private static final URI zipType = format.createExtensionUri("zip");
   
    private static File utils_tmp = null;
   
    static {
        utils_tmp = new File(SYSTEM_TEMP_DIR, "dig-ob-utils-tmp".toUpperCase());
        try {
            FileUtils.forceMkdir(utils_tmp);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @return The total size, in bytes, of the bytestream contained or referred
     *         to by this Digital Object. Does not include the size of any
     *         associated metadata, or the Java objects etc.
     */
    public static long getContentSize(final DigitalObject dob) {
        long bytes = 0;
        // Get the size at this level, if set:
        byte[] buf = new byte[1024];
        if (dob.getContent() != null) {
            InputStream inputStream = dob.getContent().getInputStream();
            int length = 0;
            try {
                while ((inputStream != null)
                        && ((length = inputStream.read(buf)) != -1)) {
                    bytes += length;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // Return the total:
        return bytes;
    }
   
    /**
     * @param object The digital object to copy to a temporary file
     * @return The temporary file the digital object's byte stream was written to
     */
    public static File toFile(final DigitalObject object) {
        try {
            /* TODO: use format registry to set the extension? The framework should not presume user needs or perform preservation actions silently. */
            /* TODO: use data registry to store the content? Maybe, but TMP files are needed too: toTmpFile.*/
            File file = File.createTempFile("planets", null);
            file.deleteOnExit();
            toFile(object, file);
            return file;
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new IllegalStateException("Could not copy digital object: " + object);
    }
   
    /**
     * @param object The digital object to copy to a file
     * @param file The file to copy the digital object's byte stream to
     * @return The number of bytes copied
     */
    public static long toFile(final DigitalObject object, final File file) {
        try {
            FileOutputStream fOut = new FileOutputStream(file);
            long bytesCopied = IOUtils.copyLarge(object.getContent().getInputStream(), fOut);
            fOut.close();
            return bytesCopied;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }
   
    /**
     * These cases: <br/>
     * - A compound DO, zip as Content, with MD outside the zip, pointing into
     * it via Title. This is to pass between services.<br/>
     * - A zip file containing CDO, MD inside the zip, pointing to the binaries
     * via the Title. This is an pure file 'IP', in effect.<br/>
     * - A compound DO, pulled from such a CDO zip file, with inputstreams for
     * content. Okay, two formats, different contexts and packing/unpacking
     * options.<br/>
     * - (CDO[zip] or CDO) i.e. If no Content, look up to root and unpack?<br/>
     * - DOIP - a special ZIP file containing CDOs. <br/>
     * Operations:<br/>
     * - Packing one or more CDOs into a DOIP, optionally embedding referenced
     * resources. (Value) resources always to be embedded.<br/>
     * - Unpacking a DOIP and getting N CDOs out, optionally embedding binaries,
     * using ZipInputStreams, or unpacking into Files?<br/>
     * TODO Should DO use URI internally got Content.reference, to allow
     * relative resolution?
     */
    public static void main(String args[]) {
        try {
            URI uri = new URI("FAQ.html");
            System.out.println("Got " + uri);
            System.out.println("Got " + uri.isAbsolute());
            uri = new URI("http://localhost/FAQ.html");
            System.out.println("Got " + uri);
            System.out.println("Got " + uri.isAbsolute());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
  /**
     * A utility method that creates files for the content of "contained"-DigObs in a DigOb.
     * This method returns all contained DigObs one level deep.
     *
     * @param listOfDigObjs The digital objects to create files from
     * @param targetFolder The folder to store result files in
     * @return The child elements of the given digital object as files
     */
    public static List<File> getDigitalObjectsAsFiles(final List<DigitalObject> listOfDigObjs, final File targetFolder) {
        List<File> containedFiles = new ArrayList<File>();
        log.info("received list of dig obj with lengh: "+ listOfDigObjs.size());
        if (listOfDigObjs.size() > 0) {
            for (DigitalObject currentDigObj : listOfDigObjs) {
                String name = getFileNameFromDigObject(currentDigObj, null);
                log.info("name of dig obj is: "+name);
                File file = new File(targetFolder, name);
                toFile(currentDigObj, file);
                containedFiles.add(file);
            }
        }
        log.info(String.format("Returning %s files", containedFiles.size()));
        return containedFiles;
    }
 
  /**
   * Creates a Zip-type DigitalObject either from a given folder or from a zip file.
   * @param zip_Or_Folder
   * @param destZipName the name of the created zip file
   * @param createByReference Create the Content of the DO by reference or by value
   * @param withChecksum Create a checksum for the zip file to create
   * @param compress compress the content of the zip file
   * @return The digital object representing the zipped files
   */
  public static DigitalObject createZipTypeDigitalObject(File zip_Or_Folder, String destZipName, boolean createByReference, boolean withChecksum, boolean compress) {
    if(zip_Or_Folder.isFile() && ZipUtils.isZipFile(zip_Or_Folder)) {
      return createZipTypeDigitalObjectFromZip(zip_Or_Folder, createByReference, withChecksum);
    }
    else {
      return createZipTypeDigitalObjectFromFolder(zip_Or_Folder, destZipName, createByReference, withChecksum, compress);
    }
  }


  /**
     * This method returns a new DigOb, containing a file that is specified by the fragment. The Fragment points to a file inside the zip.
     * If the passed DigOb is not a ZIP type DigOb, null is returned.
     *
     * @param digOb the zip type DigOb to get the fragment from
     * @param fragment the fragment (file in the zip) to retrieve
     * @param createByReference create by reference (true) or as stream (false)
     * @return a new DigitalObject containing the extracted fragment as content
     */
    public static DigitalObject getFragment(DigitalObject digOb, String fragment, boolean createByReference) {
      if(!isZipType(digOb)) {
        log.severe("The DigitalObject you have passed is NOT a Zip type DigOb. No Fragment could be retrieved!");
        return null;
      }
      // Do all the tmpFolder related stuff....
      String tmpfolderName = randomizeFileName(getFolderNameFromDigObject(digOb));
      File digObTmp = new File(utils_tmp, tmpfolderName);
      try {
            FileUtils.forceMkdir(digObTmp);
        } catch (IOException e) {
            e.printStackTrace();
        }
      File zip = getZipAsFile(digOb);
     
      File target = ZipUtils.getFileFrom(zip, fragment, digObTmp);     
   
    DigitalObject resultDigOb = createDigitalObject(target, createByReference);
   
    return resultDigOb;
    }
   
   
    public static DigitalObject insertFragment(DigitalObject zipTypeDigOb, File fragmentFile, String targetPathInZip, boolean createByReference) {
    if(!isZipType(zipTypeDigOb)) {
      log.severe("The DigitalObject you have passed is NOT a Zip type DigOb. No Fragment could be retrieved!");
      return null;
    }
   
    File zip = getZipAsFile(zipTypeDigOb);
   
    File modifiedZip = ZipUtils.insertFileInto(zip, fragmentFile, targetPathInZip);
    DigitalObject result = createZipTypeDigitalObjectFromZip(modifiedZip, createByReference, false);
    return result;
  }
   
    public static DigitalObject removeFragment(DigitalObject zipTypeDigOb, String targetPathInZip, boolean createByReference) {
    if(!isZipType(zipTypeDigOb)) {
      log.severe("The DigitalObject you have passed is NOT a Zip type DigOb. No Fragment could be retrieved!");
      return null;
    }
   
    File zip = getZipAsFile(zipTypeDigOb);
   
    File modifiedZip = ZipUtils.removeFileFrom(zip, targetPathInZip);
    DigitalObject result = createZipTypeDigitalObjectFromZip(modifiedZip, createByReference, false);
    return result;
  }

  public static List<String> listFragments(DigitalObject digOb) {
      if(!isZipType(digOb)) {
        log.severe("This DigitalObject is NOT a Zip-type DigOb! No Fragments to return, sorry!!!");
        return null;
      }
     
      return digOb.getFragments();
    }
   
 
  /**
   * test if this is a zip type DigitalObject (format-URL == planets:fmt/ext/zip)
   * @param digOb the DigitalObject to test
   * @return "true" if the digOb is of type zip, "false" if not ;-)
   */
  public static boolean isZipType(DigitalObject digOb) {
    if(digOb.getFormat()==null) {
      return false;
    }
    return digOb.getFormat().equals(zipType);
  }
 
 
  /**
   * Gets the title from the passed digOb and returns a proper folder name (e.g. strip the extension etc.)
   * @param digOb to get the folder name from
   * @return the folder name based on "title" in the passed digOb.
   */
  public static String getFolderNameFromDigObject(DigitalObject digOb) {
    String title = digOb.getTitle();
    if(title==null) {
      return null;
    }
   
    if(title.contains(" ")) {
      title = title.replaceAll(" ", "_");
    }
   
    if(title.equalsIgnoreCase(".svn")) {
      return title;
    }
    if(title.contains(".")) {
      title = title.substring(0, title.lastIndexOf("."));
    }
    return title;
  }

  /**
   * Gets the title from the passed digOb and returns a proper file name
   * @param digOb to get the file name from
   * @param supposedFormatURI This could be the format you believe the file has. Used to create a proper file name.
   * @return the folder name based on "title" in the passed digOb.
   */
  public static String getFileNameFromDigObject(DigitalObject digOb, URI supposedFormatURI) {
    String title = digOb.getTitle();
    String ext = null;
   
   
    // I know, this is evil, but this is a workaround for the Zip-DigitalObjectUtils
    if(supposedFormatURI==null) {
      URI digObFormat = digOb.getFormat();
      if(digObFormat==null) {
        ext = "bin";
      }
      else {
        ext = format.getFirstExtension(digObFormat);
      }
    }
    else {
      ext = format.getFirstExtension(supposedFormatURI);
    }
   
    if(title==null) {
      String defaultTitle = "default_input";
      title = defaultTitle + "." + ext;
    }
   
    if(title.contains(" ")) {
      title = title.replaceAll(" ", "_");
    }
   
    if(title.contains(".")) {
      return title;
    }
    else {
      title = title + "." + ext;
    }
    return randomizeFileName(title);
   
  }

  public static boolean cleanDigObUtilsTmp() {
      try {
            FileUtils.cleanDirectory(utils_tmp);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    return true;
  }

  /**
       * Generates a ZIP-type DigitalObject from a given folder, containing the zip file itself at the top-level
       * DigitalObject and a list of the files contained in this zip as "fragments" DigitalObjects.
       *
       * @param folder the folder to create a zip from and build the DigitalObject
     * @param destZipName the name the zip file should have. If no name is specified, the name of the folder will be used.
     * @param createByReference a flag to set whether you want to create the DigObs by Reference or as stream...
     * @param withChecksum creates a zip with a checksum.
     * @param compress compress the zip content or not.
     * @return a DigitalObject containing the zip file created from "folder" and a list of the files inside the zip as "fragments".
       */
      private static DigitalObject createZipTypeDigitalObjectFromFolder(File folder, String destZipName, boolean createByReference, boolean withChecksum, boolean compress) {
        String zipName = null;
        if(destZipName==null) {
          zipName = folder.getName() + ".zip";
        }
        else {
          if(destZipName.contains(".")) {
            String tmpName = destZipName.substring(0, destZipName.lastIndexOf(".")) + ".zip";
            zipName = tmpName;
          }
          else {
            zipName = destZipName + ".zip";
          }
        }
        File zip_tmp = new File(utils_tmp, randomizeFileName("zip_from_folder_tmp"));
        try {
                FileUtils.forceMkdir(zip_tmp);
            } catch (IOException e) {
                e.printStackTrace();
            }
       
        if(withChecksum) {
          ZipResult zipResult = ZipUtils.createZipAndCheck(folder, zip_tmp, zipName, compress);
         
          if(createByReference) {
            DigitalObject digOb = null;
          digOb = new DigitalObject.Builder(Content.byReference(getUrlFromFile(zipResult.getZipFile()))
              .withChecksum(zipResult.getChecksum()))
              .title(zipName)
              .format(format.createExtensionUri("zip"))
              .fragments(ZipUtils.getAllFragments(zipResult.getZipFile()))
              .build();
            return digOb;
          }
          else {
            DigitalObject digOb = new DigitalObject.Builder(Content.byReference(zipResult.getZipFile())
              .withChecksum(zipResult.getChecksum()))
              .title(zipName)
              .format(format.createExtensionUri("zip"))
              .fragments(ZipUtils.getAllFragments(zipResult.getZipFile()))
              .build();
            return digOb;
          }
        }
        else {
          File result = ZipUtils.createZip(folder, zip_tmp, zipName, compress);
         
          if(createByReference) {
            DigitalObject digOb = null;
          digOb = new DigitalObject.Builder(Content.byReference(getUrlFromFile(result)))
              .title(zipName)
              .format(format.createExtensionUri("zip"))
              .fragments(ZipUtils.getAllFragments(result))
              .build();
            return digOb;
          }
          else {
            DigitalObject digOb = new DigitalObject.Builder(Content.byReference(result))
              .title(zipName)
              .format(format.createExtensionUri("zip"))
              .fragments(ZipUtils.getAllFragments(result))
              .build();
            return digOb;
          }
        }
      }

  /**
   * Generates a ZIP-type DigitalObject from a given zip file, containing the zip file itself at the top-level
   * DigitalObject and the files contained in this zip as "contained" DigitalObjects.
   *
   * @param zipFile the zip file to create a DigitalObject with
   * @param createByReference a flag to set whether you want to create the DigObs by Reference or as stream...
   * @param withChecksum create DigOb with checksum or not?
   * @return a DigitalObject containing the zip file and a list of the contained files in this zip as "fragments".
   */
  private static DigitalObject createZipTypeDigitalObjectFromZip(File zipFile, boolean createByReference, boolean withChecksum) {
    DigitalObject digOb = null;
    if(withChecksum) {
      Checksum checksum = null;
      try {
        checksum = new Checksum("MD5", Arrays.toString(Checksums.md5(zipFile)));
      } catch (IOException e) {
        e.printStackTrace();
      }
      if(createByReference) {
        digOb = new DigitalObject.Builder(Content.byReference(getUrlFromFile(zipFile))
            .withChecksum(checksum))
            .title(zipFile.getName())
            .format(format.createExtensionUri("zip"))
            // lists all entries in this zip file and includes them as "fragments"
            .fragments(ZipUtils.getAllFragments(zipFile))
            .build();
      }
      else {
        digOb = new DigitalObject.Builder(Content.byReference(zipFile)
            .withChecksum(checksum))
            .title(zipFile.getName())
            .format(format.createExtensionUri("zip"))
            // lists all entries in this zip file and includes them as "fragments"
            .fragments(ZipUtils.getAllFragments(zipFile))
            .build();
      }
    }
    else {
      if(createByReference) {
        digOb = new DigitalObject.Builder(Content.byReference(getUrlFromFile(zipFile)))
            .title(zipFile.getName())
            .format(format.createExtensionUri("zip"))
            // lists all entries in this zip file and includes them as "fragments"
            .fragments(ZipUtils.getAllFragments(zipFile))
            .build();
      }
      else {
        digOb = new DigitalObject.Builder(Content.byReference(zipFile))
            .title(zipFile.getName())
            .format(format.createExtensionUri("zip"))
            // lists all entries in this zip file and includes them as "fragments"
            .fragments(ZipUtils.getAllFragments(zipFile))
            .build();
      }
    }
    return digOb;
  }

  private static File getZipAsFile(DigitalObject digOb) {
      String folderName = randomizeFileName(getFolderNameFromDigObject(digOb));
     
    File tmpFolder = new File(utils_tmp, folderName);
    File zip = null;
        try {
            FileUtils.forceMkdir(tmpFolder);
           
            zip = new File(tmpFolder, getFileNameFromDigObject(digOb, null));
           
            FileOutputStream out = new FileOutputStream(zip);
            IOUtils.copyLarge(digOb.getContent().getInputStream(), out);
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
   
    return zip;
  }
 
  static String randomizeFileName(String name) {
        Random random = new Random();
        String prefix = null;
        String postfix = null;
        String randomName = null;
        if(name==null) {
            name = "";
        }
        if(name.contains(".")) {
            prefix = name.substring(0, name.lastIndexOf(".")) + "_";
            postfix = name.substring(name.lastIndexOf("."));
            randomName = prefix + random.nextInt(Integer.MAX_VALUE) + postfix;
        }
        else {
            randomName = name + "_" + random.nextInt(Integer.MAX_VALUE);
        }
        return randomName;
    }

  /**
   * Creates a ZIP-type DigitalObject from a given file, by reference or as stream
   * @param file the file to create the DigitalObject from
   * @param createByReference create by reference (true) or as stream (false)
   * @return
   */
  private static DigitalObject createDigitalObject(File file, boolean createByReference) {
    DigitalObject result = null;
    if(file.isDirectory()) {
      result = createZipTypeDigitalObjectFromFolder(file, FilenameUtils.getBaseName(file.getName()), createByReference, true, true);
      return result;
    }
    else if(ZipUtils.isZipFile(file)) {
      result = createZipTypeDigitalObjectFromZip(file, createByReference, false);
      return result;
    }
    else {
      if(createByReference) {
        result = new DigitalObject.Builder(Content.byReference(getUrlFromFile(file))).title(file.getName()).build();
      }
      else {
        result = new DigitalObject.Builder(Content.byReference(file)).title(file.getName()).build();
      }
    }
    return result;
  }
 
   /**
     * Convenience method that creates a URL from a file in a proper (i.e. not deprecated) way, using the toURI().toURL() way.
     * Hiding the Exception, so you don't have to put it in a try-catch block.
     * @param file
     * @return The URL for the given file
     */
    private static URL getUrlFromFile(File file) {
        try {
            return file.toURI().toURL();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return null;
    }
 
  /**
   * @param digitalObject
   *        The digital object to be updated
   * @param newEvent
   *        The event to add to the digital object
   * @return changed digital object with new event
   */
  public static DigitalObject addEvent(DigitalObject digitalObject, Event newEvent)
    {
    DigitalObject res = null;
   
      if (digitalObject != null && newEvent != null)
      {
        DigitalObject.Builder b = new DigitalObject.Builder(digitalObject.getContent());
        if (digitalObject.getTitle() != null) b.title(digitalObject.getTitle());
        if (digitalObject.getPermanentUri() != null) b.permanentUri(digitalObject.getPermanentUri());
        if (digitalObject.getFormat() != null) b.format(digitalObject.getFormat());
        if (digitalObject.getManifestationOf() != null)
          b.manifestationOf(digitalObject.getManifestationOf());
        if (digitalObject.getMetadata() != null)
          b.metadata((Metadata[]) digitalObject.getMetadata().toArray(new Metadata[0]));
        if (digitalObject.getEvents() != null)
        {
        List<Event> eventList = digitalObject.getEvents();
        eventList.add(newEvent);
          b.events((Event[]) eventList.toArray(new Event[0]));
        }
            res = b.build();
      }
    return res;
  }
 
  /**
   * This method returns event by summary
   *
   * in the targetObj
   * @param initObj
   *        The initial digital object
   * @param summary
   *        Event property we are looking for
   * @return res
   *         The found event for particular summary
   */
  public static Event getEventBySummary(DigitalObject initObj, String summary)
  {
    Event res = null;
   
    if (summary != null && initObj != null)
    {   
      // search for the right event
      for(Event event : initObj.getEvents())
      {
        if (event != null)
        {
          if(event.getSummary().equals(summary))
          {
              res = event;
          }
        }
      }     
    }
   
    return res;
  }
 
  /**
   * This method evaluates if particular digital object contains an ingest event
   *
   * @param obj
   *        The digital object
   * @param summary
   *        The summary of the event
   * @return res
   *        Returns true if digital object contains ingest event otherwise false
   */
  public static boolean hasEvent(DigitalObject obj, String summary)
  {
    boolean res = false;
   
    if (obj != null && summary != null)
    {   
      // search for the right event
      for(Event event : obj.getEvents())
      {
        if (event != null)
        {
        if(event.getSummary().equals(summary))
        {
            res = true;
        }
        }
      }     
    }
   
    return res;
  }
}
TOP

Related Classes of eu.planets_project.services.utils.DigitalObjectUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.