Package com.atlassian.labs.speakeasy.manager

Source Code of com.atlassian.labs.speakeasy.manager.AbstractOsgiPluginTypeHandler

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();
    }


}
TOP

Related Classes of com.atlassian.labs.speakeasy.manager.AbstractOsgiPluginTypeHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.