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-2016 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.plugin.services.importer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.pentaho.metadata.repository.DomainAlreadyExistsException; import org.pentaho.metadata.repository.DomainIdNullException; import org.pentaho.metadata.repository.DomainStorageException; import org.pentaho.platform.api.engine.ISolutionEngine; import org.pentaho.platform.api.engine.PluginBeanException; import org.pentaho.platform.api.mimetype.IMimeType; import org.pentaho.platform.api.mimetype.IPlatformMimeResolver; import org.pentaho.platform.api.repository.datasource.IDatasourceMgmtService; import org.pentaho.platform.api.repository2.unified.Converter; import org.pentaho.platform.api.repository2.unified.IPlatformImportBundle; import org.pentaho.platform.api.repository2.unified.IRepositoryContentConverterHandler; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.api.repository2.unified.data.simple.SimpleRepositoryFileData; import org.pentaho.platform.core.mimetype.MimeType; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.core.system.boot.PlatformInitializationException; import org.pentaho.platform.engine.services.solution.SolutionEngine; import org.pentaho.platform.plugin.services.importexport.Log4JRepositoryImportLogger; import org.pentaho.platform.plugin.services.importexport.StreamConverter; import org.pentaho.platform.repository2.unified.fs.FileSystemBackedUnifiedRepository; import org.pentaho.test.platform.engine.core.MicroPlatform; import org.pentaho.test.platform.utils.TestResourceLocation; /** * * Checks that SolutionImportHandler processes file names correctly * */ public class SolutionImportHandlerNamingIT extends Assert { private static final String SOLUTION_PATH = TestResourceLocation.TEST_RESOURCES + "/SolutionImportHandlerNamingTest"; private static final String REPO_PATH = "/repo"; private static final String IMPORT_REPO_DIR = "/home/testuser"; private static final String DEFAULT_ENCODING = "UTF-8"; private static final String SRC_ROOT = "/exported"; private static final String SRC_EXPORTMANIFEST = SRC_ROOT + "/exportManifest.xml"; private static final String SRC_CONTENT_FILE = SRC_ROOT + "/content.prpt"; private static final String ZIPENTRY_EXPORTMANIFEST = "exportManifest.xml"; private static final String ZIPENTRY_CONTENT_FILE = "two+words%2525/eval+%28%2B%29%2525.prpt"; private static final String ZIPENTRY_CONTENT_FILE_NOMANIFEST = "two words%25/eval (+)%25.prpt"; private final IMimeType MIME_SOLUTION = new MimeType("application/vnd.pentaho.solution-repository", "zip"); private final IMimeType MIME_PRPT = new MimeType("text/prptMimeType", "prpt"); private final IMimeType MIME_XML = new MimeType("text/xml", "xml"); private static File tempDir; private static File solutionDir; private SolutionImportHandler solutionImportHandler; private File repoRoot; private FileSystemBackedUnifiedRepository repo; private MicroPlatform microPlatform; private AnswerTest<RepositoryFile> answer; // private PentahoPlatformImporter importer; @BeforeClass public static void beforeClass() throws IOException { tempDir = File.createTempFile("test", null); tempDir.delete(); tempDir.mkdir(); FileUtils.forceDeleteOnExit(tempDir); solutionDir = new File(getSolutionPath()); assertTrue(solutionDir.exists()); assertTrue(solutionDir.isDirectory()); } @AfterClass public static void afterClass() throws IOException { FileUtils.forceDelete(tempDir); } @Before public void init() throws IOException, PlatformInitializationException, PlatformImportException, DomainIdNullException, DomainAlreadyExistsException, DomainStorageException { // repository File repoDir = new File(tempDir.getAbsolutePath() + REPO_PATH); FileUtils.forceMkdir(repoDir); FileUtils.cleanDirectory(repoDir); repoRoot = repoDir; repo = new FileSystemBackedUnifiedRepository(); repo = Mockito.spy(repo); repo.setRootDir(repoRoot); // mimeResolver final Converter defaultConverter = new StreamConverter(); final List<IMimeType> solutionMimeList = java.util.Collections.singletonList(MIME_SOLUTION); final List<IMimeType> contentMimeList = java.util.Arrays.asList(new IMimeType[] { MIME_PRPT, MIME_XML }); final List<IMimeType> allMimeTypes = new ArrayList<IMimeType>( solutionMimeList.size() + contentMimeList.size()); { allMimeTypes.addAll(solutionMimeList); allMimeTypes.addAll(contentMimeList); for (IMimeType mimeType : allMimeTypes) { mimeType.setConverter(defaultConverter); } } final IPlatformMimeResolver mimeResolver = new NameBaseMimeResolver(); for (IMimeType mimeType : allMimeTypes) { mimeResolver.addMimeType(mimeType); } // platform, import handlers PentahoSystem.clearObjectFactory(); microPlatform = new MicroPlatform(getSolutionPath()); microPlatform.defineInstance(IUnifiedRepository.class, repo); microPlatform.defineInstance(IPlatformMimeResolver.class, mimeResolver); microPlatform.defineInstance(ISolutionEngine.class, Mockito.mock(SolutionEngine.class)); microPlatform.defineInstance(IDatasourceMgmtService.class, Mockito.mock(IDatasourceMgmtService.class)); IRepositoryContentConverterHandler converterHandler = new DefaultRepositoryContentConverterHandler( new HashMap<String, Converter>()); RepositoryFileImportFileHandler contentImportFileHandler = new RepositoryFileImportFileHandler( contentMimeList); contentImportFileHandler.setRepository(repo); solutionImportHandler = new SolutionImportHandler(solutionMimeList); List<IPlatformImportHandler> handlers = new ArrayList<IPlatformImportHandler>(); handlers.add(contentImportFileHandler); handlers.add(solutionImportHandler); PentahoPlatformImporter importer = new PentahoPlatformImporter(handlers, converterHandler); importer.setDefaultHandler(contentImportFileHandler); importer.setRepositoryImportLogger(new Log4JRepositoryImportLogger()); microPlatform.defineInstance(IPlatformImporter.class, importer); microPlatform.start(); } @After public void cleanup() throws PluginBeanException, PlatformInitializationException, IOException { microPlatform.stop(); FileUtils.cleanDirectory(repoRoot); } private static String getSolutionPath() { return SOLUTION_PATH; } private void assertFileContentEquals(File expected, RepositoryFile actual) throws IOException { FileInputStream inExp = null; InputStream inAct = null; try { inExp = new FileInputStream(expected); try { inAct = repo.getDataForRead(actual.getId(), SimpleRepositoryFileData.class).getInputStream(); final String msg = "src{ " + expected.getName() + " } == repo{ " + actual.getName() + " }"; assertTrue(msg, IOUtils.contentEquals(inExp, inAct)); } finally { if (inAct != null) { inAct.close(); } } } finally { if (inExp != null) { inExp.close(); } } } /** * Import has to be launched in a separate thread because importSession is thread-local. * * @param solutionImportHandler * @param bundle * @throws InterruptedException */ private void runImport(final SolutionImportHandler solutionImportHandler, final IPlatformImportBundle bundle) throws InterruptedException { Thread thr = new Thread() { @Override public void run() { try { solutionImportHandler.importFile(bundle); } catch (Error | RuntimeException e) { e.printStackTrace(); throw e; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } }; thr.start(); thr.join(0L); } @Test public void testImportFileWithoutManifest() throws PlatformImportException, DomainIdNullException, DomainAlreadyExistsException, DomainStorageException, IOException, PlatformInitializationException, InterruptedException { ByteArrayInputStream solutionInputStream = null; final File srcContentFile = new File(solutionDir + SRC_CONTENT_FILE); ByteArrayOutputStream tmpOS = null; try { tmpOS = new ByteArrayOutputStream(); ZipOutputStream zipOS = new ZipOutputStream(tmpOS); zipOS.putNextEntry(new ZipEntry(ZIPENTRY_CONTENT_FILE_NOMANIFEST)); FileUtils.copyFile(srcContentFile, zipOS); zipOS.closeEntry(); zipOS.close(); solutionInputStream = new ByteArrayInputStream(tmpOS.toByteArray()); } finally { if (tmpOS != null) { tmpOS.close(); } } final IPlatformImportBundle bundle = buildBundle(solutionInputStream); runImport(solutionImportHandler, bundle); { // files with correct names do exist RepositoryFile dir = repo.getFile(IMPORT_REPO_DIR + "/two words%25"); assertNotNull(dir); assertTrue(dir.isFolder()); RepositoryFile file = repo.getFile(IMPORT_REPO_DIR + "/two words%25/eval (+)%25.prpt"); assertNotNull(file); assertFalse(file.isFolder()); assertFileContentEquals(srcContentFile, file); } { // files with incorrect names do not exist assertNull(repo.getFile(IMPORT_REPO_DIR + "/two+words%2525")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two+words%25")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two+words%")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two words%2525")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two words%")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two words%25/eval+%28%2B%29%2525.prpt")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two words%25/eval (+)%.prpt")); } } @Test public void testImportFileWithManifest() throws PlatformImportException, DomainIdNullException, DomainAlreadyExistsException, DomainStorageException, IOException, PlatformInitializationException, InterruptedException { ZipBuilder zipBuilder = new ZipBuilder(); zipBuilder.addFile(solutionDir + SRC_EXPORTMANIFEST, ZIPENTRY_EXPORTMANIFEST); zipBuilder.addFile(solutionDir + SRC_CONTENT_FILE, ZIPENTRY_CONTENT_FILE); ByteArrayOutputStream out = zipBuilder.build(); ByteArrayInputStream solutionInputStream = new ByteArrayInputStream(out.toByteArray()); final IPlatformImportBundle bundle = buildBundle(solutionInputStream); runImport(solutionImportHandler, bundle); { // files with correct names do exist RepositoryFile dir = repo.getFile(IMPORT_REPO_DIR + "/two words%25"); assertNotNull(dir); assertTrue(dir.isFolder()); RepositoryFile file = repo.getFile(IMPORT_REPO_DIR + "/two words%25/eval (+)%25.prpt"); assertNotNull(file); assertFalse(file.isFolder()); assertFileContentEquals(new File(solutionDir + SRC_CONTENT_FILE), file); } { // exportManifest.xml does not exist assertNull(repo.getFile(IMPORT_REPO_DIR + "/exportManifest.xml")); } { // files with incorrect names do not exist assertNull(repo.getFile(IMPORT_REPO_DIR + "/two+words%2525")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two+words%25")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two+words%")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two words%2525")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two words%")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two words%25/eval+%28%2B%29%2525.prpt")); assertNull(repo.getFile(IMPORT_REPO_DIR + "/two words%25/eval (+)%.prpt")); } } private static class ZipBuilder { private ByteArrayOutputStream out = new ByteArrayOutputStream(); private ZipOutputStream zip = new ZipOutputStream(out); public void addFile(String filePath, String fileName) throws IOException { final File file = new File(filePath); assertTrue(file.getAbsolutePath() + " didn't found.", file.exists()); zip.putNextEntry(new ZipEntry(fileName)); FileUtils.copyFile(file, zip); zip.closeEntry(); } public ByteArrayOutputStream build() throws IOException { zip.close(); out.close(); return out; } } private IPlatformImportBundle buildBundle(InputStream solutionInputStream) { final RepositoryFileImportBundle.Builder bundleBuilder = new RepositoryFileImportBundle.Builder(); bundleBuilder.input(solutionInputStream); bundleBuilder.charSet(DEFAULT_ENCODING); bundleBuilder.hidden(RepositoryFile.HIDDEN_BY_DEFAULT); bundleBuilder.schedulable(RepositoryFile.SCHEDULABLE_BY_DEFAULT); bundleBuilder.path(IMPORT_REPO_DIR); bundleBuilder.overwriteFile(false); bundleBuilder.applyAclSettings(false); bundleBuilder.overwriteAclSettings(false); bundleBuilder.retainOwnership(true); bundleBuilder.name("testSrc.zip"); bundleBuilder.mime("application/vnd.pentaho.solution-repository"); return bundleBuilder.build(); } @Test public void testImportHiddenFileByManifest() throws IOException, InterruptedException { repo.deleteFile(SRC_CONTENT_FILE, ""); answer = new AnswerTest<RepositoryFile>() { @Override public RepositoryFile answer(InvocationOnMock invocation) throws Throwable { obj = invocation.getArgumentAt(1, RepositoryFile.class); return null; } }; Mockito.doAnswer(answer).when(repo).createFile(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()); // isHidden="true" isSchedulable="true" RepositoryFile file = importFile("/manifestFileHidden.xml"); assertTrue(file.isHidden()); assertTrue(file.isSchedulable()); // isHidden="false" isSchedulable="false" file = importFile("/manifestFileNotHidden.xml"); assertFalse(file.isHidden()); assertFalse(file.isSchedulable()); // nothing file = importFile("/manifestHiddenByDefault.xml"); assertEquals(file.isHidden(), RepositoryFile.HIDDEN_BY_DEFAULT); assertEquals(file.isSchedulable(), RepositoryFile.SCHEDULABLE_BY_DEFAULT); } private RepositoryFile importFile(String manifest) throws IOException, InterruptedException { ZipBuilder zipBuilder = new ZipBuilder(); zipBuilder.addFile(solutionDir + SRC_ROOT + manifest, "exportManifest.xml"); zipBuilder.addFile(solutionDir + SRC_CONTENT_FILE, SRC_CONTENT_FILE); ByteArrayOutputStream out = zipBuilder.build(); ByteArrayInputStream solutionInputStream = new ByteArrayInputStream(out.toByteArray()); IPlatformImportBundle bundle = buildBundle(solutionInputStream); runImport(solutionImportHandler, bundle); return answer != null ? answer.getObj() : null; } private abstract static class AnswerTest<T> implements Answer<T> { protected T obj; public T getObj() { return obj; } } }