implement WebResourceLoaders for loading plugin web resources

This commit is contained in:
Sebastian Sdorra
2014-08-27 21:01:05 +02:00
parent ad686cb787
commit a3be1c775b
15 changed files with 1029 additions and 79 deletions

View File

@@ -38,6 +38,7 @@ package sonia.scm.plugin;
import com.google.inject.Binder;
import com.google.inject.Module;
//~--- JDK imports ------------------------------------------------------------
import java.util.Collection;
@@ -81,13 +82,23 @@ public interface PluginLoader
*
* @return
*/
public Collection<Plugin> getInstalledPlugins();
public Collection<PluginWrapper> getInstalledPlugins();
/**
* Method description
* Returns a {@link ClassLoader} which is able to load classes and resources
* from the webapp and all installed plugins.
*
*
* @return
* @return uber classloader
*/
public ClassLoader getUberClassLoader();
/**
* Returns a {@link WebResourceLoader} which is able to load web resources
* from the webapp and all installed plugins.
*
*
* @return uber webresourceloader
*/
public UberWebResourceLoader getUberWebResourceLoader();
}

View File

@@ -36,8 +36,8 @@ package sonia.scm.plugin;
import java.nio.file.Path;
/**
* Wrapper for a {@link Plugin}. The wrapper holds the directory and the
* {@link ClassLoader}, which is able to load plugin classes.
* Wrapper for a {@link Plugin}. The wrapper holds the directory,
* {@link ClassLoader} and {@link WebResourceLoader} of a plugin.
*
* @author Sebastian Sdorra
* @since 2.0.0
@@ -50,12 +50,15 @@ public final class PluginWrapper
*
* @param plugin wrapped plugin
* @param classLoader plugin class loader
* @param webResourceLoader web resource loader
* @param directory plugin directory
*/
public PluginWrapper(Plugin plugin, ClassLoader classLoader, Path directory)
public PluginWrapper(Plugin plugin, ClassLoader classLoader,
WebResourceLoader webResourceLoader, Path directory)
{
this.plugin = plugin;
this.classLoader = classLoader;
this.webResourceLoader = webResourceLoader;
this.directory = directory;
}
@@ -105,6 +108,17 @@ public final class PluginWrapper
return plugin;
}
/**
* Returns the {@link WebResourceLoader} for this plugin.
*
*
* @return web resource loader
*/
public WebResourceLoader getWebResourceLoader()
{
return webResourceLoader;
}
//~--- fields ---------------------------------------------------------------
/** plugin class loader */
@@ -115,4 +129,7 @@ public final class PluginWrapper
/** plugin */
private final Plugin plugin;
/** plugin web resource loader */
private final WebResourceLoader webResourceLoader;
}

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.plugin;
//~--- JDK imports ------------------------------------------------------------
import java.net.URL;
import java.util.List;
import javax.servlet.ServletContext;
/**
* Load resources from {@link ServletContext} and from the installed plugins.
* The UberWebResourceLoader will first look into the {@link ServletContext} and
* afterwards it will search the plugin directories.
*
* @author Sebastian Sdorra
* @since 2.0.0
*/
public interface UberWebResourceLoader extends WebResourceLoader
{
/**
* Returns all {@link URL} objects for the given path. The method will collect
* all resources from {@link ServletContext} and all plugin directories which
* matches the given path. The method will return an empty list, if no url
* could be found for the given path.
*
* @param path resource path
*
* @return list of url objects for the given path
*/
public List<URL> getResources(String path);
}

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.plugin;
//~--- JDK imports ------------------------------------------------------------
import java.net.URL;
import javax.servlet.ServletContext;
/**
* The WebResourceLoader is able to load web resources. The resources are loaded
* from a plugin webapp directory or from the {@link ServletContext}, according
* to its implementation. The {@link UberWebResourceLoader} is able to load
* resources from the {@link ServletContext} and all plugin directories.
*
* @author Sebastian Sdorra
* @since 2.0.0
*/
public interface WebResourceLoader
{
/**
* Returns a {@link URL} for the given path. The method will return null if no
* resources could be found for the given path.
*
* @param path resource path
*
* @return url object for the given path or null
*/
public URL getResource(String path);
}

View File

@@ -95,8 +95,8 @@ public enum ResourceType
//~--- fields ---------------------------------------------------------------
/** Field description */
private String contentType;
private final String contentType;
/** Field description */
private String extension;
private final String extension;
}

View File

@@ -209,7 +209,8 @@ public class ScmContextListener extends GuiceServletContextListener
*/
private Injector getDefaultInjector(ServletContext servletCtx)
{
DefaultPluginLoader pluginLoader = new DefaultPluginLoader(parent, plugins);
DefaultPluginLoader pluginLoader = new DefaultPluginLoader(servletCtx,
parent, plugins);
ClassOverrides overrides =
ClassOverrides.findOverrides(pluginLoader.getUberClassLoader());

View File

@@ -56,6 +56,8 @@ import java.util.Collection;
import java.util.Enumeration;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
@@ -81,13 +83,17 @@ public class DefaultPluginLoader implements PluginLoader
/**
* Constructs ...
*
* @param servletContext
* @param parent
* @param wrappedPlugins
* @param installedPlugins
*/
public DefaultPluginLoader(ClassLoader parent,
Set<PluginWrapper> wrappedPlugins)
public DefaultPluginLoader(ServletContext servletContext, ClassLoader parent,
Set<PluginWrapper> installedPlugins)
{
this.uberClassLoader = new UberClassLoader(parent, wrappedPlugins);
this.installedPlugins = installedPlugins;
this.uberClassLoader = new UberClassLoader(parent, installedPlugins);
this.uberWebResourceLoader =
new DefaultUberWebResourceLoader(servletContext, installedPlugins);
try
{
@@ -96,16 +102,8 @@ public class DefaultPluginLoader implements PluginLoader
modules = getInstalled(parent, context, PATH_MODULECONFIG);
// hidden plugins ???
Set<Plugin> ips = getInstalled(parent, context, PATH_PLUGINCONFIG);
Builder<Plugin> builder = ImmutableSet.builder();
builder.addAll(ips);
builder.addAll(PluginsInternal.unwrap(wrappedPlugins));
plugins = builder.build();
appendExtensions(multiple, single, extensions, modules);
appendExtensions(multiple, single, extensions, plugins);
appendExtensions(multiple, single, extensions, unwrap());
}
catch (IOException | JAXBException ex)
{
@@ -127,7 +125,7 @@ public class DefaultPluginLoader implements PluginLoader
logger.info("start processing extensions");
appendExtensions(multiple, single, extensions, modules);
appendExtensions(multiple, single, extensions, plugins);
appendExtensions(multiple, single, extensions, unwrap());
if (logger.isInfoEnabled())
{
@@ -173,9 +171,9 @@ public class DefaultPluginLoader implements PluginLoader
* @return
*/
@Override
public Collection<Plugin> getInstalledPlugins()
public Collection<PluginWrapper> getInstalledPlugins()
{
return plugins;
return installedPlugins;
}
/**
@@ -190,6 +188,18 @@ public class DefaultPluginLoader implements PluginLoader
return uberClassLoader;
}
/**
* Method description
*
*
* @return
*/
@Override
public UberWebResourceLoader getUberWebResourceLoader()
{
return uberWebResourceLoader;
}
//~--- methods --------------------------------------------------------------
/**
@@ -242,6 +252,17 @@ public class DefaultPluginLoader implements PluginLoader
}
}
/**
* Method description
*
*
* @return
*/
private Iterable<Plugin> unwrap()
{
return PluginsInternal.unwrap(installedPlugins);
}
//~--- get methods ----------------------------------------------------------
/**
@@ -282,15 +303,18 @@ public class DefaultPluginLoader implements PluginLoader
/** Field description */
private final ClassLoader uberClassLoader;
/** Field description */
private final UberWebResourceLoader uberWebResourceLoader;
/** Field description */
private Set<PluginWrapper> installedPlugins;
/** Field description */
private Set<ScmModule> modules;
/** Field description */
private Set<Class> multiple = Sets.newHashSet();
/** Field description */
private Set<Plugin> plugins;
/** Field description */
private Set<Class> single = Sets.newHashSet();

View File

@@ -98,10 +98,6 @@ public class DefaultPluginManager implements PluginManager
/** Field description */
public static final String ENCODING = "UTF-8";
/** Field description */
private static final String ADVANCED_CONFIGURATION =
"advanced-configuration.xml";
/** the logger for DefaultPluginManager */
private static final Logger logger =
LoggerFactory.getLogger(DefaultPluginManager.class);
@@ -133,10 +129,11 @@ public class DefaultPluginManager implements PluginManager
this.configuration = configuration;
this.cache = cacheManager.getCache(CACHE_NAME);
this.clientProvider = clientProvider;
installedPlugins = new HashMap<String, Plugin>();
installedPlugins = new HashMap<>();
for (Plugin plugin : pluginLoader.getInstalledPlugins())
for (PluginWrapper wrapper : pluginLoader.getInstalledPlugins())
{
Plugin plugin = wrapper.getPlugin();
PluginInformation info = plugin.getInformation();
if ((info != null) && info.isValid())
@@ -247,15 +244,17 @@ public class DefaultPluginManager implements PluginManager
throw new PluginConditionFailedException(condition);
}
/*AetherPluginHandler aph = new AetherPluginHandler(this, context,
configuration);
Collection<PluginRepository> repositories =
Sets.newHashSet(new PluginRepository("package-repository",
"file://".concat(tempDirectory.getAbsolutePath())));
aph.setPluginRepositories(repositories);
aph.install(plugin.getInformation().getId());*/
/*
* AetherPluginHandler aph = new AetherPluginHandler(this, context,
* configuration);
* Collection<PluginRepository> repositories =
* Sets.newHashSet(new PluginRepository("package-repository",
* "file://".concat(tempDirectory.getAbsolutePath())));
*
* aph.setPluginRepositories(repositories);
*
* aph.install(plugin.getInformation().getId());
*/
plugin.getInformation().setState(PluginState.INSTALLED);
installedPlugins.put(plugin.getInformation().getId(), plugin);
@@ -300,12 +299,14 @@ public class DefaultPluginManager implements PluginManager
throw new PluginNotInstalledException(id.concat(" is not install"));
}
/*if (pluginHandler == null)
{
getPluginCenter();
}
pluginHandler.uninstall(id);*/
/*
* if (pluginHandler == null)
* {
* getPluginCenter();
* }
*
* pluginHandler.uninstall(id);
*/
installedPlugins.remove(id);
preparePlugins(getPluginCenter());
}
@@ -394,7 +395,7 @@ public class DefaultPluginManager implements PluginManager
AssertUtil.assertIsNotNull(predicate);
SecurityUtil.assertIsAdmin();
Set<PluginInformation> infoSet = new HashSet<PluginInformation>();
Set<PluginInformation> infoSet = new HashSet<>();
filter(infoSet, getInstalled(), predicate);
filter(infoSet, getPluginCenter().getPlugins(), predicate);
@@ -431,7 +432,7 @@ public class DefaultPluginManager implements PluginManager
{
SecurityUtil.assertIsAdmin();
Set<PluginInformation> availablePlugins = new HashSet<PluginInformation>();
Set<PluginInformation> availablePlugins = new HashSet<>();
Set<PluginInformation> centerPlugins = getPluginCenter().getPlugins();
for (PluginInformation info : centerPlugins)
@@ -470,7 +471,7 @@ public class DefaultPluginManager implements PluginManager
{
SecurityUtil.assertIsAdmin();
Set<PluginInformation> infoSet = new LinkedHashSet<PluginInformation>();
Set<PluginInformation> infoSet = new LinkedHashSet<>();
for (Plugin plugin : installedPlugins.values())
{
@@ -642,16 +643,18 @@ public class DefaultPluginManager implements PluginManager
preparePlugins(center);
cache.put(PluginCenter.class.getName(), center);
/*if (pluginHandler == null)
{
pluginHandler = new AetherPluginHandler(this,
SCMContext.getContext(), configuration,
advancedPluginConfiguration);
}
pluginHandler.setPluginRepositories(center.getRepositories());*/
/*
* if (pluginHandler == null)
* {
* pluginHandler = new AetherPluginHandler(this,
* SCMContext.getContext(), configuration,
* advancedPluginConfiguration);
* }
*
* pluginHandler.setPluginRepositories(center.getRepositories());
*/
}
catch (Exception ex)
catch (IOException | JAXBException ex)
{
logger.error("could not load plugins from plugin center", ex);
}

View File

@@ -0,0 +1,231 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.plugin;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//~--- JDK imports ------------------------------------------------------------
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import javax.servlet.ServletContext;
/**
* Default implementation of the {@link UberWebResourceLoader}.
*
* @author Sebastian Sdorra
* @since 2.0.0
*/
public class DefaultUberWebResourceLoader implements UberWebResourceLoader
{
/**
* the logger for DefaultUberWebResourceLoader
*/
private static final Logger logger =
LoggerFactory.getLogger(DefaultUberWebResourceLoader.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param servletContext
* @param plugins
*/
public DefaultUberWebResourceLoader(ServletContext servletContext,
Iterable<PluginWrapper> plugins)
{
this.servletContext = servletContext;
this.plugins = plugins;
this.cache = CacheBuilder.newBuilder().build();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param path
*
* @return
*/
@Override
public URL getResource(String path)
{
URL resource = cache.getIfPresent(path);
if (resource == null)
{
resource = find(path);
if (resource != null)
{
cache.put(path, resource);
}
}
else
{
logger.trace("return web resource {} from cache", path);
}
return resource;
}
/**
* Method description
*
*
* @param path
*
* @return
*/
@Override
public List<URL> getResources(String path)
{
// caching ???
Builder<URL> resources = ImmutableList.builder();
try
{
URL ctxResource = servletContext.getResource(path);
if (ctxResource != null)
{
logger.trace("found path {} at ServletContext", path);
resources.add(ctxResource);
}
for (PluginWrapper wrapper : plugins)
{
URL resource = wrapper.getWebResourceLoader().getResource(path);
if (resource != null)
{
resources.add(resource);
}
}
}
catch (MalformedURLException ex)
{
// TODO define an extra exception
throw Throwables.propagate(ex);
}
return resources.build();
}
/**
* Method description
*
*
* @return
*/
@VisibleForTesting
Cache<String, URL> getCache()
{
return cache;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param path
*
* @return
*/
private URL find(String path)
{
URL resource = null;
try
{
resource = servletContext.getResource(path);
if (resource == null)
{
for (PluginWrapper wrapper : plugins)
{
resource = wrapper.getWebResourceLoader().getResource(path);
if (resource != null)
{
break;
}
}
}
else
{
logger.trace("found path {} at ServletContext", path);
}
}
catch (MalformedURLException ex)
{
// TODO define an extra exception
throw Throwables.propagate(ex);
}
return resource;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final Cache<String, URL> cache;
/** Field description */
private final Iterable<PluginWrapper> plugins;
/** Field description */
private final ServletContext servletContext;
}

View File

@@ -0,0 +1,162 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.plugin;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* Load web resources from a plugin webapp directory.
*
* @author Sebastian Sdorra
* @since 2.0.0
*/
public class PathWebResourceLoader implements WebResourceLoader
{
/** Field description */
private static final String DEFAULT_SEPARATOR = "/";
/**
* the logger for PathWebResourceLoader
*/
private static final Logger logger =
LoggerFactory.getLogger(PathWebResourceLoader.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param directory
*/
public PathWebResourceLoader(Path directory)
{
this.directory = directory;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param path
*
* @return
*/
@Override
public URL getResource(String path)
{
URL resource = null;
Path file = directory.resolve(filePath(path));
if (Files.exists(file))
{
logger.trace("found path {} at {}", path, file);
try
{
resource = file.toUri().toURL();
}
catch (MalformedURLException ex)
{
logger.error("could not transform path to url", ex);
}
}
return resource;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param path
*
* @return
*/
private String filePath(String path)
{
// TODO handle illegal path parts, such as ..
String filePath = filePath(DEFAULT_SEPARATOR, path);
if (!DEFAULT_SEPARATOR.equals(File.separator))
{
filePath = filePath(File.separator, path);
}
return filePath;
}
/**
* Method description
*
*
* @param separator
* @param path
*
* @return
*/
private String filePath(String separator, String path)
{
String filePath = path;
if (filePath.startsWith(separator))
{
filePath = filePath.substring(separator.length());
}
return filePath;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final Path directory;
}

View File

@@ -491,7 +491,8 @@ public final class PluginProcessor
throws IOException
{
PluginWrapper wrapper = null;
Path descriptor = smp.getPath().resolve(PluginConstants.FILE_DESCRIPTOR);
Path directory = smp.getPath();
Path descriptor = directory.resolve(PluginConstants.FILE_DESCRIPTOR);
if (Files.exists(descriptor))
{
@@ -499,7 +500,8 @@ public final class PluginProcessor
Plugin plugin = createPlugin(cl, descriptor);
wrapper = new PluginWrapper(plugin, cl, smp.getPath());
wrapper = new PluginWrapper(plugin, cl,
new PathWebResourceLoader(directory), directory);
}
else
{

View File

@@ -51,6 +51,7 @@ import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.ServletContext;
import sonia.scm.plugin.PluginWrapper;
/**
*
@@ -117,7 +118,7 @@ public abstract class AbstractResourceManager implements ResourceManager
@Override
public List<Resource> getResources(ResourceType type)
{
List<Resource> resources = new ArrayList<Resource>();
List<Resource> resources = new ArrayList<>();
for (Entry<ResourceKey, Resource> e : resourceMap.entrySet())
{
@@ -140,14 +141,14 @@ public abstract class AbstractResourceManager implements ResourceManager
*/
protected List<String> getScriptResources()
{
List<String> resources = new ArrayList<String>();
Collection<Plugin> plugins = pluginLoader.getInstalledPlugins();
List<String> resources = new ArrayList<>();
Collection<PluginWrapper> wrappers = pluginLoader.getInstalledPlugins();
if (plugins != null)
if (wrappers != null)
{
for (Plugin plugin : plugins)
for (PluginWrapper plugin : wrappers)
{
processPlugin(resources, plugin);
processPlugin(resources, plugin.getPlugin());
}
}
@@ -235,12 +236,7 @@ public abstract class AbstractResourceManager implements ResourceManager
return false;
}
if (this.type != other.type)
{
return false;
}
return true;
return this.type == other.type;
}
/**
@@ -291,10 +287,10 @@ public abstract class AbstractResourceManager implements ResourceManager
//~--- fields -------------------------------------------------------------
/** Field description */
private String name;
private final String name;
/** Field description */
private ResourceType type;
private final ResourceType type;
}
@@ -307,8 +303,7 @@ public abstract class AbstractResourceManager implements ResourceManager
protected Set<ResourceHandler> resourceHandlers;
/** Field description */
protected Map<ResourceKey, Resource> resourceMap = new HashMap<ResourceKey,
Resource>();
protected Map<ResourceKey, Resource> resourceMap = new HashMap<>();
/** Field description */
protected ServletContext servletContext;

View File

@@ -0,0 +1,216 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.plugin;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.collect.Lists;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultUberWebResourceLoaderTest extends WebResourceLoaderTestBase
{
/** Field description */
private static URL BITBUCKET;
/** Field description */
private static URL GITHUB;
/** Field description */
private static URL SCM_MANAGER;
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @throws MalformedURLException
*/
@BeforeClass
public static void prepare() throws MalformedURLException
{
SCM_MANAGER = new URL("https://www.scm-manager.org");
BITBUCKET = new URL("https://bitbucket.org");
GITHUB = new URL("https://github.com");
}
/**
* Method description
*
*
* @throws MalformedURLException
*/
@Test
public void testGetResourceFromCache() throws MalformedURLException
{
when(servletContext.getResource("/myresource")).thenReturn(SCM_MANAGER);
DefaultUberWebResourceLoader resourceLoader =
new DefaultUberWebResourceLoader(servletContext,
new ArrayList<PluginWrapper>());
resourceLoader.getCache().put("/myresource", GITHUB);
URL resource = resourceLoader.getResource("/myresource");
assertSame(GITHUB, resource);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testGetResourceFromDirectory() throws IOException
{
File directory = temp.newFolder();
File file = file(directory, "myresource");
PluginWrapper wrapper = createPluginWrapper(directory);
List<PluginWrapper> plugins = Lists.newArrayList(wrapper);
WebResourceLoader resourceLoader =
new DefaultUberWebResourceLoader(servletContext, plugins);
assertEquals(file.toURI().toURL(),
resourceLoader.getResource("/myresource"));
}
/**
* Method description
*
* @throws MalformedURLException
*/
@Test
public void testGetResourceFromServletContext() throws MalformedURLException
{
when(servletContext.getResource("/myresource")).thenReturn(SCM_MANAGER);
WebResourceLoader resourceLoader =
new DefaultUberWebResourceLoader(servletContext,
new ArrayList<PluginWrapper>());
URL resource = resourceLoader.getResource("/myresource");
assertSame(SCM_MANAGER, resource);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testGetResources() throws IOException
{
when(servletContext.getResource("/myresource")).thenReturn(BITBUCKET);
File directory = temp.newFolder();
File file = file(directory, "myresource");
PluginWrapper wrapper = createPluginWrapper(directory);
List<PluginWrapper> plugins = Lists.newArrayList(wrapper);
UberWebResourceLoader resourceLoader =
new DefaultUberWebResourceLoader(servletContext, plugins);
assertThat(resourceLoader.getResources("/myresource"),
containsInAnyOrder(file.toURI().toURL(), BITBUCKET));
}
/**
* Method description
*
*
* @param directory
*
* @return
*/
private PluginWrapper createPluginWrapper(File directory)
{
return createPluginWrapper(directory.toPath());
}
/**
* Method description
*
*
* @param directory
*
* @return
*/
private PluginWrapper createPluginWrapper(Path directory)
{
return new PluginWrapper(null, null, new PathWebResourceLoader(directory),
directory);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@Mock
private ServletContext servletContext;
}

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.plugin;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
*
* @author Sebastian Sdorra
*/
public class PathWebResourceLoaderTest extends WebResourceLoaderTestBase
{
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testGetResource() throws IOException
{
File directory = temp.newFolder();
URL url = file(directory, "myresource").toURI().toURL();
WebResourceLoader resourceLoader =
new PathWebResourceLoader(directory.toPath());
assertEquals(url, resourceLoader.getResource("/myresource"));
assertEquals(url, resourceLoader.getResource("myresource"));
assertNull(resourceLoader.getResource("other"));
}
//~--- fields ---------------------------------------------------------------
}

View File

@@ -0,0 +1,83 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.plugin;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
/**
*
* @author Sebastian Sdorra
*/
public abstract class WebResourceLoaderTestBase
{
/**
* Method description
*
*
* @param directory
* @param path
*
* @return
*
* @throws IOException
*/
protected File file(File directory, String path) throws IOException
{
IOUtil.mkdirs(directory);
File file = new File(directory, path);
Files.append("a", file, Charsets.UTF_8);
return file;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@Rule
public TemporaryFolder temp = new TemporaryFolder();
}