org.pentaho.reporting.libraries.pensol.JCRSolutionDirectFileModel.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.reporting.libraries.pensol.JCRSolutionDirectFileModel.java

Source

/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 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 Lesser General Public License for more details.
*
* Copyright (c) 2002-2017 Hitachi Vantara..  All rights reserved.
*/

package org.pentaho.reporting.libraries.pensol;

import com.sun.jersey.core.header.FormDataContentDisposition;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs2.FileName;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.http.HttpStatus;
import org.pentaho.platform.repository2.unified.webservices.RepositoryFileDto;
import org.pentaho.platform.repository2.unified.webservices.RepositoryFileTreeDto;
import org.pentaho.platform.web.http.api.resources.DirectoryResource;
import org.pentaho.platform.web.http.api.resources.FileResource;
import org.pentaho.platform.web.http.api.resources.RepositoryImportResource;
import org.pentaho.reporting.libraries.base.util.FastStack;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @author Marco Vala
 */
public class JCRSolutionDirectFileModel implements SolutionFileModel {
    private static final Log logger = LogFactory.getLog(JCRSolutionDirectFileModel.class);

    private static final String SLASH = "/";
    private static final String COLON = ":";
    private static final String DO_GET_ROOT_CHILDREN = "doGetRootChildren";
    private static final String DO_GET_FILE_OR_DIR_AS_DOWNLOAD = "doGetFileOrDirAsDownload";
    private static final String FAILED_TO_ACCESS_REPOSITORY = "Failed to access repository";
    private static final String FILE_NOT_FOUND = "File does not exist: {0}";
    private static final String FAILED_TO_WRITE_FILE = "Failed to write file: {0}";
    private static final String NULL_OBJECT = "Repository returned <null> for file: {0}";
    private static final String NULL_MODIFIED_DATE = "Repository returned <null> for last-modified-date on file: ";
    private static final String INVALID_USERNAME_OR_PASSWORD = "Invalid username or password";
    private static final String BAD_RESPONSE = "Failed with error-code: {0}";
    private static final String NOT_SUPPORTED = "Operation not supported: {0}";

    private RepositoryFileTreeDto root;
    private FileResource fileRes;
    private DirectoryResource dirRes;
    private RepositoryImportResource importRes;
    private Method doGetRootChildrenMethod;
    private Method doGetFileOrDirAsDownloadMethod;

    public JCRSolutionDirectFileModel() {
        this.fileRes = new FileResource();
        this.dirRes = new DirectoryResource();
        this.importRes = new RepositoryImportResource();

        // check if [5.0-SNAPSHOT] backports are needed
        try {
            /*
            [5.0-SNAPSHOT]
            /api/repo/files/children?depth=-1&filter=*&showHidden=true
            public RepositoryFileTreeDto doGetRootChildren(
              @QueryParam("depth") Integer depth,
              @QueryParam("filter") String filter,
              @QueryParam("showHidden") Boolean showHidden )
            */
            this.doGetRootChildrenMethod = this.fileRes.getClass().getDeclaredMethod(DO_GET_ROOT_CHILDREN,
                    Integer.class, String.class, Boolean.class);
        } catch (NoSuchMethodException e) {
            this.doGetRootChildrenMethod = null;
        }
        try {
            /*
            [5.0-SNAPSHOT]
            /api/repo/files/{0}/download?withManifest=false
            public Response doGetFileOrDirAsDownload(
              @PathParam("pathId") String pathId,
              @QueryParam("withManifest") String strWithManifest )
            */
            this.doGetFileOrDirAsDownloadMethod = this.fileRes.getClass()
                    .getDeclaredMethod(DO_GET_FILE_OR_DIR_AS_DOWNLOAD, String.class, String.class);
        } catch (NoSuchMethodException e) {
            this.doGetFileOrDirAsDownloadMethod = null;
        }
    }

    ////
    //// Repository access
    ////

    private RepositoryFileTreeDto getFileTree() throws FileSystemException {
        /*
        /api/repo/files/tree?depth=-1&filter=*&showHidden=true
        public RepositoryFileTreeDto doGetRootTree(
          @QueryParam( "depth" ) Integer depth,
          @QueryParam( "filter" ) String filter,
          @QueryParam( "showHidden" ) Boolean showHidden,
          @DefaultValue( "false" ) @QueryParam( "includeAcls" ) Boolean includeAcls )
        */

        final int depth = -1;
        final String filter = "*";
        final boolean showHidden = true;

        RepositoryFileTreeDto fileTree = null;
        if (this.doGetRootChildrenMethod == null) {
            fileTree = this.fileRes.doGetRootTree(depth, filter, showHidden, false);
        } else {
            // apply [5.0-SNAPSHOT] backport
            try {
                fileTree = (RepositoryFileTreeDto) this.doGetRootChildrenMethod.invoke(this.fileRes, depth, filter,
                        showHidden);
            } catch (InvocationTargetException e) {
                throw new FileSystemException(FAILED_TO_ACCESS_REPOSITORY);
            } catch (IllegalAccessException e) {
                throw new FileSystemException(FAILED_TO_ACCESS_REPOSITORY);
            }
        }
        return fileTree;
    }

    private RepositoryFileTreeDto getTreeNode(FileName fullName) throws FileSystemException {
        if (this.root == null) {
            refresh();
        }
        return searchTreeNode(stackName(fullName), this.root);
    }

    private RepositoryFileTreeDto searchTreeNode(FastStack<String> fullName, RepositoryFileTreeDto treeNode) {
        // no more name parts to search, found file in subtree
        if (fullName.size() == 0) {
            return treeNode;
        }

        // search recursively for each name part in subtree
        final String fileOrDirName = fullName.peek();
        final List<RepositoryFileTreeDto> children = treeNode.getChildren();
        for (final RepositoryFileTreeDto child : children) {
            final String childName = child.getFile().getName();
            if (fileOrDirName.equals(childName)) {
                fullName.pop();
                return searchTreeNode(fullName, child);
            }
        }

        // didn't find file
        return null;
    }

    private FastStack<String> stackName(FileName fullName) {
        final FastStack<String> stack = new FastStack<String>();
        while (fullName != null) {
            final String name = fullName.getBaseName().trim();
            if (!name.equals("")) {
                stack.push(name);
            }
            fullName = fullName.getParent();
        }
        return stack;
    }

    private RepositoryFileDto getFile(FileName fullName) throws FileSystemException {
        final RepositoryFileTreeDto tree = getTreeNode(fullName);
        if (tree == null) {
            throw new FileSystemException(FILE_NOT_FOUND, fullName);
        }
        return tree.getFile();
    }

    private List<RepositoryFileTreeDto> getChildNodes(final FileName fullName) throws FileSystemException {
        final RepositoryFileTreeDto tree = getTreeNode(fullName);
        if (tree == null) {
            throw new FileSystemException(FILE_NOT_FOUND, fullName);
        }
        final List<RepositoryFileTreeDto> children = tree.getChildren();
        return children == null ? Collections.<RepositoryFileTreeDto>emptyList() : children;
    }

    private String pathToId(String path) {
        return path.replace(SLASH, COLON);
    }

    private void throwExceptionOnBadResponse(Response response) throws FileSystemException {
        final int status = response.getStatus();
        switch (status) {
        case HttpStatus.SC_OK:
            logger.debug("OK");
            // response OK => do not throw exception and continue execution
            break;

        case HttpStatus.SC_UNAUTHORIZED:
        case HttpStatus.SC_FORBIDDEN:
        case HttpStatus.SC_MOVED_TEMPORARILY:
            logger.debug("FORBIDDEN");
            throw new FileSystemException(INVALID_USERNAME_OR_PASSWORD);

        default:
            logger.debug("ERROR " + status);
            throw new FileSystemException(BAD_RESPONSE, status);
        }
    }

    ////
    //// SolutionFileModel implementation
    ////

    @Override
    public void refresh() throws FileSystemException {
        logger.debug("refresh");

        this.root = getFileTree();
    }

    @Override
    public String[] getChilds(final FileName fullName) throws FileSystemException {
        logger.debug("getChilds: " + fullName);

        final List<RepositoryFileTreeDto> children = getChildNodes(fullName);
        logger.debug("size = " + children.size());

        final String[] childrenArray = new String[children.size()];
        for (int i = 0; i < children.size(); i++) {
            final RepositoryFileTreeDto treeNode = children.get(i);
            if (treeNode != null) {
                final RepositoryFileDto file = treeNode.getFile();
                if (file != null) {
                    logger.debug("file " + file.getName());
                    childrenArray[i] = file.getName();
                } else {
                    throw new FileSystemException(NULL_OBJECT);
                }
            }
        }
        return childrenArray;
    }

    @Override
    public boolean exists(final FileName fullName) throws FileSystemException {
        return (getTreeNode(fullName) != null);
    }

    @Override
    public boolean isVisible(final FileName fullName) throws FileSystemException {
        return !getFile(fullName).isHidden();
    }

    @Override
    public boolean isDirectory(final FileName fullName) throws FileSystemException {
        return getFile(fullName).isFolder();
    }

    @Override
    public long getLastModifiedDate(final FileName fullName) throws FileSystemException {
        final Date lastModifiedDate = getFile(fullName).getLastModifiedDate();
        if (lastModifiedDate == null) {
            logger.error(NULL_MODIFIED_DATE + fullName);
            return -1;
        }
        return lastModifiedDate.getTime();
    }

    @Override
    public String getLocalizedName(final FileName fullName) throws FileSystemException {
        return getFile(fullName).getTitle();
    }

    @Override
    public void setDescription(final FileName fullName, final String description) throws FileSystemException {
        getFile(fullName).setDescription(description);
    }

    @Override
    public String getDescription(final FileName fullName) throws FileSystemException {
        return getFile(fullName).getDescription();
    }

    @Override
    public long getContentSize(final FileName fullName) throws FileSystemException {
        return getFile(fullName).getFileSize();
    }

    @Override
    public byte[] getData(final FileName fullName) throws FileSystemException {
        /*
        /api/repo/files/{0}/download?withManifest=false
        public Response doGetFileOrDirAsDownloadMethod(
          @PathParam("pathId") String pathId,
          @QueryParam("withManifest") String strWithManifest )
        */
        logger.debug("getData: " + fullName);

        try {
            final String fileId = pathToId(fullName.getPath());
            Response response = null;
            if (this.doGetFileOrDirAsDownloadMethod == null) {
                response = this.fileRes.doGetFileOrDirAsDownload("", fileId, "false");
            } else {
                // apply [5.0-SNAPSHOT] backport
                try {
                    response = (Response) this.doGetFileOrDirAsDownloadMethod.invoke(this.fileRes, fileId, "false");
                } catch (InvocationTargetException e) {
                    throw new FileSystemException(FAILED_TO_ACCESS_REPOSITORY);
                } catch (IllegalAccessException e) {
                    throw new FileSystemException(FAILED_TO_ACCESS_REPOSITORY);
                }
            }
            throwExceptionOnBadResponse(response);
            StreamingOutput output = (StreamingOutput) response.getEntity();
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            output.write(stream);
            return stream.toByteArray();
        } catch (FileNotFoundException e) {
            throw new FileSystemException(FILE_NOT_FOUND, fullName);
        } catch (IOException e) {
            throw new FileSystemException(FAILED_TO_WRITE_FILE, fullName);
        }
    }

    @Override
    public void setData(final FileName fullName, final byte[] data) throws FileSystemException {
        /*
        /api/repo/files/import
        public Response doPostImport(
          @FormDataParam("importDir") String uploadDir,
          @FormDataParam("fileUpload") InputStream fileIS,
          @FormDataParam("overwriteFile") String overwriteFile,
          @FormDataParam("overwriteAclPermissions") String overwriteAclPermissions,
          @FormDataParam("applyAclPermissions") String applyAclPermission,
          @FormDataParam("retainOwnership") String retainOwnership,
          @FormDataParam("charSet") String charSet,
          @FormDataParam("logLevel") String logLevel,
          @FormDataParam("fileUpload") FormDataContentDisposition fileInfo,
          @FormDataParam("fileNameOverried) String fileNameOveride )
        */
        logger.debug("setData: " + fullName);

        final String name = fullName.getBaseName();
        final String parent = fullName.getParent().getPath();
        final ByteArrayInputStream stream = new ByteArrayInputStream(data);
        final FormDataContentDisposition fd = FormDataContentDisposition.name(name).fileName(name).build();
        Response response = this.importRes.doPostImport(parent, stream, "true", null, "true", "true", null, "WARN",
                fd, null);
        throwExceptionOnBadResponse(response);
    }

    @Override
    public void createFolder(final FileName fullName) throws FileSystemException {
        /*
        /api/repo/dirs/{0}
        public Response createDirs(
          @PathParam( "pathId" ) String pathId )
        */
        logger.debug("createFolder: " + fullName);

        Response response = this.dirRes.createDirs(pathToId(fullName.getPath()));
        throwExceptionOnBadResponse(response);
        refresh();
    }

    @Override
    public boolean delete(final FileName fullName) throws FileSystemException {
        /*
        /api/repo/files/delete
        public Response doDeleteFiles(String params)
         */
        logger.debug("delete: " + fullName);

        Response response = fileRes.doDeleteFiles(getFile(fullName).getId());
        throwExceptionOnBadResponse(response);
        refresh();
        return true;
    }

    @Override
    public String getParamServiceUrl(FileName fullName) throws FileSystemException {
        throw new FileSystemException(NOT_SUPPORTED, "getParamServiceUrl");
    }

    @Override
    public String getUrl(FileName fullName) throws FileSystemException {
        throw new FileSystemException(NOT_SUPPORTED, "getUrl");
    }
}