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-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.web.http.api.resources; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.MediaType.APPLICATION_XML; import static javax.ws.rs.core.MediaType.TEXT_PLAIN; import static javax.ws.rs.core.MediaType.WILDCARD; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static javax.ws.rs.core.Response.Status.FORBIDDEN; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import static javax.ws.rs.core.Response.Status.NOT_FOUND; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.channels.IllegalSelectorException; import java.security.GeneralSecurityException; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.StreamingOutput; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.enunciate.Facet; import org.codehaus.enunciate.jaxrs.ResponseCode; import org.codehaus.enunciate.jaxrs.StatusCodes; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.pentaho.platform.api.engine.IAuthorizationPolicy; import org.pentaho.platform.api.engine.IContentGenerator; import org.pentaho.platform.api.engine.IParameterProvider; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.engine.IPluginManager; import org.pentaho.platform.api.mimetype.IPlatformMimeResolver; import org.pentaho.platform.api.repository2.unified.Converter; import org.pentaho.platform.api.repository2.unified.IRepositoryContentConverterHandler; import org.pentaho.platform.api.repository2.unified.IRepositoryVersionManager; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.engine.core.output.SimpleOutputHandler; import org.pentaho.platform.engine.core.solution.SimpleParameterProvider; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.plugin.services.importexport.Exporter; import org.pentaho.platform.repository.RepositoryDownloadWhitelist; import org.pentaho.platform.repository2.unified.webservices.DefaultUnifiedRepositoryWebService; import org.pentaho.platform.repository2.unified.webservices.FileVersioningConfiguration; import org.pentaho.platform.repository2.unified.webservices.LocaleMapDto; import org.pentaho.platform.repository2.unified.webservices.RepositoryFileAclDto; import org.pentaho.platform.repository2.unified.webservices.RepositoryFileDto; import org.pentaho.platform.repository2.unified.webservices.RepositoryFileTreeDto; import org.pentaho.platform.repository2.unified.webservices.StringKeyStringValueDto; import org.pentaho.platform.security.policy.rolebased.actions.PublishAction; import org.pentaho.platform.web.http.api.resources.services.FileService; import org.pentaho.platform.web.http.api.resources.utils.FileUtils; import org.pentaho.platform.web.http.messages.Messages; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; /** * This service provides methods for listing, creating, downloading, uploading, and removal of files. * * @author aaron */ @Path("/repo/files/") public class FileResource extends AbstractJaxRSResource { public static final String PATH_SEPARATOR = "/"; //$NON-NLS-1$ public static final String APPLICATION_ZIP = "application/zip"; //$NON-NLS-1$ protected static final Log logger = LogFactory.getLog(FileResource.class); protected FileService fileService; protected SchedulerResource schedulerResource; protected RepositoryDownloadWhitelist whitelist; protected static IUnifiedRepository repository; protected static DefaultUnifiedRepositoryWebService repoWs; protected static IAuthorizationPolicy policy; IRepositoryContentConverterHandler converterHandler; Map<String, Converter> converters; protected IPlatformMimeResolver mimeResolver; public FileResource() { fileService = new FileService(); schedulerResource = new SchedulerResource(); } public FileResource(HttpServletResponse httpServletResponse) { this(); this.httpServletResponse = httpServletResponse; } public static String idToPath(String pathId) { return FileUtils.idToPath(pathId); } /** * Move a list of files to the user's trash folder. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/delete * </p> * * @param params Comma separated list of the files to be moved to trash folder. * * @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT @Path("/delete") @Consumes({ WILDCARD }) @Facet(name = "Unsupported") @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully moved file to trash."), @ResponseCode(code = 500, condition = "Failure move the file to the trash.") }) public Response doDeleteFiles(String params) { try { fileService.doDeleteFiles(params); return buildOkResponse(); } catch (Throwable t) { return buildServerErrorResponse(t); } } /** * Permanently deletes the selected list of files from the repository. * * @param params Comma separated list of the files to be deleted. * * @return Server Response indicating the success of the operation. */ @PUT @Path("/deletepermanent") @Consumes({ WILDCARD }) @Facet(name = "Unsupported") @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully deleted the comma seperated list of fileIds from the system."), @ResponseCode(code = 403, condition = "Failure to delete the file due to path not found.") }) public Response doDeleteFilesPermanent(String params) { try { fileService.doDeleteFilesPermanent(params); return buildOkResponse(); } catch (Throwable t) { t.printStackTrace(); return buildServerErrorResponse(t); } } /** * Moves a list of files from its current location to another. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/{pathId}/move * </p> * * @param destPathId Colon separated path for the destination path. * @param params Comma separated list of files to be moved. * * @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT @Path("{pathId : .+}/move") @Consumes({ WILDCARD }) @Facet(name = "Unsupported") @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully moved the file."), @ResponseCode(code = 403, condition = "Failure to move the file due to path not found."), @ResponseCode(code = 500, condition = "Failure to move the file.") }) public Response doMove(@PathParam("pathId") String destPathId, String params) { try { fileService.doMoveFiles(destPathId, params); return buildOkResponse(); } catch (FileNotFoundException e) { logger.error(Messages.getInstance().getErrorString("FileResource.DESTINATION_PATH_UNKNOWN", destPathId), e); return buildStatusResponse(NOT_FOUND); } catch (Throwable t) { logger.error(Messages.getInstance().getString("SystemResource.FILE_MOVE_FAILED"), t); return buildStatusResponse(INTERNAL_SERVER_ERROR); } } /** * Restores a list of files from the user's trash folder to their previous locations. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/restore * </p> * * @param params comma separated list of file ids to be restored. * * @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT @Path("/restore") @Consumes({ WILDCARD }) @Facet(name = "Unsupported") @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully restored the file."), @ResponseCode(code = 403, condition = "Failure to Restore the file."), }) public Response doRestore(String params) { try { fileService.doRestoreFiles(params); return buildOkResponse(); } catch (InternalError e) { logger.error(Messages.getInstance().getString("FileResource.FILE_GET_LOCALES"), e); return buildStatusResponse(INTERNAL_SERVER_ERROR); } } /** * Creates a new file with the provided contents at a given path. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml * <br /><b>PUT data:</b> * <pre function="syntax.xml"> * This PUT body does not contain data. * </pre> * </p> * * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * @param fileContents An Input Stream with the contents of the file to be created. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * This response does not contain data. * </pre> */ @PUT @Path("{pathId : .+}") @Consumes({ WILDCARD }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully created the file."), @ResponseCode(code = 403, condition = "Failure to create the file due to permissions, file already exists, or invalid path id.") }) public Response createFile(@PathParam("pathId") String pathId, InputStream fileContents) { try { fileService.createFile(httpServletRequest.getCharacterEncoding(), pathId, fileContents); return buildOkResponse(); } catch (Throwable t) { return buildServerErrorResponse(t); } } /** * Copy selected list of files to a new specified location. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/{pathId}/children?mode=2 * </p> * * @param pathId Colon separated path for the destination for files to be copied. * @param mode Default is RENAME (2) which adds a number to the end of the file name. MODE_OVERWRITE (1) will just replace existing * or MODE_NO_OVERWRITE (3) will not copy if file exist. * @param params Comma separated list of file ids to be copied. * * @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT @Path("{pathId : .+}/children") @Consumes({ TEXT_PLAIN }) @Facet(name = "Unsupported") @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully copied the file."), @ResponseCode(code = 500, condition = "Failure to Copy file due to exception while getting file with id fileid..."), }) public Response doCopyFiles(@PathParam("pathId") String pathId, @QueryParam("mode") Integer mode, String params) { try { fileService.doCopyFiles(pathId, mode, params); } catch (IllegalArgumentException e) { return buildStatusResponse(FORBIDDEN); } catch (Exception e) { logger.error(Messages.getInstance().getString("SystemResource.GENERAL_ERROR"), e); return buildSafeHtmlServerErrorResponse(e); } return buildOkResponse(); } /** * Takes a pathId and returns a Response with the output stream based on the file located at the pathId. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml * </p> * * @param pathId Colon separated path for the repository file. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * This response does not contain data. * </pre> */ @GET @Path("{pathId : .+}") @Produces({ WILDCARD }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully get the file or directory."), @ResponseCode(code = 404, condition = "Failed to find the file or resource."), @ResponseCode(code = 500, condition = "Failed to open content.") }) public Response doGetFileOrDir(@PathParam("pathId") String pathId) { try { FileService.RepositoryFileToStreamWrapper wrapper = fileService.doGetFileOrDir(pathId); return buildOkResponse(wrapper); } catch (FileNotFoundException fileNotFound) { return buildStatusResponse(NOT_FOUND); } catch (IllegalArgumentException illegalArgument) { return buildStatusResponse(FORBIDDEN); } } // Overloaded this method to try and minimize calls to the repo // Had to unmap this method since browsers ask for resources with Accepts="*/*" which will default to this method // @GET // @Path("{pathId : .+}") // @Produces({ APPLICATION_ZIP }) public Response doGetDirAsZip(@PathParam("pathId") String pathId) { String path = fileService.idToPath(pathId); if (!isPathValid(path)) { return buildStatusResponse(FORBIDDEN); } // you have to have PublishAction in order to get dir as zip if (!getPolicy().isAllowed(PublishAction.NAME)) { return buildStatusResponse(FORBIDDEN); } RepositoryFile repoFile = getRepository().getFile(path); if (repoFile == null) { // file does not exist or is not readable but we can't tell at this point return buildStatusResponse(NOT_FOUND); } return doGetDirAsZip(repoFile); } /** * @param repositoryFile * @return */ public Response doGetDirAsZip(RepositoryFile repositoryFile) { String path = repositoryFile.getPath(); final InputStream is; try { Exporter exporter = getExporter(); exporter.setRepoPath(path); exporter.setRepoWs(repoWs); File zipFile = exporter.doExportAsZip(repositoryFile); is = getFileInputStream(zipFile); } catch (Exception e) { return buildServerErrorResponse(e.toString()); } StreamingOutput streamingOutput = getStreamingOutput(is); return buildOkResponse(streamingOutput, APPLICATION_ZIP); } /** * Determines whether a selected file supports parameters or not * * @param pathId Colon separated path for the repository file. * * @return ("true" or "false") * @throws FileNotFoundException */ @GET @Path("{pathId : .+}/parameterizable") @Produces(TEXT_PLAIN) @Facet(name = "Unsupported") @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully get the file or directory."), @ResponseCode(code = 404, condition = "Failed to find the file or resource.") }) // have to accept anything for browsers to work public String doIsParameterizable(@PathParam("pathId") String pathId) throws FileNotFoundException { boolean hasParameterUi = false; RepositoryFile repositoryFile = getRepository().getFile(fileService.idToPath(pathId)); if (repositoryFile != null) { try { hasParameterUi = hasParameterUi(repositoryFile); } catch (NoSuchBeanDefinitionException e) { // Do nothing. } } boolean hasParameters = false; if (hasParameterUi) { try { IContentGenerator parameterContentGenerator = getContentGenerator(repositoryFile); if (parameterContentGenerator != null) { ByteArrayOutputStream outputStream = getByteArrayOutputStream(); parameterContentGenerator.setOutputHandler(new SimpleOutputHandler(outputStream, false)); parameterContentGenerator.setMessagesList(new ArrayList<String>()); Map<String, IParameterProvider> parameterProviders = new HashMap<String, IParameterProvider>(); SimpleParameterProvider parameterProvider = getSimpleParameterProvider(); parameterProvider.setParameter("path", encode(repositoryFile.getPath())); parameterProvider.setParameter("renderMode", "PARAMETER"); parameterProviders.put(IParameterProvider.SCOPE_REQUEST, parameterProvider); parameterContentGenerator.setParameterProviders(parameterProviders); parameterContentGenerator.setSession(getSession()); parameterContentGenerator.createContent(); if (outputStream.size() > 0) { Document document = parseText(outputStream.toString()); // exclude all parameters that are of type "system", xactions set system params that have to be ignored. @SuppressWarnings("rawtypes") List nodes = document.selectNodes("parameters/parameter"); for (int i = 0; i < nodes.size() && !hasParameters; i++) { Element elem = (Element) nodes.get(i); if (elem.attributeValue("name").equalsIgnoreCase("output-target") && elem.attributeValue("is-mandatory").equalsIgnoreCase("true")) { hasParameters = true; continue; } Element attrib = (Element) elem .selectSingleNode("attribute[@namespace='http://reporting.pentaho" + ".org/namespaces/engine/parameter-attributes/core' and @name='role']"); if (attrib == null || !"system".equals(attrib.attributeValue("value"))) { hasParameters = true; } } } } } catch (Exception e) { logger.error(getMessagesInstance().getString("FileResource.PARAM_FAILURE", e.getMessage()), e); } } return Boolean.toString(hasParameters); } /** * Download the selected file or folder from the repository. In order to download file from the repository, the user needs to * have Publish action. How the file comes down to the user and where it is saved is system and browser dependent. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/download?locale=de * </p> * * @param pathId Colon separated path for the repository file. * @param strWithManifest true or false (download file with manifest). Defaults to true (include manifest) if this string can't be directly * parsed to 'false' (case sensitive). This argument is only used if a directory is being downloaded. * @param userAgent A string representing the type of browser to use. Currently only applicable if contains 'FireFox' as FireFox * requires a header with encoding information (UTF-8) and a quoted filename, otherwise encoding information is not * supplied and the filename is not quoted. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * Encrypted file stream * </pre> */ @GET @Path("{pathId : .+}/download") @Produces(WILDCARD) @StatusCodes({ @ResponseCode(code = 200, condition = "Successful download."), @ResponseCode(code = 400, condition = "Usually a bad pathId."), @ResponseCode(code = 403, condition = "pathId points at a file the user doesn't have access to."), @ResponseCode(code = 404, condition = "File not found."), @ResponseCode(code = 500, condition = "Failed to download file for another reason.") }) // have to accept anything for browsers to work public Response doGetFileOrDirAsDownload(@HeaderParam("user-agent") String userAgent, @PathParam("pathId") String pathId, @QueryParam("withManifest") String strWithManifest) { FileService.DownloadFileWrapper wrapper = null; try { wrapper = fileService.doGetFileOrDirAsDownload(userAgent, pathId, strWithManifest); return buildZipOkResponse(wrapper); } catch (InvalidParameterException e) { logger.error(getMessagesInstance().getString("FileResource.EXPORT_FAILED", e.getMessage()), e); return buildStatusResponse(BAD_REQUEST); } catch (IllegalSelectorException e) { logger.error(getMessagesInstance().getString("FileResource.EXPORT_FAILED", e.getMessage()), e); return buildStatusResponse(FORBIDDEN); } catch (GeneralSecurityException e) { logger.error(getMessagesInstance().getString("FileResource.EXPORT_FAILED", e.getMessage()), e); return buildStatusResponse(FORBIDDEN); } catch (FileNotFoundException e) { logger.error(getMessagesInstance().getString("FileResource.EXPORT_FAILED", e.getMessage()), e); return buildStatusResponse(NOT_FOUND); } catch (Throwable e) { logger.error( getMessagesInstance().getString("FileResource.EXPORT_FAILED", pathId + " " + e.getMessage()), e); return buildStatusResponse(INTERNAL_SERVER_ERROR); } } /** * Retrieves the file from the repository as inline. This is mainly used for css and dependent files for the html * document. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/inline * </p> * * @param pathId Colon separated path for the repository file. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <?xml version="1.0" encoding="UTF-8" standalone="yes"?><repositoryFileAclDto><entriesInheriting>true</entriesInheriting><id>d45d4972-989e-48d5-8bd0-f7024a77f08f</id><owner>admin</owner><ownerType>0</ownerType></repositoryFileAclDto> * </pre> */ @GET @Path("{pathId : .+}/inline") @Produces(WILDCARD) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved file."), @ResponseCode(code = 403, condition = "Failed to retrieve file due to permission problem."), @ResponseCode(code = 404, condition = "Failed to retrieve file due because file was not found."), @ResponseCode(code = 500, condition = "Failed to download file because of some other error.") }) public Response doGetFileAsInline(@PathParam("pathId") String pathId) { try { FileService.RepositoryFileToStreamWrapper wrapper = fileService.doGetFileAsInline(pathId); return buildOkResponse(wrapper); } catch (IllegalArgumentException e) { logger.error(getMessagesInstance().getString("SystemResource.GENERAL_ERROR"), e); return buildStatusResponse(FORBIDDEN); } catch (FileNotFoundException e) { logger.error(getMessagesInstance().getString("SystemResource.GENERAL_ERROR"), e); return buildStatusResponse(NOT_FOUND); } catch (InternalError e) { logger.error(getMessagesInstance().getString("SystemResource.GENERAL_ERROR"), e); return buildStatusResponse(INTERNAL_SERVER_ERROR); } } /** * This method is used to update and save the acls of the selected file to the repository. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/acl * <br /><b>PUT data:</b> * <pre function="syntax.xml"> * <?xml version="1.0" encoding="UTF-8" standalone="yes"?><repositoryFileAclDto><entriesInheriting>true</entriesInheriting><id>d45d4972-989e-48d5-8bd0-f7024a77f08f</id><owner>admin</owner><ownerType>0</ownerType></repositoryFileAclDto> * </pre> * </p> * * @param pathId Colon separated path for the repository file. * @param acl Acl of the repository file RepositoryFileAclDto. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * This response does not contain data. * </pre> */ @PUT @Path("{pathId : .+}/acl") @Consumes({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully saved file."), @ResponseCode(code = 403, condition = "Failed to save acls due to missing or incorrect properties."), @ResponseCode(code = 400, condition = "Failed to save acls due to malformed xml."), @ResponseCode(code = 500, condition = "Failed to save acls due to another error.") }) public Response setFileAcls(@PathParam("pathId") String pathId, RepositoryFileAclDto acl) { try { fileService.setFileAcls(pathId, acl); return buildOkResponse(); } catch (Exception exception) { logger.error(getMessagesInstance().getString("SystemResource.GENERAL_ERROR"), exception); return buildStatusResponse(INTERNAL_SERVER_ERROR); } } /** * Store content creator for the given path of created content. * * @param pathId colon separated path for the repository file that was created by the contenCreator below * <pre function="syntax.xml"> * :path:to:file:id * </pre> * @param contentCreator Repository file that created the file at the above pathId location * <pre function="syntax.xml"> * <repositoryFileDto> * <createdDate>1402911997019</createdDate> * <fileSize>3461</fileSize> * <folder>false</folder> * <hidden>false</hidden> * <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id> * <lastModifiedDate>1406647160536</lastModifiedDate> * <locale>en</locale> * <localePropertiesMapEntries> * <localeMapDto> * <locale>default</locale> * <properties> * <stringKeyStringValueDto> * <key>file.title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>jcr:primaryType</key> * <value>nt:unstructured</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>file.description</key> * <value>myFile Description</value> * </stringKeyStringValueDto> * </properties> * </localeMapDto> * </localePropertiesMapEntries> * <locked>false</locked> * <name>myFile.prpt</name></name> * <originalParentFolderPath>/public/admin</originalParentFolderPath> * <ownerType>-1</ownerType> * <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path> * <title>myFile</title> * <versionId>1.9</versionId> * <versioned>true</versioned> * </repositoryFileAclDto> * </pre> * @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT @Path("{pathId : .+}/creator") @Consumes({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved file."), @ResponseCode(code = 500, condition = "Failed to download file because of some other error.") }) @Facet(name = "Unsupported") public Response doSetContentCreator(@PathParam("pathId") String pathId, RepositoryFileDto contentCreator) { try { fileService.doSetContentCreator(pathId, contentCreator); return buildOkResponse(); } catch (FileNotFoundException e) { logger.error(getMessagesInstance().getErrorString("FileResource.FILE_NOT_FOUND", pathId), e); return buildStatusResponse(NOT_FOUND); } catch (Throwable t) { logger.error(getMessagesInstance().getString("SystemResource.GENERAL_ERROR"), t); return buildStatusResponse(INTERNAL_SERVER_ERROR); } } /** * Retrieves the list of locale maps for the selected repository file. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/locales * </p> * * @param pathId Colon separated path for the repository file. * * @return List<LocaleMapDto> the list of locales. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <localePropertiesMapEntries> * <localeMapDto> * <locale>default</locale> * <properties> * <stringKeyStringValueDto> * <key>file.title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>jcr:primaryType</key> * <value>nt:unstructured</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>file.description</key> * <value>myFile Description</value> * </stringKeyStringValueDto> * </properties> * </localeMapDto> * </localePropertiesMapEntries> * </pre> */ @GET @Path("{pathId : .+}/locales") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved locale information."), @ResponseCode(code = 404, condition = "Failed to retrieve locales because the file was not found."), @ResponseCode(code = 500, condition = "Unable to retrieve locales due to some other error.") }) public List<LocaleMapDto> doGetFileLocales(@PathParam("pathId") String pathId) { List<LocaleMapDto> locales = new ArrayList<LocaleMapDto>(); try { locales = fileService.doGetFileLocales(pathId); } catch (FileNotFoundException e) { logger.error(getMessagesInstance().getErrorString("FileResource.FILE_NOT_FOUND", pathId), e); } catch (Throwable t) { logger.error(getMessagesInstance().getString("SystemResource.GENERAL_ERROR"), t); } return locales; } /** * Retrieve the list of locale properties for a given locale. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/localeProperties?locale=ja * </p> * * @param pathId Colon separated path for the repository file. * @param locale The specified locale. * * @return A list of locale properties. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <stringKeyStringValueDtoes> * <stringKeyStringValueDto> * <key>file.title</key> * <value>File Title</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>jcr:primaryType</key> * <value>nt:unstructured</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>title</key> * <value>File Title</value> * </stringKeyStringValueDto> * </stringKeyStringValueDtoes> * </pre> */ @GET @Path("{pathId : .+}/localeProperties") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved locale properties."), @ResponseCode(code = 500, condition = "Unable to retrieve locale properties due to some other error.") }) public List<StringKeyStringValueDto> doGetLocaleProperties(@PathParam("pathId") String pathId, @QueryParam("locale") String locale) { return fileService.doGetLocaleProperties(pathId, locale); } /** * Save list of locale properties for a given locale. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/localeProperties?locale=ja * <br /><b>PUT data:</b> * <pre function="syntax.xml"> * <?xml version="1.0" encoding="UTF-8" standalone="yes"?><stringKeyStringValueDtoes><stringKeyStringValueDto><key>file.title</key><value>チャート選択リスト</value></stringKeyStringValueDto><stringKeyStringValueDto><key>jcr:primaryType</key><value>nt:unstructured</value></stringKeyStringValueDto><stringKeyStringValueDto><key>file.description</key><value>複数のチャートタイプを表示します</value></stringKeyStringValueDto></stringKeyStringValueDtoes> * </pre> * </p> * * @param pathId Colon separated path for the repository file. * @param locale A string representation of the locale to set properties on. * @param properties The list of locale properties. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * This response does not contain data. * </pre> */ @PUT @Path("{pathId : .+}/localeProperties") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully updated locale properties."), @ResponseCode(code = 500, condition = "Unable to update locale properties due to some other error.") }) public Response doSetLocaleProperties(@PathParam("pathId") String pathId, @QueryParam("locale") String locale, List<StringKeyStringValueDto> properties) { try { fileService.doSetLocaleProperties(pathId, locale, properties); return Response.ok().build(); } catch (Throwable t) { return Response.serverError().entity(t.getMessage()).build(); } } /** * Delete the locale for the selected file. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/deleteLocale?locale=ja * <br /><b>PUT data:</b> * <pre function="syntax.xml"> * This PUT body does not contain data. * </pre> * </p> * * @param pathId Colon separated path for the repository file. * @param locale A string representations of the locale to be deleted. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * This response does not contain data. * </pre> */ @PUT @Path("{pathId : .+}/deleteLocale") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully deleted the locale."), @ResponseCode(code = 500, condition = "Unable to delete the locale properties due to some other error.") }) public Response doDeleteLocale(@PathParam("pathId") String pathId, @QueryParam("locale") String locale) { try { fileService.doDeleteLocale(pathId, locale); return buildOkResponse(); } catch (Throwable t) { return buildServerErrorResponse(t); } } /** * Retrieves the properties of the root directory. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/properties * </p> * * @return file properties object RepositoryFileDto for the root directory. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <repositoryFileDto> * <createdDate>1406731649407</createdDate> * <fileSize>-1</fileSize> * <folder>true</folder> * <hidden>false</hidden> * <id>6d93372c-4908-47af-9815-3aa6307e392c</id> * <locale>en</locale> * <locked>false</locked> * <name/> * <ownerType>-1</ownerType> * <path>/</path> * <title/> * <versioned>false</versioned> * </repositoryFileDto> * </pre> */ @GET @Path("/properties") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the properties of the root directory."), @ResponseCode(code = 404, condition = "Unable to retrieve the properties of the root directory due to file not found error."), @ResponseCode(code = 500, condition = "Unable to retrieve the properties of the root directory due to some other error.") }) public RepositoryFileDto doGetRootProperties() { return fileService.doGetRootProperties(); } /** * Checks whether the current user has permissions to the selected files. This can check for more than one permission at once * but will only return true if all permissions checked are valid. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.txt/canAccessMap?permissions=1 * </p> * * @param pathId Colon separated path for the repository file. * @param permissions Pipe separated permissions to be checked. * * @return List of permissions for the selected files. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * {"setting":[{"name":"1","value":"true"}]} * </pre> */ @GET @Path("{pathId : .+}/canAccessMap") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the permissions of the file."), @ResponseCode(code = 500, condition = "Unable to retrieve the permissions of the file due to some other error.") }) public List<Setting> doGetCanAccessList(@PathParam("pathId") String pathId, @QueryParam("permissions") String permissions) { return fileService.doGetCanAccessList(pathId, permissions); } /** * Checks whether the current user has permissions to the provided list of paths. * * <p><b>Example Request:</b><br /> * POST pentaho/api/repo/files/pathsAccessList * <br /><b>POST data:</b> * <pre function="syntax.xml"> * <?xml version="1.0" encoding="UTF-8"?> * <stringListWrapper> * <strings>/public</strings> * </stringListWrapper> * </pre> * </p> * * @param pathsWrapper Collection of Strings containing the paths to be checked. * * @return A collection of the permission settings for the paths. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <settings> * <setting> * <name> * /public * </name> * <value> * 0 * </value> * </setting> * <setting> * <name> * /public * </name> * <value> * 1 * </value> * </setting> * </settings> * </pre> */ @POST @Path("/pathsAccessList") @Consumes({ APPLICATION_XML, APPLICATION_JSON }) @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the permissions of the given paths."), @ResponseCode(code = 500, condition = "Unable to retrieve the permissions of the given paths due to some other error.") }) public List<Setting> doGetPathsAccessList(StringListWrapper pathsWrapper) { return fileService.doGetPathsAccessList(pathsWrapper); } /** * Check whether the current user has specific permission on the selected repository file. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/canAccess?permissions=1 * </p> * * @param pathId Colon separated path for the repository file. * @param permissions Pipe separated list of permissions. * * @return String "true" if the user has requested permissions on the file, or "false" otherwise. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * true * </pre> */ @GET @Path("{pathId : .+}/canAccess") @Produces(TEXT_PLAIN) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the permissions of the given paths."), @ResponseCode(code = 500, condition = "Unable to retrieve the permissions of the given paths due to some other error.") }) public String doGetCanAccess(@PathParam("pathId") String pathId, @QueryParam("permissions") String permissions) { return fileService.doGetCanAccess(pathId, permissions); } /** * Checks to see if the current user is an administer of the platform and returns a boolean response. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/canAdminister * </p> * * @return String "true" if the user can administer the platform, or "false" otherwise. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * true * </pre> */ @GET @Path("/canAdminister") @Produces(TEXT_PLAIN) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully returns a boolean value, either true or false") }) public String doGetCanAdminister() { try { return fileService.doCanAdminister() ? "true" : "false"; } catch (Exception e) { return "false"; } } /** * Returns the list of reserved characters from the repository. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/reservedCharacters * </p> * * @return List of characters that are reserved by the repository. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * "/ \" * </pre> */ @GET @Path("/reservedCharacters") @Produces({ TEXT_PLAIN }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully returns a list of repositroy reserved characters") }) public Response doGetReservedChars() { StringBuffer buffer = fileService.doGetReservedChars(); return buildPlainTextOkResponse(buffer.toString()); } /** * Returns the list of reserved characters from the repository. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/reservedCharactersDisplay * </p> * * @return List of characters that are reserved by the repository. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * "/, \, \t, \r, \nF" * </pre> */ @GET @Path("/reservedCharactersDisplay") @Produces({ TEXT_PLAIN }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully returns a list of repositroy reserved characters") }) public Response doGetReservedCharactersDisplay() { StringBuffer buffer = fileService.doGetReservedCharactersDisplay(); return buildPlainTextOkResponse(buffer.toString()); } /** * Checks the users permission to determine if that user can create new content in the repository. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/canCreate * </p> * * @return String "true" if the user can create new content, or "false" otherwise. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * true * </pre> */ @GET @Path("/canCreate") @Produces(TEXT_PLAIN) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully returns true or false depending on the users permissions") }) public String doGetCanCreate() { return fileService.doGetCanCreate(); } /** * Retrieves the ACL settings of the requested repository file in either xml or json format. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/acl * </p> * * @param pathId colon separated path for the repository file. * * @return RepositoryFileAclDto object containing the ACL settings of the requested file. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <repositoryFileAclDto> * <aces> * <modifiable>true</modifiable> * <permissions>4</permissions> * <recipient>admin</recipient> * <recipientType>0</recipientType> * </aces> * <aces> * <modifiable>false</modifiable> * <permissions>4</permissions> * <recipient>Administrator</recipient> * <recipientType>1</recipientType> * </aces> * <entriesInheriting>true</entriesInheriting> * <id>068390ba-f90d-46e3-8c55-bbe55e24b2fe</id> * <owner>admin</owner> * <ownerType>0</ownerType> * </repositoryFileAclDto> * </pre> */ @GET @Path("{pathId : .+}/acl") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Returns the requested file permissions in xml or json format"), @ResponseCode(code = 500, condition = "File failed to be retrieved. This could be caused by an invalid path, or the file does not exist.") }) public RepositoryFileAclDto doGetFileAcl(@PathParam("pathId") String pathId) { return fileService.doGetFileAcl(pathId); } /** * Retrieves the properties of a selected repository file. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:/properties * </p> * * @param pathId Colon separated path for the repository file. * * @return A RepositoryDto object containing the properties for the given file. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * { * "createdDate":"1406732545857", * "description":"description", * "fileSize":"1234", * "folder":"false", * "hidden":"false", * "id":"fileId", * "lastModifiedDate":"1406732545858", * "locale":"en", * "localePropertiesMapEntries":[ * { * "locale":"default", * "properties":[ * {"key":"file.title","value":"afile"}, * {"key":"description","value":"afile.prpti"}, * {"key":"jcr:primaryType","value":"nt:unstructured"}, * {"key":"title","value":"afile"}, * {"key":"file.description","value":"afile.prpti"} * ] * } * ], * "locked":"false", * "name":"filename", * "ownerType":"-1","path":"pathToFile:filename", * "title":"title","versioned":"false" * } * </pre> */ @GET @Path("{pathId : .+}/properties") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the properties for a file."), @ResponseCode(code = 204, condition = "Invalid file path.") }) public RepositoryFileDto doGetProperties(@PathParam("pathId") String pathId) { try { return fileService.doGetProperties(pathId); } catch (FileNotFoundException fileNotFound) { logger.error(getMessagesInstance().getString("SystemResource.GENERAL_ERROR"), fileNotFound); //TODO: What do we return in this error case? return null; } } /** * Retrieves the file by creator id * * @param pathId Colon separated path for the destination for files to be copied. * * @return file properties object RepositoryFileDto */ @GET @Path("{pathId : .+}/creator") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @Facet(name = "Unsupported") @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the content creator for a file."), @ResponseCode(code = 403, condition = "Failure to move the file due to path not found.") }) public RepositoryFileDto doGetContentCreator(@PathParam("pathId") String pathId) { try { return fileService.doGetContentCreator(pathId); } catch (Throwable t) { return null; } } /** * Retrieve the list of executed contents for a selected content from the repository. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/generatedContent?locale=de * </p> * * @param pathId Colon separated path for the destination for files to be copied. * * @return A list of RepositoryDto objects containing the executed contents for a selected content from the repository. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <List> * <repositoryFileDto> * <createdDate>1402911997019</createdDate> * <fileSize>3461</fileSize> * <folder>false</folder> * <hidden>false</hidden> * <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id> * <lastModifiedDate>1406647160536</lastModifiedDate> * <locale>en</locale> * <localePropertiesMapEntries> * <localeMapDto> * <locale>default</locale> * <properties> * <stringKeyStringValueDto> * <key>file.title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>jcr:primaryType</key> * <value>nt:unstructured</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>file.description</key> * <value>myFile Description</value> * </stringKeyStringValueDto> * </properties> * </localeMapDto> * </localePropertiesMapEntries> * <locked>false</locked> * <name>myFile.prpt</name></name> * <originalParentFolderPath>/public/admin</originalParentFolderPath> * <ownerType>-1</ownerType> * <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path> * <title>myFile</title> * <versionId>1.9</versionId> * <versioned>true</versioned> * </repositoryFileAclDto> * </List> * </pre> */ @GET @Path("{pathId : .+}/generatedContent") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the list of RepositoryFileDto objects."), @ResponseCode(code = 200, condition = "Empty list of RepositoryFileDto objects.") }) public List<RepositoryFileDto> doGetGeneratedContent(@PathParam("pathId") String pathId) { List<RepositoryFileDto> repositoryFileDtoList = new ArrayList<RepositoryFileDto>(); try { repositoryFileDtoList = fileService.doGetGeneratedContent(pathId); } catch (FileNotFoundException e) { //return the empty list } catch (Throwable t) { logger.error(getMessagesInstance().getString("FileResource.GENERATED_CONTENT_FAILED", pathId), t); } return repositoryFileDtoList; } /** * Retrieve the executed contents for a selected repository file and a given user. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/generatedContentForUser?user=admin * </p> * * @param pathId Colon separated path for the destination for files to be copied. * @param user The username for the generated content folder. * * @return A list of RepositoryDto objects containing the executed contents for a selected file from the repository. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <List> * <repositoryFileDto> * <createdDate>1402911997019</createdDate> * <fileSize>3461</fileSize> * <folder>false</folder> * <hidden>false</hidden> * <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id> * <lastModifiedDate>1406647160536</lastModifiedDate> * <locale>en</locale> * <localePropertiesMapEntries> * <localeMapDto> * <locale>default</locale> * <properties> * <stringKeyStringValueDto> * <key>file.title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>jcr:primaryType</key> * <value>nt:unstructured</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>file.description</key> * <value>myFile Description</value> * </stringKeyStringValueDto> * </properties> * </localeMapDto> * </localePropertiesMapEntries> * <locked>false</locked> * <name>myFile.prpt</name></name> * <originalParentFolderPath>/public/admin</originalParentFolderPath> * <ownerType>-1</ownerType> * <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path> * <title>myFile</title> * <versionId>1.9</versionId> * <versioned>true</versioned> * </repositoryFileAclDto> * </List> * </pre> */ @GET @Path("{pathId : .+}/generatedContentForUser") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the list of RepositoryFileDto objects."), @ResponseCode(code = 200, condition = "Empty list of RepositoryFileDto objects."), @ResponseCode(code = 500, condition = "Server Error.") }) public List<RepositoryFileDto> doGetGeneratedContentForUser(@PathParam("pathId") String pathId, @QueryParam("user") String user) { List<RepositoryFileDto> repositoryFileDtoList = new ArrayList<RepositoryFileDto>(); try { repositoryFileDtoList = fileService.doGetGeneratedContent(pathId, user); } catch (FileNotFoundException e) { //return the empty list } catch (Throwable t) { logger.error( getMessagesInstance().getString("FileResource.GENERATED_CONTENT_FOR_USER_FAILED", pathId, user), t); } return repositoryFileDtoList; } /** * Retrieve the recursive list of files from root of the repository based on the filters provided. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/tree?showHidden=false&filter=*|FILES&_=1389042244670 * </p> * * @param depth How many level should the search go. * @param filter Filter to be applied for search. The filter can be broken down into 3 parts; File types, Child Node * Filter, and Member Filters. Each part is separated with a pipe (|) character. * <p/> * File Types are represented by a word phrase. This phrase is recognized as a file type phrase and processed * accordingly. Valid File Type word phrases include "FILES", "FOLDERS", and "FILES_FOLDERS" and denote * whether to return files, folders, or both files and folders, respectively. * <p/> * The Child Node Filter is a list of allowed names of files separated by the pipe (|) character. Each file * name in the filter may be a full name or a partial name with one or more wildcard characters ("*"). The * filter does not apply to root node. * <p/> * The Member Filter portion of the filter parameter allows the caller to specify which properties of the * metadata to return. Member Filters start with "includeMembers=" or "excludeMembers=" followed by a list of * comma separated field names that are to be included in, or, excluded from, the list. Valid field names can * be found in org.pentaho.platform.repository2.unified.webservices#RepositoryFileAdapter. * Omission of a member filter will return all members. It is invalid to both and includeMembers= and an * excludeMembers= clause in the same service call. * @param showHidden Include or exclude hidden files from the file list. * * @return A RepositoryFileTreeDto object containing the files at the root of the repository. Will return files but not folders under the "/" folder. The fields returned will include the name, filesize, description, id and title. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <repositoryFileTreeDto> * <children> * <file> * <createdDate>1405356318621</createdDate> * <fileSize>-1</fileSize> * <folder>true</folder> * <hidden>false</hidden> * <id>fileId;/id> * <locale>en</locale> * <locked>false</locked> * <name>admin</name> * <ownerType>-1</ownerType> * <path>/path/to/dir</path> * <title>admin</title> * <versioned>false</versioned> * </file> * </children> * </repositoryFileTreeDto> * </pre> */ @GET @Path("/tree") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the list of files from root of the repository."), @ResponseCode(code = 404, condition = "Invalid parameters."), @ResponseCode(code = 500, condition = "Server Error.") }) public RepositoryFileTreeDto doGetRootTree(@QueryParam("depth") Integer depth, @QueryParam("filter") String filter, @QueryParam("showHidden") Boolean showHidden, @DefaultValue("false") @QueryParam("includeAcls") Boolean includeAcls) { return fileService.doGetTree(FileUtils.PATH_SEPARATOR, depth, filter, showHidden, includeAcls); } /** * Retrieve a list of child files from the root of the repository. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/children?showHidden=false&filter=*|FILES&_=1389042244670 * </p> * * @param filter Filter to be applied for search. The filter can be broken down into 3 parts; File types, Child Node * Filter, and Member Filters. Each part is separated with a pipe (|) character. * <p/> * File Types are represented by a word phrase. This phrase is recognized as a file type phrase and processed * accordingly. Valid File Type word phrases include "FILES", "FOLDERS", and "FILES_FOLDERS" and denote * whether to return files, folders, or both files and folders, respectively. * <p/> * The Child Node Filter is a list of allowed names of files separated by the pipe (|) character. Each file * name in the filter may be a full name or a partial name with one or more wildcard characters ("*"). The * filter does not apply to root node. * <p/> * The Member Filter portion of the filter parameter allows the caller to specify which properties of the * metadata to return. Member Filters start with "includeMembers=" or "excludeMembers=" followed by a list of * comma separated field names that are to be included in, or, excluded from, the list. Valid field names can * be found in org.pentaho.platform.repository2.unified.webservices#RepositoryFileAdapter. * Omission of a member filter will return all members. It is invalid to both and includeMembers= and an * excludeMembers= clause in the same service call. * @param showHidden Include or exclude hidden files from the file list. * @param includeAcls Include permission information about the file in the output. * * @return A RepositoryFileTreeDto object containing the files at the root of the repository. Will return files but not folders under the "/" folder. The fields returned will include the name, filesize, description, id and title. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <repositoryFileTreeDto> * <children> * <file> * <createdDate>1405356318621</createdDate> * <fileSize>-1</fileSize> * <folder>true</folder> * <hidden>false</hidden> * <id>fileId;/id> * <locale>en</locale> * <locked>false</locked> * <name>admin</name> * <ownerType>-1</ownerType> * <path>/path/to/dir</path> * <title>admin</title> * <versioned>false</versioned> * </file> * </children> * </repositoryFileTreeDto> * </pre> */ @GET @Path("/children") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the list of child files from root of the repository."), @ResponseCode(code = 500, condition = "Server Error.") }) public List<RepositoryFileDto> doGetRootChildren(@QueryParam("filter") String filter, @QueryParam("showHidden") Boolean showHidden, @DefaultValue("false") @QueryParam("includeAcls") Boolean includeAcls) { return fileService.doGetChildren(FileUtils.PATH_SEPARATOR, filter, showHidden, includeAcls); } /** * Retrieve the recursive list of children of the selected repository file. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:public/tree?showHidden=false&filter=*|FILES&_=1389042244670 * </p> * * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * @param depth How many level should the search go. * @param filter Filter to be applied for search. The filter can be broken down into 3 parts; File types, Child Node * Filter, and Member Filters. Each part is separated with a pipe (|) character. * <p/> * File Types are represented by a word phrase. This phrase is recognized as a file type phrase and processed * accordingly. Valid File Type word phrases include "FILES", "FOLDERS", and "FILES_FOLDERS" and denote * whether to return files, folders, or both files and folders, respectively. * <p/> * The Child Node Filter is a list of allowed names of files separated by the pipe (|) character. Each file * name in the filter may be a full name or a partial name with one or more wildcard characters ("*"). The * filter does not apply to root node. * <p/> * The Member Filter portion of the filter parameter allows the caller to specify which properties of the * metadata to return. Member Filters start with "includeMembers=" or "excludeMembers=" followed by a list of * comma separated field names that are to be included in, or, excluded from, the list. Valid field names can * be found in org.pentaho.platform.repository2.unified.webservices#RepositoryFileAdapter. * Omission of a member filter will return all members. It is invalid to both and includeMembers= and an * excludeMembers= clause in the same service call. * @param showHidden Include or exclude hidden files from the file list. * @param includeAcls Include permission information about the file in the output. * * @return A RepositoryFileTreeDto object containing the files at the root of the repository. Will return files but not folders under the "/" folder. The fields returned will include the name, filesize, description, id and title. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <repositoryFileTreeDto> * <children> * <file> * <createdDate>1405356318621</createdDate> * <fileSize>-1</fileSize> * <folder>true</folder> * <hidden>false</hidden> * <id>fileId;/id> * <locale>en</locale> * <locked>false</locked> * <name>admin</name> * <ownerType>-1</ownerType> * <path>/path/to/dir</path> * <title>admin</title> * <versioned>false</versioned> * </file> * </children> * </repositoryFileTreeDto> * </pre> */ @GET @Path("{pathId : .+}/tree") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the list of files from root of the repository."), @ResponseCode(code = 404, condition = "Invalid parameters."), @ResponseCode(code = 500, condition = "Server Error.") }) public RepositoryFileTreeDto doGetTree(@PathParam("pathId") String pathId, @QueryParam("depth") Integer depth, @QueryParam("filter") String filter, @QueryParam("showHidden") Boolean showHidden, @DefaultValue("false") @QueryParam("includeAcls") Boolean includeAcls) { return fileService.doGetTree(pathId, depth, filter, showHidden, includeAcls); } /** * Retrieve a list of child files from the selected repository path of the repository. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test/children * </p> * * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * @param filter Filter to be applied for search. The filter can be broken down into 3 parts; File types, Child Node * Filter, and Member Filters. Each part is separated with a pipe (|) character. * <p/> * File Types are represented by a word phrase. This phrase is recognized as a file type phrase and processed * accordingly. Valid File Type word phrases include "FILES", "FOLDERS", and "FILES_FOLDERS" and denote * whether to return files, folders, or both files and folders, respectively. * <p/> * The Child Node Filter is a list of allowed names of files separated by the pipe (|) character. Each file * name in the filter may be a full name or a partial name with one or more wildcard characters ("*"). The * filter does not apply to root node. * <p/> * The Member Filter portion of the filter parameter allows the caller to specify which properties of the * metadata to return. Member Filters start with "includeMembers=" or "excludeMembers=" followed by a list of * comma separated field names that are to be included in, or, excluded from, the list. Valid field names can * be found in org.pentaho.platform.repository2.unified.webservices#RepositoryFileAdapter. * Omission of a member filter will return all members. It is invalid to both and includeMembers= and an * excludeMembers= clause in the same service call. * @param showHidden Include or exclude hidden files from the file list. * @param includeAcls Include permission information about the file in the output. * * @return A RepositoryFileTreeDto object containing the files at the selected repository path of the repository. Will return files but not folders under the "/" folder. The fields returned will include the name, filesize, description, id and title. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <repositoryFileTreeDto> * <children> * <file> * <createdDate>1405356318621</createdDate> * <fileSize>-1</fileSize> * <folder>true</folder> * <hidden>false</hidden> * <id>fileId;/id> * <locale>en</locale> * <locked>false</locked> * <name>admin</name> * <ownerType>-1</ownerType> * <path>/path/to/dir</path> * <title>admin</title> * <versioned>false</versioned> * </file> * </children> * </repositoryFileTreeDto> * </pre> */ @GET @Path("{pathId : .+}/children") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the list of child files from selected repository path of the repository."), @ResponseCode(code = 500, condition = "Server Error.") }) public List<RepositoryFileDto> doGetChildren(@PathParam("pathId") String pathId, @QueryParam("filter") String filter, @QueryParam("showHidden") Boolean showHidden, @DefaultValue("false") @QueryParam("includeAcls") Boolean includeAcls) { return fileService.doGetChildren(pathId, filter, showHidden, includeAcls); } /** * Retrieve the list of files in the user's trash folder. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/deleted * </p> * * @return A list of RepositoryDto objects containing the files in the trash folder of the repository. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <repositoryFileDtoes> * <repositoryFileDto> * <createdDate>1405356406448</createdDate> * <deletedDate>1406573914167</deletedDate> * <fileSize>10477</fileSize> * <folder>false</folder> * <hidden>false</hidden> * <id>fileId</id> * <lastModifiedDate>1405356406448</lastModifiedDate> * <locale>en</locale> * <localePropertiesMapEntries> * <locale>default</locale> * <properties> * <key>file.title</key> * <value>File Title</value> * </properties> * <properties> * <key>jcr:primaryType</key> * <value>nt:unstructured</value> * </properties> * <properties> * <key>title</key> * <value>filename</value> * </properties> * <properties> * <key>file.description</key> * <value /> * </properties> * </localePropertiesMapEntries> * <locked>false</locked> * <name>filename.ext</name> * <originalParentFolderPath>/original/path/to/file</originalParentFolderPath> * <ownerType>-1</ownerType> * <path>/path/to/file</path> * <title>File Title</title> * <versionId>1.3</versionId> * <versioned>true</versioned> * </repositoryFileDto> * </repositoryFileDtoes> * </pre> */ @GET @Path("/deleted") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved the list of files from trash folder of the repository."), @ResponseCode(code = 500, condition = "Server Error.") }) public List<RepositoryFileDto> doGetDeletedFiles() { return fileService.doGetDeletedFiles(); } /** * Retrieve the metadata of the selected file. Even though the hidden flag is a property of the file node itself, and not * the metadata child, it is considered metadata from PUC and is included in the setMetadata call. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/metadata * </p> * * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <stringKeyStringValueDtos> * <stringKeyStringValueDto> * <key>KEY<key> * <value>KEY<value> * </stringKeyStringValueDto> * </stringKeyStringValueDtos> * </pre> */ @GET @Path("{pathId : .+}/metadata") @Produces({ APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved metadata."), @ResponseCode(code = 403, condition = "Invalid path."), @ResponseCode(code = 500, condition = "Server Error.") }) public List<StringKeyStringValueDto> doGetMetadata(@PathParam("pathId") String pathId) { try { return fileService.doGetMetadata(pathId); } catch (FileNotFoundException e) { logger.error(getMessagesInstance().getErrorString("FileResource.FILE_UNKNOWN", pathId), e); return null; } } /** * Rename the selected file. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/rename?newName=test_file_8 * <br /><b>PUT data:</b> * <pre function="syntax.xml"> * This PUT body does not contain data. * </pre> * </p> * * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * @param newName String indicating the new name of the file. * * @return Response with 200 OK, if the file does not exist to be renamed the response will return 200 OK with the string "File to be renamed does not exist". * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * This response does not contain data. * </pre> */ @PUT @Path("{pathId : .+}/rename") @Consumes({ WILDCARD }) @Produces({ WILDCARD }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully renamed file."), @ResponseCode(code = 200, condition = "File to be renamed does not exist.") }) public Response doRename(@PathParam("pathId") String pathId, @QueryParam("newName") String newName) { try { boolean success = fileService.doRename(pathId, newName); if (success) { return buildOkResponse(); } else { return buildOkResponse("File to be renamed does not exist"); } } catch (Throwable t) { return buildServerErrorResponse(t.getMessage()); } } /** * Store the metadata of the selected file. Even though the hidden flag is a property of the file node itself, and not * the metadata child, it is considered metadata from PUC and is included in the setMetadata call. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/metadata * <br /><b>PUT data:</b> * <pre function="syntax.xml"> * <?xml version="1.0" encoding="UTF-8" standalone="yes"?><stringKeyStringValueDtoes><stringKeyStringValueDto><key>metadata.key.1</key><value>metadata.value.1</value></stringKeyStringValueDto></stringKeyStringValueDtoes> * </pre> * </p> * * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * @param metadata A list of StringKeyStringValueDto objects. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * This response does not contain data. * </pre> */ @PUT @Path("{pathId : .+}/metadata") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully retrieved metadata."), @ResponseCode(code = 403, condition = "Invalid path."), @ResponseCode(code = 400, condition = "Invalid payload."), @ResponseCode(code = 500, condition = "Server Error.") }) public Response doSetMetadata(@PathParam("pathId") String pathId, List<StringKeyStringValueDto> metadata) { try { fileService.doSetMetadata(pathId, metadata); return buildOkResponse(); } catch (GeneralSecurityException e) { return buildStatusResponse(Response.Status.UNAUTHORIZED); } catch (Throwable t) { return buildServerErrorResponse(t.getMessage()); } } /** * Creates a new folder with the specified name. * * <p><b>Example Request:</b><br /> * PUT pentaho/api/repo/files/:public:jmeter-test-dir/createDir * <br /><b>PUT data:</b> * <pre function="syntax.xml"> * This PUT body does not contain data. * </pre> * </p> * * @param pathId The path from the root folder to the root node of the tree to return using colon characters in * place of / or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * * @return A jax-rs Response object with the appropriate status code, header, and body. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * This response does not contain data. * </pre> */ @PUT @Path("{pathId : .+}/createDir") @Consumes({ WILDCARD }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully created folder."), @ResponseCode(code = 409, condition = "Path already exists."), @ResponseCode(code = 500, condition = "Server Error.") }) public Response doCreateDirs(@PathParam("pathId") String pathId) { try { if (fileService.doCreateDir(pathId)) { return buildOkResponse(); } else { return Response.status(Response.Status.CONFLICT).entity("couldNotCreateFolderDuplicate").build(); } } catch (Throwable t) { return buildServerErrorResponse(t.getMessage()); } } /** * Retrieve the list of execute content by lineage id. * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/generatedContentForSchedule?lineageId= * </p> * * @param lineageId the path for the file. * * @return list of RepositoryFileDto objects. * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <List> * <repositoryFileDto> * <createdDate>1402911997019</createdDate> * <fileSize>3461</fileSize> * <folder>false</folder> * <hidden>false</hidden> * <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id> * <lastModifiedDate>1406647160536</lastModifiedDate> * <locale>en</locale> * <localePropertiesMapEntries> * <localeMapDto> * <locale>default</locale> * <properties> * <stringKeyStringValueDto> * <key>file.title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>jcr:primaryType</key> * <value>nt:unstructured</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>title</key> * <value>myFile</value> * </stringKeyStringValueDto> * <stringKeyStringValueDto> * <key>file.description</key> * <value>myFile Description</value> * </stringKeyStringValueDto> * </properties> * </localeMapDto> * </localePropertiesMapEntries> * <locked>false</locked> * <name>myFile.prpt</name></name> * <originalParentFolderPath>/public/admin</originalParentFolderPath> * <ownerType>-1</ownerType> * <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path> * <title>myFile</title> * <versionId>1.9</versionId> * <versioned>true</versioned> * </repositoryFileAclDto> * </List> * </pre> */ @GET @Path("/generatedContentForSchedule") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully got the generated content for schedule") }) public List<RepositoryFileDto> doGetGeneratedContentForSchedule(@QueryParam("lineageId") String lineageId) { return schedulerResource.doGetGeneratedContentForSchedule(lineageId); } /** * This method is used to determine whether versioning should be active for the given path * * <p><b>Example Request:</b><br /> * GET pentaho/api/repo/files/:jmeter-test:test_file_1.ktr/versioningConfiguration * </pre> * </p> * * @param pathId Colon separated path for the repository file. * * @return The Versioning Configuration applicable to the path submitted * * <p><b>Example Response:</b></p> * <pre function="syntax.xml"> * <fileVersioningConfiguration> * <versionCommentEnabled>true</versionCommentEnabled> * <versioningEnabled>true</versioningEnabled> * </fileVersioningConfiguration> * </pre> */ @GET @Path("{pathId : .+}/versioningConfiguration") @Produces({ APPLICATION_XML, APPLICATION_JSON }) @StatusCodes({ @ResponseCode(code = 200, condition = "Successfully returns the versioning configuation") }) public FileVersioningConfiguration doVersioningConfiguration(@PathParam("pathId") String pathId) { IRepositoryVersionManager repositoryVersionManager = PentahoSystem.get(IRepositoryVersionManager.class); return new FileVersioningConfiguration( repositoryVersionManager.isVersioningEnabled(FileUtils.idToPath(pathId)), repositoryVersionManager.isVersionCommentEnabled(FileUtils.idToPath(pathId))); } protected boolean isPathValid(String path) { return fileService.isPathValid(path); } public RepositoryDownloadWhitelist getWhitelist() { if (whitelist == null) { whitelist = new RepositoryDownloadWhitelist(); } return whitelist; } public void setWhitelist(RepositoryDownloadWhitelist whitelist) { this.whitelist = whitelist; } public static IAuthorizationPolicy getPolicy() { if (policy == null) { policy = PentahoSystem.get(IAuthorizationPolicy.class); } return policy; } public static IUnifiedRepository getRepository() { if (repository == null) { repository = PentahoSystem.get(IUnifiedRepository.class); } return repository; } public static DefaultUnifiedRepositoryWebService getRepoWs() { if (repoWs == null) { repoWs = new DefaultUnifiedRepositoryWebService(); } return repoWs; } public void setConverterHandler(IRepositoryContentConverterHandler converterHandler) { this.converterHandler = converterHandler; } public void setMimeResolver(IPlatformMimeResolver mimeResolver) { this.mimeResolver = mimeResolver; } protected Response buildOkResponse() { return Response.ok().build(); } protected Response buildOkResponse(String msg) { return Response.ok(msg).build(); } protected Response buildPlainTextOkResponse(String msg) { return Response.ok(msg, MediaType.TEXT_PLAIN).build(); } protected Response buildStatusResponse(Response.Status status) { return Response.status(status).build(); } protected Response buildServerErrorResponse(Throwable t) { return buildServerErrorResponse(t.getMessage()); } protected Response buildServerErrorResponse(String msg) { return Response.serverError().entity(msg).build(); } protected Response buildSafeHtmlServerErrorResponse(Exception e) { return Response.serverError() .entity(new SafeHtmlBuilder().appendEscapedLines(e.getLocalizedMessage()).toSafeHtml().asString()) .build(); } protected Response buildOkResponse(FileService.RepositoryFileToStreamWrapper wrapper) { Response.ResponseBuilder builder = Response.ok(wrapper.getOutputStream()); if (wrapper.getMimetype() != null) { builder = Response.ok(wrapper.getOutputStream(), wrapper.getMimetype()); } return builder .header("Content-Disposition", "inline; filename=\"" + wrapper.getRepositoryFile().getName() + "\"") .build(); } protected Response buildZipOkResponse(FileService.DownloadFileWrapper wrapper) { return Response.ok(wrapper.getOutputStream(), APPLICATION_ZIP + "; charset=UTF-8") .header("Content-Disposition", wrapper.getAttachment()).build(); } protected Response buildOkResponse(Object o, String s) { return Response.ok(o, s).build(); } protected Exporter getExporter() { return new Exporter(repository); } protected FileInputStream getFileInputStream(File file) throws FileNotFoundException { return new FileInputStream(file); } protected StreamingOutput getStreamingOutput(final InputStream is) { return new StreamingOutput() { public void write(OutputStream output) throws IOException { IOUtils.copy(is, output); } }; } protected boolean hasParameterUi(RepositoryFile repositoryFile) { return (PentahoSystem.get(IPluginManager.class).getContentGenerator( repositoryFile.getName().substring(repositoryFile.getName().lastIndexOf('.') + 1), "parameterUi") != null); } protected IContentGenerator getContentGenerator(RepositoryFile repositoryFile) { return PentahoSystem.get(IPluginManager.class).getContentGenerator( repositoryFile.getName().substring(repositoryFile.getName().lastIndexOf('.') + 1), "parameter"); } protected SimpleParameterProvider getSimpleParameterProvider() { return new SimpleParameterProvider(); } protected String encode(String s) throws UnsupportedEncodingException { return URLEncoder.encode(s, "UTF-8"); } protected IPentahoSession getSession() { return PentahoSessionHolder.getSession(); } protected ByteArrayOutputStream getByteArrayOutputStream() { return new ByteArrayOutputStream(); } protected Document parseText(String text) throws DocumentException { return DocumentHelper.parseText(text); } protected Messages getMessagesInstance() { return Messages.getInstance(); } }