Java tutorial
/*! * 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"); } }