From 3a9e76b63f09a32e0b6812e18ffff00fab8e58e6 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Fri, 29 Nov 2013 11:05:51 -0500
Subject: [PATCH] Flattened IGitblitManager, GitblitManager, and GitBlit classes

---
 src/main/java/com/gitblit/servlet/GitblitContext.java        |    6 
 src/main/java/com/gitblit/servlet/RpcServlet.java            |  111 +++-----
 src/main/java/com/gitblit/git/GitblitReceivePack.java        |    6 
 src/test/java/com/gitblit/tests/GitblitUnitTest.java         |    6 
 src/main/java/com/gitblit/wicket/GitBlitWebApp.java          |   20 
 src/main/java/com/gitblit/GitBlit.java                       |  415 ++++++++++++++++++++++++++++++---
 src/main/java/com/gitblit/git/GitServlet.java                |    6 
 src/main/java/com/gitblit/git/RepositoryResolver.java        |    6 
 src/main/java/com/gitblit/git/GitblitReceivePackFactory.java |    6 
 /dev/null                                                    |   21 -
 src/main/java/com/gitblit/DaggerModule.java                  |   36 --
 src/main/java/com/gitblit/manager/IGitblit.java              |    9 
 src/main/java/com/gitblit/manager/ServicesManager.java       |   45 +++
 13 files changed, 502 insertions(+), 191 deletions(-)

diff --git a/src/main/java/com/gitblit/DaggerModule.java b/src/main/java/com/gitblit/DaggerModule.java
index cc83694..135fafb 100644
--- a/src/main/java/com/gitblit/DaggerModule.java
+++ b/src/main/java/com/gitblit/DaggerModule.java
@@ -22,21 +22,18 @@
 import com.gitblit.git.GitServlet;
 import com.gitblit.manager.AuthenticationManager;
 import com.gitblit.manager.FederationManager;
-import com.gitblit.manager.GitblitManager;
 import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IFederationManager;
-import com.gitblit.manager.IGitblitManager;
+import com.gitblit.manager.IGitblit;
 import com.gitblit.manager.INotificationManager;
 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.ProjectManager;
 import com.gitblit.manager.RepositoryManager;
 import com.gitblit.manager.RuntimeManager;
-import com.gitblit.manager.ServicesManager;
 import com.gitblit.manager.UserManager;
 import com.gitblit.servlet.BranchGraphServlet;
 import com.gitblit.servlet.DownloadZipFilter;
@@ -77,12 +74,10 @@
 			IAuthenticationManager.class,
 			IRepositoryManager.class,
 			IProjectManager.class,
-			IGitblitManager.class,
 			IFederationManager.class,
-			IServicesManager.class,
 
 			// the monolithic manager
-			GitBlit.class,
+			IGitblit.class,
 
 			// filters & servlets
 			GitServlet.class,
@@ -164,25 +159,13 @@
 				repositoryManager);
 	}
 
-	@Provides @Singleton IGitblitManager provideGitblitManager(
-			IRuntimeManager runtimeManager,
-			IUserManager userManager,
-			IRepositoryManager repositoryManager) {
-
-		return new GitblitManager(
-				runtimeManager,
-				userManager,
-				repositoryManager);
-	}
-
-	@Provides @Singleton GitBlit provideGitblit(
+	@Provides @Singleton IGitblit provideGitblit(
 			IRuntimeManager runtimeManager,
 			INotificationManager notificationManager,
 			IUserManager userManager,
 			IAuthenticationManager authenticationManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
-			IGitblitManager gitblitManager,
 			IFederationManager federationManager) {
 
 		return new GitBlit(
@@ -192,12 +175,7 @@
 				authenticationManager,
 				repositoryManager,
 				projectManager,
-				gitblitManager,
 				federationManager);
-	}
-
-	@Provides @Singleton IServicesManager provideServicesManager(GitBlit gitblit) {
-		return new ServicesManager(gitblit);
 	}
 
 	@Provides @Singleton WebApplication provideWebApplication(
@@ -207,8 +185,8 @@
 			IAuthenticationManager authenticationManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
-			IGitblitManager gitblitManager,
-			IFederationManager federationManager) {
+			IFederationManager federationManager,
+			IGitblit gitblit) {
 
 		return new GitBlitWebApp(
 				runtimeManager,
@@ -217,7 +195,7 @@
 				authenticationManager,
 				repositoryManager,
 				projectManager,
-				gitblitManager,
-				federationManager);
+				federationManager,
+				gitblit);
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java
index d4e89b0..d736c57 100644
--- a/src/main/java/com/gitblit/GitBlit.java
+++ b/src/main/java/com/gitblit/GitBlit.java
@@ -15,7 +15,15 @@
  */
 package com.gitblit;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
@@ -26,17 +34,22 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jgit.lib.Repository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import com.gitblit.Constants.AccessPermission;
+import com.gitblit.Constants.AccessRestrictionType;
 import com.gitblit.Constants.FederationRequest;
 import com.gitblit.Constants.FederationToken;
 import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IFederationManager;
-import com.gitblit.manager.IGitblitManager;
+import com.gitblit.manager.IGitblit;
 import com.gitblit.manager.INotificationManager;
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.manager.IUserManager;
+import com.gitblit.manager.ServicesManager;
 import com.gitblit.models.FederationModel;
 import com.gitblit.models.FederationProposal;
 import com.gitblit.models.FederationSet;
@@ -50,8 +63,19 @@
 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;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.HttpUtils;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.JsonUtils;
+import com.gitblit.utils.ObjectCache;
+import com.gitblit.utils.StringUtils;
+import com.google.gson.Gson;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
 
 /**
  * GitBlit is an aggregate interface delegate.  It implements all the manager
@@ -62,14 +86,13 @@
  * @author James Moger
  *
  */
-public class GitBlit implements IRuntimeManager,
-								INotificationManager,
-								IUserManager,
-								IAuthenticationManager,
-								IRepositoryManager,
-								IProjectManager,
-								IGitblitManager,
-								IFederationManager {
+public class GitBlit implements IGitblit {
+
+	private final Logger logger = LoggerFactory.getLogger(getClass());
+
+	private final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>();
+
+	private final IStoredSettings settings;
 
 	private final IRuntimeManager runtimeManager;
 
@@ -83,9 +106,9 @@
 
 	private final IProjectManager projectManager;
 
-	private final IGitblitManager gitblitManager;
-
 	private final IFederationManager federationManager;
+
+	private final ServicesManager servicesManager;
 
 	public GitBlit(
 			IRuntimeManager runtimeManager,
@@ -94,27 +117,362 @@
 			IAuthenticationManager authenticationManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
-			IGitblitManager gitblitManager,
 			IFederationManager federationManager) {
 
+		this.settings = runtimeManager.getSettings();
 		this.runtimeManager = runtimeManager;
 		this.notificationManager = notificationManager;
 		this.userManager = userManager;
 		this.authenticationManager = authenticationManager;
 		this.repositoryManager = repositoryManager;
 		this.projectManager = projectManager;
-		this.gitblitManager = gitblitManager;
 		this.federationManager = federationManager;
+
+		this.servicesManager = new ServicesManager(this);
 	}
 
 	@Override
 	public GitBlit start() {
+		loadSettingModels(runtimeManager.getSettingsModel());
+		logger.info("Starting services manager...");
+		servicesManager.start();
 		return this;
 	}
 
 	@Override
 	public GitBlit stop() {
+		servicesManager.stop();
 		return this;
+	}
+
+	/*
+	 * IGITBLIT
+	 */
+
+	/**
+	 * Creates a personal fork of the specified repository. The clone is view
+	 * restricted by default and the owner of the source repository is given
+	 * access to the clone.
+	 *
+	 * @param repository
+	 * @param user
+	 * @return the repository model of the fork, if successful
+	 * @throws GitBlitException
+	 */
+	@Override
+	public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException {
+		String cloneName = MessageFormat.format("{0}/{1}.git", user.getPersonalPath(), StringUtils.stripDotGit(StringUtils.getLastPathElement(repository.name)));
+		String fromUrl = MessageFormat.format("file://{0}/{1}", repositoryManager.getRepositoriesFolder().getAbsolutePath(), repository.name);
+
+		// clone the repository
+		try {
+			JGitUtils.cloneRepository(repositoryManager.getRepositoriesFolder(), cloneName, fromUrl, true, null);
+		} catch (Exception e) {
+			throw new GitBlitException(e);
+		}
+
+		// create a Gitblit repository model for the clone
+		RepositoryModel cloneModel = repository.cloneAs(cloneName);
+		// owner has REWIND/RW+ permissions
+		cloneModel.addOwner(user.username);
+		repositoryManager.updateRepositoryModel(cloneName, cloneModel, false);
+
+		// add the owner of the source repository to the clone's access list
+		if (!ArrayUtils.isEmpty(repository.owners)) {
+			for (String owner : repository.owners) {
+				UserModel originOwner = userManager.getUserModel(owner);
+				if (originOwner != null) {
+					originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE);
+					updateUserModel(originOwner.username, originOwner, false);
+				}
+			}
+		}
+
+		// grant origin's user list clone permission to fork
+		List<String> users = repositoryManager.getRepositoryUsers(repository);
+		List<UserModel> cloneUsers = new ArrayList<UserModel>();
+		for (String name : users) {
+			if (!name.equalsIgnoreCase(user.username)) {
+				UserModel cloneUser = userManager.getUserModel(name);
+				if (cloneUser.canClone(repository)) {
+					// origin user can clone origin, grant clone access to fork
+					cloneUser.setRepositoryPermission(cloneName, AccessPermission.CLONE);
+				}
+				cloneUsers.add(cloneUser);
+			}
+		}
+		userManager.updateUserModels(cloneUsers);
+
+		// grant origin's team list clone permission to fork
+		List<String> teams = repositoryManager.getRepositoryTeams(repository);
+		List<TeamModel> cloneTeams = new ArrayList<TeamModel>();
+		for (String name : teams) {
+			TeamModel cloneTeam = userManager.getTeamModel(name);
+			if (cloneTeam.canClone(repository)) {
+				// origin team can clone origin, grant clone access to fork
+				cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE);
+			}
+			cloneTeams.add(cloneTeam);
+		}
+		userManager.updateTeamModels(cloneTeams);
+
+		// add this clone to the cached model
+		repositoryManager.addToCachedRepositoryList(cloneModel);
+		return cloneModel;
+	}
+
+	/**
+	 * Updates the TeamModel object for the specified name.
+	 *
+	 * @param teamname
+	 * @param team
+	 * @param isCreate
+	 */
+	@Override
+	public void updateTeamModel(String teamname, TeamModel team, boolean isCreate)
+			throws GitBlitException {
+		if (!teamname.equalsIgnoreCase(team.name)) {
+			if (userManager.getTeamModel(team.name) != null) {
+				throw new GitBlitException(MessageFormat.format(
+						"Failed to rename ''{0}'' because ''{1}'' already exists.", teamname,
+						team.name));
+			}
+		}
+		if (!userManager.updateTeamModel(teamname, team)) {
+			throw new GitBlitException(isCreate ? "Failed to add team!" : "Failed to update team!");
+		}
+	}
+
+	/**
+	 * Adds/updates a complete user object keyed by username. This method allows
+	 * for renaming a user.
+	 *
+	 * @see IUserService.updateUserModel(String, UserModel)
+	 * @param username
+	 * @param user
+	 * @param isCreate
+	 * @throws GitBlitException
+	 */
+	@Override
+	public void updateUserModel(String username, UserModel user, boolean isCreate)
+			throws GitBlitException {
+		if (!username.equalsIgnoreCase(user.username)) {
+			if (userManager.getUserModel(user.username) != null) {
+				throw new GitBlitException(MessageFormat.format(
+						"Failed to rename ''{0}'' because ''{1}'' already exists.", username,
+						user.username));
+			}
+
+			// rename repositories and owner fields for all repositories
+			for (RepositoryModel model : repositoryManager.getRepositoryModels(user)) {
+				if (model.isUsersPersonalRepository(username)) {
+					// personal repository
+					model.addOwner(user.username);
+					String oldRepositoryName = model.name;
+					model.name = user.getPersonalPath() + model.name.substring(model.projectPath.length());
+					model.projectPath = user.getPersonalPath();
+					repositoryManager.updateRepositoryModel(oldRepositoryName, model, false);
+				} else if (model.isOwner(username)) {
+					// common/shared repo
+					model.addOwner(user.username);
+					repositoryManager.updateRepositoryModel(model.name, model, false);
+				}
+			}
+		}
+		if (!userManager.updateUserModel(username, user)) {
+			throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!");
+		}
+	}
+
+	/**
+	 * 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));
+			}
+		}
+
+		// 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)) {
+				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));
+			}
+		}
+		return list;
+	}
+
+	protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) {
+		StringBuilder sb = new StringBuilder();
+		sb.append(HttpUtils.getGitblitURL(request));
+		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;
+	 *
+	 * @return a collection of client applications
+	 */
+	@Override
+	public Collection<GitClientApplication> getClientApplications() {
+		// prefer user definitions, if they exist
+		File userDefs = new File(runtimeManager.getBaseFolder(), "clientapps.json");
+		if (userDefs.exists()) {
+			Date lastModified = new Date(userDefs.lastModified());
+			if (clientApplications.hasCurrent("user", lastModified)) {
+				return clientApplications.getObject("user");
+			} else {
+				// (re)load user definitions
+				try {
+					InputStream is = new FileInputStream(userDefs);
+					Collection<GitClientApplication> clients = readClientApplications(is);
+					is.close();
+					if (clients != null) {
+						clientApplications.updateObject("user", lastModified, clients);
+						return clients;
+					}
+				} catch (IOException e) {
+					logger.error("Failed to deserialize " + userDefs.getAbsolutePath(), e);
+				}
+			}
+		}
+
+		// no user definitions, use system definitions
+		if (!clientApplications.hasCurrent("system", new Date(0))) {
+			try {
+				InputStream is = getClass().getResourceAsStream("/clientapps.json");
+				Collection<GitClientApplication> clients = readClientApplications(is);
+				is.close();
+				if (clients != null) {
+					clientApplications.updateObject("system", new Date(0), clients);
+				}
+			} catch (IOException e) {
+				logger.error("Failed to deserialize clientapps.json resource!", e);
+			}
+		}
+
+		return clientApplications.getObject("system");
+	}
+
+	private Collection<GitClientApplication> readClientApplications(InputStream is) {
+		try {
+			Type type = new TypeToken<Collection<GitClientApplication>>() {
+			}.getType();
+			InputStreamReader reader = new InputStreamReader(is);
+			Gson gson = JsonUtils.gson();
+			Collection<GitClientApplication> links = gson.fromJson(reader, type);
+			return links;
+		} catch (JsonIOException e) {
+			logger.error("Error deserializing client applications!", e);
+		} catch (JsonSyntaxException e) {
+			logger.error("Error deserializing client applications!", e);
+		}
+		return null;
+	}
+
+	/**
+	 * 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 void loadSettingModels(ServerSettings settingsModel) {
+		try {
+			// Read bundled Gitblit properties to extract setting descriptions.
+			// This copy is pristine and only used for populating the setting
+			// models map.
+			InputStream is = getClass().getResourceAsStream("/reference.properties");
+			BufferedReader propertiesReader = new BufferedReader(new InputStreamReader(is));
+			StringBuilder description = new StringBuilder();
+			SettingModel setting = new SettingModel();
+			String line = null;
+			while ((line = propertiesReader.readLine()) != null) {
+				if (line.length() == 0) {
+					description.setLength(0);
+					setting = new SettingModel();
+				} else {
+					if (line.charAt(0) == '#') {
+						if (line.length() > 1) {
+							String text = line.substring(1).trim();
+							if (SettingModel.CASE_SENSITIVE.equals(text)) {
+								setting.caseSensitive = true;
+							} else if (SettingModel.RESTART_REQUIRED.equals(text)) {
+								setting.restartRequired = true;
+							} else if (SettingModel.SPACE_DELIMITED.equals(text)) {
+								setting.spaceDelimited = true;
+							} else if (text.startsWith(SettingModel.SINCE)) {
+								try {
+									setting.since = text.split(" ")[1];
+								} catch (Exception e) {
+									setting.since = text;
+								}
+							} else {
+								description.append(text);
+								description.append('\n');
+							}
+						}
+					} else {
+						String[] kvp = line.split("=", 2);
+						String key = kvp[0].trim();
+						setting.name = key;
+						setting.defaultValue = kvp[1].trim();
+						setting.currentValue = setting.defaultValue;
+						setting.description = description.toString().trim();
+						settingsModel.add(setting);
+						description.setLength(0);
+						setting = new SettingModel();
+					}
+				}
+			}
+			propertiesReader.close();
+		} catch (NullPointerException e) {
+			logger.error("Failed to find resource copy of gitblit.properties");
+		} catch (IOException e) {
+			logger.error("Failed to load resource copy of gitblit.properties");
+		}
 	}
 
 	/*
@@ -719,36 +1077,5 @@
 	@Override
 	public boolean deletePendingFederationProposal(FederationProposal proposal) {
 		return federationManager.deletePendingFederationProposal(proposal);
-	}
-
-	/*
-	 * GITBLIT MANAGER
-	 */
-
-	@Override
-	public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException {
-		return gitblitManager.fork(repository, user);
-	}
-
-	@Override
-	public void updateTeamModel(String teamname, TeamModel team, boolean isCreate)
-			throws GitBlitException {
-		gitblitManager.updateTeamModel(teamname, team, isCreate);
-	}
-
-	@Override
-	public void updateUserModel(String username, UserModel user, boolean isCreate)
-			throws GitBlitException {
-		gitblitManager.updateUserModel(username, user, isCreate);
-	}
-
-	@Override
-	public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) {
-		return gitblitManager.getRepositoryUrls(request, user, repository);
-	}
-
-	@Override
-	public Collection<GitClientApplication> getClientApplications() {
-		return gitblitManager.getClientApplications();
 	}
 }
diff --git a/src/main/java/com/gitblit/git/GitServlet.java b/src/main/java/com/gitblit/git/GitServlet.java
index ff50ad6..db671e4 100644
--- a/src/main/java/com/gitblit/git/GitServlet.java
+++ b/src/main/java/com/gitblit/git/GitServlet.java
@@ -20,7 +20,7 @@
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 
-import com.gitblit.GitBlit;
+import com.gitblit.manager.IGitblit;
 
 /**
  * The GitServlet provides http/https access to Git repositories.
@@ -33,10 +33,10 @@
 
 	private static final long serialVersionUID = 1L;
 
-	private final GitBlit gitblit;
+	private final IGitblit gitblit;
 
 	@Inject
-	public GitServlet(GitBlit gitblit) {
+	public GitServlet(IGitblit gitblit) {
 		super();
 		this.gitblit = gitblit;
 	}
diff --git a/src/main/java/com/gitblit/git/GitblitReceivePack.java b/src/main/java/com/gitblit/git/GitblitReceivePack.java
index ebea265..e5c0ea4 100644
--- a/src/main/java/com/gitblit/git/GitblitReceivePack.java
+++ b/src/main/java/com/gitblit/git/GitblitReceivePack.java
@@ -44,10 +44,10 @@
 
 import com.gitblit.Constants;
 import com.gitblit.Constants.AccessRestrictionType;
-import com.gitblit.GitBlit;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
 import com.gitblit.client.Translation;
+import com.gitblit.manager.IGitblit;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.ArrayUtils;
@@ -91,10 +91,10 @@
 
 	private final IStoredSettings settings;
 
-	private final GitBlit gitblit;
+	private final IGitblit gitblit;
 
 	public GitblitReceivePack(
-			GitBlit gitblit,
+			IGitblit gitblit,
 			Repository db,
 			RepositoryModel repository,
 			UserModel user) {
diff --git a/src/main/java/com/gitblit/git/GitblitReceivePackFactory.java b/src/main/java/com/gitblit/git/GitblitReceivePackFactory.java
index e24d119..bdf9b1a 100644
--- a/src/main/java/com/gitblit/git/GitblitReceivePackFactory.java
+++ b/src/main/java/com/gitblit/git/GitblitReceivePackFactory.java
@@ -26,9 +26,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.gitblit.GitBlit;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
+import com.gitblit.manager.IGitblit;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.HttpUtils;
@@ -47,9 +47,9 @@
 
 	private final IStoredSettings settings;
 
-	private final GitBlit gitblit;
+	private final IGitblit gitblit;
 
-	public GitblitReceivePackFactory(GitBlit gitblit) {
+	public GitblitReceivePackFactory(IGitblit gitblit) {
 		super();
 		this.settings = gitblit.getSettings();
 		this.gitblit = gitblit;
diff --git a/src/main/java/com/gitblit/git/RepositoryResolver.java b/src/main/java/com/gitblit/git/RepositoryResolver.java
index 8615eea..208c1ae 100644
--- a/src/main/java/com/gitblit/git/RepositoryResolver.java
+++ b/src/main/java/com/gitblit/git/RepositoryResolver.java
@@ -27,7 +27,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.gitblit.GitBlit;
+import com.gitblit.manager.IGitblit;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 
@@ -41,9 +41,9 @@
 
 	private final Logger logger = LoggerFactory.getLogger(RepositoryResolver.class);
 
-	private final GitBlit gitblit;
+	private final IGitblit gitblit;
 
-	public RepositoryResolver(GitBlit gitblit) {
+	public RepositoryResolver(IGitblit gitblit) {
 		super(gitblit.getRepositoriesFolder(), true);
 		this.gitblit = gitblit;
 	}
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
deleted file mode 100644
index 6395c35..0000000
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * 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.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.reflect.Type;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-
-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.GitBlitException;
-import com.gitblit.IStoredSettings;
-import com.gitblit.Keys;
-import com.gitblit.models.GitClientApplication;
-import com.gitblit.models.RepositoryModel;
-import com.gitblit.models.RepositoryUrl;
-import com.gitblit.models.ServerSettings;
-import com.gitblit.models.SettingModel;
-import com.gitblit.models.TeamModel;
-import com.gitblit.models.UserModel;
-import com.gitblit.utils.ArrayUtils;
-import com.gitblit.utils.HttpUtils;
-import com.gitblit.utils.JGitUtils;
-import com.gitblit.utils.JsonUtils;
-import com.gitblit.utils.ObjectCache;
-import com.gitblit.utils.StringUtils;
-import com.google.gson.Gson;
-import com.google.gson.JsonIOException;
-import com.google.gson.JsonSyntaxException;
-import com.google.gson.reflect.TypeToken;
-
-public class GitblitManager implements IGitblitManager {
-
-	private final Logger logger = LoggerFactory.getLogger(getClass());
-
-	private final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>();
-
-	private final IStoredSettings settings;
-
-	private final IRuntimeManager runtimeManager;
-
-	private final IUserManager userManager;
-
-	private final IRepositoryManager repositoryManager;
-
-	public GitblitManager(
-			IRuntimeManager runtimeManager,
-			IUserManager userManager,
-			IRepositoryManager repositoryManager) {
-
-		this.settings = runtimeManager.getSettings();
-		this.runtimeManager = runtimeManager;
-		this.userManager = userManager;
-		this.repositoryManager = repositoryManager;
-	}
-
-	@Override
-	public GitblitManager start() {
-		loadSettingModels(runtimeManager.getSettingsModel());
-		return this;
-	}
-
-	@Override
-	public GitblitManager stop() {
-		return this;
-	}
-
-	/**
-	 * 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 void loadSettingModels(ServerSettings settingsModel) {
-		try {
-			// Read bundled Gitblit properties to extract setting descriptions.
-			// This copy is pristine and only used for populating the setting
-			// models map.
-			InputStream is = getClass().getResourceAsStream("/reference.properties");
-			BufferedReader propertiesReader = new BufferedReader(new InputStreamReader(is));
-			StringBuilder description = new StringBuilder();
-			SettingModel setting = new SettingModel();
-			String line = null;
-			while ((line = propertiesReader.readLine()) != null) {
-				if (line.length() == 0) {
-					description.setLength(0);
-					setting = new SettingModel();
-				} else {
-					if (line.charAt(0) == '#') {
-						if (line.length() > 1) {
-							String text = line.substring(1).trim();
-							if (SettingModel.CASE_SENSITIVE.equals(text)) {
-								setting.caseSensitive = true;
-							} else if (SettingModel.RESTART_REQUIRED.equals(text)) {
-								setting.restartRequired = true;
-							} else if (SettingModel.SPACE_DELIMITED.equals(text)) {
-								setting.spaceDelimited = true;
-							} else if (text.startsWith(SettingModel.SINCE)) {
-								try {
-									setting.since = text.split(" ")[1];
-								} catch (Exception e) {
-									setting.since = text;
-								}
-							} else {
-								description.append(text);
-								description.append('\n');
-							}
-						}
-					} else {
-						String[] kvp = line.split("=", 2);
-						String key = kvp[0].trim();
-						setting.name = key;
-						setting.defaultValue = kvp[1].trim();
-						setting.currentValue = setting.defaultValue;
-						setting.description = description.toString().trim();
-						settingsModel.add(setting);
-						description.setLength(0);
-						setting = new SettingModel();
-					}
-				}
-			}
-			propertiesReader.close();
-		} catch (NullPointerException e) {
-			logger.error("Failed to find resource copy of gitblit.properties");
-		} catch (IOException e) {
-			logger.error("Failed to load resource copy of gitblit.properties");
-		}
-	}
-
-	/**
-	 * 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));
-			}
-		}
-
-		// git daemon url
-		String gitDaemonUrl = getGitDaemonUrl(request, user, repository);
-		if (!StringUtils.isEmpty(gitDaemonUrl)) {
-			AccessPermission permission = getGitDaemonAccessPermission(user, repository);
-			if (permission.exceeds(AccessPermission.NONE)) {
-				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));
-			}
-		}
-		return list;
-	}
-
-	protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) {
-		StringBuilder sb = new StringBuilder();
-		sb.append(HttpUtils.getGitblitURL(request));
-		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();
-	}
-
-	protected String getGitDaemonUrl(HttpServletRequest request, UserModel user, RepositoryModel repository) {
-//		if (gitDaemon != null) {
-//			String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
-//			if (bindInterface.equals("localhost")
-//					&& (!request.getServerName().equals("localhost") && !request.getServerName().equals("127.0.0.1"))) {
-//				// git daemon is bound to localhost and the request is from elsewhere
-//				return null;
-//			}
-//			if (user.canClone(repository)) {
-//				String servername = request.getServerName();
-//				String url = gitDaemon.formatUrl(servername, repository.name);
-//				return url;
-//			}
-//		}
-		return null;
-	}
-
-	protected AccessPermission getGitDaemonAccessPermission(UserModel user, RepositoryModel repository) {
-//		if (gitDaemon != null && user.canClone(repository)) {
-//			AccessPermission gitDaemonPermission = user.getRepositoryPermission(repository).permission;
-//			if (gitDaemonPermission.atLeast(AccessPermission.CLONE)) {
-//				if (repository.accessRestriction.atLeast(AccessRestrictionType.CLONE)) {
-//					// can not authenticate clone via anonymous git protocol
-//					gitDaemonPermission = AccessPermission.NONE;
-//				} else if (repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) {
-//					// can not authenticate push via anonymous git protocol
-//					gitDaemonPermission = AccessPermission.CLONE;
-//				} else {
-//					// normal user permission
-//				}
-//			}
-//			return gitDaemonPermission;
-//		}
-		return AccessPermission.NONE;
-	}
-
-	/**
-	 * Returns the list of custom client applications to be used for the
-	 * repository url panel;
-	 *
-	 * @return a collection of client applications
-	 */
-	@Override
-	public Collection<GitClientApplication> getClientApplications() {
-		// prefer user definitions, if they exist
-		File userDefs = new File(runtimeManager.getBaseFolder(), "clientapps.json");
-		if (userDefs.exists()) {
-			Date lastModified = new Date(userDefs.lastModified());
-			if (clientApplications.hasCurrent("user", lastModified)) {
-				return clientApplications.getObject("user");
-			} else {
-				// (re)load user definitions
-				try {
-					InputStream is = new FileInputStream(userDefs);
-					Collection<GitClientApplication> clients = readClientApplications(is);
-					is.close();
-					if (clients != null) {
-						clientApplications.updateObject("user", lastModified, clients);
-						return clients;
-					}
-				} catch (IOException e) {
-					logger.error("Failed to deserialize " + userDefs.getAbsolutePath(), e);
-				}
-			}
-		}
-
-		// no user definitions, use system definitions
-		if (!clientApplications.hasCurrent("system", new Date(0))) {
-			try {
-				InputStream is = getClass().getResourceAsStream("/clientapps.json");
-				Collection<GitClientApplication> clients = readClientApplications(is);
-				is.close();
-				if (clients != null) {
-					clientApplications.updateObject("system", new Date(0), clients);
-				}
-			} catch (IOException e) {
-				logger.error("Failed to deserialize clientapps.json resource!", e);
-			}
-		}
-
-		return clientApplications.getObject("system");
-	}
-
-	private Collection<GitClientApplication> readClientApplications(InputStream is) {
-		try {
-			Type type = new TypeToken<Collection<GitClientApplication>>() {
-			}.getType();
-			InputStreamReader reader = new InputStreamReader(is);
-			Gson gson = JsonUtils.gson();
-			Collection<GitClientApplication> links = gson.fromJson(reader, type);
-			return links;
-		} catch (JsonIOException e) {
-			logger.error("Error deserializing client applications!", e);
-		} catch (JsonSyntaxException e) {
-			logger.error("Error deserializing client applications!", e);
-		}
-		return null;
-	}
-
-	/**
-	 * Creates a personal fork of the specified repository. The clone is view
-	 * restricted by default and the owner of the source repository is given
-	 * access to the clone.
-	 *
-	 * @param repository
-	 * @param user
-	 * @return the repository model of the fork, if successful
-	 * @throws GitBlitException
-	 */
-	@Override
-	public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException {
-		String cloneName = MessageFormat.format("{0}/{1}.git", user.getPersonalPath(), StringUtils.stripDotGit(StringUtils.getLastPathElement(repository.name)));
-		String fromUrl = MessageFormat.format("file://{0}/{1}", repositoryManager.getRepositoriesFolder().getAbsolutePath(), repository.name);
-
-		// clone the repository
-		try {
-			JGitUtils.cloneRepository(repositoryManager.getRepositoriesFolder(), cloneName, fromUrl, true, null);
-		} catch (Exception e) {
-			throw new GitBlitException(e);
-		}
-
-		// create a Gitblit repository model for the clone
-		RepositoryModel cloneModel = repository.cloneAs(cloneName);
-		// owner has REWIND/RW+ permissions
-		cloneModel.addOwner(user.username);
-		repositoryManager.updateRepositoryModel(cloneName, cloneModel, false);
-
-		// add the owner of the source repository to the clone's access list
-		if (!ArrayUtils.isEmpty(repository.owners)) {
-			for (String owner : repository.owners) {
-				UserModel originOwner = userManager.getUserModel(owner);
-				if (originOwner != null) {
-					originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE);
-					updateUserModel(originOwner.username, originOwner, false);
-				}
-			}
-		}
-
-		// grant origin's user list clone permission to fork
-		List<String> users = repositoryManager.getRepositoryUsers(repository);
-		List<UserModel> cloneUsers = new ArrayList<UserModel>();
-		for (String name : users) {
-			if (!name.equalsIgnoreCase(user.username)) {
-				UserModel cloneUser = userManager.getUserModel(name);
-				if (cloneUser.canClone(repository)) {
-					// origin user can clone origin, grant clone access to fork
-					cloneUser.setRepositoryPermission(cloneName, AccessPermission.CLONE);
-				}
-				cloneUsers.add(cloneUser);
-			}
-		}
-		userManager.updateUserModels(cloneUsers);
-
-		// grant origin's team list clone permission to fork
-		List<String> teams = repositoryManager.getRepositoryTeams(repository);
-		List<TeamModel> cloneTeams = new ArrayList<TeamModel>();
-		for (String name : teams) {
-			TeamModel cloneTeam = userManager.getTeamModel(name);
-			if (cloneTeam.canClone(repository)) {
-				// origin team can clone origin, grant clone access to fork
-				cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE);
-			}
-			cloneTeams.add(cloneTeam);
-		}
-		userManager.updateTeamModels(cloneTeams);
-
-		// add this clone to the cached model
-		repositoryManager.addToCachedRepositoryList(cloneModel);
-		return cloneModel;
-	}
-
-	/**
-	 * Adds/updates a complete user object keyed by username. This method allows
-	 * for renaming a user.
-	 *
-	 * @see IUserService.updateUserModel(String, UserModel)
-	 * @param username
-	 * @param user
-	 * @param isCreate
-	 * @throws GitBlitException
-	 */
-	@Override
-	public void updateUserModel(String username, UserModel user, boolean isCreate)
-			throws GitBlitException {
-		if (!username.equalsIgnoreCase(user.username)) {
-			if (userManager.getUserModel(user.username) != null) {
-				throw new GitBlitException(MessageFormat.format(
-						"Failed to rename ''{0}'' because ''{1}'' already exists.", username,
-						user.username));
-			}
-
-			// rename repositories and owner fields for all repositories
-			for (RepositoryModel model : repositoryManager.getRepositoryModels(user)) {
-				if (model.isUsersPersonalRepository(username)) {
-					// personal repository
-					model.addOwner(user.username);
-					String oldRepositoryName = model.name;
-					model.name = user.getPersonalPath() + model.name.substring(model.projectPath.length());
-					model.projectPath = user.getPersonalPath();
-					repositoryManager.updateRepositoryModel(oldRepositoryName, model, false);
-				} else if (model.isOwner(username)) {
-					// common/shared repo
-					model.addOwner(user.username);
-					repositoryManager.updateRepositoryModel(model.name, model, false);
-				}
-			}
-		}
-		if (!userManager.updateUserModel(username, user)) {
-			throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!");
-		}
-	}
-
-	/**
-	 * Updates the TeamModel object for the specified name.
-	 *
-	 * @param teamname
-	 * @param team
-	 * @param isCreate
-	 */
-	@Override
-	public void updateTeamModel(String teamname, TeamModel team, boolean isCreate)
-			throws GitBlitException {
-		if (!teamname.equalsIgnoreCase(team.name)) {
-			if (userManager.getTeamModel(team.name) != null) {
-				throw new GitBlitException(MessageFormat.format(
-						"Failed to rename ''{0}'' because ''{1}'' already exists.", teamname,
-						team.name));
-			}
-		}
-		if (!userManager.updateTeamModel(teamname, team)) {
-			throw new GitBlitException(isCreate ? "Failed to add team!" : "Failed to update team!");
-		}
-	}
-}
diff --git a/src/main/java/com/gitblit/manager/IGitblitManager.java b/src/main/java/com/gitblit/manager/IGitblit.java
similarity index 90%
rename from src/main/java/com/gitblit/manager/IGitblitManager.java
rename to src/main/java/com/gitblit/manager/IGitblit.java
index 21c9e6a..c0167f0 100644
--- a/src/main/java/com/gitblit/manager/IGitblitManager.java
+++ b/src/main/java/com/gitblit/manager/IGitblit.java
@@ -27,7 +27,14 @@
 import com.gitblit.models.TeamModel;
 import com.gitblit.models.UserModel;
 
-public interface IGitblitManager extends IManager {
+public interface IGitblit extends IManager,
+									IRuntimeManager,
+									INotificationManager,
+									IUserManager,
+									IAuthenticationManager,
+									IRepositoryManager,
+									IProjectManager,
+									IFederationManager {
 
 	/**
 	 * Returns a list of repository URLs and the user access permission.
diff --git a/src/main/java/com/gitblit/manager/IServicesManager.java b/src/main/java/com/gitblit/manager/IServicesManager.java
deleted file mode 100644
index 9fdd063..0000000
--- a/src/main/java/com/gitblit/manager/IServicesManager.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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 IServicesManager extends IManager {
-
-}
diff --git a/src/main/java/com/gitblit/manager/ServicesManager.java b/src/main/java/com/gitblit/manager/ServicesManager.java
index 4cf0743..6cc9456 100644
--- a/src/main/java/com/gitblit/manager/ServicesManager.java
+++ b/src/main/java/com/gitblit/manager/ServicesManager.java
@@ -24,9 +24,13 @@
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.gitblit.Constants.AccessPermission;
+import com.gitblit.Constants.AccessRestrictionType;
 import com.gitblit.Constants.FederationToken;
 import com.gitblit.GitBlit;
 import com.gitblit.IStoredSettings;
@@ -36,6 +40,8 @@
 import com.gitblit.fanout.FanoutSocketService;
 import com.gitblit.git.GitDaemon;
 import com.gitblit.models.FederationModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
 import com.gitblit.service.FederationPullService;
 import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.TimeUtils;
@@ -48,7 +54,7 @@
  * @author James Moger
  *
  */
-public class ServicesManager implements IServicesManager {
+public class ServicesManager implements IManager {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
 
@@ -163,6 +169,43 @@
 		}
 	}
 
+	public String getGitDaemonUrl(HttpServletRequest request, UserModel user, RepositoryModel repository) {
+		if (gitDaemon != null) {
+			String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
+			if (bindInterface.equals("localhost")
+					&& (!request.getServerName().equals("localhost") && !request.getServerName().equals("127.0.0.1"))) {
+				// git daemon is bound to localhost and the request is from elsewhere
+				return null;
+			}
+			if (user.canClone(repository)) {
+				String servername = request.getServerName();
+				String url = gitDaemon.formatUrl(servername, repository.name);
+				return url;
+			}
+		}
+		return null;
+	}
+
+	public AccessPermission getGitDaemonAccessPermission(UserModel user, RepositoryModel repository) {
+		if (gitDaemon != null && user.canClone(repository)) {
+			AccessPermission gitDaemonPermission = user.getRepositoryPermission(repository).permission;
+			if (gitDaemonPermission.atLeast(AccessPermission.CLONE)) {
+				if (repository.accessRestriction.atLeast(AccessRestrictionType.CLONE)) {
+					// can not authenticate clone via anonymous git protocol
+					gitDaemonPermission = AccessPermission.NONE;
+				} else if (repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) {
+					// can not authenticate push via anonymous git protocol
+					gitDaemonPermission = AccessPermission.CLONE;
+				} else {
+					// normal user permission
+				}
+			}
+			return gitDaemonPermission;
+		}
+		return AccessPermission.NONE;
+	}
+
+
 	private class FederationPuller extends FederationPullService {
 
 		public FederationPuller(FederationModel registration) {
diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java
index a86ecf6..ca9a67c 100644
--- a/src/main/java/com/gitblit/servlet/GitblitContext.java
+++ b/src/main/java/com/gitblit/servlet/GitblitContext.java
@@ -43,13 +43,12 @@
 import com.gitblit.git.GitServlet;
 import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IFederationManager;
-import com.gitblit.manager.IGitblitManager;
+import com.gitblit.manager.IGitblit;
 import com.gitblit.manager.IManager;
 import com.gitblit.manager.INotificationManager;
 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.utils.ContainerUtils;
 import com.gitblit.utils.StringUtils;
@@ -173,9 +172,8 @@
 		startManager(injector, IAuthenticationManager.class);
 		startManager(injector, IRepositoryManager.class);
 		startManager(injector, IProjectManager.class);
-		startManager(injector, IGitblitManager.class);
 		startManager(injector, IFederationManager.class);
-		startManager(injector, IServicesManager.class);
+		startManager(injector, IGitblit.class);
 
 		logger.info("");
 		logger.info("All managers started.");
diff --git a/src/main/java/com/gitblit/servlet/RpcServlet.java b/src/main/java/com/gitblit/servlet/RpcServlet.java
index a2013b7..481a8ba 100644
--- a/src/main/java/com/gitblit/servlet/RpcServlet.java
+++ b/src/main/java/com/gitblit/servlet/RpcServlet.java
@@ -36,11 +36,7 @@
 import com.gitblit.GitBlitException;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
-import com.gitblit.manager.IFederationManager;
-import com.gitblit.manager.IGitblitManager;
-import com.gitblit.manager.IRepositoryManager;
-import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.IUserManager;
+import com.gitblit.manager.IGitblit;
 import com.gitblit.models.RefModel;
 import com.gitblit.models.RegistrantAccessPermission;
 import com.gitblit.models.RepositoryModel;
@@ -68,32 +64,15 @@
 
 	private final IStoredSettings settings;
 
-	private final IRuntimeManager runtimeManager;
-
-	private final IUserManager userManager;
-
-	private final IRepositoryManager repositoryManager;
-
-	private final IFederationManager federationManager;
-
-	private final IGitblitManager gitblitManager;
+	private final IGitblit gitblit;
 
 	@Inject
-	public RpcServlet(
-			IRuntimeManager runtimeManager,
-			IUserManager userManager,
-			IRepositoryManager repositoryManager,
-			IFederationManager federationManager,
-			IGitblitManager gitblitManager) {
+	public RpcServlet(IGitblit gitblit) {
 
 		super();
 
-		this.settings = runtimeManager.getSettings();
-		this.runtimeManager = runtimeManager;
-		this.userManager = userManager;
-		this.repositoryManager = repositoryManager;
-		this.federationManager = federationManager;
-		this.gitblitManager = gitblitManager;
+		this.settings = gitblit.getSettings();
+		this.gitblit = gitblit;
 	}
 
 	/**
@@ -134,7 +113,7 @@
 			String cloneUrl = sb.toString();
 
 			// list repositories
-			List<RepositoryModel> list = repositoryManager.getRepositoryModels(user);
+			List<RepositoryModel> list = gitblit.getRepositoryModels(user);
 			Map<String, RepositoryModel> repositories = new HashMap<String, RepositoryModel>();
 			for (RepositoryModel model : list) {
 				String url = MessageFormat.format(cloneUrl, model.name);
@@ -144,7 +123,7 @@
 		} else if (RpcRequest.LIST_BRANCHES.equals(reqType)) {
 			// list all local branches in all repositories accessible to user
 			Map<String, List<String>> localBranches = new HashMap<String, List<String>>();
-			List<RepositoryModel> models = repositoryManager.getRepositoryModels(user);
+			List<RepositoryModel> models = gitblit.getRepositoryModels(user);
 			for (RepositoryModel model : models) {
 				if (!model.hasCommits) {
 					// skip empty repository
@@ -156,7 +135,7 @@
 					continue;
 				}
 				// get local branches
-				Repository repository = repositoryManager.getRepository(model.name);
+				Repository repository = gitblit.getRepository(model.name);
 				List<RefModel> refs = JGitUtils.getLocalBranches(repository, false, -1);
 				if (model.showRemoteBranches) {
 					// add remote branches if repository displays them
@@ -184,7 +163,7 @@
 			} else {
 				if (user.canAdmin() || objectName.equals(user.username)) {
 					// return the specified user
-					UserModel requestedUser = userManager.getUserModel(objectName);
+					UserModel requestedUser = gitblit.getUserModel(objectName);
 					if (requestedUser == null) {
 						response.setStatus(failureCode);
 					} else {
@@ -196,25 +175,25 @@
 			}
 		} else if (RpcRequest.LIST_USERS.equals(reqType)) {
 			// list users
-			List<String> names = userManager.getAllUsernames();
+			List<String> names = gitblit.getAllUsernames();
 			List<UserModel> users = new ArrayList<UserModel>();
 			for (String name : names) {
-				users.add(userManager.getUserModel(name));
+				users.add(gitblit.getUserModel(name));
 			}
 			result = users;
 		} else if (RpcRequest.LIST_TEAMS.equals(reqType)) {
 			// list teams
-			List<String> names = userManager.getAllTeamNames();
+			List<String> names = gitblit.getAllTeamNames();
 			List<TeamModel> teams = new ArrayList<TeamModel>();
 			for (String name : names) {
-				teams.add(userManager.getTeamModel(name));
+				teams.add(gitblit.getTeamModel(name));
 			}
 			result = teams;
 		} else if (RpcRequest.CREATE_REPOSITORY.equals(reqType)) {
 			// create repository
 			RepositoryModel model = deserialize(request, response, RepositoryModel.class);
 			try {
-				repositoryManager.updateRepositoryModel(model.name, model, true);
+				gitblit.updateRepositoryModel(model.name, model, true);
 			} catch (GitBlitException e) {
 				response.setStatus(failureCode);
 			}
@@ -227,19 +206,19 @@
 				repoName = model.name;
 			}
 			try {
-				repositoryManager.updateRepositoryModel(repoName, model, false);
+				gitblit.updateRepositoryModel(repoName, model, false);
 			} catch (GitBlitException e) {
 				response.setStatus(failureCode);
 			}
 		} else if (RpcRequest.DELETE_REPOSITORY.equals(reqType)) {
 			// delete repository
 			RepositoryModel model = deserialize(request, response, RepositoryModel.class);
-			repositoryManager.deleteRepositoryModel(model);
+			gitblit.deleteRepositoryModel(model);
 		} else if (RpcRequest.CREATE_USER.equals(reqType)) {
 			// create user
 			UserModel model = deserialize(request, response, UserModel.class);
 			try {
-				gitblitManager.updateUserModel(model.username, model, true);
+				gitblit.updateUserModel(model.username, model, true);
 			} catch (GitBlitException e) {
 				response.setStatus(failureCode);
 			}
@@ -252,21 +231,21 @@
 				username = model.username;
 			}
 			try {
-				gitblitManager.updateUserModel(username, model, false);
+				gitblit.updateUserModel(username, model, false);
 			} catch (GitBlitException e) {
 				response.setStatus(failureCode);
 			}
 		} else if (RpcRequest.DELETE_USER.equals(reqType)) {
 			// delete user
 			UserModel model = deserialize(request, response, UserModel.class);
-			if (!userManager.deleteUser(model.username)) {
+			if (!gitblit.deleteUser(model.username)) {
 				response.setStatus(failureCode);
 			}
 		} else if (RpcRequest.CREATE_TEAM.equals(reqType)) {
 			// create team
 			TeamModel model = deserialize(request, response, TeamModel.class);
 			try {
-				gitblitManager.updateTeamModel(model.name, model, true);
+				gitblit.updateTeamModel(model.name, model, true);
 			} catch (GitBlitException e) {
 				response.setStatus(failureCode);
 			}
@@ -279,80 +258,80 @@
 				teamname = model.name;
 			}
 			try {
-				gitblitManager.updateTeamModel(teamname, model, false);
+				gitblit.updateTeamModel(teamname, model, false);
 			} catch (GitBlitException e) {
 				response.setStatus(failureCode);
 			}
 		} else if (RpcRequest.DELETE_TEAM.equals(reqType)) {
 			// delete team
 			TeamModel model = deserialize(request, response, TeamModel.class);
-			if (!userManager.deleteTeam(model.name)) {
+			if (!gitblit.deleteTeam(model.name)) {
 				response.setStatus(failureCode);
 			}
 		} else if (RpcRequest.LIST_REPOSITORY_MEMBERS.equals(reqType)) {
 			// get repository members
-			RepositoryModel model = repositoryManager.getRepositoryModel(objectName);
-			result = repositoryManager.getRepositoryUsers(model);
+			RepositoryModel model = gitblit.getRepositoryModel(objectName);
+			result = gitblit.getRepositoryUsers(model);
 		} else if (RpcRequest.SET_REPOSITORY_MEMBERS.equals(reqType)) {
 			// rejected since 1.2.0
 			response.setStatus(failureCode);
 		} else if (RpcRequest.LIST_REPOSITORY_MEMBER_PERMISSIONS.equals(reqType)) {
 			// get repository member permissions
-			RepositoryModel model = repositoryManager.getRepositoryModel(objectName);
-			result = repositoryManager.getUserAccessPermissions(model);
+			RepositoryModel model = gitblit.getRepositoryModel(objectName);
+			result = gitblit.getUserAccessPermissions(model);
 		} else if (RpcRequest.SET_REPOSITORY_MEMBER_PERMISSIONS.equals(reqType)) {
 			// set the repository permissions for the specified users
-			RepositoryModel model = repositoryManager.getRepositoryModel(objectName);
+			RepositoryModel model = gitblit.getRepositoryModel(objectName);
 			Collection<RegistrantAccessPermission> permissions = deserialize(request, response, RpcUtils.REGISTRANT_PERMISSIONS_TYPE);
-			result = repositoryManager.setUserAccessPermissions(model, permissions);
+			result = gitblit.setUserAccessPermissions(model, permissions);
 		} else if (RpcRequest.LIST_REPOSITORY_TEAMS.equals(reqType)) {
 			// get repository teams
-			RepositoryModel model = repositoryManager.getRepositoryModel(objectName);
-			result = repositoryManager.getRepositoryTeams(model);
+			RepositoryModel model = gitblit.getRepositoryModel(objectName);
+			result = gitblit.getRepositoryTeams(model);
 		} else if (RpcRequest.SET_REPOSITORY_TEAMS.equals(reqType)) {
 			// rejected since 1.2.0
 			response.setStatus(failureCode);
 		} else if (RpcRequest.LIST_REPOSITORY_TEAM_PERMISSIONS.equals(reqType)) {
 			// get repository team permissions
-			RepositoryModel model = repositoryManager.getRepositoryModel(objectName);
-			result = repositoryManager.getTeamAccessPermissions(model);
+			RepositoryModel model = gitblit.getRepositoryModel(objectName);
+			result = gitblit.getTeamAccessPermissions(model);
 		} else if (RpcRequest.SET_REPOSITORY_TEAM_PERMISSIONS.equals(reqType)) {
 			// set the repository permissions for the specified teams
-			RepositoryModel model = repositoryManager.getRepositoryModel(objectName);
+			RepositoryModel model = gitblit.getRepositoryModel(objectName);
 			Collection<RegistrantAccessPermission> permissions = deserialize(request, response, RpcUtils.REGISTRANT_PERMISSIONS_TYPE);
-			result = repositoryManager.setTeamAccessPermissions(model, permissions);
+			result = gitblit.setTeamAccessPermissions(model, permissions);
 		} else if (RpcRequest.LIST_FEDERATION_REGISTRATIONS.equals(reqType)) {
 			// return the list of federation registrations
 			if (allowAdmin) {
-				result = federationManager.getFederationRegistrations();
+				result = gitblit.getFederationRegistrations();
 			} else {
 				response.sendError(notAllowedCode);
 			}
 		} else if (RpcRequest.LIST_FEDERATION_RESULTS.equals(reqType)) {
 			// return the list of federation result registrations
-			if (allowAdmin && federationManager.canFederate()) {
-				result = federationManager.getFederationResultRegistrations();
+			if (allowAdmin && gitblit.canFederate()) {
+				result = gitblit.getFederationResultRegistrations();
 			} else {
 				response.sendError(notAllowedCode);
 			}
 		} else if (RpcRequest.LIST_FEDERATION_PROPOSALS.equals(reqType)) {
 			// return the list of federation proposals
-			if (allowAdmin && federationManager.canFederate()) {
-				result = federationManager.getPendingFederationProposals();
+			if (allowAdmin && gitblit.canFederate()) {
+				result = gitblit.getPendingFederationProposals();
 			} else {
 				response.sendError(notAllowedCode);
 			}
 		} else if (RpcRequest.LIST_FEDERATION_SETS.equals(reqType)) {
 			// return the list of federation sets
-			if (allowAdmin && federationManager.canFederate()) {
+			if (allowAdmin && gitblit.canFederate()) {
 				String gitblitUrl = HttpUtils.getGitblitURL(request);
-				result = federationManager.getFederationSets(gitblitUrl);
+				result = gitblit.getFederationSets(gitblitUrl);
 			} else {
 				response.sendError(notAllowedCode);
 			}
 		} else if (RpcRequest.LIST_SETTINGS.equals(reqType)) {
 			// return the server's settings
-			ServerSettings serverSettings = runtimeManager.getSettingsModel();
+			ServerSettings serverSettings = gitblit.getSettingsModel();
 			if (allowAdmin) {
 				// return all settings
 				result = serverSettings;
@@ -384,21 +363,21 @@
 			if (allowAdmin) {
 				Map<String, String> map = deserialize(request, response,
 						RpcUtils.SETTINGS_TYPE);
-				runtimeManager.updateSettings(map);
+				gitblit.updateSettings(map);
 			} else {
 				response.sendError(notAllowedCode);
 			}
 		} else if (RpcRequest.LIST_STATUS.equals(reqType)) {
 			// return the server's status information
 			if (allowAdmin) {
-				result = runtimeManager.getStatus();
+				result = gitblit.getStatus();
 			} else {
 				response.sendError(notAllowedCode);
 			}
 		} else if (RpcRequest.CLEAR_REPOSITORY_CACHE.equals(reqType)) {
 			// clear the repository list cache
 			if (allowManagement) {
-				repositoryManager.resetRepositoryListCache();
+				gitblit.resetRepositoryListCache();
 			} else {
 				response.sendError(notAllowedCode);
 			}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index 1409e47..35a0823 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -30,13 +30,13 @@
 
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
+import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IFederationManager;
-import com.gitblit.manager.IGitblitManager;
+import com.gitblit.manager.IGitblit;
 import com.gitblit.manager.INotificationManager;
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IUserManager;
 import com.gitblit.utils.StringUtils;
 import com.gitblit.wicket.pages.ActivityPage;
@@ -95,9 +95,9 @@
 
 	private final IProjectManager projectManager;
 
-	private final IGitblitManager gitblitManager;
-
 	private final IFederationManager federationManager;
+
+	private final IGitblit gitblit;
 
 	public GitBlitWebApp(
 			IRuntimeManager runtimeManager,
@@ -106,8 +106,8 @@
 			IAuthenticationManager authenticationManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
-			IGitblitManager gitblitManager,
-			IFederationManager federationManager) {
+			IFederationManager federationManager,
+			IGitblit gitblit) {
 
 		super();
 		this.settings = runtimeManager.getSettings();
@@ -117,8 +117,8 @@
 		this.authenticationManager = authenticationManager;
 		this.repositoryManager = repositoryManager;
 		this.projectManager = projectManager;
-		this.gitblitManager = gitblitManager;
 		this.federationManager = federationManager;
+		this.gitblit = gitblit;
 	}
 
 	@Override
@@ -185,7 +185,7 @@
 		mount("/user", UserPage.class, "user");
 		mount("/forks", ForksPage.class, "r");
 		mount("/fork", ForkPage.class, "r");
-		
+
 		getMarkupSettings().setDefaultMarkupEncoding("UTF-8");
 		super.init();
 	}
@@ -283,8 +283,8 @@
 		return federationManager;
 	}
 
-	public IGitblitManager gitblit() {
-		return gitblitManager;
+	public IGitblit gitblit() {
+		return gitblit;
 	}
 
 	public TimeZone getTimezone() {
diff --git a/src/test/java/com/gitblit/tests/GitblitUnitTest.java b/src/test/java/com/gitblit/tests/GitblitUnitTest.java
index 1885f12..6539d65 100644
--- a/src/test/java/com/gitblit/tests/GitblitUnitTest.java
+++ b/src/test/java/com/gitblit/tests/GitblitUnitTest.java
@@ -17,7 +17,7 @@
 
 import com.gitblit.IStoredSettings;
 import com.gitblit.manager.IFederationManager;
-import com.gitblit.manager.IGitblitManager;
+import com.gitblit.manager.IGitblit;
 import com.gitblit.manager.INotificationManager;
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
@@ -61,7 +61,7 @@
 		return GitblitContext.getManager(IFederationManager.class);
 	}
 
-	public static IGitblitManager gitblit() {
-		return GitblitContext.getManager(IGitblitManager.class);
+	public static IGitblit gitblit() {
+		return GitblitContext.getManager(IGitblit.class);
 	}
 }

--
Gitblit v1.9.1