summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Moger <james.moger@gitblit.com>2013-11-20 15:26:24 -0500
committerJames Moger <james.moger@gitblit.com>2013-11-29 11:05:51 -0500
commite24670533215141f7146349f782d3c4a2d3ee535 (patch)
treea1989fb93593ff2167493581fd509064eaa52c02
parent32539684194f55a76ec171852f582bdafa4c5631 (diff)
downloadgitblit-e24670533215141f7146349f782d3c4a2d3ee535.tar.gz
gitblit-e24670533215141f7146349f782d3c4a2d3ee535.zip
Extract RuntimeManager from GitBlit singleton
Change-Id: I5358389396f816da979ec18a31421c2d2b67b3d9
-rw-r--r--src/main/java/com/gitblit/DaggerModule.java11
-rw-r--r--src/main/java/com/gitblit/FederationClient.java2
-rw-r--r--src/main/java/com/gitblit/FileSettings.java29
-rw-r--r--src/main/java/com/gitblit/GitBlit.java576
-rw-r--r--src/main/java/com/gitblit/GitBlitServer.java3
-rw-r--r--src/main/java/com/gitblit/Gitblit.java11
-rw-r--r--src/main/java/com/gitblit/IStoredSettings.java9
-rw-r--r--src/main/java/com/gitblit/manager/IManager.java23
-rw-r--r--src/main/java/com/gitblit/manager/IRuntimeManager.java2
-rw-r--r--src/main/java/com/gitblit/manager/RuntimeManager.java205
-rw-r--r--src/main/java/com/gitblit/models/ServerStatus.java7
-rw-r--r--src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java12
12 files changed, 565 insertions, 325 deletions
diff --git a/src/main/java/com/gitblit/DaggerModule.java b/src/main/java/com/gitblit/DaggerModule.java
index d25126a1..840ba609 100644
--- a/src/main/java/com/gitblit/DaggerModule.java
+++ b/src/main/java/com/gitblit/DaggerModule.java
@@ -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() {
diff --git a/src/main/java/com/gitblit/FederationClient.java b/src/main/java/com/gitblit/FederationClient.java
index eae6b94f..862b64c1 100644
--- a/src/main/java/com/gitblit/FederationClient.java
+++ b/src/main/java/com/gitblit/FederationClient.java
@@ -84,7 +84,7 @@ public class FederationClient {
// configure the Gitblit singleton for minimal, non-server operation
GitBlit gitblit = new GitBlit(settings, baseFolder);
- gitblit.configureContext(settings, baseFolder, false);
+ gitblit.beforeServletInjection(null); // XXX broken
FederationPullExecutor executor = new FederationPullExecutor(registrations, params.isDaemon);
executor.run();
if (!params.isDaemon) {
diff --git a/src/main/java/com/gitblit/FileSettings.java b/src/main/java/com/gitblit/FileSettings.java
index 12739d20..d31fc2fb 100644
--- a/src/main/java/com/gitblit/FileSettings.java
+++ b/src/main/java/com/gitblit/FileSettings.java
@@ -32,7 +32,7 @@ import com.gitblit.utils.FileUtils;
*/
public class FileSettings extends IStoredSettings {
- protected final File propertiesFile;
+ protected File propertiesFile;
private final Properties properties = new Properties();
@@ -40,18 +40,41 @@ public class FileSettings extends IStoredSettings {
private volatile boolean forceReload;
- public FileSettings(String file) {
+ public FileSettings() {
super(FileSettings.class);
+ }
+
+ public FileSettings(String file) {
+ this();
+ load(file);
+ }
+
+ public void load(String file) {
this.propertiesFile = new File(file);
}
/**
+ * Merges the provided settings into this instance. This will also
+ * set the target file for this instance IFF it is unset AND the merge
+ * source is also a FileSettings. This is a little sneaky.
+ */
+ @Override
+ public void merge(IStoredSettings settings) {
+ super.merge(settings);
+
+ // sneaky: set the target file from the merge source
+ if (propertiesFile == null && settings instanceof FileSettings) {
+ this.propertiesFile = ((FileSettings) settings).propertiesFile;
+ }
+ }
+
+ /**
* Returns a properties object which contains the most recent contents of
* the properties file.
*/
@Override
protected synchronized Properties read() {
- if (propertiesFile.exists() && (forceReload || (propertiesFile.lastModified() > lastModified))) {
+ if (propertiesFile != null && propertiesFile.exists() && (forceReload || (propertiesFile.lastModified() > lastModified))) {
FileInputStream is = null;
try {
Properties props = new Properties();
diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java
index b121b2b9..91a44b7e 100644
--- a/src/main/java/com/gitblit/GitBlit.java
+++ b/src/main/java/com/gitblit/GitBlit.java
@@ -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;
}
/**
@@ -302,71 +286,6 @@ public class GitBlit extends DaggerContextListener
}
/**
- * 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);
}
@@ -3370,36 +3260,13 @@ 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
* description of the setting and and directives about the setting.
*
* @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.
diff --git a/src/main/java/com/gitblit/GitBlitServer.java b/src/main/java/com/gitblit/GitBlitServer.java
index 292eec40..fe29804d 100644
--- a/src/main/java/com/gitblit/GitBlitServer.java
+++ b/src/main/java/com/gitblit/GitBlitServer.java
@@ -409,9 +409,8 @@ public class GitBlitServer {
rootContext.setHandler(sh);
}
- // Setup the GitBlit context
+ // Setup the Gitblit context
GitBlit gitblit = newGitblit(settings, baseFolder);
- gitblit.configureContext(settings, baseFolder, true);
rootContext.addEventListener(gitblit);
try {
diff --git a/src/main/java/com/gitblit/Gitblit.java b/src/main/java/com/gitblit/Gitblit.java
index 32157545..687e4e20 100644
--- a/src/main/java/com/gitblit/Gitblit.java
+++ b/src/main/java/com/gitblit/Gitblit.java
@@ -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
*/
diff --git a/src/main/java/com/gitblit/IStoredSettings.java b/src/main/java/com/gitblit/IStoredSettings.java
index 01c478f8..6b58e89a 100644
--- a/src/main/java/com/gitblit/IStoredSettings.java
+++ b/src/main/java/com/gitblit/IStoredSettings.java
@@ -351,4 +351,13 @@ public abstract class IStoredSettings {
* @return true if successful
*/
public abstract boolean saveSettings(Map<String, String> updatedSettings);
+
+ /**
+ * Merge all settings from the settings parameter into this instance.
+ *
+ * @param settings
+ */
+ public void merge(IStoredSettings settings) {
+ getSettings().putAll(settings.getSettings());
+ }
} \ 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
index 00000000..955c6100
--- /dev/null
+++ b/src/main/java/com/gitblit/manager/IManager.java
@@ -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();
+}
diff --git a/src/main/java/com/gitblit/manager/IRuntimeManager.java b/src/main/java/com/gitblit/manager/IRuntimeManager.java
index 178b93ca..94ce3800 100644
--- a/src/main/java/com/gitblit/manager/IRuntimeManager.java
+++ b/src/main/java/com/gitblit/manager/IRuntimeManager.java
@@ -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
index 00000000..cfb4543e
--- /dev/null
+++ b/src/main/java/com/gitblit/manager/RuntimeManager.java
@@ -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;
+ }
+}
diff --git a/src/main/java/com/gitblit/models/ServerStatus.java b/src/main/java/com/gitblit/models/ServerStatus.java
index f8afd00a..bb6396bc 100644
--- a/src/main/java/com/gitblit/models/ServerStatus.java
+++ b/src/main/java/com/gitblit/models/ServerStatus.java
@@ -39,8 +39,6 @@ public class ServerStatus implements Serializable {
public final String releaseDate;
- public final boolean isGO;
-
public final Map<String, String> systemProperties;
public final long heapMaximum;
@@ -49,13 +47,14 @@ public class ServerStatus implements Serializable {
public volatile long heapFree;
+ public boolean isGO;
+
public String servletContainer;
- public ServerStatus(boolean isGO) {
+ public ServerStatus() {
this.bootDate = new Date();
this.version = Constants.getVersion();
this.releaseDate = Constants.getBuildDate();
- this.isGO = isGO;
this.heapMaximum = Runtime.getRuntime().maxMemory();
diff --git a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
index b42d29a5..aaa6c668 100644
--- a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
+++ b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
@@ -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;
+ }
}