2020-03-23 15:35:58 +01:00
|
|
|
/*
|
|
|
|
|
* MIT License
|
2014-08-27 21:01:05 +02:00
|
|
|
*
|
2020-03-23 15:35:58 +01:00
|
|
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
2014-08-27 21:01:05 +02:00
|
|
|
*
|
2020-03-23 15:35:58 +01:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2014-08-27 21:01:05 +02:00
|
|
|
*
|
2020-03-23 15:35:58 +01:00
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
* copies or substantial portions of the Software.
|
2014-08-27 21:01:05 +02:00
|
|
|
*
|
2020-03-23 15:35:58 +01:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
* SOFTWARE.
|
2014-08-27 21:01:05 +02:00
|
|
|
*/
|
2020-03-23 15:35:58 +01:00
|
|
|
|
2014-08-27 21:01:05 +02:00
|
|
|
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;
|
2023-11-29 18:14:03 +01:00
|
|
|
import jakarta.servlet.ServletContext;
|
2014-08-27 21:01:05 +02:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
import org.slf4j.LoggerFactory;
|
2018-10-29 14:55:56 +01:00
|
|
|
import sonia.scm.SCMContext;
|
|
|
|
|
import sonia.scm.Stage;
|
2014-08-27 21:01:05 +02:00
|
|
|
|
|
|
|
|
import java.net.MalformedURLException;
|
2018-08-23 14:48:11 +02:00
|
|
|
import java.net.URISyntaxException;
|
2014-08-27 21:01:05 +02:00
|
|
|
import java.net.URL;
|
2018-08-23 14:48:11 +02:00
|
|
|
import java.nio.file.Files;
|
|
|
|
|
import java.nio.file.Paths;
|
2014-08-27 21:01:05 +02:00
|
|
|
import java.util.List;
|
|
|
|
|
|
2018-08-23 14:48:11 +02:00
|
|
|
//~--- JDK imports ------------------------------------------------------------
|
2014-08-27 21:01:05 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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 ---------------------------------------------------------
|
|
|
|
|
|
2019-08-20 07:54:00 +02:00
|
|
|
public DefaultUberWebResourceLoader(ServletContext servletContext, Iterable<InstalledPlugin> plugins) {
|
2018-10-29 14:55:56 +01:00
|
|
|
this(servletContext, plugins, SCMContext.getContext().getStage());
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 07:54:00 +02:00
|
|
|
public DefaultUberWebResourceLoader(ServletContext servletContext, Iterable<InstalledPlugin> plugins, Stage stage) {
|
2014-08-27 21:01:05 +02:00
|
|
|
this.servletContext = servletContext;
|
|
|
|
|
this.plugins = plugins;
|
2018-10-29 14:55:56 +01:00
|
|
|
this.cache = createCache(stage);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 10:35:51 +01:00
|
|
|
private Cache<String, URL> createCache(Stage stage) {
|
2018-10-29 14:55:56 +01:00
|
|
|
if (stage == Stage.DEVELOPMENT) {
|
2018-11-01 10:35:51 +01:00
|
|
|
return CacheBuilder.newBuilder().maximumSize(0).build(); // Disable caching
|
2018-10-29 14:55:56 +01:00
|
|
|
}
|
|
|
|
|
return CacheBuilder.newBuilder().build();
|
2014-08-27 21:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//~--- get methods ----------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Method description
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param path
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public URL getResource(String path)
|
|
|
|
|
{
|
2018-10-29 14:55:56 +01:00
|
|
|
URL resource = getFromCache(path);
|
2014-08-27 21:01:05 +02:00
|
|
|
|
|
|
|
|
if (resource == null)
|
|
|
|
|
{
|
|
|
|
|
resource = find(path);
|
|
|
|
|
|
|
|
|
|
if (resource != null)
|
|
|
|
|
{
|
2018-10-29 14:55:56 +01:00
|
|
|
addToCache(path, resource);
|
2014-08-27 21:01:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger.trace("return web resource {} from cache", path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resource;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-29 14:55:56 +01:00
|
|
|
private URL getFromCache(String path) {
|
2018-11-01 10:35:51 +01:00
|
|
|
return cache.getIfPresent(path);
|
2018-10-29 14:55:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void addToCache(String path, URL url) {
|
2018-11-01 10:35:51 +01:00
|
|
|
cache.put(path, url);
|
2018-10-29 14:55:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-08-27 21:01:05 +02:00
|
|
|
/**
|
|
|
|
|
* Method description
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param path
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public List<URL> getResources(String path)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// caching ???
|
|
|
|
|
Builder<URL> resources = ImmutableList.builder();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2018-08-23 14:48:11 +02:00
|
|
|
URL ctxResource = nonDirectory(servletContext.getResource(path));
|
2014-08-27 21:01:05 +02:00
|
|
|
|
|
|
|
|
if (ctxResource != null)
|
|
|
|
|
{
|
|
|
|
|
logger.trace("found path {} at ServletContext", path);
|
|
|
|
|
resources.add(ctxResource);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 07:54:00 +02:00
|
|
|
for (InstalledPlugin wrapper : plugins)
|
2014-08-27 21:01:05 +02:00
|
|
|
{
|
2018-08-23 14:48:11 +02:00
|
|
|
URL resource = nonDirectory(wrapper.getWebResourceLoader().getResource(path));
|
2014-08-27 21:01:05 +02:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2018-08-21 15:23:54 +02:00
|
|
|
URL resource;
|
2014-08-27 21:01:05 +02:00
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2018-08-23 14:48:11 +02:00
|
|
|
resource = nonDirectory(servletContext.getResource(path));
|
2014-08-27 21:01:05 +02:00
|
|
|
|
|
|
|
|
if (resource == null)
|
|
|
|
|
{
|
2019-08-20 07:54:00 +02:00
|
|
|
for (InstalledPlugin wrapper : plugins)
|
2014-08-27 21:01:05 +02:00
|
|
|
{
|
2018-08-23 14:48:11 +02:00
|
|
|
resource = nonDirectory(wrapper.getWebResourceLoader().getResource(path));
|
2014-08-27 21:01:05 +02:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-23 14:48:11 +02:00
|
|
|
private URL nonDirectory(URL url) {
|
|
|
|
|
if (url == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isDirectory(url)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return url;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isDirectory(URL url) {
|
|
|
|
|
if ("file".equals(url.getProtocol())) {
|
|
|
|
|
try {
|
|
|
|
|
return Files.isDirectory(Paths.get(url.toURI()));
|
|
|
|
|
} catch (URISyntaxException ex) {
|
|
|
|
|
throw Throwables.propagate(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-27 21:01:05 +02:00
|
|
|
//~--- fields ---------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/** Field description */
|
|
|
|
|
private final Cache<String, URL> cache;
|
|
|
|
|
|
|
|
|
|
/** Field description */
|
2019-08-20 07:54:00 +02:00
|
|
|
private final Iterable<InstalledPlugin> plugins;
|
2014-08-27 21:01:05 +02:00
|
|
|
|
|
|
|
|
/** Field description */
|
|
|
|
|
private final ServletContext servletContext;
|
|
|
|
|
}
|