From 94e12c168f5eec300fd23d0de25c7dc93a96c429 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Mon, 03 Mar 2014 17:51:21 -0500
Subject: [PATCH] Eliminate Gravatar profile linking and improve api

---
 src/main/java/com/gitblit/manager/GitblitManager.java | 1119 ++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 890 insertions(+), 229 deletions(-)

diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
index 9947382..6eb6023 100644
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ b/src/main/java/com/gitblit/manager/GitblitManager.java
@@ -27,22 +27,38 @@
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jgit.lib.Repository;
 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.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;
+import com.gitblit.models.ForkModel;
 import com.gitblit.models.GitClientApplication;
+import com.gitblit.models.Mailing;
+import com.gitblit.models.Metric;
+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;
 import com.gitblit.models.SettingModel;
 import com.gitblit.models.TeamModel;
 import com.gitblit.models.UserModel;
@@ -57,29 +73,57 @@
 import com.google.gson.JsonSyntaxException;
 import com.google.gson.reflect.TypeToken;
 
-public class GitblitManager implements IGitblitManager {
+/**
+ * GitblitManager is an aggregate interface delegate.  It implements all the manager
+ * interfaces and delegates most methods calls to the proper manager implementation.
+ * It's primary purpose is to provide complete management control to the git
+ * upload and receive pack functions.
+ *
+ * GitblitManager also implements several integration methods when it is required
+ * to manipulate several manages for one operation.
+ *
+ * @author James Moger
+ *
+ */
+public class GitblitManager implements IGitblit {
 
-	private final Logger logger = LoggerFactory.getLogger(getClass());
+	protected final Logger logger = LoggerFactory.getLogger(getClass());
 
-	private final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>();
+	protected final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>();
 
-	private final IStoredSettings settings;
+	protected final IStoredSettings settings;
 
-	private final IRuntimeManager runtimeManager;
+	protected final IRuntimeManager runtimeManager;
 
-	private final IUserManager userManager;
+	protected final INotificationManager notificationManager;
 
-	private final IRepositoryManager repositoryManager;
+	protected final IUserManager userManager;
+
+	protected final IAuthenticationManager authenticationManager;
+
+	protected final IRepositoryManager repositoryManager;
+
+	protected final IProjectManager projectManager;
+
+	protected final IFederationManager federationManager;
 
 	public GitblitManager(
 			IRuntimeManager runtimeManager,
+			INotificationManager notificationManager,
 			IUserManager userManager,
-			IRepositoryManager repositoryManager) {
+			IAuthenticationManager authenticationManager,
+			IRepositoryManager repositoryManager,
+			IProjectManager projectManager,
+			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.federationManager = federationManager;
 	}
 
 	@Override
@@ -93,66 +137,163 @@
 		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>
+	/*
+	 * IGITBLIT
 	 */
-	private void loadSettingModels(ServerSettings settingsModel) {
+
+	/**
+	 * 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 {
-			// 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();
-					}
+			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.canClone(cloneModel)) {
+					// origin owner can't yet clone fork, grant explicit clone access
+					originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE);
+					reviseUser(originOwner.username, originOwner);
 				}
 			}
-			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");
+		}
+
+		// 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) && !cloneUser.canClone(cloneModel)) {
+					// origin user can't yet clone fork, grant explicit clone access
+					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) && !cloneTeam.canClone(cloneModel)) {
+				// origin team can't yet clone fork, grant explicit clone access
+				cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE);
+			}
+			cloneTeams.add(cloneTeam);
+		}
+		userManager.updateTeamModels(cloneTeams);
+
+		// add this clone to the cached model
+		repositoryManager.addToCachedRepositoryList(cloneModel);
+		return cloneModel;
+	}
+
+	/**
+	 * Adds a TeamModel object.
+	 *
+	 * @param team
+	 */
+	@Override
+	public void addTeam(TeamModel team) throws GitBlitException {
+		if (!userManager.updateTeamModel(team)) {
+			throw new GitBlitException("Failed to add team!");
+		}
+	}
+
+	/**
+	 * Updates the TeamModel object for the specified name.
+	 *
+	 * @param teamname
+	 * @param team
+	 */
+	@Override
+	public void reviseTeam(String teamname, TeamModel team) 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("Failed to update team!");
+		}
+	}
+
+	/**
+	 * Adds a user object.
+	 *
+	 * @param user
+	 * @throws GitBlitException
+	 */
+	@Override
+	public void addUser(UserModel user) throws GitBlitException {
+		if (!userManager.updateUserModel(user)) {
+			throw new GitBlitException("Failed to add user!");
+		}
+	}
+
+	/**
+	 * Updates a user object keyed by username. This method allows
+	 * for renaming a user.
+	 *
+	 * @param username
+	 * @param user
+	 * @throws GitBlitException
+	 */
+	@Override
+	public void reviseUser(String username, UserModel user) 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("Failed to update user!");
 		}
 	}
 
@@ -180,15 +321,6 @@
 			}
 		}
 
-		// 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
@@ -207,9 +339,13 @@
 	}
 
 	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(HttpUtils.getGitblitURL(request));
-		sb.append(Constants.GIT_PATH);
+		sb.append(gitblitUrl);
+		sb.append(Constants.R_PATH);
 		sb.append(repository.name);
 
 		// inject username into repository url if authentication is required
@@ -220,41 +356,6 @@
 		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
@@ -320,137 +421,697 @@
 	}
 
 	/**
-	 * 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.
+	 * 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.
 	 *
-	 * @param repository
-	 * @param user
-	 * @return the repository model of the fork, if successful
-	 * @throws GitBlitException
+	 * @return Map<String, SettingModel>
 	 */
-	@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
+	private void loadSettingModels(ServerSettings settingsModel) {
 		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);
+			// 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();
+					}
 				}
 			}
-		}
-
-		// 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!");
+			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");
 		}
 	}
 
-	/**
-	 * Updates the TeamModel object for the specified name.
+	/*
+	 * ISTOREDSETTINGS
 	 *
-	 * @param teamname
-	 * @param team
-	 * @param isCreate
+	 * these methods are necessary for (nearly) seamless Groovy hook operation
+	 * after the massive refactor.
 	 */
+
+	public boolean getBoolean(String key, boolean defaultValue) {
+		return runtimeManager.getSettings().getBoolean(key, defaultValue);
+	}
+
+	public String getString(String key, String defaultValue) {
+		return runtimeManager.getSettings().getString(key, defaultValue);
+	}
+
+	public int getInteger(String key, int defaultValue) {
+		return runtimeManager.getSettings().getInteger(key, defaultValue);
+	}
+
+	public List<String> getStrings(String key) {
+		return runtimeManager.getSettings().getStrings(key);
+	}
+
+	/*
+	 * RUNTIME MANAGER
+	 */
+
 	@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));
-			}
+	public File getBaseFolder() {
+		return runtimeManager.getBaseFolder();
+	}
+
+	@Override
+	public void setBaseFolder(File folder) {
+		runtimeManager.setBaseFolder(folder);
+	}
+
+	@Override
+	public Date getBootDate() {
+		return runtimeManager.getBootDate();
+	}
+
+	@Override
+	public ServerSettings getSettingsModel() {
+		return runtimeManager.getSettingsModel();
+	}
+
+	@Override
+	public boolean isServingRepositories() {
+		return runtimeManager.isServingRepositories();
+	}
+
+	@Override
+	public TimeZone getTimezone() {
+		return runtimeManager.getTimezone();
+	}
+
+	@Override
+	public boolean isDebugMode() {
+		return runtimeManager.isDebugMode();
+	}
+
+	@Override
+	public File getFileOrFolder(String key, String defaultFileOrFolder) {
+		return runtimeManager.getFileOrFolder(key, defaultFileOrFolder);
+	}
+
+	@Override
+	public File getFileOrFolder(String fileOrFolder) {
+		return runtimeManager.getFileOrFolder(fileOrFolder);
+	}
+
+	@Override
+	public IStoredSettings getSettings() {
+		return runtimeManager.getSettings();
+	}
+
+	@Override
+	public boolean updateSettings(Map<String, String> updatedSettings) {
+		return runtimeManager.updateSettings(updatedSettings);
+	}
+
+	@Override
+	public ServerStatus getStatus() {
+		return runtimeManager.getStatus();
+	}
+
+	/*
+	 * NOTIFICATION MANAGER
+	 */
+
+	@Override
+	public void sendMailToAdministrators(String subject, String message) {
+		notificationManager.sendMailToAdministrators(subject, message);
+	}
+
+	@Override
+	public void sendMail(String subject, String message, Collection<String> toAddresses) {
+		notificationManager.sendMail(subject, message, toAddresses);
+	}
+
+	@Override
+	public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) {
+		notificationManager.sendHtmlMail(subject, message, toAddresses);
+	}
+
+	@Override
+	public void send(Mailing mail) {
+		notificationManager.send(mail);
+	}
+
+	/*
+	 * SESSION MANAGER
+	 */
+
+	@Override
+	public UserModel authenticate(String username, char[] password) {
+		return authenticationManager.authenticate(username, password);
+	}
+
+	@Override
+	public UserModel authenticate(HttpServletRequest httpRequest) {
+		UserModel user = authenticationManager.authenticate(httpRequest, false);
+		if (user == null) {
+			user = federationManager.authenticate(httpRequest);
 		}
-		if (!userManager.updateTeamModel(teamname, team)) {
-			throw new GitBlitException(isCreate ? "Failed to add team!" : "Failed to update team!");
+		return user;
+	}
+	@Override
+	public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
+		UserModel user = authenticationManager.authenticate(httpRequest, requiresCertificate);
+		if (user == null) {
+			user = federationManager.authenticate(httpRequest);
 		}
+		return user;
+	}
+
+	@Override
+	public String getCookie(HttpServletRequest request) {
+		return authenticationManager.getCookie(request);
+	}
+
+	@Override
+	public void setCookie(HttpServletResponse response, UserModel user) {
+		authenticationManager.setCookie(response, user);
+	}
+
+	@Override
+	public void logout(HttpServletResponse response, UserModel user) {
+		authenticationManager.logout(response, user);
+	}
+
+	@Override
+	public boolean supportsCredentialChanges(UserModel user) {
+		return authenticationManager.supportsCredentialChanges(user);
+	}
+
+	@Override
+	public boolean supportsDisplayNameChanges(UserModel user) {
+		return authenticationManager.supportsDisplayNameChanges(user);
+	}
+
+	@Override
+	public boolean supportsEmailAddressChanges(UserModel user) {
+		return authenticationManager.supportsEmailAddressChanges(user);
+	}
+
+	@Override
+	public boolean supportsTeamMembershipChanges(UserModel user) {
+		return authenticationManager.supportsTeamMembershipChanges(user);
+	}
+
+	@Override
+	public boolean supportsTeamMembershipChanges(TeamModel team) {
+		return authenticationManager.supportsTeamMembershipChanges(team);
+	}
+
+	/*
+	 * USER MANAGER
+	 */
+
+	@Override
+	public void setup(IRuntimeManager runtimeManager) {
+	}
+
+	@Override
+	public boolean isInternalAccount(String username) {
+		return userManager.isInternalAccount(username);
+	}
+
+	@Override
+	public List<String> getAllUsernames() {
+		return userManager.getAllUsernames();
+	}
+
+	@Override
+	public List<UserModel> getAllUsers() {
+		return userManager.getAllUsers();
+	}
+
+	@Override
+	public boolean deleteUser(String username) {
+		return userManager.deleteUser(username);
+	}
+
+	@Override
+	public UserModel getUserModel(String username) {
+		return userManager.getUserModel(username);
+	}
+
+	@Override
+	public List<TeamModel> getAllTeams() {
+		return userManager.getAllTeams();
+	}
+
+	@Override
+	public TeamModel getTeamModel(String teamname) {
+		return userManager.getTeamModel(teamname);
+	}
+
+	@Override
+	public String getCookie(UserModel model) {
+		return userManager.getCookie(model);
+	}
+
+	@Override
+	public UserModel getUserModel(char[] cookie) {
+		return userManager.getUserModel(cookie);
+	}
+
+	@Override
+	public boolean updateUserModel(UserModel model) {
+		return userManager.updateUserModel(model);
+	}
+
+	@Override
+	public boolean updateUserModels(Collection<UserModel> models) {
+		return userManager.updateUserModels(models);
+	}
+
+	@Override
+	public boolean updateUserModel(String username, UserModel model) {
+		return userManager.updateUserModel(username, model);
+	}
+
+	@Override
+	public boolean deleteUserModel(UserModel model) {
+		return userManager.deleteUserModel(model);
+	}
+
+	@Override
+	public List<String> getAllTeamNames() {
+		return userManager.getAllTeamNames();
+	}
+
+	@Override
+	public List<String> getTeamNamesForRepositoryRole(String role) {
+		return userManager.getTeamNamesForRepositoryRole(role);
+	}
+
+	@Override
+	public boolean updateTeamModel(TeamModel model) {
+		return userManager.updateTeamModel(model);
+	}
+
+	@Override
+	public boolean updateTeamModels(Collection<TeamModel> models) {
+		return userManager.updateTeamModels(models);
+	}
+
+	@Override
+	public boolean updateTeamModel(String teamname, TeamModel model) {
+		return userManager.updateTeamModel(teamname, model);
+	}
+
+	@Override
+	public boolean deleteTeamModel(TeamModel model) {
+		return userManager.deleteTeamModel(model);
+	}
+
+	@Override
+	public List<String> getUsernamesForRepositoryRole(String role) {
+		return userManager.getUsernamesForRepositoryRole(role);
+	}
+
+	@Override
+	public boolean renameRepositoryRole(String oldRole, String newRole) {
+		return userManager.renameRepositoryRole(oldRole, newRole);
+	}
+
+	@Override
+	public boolean deleteRepositoryRole(String role) {
+		return userManager.deleteRepositoryRole(role);
+	}
+
+	@Override
+	public boolean deleteTeam(String teamname) {
+		return userManager.deleteTeam(teamname);
+	}
+
+	/*
+	 * REPOSITORY MANAGER
+	 */
+
+	@Override
+	public Date getLastActivityDate() {
+		return repositoryManager.getLastActivityDate();
+	}
+
+	@Override
+	public File getRepositoriesFolder() {
+		return repositoryManager.getRepositoriesFolder();
+	}
+
+	@Override
+	public File getHooksFolder() {
+		return repositoryManager.getHooksFolder();
+	}
+
+	@Override
+	public File getGrapesFolder() {
+		return repositoryManager.getGrapesFolder();
+	}
+
+	@Override
+	public List<RegistrantAccessPermission> getUserAccessPermissions(UserModel user) {
+		return repositoryManager.getUserAccessPermissions(user);
+	}
+
+	@Override
+	public List<RegistrantAccessPermission> getUserAccessPermissions(RepositoryModel repository) {
+		return repositoryManager.getUserAccessPermissions(repository);
+	}
+
+	@Override
+	public boolean setUserAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) {
+		return repositoryManager.setUserAccessPermissions(repository, permissions);
+	}
+
+	@Override
+	public List<String> getRepositoryUsers(RepositoryModel repository) {
+		return repositoryManager.getRepositoryUsers(repository);
+	}
+
+	@Override
+	public List<RegistrantAccessPermission> getTeamAccessPermissions(RepositoryModel repository) {
+		return repositoryManager.getTeamAccessPermissions(repository);
+	}
+
+	@Override
+	public boolean setTeamAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) {
+		return repositoryManager.setTeamAccessPermissions(repository, permissions);
+	}
+
+	@Override
+	public List<String> getRepositoryTeams(RepositoryModel repository) {
+		return repositoryManager.getRepositoryTeams(repository);
+	}
+	@Override
+	public void addToCachedRepositoryList(RepositoryModel model) {
+		repositoryManager.addToCachedRepositoryList(model);
+	}
+
+	@Override
+	public void resetRepositoryListCache() {
+		repositoryManager.resetRepositoryListCache();
+	}
+
+	@Override
+	public List<String> getRepositoryList() {
+		return repositoryManager.getRepositoryList();
+	}
+
+	@Override
+	public Repository getRepository(String repositoryName) {
+		return repositoryManager.getRepository(repositoryName);
+	}
+
+	@Override
+	public Repository getRepository(String repositoryName, boolean logError) {
+		return repositoryManager.getRepository(repositoryName, logError);
+	}
+
+	@Override
+	public List<RepositoryModel> getRepositoryModels(UserModel user) {
+		return repositoryManager.getRepositoryModels(user);
+	}
+
+	@Override
+	public RepositoryModel getRepositoryModel(UserModel user, String repositoryName) {
+		return repositoryManager.getRepositoryModel(repositoryName);
+	}
+
+	@Override
+	public RepositoryModel getRepositoryModel(String repositoryName) {
+		return repositoryManager.getRepositoryModel(repositoryName);
+	}
+
+	@Override
+	public long getStarCount(RepositoryModel repository) {
+		return repositoryManager.getStarCount(repository);
+	}
+
+	@Override
+	public boolean hasRepository(String repositoryName) {
+		return repositoryManager.hasRepository(repositoryName);
+	}
+
+	@Override
+	public boolean hasRepository(String repositoryName, boolean caseSensitiveCheck) {
+		return repositoryManager.hasRepository(repositoryName, caseSensitiveCheck);
+	}
+
+	@Override
+	public boolean hasFork(String username, String origin) {
+		return repositoryManager.hasFork(username, origin);
+	}
+
+	@Override
+	public String getFork(String username, String origin) {
+		return repositoryManager.getFork(username, origin);
+	}
+
+	@Override
+	public ForkModel getForkNetwork(String repository) {
+		return repositoryManager.getForkNetwork(repository);
+	}
+
+	@Override
+	public long updateLastChangeFields(Repository r, RepositoryModel model) {
+		return repositoryManager.updateLastChangeFields(r, model);
+	}
+
+	@Override
+	public List<Metric> getRepositoryDefaultMetrics(RepositoryModel model, Repository repository) {
+		return repositoryManager.getRepositoryDefaultMetrics(model, repository);
+	}
+
+	@Override
+	public void updateRepositoryModel(String repositoryName, RepositoryModel repository,
+			boolean isCreate) throws GitBlitException {
+		repositoryManager.updateRepositoryModel(repositoryName, repository, isCreate);
+	}
+
+	@Override
+	public void updateConfiguration(Repository r, RepositoryModel repository) {
+		repositoryManager.updateConfiguration(r, repository);
+	}
+
+	@Override
+	public boolean deleteRepositoryModel(RepositoryModel model) {
+		return repositoryManager.deleteRepositoryModel(model);
+	}
+
+	@Override
+	public boolean deleteRepository(String repositoryName) {
+		return repositoryManager.deleteRepository(repositoryName);
+	}
+
+	@Override
+	public List<String> getAllScripts() {
+		return repositoryManager.getAllScripts();
+	}
+
+	@Override
+	public List<String> getPreReceiveScriptsInherited(RepositoryModel repository) {
+		return repositoryManager.getPreReceiveScriptsInherited(repository);
+	}
+
+	@Override
+	public List<String> getPreReceiveScriptsUnused(RepositoryModel repository) {
+		return repositoryManager.getPreReceiveScriptsUnused(repository);
+	}
+
+	@Override
+	public List<String> getPostReceiveScriptsInherited(RepositoryModel repository) {
+		return repositoryManager.getPostReceiveScriptsInherited(repository);
+	}
+
+	@Override
+	public List<String> getPostReceiveScriptsUnused(RepositoryModel repository) {
+		return repositoryManager.getPostReceiveScriptsUnused(repository);
+	}
+
+	@Override
+	public List<SearchResult> search(String query, int page, int pageSize, List<String> repositories) {
+		return repositoryManager.search(query, page, pageSize, repositories);
+	}
+
+	@Override
+	public boolean isCollectingGarbage() {
+		return repositoryManager.isCollectingGarbage();
+	}
+
+	@Override
+	public boolean isCollectingGarbage(String repositoryName) {
+		return repositoryManager.isCollectingGarbage(repositoryName);
+	}
+
+	/*
+	 * PROJECT MANAGER
+	 */
+
+	@Override
+	public List<ProjectModel> getProjectModels(UserModel user, boolean includeUsers) {
+		return projectManager.getProjectModels(user, includeUsers);
+	}
+
+	@Override
+	public ProjectModel getProjectModel(String name, UserModel user) {
+		return projectManager.getProjectModel(name, user);
+	}
+
+	@Override
+	public ProjectModel getProjectModel(String name) {
+		return projectManager.getProjectModel(name);
+	}
+
+	@Override
+	public List<ProjectModel> getProjectModels(List<RepositoryModel> repositoryModels, boolean includeUsers) {
+		return projectManager.getProjectModels(repositoryModels, includeUsers);
+	}
+
+	/*
+	 * FEDERATION MANAGER
+	 */
+
+	@Override
+	public File getProposalsFolder() {
+		return federationManager.getProposalsFolder();
+	}
+
+	@Override
+	public boolean canFederate() {
+		return federationManager.canFederate();
+	}
+
+	@Override
+	public UserModel getFederationUser() {
+		return federationManager.getFederationUser();
+	}
+
+	@Override
+	public List<FederationModel> getFederationRegistrations() {
+		return federationManager.getFederationRegistrations();
+	}
+
+	@Override
+	public FederationModel getFederationRegistration(String url, String name) {
+		return federationManager.getFederationRegistration(url, name);
+	}
+
+	@Override
+	public List<FederationSet> getFederationSets(String gitblitUrl) {
+		return federationManager.getFederationSets(gitblitUrl);
+	}
+
+	@Override
+	public List<String> getFederationTokens() {
+		return federationManager.getFederationTokens();
+	}
+
+	@Override
+	public String getFederationToken(FederationToken type) {
+		return federationManager.getFederationToken(type);
+	}
+
+	@Override
+	public String getFederationToken(String value) {
+		return federationManager.getFederationToken(value);
+	}
+
+	@Override
+	public boolean validateFederationRequest(FederationRequest req, String token) {
+		return federationManager.validateFederationRequest(req, token);
+	}
+
+	@Override
+	public boolean acknowledgeFederationStatus(String identification, FederationModel registration) {
+		return federationManager.acknowledgeFederationStatus(identification, registration);
+	}
+
+	@Override
+	public List<FederationModel> getFederationResultRegistrations() {
+		return federationManager.getFederationResultRegistrations();
+	}
+
+	@Override
+	public boolean submitFederationProposal(FederationProposal proposal, String gitblitUrl) {
+		return federationManager.submitFederationProposal(proposal, gitblitUrl);
+	}
+
+	@Override
+	public List<FederationProposal> getPendingFederationProposals() {
+		return federationManager.getPendingFederationProposals();
+	}
+
+	@Override
+	public Map<String, RepositoryModel> getRepositories(String gitblitUrl, String token) {
+		return federationManager.getRepositories(gitblitUrl, token);
+	}
+
+	@Override
+	public FederationProposal createFederationProposal(String gitblitUrl, String token) {
+		return federationManager.createFederationProposal(gitblitUrl, token);
+	}
+
+	@Override
+	public FederationProposal getPendingFederationProposal(String token) {
+		return federationManager.getPendingFederationProposal(token);
+	}
+
+	@Override
+	public boolean deletePendingFederationProposal(FederationProposal proposal) {
+		return federationManager.deletePendingFederationProposal(proposal);
+	}
+
+	@Override
+	public void closeAll() {
+		repositoryManager.closeAll();
+	}
+
+	@Override
+	public void close(String repository) {
+		repositoryManager.close(repository);
+	}
+
+	@Override
+	public boolean isIdle(Repository repository) {
+		return repositoryManager.isIdle(repository);
 	}
 }

--
Gitblit v1.9.1