Package org.structr.web.common

Source Code of org.structr.web.common.FileHelper$Base64URIData

/**
* Copyright (C) 2010-2014 Morgner UG (haftungsbeschränkt)
*
* This file is part of Structr <http://structr.org>.
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr 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 Affero General Public License
* along with Structr.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.web.common;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.activation.MimetypesFileTypeMap;
import net.sf.jmimemagic.Magic;
import net.sf.jmimemagic.MagicException;
import net.sf.jmimemagic.MagicMatch;
import net.sf.jmimemagic.MagicMatchNotFoundException;
import net.sf.jmimemagic.MagicParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.structr.common.PathHelper;
import org.structr.common.SecurityContext;
import org.structr.common.error.FrameworkException;
import org.structr.core.GraphObject;
import org.structr.core.Services;
import org.structr.core.app.App;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.AbstractNode;
import org.structr.core.entity.LinkedTreeNode;
import org.structr.core.property.PropertyMap;
import org.structr.util.Base64;
import org.structr.web.entity.AbstractFile;
import org.structr.web.entity.FileBase;
import org.structr.web.entity.Folder;

//~--- classes ----------------------------------------------------------------
/**
* File utility class.
*
* @author Axel Morgner
*/
public class FileHelper {

  private static final String UNKNOWN_MIME_TYPE = "application/octet-stream";
  private static final Logger logger = Logger.getLogger(FileHelper.class.getName());
  private static final MimetypesFileTypeMap mimeTypeMap = new MimetypesFileTypeMap(FileHelper.class.getResourceAsStream("/mime.types"));

  //~--- methods --------------------------------------------------------
  /**
   * Transform an existing file into the target class.
   *
   * @param <T>
   * @param securityContext
   * @param uuid
   * @param fileType
   * @return transformed file
   * @throws FrameworkException
   * @throws IOException
   */
  public static <T extends org.structr.dynamic.File> T transformFile(final SecurityContext securityContext, final String uuid, final Class<T> fileType) throws FrameworkException, IOException {

    AbstractFile existingFile = getFileByUuid(securityContext, uuid);

    if (existingFile != null) {

      existingFile.unlockReadOnlyPropertiesOnce();
      existingFile.setProperty(AbstractNode.type, fileType == null ? org.structr.dynamic.File.class.getSimpleName() : fileType.getSimpleName());

      existingFile = getFileByUuid(securityContext, uuid);

      return (T)(fileType != null ? fileType.cast(existingFile) : (org.structr.dynamic.File) existingFile);
    }

    return null;
  }

  /**
   * Create a new image node from image data encoded in base64 format.
   *
   * If the given string is an uuid of an existing file, transform it into
   * the target class.
   *
   * @param <T>
   * @param securityContext
   * @param rawData
   * @param t defaults to File.class if null
   * @return file
   * @throws FrameworkException
   * @throws IOException
   */
  public static <T extends org.structr.dynamic.File> T createFileBase64(final SecurityContext securityContext, final String rawData, final Class<T> t) throws FrameworkException, IOException {

    Base64URIData uriData = new Base64URIData(rawData);

    return createFile(securityContext, uriData.getBinaryData(), uriData.getContentType(), t);

  }

  /**
   * Create a new file node from the given input stream
   *
   * @param <T>
   * @param securityContext
   * @param fileStream
   * @param contentType
   * @param fileType defaults to File.class if null
   * @param name
   * @return file
   * @throws FrameworkException
   * @throws IOException
   */
  public static <T extends org.structr.dynamic.File> T createFile(final SecurityContext securityContext, final InputStream fileStream, final String contentType, final Class<T> fileType, final String name)
    throws FrameworkException, IOException {

    final byte[] data = IOUtils.toByteArray(fileStream);
    return createFile(securityContext, data, contentType, fileType, name);

  }

  /**
   * Create a new file node from the given byte array
   *
   * @param <T>
   * @param securityContext
   * @param fileData
   * @param contentType if null, try to auto-detect content type
   * @param t
   * @param name
   * @return file
   * @throws FrameworkException
   * @throws IOException
   */
  public static <T extends org.structr.dynamic.File> T createFile(final SecurityContext securityContext, final byte[] fileData, final String contentType, final Class<T> t, final String name)
    throws FrameworkException, IOException {

    PropertyMap props = new PropertyMap();

    props.put(AbstractNode.name, name);

    T newFile = (T) StructrApp.getInstance(securityContext).create(t, props);

    setFileData(newFile, fileData, contentType);

    return newFile;
  }

  /**
   * Create a new file node from the given byte array
   *
   * @param <T>
   * @param securityContext
   * @param fileData
   * @param contentType
   * @param t defaults to File.class if null
   * @return file
   * @throws FrameworkException
   * @throws IOException
   */
  public static <T extends org.structr.dynamic.File> T createFile(final SecurityContext securityContext, final byte[] fileData, final String contentType, final Class<T> t)
    throws FrameworkException, IOException {

    return createFile(securityContext, fileData, contentType, t, null);

  }

  /**
   * Decodes base64-encoded raw data into binary data and writes it to the
   * given file.
   *
   * @param file
   * @param rawData
   * @throws FrameworkException
   * @throws IOException
   */
  public static void decodeAndSetFileData(final org.structr.dynamic.File file, final String rawData) throws FrameworkException, IOException {

    Base64URIData uriData = new Base64URIData(rawData);
    setFileData(file, uriData.getBinaryData(), uriData.getContentType());

  }

  /**
   * Write image data to the given file node and set checksum and size.
   *
   * @param file
   * @param fileData
   * @param contentType if null, try to auto-detect content type
   * @throws FrameworkException
   * @throws IOException
   */
  public static void setFileData(final org.structr.dynamic.File file, final byte[] fileData, final String contentType)
    throws FrameworkException, IOException {

    FileHelper.writeToFile(file, fileData);
    file.setProperty(org.structr.dynamic.File.contentType, contentType != null ? contentType : getContentMimeType(file));
    file.unlockReadOnlyPropertiesOnce();
    file.setProperty(org.structr.dynamic.File.checksum, FileHelper.getChecksum(file));
    file.unlockReadOnlyPropertiesOnce();
    file.setProperty(org.structr.dynamic.File.size, FileHelper.getSize(file));
    file.unlockReadOnlyPropertiesOnce();
    file.setProperty(org.structr.dynamic.File.version, 1);

  }

  /**
   * Update checksum content type and size of the given file
   *
   * @param file the file
   * @throws FrameworkException
   * @throws IOException
   */
  public static void updateMetadata(final org.structr.dynamic.File file) throws FrameworkException, IOException {

    file.setProperty(org.structr.dynamic.File.contentType, getContentMimeType(file));
    file.setProperty(org.structr.dynamic.File.checksum, FileHelper.getChecksum(file));
    file.setProperty(org.structr.dynamic.File.size, FileHelper.getSize(file));

  }

  //~--- get methods ----------------------------------------------------
  public static String getBase64String(final org.structr.dynamic.File file) {

    try {

      return Base64.encodeToString(IOUtils.toByteArray(file.getInputStream()), false);

    } catch (IOException ex) {
      logger.log(Level.SEVERE, "Could not get base64 string from file ", ex);
    }

    return null;
  }

  //~--- inner classes --------------------------------------------------
  public static class Base64URIData {

    private final String contentType;
    private final String data;

    //~--- constructors -------------------------------------------
    public Base64URIData(final String rawData) {

      String[] parts = StringUtils.split(rawData, ",");

      data = parts[1];
      contentType = StringUtils.substringBetween(parts[0], "data:", ";base64");

    }

    //~--- get methods --------------------------------------------
    public String getContentType() {

      return contentType;

    }

    public String getData() {

      return data;

    }

    public byte[] getBinaryData() {

      return Base64.decode(data);

    }

  }

  /**
   * Write binary data to a file and reference the file on disk at the
   * given file node
   *
   * @param fileNode
   * @param inStream
   * @throws FrameworkException
   * @throws IOException
   */
  public static void writeToFile(final org.structr.dynamic.File fileNode, final InputStream inStream) throws FrameworkException, IOException {

    writeToFile(fileNode, IOUtils.toByteArray(inStream));

  }

  /**
   * Write binary data to a file and reference the file on disk at the
   * given file node
   *
   * @param fileNode
   * @param data
   * @throws FrameworkException
   * @throws IOException
   * @return the file on disk
   */
  public static File writeToFile(final org.structr.dynamic.File fileNode, final byte[] data) throws FrameworkException, IOException {

    String id = fileNode.getProperty(GraphObject.id);
    if (id == null) {

      final String newUuid = UUID.randomUUID().toString().replaceAll("[\\-]+", "");
      id = newUuid;

      fileNode.unlockReadOnlyPropertiesOnce();
      fileNode.setProperty(GraphObject.id, newUuid);
    }

    fileNode.unlockReadOnlyPropertiesOnce();
    fileNode.setProperty(org.structr.dynamic.File.relativeFilePath, org.structr.dynamic.File.getDirectoryPath(id) + "/" + id);

    final String filesPath = Services.getInstance().getConfigurationValue(Services.FILES_PATH);

    java.io.File fileOnDisk = new java.io.File(filesPath + "/" + fileNode.getRelativeFilePath());

    fileOnDisk.getParentFile().mkdirs();
    FileUtils.writeByteArrayToFile(fileOnDisk, data);

    return fileOnDisk;

  }

  //~--- get methods ----------------------------------------------------
  /**
   * Return mime type of given file
   *
   * @param file
   * @return content type
   * @throws java.io.IOException
   */
  public static String getContentMimeType(final org.structr.web.entity.FileBase file) throws IOException {
    return getContentMimeType(file.getFileOnDisk(), file.getProperty(AbstractNode.name));
  }

  /**
   * Return mime type of given file
   *
   * @param file
   * @param name
   * @return content type
   * @throws java.io.IOException
   */
  public static String getContentMimeType(final java.io.File file, final String name) throws IOException {

    String mimeType;
   
    // try name first, if not null
    if (name != null) {
      mimeType = mimeTypeMap.getContentType(name);
      if (mimeType != null && !UNKNOWN_MIME_TYPE.equals(mimeType)) {
        return mimeType;
      }
    }

    // then file content
    mimeType = Files.probeContentType(file.toPath());
    if (mimeType != null && !UNKNOWN_MIME_TYPE.equals(mimeType)) {

      return mimeType;
    }

    // fallback: jmimemagic
    try {
      final MagicMatch match = Magic.getMagicMatch(file, false, true);
      if (match != null) {

        return match.getMimeType();
      }

    } catch (MagicParseException | MagicMatchNotFoundException | MagicException ignore) {
      // mex.printStackTrace();
    }


    // no success :(
    return UNKNOWN_MIME_TYPE;
  }

  /**
   * Calculate CRC32 checksum of given file
   *
   * @param file
   * @return checksum
   */
  public static Long getChecksum(final FileBase file) {

    String relativeFilePath = file.getRelativeFilePath();

    if (relativeFilePath != null) {

      String filePath = getFilePath(relativeFilePath);

      try {

        java.io.File fileOnDisk = new java.io.File(filePath);
        Long checksum = FileUtils.checksumCRC32(fileOnDisk);

        logger.log(Level.FINE, "Checksum of file {0} ({1}): {2}", new Object[]{file.getUuid(), filePath, checksum});

        return checksum;

      } catch (IOException ex) {

        logger.log(Level.WARNING, "Could not calculate checksum of file {0}", filePath);

      }

    }

    return null;

  }

  /**
   * Return size of file on disk, or -1 if not possible
   *
   * @param file
   * @return size
   */
  public static long getSize(final FileBase file) {

    String path = file.getRelativeFilePath();

    if (path != null) {

      String filePath = getFilePath(path);

      try {

        java.io.File fileOnDisk = new java.io.File(filePath);
        long fileSize = fileOnDisk.length();

        logger.log(Level.FINE, "File size of node {0} ({1}): {2}", new Object[]{file.getUuid(), filePath, fileSize});

        return fileSize;

      } catch (Exception ex) {

        logger.log(Level.WARNING, "Could not calculate file size{0}", filePath);

      }

    }

    return -1;

  }

  /**
   * Find a file by its absolute ancestor path.
   *
   * File may not be hidden or deleted.
   *
   * @param securityContext
   * @param absolutePath
   * @return file
   */
  public static AbstractFile getFileByAbsolutePath(final SecurityContext securityContext, final String absolutePath) {

    String[] parts = PathHelper.getParts(absolutePath);

    if (parts == null || parts.length == 0) {
      return null;
    }

    // Find root folder
    if (parts[0].length() == 0) {
      return null;
    }

    AbstractFile currentFile = getFirstRootFileByName(securityContext, parts[0]);
    if (currentFile == null) {
      return null;
    }

    for (int i = 1; i < parts.length; i++) {

      List<AbstractFile> children = currentFile.getProperty(AbstractFile.children);

      currentFile = null;

      for (AbstractFile child : children) {

        if (child.getProperty(AbstractFile.name).equals(parts[i])) {

          // Child with matching name found
          currentFile = child;
          break;
        }

      }

      if (currentFile == null) {
        return null;
      }

    }

    return currentFile;

  }

  public static AbstractFile getFileByUuid(final SecurityContext securityContext, final String uuid) {

    logger.log(Level.FINE, "Search for file with uuid: {0}", uuid);

    try {
      return StructrApp.getInstance(securityContext).get(AbstractFile.class, uuid);

    } catch (FrameworkException fex) {

      logger.log(Level.WARNING, "Unable to find a file by UUID {0}: {1}", new Object[]{uuid, fex.getMessage()});
    }

    return null;
  }

  public static AbstractFile getFirstFileByName(final SecurityContext securityContext, final String name) {

    logger.log(Level.FINE, "Search for file with name: {0}", name);

    try {
      return StructrApp.getInstance(securityContext).nodeQuery(AbstractFile.class).andName(name).getFirst();

    } catch (FrameworkException fex) {

      logger.log(Level.WARNING, "Unable to find a file for name {0}: {1}", new Object[]{name, fex.getMessage()});
    }

    return null;
  }

  /**
   * Find the first file with given name on root level (without parent folder).
   *
   * @param securityContext
   * @param name
   * @return file
   */
  public static AbstractFile getFirstRootFileByName(final SecurityContext securityContext, final String name) {

    logger.log(Level.FINE, "Search for file with name: {0}", name);

    try {
      final List<AbstractFile> files = StructrApp.getInstance(securityContext).nodeQuery(AbstractFile.class).andName(name).getAsList();

      for (final AbstractFile file : files) {

        if (file.getProperty(AbstractFile.parent) == null) {
          return file;
        }

      }

    } catch (FrameworkException fex) {

      logger.log(Level.WARNING, "Unable to find a file for name {0}: {1}", new Object[]{name, fex.getMessage()});
    }

    return null;
  }

  /**
   * Return the virtual folder path of any
   * {@link File} or
   * {@link org.structr.web.entity.Folder}
   *
   * @param file
   * @return path
   */
  public static String getFolderPath(final AbstractFile file) {

    LinkedTreeNode parentFolder = file.getProperty(AbstractFile.parent);

    String folderPath = file.getProperty(AbstractFile.name);

    if (folderPath == null) {
      folderPath = file.getProperty(GraphObject.id);
    }

    while (parentFolder != null) {
      folderPath = parentFolder.getName().concat("/").concat(folderPath);
      parentFolder = parentFolder.getProperty(AbstractFile.parent);
    }

    return "/".concat(folderPath);
  }

  public static String getFilePath(final String... pathParts) {

    String filePath = Services.getInstance().getConfigurationValue(Services.FILES_PATH);
    StringBuilder returnPath = new StringBuilder();

    returnPath.append(filePath);
    returnPath.append(filePath.endsWith("/")
      ? ""
      : "/");

    for (String pathPart : pathParts) {
      returnPath.append(pathPart);
    }

    return returnPath.toString();
  }

  /**
   * Create one folder per path item and return the last folder.
   *
   * F.e.: /a/b/c => Folder["name":"a"] --HAS_CHILD--> Folder["name":"b"]
   * --HAS_CHILD--> Folder["name":"c"], returns Folder["name":"c"]
   *
   * @param securityContext
   * @param path
   * @return folder
   * @throws FrameworkException
   */
  public static Folder createFolderPath(final SecurityContext securityContext, final String path) throws FrameworkException {

    App app = StructrApp.getInstance(securityContext);

    if (path == null) {

      return null;
    }

    Folder folder = (Folder) FileHelper.getFileByAbsolutePath(securityContext, path);

    if (folder != null) {
      return folder;
    }

    String[] parts = PathHelper.getParts(path);
    String partialPath = "";

    for (String part : parts) {

      // ignore ".." and "." in paths
      if ("..".equals(part) || ".".equals(part)) {
        continue;
      }

      Folder parent = folder;

      partialPath += PathHelper.PATH_SEP + part;
      folder = (Folder) FileHelper.getFileByAbsolutePath(securityContext, partialPath);

      if (folder == null) {

        folder = app.create(Folder.class, part);

      }

      if (parent != null) {

        folder.setProperty(Folder.parent, parent);

      }

//      if (folder != null && parent != null) {
//        app.create(parent, folder, Folders.class);
//        folder.updateInIndex();
//      }

    }

    return folder;

  }


}
TOP

Related Classes of org.structr.web.common.FileHelper$Base64URIData

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.