From 7d3a31514afbe88664081b4ea57cd7939de99014 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Thu, 03 Jul 2014 17:00:40 -0400
Subject: [PATCH] Extract services manager into a top-level injectable manager

---
 src/main/java/com/gitblit/manager/IServicesManager.java         |   75 +++++
 src/main/java/com/gitblit/manager/IRuntimeManager.java          |   36 --
 src/main/java/com/gitblit/servlet/GitblitContext.java           |    2 
 src/main/java/com/gitblit/wicket/GitBlitWebApp.java             |   20 +
 src/main/java/com/gitblit/wicket/pages/TicketPage.java          |    2 
 src/main/java/com/gitblit/wicket/pages/UserPage.java            |    8 
 src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java |    4 
 src/main/java/com/gitblit/GitBlit.java                          |  181 ------------
 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java |    2 
 src/main/java/com/gitblit/manager/RuntimeManager.java           |   51 ---
 src/main/java/com/gitblit/wicket/GitblitWicketApp.java          |    3 
 src/main/java/com/gitblit/guice/WorkQueueProvider.java          |   57 ++++
 src/main/java/com/gitblit/manager/IGitblit.java                 |   15 -
 src/main/java/com/gitblit/manager/GitblitManager.java           |   84 ------
 src/main/java/com/gitblit/manager/ServicesManager.java          |  226 +++++++++++++++-
 src/main/java/com/gitblit/manager/RepositoryManager.java        |   26 -
 src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java    |   20 -
 src/main/java/com/gitblit/guice/CoreModule.java                 |    9 
 18 files changed, 397 insertions(+), 424 deletions(-)

diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java
index a39b0fc..edad32e 100644
--- a/src/main/java/com/gitblit/GitBlit.java
+++ b/src/main/java/com/gitblit/GitBlit.java
@@ -25,10 +25,7 @@
 import java.util.Set;
 
 import com.google.inject.Inject;
-import javax.servlet.http.HttpServletRequest;
 
-import com.gitblit.Constants.AccessPermission;
-import com.gitblit.Constants.Transport;
 import com.gitblit.manager.GitblitManager;
 import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IFederationManager;
@@ -39,9 +36,7 @@
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.manager.IUserManager;
-import com.gitblit.manager.ServicesManager;
 import com.gitblit.models.RepositoryModel;
-import com.gitblit.models.RepositoryUrl;
 import com.gitblit.models.UserModel;
 import com.gitblit.tickets.ITicketService;
 import com.gitblit.tickets.NullTicketService;
@@ -61,8 +56,6 @@
 public class GitBlit extends GitblitManager {
 
 	private final Injector injector;
-
-	private final ServicesManager servicesManager;
 
 	private ITicketService ticketService;
 
@@ -89,15 +82,11 @@
 				federationManager);
 
 		this.injector = Guice.createInjector(getModules());
-
-		this.servicesManager = new ServicesManager(this);
 	}
 
 	@Override
 	public GitBlit start() {
 		super.start();
-		logger.info("Starting services manager...");
-		servicesManager.start();
 		configureTicketService();
 		return this;
 	}
@@ -105,182 +94,12 @@
 	@Override
 	public GitBlit stop() {
 		super.stop();
-		servicesManager.stop();
 		ticketService.stop();
 		return this;
 	}
 
-	@Override
-	public boolean isServingRepositories() {
-		return servicesManager.isServingRepositories();
-	}
-
-	@Override
-	public boolean isServingHTTP() {
-		return servicesManager.isServingHTTP();
-	}
-
-	@Override
-	public boolean isServingGIT() {
-		return servicesManager.isServingGIT();
-	}
-
-	@Override
-	public boolean isServingSSH() {
-		return servicesManager.isServingSSH();
-	}
-
 	protected AbstractModule [] getModules() {
 		return new AbstractModule [] { new GitBlitModule()};
-	}
-
-	protected boolean acceptPush(Transport byTransport) {
-		if (byTransport == null) {
-			logger.info("Unknown transport, push rejected!");
-			return false;
-		}
-
-		Set<Transport> transports = new HashSet<Transport>();
-		for (String value : getSettings().getStrings(Keys.git.acceptedPushTransports)) {
-			Transport transport = Transport.fromString(value);
-			if (transport == null) {
-				logger.info(String.format("Ignoring unknown registered transport %s", value));
-				continue;
-			}
-
-			transports.add(transport);
-		}
-
-		if (transports.isEmpty()) {
-			// no transports are explicitly specified, all are acceptable
-			return true;
-		}
-
-		// verify that the transport is permitted
-		return transports.contains(byTransport);
-	}
-
-	/**
-	 * Returns a list of repository URLs and the user access permission.
-	 *
-	 * @param request
-	 * @param user
-	 * @param repository
-	 * @return a list of repository urls
-	 */
-	@Override
-	public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) {
-		if (user == null) {
-			user = UserModel.ANONYMOUS;
-		}
-		String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username);
-
-		List<RepositoryUrl> list = new ArrayList<RepositoryUrl>();
-
-		// http/https url
-		if (settings.getBoolean(Keys.git.enableGitServlet, true)) {
-			AccessPermission permission = user.getRepositoryPermission(repository).permission;
-			if (permission.exceeds(AccessPermission.NONE)) {
-				Transport transport = Transport.fromString(request.getScheme());
-				if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(transport)) {
-					// downgrade the repo permission for this transport
-					// because it is not an acceptable PUSH transport
-					permission = AccessPermission.CLONE;
-				}
-				list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission));
-			}
-		}
-
-		// ssh daemon url
-		String sshDaemonUrl = servicesManager.getSshDaemonUrl(request, user, repository);
-		if (!StringUtils.isEmpty(sshDaemonUrl)) {
-			AccessPermission permission = user.getRepositoryPermission(repository).permission;
-			if (permission.exceeds(AccessPermission.NONE)) {
-				if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.SSH)) {
-					// downgrade the repo permission for this transport
-					// because it is not an acceptable PUSH transport
-					permission = AccessPermission.CLONE;
-				}
-
-				list.add(new RepositoryUrl(sshDaemonUrl, permission));
-			}
-		}
-
-		// git daemon url
-		String gitDaemonUrl = servicesManager.getGitDaemonUrl(request, user, repository);
-		if (!StringUtils.isEmpty(gitDaemonUrl)) {
-			AccessPermission permission = servicesManager.getGitDaemonAccessPermission(user, repository);
-			if (permission.exceeds(AccessPermission.NONE)) {
-				if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.GIT)) {
-					// downgrade the repo permission for this transport
-					// because it is not an acceptable PUSH transport
-					permission = AccessPermission.CLONE;
-				}
-				list.add(new RepositoryUrl(gitDaemonUrl, permission));
-			}
-		}
-
-		// add all other urls
-		// {0} = repository
-		// {1} = username
-		for (String url : settings.getStrings(Keys.web.otherUrls)) {
-			if (url.contains("{1}")) {
-				// external url requires username, only add url IF we have one
-				if (!StringUtils.isEmpty(username)) {
-					list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null));
-				}
-			} else {
-				// external url does not require username
-				list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null));
-			}
-		}
-
-		// sort transports by highest permission and then by transport security
-		Collections.sort(list, new Comparator<RepositoryUrl>() {
-
-			@Override
-			public int compare(RepositoryUrl o1, RepositoryUrl o2) {
-				if (!o1.isExternal() && o2.isExternal()) {
-					// prefer Gitblit over external
-					return -1;
-				} else if (o1.isExternal() && !o2.isExternal()) {
-					// prefer Gitblit over external
-					return 1;
-				} else if (o1.isExternal() && o2.isExternal()) {
-					// sort by Transport ordinal
-					return o1.transport.compareTo(o2.transport);
-				} else if (o1.permission.exceeds(o2.permission)) {
-					// prefer highest permission
-					return -1;
-				} else if (o2.permission.exceeds(o1.permission)) {
-					// prefer highest permission
-					return 1;
-				}
-
-				// prefer more secure transports
-				return o1.transport.compareTo(o2.transport);
-			}
-		});
-
-		// consider the user's transport preference
-		RepositoryUrl preferredUrl = null;
-		Transport preferredTransport = user.getPreferences().getTransport();
-		if (preferredTransport != null) {
-			Iterator<RepositoryUrl> itr = list.iterator();
-			while (itr.hasNext()) {
-				RepositoryUrl url = itr.next();
-				if (url.transport.equals(preferredTransport)) {
-					itr.remove();
-					preferredUrl = url;
-					break;
-				}
-			}
-		}
-		if (preferredUrl != null) {
-			list.add(0, preferredUrl);
-		}
-
-		return list;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/guice/CoreModule.java b/src/main/java/com/gitblit/guice/CoreModule.java
index 89be94f..03cdbf2 100644
--- a/src/main/java/com/gitblit/guice/CoreModule.java
+++ b/src/main/java/com/gitblit/guice/CoreModule.java
@@ -31,18 +31,21 @@
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.manager.IServicesManager;
 import com.gitblit.manager.IUserManager;
 import com.gitblit.manager.NotificationManager;
 import com.gitblit.manager.PluginManager;
 import com.gitblit.manager.ProjectManager;
 import com.gitblit.manager.RepositoryManager;
 import com.gitblit.manager.RuntimeManager;
+import com.gitblit.manager.ServicesManager;
 import com.gitblit.manager.UserManager;
 import com.gitblit.transport.ssh.FileKeyManager;
 import com.gitblit.transport.ssh.IPublicKeyManager;
 import com.gitblit.transport.ssh.MemoryKeyManager;
 import com.gitblit.transport.ssh.NullKeyManager;
 import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.WorkQueue;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 
@@ -59,6 +62,9 @@
 
 		bind(IStoredSettings.class).toInstance(new FileSettings());
 
+		// bind complex providers
+		bind(WorkQueue.class).toProvider(WorkQueueProvider.class);
+		
 		// core managers
 		bind(IRuntimeManager.class).to(RuntimeManager.class).in(Singleton.class);
 		bind(IPluginManager.class).to(PluginManager.class).in(Singleton.class);
@@ -71,6 +77,9 @@
 
 		// the monolithic manager
 		bind(IGitblit.class).to(GitBlit.class).in(Singleton.class);
+
+		// manager for long-running daemons and services
+		bind(IServicesManager.class).to(ServicesManager.class);
 	}
 
 	@Provides
diff --git a/src/main/java/com/gitblit/guice/WorkQueueProvider.java b/src/main/java/com/gitblit/guice/WorkQueueProvider.java
new file mode 100644
index 0000000..cde27ea
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/WorkQueueProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 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.guice;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.Keys;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.utils.IdGenerator;
+import com.gitblit.utils.WorkQueue;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * Provides a lazily-instantiated WorkQueue configured from IStoredSettings.
+ *
+ * @author James Moger
+ *
+ */
+@Singleton
+public class WorkQueueProvider implements Provider<WorkQueue> {
+
+	private final IRuntimeManager runtimeManager;
+
+	private volatile WorkQueue workQueue;
+
+	@Inject
+	public WorkQueueProvider(IRuntimeManager runtimeManager) {
+		this.runtimeManager = runtimeManager;
+	}
+
+	@Override
+	public synchronized WorkQueue get() {
+		if (workQueue != null) {
+			return workQueue;
+		}
+
+		IStoredSettings settings = runtimeManager.getSettings();
+		int defaultThreadPoolSize = settings.getInteger(Keys.execution.defaultThreadPoolSize, 1);
+		IdGenerator idGenerator = new IdGenerator();
+		workQueue = new WorkQueue(idGenerator, defaultThreadPoolSize);
+		return workQueue;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
index a0718f7..2c88e40 100644
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ b/src/main/java/com/gitblit/manager/GitblitManager.java
@@ -49,12 +49,10 @@
 
 import com.gitblit.Constants;
 import com.gitblit.Constants.AccessPermission;
-import com.gitblit.Constants.AccessRestrictionType;
 import com.gitblit.Constants.FederationRequest;
 import com.gitblit.Constants.FederationToken;
 import com.gitblit.GitBlitException;
 import com.gitblit.IStoredSettings;
-import com.gitblit.Keys;
 import com.gitblit.models.FederationModel;
 import com.gitblit.models.FederationProposal;
 import com.gitblit.models.FederationSet;
@@ -68,7 +66,6 @@
 import com.gitblit.models.ProjectModel;
 import com.gitblit.models.RegistrantAccessPermission;
 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;
@@ -79,7 +76,6 @@
 import com.gitblit.transport.ssh.IPublicKeyManager;
 import com.gitblit.transport.ssh.SshKey;
 import com.gitblit.utils.ArrayUtils;
-import com.gitblit.utils.HttpUtils;
 import com.gitblit.utils.JsonUtils;
 import com.gitblit.utils.ObjectCache;
 import com.gitblit.utils.StringUtils;
@@ -351,66 +347,6 @@
 	}
 
 	/**
-	 * Returns a list of repository URLs and the user access permission.
-	 *
-	 * @param request
-	 * @param user
-	 * @param repository
-	 * @return a list of repository urls
-	 */
-	@Override
-	public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) {
-		if (user == null) {
-			user = UserModel.ANONYMOUS;
-		}
-		String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username);
-
-		List<RepositoryUrl> list = new ArrayList<RepositoryUrl>();
-		// http/https url
-		if (settings.getBoolean(Keys.git.enableGitServlet, true)) {
-			AccessPermission permission = user.getRepositoryPermission(repository).permission;
-			if (permission.exceeds(AccessPermission.NONE)) {
-				list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission));
-			}
-		}
-
-		// add all other urls
-		// {0} = repository
-		// {1} = username
-		for (String url : settings.getStrings(Keys.web.otherUrls)) {
-			if (url.contains("{1}")) {
-				// external url requires username, only add url IF we have one
-				if (!StringUtils.isEmpty(username)) {
-					list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null));
-				}
-			} else {
-				// external url does not require username
-				list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null));
-			}
-		}
-		return list;
-	}
-
-	protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) {
-		String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null);
-		if (StringUtils.isEmpty(gitblitUrl)) {
-			gitblitUrl = HttpUtils.getGitblitURL(request);
-		}
-		StringBuilder sb = new StringBuilder();
-		sb.append(gitblitUrl);
-		sb.append(Constants.R_PATH);
-		sb.append(repository.name);
-
-		// inject username into repository url if authentication is required
-		if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE)
-				&& !StringUtils.isEmpty(username)) {
-			sb.insert(sb.indexOf("://") + 3, username + "@");
-		}
-		return sb.toString();
-	}
-
-
-	/**
 	 * Returns the list of custom client applications to be used for the
 	 * repository url panel;
 	 *
@@ -595,26 +531,6 @@
 	@Override
 	public ServerSettings getSettingsModel() {
 		return runtimeManager.getSettingsModel();
-	}
-
-	@Override
-	public boolean isServingRepositories() {
-		return runtimeManager.isServingRepositories();
-	}
-
-	@Override
-	public boolean isServingHTTP() {
-		return runtimeManager.isServingHTTP();
-	}
-
-	@Override
-	public boolean isServingGIT() {
-		return runtimeManager.isServingGIT();
-	}
-
-	@Override
-	public boolean isServingSSH() {
-		return runtimeManager.isServingSSH();
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/manager/IGitblit.java b/src/main/java/com/gitblit/manager/IGitblit.java
index 50ec8b1..6c5b374 100644
--- a/src/main/java/com/gitblit/manager/IGitblit.java
+++ b/src/main/java/com/gitblit/manager/IGitblit.java
@@ -16,14 +16,10 @@
 package com.gitblit.manager;
 
 import java.util.Collection;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
 
 import com.gitblit.GitBlitException;
 import com.gitblit.models.GitClientApplication;
 import com.gitblit.models.RepositoryModel;
-import com.gitblit.models.RepositoryUrl;
 import com.gitblit.models.TeamModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.tickets.ITicketService;
@@ -38,17 +34,6 @@
 									IRepositoryManager,
 									IProjectManager,
 									IFederationManager {
-
-	/**
-	 * Returns a list of repository URLs and the user access permission.
-	 *
-	 * @param request
-	 * @param user
-	 * @param repository
-	 * @return a list of repository urls
-	 * @since 1.4.0
-	 */
-	List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository);
 
 	/**
 	 * Creates a complete user object.
diff --git a/src/main/java/com/gitblit/manager/IRuntimeManager.java b/src/main/java/com/gitblit/manager/IRuntimeManager.java
index f736a05..8322d34 100644
--- a/src/main/java/com/gitblit/manager/IRuntimeManager.java
+++ b/src/main/java/com/gitblit/manager/IRuntimeManager.java
@@ -51,42 +51,6 @@
 	Locale getLocale();
 
 	/**
-	 * 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
- 	 * @since 1.4.0
-	 */
-	boolean isServingRepositories();
-
-	/**
-	 * Determine if this Gitblit instance is actively serving git repositories
-	 * over HTTP.
-	 *
-	 * @return true if Gitblit is serving repositories over HTTP
- 	 * @since 1.6.0
-	 */
-	boolean isServingHTTP();
-
-	/**
-	 * Determine if this Gitblit instance is actively serving git repositories
-	 * over the GIT Daemon protocol.
-	 *
-	 * @return true if Gitblit is serving repositories over the GIT Daemon protocol
- 	 * @since 1.6.0
-	 */
-	boolean isServingGIT();
-
-	/**
-	 * Determine if this Gitblit instance is actively serving git repositories
-	 * over the SSH protocol.
-	 *
-	 * @return true if Gitblit is serving repositories over the SSH protocol
- 	 * @since 1.6.0
-	 */
-	boolean isServingSSH();
-
-	/**
 	 * Determine if this Gitblit instance is running in debug mode
 	 *
 	 * @return true if Gitblit is running in debug mode
diff --git a/src/main/java/com/gitblit/manager/IServicesManager.java b/src/main/java/com/gitblit/manager/IServicesManager.java
new file mode 100644
index 0000000..5bb135d
--- /dev/null
+++ b/src/main/java/com/gitblit/manager/IServicesManager.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014 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.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.RepositoryUrl;
+import com.gitblit.models.UserModel;
+
+public interface IServicesManager extends IManager {
+
+	/**
+	 * 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
+ 	 * @since 1.7.0
+	 */
+	boolean isServingRepositories();
+
+	/**
+	 * Determine if this Gitblit instance is actively serving git repositories
+	 * over HTTP.
+	 *
+	 * @return true if Gitblit is serving repositories over HTTP
+ 	 * @since 1.7.0
+	 */
+	boolean isServingHTTP();
+
+	/**
+	 * Determine if this Gitblit instance is actively serving git repositories
+	 * over the GIT Daemon protocol.
+	 *
+	 * @return true if Gitblit is serving repositories over the GIT Daemon protocol
+ 	 * @since 1.7.0
+	 */
+	boolean isServingGIT();
+
+	/**
+	 * Determine if this Gitblit instance is actively serving git repositories
+	 * over the SSH protocol.
+	 *
+	 * @return true if Gitblit is serving repositories over the SSH protocol
+ 	 * @since 1.7.0
+	 */
+	boolean isServingSSH();
+
+	/**
+	 * Returns a list of repository URLs and the user access permission.
+	 *
+	 * @param request
+	 * @param user
+	 * @param repository
+	 * @return a list of repository urls
+	 * @since 1.7.0
+	 */
+	List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java
index 9b061e2..a417c02 100644
--- a/src/main/java/com/gitblit/manager/RepositoryManager.java
+++ b/src/main/java/com/gitblit/manager/RepositoryManager.java
@@ -1937,21 +1937,19 @@
 	}
 
 	protected void confirmWriteAccess() {
-		if (runtimeManager.isServingRepositories()) {
-			try {
-				if (!getRepositoriesFolder().exists()) {
-					getRepositoriesFolder().mkdirs();
-				}
-				File file = File.createTempFile(".test-", ".txt", getRepositoriesFolder());
-				file.delete();
-			} catch (Exception e) {
-				logger.error("");
-				logger.error(Constants.BORDER2);
-				logger.error("Please check filesystem permissions!");
-				logger.error("FAILED TO WRITE TO REPOSITORIES FOLDER!!", e);
-				logger.error(Constants.BORDER2);
-				logger.error("");
+		try {
+			if (!getRepositoriesFolder().exists()) {
+				getRepositoriesFolder().mkdirs();
 			}
+			File file = File.createTempFile(".test-", ".txt", getRepositoriesFolder());
+			file.delete();
+		} catch (Exception e) {
+			logger.error("");
+			logger.error(Constants.BORDER2);
+			logger.error("Please check filesystem permissions!");
+			logger.error("FAILED TO WRITE TO REPOSITORIES FOLDER!!", e);
+			logger.error(Constants.BORDER2);
+			logger.error("");
 		}
 	}
 }
diff --git a/src/main/java/com/gitblit/manager/RuntimeManager.java b/src/main/java/com/gitblit/manager/RuntimeManager.java
index 383b1dc..95a363f 100644
--- a/src/main/java/com/gitblit/manager/RuntimeManager.java
+++ b/src/main/java/com/gitblit/manager/RuntimeManager.java
@@ -22,8 +22,6 @@
 import java.util.Map;
 import java.util.TimeZone;
 
-import com.google.inject.Inject;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,8 +32,11 @@
 import com.gitblit.models.ServerStatus;
 import com.gitblit.models.SettingModel;
 import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
 import com.google.inject.Injector;
+import com.google.inject.Singleton;
 
+@Singleton
 public class RuntimeManager implements IRuntimeManager {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -121,52 +122,6 @@
 		}
 //		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 isServingHTTP()
-				|| isServingGIT()
-				|| isServingSSH();
-	}
-
-	/**
-	 * Determine if this Gitblit instance is actively serving git repositories
-	 * over the HTTP protocol.
-	 *
-	 * @return true if Gitblit is serving repositories over the HTTP protocol
-	 */
-	@Override
-	public boolean isServingHTTP() {
-		return settings.getBoolean(Keys.git.enableGitServlet, true);
-	}
-
-	/**
-	 * Determine if this Gitblit instance is actively serving git repositories
-	 * over the Git Daemon protocol.
-	 *
-	 * @return true if Gitblit is serving repositories over the Git Daemon protocol
-	 */
-	@Override
-	public boolean isServingGIT() {
-		return settings.getInteger(Keys.git.daemonPort, 0) > 0;
-	}
-
-	/**
-	 * Determine if this Gitblit instance is actively serving git repositories
-	 * over the SSH protocol.
-	 *
-	 * @return true if Gitblit is serving repositories over the SSH protocol
-	 */
-	@Override
-	public boolean isServingSSH() {
-		return settings.getInteger(Keys.git.sshPort, 0) > 0;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/manager/ServicesManager.java b/src/main/java/com/gitblit/manager/ServicesManager.java
index 3721578..2550f66 100644
--- a/src/main/java/com/gitblit/manager/ServicesManager.java
+++ b/src/main/java/com/gitblit/manager/ServicesManager.java
@@ -18,9 +18,15 @@
 import java.io.IOException;
 import java.net.URI;
 import java.text.MessageFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -30,9 +36,11 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.gitblit.Constants;
 import com.gitblit.Constants.AccessPermission;
 import com.gitblit.Constants.AccessRestrictionType;
 import com.gitblit.Constants.FederationToken;
+import com.gitblit.Constants.Transport;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
 import com.gitblit.fanout.FanoutNioService;
@@ -40,14 +48,18 @@
 import com.gitblit.fanout.FanoutSocketService;
 import com.gitblit.models.FederationModel;
 import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.RepositoryUrl;
 import com.gitblit.models.UserModel;
 import com.gitblit.service.FederationPullService;
 import com.gitblit.transport.git.GitDaemon;
 import com.gitblit.transport.ssh.SshDaemon;
-import com.gitblit.utils.IdGenerator;
+import com.gitblit.utils.HttpUtils;
 import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.TimeUtils;
 import com.gitblit.utils.WorkQueue;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 /**
  * Services manager manages long-running services/processes that either have no
@@ -57,19 +69,18 @@
  * @author James Moger
  *
  */
-public class ServicesManager implements IManager {
+@Singleton
+public class ServicesManager implements IServicesManager {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
 
 	private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(5);
 
+	private final Provider<WorkQueue> workQueueProvider;
+
 	private final IStoredSettings settings;
 
 	private final IGitblit gitblit;
-
-	private final IdGenerator idGenerator;
-
-	private final WorkQueue workQueue;
 
 	private FanoutService fanoutService;
 
@@ -77,12 +88,16 @@
 
 	private SshDaemon sshDaemon;
 
-	public ServicesManager(IGitblit gitblit) {
-		this.settings = gitblit.getSettings();
+	@Inject
+	public ServicesManager(
+			Provider<WorkQueue> workQueueProvider,
+			IStoredSettings settings,
+			IGitblit gitblit) {
+
+		this.workQueueProvider = workQueueProvider;
+
+		this.settings = settings;
 		this.gitblit = gitblit;
-		int defaultThreadPoolSize = settings.getInteger(Keys.execution.defaultThreadPoolSize, 1);
-		this.idGenerator = new IdGenerator();
-		this.workQueue = new WorkQueue(idGenerator, defaultThreadPoolSize);
 	}
 
 	@Override
@@ -107,24 +122,181 @@
 		if (sshDaemon != null) {
 			sshDaemon.stop();
 		}
-		workQueue.stop();
+		workQueueProvider.get().stop();
 		return this;
 	}
 
+	protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) {
+		String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null);
+		if (StringUtils.isEmpty(gitblitUrl)) {
+			gitblitUrl = HttpUtils.getGitblitURL(request);
+		}
+		StringBuilder sb = new StringBuilder();
+		sb.append(gitblitUrl);
+		sb.append(Constants.R_PATH);
+		sb.append(repository.name);
+
+		// inject username into repository url if authentication is required
+		if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE)
+				&& !StringUtils.isEmpty(username)) {
+			sb.insert(sb.indexOf("://") + 3, username + "@");
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * Returns a list of repository URLs and the user access permission.
+	 *
+	 * @param request
+	 * @param user
+	 * @param repository
+	 * @return a list of repository urls
+	 */
+	@Override
+	public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) {
+		if (user == null) {
+			user = UserModel.ANONYMOUS;
+		}
+		String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username);
+
+		List<RepositoryUrl> list = new ArrayList<RepositoryUrl>();
+
+		// http/https url
+		if (settings.getBoolean(Keys.git.enableGitServlet, true)) {
+			AccessPermission permission = user.getRepositoryPermission(repository).permission;
+			if (permission.exceeds(AccessPermission.NONE)) {
+				Transport transport = Transport.fromString(request.getScheme());
+				if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(transport)) {
+					// downgrade the repo permission for this transport
+					// because it is not an acceptable PUSH transport
+					permission = AccessPermission.CLONE;
+				}
+				list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission));
+			}
+		}
+
+		// ssh daemon url
+		String sshDaemonUrl = getSshDaemonUrl(request, user, repository);
+		if (!StringUtils.isEmpty(sshDaemonUrl)) {
+			AccessPermission permission = user.getRepositoryPermission(repository).permission;
+			if (permission.exceeds(AccessPermission.NONE)) {
+				if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.SSH)) {
+					// downgrade the repo permission for this transport
+					// because it is not an acceptable PUSH transport
+					permission = AccessPermission.CLONE;
+				}
+
+				list.add(new RepositoryUrl(sshDaemonUrl, permission));
+			}
+		}
+
+		// git daemon url
+		String gitDaemonUrl = getGitDaemonUrl(request, user, repository);
+		if (!StringUtils.isEmpty(gitDaemonUrl)) {
+			AccessPermission permission = getGitDaemonAccessPermission(user, repository);
+			if (permission.exceeds(AccessPermission.NONE)) {
+				if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.GIT)) {
+					// downgrade the repo permission for this transport
+					// because it is not an acceptable PUSH transport
+					permission = AccessPermission.CLONE;
+				}
+				list.add(new RepositoryUrl(gitDaemonUrl, permission));
+			}
+		}
+
+		// add all other urls
+		// {0} = repository
+		// {1} = username
+		for (String url : settings.getStrings(Keys.web.otherUrls)) {
+			if (url.contains("{1}")) {
+				// external url requires username, only add url IF we have one
+				if (!StringUtils.isEmpty(username)) {
+					list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null));
+				}
+			} else {
+				// external url does not require username
+				list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null));
+			}
+		}
+
+		// sort transports by highest permission and then by transport security
+		Collections.sort(list, new Comparator<RepositoryUrl>() {
+
+			@Override
+			public int compare(RepositoryUrl o1, RepositoryUrl o2) {
+				if (!o1.isExternal() && o2.isExternal()) {
+					// prefer Gitblit over external
+					return -1;
+				} else if (o1.isExternal() && !o2.isExternal()) {
+					// prefer Gitblit over external
+					return 1;
+				} else if (o1.isExternal() && o2.isExternal()) {
+					// sort by Transport ordinal
+					return o1.transport.compareTo(o2.transport);
+				} else if (o1.permission.exceeds(o2.permission)) {
+					// prefer highest permission
+					return -1;
+				} else if (o2.permission.exceeds(o1.permission)) {
+					// prefer highest permission
+					return 1;
+				}
+
+				// prefer more secure transports
+				return o1.transport.compareTo(o2.transport);
+			}
+		});
+
+		// consider the user's transport preference
+		RepositoryUrl preferredUrl = null;
+		Transport preferredTransport = user.getPreferences().getTransport();
+		if (preferredTransport != null) {
+			Iterator<RepositoryUrl> itr = list.iterator();
+			while (itr.hasNext()) {
+				RepositoryUrl url = itr.next();
+				if (url.transport.equals(preferredTransport)) {
+					itr.remove();
+					preferredUrl = url;
+					break;
+				}
+			}
+		}
+		if (preferredUrl != null) {
+			list.add(0, preferredUrl);
+		}
+
+		return list;
+	}
+
+	/* (non-Javadoc)
+	 * @see com.gitblit.manager.IServicesManager#isServingRepositories()
+	 */
+	@Override
 	public boolean isServingRepositories() {
 		return isServingHTTP()
 				|| isServingGIT()
 				|| isServingSSH();
 	}
 
+	/* (non-Javadoc)
+	 * @see com.gitblit.manager.IServicesManager#isServingHTTP()
+	 */
+	@Override
 	public boolean isServingHTTP() {
 		return settings.getBoolean(Keys.git.enableGitServlet, true);
 	}
 
+	/* (non-Javadoc)
+	 * @see com.gitblit.manager.IServicesManager#isServingGIT()
+	 */
+	@Override
 	public boolean isServingGIT() {
 		return gitDaemon != null && gitDaemon.isRunning();
 	}
 
+	/* (non-Javadoc)
+	 * @see com.gitblit.manager.IServicesManager#isServingSSH()
+	 */
+	@Override
 	public boolean isServingSSH() {
 		return sshDaemon != null && sshDaemon.isRunning();
 	}
@@ -158,6 +330,32 @@
 		}
 	}
 
+	protected boolean acceptPush(Transport byTransport) {
+		if (byTransport == null) {
+			logger.info("Unknown transport, push rejected!");
+			return false;
+		}
+
+		Set<Transport> transports = new HashSet<Transport>();
+		for (String value : settings.getStrings(Keys.git.acceptedPushTransports)) {
+			Transport transport = Transport.fromString(value);
+			if (transport == null) {
+				logger.info(String.format("Ignoring unknown registered transport %s", value));
+				continue;
+			}
+
+			transports.add(transport);
+		}
+
+		if (transports.isEmpty()) {
+			// no transports are explicitly specified, all are acceptable
+			return true;
+		}
+
+		// verify that the transport is permitted
+		return transports.contains(byTransport);
+	}
+
 	protected void configureGitDaemon() {
 		int port = settings.getInteger(Keys.git.daemonPort, 0);
 		String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
@@ -179,7 +377,7 @@
 		String bindInterface = settings.getString(Keys.git.sshBindInterface, "localhost");
 		if (port > 0) {
 			try {
-				sshDaemon = new SshDaemon(gitblit, workQueue);
+				sshDaemon = new SshDaemon(gitblit, workQueueProvider.get());
 				sshDaemon.start();
 			} catch (IOException e) {
 				sshDaemon = null;
@@ -285,7 +483,7 @@
 	 */
 	protected String getHostname(HttpServletRequest request) {
 		String hostname = request.getServerName();
-		String canonicalUrl = gitblit.getSettings().getString(Keys.web.canonicalUrl, null);
+		String canonicalUrl = settings.getString(Keys.web.canonicalUrl, null);
 		if (!StringUtils.isEmpty(canonicalUrl)) {
 			try {
 				URI uri = new URI(canonicalUrl);
diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java
index e0f6003..44a857c 100644
--- a/src/main/java/com/gitblit/servlet/GitblitContext.java
+++ b/src/main/java/com/gitblit/servlet/GitblitContext.java
@@ -51,6 +51,7 @@
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.manager.IServicesManager;
 import com.gitblit.manager.IUserManager;
 import com.gitblit.transport.ssh.IPublicKeyManager;
 import com.gitblit.utils.ContainerUtils;
@@ -200,6 +201,7 @@
 		startManager(injector, IProjectManager.class);
 		startManager(injector, IFederationManager.class);
 		startManager(injector, IGitblit.class);
+		startManager(injector, IServicesManager.class);
 
 		// start the plugin manager last so that plugins can depend on
 		// deterministic access to all other managers in their start() methods
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index a907311..24468c0 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -21,9 +21,6 @@
 import java.util.Map;
 import java.util.TimeZone;
 
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
 import org.apache.wicket.Application;
 import org.apache.wicket.Request;
 import org.apache.wicket.Response;
@@ -46,6 +43,7 @@
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.manager.IServicesManager;
 import com.gitblit.manager.IUserManager;
 import com.gitblit.tickets.ITicketService;
 import com.gitblit.transport.ssh.IPublicKeyManager;
@@ -92,6 +90,8 @@
 import com.gitblit.wicket.pages.TreePage;
 import com.gitblit.wicket.pages.UserPage;
 import com.gitblit.wicket.pages.UsersPage;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 @Singleton
 public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
@@ -124,6 +124,8 @@
 
 	private final IGitblit gitblit;
 
+	private final IServicesManager services;
+
 	@Inject
 	public GitBlitWebApp(
 			IRuntimeManager runtimeManager,
@@ -135,7 +137,8 @@
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
 			IFederationManager federationManager,
-			IGitblit gitblit) {
+			IGitblit gitblit,
+			IServicesManager services) {
 
 		super();
 		this.settings = runtimeManager.getSettings();
@@ -149,6 +152,7 @@
 		this.projectManager = projectManager;
 		this.federationManager = federationManager;
 		this.gitblit = gitblit;
+		this.services = services;
 	}
 
 	@Override
@@ -421,6 +425,14 @@
 	}
 
 	/* (non-Javadoc)
+	 * @see com.gitblit.wicket.Webapp#services()
+	 */
+	@Override
+	public IServicesManager services() {
+		return services;
+	}
+
+	/* (non-Javadoc)
 	 * @see com.gitblit.wicket.Webapp#tickets()
 	 */
 	@Override
diff --git a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
index a56e699..7013097 100644
--- a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
+++ b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
@@ -14,6 +14,7 @@
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.manager.IServicesManager;
 import com.gitblit.manager.IUserManager;
 import com.gitblit.tickets.ITicketService;
 import com.gitblit.transport.ssh.IPublicKeyManager;
@@ -65,6 +66,8 @@
 
 	public abstract IGitblit gitblit();
 
+	public abstract IServicesManager services();
+
 	public abstract ITicketService tickets();
 
 	public abstract TimeZone getTimezone();
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java
index b3c5243..72d1e1a 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java
@@ -55,7 +55,7 @@
 		}
 
 		HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
-		List<RepositoryUrl> repositoryUrls = app().gitblit().getRepositoryUrls(req, user, repository);
+		List<RepositoryUrl> repositoryUrls = app().services().getRepositoryUrls(req, user, repository);
 		RepositoryUrl primaryUrl = repositoryUrls.size() == 0 ? null : repositoryUrls.get(0);
 		String url = primaryUrl != null ? primaryUrl.url : "";
 
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.java b/src/main/java/com/gitblit/wicket/pages/TicketPage.java
index f5f63d2..e1e8162 100644
--- a/src/main/java/com/gitblit/wicket/pages/TicketPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.java
@@ -1505,7 +1505,7 @@
 	 */
 	protected RepositoryUrl getRepositoryUrl(UserModel user, RepositoryModel repository) {
 		HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
-		List<RepositoryUrl> urls = app().gitblit().getRepositoryUrls(req, user, repository);
+		List<RepositoryUrl> urls = app().services().getRepositoryUrls(req, user, repository);
 		if (ArrayUtils.isEmpty(urls)) {
 			return null;
 		}
diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java
index 8931d5e..e21431d 100644
--- a/src/main/java/com/gitblit/wicket/pages/UserPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java
@@ -104,7 +104,7 @@
 		if (isMyProfile) {
 			addPreferences(user);
 
-			if (app().gitblit().isServingSSH()) {
+			if (app().services().isServingSSH()) {
 				// show the SSH key management tab
 				addSshKeys(user);
 			} else {
@@ -248,14 +248,14 @@
 				emailMeOnMyTicketChanges).setVisible(app().notifier().isSendingMail()));
 
 		List<Transport> availableTransports = new ArrayList<>();
-		if (app().gitblit().isServingSSH()) {
+		if (app().services().isServingSSH()) {
 			availableTransports.add(Transport.SSH);
 		}
-		if (app().gitblit().isServingHTTP()) {
+		if (app().services().isServingHTTP()) {
 			availableTransports.add(Transport.HTTPS);
 			availableTransports.add(Transport.HTTP);
 		}
-		if (app().gitblit().isServingGIT()) {
+		if (app().services().isServingGIT()) {
 			availableTransports.add(Transport.GIT);
 		}
 
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
index 938226a..0666fcd 100644
--- a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
@@ -80,7 +80,7 @@
 
 		HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
 
-		List<RepositoryUrl> repositoryUrls = app().gitblit().getRepositoryUrls(req, user, repository);
+		List<RepositoryUrl> repositoryUrls = app().services().getRepositoryUrls(req, user, repository);
 		// grab primary url from the top of the list
 		primaryUrl = repositoryUrls.size() == 0 ? null : repositoryUrls.get(0);
 
@@ -165,7 +165,7 @@
 		if (repository.isMirror) {
 			urlPanel.add(WicketUtils.newImage("accessRestrictionIcon", "mirror_16x16.png",
 					getString("gb.isMirror")));
-		} else if (app().gitblit().isServingRepositories()) {
+		} else if (app().services().isServingRepositories()) {
 			switch (repository.accessRestriction) {
 			case NONE:
 				urlPanel.add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
diff --git a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
index 36a0218..9a71c88 100644
--- a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
+++ b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
@@ -83,26 +83,6 @@
 	}
 
 	@Override
-	public boolean isServingRepositories() {
-		return true;
-	}
-
-	@Override
-	public boolean isServingHTTP() {
-		return true;
-	}
-
-	@Override
-	public boolean isServingGIT() {
-		return true;
-	}
-
-	@Override
-	public boolean isServingSSH() {
-		return true;
-	}
-
-	@Override
 	public boolean isDebugMode() {
 		return true;
 	}

--
Gitblit v1.9.1