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.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; 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.util.RepositoryPathEncoder; import org.pentaho.reporting.libraries.base.util.FastStack; import org.pentaho.reporting.libraries.base.util.URLEncoder; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; public class JCRSolutionFileModel implements SolutionFileModel { private static final Log logger = LogFactory.getLog(JCRSolutionFileModel.class); private static final String LOAD_REPOSITORY_SERVICE = LibPensolBoot.getInstance().getGlobalConfig() .getConfigProperty("org.pentaho.reporting.libraries.pensol.jcr.LoadRepositoryDoc"); private static final String PARTIAL_LOADING_ENABLED = LibPensolBoot.getInstance().getGlobalConfig() .getConfigProperty("org.pentaho.reporting.libraries.pensol.jcr.PartialLoading", Boolean.TRUE.toString()); private static final String LOAD_REPOSITORY_PARTIALLY_SERVICE = LibPensolBoot.getInstance().getGlobalConfig() .getConfigProperty("org.pentaho.reporting.libraries.pensol.jcr.LoadRepositoryDocPartially"); private static final String CREATE_FOLDER_SERVICE = LibPensolBoot.getInstance().getGlobalConfig() .getConfigProperty("org.pentaho.reporting.libraries.pensol.jcr.CreateNewFolder"); private static final String DOWNLOAD_SERVICE = LibPensolBoot.getInstance().getGlobalConfig() .getConfigProperty("org.pentaho.reporting.libraries.pensol.jcr.DownloadService"); private static final String UPLOAD_SERVICE = LibPensolBoot.getInstance().getGlobalConfig() .getConfigProperty("org.pentaho.reporting.libraries.pensol.jcr.UploadService"); public static final String RETRIEVE_CONTENT_SERVICE = LibPensolBoot.getInstance().getGlobalConfig() .getConfigProperty("org.pentaho.reporting.libraries.pensol.jcr.RetrieveContent"); public static final String RETRIEVE_PARAMETER_URL_SERVICE = LibPensolBoot.getInstance().getGlobalConfig() .getConfigProperty("org.pentaho.reporting.libraries.pensol.jcr.RetrieveParameters"); public static final String DELETE_FILE_OR_FOLDER = LibPensolBoot.getInstance().getGlobalConfig() .getConfigProperty("org.pentaho.reporting.libraries.pensol.jcr.delete.file.or.folder"); private static final String BI_SERVER_NULL_OBJECT = "BI-Server returned a RepositoryFileTreeDto without an attached RepositoryFileDto. " + "Please file a bug report at http://jira.pentaho.org/browse/BISERVER !"; private static final String FILE_NOT_FOUND = "The specified file name does not exist: {0}"; //this is required to retrieve a prpt - if true we get z ZIP file with .locale info private static final String SLASH = "/"; // ":" --> "%3A" private static final String ENCODED_COLON = RepositoryPathEncoder.encodeURIComponent(":"); private Client client; private String url; private RepositoryFileTreeDto root; private HashMap<FileName, String> descriptionEntries; private long refreshTime; private String majorVersion; private String minorVersion; private String releaseVersion; private String buildVersion; private String milestoneVersion; private final boolean loadTreePartially; public JCRSolutionFileModel(final String url, final String username, final String password, final int timeout) { if (url == null) { throw new NullPointerException(); } this.url = url; descriptionEntries = new HashMap<FileName, String>(); final ClientConfig config = new DefaultClientConfig(); config.getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true); config.getProperties().put(ClientConfig.PROPERTY_READ_TIMEOUT, timeout); this.client = Client.create(config); this.client.addFilter(new CookiesHandlerFilter()); // must be inserted before HTTPBasicAuthFilter this.client.addFilter(new HTTPBasicAuthFilter(username, password)); this.majorVersion = "999"; this.minorVersion = "999"; this.releaseVersion = "999"; this.buildVersion = "999"; this.milestoneVersion = "999"; this.loadTreePartially = Boolean.parseBoolean(PARTIAL_LOADING_ENABLED); } // package-local constructor for testing purposes JCRSolutionFileModel(String url, Client client, boolean loadTreePartially) { this.url = url; this.descriptionEntries = new HashMap<FileName, String>(); this.client = client; this.loadTreePartially = loadTreePartially; } public void refresh() throws IOException { RepositoryFileTreeDto tree; if (loadTreePartially) { WebResource resource = client.resource(url + LOAD_REPOSITORY_PARTIALLY_SERVICE); tree = resource.path("").accept(MediaType.APPLICATION_XML_TYPE).get(RepositoryFileTreeDto.class); tree = proxyRoot(tree); } else { WebResource resource = client.resource(url + LOAD_REPOSITORY_SERVICE); tree = resource.path("").accept(MediaType.APPLICATION_XML_TYPE).get(RepositoryFileTreeDto.class); } setRoot(tree); } private RepositoryFileTreeDtoProxy proxyRoot(RepositoryFileTreeDto original) { // save it, as proxy will replace the list with empty List<RepositoryFileTreeDto> originalChildren = original.getChildren(); RepositoryFileTreeDtoProxy proxy = new RepositoryFileTreeDtoProxy(original, client, url); if (originalChildren == null) { proxy.setChildren(Collections.<RepositoryFileTreeDto>emptyList()); } else { // pre-populating root's direct children List<RepositoryFileTreeDto> proxiedChildren = new ArrayList<RepositoryFileTreeDto>( originalChildren.size()); for (RepositoryFileTreeDto child : originalChildren) { proxiedChildren.add(new RepositoryFileTreeDtoProxy(child, client, url)); } proxy.setChildren(proxiedChildren); } return proxy; } public void createFolder(final FileName file) throws FileSystemException { try { final String path = URLEncoder .encodeUTF8(URLDecoder.decode(normalizePath(file.getPath().replaceAll("\\+", "%2B")), "UTF-8")) .replaceAll("\\!", "%21"); final String service = MessageFormat.format(CREATE_FOLDER_SERVICE, path); final WebResource resource = client.resource(url + service); final ClientResponse response = resource.type("text/plain").put(ClientResponse.class, null); if (response.getStatus() == 200) { refresh(); } else { throw new FileSystemException("Failed with error-code", response.getStatus()); } } catch (FileSystemException fse) { throw fse; } catch (Exception e) { throw new FileSystemException("Failed", e); } } private static String normalizePath(final String path) { return RepositoryPathEncoder.encodeRepositoryPath(path); } static String encodePathForRequest(String path) { String pathEncoded = RepositoryPathEncoder.encodeRepositoryPath(path); String utf8 = RepositoryPathEncoder.encodeURIComponent(pathEncoded); // replace encoded colons with original return utf8.replaceAll(ENCODED_COLON, ":"); } public RepositoryFileTreeDto getRoot() throws IOException { if (root == null && refreshTime == 0) { refresh(); } return root; } public void setRoot(final RepositoryFileTreeDto root) { if (root == null) { throw new NullPointerException(); } this.descriptionEntries.clear(); this.refreshTime = System.currentTimeMillis(); this.root = root; } public boolean isDirectory(final FileName file) throws FileSystemException { final String[] fileName = computeFileNames(file); final RepositoryFileTreeDto fileInfo = lookupNode(fileName); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, file); } final RepositoryFileDto fileDto = fileInfo.getFile(); if (fileDto == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } return fileDto.isFolder(); } public boolean exists(final FileName file) throws FileSystemException { final String[] fileName = computeFileNames(file); final RepositoryFileTreeDto fileInfo = lookupNode(fileName); return (fileInfo != null); } public boolean isVisible(final FileName file) throws FileSystemException { final String[] fileName = computeFileNames(file); final RepositoryFileTreeDto fileInfo = lookupNode(fileName); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, file); } final RepositoryFileDto fileDto = fileInfo.getFile(); if (fileDto == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } return !fileDto.isHidden(); } public void setDescription(final FileName file, final String description) throws FileSystemException { final String[] fileName = computeFileNames(file); final RepositoryFileTreeDto fileInfo = lookupNode(fileName); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, file); } final RepositoryFileDto fileDto = fileInfo.getFile(); if (fileDto == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } fileDto.setDescription(description); } public String getDescription(final FileName file) throws FileSystemException { final String[] fileName = computeFileNames(file); final RepositoryFileTreeDto fileInfo = lookupNode(fileName); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, file); } final RepositoryFileDto fileDto = fileInfo.getFile(); if (fileDto == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } return fileDto.getDescription(); } public long getLastModifiedDate(final FileName file) throws FileSystemException { final String[] fileName = computeFileNames(file); final RepositoryFileTreeDto fileInfo = lookupNode(fileName); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, file); } final RepositoryFileDto fileDto = fileInfo.getFile(); if (fileDto == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } final Date lastModifiedDate = fileDto.getLastModifiedDate(); if (lastModifiedDate == null) { logger.error("Repository returned <null> for last-modified-date on file: " + file); return -1; } return lastModifiedDate.getTime(); } private String getFormattedServiceUrl(final String urlService, final FileName file) throws FileSystemException { if (urlService == null) { throw new NullPointerException(); } final String[] fileName = computeFileNames(file); final RepositoryFileTreeDto fileInfo = lookupNode(fileName); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, file); } final String restName = normalizePath(file.getPath()); return MessageFormat.format(urlService, URLEncoder.encodeUTF8(restName).replaceAll("\\!", "%21").replaceAll("\\+", "%2B")); } public String getUrl(final FileName file) throws FileSystemException { return getFormattedServiceUrl(RETRIEVE_CONTENT_SERVICE, file); } public List<RepositoryFileTreeDto> getChildren(final FileName parent) throws FileSystemException { final String[] pathArray = computeFileNames(parent); final RepositoryFileTreeDto fileInfo = lookupNode(pathArray); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, parent); } final List<RepositoryFileTreeDto> childNodes = fileInfo.getChildren(); return childNodes == null ? Collections.<RepositoryFileTreeDto>emptyList() : childNodes; } protected RepositoryFileTreeDto lookupNode(final String[] path) throws FileSystemException { if (root == null) { try { refresh(); } catch (IOException e) { throw new FileSystemException(e); } } if (path.length == 0) { return root; } if ("".equals(path[0])) { if (path.length == 1) { return root; } } RepositoryFileTreeDto element = root; for (final String pathSegment : path) { RepositoryFileTreeDto name = null; final List<RepositoryFileTreeDto> children = element.getChildren(); if (children == null) { return null; } for (final RepositoryFileTreeDto child : children) { final RepositoryFileDto file = child.getFile(); if (file == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } if (pathSegment.equals(file.getName())) { name = child; break; } } if (name == null) { return null; } element = name; } return element; } protected String[] computeFileNames(FileName file) { final FastStack<String> stack = new FastStack<String>(); while (file != null) { String name; try { name = URLDecoder.decode(file.getBaseName().trim().replaceAll("\\+", "%2B"), "UTF-8"); } catch (UnsupportedEncodingException e) { name = file.getBaseName().trim(); } if (!"".equals(name)) { stack.push(name); } file = file.getParent(); } final int size = stack.size(); final String[] result = new String[size]; for (int i = 0; i < result.length; i++) { result[i] = stack.pop(); } return result; } public byte[] getData(final FileName file) throws FileSystemException { final String[] fileName = computeFileNames(file); final RepositoryFileTreeDto fileInfo = lookupNode(fileName); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, file); } final RepositoryFileDto fileDto = fileInfo.getFile(); if (fileDto == null) { throw new IllegalStateException(BI_SERVER_NULL_OBJECT); } final String path = normalizePath(fileDto.getPath()); String urlPath = path; try { urlPath = URLEncoder.encodeUTF8(path).replaceAll("\\!", "%21").replaceAll("\\+", "%2B"); } catch (Exception ex) { } //tcb final String service = MessageFormat.format(DOWNLOAD_SERVICE, urlPath); return client.resource(url + service).accept(MediaType.APPLICATION_XML_TYPE).get(byte[].class); } public void setData(final FileName file, final byte[] data) throws FileSystemException { final String[] fileName = computeFileNames(file); final StringBuilder b = new StringBuilder(); for (int i = 0; i < fileName.length; i++) { if (i != 0) { b.append(SLASH); } b.append(fileName[i]); } String service = MessageFormat.format(UPLOAD_SERVICE, URLEncoder .encodeUTF8(normalizePath(b.toString()).replaceAll("\\!", "%21").replaceAll("\\+", "%2B"))); final WebResource resource = client.resource(url + service); final ByteArrayInputStream stream = new ByteArrayInputStream(data); final ClientResponse response = resource.put(ClientResponse.class, stream); final int status = response.getStatus(); if (status != HttpStatus.SC_OK) { if (status == HttpStatus.SC_MOVED_TEMPORARILY || status == HttpStatus.SC_FORBIDDEN || status == HttpStatus.SC_UNAUTHORIZED) { throw new FileSystemException("ERROR_INVALID_USERNAME_OR_PASSWORD"); } else { throw new FileSystemException("ERROR_FAILED", status); } } try { // Perhaps a New file was created. Refresh local tree model. this.refresh(); } catch (IOException e) { // Ignore if unable to refresh } } public String[] getChilds(final FileName name) throws FileSystemException { final List<RepositoryFileTreeDto> children = getChildren(name); final String[] childrenArray = new String[children.size()]; for (int i = 0; i < children.size(); i++) { final RepositoryFileTreeDto repositoryFileTreeDto = children.get(i); if (repositoryFileTreeDto == null) { continue; } final RepositoryFileDto file = repositoryFileTreeDto.getFile(); if (file == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } childrenArray[i] = file.getName().replaceAll("\\%", "%25").replaceAll("\\!", "%21").replaceAll("\\+", "%2B"); } return childrenArray; } public String getLocalizedName(final FileName file) throws FileSystemException { final String[] fileName = computeFileNames(file); final RepositoryFileTreeDto fileInfo = lookupNode(fileName); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, file); } final RepositoryFileDto fileDto = fileInfo.getFile(); if (fileDto == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } return fileDto.getTitle(); } public String getParamServiceUrl(final FileName name) throws FileSystemException { return url + getFormattedServiceUrl(RETRIEVE_PARAMETER_URL_SERVICE, name); } public long getRefreshTime() { return refreshTime; } public void setRefreshTime(final long refreshTime) { this.refreshTime = refreshTime; } public HashMap<FileName, String> getDescriptionEntries() { return descriptionEntries; } public String getMajorVersion() { return majorVersion; } public String getMinorVersion() { return minorVersion; } public String getReleaseVersion() { return releaseVersion; } public String getBuildVersion() { return buildVersion; } public String getMilestoneVersion() { return milestoneVersion; } public long getContentSize(final FileName name) throws FileSystemException { final String[] pathArray = computeFileNames(name); final RepositoryFileTreeDto fileInfo = lookupNode(pathArray); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, name); } final RepositoryFileDto file = fileInfo.getFile(); if (file == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } return file.getFileSize(); } @Override public boolean delete(FileName name) throws FileSystemException { boolean success = false; final RepositoryFileDto file = getFile(name); try { final WebResource resource = client.resource(url + DELETE_FILE_OR_FOLDER); final ClientResponse response = resource.put(ClientResponse.class, file.getId()); if (response != null && response.getStatus() == Response.Status.OK.getStatusCode()) { refresh(); success = true; } else { throw new FileSystemException("Failed with error-code " + response.getStatus()); } } catch (Exception e) { throw new FileSystemException("Failed", e); } return success; } private RepositoryFileDto getFile(FileName name) throws FileSystemException { if (name == null) { throw new FileSystemException(FILE_NOT_FOUND); } final String[] pathArray = computeFileNames(name); final RepositoryFileTreeDto fileInfo = lookupNode(pathArray); if (fileInfo == null) { throw new FileSystemException(FILE_NOT_FOUND, name); } final RepositoryFileDto file = fileInfo.getFile(); if (file == null) { throw new FileSystemException(BI_SERVER_NULL_OBJECT); } return file; } }