diff --git a/scm-webapp/src/main/java/sonia/scm/BindingExtensionProcessor.java b/scm-webapp/src/main/java/sonia/scm/BindingExtensionProcessor.java index f9a25c2c6a..1f26f683ed 100644 --- a/scm-webapp/src/main/java/sonia/scm/BindingExtensionProcessor.java +++ b/scm-webapp/src/main/java/sonia/scm/BindingExtensionProcessor.java @@ -47,7 +47,6 @@ import sonia.scm.plugin.ext.ExtensionProcessor; import sonia.scm.repository.RepositoryHandler; import sonia.scm.security.EncryptionHandler; import sonia.scm.web.security.AuthenticationHandler; -import sonia.scm.web.security.AuthenticationManager; import sonia.scm.web.security.XmlAuthenticationHandler; //~--- JDK imports ------------------------------------------------------------ @@ -119,7 +118,8 @@ public class BindingExtensionProcessor implements ExtensionProcessor { if (logger.isInfoEnabled()) { - logger.info("bind AuthenticationHandler {}", extensionClass.getName()); + logger.info("bind AuthenticationHandler {}", + extensionClass.getName()); } binder.bind(extensionClass); diff --git a/scm-webapp/src/main/java/sonia/scm/ContextListener.java b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java similarity index 98% rename from scm-webapp/src/main/java/sonia/scm/ContextListener.java rename to scm-webapp/src/main/java/sonia/scm/ScmContextListener.java index a362e9ce37..bc1110604f 100644 --- a/scm-webapp/src/main/java/sonia/scm/ContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java @@ -59,7 +59,7 @@ import javax.servlet.ServletContextEvent; * * @author Sebastian Sdorra */ -public class ContextListener extends GuiceServletContextListener +public class ScmContextListener extends GuiceServletContextListener { /** diff --git a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapFilter.java b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapFilter.java new file mode 100644 index 0000000000..7ece6b4954 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapFilter.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2010, 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.boot; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +/** + * + * @author Sebastian Sdorra + */ +public class BootstrapFilter implements Filter +{ + + /** Field description */ + public static final String FILTER = "com.google.inject.servlet.GuiceFilter"; + + /** the logger for BootstrapFilter */ + private static final Logger logger = + LoggerFactory.getLogger(BootstrapFilter.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + */ + @Override + public void destroy() + { + if (classLoader != null) + { + Thread.currentThread().setContextClassLoader(classLoader); + } + + guiceFilter.destroy(); + } + + /** + * Method description + * + * + * @param request + * @param response + * @param chain + * + * @throws IOException + * @throws ServletException + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) + throws IOException, ServletException + { + if (classLoader != null) + { + Thread.currentThread().setContextClassLoader(classLoader); + } + + guiceFilter.doFilter(request, response, chain); + } + + /** + * Method description + * + * + * @param filterConfig + * + * @throws ServletException + */ + @Override + public void init(FilterConfig filterConfig) throws ServletException + { + classLoader = + BootstrapUtil.getClassLoader(filterConfig.getServletContext()); + + if (classLoader != null) + { + logger.info("loading GuiceFilter with ScmBootstrapClassLoader"); + Thread.currentThread().setContextClassLoader(classLoader); + guiceFilter = BootstrapUtil.loadClass(classLoader, Filter.class, FILTER); + } + + if (guiceFilter == null) + { + logger.info("fallback to default classloader for GuiceFilter"); + guiceFilter = BootstrapUtil.loadClass(Filter.class, FILTER); + } + + guiceFilter.init(filterConfig); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private ClassLoader classLoader; + + /** Field description */ + private Filter guiceFilter; +} diff --git a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java new file mode 100644 index 0000000000..a6ece57fe9 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java @@ -0,0 +1,206 @@ +/** + * Copyright (c) 2010, 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.boot; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.SCMContext; +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; + +import java.net.URL; +import java.net.URLClassLoader; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * + * @author Sebastian Sdorra + */ +public class BootstrapListener implements ServletContextListener +{ + + /** Field description */ + public static final String LISTENER = "sonia.scm.ScmContextListener"; + + /** Field description */ + public static final String PLUGIN_DIRECTORY = "plugins"; + + /** the logger for BootstrapListener */ + private static final Logger logger = + LoggerFactory.getLogger(BootstrapListener.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param sce + */ + @Override + public void contextDestroyed(ServletContextEvent sce) + { + if (scmContextListener != null) + { + scmContextListener.contextDestroyed(sce); + } + } + + /** + * Method description + * + * + * @param sce + */ + @Override + public void contextInitialized(ServletContextEvent sce) + { + ClassLoader classLoader = null; + File pluginDirectory = new File(SCMContext.getContext().getBaseDirectory(), + PLUGIN_DIRECTORY); + + if (pluginDirectory.exists()) + { + try + { + File[] jarFiles = pluginDirectory.listFiles(new JarFilenameFilter()); + + if (Util.isNotEmpty(jarFiles)) + { + int size = jarFiles.length; + URL[] urls = new URL[size]; + + for (int i = 0; i < size; i++) + { + urls[i] = jarFiles[i].toURI().toURL(); + + if (logger.isDebugEnabled()) + { + logger.debug("added jar {} to classpath", + urls[i].toExternalForm()); + } + } + + classLoader = new URLClassLoader(urls, getParentClassLoader()); + } + } + catch (IOException ex) + { + logger.error(ex.getMessage(), ex); + } + } + + if (classLoader != null) + { + logger.info("try to use ScmBootstrapClassLoader"); + scmContextListener = BootstrapUtil.loadClass(classLoader, + ServletContextListener.class, LISTENER); + Thread.currentThread().setContextClassLoader(classLoader); + BootstrapUtil.setClassLoader(sce.getServletContext(), classLoader); + } + + if (scmContextListener == null) + { + logger.warn("fallback to default classloader"); + scmContextListener = + BootstrapUtil.loadClass(ServletContextListener.class, LISTENER); + } + + scmContextListener.contextInitialized(sce); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + private ClassLoader getParentClassLoader() + { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + + if (classLoader == null) + { + classLoader = BootstrapListener.class.getClassLoader(); + } + + return classLoader; + } + + //~--- inner classes -------------------------------------------------------- + + /** + * Class description + * + * + * @version Enter version here..., 2010-12-09 + * @author Sebastian Sdorra + */ + private static class JarFilenameFilter implements FilenameFilter + { + + /** + * Method description + * + * + * @param file + * @param name + * + * @return + */ + @Override + public boolean accept(File file, String name) + { + return name.endsWith(".jar"); + } + } + + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private ServletContextListener scmContextListener; +} diff --git a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapUtil.java b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapUtil.java new file mode 100644 index 0000000000..f7cf02cd94 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapUtil.java @@ -0,0 +1,171 @@ +/** + * Copyright (c) 2010, 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.boot; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +//~--- JDK imports ------------------------------------------------------------ + +import javax.servlet.ServletContext; + +/** + * + * @author Sebastian Sdorra + */ +public class BootstrapUtil +{ + + /** Field description */ + public static final String CLASSLOADER = "sonia.scm.BoostrapClassLoader"; + + /** the logger for BootstrapUtil */ + private static final Logger logger = + LoggerFactory.getLogger(BootstrapUtil.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param classLoader + * @param clazz + * @param + * + * @return + */ + public static T loadClass(ClassLoader classLoader, Class clazz) + { + T instance = null; + + try + { + instance = (T) classLoader.loadClass(clazz.getName()).newInstance(); + } + catch (Exception ex) + { + logger.error(ex.getMessage(), ex); + } + + return instance; + } + + /** + * Method description + * + * + * @param classLoader + * @param clazz + * @param className + * @param + * + * @return + */ + public static T loadClass(ClassLoader classLoader, Class clazz, + String className) + { + T instance = null; + + try + { + instance = (T) classLoader.loadClass(className).newInstance(); + } + catch (Exception ex) + { + logger.error(ex.getMessage(), ex); + } + + return instance; + } + + /** + * Method description + * + * + * + * @param clazz + * @param className + * @param + * + * @return + */ + public static T loadClass(Class clazz, String className) + { + T instance = null; + + try + { + instance = (T) Class.forName(className).newInstance(); + } + catch (Exception ex) + { + logger.error(ex.getMessage(), ex); + } + + return instance; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param context + * + * @return + */ + public static ClassLoader getClassLoader(ServletContext context) + { + return (ClassLoader) context.getAttribute(CLASSLOADER); + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param context + * @param classLoader + */ + public static void setClassLoader(ServletContext context, + ClassLoader classLoader) + { + context.setAttribute(CLASSLOADER, classLoader); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/ScriptResourceServlet.java b/scm-webapp/src/main/java/sonia/scm/plugin/ScriptResourceServlet.java index 837d5e24f5..e9c4a4b41a 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/ScriptResourceServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/ScriptResourceServlet.java @@ -38,6 +38,7 @@ package sonia.scm.plugin; import com.google.inject.Inject; import com.google.inject.Singleton; +import sonia.scm.boot.BootstrapUtil; import sonia.scm.util.IOUtil; import sonia.scm.util.Util; @@ -140,7 +141,7 @@ public class ScriptResourceServlet extends AbstractResourceServlet private void appendResource(OutputStream stream, String script) throws ServletException, IOException { - InputStream input = ScriptResourceServlet.class.getResourceAsStream(script); + InputStream input = getResourceAsStream(script); if (input != null) { @@ -179,6 +180,39 @@ public class ScriptResourceServlet extends AbstractResourceServlet //~--- get methods ---------------------------------------------------------- + /** + * Method description + * + * + * @param resource + * + * @return + */ + private InputStream getResourceAsStream(String resource) + { + InputStream input = null; + ClassLoader classLoader = BootstrapUtil.getClassLoader(getServletContext()); + + if (classLoader != null) + { + String classLoaderResource = resource; + + if (classLoaderResource.startsWith("/")) + { + classLoaderResource = classLoaderResource.substring(1); + } + + input = classLoader.getResourceAsStream(classLoaderResource); + } + + if (input == null) + { + input = ScriptResourceServlet.class.getResourceAsStream(resource); + } + + return input; + } + /** * Method description * diff --git a/scm-webapp/src/main/webapp/WEB-INF/web.xml b/scm-webapp/src/main/webapp/WEB-INF/web.xml index 05233344e1..964b355aca 100644 --- a/scm-webapp/src/main/webapp/WEB-INF/web.xml +++ b/scm-webapp/src/main/webapp/WEB-INF/web.xml @@ -36,28 +36,26 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> - - sonia.scm.ContextListener - + + sonia.scm.boot.BootstrapListener + - - guiceFilter - com.google.inject.servlet.GuiceFilter - + + guiceFilter + sonia.scm.boot.BootstrapFilter + - - guiceFilter - /* - + + guiceFilter + /* + - - index.html - - - - - 30 - - + + index.html + + + 30 + +