use new core plugin index and improved plugin directory structure

This commit is contained in:
Sebastian Sdorra
2014-07-12 16:41:20 +02:00
parent 80e52a347a
commit 598f8c95ba
3 changed files with 249 additions and 46 deletions

View File

@@ -34,8 +34,8 @@ package sonia.scm.boot;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.io.Resources;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,9 +43,11 @@ import org.slf4j.LoggerFactory;
import sonia.scm.SCMContext;
import sonia.scm.ScmContextListener;
import sonia.scm.plugin.PluginException;
import sonia.scm.plugin.PluginId;
import sonia.scm.plugin.PluginLoadException;
import sonia.scm.plugin.PluginWrapper;
import sonia.scm.plugin.Plugins;
import sonia.scm.plugin.SmpArchive;
import sonia.scm.util.ClassLoaders;
import sonia.scm.util.IOUtil;
@@ -53,12 +55,12 @@ import sonia.scm.util.IOUtil;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -66,6 +68,13 @@ import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.xml.bind.DataBindingException;
import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
@@ -76,6 +85,9 @@ public class BootstrapContextListener implements ServletContextListener
/** Field description */
private static final String DIRECTORY_PLUGINS = "plugins";
/** Field description */
private static final String FILE_CHECKSUM = "checksum";
/** Field description */
private static final String PLUGIN_DIRECTORY = "/WEB-INF/plugins/";
@@ -87,7 +99,7 @@ public class BootstrapContextListener implements ServletContextListener
/** Field description */
private static final String PLUGIN_COREINDEX =
PLUGIN_DIRECTORY.concat("plugin.idx");
PLUGIN_DIRECTORY.concat("plugin-index.xml");
//~--- methods --------------------------------------------------------------
@@ -132,17 +144,17 @@ public class BootstrapContextListener implements ServletContextListener
public void contextInitialized(ServletContextEvent sce)
{
ServletContext context = sce.getServletContext();
List<String> lines = readCorePluginIndex(context);
PluginIndex index = readCorePluginIndex(context);
File pluginDirectory = getPluginDirectory();
copyCorePlugins(context, pluginDirectory, lines);
try
{
extractCorePlugins(context, pluginDirectory, index);
ClassLoader cl =
ClassLoaders.getContextClassLoader(BootstrapContextListener.class);
try
{
Set<PluginWrapper> plugins = Plugins.collectPlugins(cl,
pluginDirectory.toPath());
@@ -160,22 +172,83 @@ public class BootstrapContextListener implements ServletContextListener
* Method description
*
*
* @param context
* @param pluginDirectory
* @param name
* @param archive
* @param checksum
* @param directory
* @param checksumFile
*
* @throws IOException
*/
private void copyCorePlugin(ServletContext context, File pluginDirectory,
String name)
private void extract(SmpArchive archive, String checksum, File directory,
File checksumFile)
throws IOException
{
URL url = context.getResource(PLUGIN_DIRECTORY.concat(name));
File file = new File(pluginDirectory, name);
try (OutputStream output = new FileOutputStream(file))
if (directory.exists())
{
Resources.copy(url, output);
logger.debug("delete directory {} for plugin extraction",
archive.getPluginId());
IOUtil.delete(directory);
}
IOUtil.mkdirs(directory);
logger.debug("extract plugin {}", archive.getPluginId());
archive.extract(directory);
//J-
com.google.common.io.Files.write(
checksum,
checksumFile,
Charsets.UTF_8
);
//J+
}
/**
* Method description
*
*
* @param context
* @param pluginDirectory
* @param name
* @param entry
*
* @throws IOException
*/
private void extractCorePlugin(ServletContext context, File pluginDirectory,
PluginIndexEntry entry)
throws IOException
{
URL url = context.getResource(PLUGIN_DIRECTORY.concat(entry.getName()));
SmpArchive archive = SmpArchive.create(url);
PluginId id = archive.getPluginId();
File directory = Plugins.createPluginDirectory(pluginDirectory, id);
File checksumFile = new File(directory, FILE_CHECKSUM);
if (!directory.exists())
{
logger.warn("install plugin {}", id);
extract(archive, entry.getChecksum(), directory, checksumFile);
}
else if (!checksumFile.exists())
{
logger.warn("plugin directory {} exists without checksum file.",
directory);
extract(archive, entry.getChecksum(), directory, checksumFile);
}
else
{
String checksum = Files.toString(checksumFile, Charsets.UTF_8).trim();
if (checksum.equals(entry.getChecksum()))
{
logger.debug("plugin {} is up to date", id);
}
else
{
logger.warn("checksum mismatch of pluing {}, start update", id);
extract(archive, entry.getChecksum(), directory, checksumFile);
}
}
}
@@ -186,27 +259,19 @@ public class BootstrapContextListener implements ServletContextListener
* @param context
* @param pluginDirectory
* @param lines
* @param index
*
* @throws IOException
*/
private void copyCorePlugins(ServletContext context, File pluginDirectory,
List<String> lines)
private void extractCorePlugins(ServletContext context, File pluginDirectory,
PluginIndex index)
throws IOException
{
IOUtil.mkdirs(pluginDirectory);
for (String line : lines)
for (PluginIndexEntry entry : index)
{
line = line.trim();
if (!Strings.isNullOrEmpty(line))
{
try
{
copyCorePlugin(context, pluginDirectory, line);
}
catch (IOException ex)
{
logger.error("could not copy core plugin", ex);
}
}
extractCorePlugin(context, pluginDirectory, entry);
}
}
@@ -218,27 +283,31 @@ public class BootstrapContextListener implements ServletContextListener
*
* @return
*/
private List<String> readCorePluginIndex(ServletContext context)
private PluginIndex readCorePluginIndex(ServletContext context)
{
List<String> lines;
PluginIndex index = null;
try
{
URL index = context.getResource(PLUGIN_COREINDEX);
URL indexUrl = context.getResource(PLUGIN_COREINDEX);
if (index == null)
if (indexUrl == null)
{
throw new PluginException("no core plugin index found");
}
lines = Resources.readLines(index, Charsets.UTF_8);
index = JAXB.unmarshal(indexUrl, PluginIndex.class);
}
catch (IOException ex)
catch (MalformedURLException ex)
{
throw new PluginException("could not load core plugin index", ex);
}
catch (DataBindingException ex)
{
throw new PluginException("could not unmarshall core plugin index", ex);
}
return lines;
return index;
}
//~--- get methods ----------------------------------------------------------
@@ -256,6 +325,102 @@ public class BootstrapContextListener implements ServletContextListener
return new File(baseDirectory, DIRECTORY_PLUGINS);
}
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 14/07/09
* @author Enter your name here...
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "plugin-index")
private static class PluginIndex implements Iterable<PluginIndexEntry>
{
/**
* Method description
*
*
* @return
*/
@Override
public Iterator<PluginIndexEntry> iterator()
{
return getPlugins().iterator();
}
//~--- get methods --------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public List<PluginIndexEntry> getPlugins()
{
if (plugins == null)
{
plugins = ImmutableList.of();
}
return plugins;
}
//~--- fields -------------------------------------------------------------
/** Field description */
@XmlElement(name = "plugins")
private List<PluginIndexEntry> plugins;
}
/**
* Class description
*
*
* @version Enter version here..., 14/07/09
* @author Enter your name here...
*/
@XmlRootElement(name = "plugins")
@XmlAccessorType(XmlAccessType.FIELD)
private static class PluginIndexEntry
{
/**
* Method description
*
*
* @return
*/
public String getChecksum()
{
return checksum;
}
/**
* Method description
*
*
* @return
*/
public String getName()
{
return name;
}
//~--- fields -------------------------------------------------------------
/** Field description */
private String checksum;
/** Field description */
private String name;
}
//~--- fields ---------------------------------------------------------------
/** Field description */

View File

@@ -34,6 +34,7 @@ package sonia.scm.plugin;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
@@ -236,7 +237,7 @@ public final class PluginProcessor
extract(archives);
Set<Path> directories = collect(pluginDirectory, new DirectoryFilter());
Set<Path> directories = collectPluginDirectories(pluginDirectory);
if (logger.isDebugEnabled())
{
@@ -278,6 +279,36 @@ public final class PluginProcessor
return paths;
}
/**
* Method description
*
*
* @param directory
*
* @return
*
* @throws IOException
*/
private Set<Path> collectPluginDirectories(Path directory) throws IOException
{
Builder<Path> paths = ImmutableSet.builder();
Filter<Path> filter = new DirectoryFilter();
try (DirectoryStream<Path> parentStream = stream(directory, filter))
{
for (Path parent : parentStream)
{
try (DirectoryStream<Path> direcotries = stream(parent, filter))
{
paths.addAll(direcotries);
}
}
}
return paths.build();
}
/**
* Method description
*
@@ -381,6 +412,8 @@ public final class PluginProcessor
*/
private void extract(Iterable<Path> archives) throws IOException
{
// TODO use SmpArchive and new path
logger.debug("extract archives");
for (Path archive : archives)

View File

@@ -12,6 +12,7 @@ package sonia.scm.plugin;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import java.io.File;
//~--- JDK imports ------------------------------------------------------------
@@ -56,6 +57,10 @@ public final class Plugins
return processor.collectPlugins(classLoader);
}
public static File createPluginDirectory(File parent, PluginId id){
return new File(new File(parent, id.getGroupId()), id.getArtifactId());
}
/**
* Method description
*