]> source.dussan.org Git - gitblit.git/commitdiff
Extract RuntimeManager from GitBlit singleton
authorJames Moger <james.moger@gitblit.com>
Wed, 20 Nov 2013 20:26:24 +0000 (15:26 -0500)
committerJames Moger <james.moger@gitblit.com>
Fri, 29 Nov 2013 16:05:51 +0000 (11:05 -0500)
Change-Id: I5358389396f816da979ec18a31421c2d2b67b3d9

12 files changed:
src/main/java/com/gitblit/DaggerModule.java
src/main/java/com/gitblit/FederationClient.java
src/main/java/com/gitblit/FileSettings.java
src/main/java/com/gitblit/GitBlit.java
src/main/java/com/gitblit/GitBlitServer.java
src/main/java/com/gitblit/Gitblit.java
src/main/java/com/gitblit/IStoredSettings.java
src/main/java/com/gitblit/manager/IManager.java [new file with mode: 0644]
src/main/java/com/gitblit/manager/IRuntimeManager.java
src/main/java/com/gitblit/manager/RuntimeManager.java [new file with mode: 0644]
src/main/java/com/gitblit/models/ServerStatus.java
src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java

index d25126a1f71987ee456d197d518d54413767f2e1..840ba609076b9e35ca11aca73c1ef0f480d4b7a6 100644 (file)
@@ -28,6 +28,7 @@ import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.manager.ISessionManager;
 import com.gitblit.manager.IUserManager;
+import com.gitblit.manager.RuntimeManager;
 import com.gitblit.wicket.GitBlitWebApp;
 import com.gitblit.wicket.GitblitWicketFilter;
 
@@ -42,6 +43,8 @@ import dagger.Provides;
  */
 @Module(
        injects = {
+                       IStoredSettings.class,
+
                        // core managers
                        IRuntimeManager.class,
                        INotificationManager.class,
@@ -84,8 +87,12 @@ public class DaggerModule {
                this.gitblit = gitblit;
        }
 
-       @Provides @Singleton IRuntimeManager provideRuntimeManager() {
-               return gitblit;
+       @Provides @Singleton IStoredSettings provideSettings() {
+               return new FileSettings();
+       }
+
+       @Provides @Singleton IRuntimeManager provideRuntimeManager(IStoredSettings settings) {
+               return new RuntimeManager(settings);
        }
 
        @Provides @Singleton INotificationManager provideNotificationManager() {
index eae6b94f087af973f456538de29ea150f2a088a8..862b64c194dca33f599615ff8c180b475c5c5312 100644 (file)
@@ -84,7 +84,7 @@ public class FederationClient {
 \r
                // configure the Gitblit singleton for minimal, non-server operation\r
                GitBlit gitblit = new GitBlit(settings, baseFolder);\r
-               gitblit.configureContext(settings, baseFolder, false);\r
+               gitblit.beforeServletInjection(null); // XXX broken\r
                FederationPullExecutor executor = new FederationPullExecutor(registrations, params.isDaemon);\r
                executor.run();\r
                if (!params.isDaemon) {\r
index 12739d202f35c7d6cf226e0c6897107b6e08a15f..d31fc2fbb62c1a79fd627cb2ff2228bf6229e47b 100644 (file)
@@ -32,7 +32,7 @@ import com.gitblit.utils.FileUtils;
  */\r
 public class FileSettings extends IStoredSettings {\r
 \r
-       protected final File propertiesFile;\r
+       protected File propertiesFile;\r
 \r
        private final Properties properties = new Properties();\r
 \r
@@ -40,18 +40,41 @@ public class FileSettings extends IStoredSettings {
 \r
        private volatile boolean forceReload;\r
 \r
-       public FileSettings(String file) {\r
+       public FileSettings() {\r
                super(FileSettings.class);\r
+       }\r
+\r
+       public FileSettings(String file) {\r
+               this();\r
+               load(file);\r
+       }\r
+\r
+       public void load(String file) {\r
                this.propertiesFile = new File(file);\r
        }\r
 \r
+       /**\r
+        * Merges the provided settings into this instance.  This will also\r
+        * set the target file for this instance IFF it is unset AND the merge\r
+        * source is also a FileSettings.  This is a little sneaky.\r
+        */\r
+       @Override\r
+       public void merge(IStoredSettings settings) {\r
+               super.merge(settings);\r
+\r
+               // sneaky: set the target file from the merge source\r
+               if (propertiesFile == null && settings instanceof FileSettings) {\r
+                       this.propertiesFile = ((FileSettings) settings).propertiesFile;\r
+               }\r
+       }\r
+\r
        /**\r
         * Returns a properties object which contains the most recent contents of\r
         * the properties file.\r
         */\r
        @Override\r
        protected synchronized Properties read() {\r
-               if (propertiesFile.exists() && (forceReload || (propertiesFile.lastModified() > lastModified))) {\r
+               if (propertiesFile != null && propertiesFile.exists() && (forceReload || (propertiesFile.lastModified() > lastModified))) {\r
                        FileInputStream is = null;\r
                        try {\r
                                Properties props = new Properties();\r
index b121b2b920c2b9d06ffc97c2a42bfe03c635ae56..91a44b7e5110a85c54769af1799415d8f799cd30 100644 (file)
@@ -47,7 +47,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.TimeZone;
 import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
@@ -102,6 +101,7 @@ import com.gitblit.git.GitDaemon;
 import com.gitblit.git.GitServlet;
 import com.gitblit.manager.IFederationManager;
 import com.gitblit.manager.IGitblitManager;
+import com.gitblit.manager.IManager;
 import com.gitblit.manager.INotificationManager;
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
@@ -121,7 +121,6 @@ import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.RepositoryUrl;
 import com.gitblit.models.SearchResult;
 import com.gitblit.models.ServerSettings;
-import com.gitblit.models.ServerStatus;
 import com.gitblit.models.SettingModel;
 import com.gitblit.models.TeamModel;
 import com.gitblit.models.UserModel;
@@ -151,6 +150,8 @@ import com.google.gson.JsonIOException;
 import com.google.gson.JsonSyntaxException;
 import com.google.gson.reflect.TypeToken;
 
+import dagger.ObjectGraph;
+
 /**
  * GitBlit is the servlet context listener singleton that acts as the core for
  * the web ui and the servlets. This class is either directly instantiated by
@@ -165,8 +166,7 @@ import com.google.gson.reflect.TypeToken;
  */
 @WebListener
 public class GitBlit extends DaggerContextListener
-                                        implements IRuntimeManager,
-                                                               INotificationManager,
+                                        implements INotificationManager,
                                                                IUserManager,
                                                                ISessionManager,
                                                                IRepositoryManager,
@@ -178,6 +178,10 @@ public class GitBlit extends DaggerContextListener
 
        private final IStoredSettings goSettings;
 
+       private final File goBaseFolder;
+
+       private final List<IManager> managers = new ArrayList<IManager>();
+
        private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(10);
 
        private final List<FederationModel> federationRegistrations = Collections
@@ -201,18 +205,12 @@ public class GitBlit extends DaggerContextListener
 
        private final ObjectCache<String> projectRepositoriesMarkdownCache = new ObjectCache<String>();
 
-       private File baseFolder;
-
        private File repositoriesFolder;
 
        private IUserService userService;
 
        private IStoredSettings settings;
 
-       private ServerSettings settingsModel;
-
-       private ServerStatus serverStatus;
-
        private MailExecutor mailExecutor;
 
        private LuceneExecutor luceneExecutor;
@@ -221,8 +219,6 @@ public class GitBlit extends DaggerContextListener
 
        private MirrorExecutor mirrorExecutor;
 
-       private TimeZone timezone;
-
        private FileBasedConfig projectConfigs;
 
        private FanoutService fanoutService;
@@ -231,17 +227,19 @@ public class GitBlit extends DaggerContextListener
 
        public GitBlit() {
                this.goSettings = null;
+               this.goBaseFolder = null;
        }
 
        protected GitBlit(final IUserService userService) {
                this.goSettings = null;
+               this.goBaseFolder = null;
                this.userService = userService;
                gitblit = this;
        }
 
        public GitBlit(IStoredSettings settings, File baseFolder) {
                this.goSettings = settings;
-               this.baseFolder = baseFolder;
+               this.goBaseFolder = baseFolder;
                gitblit = this;
        }
 
@@ -259,27 +257,13 @@ public class GitBlit extends DaggerContextListener
                if (managerClass.isAssignableFrom(GitBlit.class)) {
                        return (X) gitblit;
                }
-               return null;
-       }
-
-       @Override
-       public File getBaseFolder() {
-               return baseFolder;
-       }
-
-       @Override
-       public void setBaseFolder(File folder) {
-               this.baseFolder = folder;
-       }
 
-       /**
-        * Returns the boot date of the Gitblit server.
-        *
-        * @return the boot date of Gitblit
-        */
-       @Override
-       public Date getBootDate() {
-               return serverStatus.bootDate;
+               for (IManager manager : gitblit.managers) {
+                       if (managerClass.isAssignableFrom(manager.getClass())) {
+                               return (X) manager;
+                       }
+               }
+               return null;
        }
 
        /**
@@ -301,71 +285,6 @@ public class GitBlit extends DaggerContextListener
                return date;
        }
 
-       /**
-        * Determine if this Gitblit instance is actively serving git repositories
-        * or if it is merely a repository viewer.
-        *
-        * @return true if Gitblit is serving repositories
-        */
-       @Override
-       public boolean isServingRepositories() {
-               return settings.getBoolean(Keys.git.enableGitServlet, true) || (settings.getInteger(Keys.git.daemonPort, 0) > 0);
-       }
-
-       /**
-        * Returns the preferred timezone for the Gitblit instance.
-        *
-        * @return a timezone
-        */
-       @Override
-       public TimeZone getTimezone() {
-               if (timezone == null) {
-                       String tzid = settings.getString("web.timezone", null);
-                       if (StringUtils.isEmpty(tzid)) {
-                               timezone = TimeZone.getDefault();
-                               return timezone;
-                       }
-                       timezone = TimeZone.getTimeZone(tzid);
-               }
-               return timezone;
-       }
-
-       /**
-        * Is Gitblit running in debug mode?
-        *
-        * @return true if Gitblit is running in debug mode
-        */
-       @Override
-       public boolean isDebugMode() {
-               return settings.getBoolean(Keys.web.debugMode, false);
-       }
-
-       /**
-        * Returns the file object for the specified configuration key.
-        *
-        * @return the file
-        */
-       @Override
-       public File getFileOrFolder(String key, String defaultFileOrFolder) {
-               String fileOrFolder = settings.getString(key, defaultFileOrFolder);
-               return getFileOrFolder(fileOrFolder);
-       }
-
-       /**
-        * Returns the file object which may have it's base-path determined by
-        * environment variables for running on a cloud hosting service. All Gitblit
-        * file or folder retrievals are (at least initially) funneled through this
-        * method so it is the correct point to globally override/alter filesystem
-        * access based on environment or some other indicator.
-        *
-        * @return the file
-        */
-       @Override
-       public File getFileOrFolder(String fileOrFolder) {
-               return com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$,
-                               baseFolder, fileOrFolder);
-       }
-
        /**
         * Returns the path of the repositories folder. This method checks to see if
         * Gitblit is running on a cloud service and may return an adjusted path.
@@ -374,7 +293,7 @@ public class GitBlit extends DaggerContextListener
         */
        @Override
        public File getRepositoriesFolder() {
-               return getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git");
+               return getManager(IRuntimeManager.class).getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git");
        }
 
        /**
@@ -385,7 +304,7 @@ public class GitBlit extends DaggerContextListener
         */
        @Override
        public File getProposalsFolder() {
-               return getFileOrFolder(Keys.federation.proposalsFolder, "${baseFolder}/proposals");
+               return getManager(IRuntimeManager.class).getFileOrFolder(Keys.federation.proposalsFolder, "${baseFolder}/proposals");
        }
 
        /**
@@ -396,7 +315,7 @@ public class GitBlit extends DaggerContextListener
         */
        @Override
        public File getHooksFolder() {
-               return getFileOrFolder(Keys.groovy.scriptsFolder, "${baseFolder}/groovy");
+               return getManager(IRuntimeManager.class).getFileOrFolder(Keys.groovy.scriptsFolder, "${baseFolder}/groovy");
        }
 
        /**
@@ -407,36 +326,7 @@ public class GitBlit extends DaggerContextListener
         */
        @Override
        public File getGrapesFolder() {
-               return getFileOrFolder(Keys.groovy.grapeFolder, "${baseFolder}/groovy/grape");
-       }
-
-       /**
-        * Returns the runtime settings.
-        *
-        * @return runtime settings
-        */
-       @Override
-       public IStoredSettings getSettings() {
-               return settings;
-       }
-
-       /**
-        * Updates the runtime settings.
-        *
-        * @param settings
-        * @return true if the update succeeded
-        */
-       @Override
-       public boolean updateSettings(Map<String, String> updatedSettings) {
-               return settings.saveSettings(updatedSettings);
-       }
-
-       @Override
-       public ServerStatus getStatus() {
-               // update heap memory status
-               serverStatus.heapAllocated = Runtime.getRuntime().totalMemory();
-               serverStatus.heapFree = Runtime.getRuntime().freeMemory();
-               return serverStatus;
+               return getManager(IRuntimeManager.class).getFileOrFolder(Keys.groovy.grapeFolder, "${baseFolder}/groovy/grape");
        }
 
        /**
@@ -548,7 +438,7 @@ public class GitBlit extends DaggerContextListener
        @Override
        public Collection<GitClientApplication> getClientApplications() {
                // prefer user definitions, if they exist
-               File userDefs = new File(baseFolder, "clientapps.json");
+               File userDefs = new File(getManager(IRuntimeManager.class).getBaseFolder(), "clientapps.json");
                if (userDefs.exists()) {
                        Date lastModified = new Date(userDefs.lastModified());
                        if (clientApplications.hasCurrent("user", lastModified)) {
@@ -1912,7 +1802,7 @@ public class GitBlit extends DaggerContextListener
                }
                RepositoryModel model = new RepositoryModel();
                model.isBare = r.isBare();
-               File basePath = getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git");
+               File basePath = getRepositoriesFolder();
                if (model.isBare) {
                        model.name = com.gitblit.utils.FileUtils.getRelativePath(basePath, r.getDirectory());
                } else {
@@ -2283,7 +2173,7 @@ public class GitBlit extends DaggerContextListener
                if (repositoryMetricsCache.hasCurrent(model.name, model.lastChange)) {
                        return new ArrayList<Metric>(repositoryMetricsCache.getObject(model.name));
                }
-               List<Metric> metrics = MetricUtils.getDateMetrics(repository, null, true, null, getTimezone());
+               List<Metric> metrics = MetricUtils.getDateMetrics(repository, null, true, null, getManager(IRuntimeManager.class).getTimezone());
                repositoryMetricsCache.updateObject(model.name, model.lastChange, metrics);
                return new ArrayList<Metric>(metrics);
        }
@@ -3369,28 +3259,6 @@ public class GitBlit extends DaggerContextListener
                }
        }
 
-       /**
-        * Returns the descriptions/comments of the Gitblit config settings.
-        *
-        * @return SettingsModel
-        */
-       @Override
-       public ServerSettings getSettingsModel() {
-               // ensure that the current values are updated in the setting models
-               for (String key : settings.getAllKeys(null)) {
-                       SettingModel setting = settingsModel.get(key);
-                       if (setting == null) {
-                               // unreferenced setting, create a setting model
-                               setting = new SettingModel();
-                               setting.name = key;
-                               settingsModel.add(setting);
-                       }
-                       setting.currentValue = settings.getString(key, "");
-               }
-               settingsModel.pushScripts = getAllScripts();
-               return settingsModel;
-       }
-
        /**
         * Parse the properties file and aggregate all the comments by the setting
         * key. A setting model tracks the current value, the default value, the
@@ -3398,8 +3266,7 @@ public class GitBlit extends DaggerContextListener
         *
         * @return Map<String, SettingModel>
         */
-       private ServerSettings loadSettingModels() {
-               ServerSettings settingsModel = new ServerSettings();
+       private ServerSettings loadSettingModels(ServerSettings settingsModel) {
                settingsModel.supportsCredentialChanges = userService.supportsCredentialChanges();
                settingsModel.supportsDisplayNameChanges = userService.supportsDisplayNameChanges();
                settingsModel.supportsEmailAddressChanges = userService.supportsEmailAddressChanges();
@@ -3460,77 +3327,6 @@ public class GitBlit extends DaggerContextListener
                return settingsModel;
        }
 
-       /**
-        * Configure the Gitblit singleton with the specified settings source. This
-        * source may be file settings (Gitblit GO) or may be web.xml settings
-        * (Gitblit WAR).
-        *
-        * @param settings
-        */
-       public void configureContext(IStoredSettings settings, File folder, boolean startFederation) {
-               this.settings = settings;
-               this.baseFolder = folder;
-
-               repositoriesFolder = getRepositoriesFolder();
-
-               logger.info("Gitblit base folder     = " + folder.getAbsolutePath());
-               logger.info("Git repositories folder = " + repositoriesFolder.getAbsolutePath());
-               logger.info("Gitblit settings        = " + settings.toString());
-
-               // prepare service executors
-               mailExecutor = new MailExecutor(settings);
-               luceneExecutor = new LuceneExecutor(settings, getManager(IRepositoryManager.class));
-               gcExecutor = new GCExecutor(settings, getManager(IRepositoryManager.class));
-               mirrorExecutor = new MirrorExecutor(settings, getManager(IRepositoryManager.class));
-
-               // initialize utilities
-               String prefix = settings.getString(Keys.git.userRepositoryPrefix, "~");
-               ModelUtils.setUserRepoPrefix(prefix);
-
-               // calculate repository list settings checksum for future config changes
-               repositoryListSettingsChecksum.set(getRepositoryListSettingsChecksum());
-
-               // build initial repository list
-               if (settings.getBoolean(Keys.git.cacheRepositoryList,  true)) {
-                       logger.info("Identifying available repositories...");
-                       getRepositoryList();
-               }
-
-               logTimezone("JVM", TimeZone.getDefault());
-               logTimezone(Constants.NAME, getTimezone());
-
-               serverStatus = new ServerStatus(goSettings != null);
-
-               if (this.userService == null) {
-                       String realm = settings.getString(Keys.realm.userService, "${baseFolder}/users.properties");
-                       IUserService loginService = null;
-                       try {
-                               // check to see if this "file" is a login service class
-                               Class<?> realmClass = Class.forName(realm);
-                               loginService = (IUserService) realmClass.newInstance();
-                       } catch (Throwable t) {
-                               loginService = new GitblitUserService();
-                       }
-                       setUserService(loginService);
-               }
-
-               // load and cache the project metadata
-               projectConfigs = new FileBasedConfig(getFileOrFolder(Keys.web.projectsFile, "${baseFolder}/projects.conf"), FS.detect());
-               getProjectConfigs();
-
-               configureMailExecutor();
-               configureLuceneIndexing();
-               configureGarbageCollector();
-               configureMirrorExecutor();
-               if (startFederation) {
-                       configureFederation();
-               }
-               configureJGit();
-               configureFanout();
-               configureGitDaemon();
-               configureCommitCache();
-       }
-
        protected void configureMailExecutor() {
                if (mailExecutor.isReady()) {
                        logger.info("Mail executor is scheduled to process the message queue every 2 minutes.");
@@ -3642,7 +3438,15 @@ public class GitBlit extends DaggerContextListener
                if (port > 0) {
                        try {
                                // HACK temporary pending manager separation and injection
-                               Gitblit gitblit = new Gitblit(this, this, this, this, this, this, this, this);
+                               Gitblit gitblit = new Gitblit(
+                                               getManager(IRuntimeManager.class),
+                                               this,
+                                               this,
+                                               this,
+                                               this,
+                                               this,
+                                               this,
+                                               this);
                                gitDaemon = new GitDaemon(gitblit);
                                gitDaemon.start();
                        } catch (IOException e) {
@@ -3700,13 +3504,6 @@ public class GitBlit extends DaggerContextListener
                return luceneExecutor;
        }
 
-       private void logTimezone(String type, TimeZone zone) {
-               SimpleDateFormat df = new SimpleDateFormat("z Z");
-               df.setTimeZone(zone);
-               String offset = df.format(new Date());
-               logger.info(type + " timezone is " + zone.getID() + " (" + offset + ")");
-       }
-
        /**
         * Configure Gitblit from the web.xml, if no configuration has already been
         * specified.
@@ -3715,93 +3512,237 @@ public class GitBlit extends DaggerContextListener
         */
        @Override
        protected void beforeServletInjection(ServletContext context) {
-               if (settings == null) {
-                       // Gitblit is running in a servlet container
+               ObjectGraph injector = getInjector(context);
+
+               // create the runtime settings object
+               IStoredSettings runtimeSettings = injector.get(IStoredSettings.class);
+               this.settings = runtimeSettings; // XXX remove me eventually
+               final File baseFolder;
+
+               if (goSettings != null) {
+                       // Gitblit GO
+                       logger.debug("configuring 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;
-                       String openShift = System.getenv("OPENSHIFT_DATA_DIR");
-
-                       if (!StringUtils.isEmpty(openShift)) {
-                               // Gitblit is running in OpenShift/JBoss
-                               File base = new File(openShift);
-                               logger.info("EXPRESS contextFolder is " + contextFolder.getAbsolutePath());
-
-                               // gitblit.properties setting overrides
-                               File overrideFile = new File(base, "gitblit.properties");
-                               webxmlSettings.applyOverrides(overrideFile);
-
-                               // 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));
-                                               }
-                                       }
-                               }
-
-                               // disable Git daemon on Express - we can't bind 9418 and we
-                               // can't port-forward to the daemon
-                               webxmlSettings.overrideSetting(Keys.git.daemonPort, 0);
 
-                               // configure context using the web.xml
-                               configureContext(webxmlSettings, base, true);
+                       if (!StringUtils.isEmpty(System.getenv("OPENSHIFT_DATA_DIR"))) {
+                               // RedHat OpenShift
+                               logger.debug("configuring Gitblit Express");
+                               baseFolder = configureExpress(context, webxmlSettings, contextFolder, runtimeSettings);
                        } else {
-                               // Gitblit is running in a standard servlet container
-                               logger.info("WAR contextFolder is " + ((contextFolder != null) ? contextFolder.getAbsolutePath() : "<empty>"));
-
-                               String path = webxmlSettings.getString(Constants.baseFolder, Constants.contextFolder$ + "/WEB-INF/data");
-
-                               if (path.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("");
-                               }
+                               // standard WAR
+                               logger.debug("configuring Gitblit WAR");
+                               baseFolder = configureWAR(context, webxmlSettings, contextFolder, runtimeSettings);
+                       }
 
-                               try {
-                                       // try to lookup JNDI env-entry for the baseFolder
-                                       InitialContext ic = new InitialContext();
-                                       Context env = (Context) ic.lookup("java:comp/env");
-                                       String val = (String) env.lookup("baseFolder");
-                                       if (!StringUtils.isEmpty(val)) {
-                                               path = val;
-                                       }
-                               } catch (NamingException n) {
-                                       logger.error("Failed to get JNDI env-entry: " + n.getExplanation());
-                               }
+                       // Test for Tomcat forward-slash/%2F issue and auto-adjust settings
+                       ContainerUtils.CVE_2007_0450.test(runtimeSettings);
+               }
 
-                               File base = com.gitblit.utils.FileUtils.resolveParameter(Constants.contextFolder$, contextFolder, path);
-                               base.mkdirs();
+               // Runtime manager is a container for settings and other parameters
+               IRuntimeManager runtime = startManager(injector, IRuntimeManager.class);
+               runtime.setBaseFolder(baseFolder);
+               runtime.getStatus().isGO = goSettings != null;
+               runtime.getStatus().servletContainer = context.getServerInfo();
 
-                               // try to extract the data folder resource to the baseFolder
-                               File localSettings = new File(base, "gitblit.properties");
-                               if (!localSettings.exists()) {
-                                       extractResources(context, "/WEB-INF/data/", base);
-                               }
+               repositoriesFolder = getRepositoriesFolder();
+
+               logger.info("Gitblit base folder     = " + baseFolder.getAbsolutePath());
+               logger.info("Git repositories folder = " + repositoriesFolder.getAbsolutePath());
+
+               // prepare service executors
+               mailExecutor = new MailExecutor(runtimeSettings);
+               luceneExecutor = new LuceneExecutor(runtimeSettings, getManager(IRepositoryManager.class));
+               gcExecutor = new GCExecutor(runtimeSettings, getManager(IRepositoryManager.class));
+               mirrorExecutor = new MirrorExecutor(runtimeSettings, getManager(IRepositoryManager.class));
+
+               // initialize utilities
+               String prefix = runtimeSettings.getString(Keys.git.userRepositoryPrefix, "~");
+               ModelUtils.setUserRepoPrefix(prefix);
+
+               // calculate repository list settings checksum for future config changes
+               repositoryListSettingsChecksum.set(getRepositoryListSettingsChecksum());
+
+               // build initial repository list
+               if (runtimeSettings.getBoolean(Keys.git.cacheRepositoryList,  true)) {
+                       logger.info("Identifying available repositories...");
+                       getRepositoryList();
+               }
+
+               if (this.userService == null) {
+                       String realm = runtimeSettings.getString(Keys.realm.userService, "${baseFolder}/users.properties");
+                       IUserService loginService = null;
+                       try {
+                               // check to see if this "file" is a login service class
+                               Class<?> realmClass = Class.forName(realm);
+                               loginService = (IUserService) realmClass.newInstance();
+                       } catch (Throwable t) {
+                               loginService = new GitblitUserService();
+                       }
+                       setUserService(loginService);
+               }
+
+               loadSettingModels(runtime.getSettingsModel());
+
+               // load and cache the project metadata
+               projectConfigs = new FileBasedConfig(runtime.getFileOrFolder(Keys.web.projectsFile, "${baseFolder}/projects.conf"), FS.detect());
+               getProjectConfigs();
+
+               configureMailExecutor();
+               configureLuceneIndexing();
+               configureGarbageCollector();
+               configureMirrorExecutor();
+               if (true/*startFederation*/) {
+                       configureFederation();
+               }
+               configureJGit();
+               configureFanout();
+               configureGitDaemon();
+               configureCommitCache();
+       }
+
+       /**
+        * 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) {
+
+               // 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) {
 
-                               // delegate all config to baseFolder/gitblit.properties file
-                               FileSettings settings = new FileSettings(localSettings.getAbsolutePath());
-                               configureContext(settings, base, true);
+               // Gitblit is running in a standard servlet container
+               logger.info("WAR contextFolder is " + ((contextFolder != null) ? contextFolder.getAbsolutePath() : "<empty>"));
+
+               String path = webxmlSettings.getString(Constants.baseFolder, Constants.contextFolder$ + "/WEB-INF/data");
+
+               if (path.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("");
+               }
+
+               try {
+                       // try to lookup JNDI env-entry for the baseFolder
+                       InitialContext ic = new InitialContext();
+                       Context env = (Context) ic.lookup("java:comp/env");
+                       String val = (String) env.lookup("baseFolder");
+                       if (!StringUtils.isEmpty(val)) {
+                               path = val;
                        }
+               } catch (NamingException n) {
+                       logger.error("Failed to get JNDI env-entry: " + n.getExplanation());
+               }
 
-                       // WAR or Express is likely to be running on a Tomcat.
-                       // Test for the forward-slash/%2F issue and auto-adjust settings.
-                       ContainerUtils.CVE_2007_0450.test(settings);
+               File base = com.gitblit.utils.FileUtils.resolveParameter(Constants.contextFolder$, contextFolder, path);
+               base.mkdirs();
+
+               // try to extract the data folder resource to the baseFolder
+               File localSettings = new File(base, "gitblit.properties");
+               if (!localSettings.exists()) {
+                       extractResources(context, "/WEB-INF/data/", base);
                }
 
-               settingsModel = loadSettingModels();
-               serverStatus.servletContainer = context.getServerInfo();
+               // delegate all config to baseFolder/gitblit.properties file
+               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;
+       }
+
+       /**
+        * 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
+               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));
+                               }
+                       }
+               }
+
+               // 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) {
@@ -3858,6 +3799,11 @@ public class GitBlit extends DaggerContextListener
        @Override
        protected void destroyContext(ServletContext context) {
                logger.info("Gitblit context destroyed by servlet container.");
+               for (IManager manager : managers) {
+                       logger.debug("stopping {}", manager.getClass().getSimpleName());
+                       manager.stop();
+               }
+
                scheduledExecutor.shutdownNow();
                luceneExecutor.close();
                gcExecutor.close();
@@ -4059,6 +4005,14 @@ public class GitBlit extends DaggerContextListener
                return new Object [] { new DaggerModule(this) };
        }
 
+       protected <X extends IManager> X startManager(ObjectGraph injector, Class<X> clazz) {
+               logger.debug("injecting and starting {}", clazz.getSimpleName());
+               X x = injector.get(clazz);
+               x.setup();
+               managers.add(x);
+               return x;
+       }
+
        /**
         * Instantiate and inject all filters and servlets into the container using
         * the servlet 3 specification.
index 292eec40bd9c9d700700426c3db28c00f306a464..fe29804de2c679de0854aac330aa391d69c29be4 100644 (file)
@@ -409,9 +409,8 @@ public class GitBlitServer {
                        rootContext.setHandler(sh);\r
                }\r
 \r
-               // Setup the GitBlit context\r
+               // Setup the Gitblit context\r
                GitBlit gitblit = newGitblit(settings, baseFolder);\r
-               gitblit.configureContext(settings, baseFolder, true);\r
                rootContext.addEventListener(gitblit);\r
 \r
                try {\r
index 321575457b078cc8fc3f687b2959de20fff5ce1c..687e4e20989b6ab45e802ae45f535937c9f18efa 100644 (file)
@@ -33,6 +33,7 @@ import com.gitblit.Constants.FederationRequest;
 import com.gitblit.Constants.FederationToken;
 import com.gitblit.manager.IFederationManager;
 import com.gitblit.manager.IGitblitManager;
+import com.gitblit.manager.IManager;
 import com.gitblit.manager.INotificationManager;
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
@@ -111,6 +112,16 @@ public class Gitblit implements IRuntimeManager,
                this.gitblitManager = gitblitManager;
        }
 
+       @Override
+       public IManager setup() {
+               return this;
+       }
+
+       @Override
+       public IManager stop() {
+               return this;
+       }
+
        /*
         * RUNTIME MANAGER
         */
index 01c478f8d586f10f3ff4dd6ac8289b5849a65fea..6b58e89ade8f2cb51c53ea9d9b951321e2a29ae1 100644 (file)
@@ -351,4 +351,13 @@ public abstract class IStoredSettings {
         * @return true if successful\r
         */\r
        public abstract boolean saveSettings(Map<String, String> updatedSettings);\r
+\r
+       /**\r
+        * Merge all settings from the settings parameter into this instance.\r
+        *\r
+        * @param settings\r
+        */\r
+       public void merge(IStoredSettings settings) {\r
+               getSettings().putAll(settings.getSettings());\r
+       }\r
 }
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/IManager.java b/src/main/java/com/gitblit/manager/IManager.java
new file mode 100644 (file)
index 0000000..955c610
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2013 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.manager;
+
+public interface IManager {
+
+       IManager setup();
+
+       IManager stop();
+}
index 178b93ca37b62b3c4d87874ef369a65984877397..94ce38009b5ebeab6bd7631ba910b3b39ead6543 100644 (file)
@@ -24,7 +24,7 @@ import com.gitblit.IStoredSettings;
 import com.gitblit.models.ServerSettings;
 import com.gitblit.models.ServerStatus;
 
-public interface IRuntimeManager {
+public interface IRuntimeManager extends IManager {
 
        void setBaseFolder(File folder);
 
diff --git a/src/main/java/com/gitblit/manager/RuntimeManager.java b/src/main/java/com/gitblit/manager/RuntimeManager.java
new file mode 100644 (file)
index 0000000..cfb4543
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2013 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.manager;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.Constants;
+import com.gitblit.IStoredSettings;
+import com.gitblit.Keys;
+import com.gitblit.models.ServerSettings;
+import com.gitblit.models.ServerStatus;
+import com.gitblit.models.SettingModel;
+import com.gitblit.utils.StringUtils;
+
+public class RuntimeManager implements IRuntimeManager {
+
+       private final Logger logger = LoggerFactory.getLogger(getClass());
+
+       private final IStoredSettings settings;
+
+       private final ServerStatus serverStatus;
+
+       private TimeZone timezone;
+
+       private File baseFolder;
+
+       private ServerSettings settingsModel;
+
+       public RuntimeManager(IStoredSettings settings) {
+               this.settings = settings;
+               this.settingsModel = new ServerSettings();
+               this.serverStatus = new ServerStatus();
+       }
+
+       @Override
+       public RuntimeManager setup() {
+               logger.info("Gitblit settings        = " + settings.toString());
+               logTimezone("JVM", TimeZone.getDefault());
+               logTimezone(Constants.NAME, getTimezone());
+               return this;
+       }
+
+       @Override
+       public RuntimeManager stop() {
+               return this;
+       }
+
+       @Override
+       public File getBaseFolder() {
+               return baseFolder;
+       }
+
+       @Override
+       public void setBaseFolder(File folder) {
+               this.baseFolder = folder;
+       }
+
+       /**
+        * Returns the boot date of the Gitblit server.
+        *
+        * @return the boot date of Gitblit
+        */
+       @Override
+       public Date getBootDate() {
+               return serverStatus.bootDate;
+       }
+
+       @Override
+       public ServerSettings getSettingsModel() {
+               // ensure that the current values are updated in the setting models
+               for (String key : settings.getAllKeys(null)) {
+                       SettingModel setting = settingsModel.get(key);
+                       if (setting == null) {
+                               // unreferenced setting, create a setting model
+                               setting = new SettingModel();
+                               setting.name = key;
+                               settingsModel.add(setting);
+                       }
+                       setting.currentValue = settings.getString(key, "");
+               }
+//             settingsModel.pushScripts = getAllScripts();
+               return settingsModel;
+       }
+
+       /**
+        * Determine if this Gitblit instance is actively serving git repositories
+        * or if it is merely a repository viewer.
+        *
+        * @return true if Gitblit is serving repositories
+        */
+       @Override
+       public boolean isServingRepositories() {
+               return settings.getBoolean(Keys.git.enableGitServlet, true) || (settings.getInteger(Keys.git.daemonPort, 0) > 0);
+       }
+
+       /**
+        * Returns the preferred timezone for the Gitblit instance.
+        *
+        * @return a timezone
+        */
+       @Override
+       public TimeZone getTimezone() {
+               if (timezone == null) {
+                       String tzid = settings.getString("web.timezone", null);
+                       if (StringUtils.isEmpty(tzid)) {
+                               timezone = TimeZone.getDefault();
+                               return timezone;
+                       }
+                       timezone = TimeZone.getTimeZone(tzid);
+               }
+               return timezone;
+       }
+
+       private void logTimezone(String type, TimeZone zone) {
+               SimpleDateFormat df = new SimpleDateFormat("z Z");
+               df.setTimeZone(zone);
+               String offset = df.format(new Date());
+               logger.info(type + " timezone is " + zone.getID() + " (" + offset + ")");
+       }
+
+       /**
+        * Is Gitblit running in debug mode?
+        *
+        * @return true if Gitblit is running in debug mode
+        */
+       @Override
+       public boolean isDebugMode() {
+               return settings.getBoolean(Keys.web.debugMode, false);
+       }
+
+       /**
+        * Returns the file object for the specified configuration key.
+        *
+        * @return the file
+        */
+       @Override
+       public File getFileOrFolder(String key, String defaultFileOrFolder) {
+               String fileOrFolder = settings.getString(key, defaultFileOrFolder);
+               return getFileOrFolder(fileOrFolder);
+       }
+
+       /**
+        * Returns the file object which may have it's base-path determined by
+        * environment variables for running on a cloud hosting service. All Gitblit
+        * file or folder retrievals are (at least initially) funneled through this
+        * method so it is the correct point to globally override/alter filesystem
+        * access based on environment or some other indicator.
+        *
+        * @return the file
+        */
+       @Override
+       public File getFileOrFolder(String fileOrFolder) {
+               return com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$,
+                               baseFolder, fileOrFolder);
+       }
+
+       /**
+        * Returns the runtime settings.
+        *
+        * @return runtime settings
+        */
+       @Override
+       public IStoredSettings getSettings() {
+               return settings;
+       }
+
+       /**
+        * Updates the runtime settings.
+        *
+        * @param settings
+        * @return true if the update succeeded
+        */
+       @Override
+       public boolean updateSettings(Map<String, String> updatedSettings) {
+               return settings.saveSettings(updatedSettings);
+       }
+
+       @Override
+       public ServerStatus getStatus() {
+               // update heap memory status
+               serverStatus.heapAllocated = Runtime.getRuntime().totalMemory();
+               serverStatus.heapFree = Runtime.getRuntime().freeMemory();
+               return serverStatus;
+       }
+}
index f8afd00a27122925187e817bbd25bad159c8fd6d..bb6396bc8c4832f8e0435cd7c94479ed55c78384 100644 (file)
@@ -39,8 +39,6 @@ public class ServerStatus implements Serializable {
 \r
        public final String releaseDate;\r
 \r
-       public final boolean isGO;\r
-\r
        public final Map<String, String> systemProperties;\r
 \r
        public final long heapMaximum;\r
@@ -49,13 +47,14 @@ public class ServerStatus implements Serializable {
 \r
        public volatile long heapFree;\r
 \r
+       public boolean isGO;\r
+\r
        public String servletContainer;\r
 \r
-       public ServerStatus(boolean isGO) {\r
+       public ServerStatus() {\r
                this.bootDate = new Date();\r
                this.version = Constants.getVersion();\r
                this.releaseDate = Constants.getBuildDate();\r
-               this.isGO = isGO;\r
 \r
                this.heapMaximum = Runtime.getRuntime().maxMemory();\r
 \r
index b42d29a583ee4d684d7b91b160bbd6b0e3c3347b..aaa6c6686b4858203e9c240f4f7d8bdf84cceae5 100644 (file)
@@ -22,6 +22,7 @@ import java.util.TimeZone;
 
 import com.gitblit.Constants;
 import com.gitblit.IStoredSettings;
+import com.gitblit.manager.IManager;
 import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.ServerSettings;
 import com.gitblit.models.ServerStatus;
@@ -48,7 +49,7 @@ public class MockRuntimeManager implements IRuntimeManager {
        public MockRuntimeManager(IStoredSettings settings) {
                this.settings = settings;
 
-               this.serverStatus = new ServerStatus(true);
+               this.serverStatus = new ServerStatus();
                this.serverStatus.servletContainer = "MockServer";
 
                this.serverSettings = new ServerSettings();
@@ -130,4 +131,13 @@ public class MockRuntimeManager implements IRuntimeManager {
                return settings.saveSettings(updatedSettings);
        }
 
+       @Override
+       public IManager stop() {
+               return this;
+       }
+
+       @Override
+       public IRuntimeManager setup() {
+               return this;
+       }
 }