/plugin/src/main/java/com/atlassian/labs/speakeasy/manager/AbstractOsgiPluginTypeHandler.java
Java | 371 lines | 329 code | 37 blank | 5 comment | 17 complexity | c5722194373275bf08674973f3956421 MD5 | raw file
- package com.atlassian.labs.speakeasy.manager;
- import com.atlassian.labs.speakeasy.git.GitRepositoryManager;
- import com.atlassian.labs.speakeasy.util.RepositoryDirectoryUtil;
- import com.atlassian.labs.speakeasy.util.exec.ReadOnlyOperation;
- import com.atlassian.plugin.JarPluginArtifact;
- import com.atlassian.plugin.PluginArtifact;
- import com.atlassian.templaterenderer.TemplateRenderer;
- import org.apache.commons.io.FileUtils;
- import org.apache.commons.io.IOUtils;
- import org.eclipse.jgit.lib.Repository;
- import org.osgi.framework.Bundle;
- import java.io.*;
- import java.net.URL;
- import java.util.Enumeration;
- import java.util.List;
- import java.util.Map;
- import java.util.regex.Pattern;
- import java.util.zip.ZipEntry;
- import java.util.zip.ZipFile;
- import java.util.zip.ZipOutputStream;
- import static com.atlassian.labs.speakeasy.util.ExtensionValidate.isValidExtensionKey;
- import static com.atlassian.labs.speakeasy.util.KeyExtractor.createExtractableTempFile;
- import static java.util.Arrays.asList;
- /**
- *
- */
- public abstract class AbstractOsgiPluginTypeHandler implements PluginTypeHandler
- {
- protected static final Iterable<Pattern> CORE_WHITELIST = asList(
- Pattern.compile(".*[._]js", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]eot", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]ttf", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]woff", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]svg", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]svgz", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]mu", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]json", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]gif", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]png", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]jpg", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*[._]jpeg", Pattern.CASE_INSENSITIVE),
- // Pattern.compile(".*\\.xml", Pattern.CASE_INSENSITIVE), // excluded for now as you could add a spring XML file and load other classes
- Pattern.compile(".*[._]css", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*/\\._[^.]+", Pattern.CASE_INSENSITIVE),
- Pattern.compile(".*/$"),
- Pattern.compile("META-INF/MANIFEST.MF"),
- Pattern.compile(".*/pom.xml"),
- Pattern.compile(".*/pom.properties"),
- Pattern.compile("README.txt"),
- Pattern.compile("LICENSE.txt"),
- Pattern.compile("README.md"),
- Pattern.compile("\\.gitignore"),
- Pattern.compile(".*\\.DS_Store"));
- private final TemplateRenderer templateRenderer;
- private final GitRepositoryManager gitRepositoryManager;
- public AbstractOsgiPluginTypeHandler(TemplateRenderer templateRenderer, GitRepositoryManager repositoryManager)
- {
- this.templateRenderer = templateRenderer;
- this.gitRepositoryManager = repositoryManager;
- }
- public final boolean allowEntryPath(String path)
- {
- Iterable<Pattern> whitelistPatterns = getWhitelistPatterns();
- for (Pattern whitelist : whitelistPatterns)
- {
- if (whitelist.matcher(path).matches())
- {
- return true;
- }
- }
- return false;
- }
- public final File createTempFile(String pluginKey) throws IOException
- {
- return createExtractableTempFile(pluginKey, "." + getExtension());
- }
- public final String canInstall(File file)
- {
- PluginArtifact artifact = new JarPluginArtifact(file);
- if (artifact.doesResourceExist(getDescriptorPath()))
- {
- String key = extractPluginKey(artifact);
- if (isValidExtensionKey(key))
- {
- return key;
- }
- }
- return null;
- }
- public final PluginArtifact createArtifact(File uploadedFile)
- {
- PluginArtifact pluginArtifact = new JarPluginArtifact(uploadedFile);
- verifyContents(pluginArtifact);
- pluginArtifact = validatePluginArtifact(pluginArtifact);
- return pluginArtifact;
- }
- public String getPluginFile(final String pluginKey, final String fileName) throws IOException
- {
- return gitRepositoryManager.operateOnRepository(pluginKey, new ReadOnlyOperation<Repository, String>()
- {
- public String operateOn(Repository repo) throws Exception
- {
- File dir = repo.getWorkTree();
- File file = new File(dir, fileName);
- if (file.exists())
- {
- return FileUtils.readFileToString(file);
- }
- throw new FileNotFoundException(fileName);
- }
- });
- }
- public File getPluginArtifact(String pluginKey) throws IOException
- {
- return gitRepositoryManager.buildJarFromRepository(pluginKey);
- }
- public List<String> getPluginFileNames(String pluginKey)
- {
- return gitRepositoryManager.operateOnRepository(pluginKey, new ReadOnlyOperation<Repository, List<String>>()
- {
- public List<String> operateOn(Repository repo) throws Exception
- {
- final File dir = repo.getWorkTree();
- return RepositoryDirectoryUtil.getEntries(dir);
- }
- });
- }
- public File getPluginAsProject(String pluginKey, final Map<String, Object> context)
- {
- return gitRepositoryManager.operateOnRepository(pluginKey, new ReadOnlyOperation<Repository, File>()
- {
- public File operateOn(Repository repo) throws Exception
- {
- FileOutputStream fout = null;
- ZipOutputStream zout = null;
- File file = null;
- try
- {
- file = File.createTempFile("speakeasy-plugin-project", ".zip");
- fout = new FileOutputStream(file);
- zout = new ZipOutputStream(fout);
- zout.putNextEntry(new ZipEntry("src/"));
- zout.putNextEntry(new ZipEntry("src/main/"));
- zout.putNextEntry(new ZipEntry("src/main/resources/"));
- List<String> paths = RepositoryDirectoryUtil.getEntries(repo.getWorkTree());
- for (String path : paths)
- {
- String actualPath = "src/main/resources/" + path;
- ZipEntry entry = new ZipEntry(actualPath);
- zout.putNextEntry(entry);
- if (!path.endsWith("/"))
- {
- byte[] data = FileUtils.readFileToByteArray(new File(repo.getWorkTree(), path));
- zout.write(data, 0, data.length);
- }
- }
- zout.putNextEntry(new ZipEntry("pom.xml"));
- String pomContents = renderPom(context);
- IOUtils.copy(new StringReader(pomContents), zout);
- }
- catch (IOException e)
- {
- throw new RuntimeException("Unable to create plugin project", e);
- }
- finally
- {
- IOUtils.closeQuietly(zout);
- IOUtils.closeQuietly(fout);
- }
- return file;
- }
- });
- }
- public File createExample(String pluginKey, String name, String description) throws IOException
- {
- ZipOutputStream zout = null;
- File tmpFile = null;
- try
- {
- tmpFile = createTempFile(pluginKey);
- zout = new ZipOutputStream(new FileOutputStream(tmpFile));
- createExampleContents(zout, pluginKey, name, description);
- zout.close();
- }
- finally
- {
- IOUtils.closeQuietly(zout);
- }
- return tmpFile;
- }
- public File createFork(String pluginKey, final String forkPluginKey, String user, final String description) throws IOException
- {
- return gitRepositoryManager.operateOnRepository(pluginKey, new ReadOnlyOperation<Repository, File>()
- {
- public File operateOn(Repository repo) throws Exception
- {
- ZipOutputStream zout = null;
- File tmpFile = null;
- try
- {
- tmpFile = createTempFile(forkPluginKey);
- zout = new ZipOutputStream(new FileOutputStream(tmpFile));
- final File repoDir = repo.getWorkTree();
- List<String> bundlePaths = RepositoryDirectoryUtil.getEntries(repoDir);
- bundlePaths.remove(getDescriptorPath());
- for (String path : bundlePaths)
- {
- ZipEntry entry = new ZipEntry(path);
- zout.putNextEntry(entry);
- if (!path.endsWith("/"))
- {
- byte[] data = FileUtils.readFileToByteArray(new File(repoDir, path));
- zout.write(data, 0, data.length);
- }
- }
- zout.putNextEntry(new ZipEntry(getDescriptorPath()));
- forkDescriptor(new ByteArrayInputStream(FileUtils.readFileToByteArray(new File(repoDir, getDescriptorPath()))),
- zout, forkPluginKey, description);
- zout.close();
- }
- finally
- {
- IOUtils.closeQuietly(zout);
- }
- return tmpFile;
- }
- });
- }
- public File rebuildPlugin(final String pluginKey, final String fileName, final String contents) throws IOException
- {
- return gitRepositoryManager.operateOnRepository(pluginKey, new ReadOnlyOperation<Repository, File>()
- {
- public File operateOn(Repository repo) throws Exception
- {
- ZipOutputStream zout = null;
- File tmpFile = null;
- try
- {
- tmpFile = createTempFile(pluginKey);
- zout = new ZipOutputStream(new FileOutputStream(tmpFile));
- final File repoDir = repo.getWorkTree();
- for (String path : RepositoryDirectoryUtil.getEntries(repoDir))
- {
- if (!path.equals(fileName) && !path.contains("-min."))
- {
- ZipEntry entry = new ZipEntry(path);
- zout.putNextEntry(entry);
- if (!path.endsWith("/"))
- {
- byte[] data = FileUtils.readFileToByteArray(new File(repoDir, path));
- zout.write(data, 0, data.length);
- }
- }
- }
- ZipEntry entry = new ZipEntry(fileName);
- byte[] data = contents.getBytes();
- entry.setSize(data.length);
- zout.putNextEntry(entry);
- zout.write(data);
- zout.close();
- }
- finally
- {
- IOUtils.closeQuietly(zout);
- }
- return tmpFile;
- }
- });
- }
- private String renderPom(Map<String,Object> context) throws IOException
- {
- StringWriter writer = new StringWriter();
- templateRenderer.render("templates/pom.vm", context, writer);
- return writer.toString();
- }
- protected abstract Iterable<Pattern> getWhitelistPatterns();
- protected abstract void createExampleContents(ZipOutputStream zout, String pluginKey, String name, String description) throws IOException;
- protected abstract String extractPluginKey(PluginArtifact artifact);
- protected abstract String getExtension();
- protected abstract PluginArtifact validatePluginArtifact(PluginArtifact pluginArtifact);
- protected abstract String getDescriptorPath();
- protected abstract void forkDescriptor(InputStream byteArrayInputStream, OutputStream zout, String key, String description) throws IOException;
- private void verifyContents(PluginArtifact plugin) throws PluginOperationFailedException
- {
- ZipFile zip = null;
- try
- {
- zip = new ZipFile(plugin.toFile());
- for (Enumeration<? extends ZipEntry> e = zip.entries(); e.hasMoreElements();)
- {
- ZipEntry entry = e.nextElement();
- if (!allowEntryPath(entry.getName()))
- {
- throw new PluginOperationFailedException("Invalid plugin entry: " + entry.getName(), null);
- }
- }
- }
- catch (IOException e)
- {
- throw new PluginOperationFailedException("Unable to open plugin zip", e, null);
- }
- finally
- {
- if (zip != null)
- {
- try
- {
- zip.close();
- }
- catch (IOException e)
- {
- // ignore
- }
- }
- }
- }
- private byte[] readEntry(Bundle bundle, String path)
- throws IOException
- {
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- URL url = bundle.getEntry(path);
- InputStream urlIn = null;
- try
- {
- urlIn = url.openStream();
- IOUtils.copy(urlIn, bout);
- }
- finally
- {
- IOUtils.closeQuietly(urlIn);
- }
- return bout.toByteArray();
- }
- }