org.structr.web.entity.FileBase.java Source code

Java tutorial

Introduction

Here is the source code for org.structr.web.entity.FileBase.java

Source

/**
 * Copyright (C) 2010-2016 Structr GmbH
 *
 * 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 Affero 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.entity;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.chemistry.opencmis.commons.data.AllowableActions;
import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.structr.cmis.CMISInfo;
import org.structr.cmis.info.CMISDocumentInfo;
import org.structr.cmis.info.CMISFolderInfo;
import org.structr.cmis.info.CMISItemInfo;
import org.structr.cmis.info.CMISPolicyInfo;
import org.structr.cmis.info.CMISRelationshipInfo;
import org.structr.cmis.info.CMISSecondaryInfo;
import org.structr.common.Permission;
import org.structr.common.PropertyView;
import org.structr.common.SecurityContext;
import org.structr.common.View;
import org.structr.common.error.ErrorBuffer;
import org.structr.common.error.FrameworkException;
import org.structr.core.Export;
import org.structr.core.GraphObject;
import org.structr.core.Services;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.Principal;
import org.structr.core.graph.NodeInterface;
import org.structr.core.graph.Tx;
import org.structr.core.property.BooleanProperty;
import org.structr.core.property.IntProperty;
import org.structr.core.property.LongProperty;
import org.structr.core.property.Property;
import org.structr.core.property.StringProperty;
import org.structr.files.cmis.config.StructrFileActions;
import org.structr.files.text.FulltextIndexingTask;
import org.structr.schema.action.JavaScriptSource;
import org.structr.web.common.DownloadHelper;
import org.structr.web.common.FileHelper;
import org.structr.web.common.ImageHelper;
import static org.structr.web.entity.Indexable.extractedContent;
import org.structr.web.entity.relation.Folders;

/**
 *
 *
 */
public class FileBase extends AbstractFile
        implements Indexable, Linkable, JavaScriptSource, CMISInfo, CMISDocumentInfo {

    private static final Logger logger = Logger.getLogger(FileBase.class.getName());

    public static final Property<String> contentType = new StringProperty("contentType").indexedWhenEmpty();
    public static final Property<String> relativeFilePath = new StringProperty("relativeFilePath").readOnly();
    public static final Property<Long> size = new LongProperty("size").indexed().readOnly();
    public static final Property<String> url = new StringProperty("url");
    public static final Property<Long> checksum = new LongProperty("checksum").indexed().unvalidated().readOnly();
    public static final Property<Integer> cacheForSeconds = new IntProperty("cacheForSeconds").cmis();
    public static final Property<Integer> version = new IntProperty("version").indexed().readOnly();
    public static final Property<Boolean> isFile = new BooleanProperty("isFile").defaultValue(true).readOnly();

    public static final View publicView = new View(FileBase.class, PropertyView.Public, type, name, contentType,
            size, url, owner, path, isFile);
    //public static final View uiView = new View(FileBase.class, PropertyView.Ui, type, contentType, relativeFilePath, size, url, parent, checksum, version, cacheForSeconds, owner, isFile, hasParent, extractedContent, indexedWords);
    public static final View uiView = new View(FileBase.class, PropertyView.Ui, type, contentType, relativeFilePath,
            size, url, parent, checksum, version, cacheForSeconds, owner, isFile, hasParent, extractedContent);

    @Override
    public boolean onCreation(final SecurityContext securityContext, final ErrorBuffer errorBuffer)
            throws FrameworkException {

        if (super.onCreation(securityContext, errorBuffer)) {

            setProperty(hasParent, getProperty(parentId) != null);

            if ("true".equals(StructrApp.getConfigurationValue(Services.APPLICATION_FILESYSTEM_ENABLED, "false"))) {

                final Folder workingOrHomeDir = getCurrentWorkingDir();
                if (workingOrHomeDir != null && getProperty(AbstractFile.parent) == null) {

                    setProperty(AbstractFile.parent, workingOrHomeDir);
                }
            }

            return true;
        }

        return false;
    }

    @Override
    public boolean onModification(final SecurityContext securityContext, final ErrorBuffer errorBuffer)
            throws FrameworkException {

        if (super.onModification(securityContext, errorBuffer)) {

            setProperty(hasParent, getProperty(parentId) != null);
            return true;
        }

        return false;
    }

    @Override
    public void onNodeCreation() {

        final String uuid = getUuid();
        final String filePath = getDirectoryPath(uuid) + "/" + uuid;

        try {
            unlockReadOnlyPropertiesOnce();
            setProperty(relativeFilePath, filePath);

        } catch (Throwable t) {

            logger.log(Level.WARNING, "Exception while trying to set relative file path {0}: {1}",
                    new Object[] { filePath, t });

        }
    }

    @Override
    public void onNodeDeletion() {

        String filePath = null;
        try {
            final String path = getRelativeFilePath();

            if (path != null) {

                filePath = FileHelper.getFilePath(path);

                java.io.File toDelete = new java.io.File(filePath);

                if (toDelete.exists() && toDelete.isFile()) {

                    toDelete.delete();
                }
            }

        } catch (Throwable t) {

            logger.log(Level.WARNING, "Exception while trying to delete file {0}: {1}",
                    new Object[] { filePath, t });

        }

    }

    @Override
    public void afterCreation(SecurityContext securityContext) {

        try {

            final String filesPath = Services.getInstance().getConfigurationValue(Services.FILES_PATH);
            java.io.File fileOnDisk = new java.io.File(filesPath + "/" + getRelativeFilePath());

            if (fileOnDisk.exists()) {
                return;
            }

            fileOnDisk.getParentFile().mkdirs();

            try {

                fileOnDisk.createNewFile();

            } catch (IOException ex) {

                logger.log(Level.SEVERE, "Could not create file", ex);
                return;
            }

            unlockReadOnlyPropertiesOnce();
            setProperty(checksum, FileHelper.getChecksum(FileBase.this));

            unlockReadOnlyPropertiesOnce();
            setProperty(version, 0);

            long fileSize = FileHelper.getSize(FileBase.this);
            if (fileSize > 0) {
                unlockReadOnlyPropertiesOnce();
                setProperty(size, fileSize);
            }

        } catch (FrameworkException ex) {

            logger.log(Level.SEVERE, "Could not create file", ex);

        }

    }

    @Override
    public String getPath() {
        return FileHelper.getFolderPath(this);
    }

    @Export
    @Override
    public GraphObject getSearchContext(final String searchTerm, final int contextLength) {

        final String text = getProperty(extractedContent);
        if (text != null) {

            return DownloadHelper.getContextObject(searchTerm, text, contextLength);
        }

        return null;
    }

    public void notifyUploadCompletion() {
        StructrApp.getInstance(securityContext).processTasks(new FulltextIndexingTask(this));
    }

    public String getRelativeFilePath() {

        return getProperty(FileBase.relativeFilePath);

    }

    public String getUrl() {

        return getProperty(FileBase.url);

    }

    @Override
    public String getContentType() {

        return getProperty(FileBase.contentType);

    }

    @Override
    public Long getSize() {

        return getProperty(size);

    }

    public Long getChecksum() {

        return getProperty(checksum);

    }

    public String getFormattedSize() {

        return FileUtils.byteCountToDisplaySize(getSize());

    }

    public static String getDirectoryPath(final String uuid) {

        return (uuid != null)
                ? uuid.substring(0, 1) + "/" + uuid.substring(1, 2) + "/" + uuid.substring(2, 3) + "/"
                        + uuid.substring(3, 4)
                : null;

    }

    public void increaseVersion() throws FrameworkException {

        final Integer _version = getProperty(FileBase.version);

        unlockReadOnlyPropertiesOnce();
        if (_version == null) {

            setProperty(FileBase.version, 1);

        } else {

            setProperty(FileBase.version, _version + 1);
        }
    }

    @Override
    public InputStream getInputStream() {

        final String path = getRelativeFilePath();

        if (path != null) {

            final String filePath = FileHelper.getFilePath(path);

            FileInputStream fis = null;
            try {

                java.io.File fileOnDisk = new java.io.File(filePath);

                // Return file input stream and save checksum and size after closing
                fis = new FileInputStream(fileOnDisk);

                return fis;

            } catch (FileNotFoundException e) {
                logger.log(Level.FINE, "File not found: {0}", new Object[] { path });

                if (fis != null) {

                    try {

                        fis.close();

                    } catch (IOException ignore) {
                    }

                }
            }
        }

        return null;
    }

    public OutputStream getOutputStream() {
        return getOutputStream(true);
    }

    public OutputStream getOutputStream(final boolean notifyIndexerAfterClosing) {

        final String path = getRelativeFilePath();
        if (path != null) {

            final String filePath = FileHelper.getFilePath(path);

            try {

                final java.io.File fileOnDisk = new java.io.File(filePath);
                fileOnDisk.getParentFile().mkdirs();

                // Return file output stream and save checksum and size after closing
                final FileOutputStream fos = new FileOutputStream(fileOnDisk) {

                    private boolean closed = false;

                    @Override
                    public void close() throws IOException {

                        if (closed) {
                            return;
                        }

                        try (Tx tx = StructrApp.getInstance().tx()) {

                            super.close();

                            final String _contentType = FileHelper.getContentMimeType(FileBase.this);

                            unlockReadOnlyPropertiesOnce();
                            setProperty(checksum, FileHelper.getChecksum(FileBase.this));

                            unlockReadOnlyPropertiesOnce();
                            setProperty(size, FileHelper.getSize(FileBase.this));
                            setProperty(contentType, _contentType);

                            if (StringUtils.startsWith(_contentType, "image")
                                    || ImageHelper.isImageType(getProperty(name))) {
                                setProperty(NodeInterface.type, Image.class.getSimpleName());
                            }

                            increaseVersion();

                            if (notifyIndexerAfterClosing) {
                                notifyUploadCompletion();
                            }

                            tx.success();

                        } catch (Throwable ex) {

                            logger.log(Level.SEVERE,
                                    "Could not determine or save checksum and size after closing file output stream",
                                    ex);

                        }

                        closed = true;
                    }
                };

                return fos;

            } catch (FileNotFoundException e) {

                e.printStackTrace();
                logger.log(Level.SEVERE, "File not found: {0}", new Object[] { path });
            }

        }

        return null;

    }

    public java.io.File getFileOnDisk() {

        final String path = getRelativeFilePath();
        if (path != null) {

            return new java.io.File(FileHelper.getFilePath(path));
        }

        return null;
    }

    // ----- private methods -----
    /**
     * Returns the Folder entity for the current working directory,
     * or the user's home directory as a fallback.
     * @return
     */
    private Folder getCurrentWorkingDir() {

        final Principal _owner = getProperty(owner);
        Folder workingOrHomeDir = null;

        if (_owner != null && _owner instanceof User) {

            workingOrHomeDir = _owner.getProperty(User.workingDirectory);
            if (workingOrHomeDir == null) {

                workingOrHomeDir = _owner.getProperty(User.homeDirectory);
            }
        }

        return workingOrHomeDir;
    }

    private int flushWordBuffer(final StringBuilder lineBuffer, final StringBuilder wordBuffer,
            final boolean prepend) {

        int wordCount = 0;

        if (wordBuffer.length() > 0) {

            final String word = wordBuffer.toString().replaceAll("[\\n\\t]+", " ");
            if (StringUtils.isNotBlank(word)) {

                if (prepend) {

                    lineBuffer.insert(0, word);

                } else {

                    lineBuffer.append(word);
                }

                // increase word count
                wordCount = 1;
            }

            wordBuffer.setLength(0);
        }

        return wordCount;
    }

    // ----- interface Syncable -----
    @Override
    public List<GraphObject> getSyncData() throws FrameworkException {

        final List<GraphObject> data = super.getSyncData();

        // nodes
        data.add(getProperty(parent));
        data.add(getIncomingRelationship(Folders.class));

        return data;
    }

    // ----- interface JavaScriptSource -----
    @Override
    public String getJavascriptLibraryCode() {

        try (final InputStream is = getInputStream()) {

            return IOUtils.toString(is);

        } catch (IOException ioex) {
            ioex.printStackTrace();
        }

        return null;
    }

    // ----- CMIS support -----
    @Override
    public CMISInfo getCMISInfo() {
        return this;
    }

    @Override
    public BaseTypeId getBaseTypeId() {
        return BaseTypeId.CMIS_DOCUMENT;
    }

    @Override
    public CMISFolderInfo getFolderInfo() {
        return null;
    }

    @Override
    public CMISDocumentInfo getDocumentInfo() {
        return this;
    }

    @Override
    public CMISItemInfo geItemInfo() {
        return null;
    }

    @Override
    public CMISRelationshipInfo getRelationshipInfo() {
        return null;
    }

    @Override
    public CMISPolicyInfo getPolicyInfo() {
        return null;
    }

    @Override
    public CMISSecondaryInfo getSecondaryInfo() {
        return null;
    }

    @Override
    public String getParentId() {
        return getProperty(FileBase.parentId);
    }

    @Override
    public AllowableActions getAllowableActions() {
        return new StructrFileActions(isImmutable());
    }

    @Override
    public String getChangeToken() {

        // versioning not supported yet.
        return null;
    }

    @Override
    public boolean isImmutable() {

        final Principal _owner = getOwnerNode();
        if (_owner != null) {

            return !_owner.isGranted(Permission.write, securityContext);
        }

        return true;
    }
}