/src/main/java/com/gitblit/servlet/GitblitContext.java
Java | 511 lines | 319 code | 64 blank | 128 comment | 37 complexity | 730c2d0349870accf4b2012264e2b532 MD5 | raw file
- /*
- * Copyright 2011 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.gitblit.servlet;
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.text.MessageFormat;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Set;
- import javax.naming.Context;
- import javax.naming.InitialContext;
- import javax.naming.NamingException;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletContextEvent;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import com.gitblit.Constants;
- import com.gitblit.FileSettings;
- import com.gitblit.IStoredSettings;
- import com.gitblit.Keys;
- import com.gitblit.WebXmlSettings;
- import com.gitblit.extensions.LifeCycleListener;
- import com.gitblit.guice.CoreModule;
- import com.gitblit.guice.WebModule;
- import com.gitblit.manager.IAuthenticationManager;
- import com.gitblit.manager.IFederationManager;
- import com.gitblit.manager.IFilestoreManager;
- import com.gitblit.manager.IGitblit;
- import com.gitblit.manager.IManager;
- import com.gitblit.manager.INotificationManager;
- import com.gitblit.manager.IPluginManager;
- import com.gitblit.manager.IProjectManager;
- import com.gitblit.manager.IRepositoryManager;
- import com.gitblit.manager.IRuntimeManager;
- import com.gitblit.manager.IServicesManager;
- import com.gitblit.manager.IUserManager;
- import com.gitblit.tickets.ITicketService;
- import com.gitblit.transport.ssh.IPublicKeyManager;
- import com.gitblit.utils.ContainerUtils;
- import com.gitblit.utils.StringUtils;
- import com.google.inject.AbstractModule;
- import com.google.inject.Guice;
- import com.google.inject.Injector;
- import com.google.inject.servlet.GuiceServletContextListener;
- /**
- * This class is the main entry point for the entire webapp. It is a singleton
- * created manually by Gitblit GO or dynamically by the WAR/Express servlet
- * container. This class instantiates and starts all managers.
- *
- * Servlets and filters are injected which allows Gitblit to be completely
- * code-driven.
- *
- * @author James Moger
- *
- */
- public class GitblitContext extends GuiceServletContextListener {
- private static GitblitContext gitblit;
- protected final Logger logger = LoggerFactory.getLogger(getClass());
- private final List<IManager> managers = new ArrayList<IManager>();
- private final IStoredSettings goSettings;
- private final File goBaseFolder;
- /**
- * Construct a Gitblit WAR/Express context.
- */
- public GitblitContext() {
- this(null, null);
- }
- /**
- * Construct a Gitblit GO context.
- *
- * @param settings
- * @param baseFolder
- */
- public GitblitContext(IStoredSettings settings, File baseFolder) {
- this.goSettings = settings;
- this.goBaseFolder = baseFolder;
- gitblit = this;
- }
- /**
- * This method is only used for unit and integration testing.
- *
- * @param managerClass
- * @return a manager
- */
- @SuppressWarnings("unchecked")
- public static <X extends IManager> X getManager(Class<X> managerClass) {
- for (IManager manager : gitblit.managers) {
- if (managerClass.isAssignableFrom(manager.getClass())) {
- return (X) manager;
- }
- }
- return null;
- }
- @Override
- protected Injector getInjector() {
- return Guice.createInjector(getModules());
- }
- /**
- * Returns Gitblit's Guice injection modules.
- */
- protected AbstractModule [] getModules() {
- return new AbstractModule [] { new CoreModule(), new WebModule() };
- }
- /**
- * Configure Gitblit from the web.xml, if no configuration has already been
- * specified.
- *
- * @see ServletContextListener.contextInitialize(ServletContextEvent)
- */
- @Override
- public final void contextInitialized(ServletContextEvent contextEvent) {
- super.contextInitialized(contextEvent);
- ServletContext context = contextEvent.getServletContext();
- startCore(context);
- }
- /**
- * Prepare runtime settings and start all manager instances.
- */
- protected void startCore(ServletContext context) {
- Injector injector = (Injector) context.getAttribute(Injector.class.getName());
- // create the runtime settings object
- IStoredSettings runtimeSettings = injector.getInstance(IStoredSettings.class);
- final File baseFolder;
- if (goSettings != null) {
- // Gitblit GO
- baseFolder = configureGO(context, goSettings, goBaseFolder, runtimeSettings);
- } else {
- // servlet container
- WebXmlSettings webxmlSettings = new WebXmlSettings(context);
- String contextRealPath = context.getRealPath("/");
- File contextFolder = (contextRealPath != null) ? new File(contextRealPath) : null;
- // if the base folder dosen't match the default assume they don't want to use express,
- // this allows for other containers to customise the basefolder per context.
- String defaultBase = Constants.contextFolder$ + "/WEB-INF/data";
- String base = getBaseFolderPath(defaultBase);
- if (!StringUtils.isEmpty(System.getenv("OPENSHIFT_DATA_DIR")) && defaultBase.equals(base)) {
- // RedHat OpenShift
- baseFolder = configureExpress(context, webxmlSettings, contextFolder, runtimeSettings);
- } else {
- // standard WAR
- baseFolder = configureWAR(context, webxmlSettings, contextFolder, runtimeSettings);
- }
- // Test for Tomcat forward-slash/%2F issue and auto-adjust settings
- ContainerUtils.CVE_2007_0450.test(runtimeSettings);
- }
- // Manually configure IRuntimeManager
- logManager(IRuntimeManager.class);
- IRuntimeManager runtime = injector.getInstance(IRuntimeManager.class);
- runtime.setBaseFolder(baseFolder);
- runtime.getStatus().isGO = goSettings != null;
- runtime.getStatus().servletContainer = context.getServerInfo();
- runtime.start();
- managers.add(runtime);
- // create the plugin manager instance but do not start it
- loadManager(injector, IPluginManager.class);
- // start all other managers
- startManager(injector, INotificationManager.class);
- startManager(injector, IUserManager.class);
- startManager(injector, IAuthenticationManager.class);
- startManager(injector, IPublicKeyManager.class);
- startManager(injector, IRepositoryManager.class);
- startManager(injector, IProjectManager.class);
- startManager(injector, IFederationManager.class);
- startManager(injector, ITicketService.class);
- startManager(injector, IGitblit.class);
- startManager(injector, IServicesManager.class);
- startManager(injector, IFilestoreManager.class);
- // start the plugin manager last so that plugins can depend on
- // deterministic access to all other managers in their start() methods
- startManager(injector, IPluginManager.class);
- logger.info("");
- logger.info("All managers started.");
- logger.info("");
- IPluginManager pluginManager = injector.getInstance(IPluginManager.class);
- for (LifeCycleListener listener : pluginManager.getExtensions(LifeCycleListener.class)) {
- try {
- listener.onStartup();
- } catch (Throwable t) {
- logger.error(null, t);
- }
- }
- }
- private String lookupBaseFolderFromJndi() {
- try {
- // try to lookup JNDI env-entry for the baseFolder
- InitialContext ic = new InitialContext();
- Context env = (Context) ic.lookup("java:comp/env");
- return (String) env.lookup("baseFolder");
- } catch (NamingException n) {
- logger.error("Failed to get JNDI env-entry: " + n.getExplanation());
- }
- return null;
- }
- protected String getBaseFolderPath(String defaultBaseFolder) {
- // try a system property or a JNDI property
- String specifiedBaseFolder = System.getProperty("GITBLIT_HOME", lookupBaseFolderFromJndi());
- if (!StringUtils.isEmpty(System.getenv("GITBLIT_HOME"))) {
- // try an environment variable
- specifiedBaseFolder = System.getenv("GITBLIT_HOME");
- }
- if (!StringUtils.isEmpty(specifiedBaseFolder)) {
- // use specified base folder path
- return specifiedBaseFolder;
- }
- // use default base folder path
- return defaultBaseFolder;
- }
- protected <X extends IManager> X loadManager(Injector injector, Class<X> clazz) {
- X x = injector.getInstance(clazz);
- return x;
- }
- protected <X extends IManager> X startManager(Injector injector, Class<X> clazz) {
- X x = loadManager(injector, clazz);
- logManager(clazz);
- return startManager(x);
- }
- protected <X extends IManager> X startManager(X x) {
- x.start();
- managers.add(x);
- return x;
- }
- protected void logManager(Class<? extends IManager> clazz) {
- logger.info("");
- logger.info("----[{}]----", clazz.getName());
- }
- @Override
- public final void contextDestroyed(ServletContextEvent contextEvent) {
- super.contextDestroyed(contextEvent);
- ServletContext context = contextEvent.getServletContext();
- destroyContext(context);
- }
- /**
- * Gitblit is being shutdown either because the servlet container is
- * shutting down or because the servlet container is re-deploying Gitblit.
- */
- protected void destroyContext(ServletContext context) {
- logger.info("Gitblit context destroyed by servlet container.");
- IPluginManager pluginManager = getManager(IPluginManager.class);
- if (pluginManager != null) {
- for (LifeCycleListener listener : pluginManager.getExtensions(LifeCycleListener.class)) {
- try {
- listener.onShutdown();
- } catch (Throwable t) {
- logger.error(null, t);
- }
- }
- }
- for (IManager manager : managers) {
- logger.debug("stopping {}", manager.getClass().getSimpleName());
- manager.stop();
- }
- }
- /**
- * Configures Gitblit GO
- *
- * @param context
- * @param settings
- * @param baseFolder
- * @param runtimeSettings
- * @return the base folder
- */
- protected File configureGO(
- ServletContext context,
- IStoredSettings goSettings,
- File goBaseFolder,
- IStoredSettings runtimeSettings) {
- logger.debug("configuring Gitblit GO");
- // merge the stored settings into the runtime settings
- //
- // if runtimeSettings is also a FileSettings w/o a specified target file,
- // the target file for runtimeSettings is set to "localSettings".
- runtimeSettings.merge(goSettings);
- File base = goBaseFolder;
- return base;
- }
- /**
- * Configures a standard WAR instance of Gitblit.
- *
- * @param context
- * @param webxmlSettings
- * @param contextFolder
- * @param runtimeSettings
- * @return the base folder
- */
- protected File configureWAR(
- ServletContext context,
- WebXmlSettings webxmlSettings,
- File contextFolder,
- IStoredSettings runtimeSettings) {
- // Gitblit is running in a standard servlet container
- logger.debug("configuring Gitblit WAR");
- logger.info("WAR contextFolder is " + ((contextFolder != null) ? contextFolder.getAbsolutePath() : "<empty>"));
- String webXmlPath = webxmlSettings.getString(Constants.baseFolder, Constants.contextFolder$ + "/WEB-INF/data");
- if (webXmlPath.contains(Constants.contextFolder$) && contextFolder == null) {
- // warn about null contextFolder (issue-199)
- logger.error("");
- logger.error(MessageFormat.format("\"{0}\" depends on \"{1}\" but \"{2}\" is returning NULL for \"{1}\"!",
- Constants.baseFolder, Constants.contextFolder$, context.getServerInfo()));
- logger.error(MessageFormat.format("Please specify a non-parameterized path for <context-param> {0} in web.xml!!", Constants.baseFolder));
- logger.error(MessageFormat.format("OR configure your servlet container to specify a \"{0}\" parameter in the context configuration!!", Constants.baseFolder));
- logger.error("");
- }
- String baseFolderPath = getBaseFolderPath(webXmlPath);
- File baseFolder = com.gitblit.utils.FileUtils.resolveParameter(Constants.contextFolder$, contextFolder, baseFolderPath);
- baseFolder.mkdirs();
- // try to extract the data folder resource to the baseFolder
- extractResources(context, "/WEB-INF/data/", baseFolder);
- // delegate all config to baseFolder/gitblit.properties file
- File localSettings = new File(baseFolder, "gitblit.properties");
- FileSettings fileSettings = new FileSettings(localSettings.getAbsolutePath());
- // merge the stored settings into the runtime settings
- //
- // if runtimeSettings is also a FileSettings w/o a specified target file,
- // the target file for runtimeSettings is set to "localSettings".
- runtimeSettings.merge(fileSettings);
- return baseFolder;
- }
- /**
- * Configures an OpenShift instance of Gitblit.
- *
- * @param context
- * @param webxmlSettings
- * @param contextFolder
- * @param runtimeSettings
- * @return the base folder
- */
- private File configureExpress(
- ServletContext context,
- WebXmlSettings webxmlSettings,
- File contextFolder,
- IStoredSettings runtimeSettings) {
- // Gitblit is running in OpenShift/JBoss
- logger.debug("configuring Gitblit Express");
- String openShift = System.getenv("OPENSHIFT_DATA_DIR");
- File base = new File(openShift);
- logger.info("EXPRESS contextFolder is " + contextFolder.getAbsolutePath());
- // Copy the included scripts to the configured groovy folder
- String path = webxmlSettings.getString(Keys.groovy.scriptsFolder, "groovy");
- File localScripts = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, base, path);
- if (!localScripts.exists()) {
- File warScripts = new File(contextFolder, "/WEB-INF/data/groovy");
- if (!warScripts.equals(localScripts)) {
- try {
- com.gitblit.utils.FileUtils.copy(localScripts, warScripts.listFiles());
- } catch (IOException e) {
- logger.error(MessageFormat.format(
- "Failed to copy included Groovy scripts from {0} to {1}",
- warScripts, localScripts));
- }
- }
- }
- // Copy the included gitignore files to the configured gitignore folder
- String gitignorePath = webxmlSettings.getString(Keys.git.gitignoreFolder, "gitignore");
- File localGitignores = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, base, gitignorePath);
- if (!localGitignores.exists()) {
- File warGitignores = new File(contextFolder, "/WEB-INF/data/gitignore");
- if (!warGitignores.equals(localGitignores)) {
- try {
- com.gitblit.utils.FileUtils.copy(localGitignores, warGitignores.listFiles());
- } catch (IOException e) {
- logger.error(MessageFormat.format(
- "Failed to copy included .gitignore files from {0} to {1}",
- warGitignores, localGitignores));
- }
- }
- }
- // merge the WebXmlSettings into the runtime settings (for backwards-compatibilty)
- runtimeSettings.merge(webxmlSettings);
- // settings are to be stored in openshift/gitblit.properties
- File localSettings = new File(base, "gitblit.properties");
- FileSettings fileSettings = new FileSettings(localSettings.getAbsolutePath());
- // merge the stored settings into the runtime settings
- //
- // if runtimeSettings is also a FileSettings w/o a specified target file,
- // the target file for runtimeSettings is set to "localSettings".
- runtimeSettings.merge(fileSettings);
- return base;
- }
- protected void extractResources(ServletContext context, String path, File toDir) {
- Set<String> resources = context.getResourcePaths(path);
- if (resources == null) {
- logger.warn("There are no WAR resources to extract from {}", path);
- return;
- }
- for (String resource : resources) {
- // extract the resource to the directory if it does not exist
- File f = new File(toDir, resource.substring(path.length()));
- if (!f.exists()) {
- InputStream is = null;
- OutputStream os = null;
- try {
- if (resource.charAt(resource.length() - 1) == '/') {
- // directory
- f.mkdirs();
- extractResources(context, resource, f);
- } else {
- // file
- f.getParentFile().mkdirs();
- is = context.getResourceAsStream(resource);
- os = new FileOutputStream(f);
- byte [] buffer = new byte[4096];
- int len = 0;
- while ((len = is.read(buffer)) > -1) {
- os.write(buffer, 0, len);
- }
- }
- } catch (FileNotFoundException e) {
- logger.error("Failed to find resource \"" + resource + "\"", e);
- } catch (IOException e) {
- logger.error("Failed to copy resource \"" + resource + "\" to " + f, e);
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- // ignore
- }
- }
- if (os != null) {
- try {
- os.close();
- } catch (IOException e) {
- // ignore
- }
- }
- }
- }
- }
- }
- }