From 95cdba46c79d952f2c2baba937e70796674ed57e 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] Extract RepositoryManager from the GitBlit singleton

---
 src/main/java/com/gitblit/GitBlit.java | 1816 ----------------------------------------------------------
 1 files changed, 18 insertions(+), 1,798 deletions(-)

diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java
index e012aec..4e8822b 100644
--- a/src/main/java/com/gitblit/GitBlit.java
+++ b/src/main/java/com/gitblit/GitBlit.java
@@ -25,34 +25,21 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
-import java.lang.reflect.Field;
 import java.lang.reflect.Type;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.text.MessageFormat;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 import java.util.TreeMap;
-import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
 
 import javax.naming.Context;
 import javax.naming.InitialContext;
@@ -63,25 +50,14 @@
 
 import org.apache.wicket.resource.ContextRelativeResource;
 import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.lib.RepositoryCache;
-import org.eclipse.jgit.lib.RepositoryCache.FileKey;
-import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
-import org.eclipse.jgit.storage.file.WindowCacheConfig;
 import org.eclipse.jgit.util.FS;
-import org.eclipse.jgit.util.FileUtils;
 import org.slf4j.Logger;
 
 import com.gitblit.Constants.AccessPermission;
 import com.gitblit.Constants.AccessRestrictionType;
-import com.gitblit.Constants.AuthorizationControl;
-import com.gitblit.Constants.CommitMessageRenderer;
 import com.gitblit.Constants.FederationRequest;
-import com.gitblit.Constants.FederationStrategy;
 import com.gitblit.Constants.FederationToken;
-import com.gitblit.Constants.PermissionType;
-import com.gitblit.Constants.RegistrantType;
 import com.gitblit.dagger.DaggerContextListener;
 import com.gitblit.fanout.FanoutNioService;
 import com.gitblit.fanout.FanoutService;
@@ -100,35 +76,24 @@
 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.Metric;
 import com.gitblit.models.ProjectModel;
-import com.gitblit.models.RefModel;
-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.SettingModel;
 import com.gitblit.models.TeamModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.ArrayUtils;
-import com.gitblit.utils.ByteFormat;
-import com.gitblit.utils.CommitCache;
 import com.gitblit.utils.ContainerUtils;
 import com.gitblit.utils.DeepCopier;
 import com.gitblit.utils.FederationUtils;
 import com.gitblit.utils.HttpUtils;
 import com.gitblit.utils.JGitUtils;
-import com.gitblit.utils.JGitUtils.LastChange;
 import com.gitblit.utils.JsonUtils;
-import com.gitblit.utils.MarkdownUtils;
-import com.gitblit.utils.MetricUtils;
 import com.gitblit.utils.ModelUtils;
 import com.gitblit.utils.ObjectCache;
 import com.gitblit.utils.StringUtils;
-import com.gitblit.utils.TimeUtils;
 import com.gitblit.wicket.GitblitWicketFilter;
 import com.gitblit.wicket.WicketUtils;
 import com.google.gson.Gson;
@@ -152,8 +117,7 @@
  */
 @WebListener
 public class GitBlit extends DaggerContextListener
-					 implements IRepositoryManager,
-								IProjectManager,
+					 implements IProjectManager,
 								IFederationManager,
 								IGitblitManager {
 
@@ -174,29 +138,13 @@
 
 	private final Map<String, FederationModel> federationPullResults = new ConcurrentHashMap<String, FederationModel>();
 
-	private final ObjectCache<Long> repositorySizeCache = new ObjectCache<Long>();
-
-	private final ObjectCache<List<Metric>> repositoryMetricsCache = new ObjectCache<List<Metric>>();
-
-	private final Map<String, RepositoryModel> repositoryListCache = new ConcurrentHashMap<String, RepositoryModel>();
-
 	private final Map<String, ProjectModel> projectCache = new ConcurrentHashMap<String, ProjectModel>();
-
-	private final AtomicReference<String> repositoryListSettingsChecksum = new AtomicReference<String>("");
 
 	private final ObjectCache<String> projectMarkdownCache = new ObjectCache<String>();
 
 	private final ObjectCache<String> projectRepositoriesMarkdownCache = new ObjectCache<String>();
 
-	private File repositoriesFolder;
-
 	private IStoredSettings settings;
-
-	private LuceneExecutor luceneExecutor;
-
-	private GCExecutor gcExecutor;
-
-	private MirrorExecutor mirrorExecutor;
 
 	private FileBasedConfig projectConfigs;
 
@@ -239,36 +187,6 @@
 	}
 
 	/**
-	 * Returns the most recent change date of any repository served by Gitblit.
-	 *
-	 * @return a date
-	 */
-	@Override
-	public Date getLastActivityDate() {
-		Date date = null;
-		for (String name : getRepositoryList()) {
-			Repository r = getRepository(name);
-			Date lastChange = JGitUtils.getLastChange(r).when;
-			r.close();
-			if (lastChange != null && (date == null || lastChange.after(date))) {
-				date = lastChange;
-			}
-		}
-		return date;
-	}
-
-	/**
-	 * Returns the path of the repositories folder. This method checks to see if
-	 * Gitblit is running on a cloud service and may return an adjusted path.
-	 *
-	 * @return the repositories folder path
-	 */
-	@Override
-	public File getRepositoriesFolder() {
-		return getManager(IRuntimeManager.class).getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git");
-	}
-
-	/**
 	 * Returns the path of the proposals folder. This method checks to see if
 	 * Gitblit is running on a cloud service and may return an adjusted path.
 	 *
@@ -277,28 +195,6 @@
 	@Override
 	public File getProposalsFolder() {
 		return getManager(IRuntimeManager.class).getFileOrFolder(Keys.federation.proposalsFolder, "${baseFolder}/proposals");
-	}
-
-	/**
-	 * Returns the path of the Groovy folder. This method checks to see if
-	 * Gitblit is running on a cloud service and may return an adjusted path.
-	 *
-	 * @return the Groovy scripts folder path
-	 */
-	@Override
-	public File getHooksFolder() {
-		return getManager(IRuntimeManager.class).getFileOrFolder(Keys.groovy.scriptsFolder, "${baseFolder}/groovy");
-	}
-
-	/**
-	 * Returns the path of the Groovy Grape folder. This method checks to see if
-	 * Gitblit is running on a cloud service and may return an adjusted path.
-	 *
-	 * @return the Groovy Grape folder path
-	 */
-	@Override
-	public File getGrapesFolder() {
-		return getManager(IRuntimeManager.class).getFileOrFolder(Keys.groovy.grapeFolder, "${baseFolder}/groovy/grape");
 	}
 
 	/**
@@ -484,130 +380,6 @@
 	}
 
 	/**
-	 * Returns the effective list of permissions for this user, taking into account
-	 * team memberships, ownerships.
-	 *
-	 * @param user
-	 * @return the effective list of permissions for the user
-	 */
-	@Override
-	public List<RegistrantAccessPermission> getUserAccessPermissions(UserModel user) {
-		if (StringUtils.isEmpty(user.username)) {
-			// new user
-			return new ArrayList<RegistrantAccessPermission>();
-		}
-		Set<RegistrantAccessPermission> set = new LinkedHashSet<RegistrantAccessPermission>();
-		set.addAll(user.getRepositoryPermissions());
-		// Flag missing repositories
-		for (RegistrantAccessPermission permission : set) {
-			if (permission.mutable && PermissionType.EXPLICIT.equals(permission.permissionType)) {
-				RepositoryModel rm = getRepositoryModel(permission.registrant);
-				if (rm == null) {
-					permission.permissionType = PermissionType.MISSING;
-					permission.mutable = false;
-					continue;
-				}
-			}
-		}
-
-		// TODO reconsider ownership as a user property
-		// manually specify personal repository ownerships
-		for (RepositoryModel rm : repositoryListCache.values()) {
-			if (rm.isUsersPersonalRepository(user.username) || rm.isOwner(user.username)) {
-				RegistrantAccessPermission rp = new RegistrantAccessPermission(rm.name, AccessPermission.REWIND,
-						PermissionType.OWNER, RegistrantType.REPOSITORY, null, false);
-				// user may be owner of a repository to which they've inherited
-				// a team permission, replace any existing perm with owner perm
-				set.remove(rp);
-				set.add(rp);
-			}
-		}
-
-		List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>(set);
-		Collections.sort(list);
-		return list;
-	}
-
-	/**
-	 * Returns the list of users and their access permissions for the specified
-	 * repository including permission source information such as the team or
-	 * regular expression which sets the permission.
-	 *
-	 * @param repository
-	 * @return a list of RegistrantAccessPermissions
-	 */
-	@Override
-	public List<RegistrantAccessPermission> getUserAccessPermissions(RepositoryModel repository) {
-		List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>();
-		if (AccessRestrictionType.NONE.equals(repository.accessRestriction)) {
-			// no permissions needed, REWIND for everyone!
-			return list;
-		}
-		if (AuthorizationControl.AUTHENTICATED.equals(repository.authorizationControl)) {
-			// no permissions needed, REWIND for authenticated!
-			return list;
-		}
-		// NAMED users and teams
-		for (UserModel user : getManager(IUserManager.class).getAllUsers()) {
-			RegistrantAccessPermission ap = user.getRepositoryPermission(repository);
-			if (ap.permission.exceeds(AccessPermission.NONE)) {
-				list.add(ap);
-			}
-		}
-		return list;
-	}
-
-	/**
-	 * Sets the access permissions to the specified repository for the specified users.
-	 *
-	 * @param repository
-	 * @param permissions
-	 * @return true if the user models have been updated
-	 */
-	@Override
-	public boolean setUserAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) {
-		List<UserModel> users = new ArrayList<UserModel>();
-		for (RegistrantAccessPermission up : permissions) {
-			if (up.mutable) {
-				// only set editable defined permissions
-				UserModel user = getManager(IUserManager.class).getUserModel(up.registrant);
-				user.setRepositoryPermission(repository.name, up.permission);
-				users.add(user);
-			}
-		}
-		return getManager(IUserManager.class).updateUserModels(users);
-	}
-
-	/**
-	 * Returns the list of all users who have an explicit access permission
-	 * for the specified repository.
-	 *
-	 * @see IUserService.getUsernamesForRepositoryRole(String)
-	 * @param repository
-	 * @return list of all usernames that have an access permission for the repository
-	 */
-	@Override
-	public List<String> getRepositoryUsers(RepositoryModel repository) {
-		return getManager(IUserManager.class).getUsernamesForRepositoryRole(repository.name);
-	}
-
-	/**
-	 * Sets the list of all uses who are allowed to bypass the access
-	 * restriction placed on the specified repository.
-	 *
-	 * @see IUserService.setUsernamesForRepositoryRole(String, List<String>)
-	 * @param repository
-	 * @param usernames
-	 * @return true if successful
-	 */
-	@Deprecated
-	public boolean setRepositoryUsers(RepositoryModel repository, List<String> repositoryUsers) {
-		// rejects all changes since 1.2.0 because this would elevate
-		// all discrete access permissions to RW+
-		return false;
-	}
-
-	/**
 	 * Adds/updates a complete user object keyed by username. This method allows
 	 * for renaming a user.
 	 *
@@ -628,95 +400,24 @@
 			}
 
 			// rename repositories and owner fields for all repositories
-			for (RepositoryModel model : getRepositoryModels(user)) {
+			for (RepositoryModel model : getManager(IRepositoryManager.class).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();
-					updateRepositoryModel(oldRepositoryName, model, false);
+					getManager(IRepositoryManager.class).updateRepositoryModel(oldRepositoryName, model, false);
 				} else if (model.isOwner(username)) {
 					// common/shared repo
 					model.addOwner(user.username);
-					updateRepositoryModel(model.name, model, false);
+					getManager(IRepositoryManager.class).updateRepositoryModel(model.name, model, false);
 				}
 			}
 		}
 		if (!getManager(IUserManager.class).updateUserModel(username, user)) {
 			throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!");
 		}
-	}
-
-	/**
-	 * Returns the list of teams and their access permissions for the specified
-	 * repository including the source of the permission such as the admin flag
-	 * or a regular expression.
-	 *
-	 * @param repository
-	 * @return a list of RegistrantAccessPermissions
-	 */
-	@Override
-	public List<RegistrantAccessPermission> getTeamAccessPermissions(RepositoryModel repository) {
-		List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>();
-		for (TeamModel team : getManager(IUserManager.class).getAllTeams()) {
-			RegistrantAccessPermission ap = team.getRepositoryPermission(repository);
-			if (ap.permission.exceeds(AccessPermission.NONE)) {
-				list.add(ap);
-			}
-		}
-		Collections.sort(list);
-		return list;
-	}
-
-	/**
-	 * Sets the access permissions to the specified repository for the specified teams.
-	 *
-	 * @param repository
-	 * @param permissions
-	 * @return true if the team models have been updated
-	 */
-	@Override
-	public boolean setTeamAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) {
-		List<TeamModel> teams = new ArrayList<TeamModel>();
-		for (RegistrantAccessPermission tp : permissions) {
-			if (tp.mutable) {
-				// only set explicitly defined access permissions
-				TeamModel team = getManager(IUserManager.class).getTeamModel(tp.registrant);
-				team.setRepositoryPermission(repository.name, tp.permission);
-				teams.add(team);
-			}
-		}
-		return getManager(IUserManager.class).updateTeamModels(teams);
-	}
-
-	/**
-	 * Returns the list of all teams who have an explicit access permission for
-	 * the specified repository.
-	 *
-	 * @see IUserService.getTeamnamesForRepositoryRole(String)
-	 * @param repository
-	 * @return list of all teamnames with explicit access permissions to the repository
-	 */
-	@Override
-	public List<String> getRepositoryTeams(RepositoryModel repository) {
-		return getManager(IUserManager.class).getTeamNamesForRepositoryRole(repository.name);
-	}
-
-	/**
-	 * Sets the list of all uses who are allowed to bypass the access
-	 * restriction placed on the specified repository.
-	 *
-	 * @see IUserService.setTeamnamesForRepositoryRole(String, List<String>)
-	 * @param repository
-	 * @param teamnames
-	 * @return true if successful
-	 */
-	@Deprecated
-	public boolean setRepositoryTeams(RepositoryModel repository, List<String> repositoryTeams) {
-		// rejects all changes since 1.2.0 because this would elevate
-		// all discrete access permissions to RW+
-		return false;
 	}
 
 	/**
@@ -741,332 +442,9 @@
 		}
 	}
 
-	/**
-	 * Adds the repository to the list of cached repositories if Gitblit is
-	 * configured to cache the repository list.
-	 *
-	 * @param model
-	 */
-	@Override
-	public void addToCachedRepositoryList(RepositoryModel model) {
-		if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
-			repositoryListCache.put(model.name.toLowerCase(), model);
-
-			// update the fork origin repository with this repository clone
-			if (!StringUtils.isEmpty(model.originRepository)) {
-				if (repositoryListCache.containsKey(model.originRepository)) {
-					RepositoryModel origin = repositoryListCache.get(model.originRepository);
-					origin.addFork(model.name);
-				}
-			}
-		}
-	}
-
-	/**
-	 * Removes the repository from the list of cached repositories.
-	 *
-	 * @param name
-	 * @return the model being removed
-	 */
-	private RepositoryModel removeFromCachedRepositoryList(String name) {
-		if (StringUtils.isEmpty(name)) {
-			return null;
-		}
-		return repositoryListCache.remove(name.toLowerCase());
-	}
-
-	/**
-	 * Clears all the cached metadata for the specified repository.
-	 *
-	 * @param repositoryName
-	 */
-	private void clearRepositoryMetadataCache(String repositoryName) {
-		repositorySizeCache.remove(repositoryName);
-		repositoryMetricsCache.remove(repositoryName);
-	}
-
-	/**
-	 * Resets the repository list cache.
-	 *
-	 */
-	@Override
-	public void resetRepositoryListCache() {
-		logger.info("Repository cache manually reset");
-		repositoryListCache.clear();
-	}
-
-	/**
-	 * Calculate the checksum of settings that affect the repository list cache.
-	 * @return a checksum
-	 */
-	private String getRepositoryListSettingsChecksum() {
-		StringBuilder ns = new StringBuilder();
-		ns.append(settings.getString(Keys.git.cacheRepositoryList, "")).append('\n');
-		ns.append(settings.getString(Keys.git.onlyAccessBareRepositories, "")).append('\n');
-		ns.append(settings.getString(Keys.git.searchRepositoriesSubfolders, "")).append('\n');
-		ns.append(settings.getString(Keys.git.searchRecursionDepth, "")).append('\n');
-		ns.append(settings.getString(Keys.git.searchExclusions, "")).append('\n');
-		String checksum = StringUtils.getSHA1(ns.toString());
-		return checksum;
-	}
-
-	/**
-	 * Compare the last repository list setting checksum to the current checksum.
-	 * If different then clear the cache so that it may be rebuilt.
-	 *
-	 * @return true if the cached repository list is valid since the last check
-	 */
-	private boolean isValidRepositoryList() {
-		String newChecksum = getRepositoryListSettingsChecksum();
-		boolean valid = newChecksum.equals(repositoryListSettingsChecksum.get());
-		repositoryListSettingsChecksum.set(newChecksum);
-		if (!valid && settings.getBoolean(Keys.git.cacheRepositoryList,  true)) {
-			logger.info("Repository list settings have changed. Clearing repository list cache.");
-			repositoryListCache.clear();
-		}
-		return valid;
-	}
-
-	/**
-	 * Returns the list of all repositories available to Gitblit. This method
-	 * does not consider user access permissions.
-	 *
-	 * @return list of all repositories
-	 */
-	@Override
-	public List<String> getRepositoryList() {
-		if (repositoryListCache.size() == 0 || !isValidRepositoryList()) {
-			// we are not caching OR we have not yet cached OR the cached list is invalid
-			long startTime = System.currentTimeMillis();
-			List<String> repositories = JGitUtils.getRepositoryList(repositoriesFolder,
-					settings.getBoolean(Keys.git.onlyAccessBareRepositories, false),
-					settings.getBoolean(Keys.git.searchRepositoriesSubfolders, true),
-					settings.getInteger(Keys.git.searchRecursionDepth, -1),
-					settings.getStrings(Keys.git.searchExclusions));
-
-			if (!settings.getBoolean(Keys.git.cacheRepositoryList,  true)) {
-				// we are not caching
-				StringUtils.sortRepositorynames(repositories);
-				return repositories;
-			} else {
-				// we are caching this list
-				String msg = "{0} repositories identified in {1} msecs";
-				if (settings.getBoolean(Keys.web.showRepositorySizes, true)) {
-					// optionally (re)calculate repository sizes
-					msg = "{0} repositories identified with calculated folder sizes in {1} msecs";
-				}
-
-				for (String repository : repositories) {
-					getRepositoryModel(repository);
-				}
-
-				// rebuild fork networks
-				for (RepositoryModel model : repositoryListCache.values()) {
-					if (!StringUtils.isEmpty(model.originRepository)) {
-						if (repositoryListCache.containsKey(model.originRepository)) {
-							RepositoryModel origin = repositoryListCache.get(model.originRepository);
-							origin.addFork(model.name);
-						}
-					}
-				}
-
-				long duration = System.currentTimeMillis() - startTime;
-				logger.info(MessageFormat.format(msg, repositoryListCache.size(), duration));
-			}
-		}
-
-		// return sorted copy of cached list
-		List<String> list = new ArrayList<String>();
-		for (RepositoryModel model : repositoryListCache.values()) {
-			list.add(model.name);
-		}
-		StringUtils.sortRepositorynames(list);
-		return list;
-	}
-
-	/**
-	 * Returns the JGit repository for the specified name.
-	 *
-	 * @param repositoryName
-	 * @return repository or null
-	 */
-	@Override
-	public Repository getRepository(String repositoryName) {
-		return getRepository(repositoryName, true);
-	}
-
-	/**
-	 * Returns the JGit repository for the specified name.
-	 *
-	 * @param repositoryName
-	 * @param logError
-	 * @return repository or null
-	 */
-	@Override
-	public Repository getRepository(String repositoryName, boolean logError) {
-		// Decode url-encoded repository name (issue-278)
-		// http://stackoverflow.com/questions/17183110
-		repositoryName = repositoryName.replace("%7E", "~").replace("%7e", "~");
-
-		if (isCollectingGarbage(repositoryName)) {
-			logger.warn(MessageFormat.format("Rejecting request for {0}, busy collecting garbage!", repositoryName));
-			return null;
-		}
-
-		File dir = FileKey.resolve(new File(repositoriesFolder, repositoryName), FS.DETECTED);
-		if (dir == null)
-			return null;
-
-		Repository r = null;
-		try {
-			FileKey key = FileKey.exact(dir, FS.DETECTED);
-			r = RepositoryCache.open(key, true);
-		} catch (IOException e) {
-			if (logError) {
-				logger.error("GitBlit.getRepository(String) failed to find "
-						+ new File(repositoriesFolder, repositoryName).getAbsolutePath());
-			}
-		}
-		return r;
-	}
-
-	/**
-	 * Returns the list of repository models that are accessible to the user.
-	 *
-	 * @param user
-	 * @return list of repository models accessible to user
-	 */
-	@Override
-	public List<RepositoryModel> getRepositoryModels(UserModel user) {
-		long methodStart = System.currentTimeMillis();
-		List<String> list = getRepositoryList();
-		List<RepositoryModel> repositories = new ArrayList<RepositoryModel>();
-		for (String repo : list) {
-			RepositoryModel model = getRepositoryModel(user, repo);
-			if (model != null) {
-				if (!model.hasCommits) {
-					// only add empty repositories that user can push to
-					if (UserModel.ANONYMOUS.canPush(model)
-							|| user != null && user.canPush(model)) {
-						repositories.add(model);
-					}
-				} else {
-					repositories.add(model);
-				}
-			}
-		}
-		long duration = System.currentTimeMillis() - methodStart;
-		logger.info(MessageFormat.format("{0} repository models loaded for {1} in {2} msecs",
-				repositories.size(), user == null ? "anonymous" : user.username, duration));
-		return repositories;
-	}
-
-	/**
-	 * Returns a repository model if the repository exists and the user may
-	 * access the repository.
-	 *
-	 * @param user
-	 * @param repositoryName
-	 * @return repository model or null
-	 */
-	@Override
-	public RepositoryModel getRepositoryModel(UserModel user, String repositoryName) {
-		RepositoryModel model = getRepositoryModel(repositoryName);
-		if (model == null) {
-			return null;
-		}
-		if (user == null) {
-			user = UserModel.ANONYMOUS;
-		}
-		if (user.canView(model)) {
-			return model;
-		}
-		return null;
-	}
-
-	/**
-	 * Returns the repository model for the specified repository. This method
-	 * does not consider user access permissions.
-	 *
-	 * @param repositoryName
-	 * @return repository model or null
-	 */
-	@Override
-	public RepositoryModel getRepositoryModel(String repositoryName) {
-		// Decode url-encoded repository name (issue-278)
-		// http://stackoverflow.com/questions/17183110
-		repositoryName = repositoryName.replace("%7E", "~").replace("%7e", "~");
-
-		if (!repositoryListCache.containsKey(repositoryName)) {
-			RepositoryModel model = loadRepositoryModel(repositoryName);
-			if (model == null) {
-				return null;
-			}
-			addToCachedRepositoryList(model);
-			return DeepCopier.copy(model);
-		}
-
-		// cached model
-		RepositoryModel model = repositoryListCache.get(repositoryName.toLowerCase());
-
-		if (gcExecutor.isCollectingGarbage(model.name)) {
-			// Gitblit is busy collecting garbage, use our cached model
-			RepositoryModel rm = DeepCopier.copy(model);
-			rm.isCollectingGarbage = true;
-			return rm;
-		}
-
-		// check for updates
-		Repository r = getRepository(model.name);
-		if (r == null) {
-			// repository is missing
-			removeFromCachedRepositoryList(repositoryName);
-			logger.error(MessageFormat.format("Repository \"{0}\" is missing! Removing from cache.", repositoryName));
-			return null;
-		}
-
-		FileBasedConfig config = (FileBasedConfig) getRepositoryConfig(r);
-		if (config.isOutdated()) {
-			// reload model
-			logger.debug(MessageFormat.format("Config for \"{0}\" has changed. Reloading model and updating cache.", repositoryName));
-			model = loadRepositoryModel(model.name);
-			removeFromCachedRepositoryList(model.name);
-			addToCachedRepositoryList(model);
-		} else {
-			// update a few repository parameters
-			if (!model.hasCommits) {
-				// update hasCommits, assume a repository only gains commits :)
-				model.hasCommits = JGitUtils.hasCommits(r);
-			}
-
-			updateLastChangeFields(r, model);
-		}
-		r.close();
-
-		// return a copy of the cached model
-		return DeepCopier.copy(model);
-	}
-
-	/**
-	 * Returns the star count of the repository.
-	 *
-	 * @param repository
-	 * @return the star count
-	 */
-	@Override
-	public long getStarCount(RepositoryModel repository) {
-		long count = 0;
-		for (UserModel user : getManager(IUserManager.class).getAllUsers()) {
-			if (user.getPreferences().isStarredRepository(repository.name)) {
-				count++;
-			}
-		}
-		return count;
-	}
-
 	private void reloadProjectMarkdown(ProjectModel project) {
 		// project markdown
-		File pmkd = new File(getRepositoriesFolder(), (project.isRoot ? "" : project.name) + "/project.mkd");
+		File pmkd = new File(getManager(IRepositoryManager.class).getRepositoriesFolder(), (project.isRoot ? "" : project.name) + "/project.mkd");
 		if (pmkd.exists()) {
 			Date lm = new Date(pmkd.lastModified());
 			if (!projectMarkdownCache.hasCurrent(project.name, lm)) {
@@ -1077,7 +455,7 @@
 		}
 
 		// project repositories markdown
-		File rmkd = new File(getRepositoriesFolder(), (project.isRoot ? "" : project.name) + "/repositories.mkd");
+		File rmkd = new File(getManager(IRepositoryManager.class).getRepositoriesFolder(), (project.isRoot ? "" : project.name) + "/repositories.mkd");
 		if (rmkd.exists()) {
 			Date lm = new Date(rmkd.lastModified());
 			if (!projectRepositoriesMarkdownCache.hasCurrent(project.name, lm)) {
@@ -1148,7 +526,7 @@
 		// root project
 		map.put("", configs.get(""));
 
-		for (RepositoryModel model : getRepositoryModels(user)) {
+		for (RepositoryModel model : getManager(IRepositoryManager.class).getRepositoryModels(user)) {
 			String rootPath = StringUtils.getRootPath(model.name).toLowerCase();
 			if (!map.containsKey(rootPath)) {
 				ProjectModel project;
@@ -1229,7 +607,7 @@
 		}
 		if (StringUtils.isEmpty(name)) {
 			// get root repositories
-			for (String repository : getRepositoryList()) {
+			for (String repository : getManager(IRepositoryManager.class).getRepositoryList()) {
 				if (repository.indexOf('/') == -1) {
 					project.addRepository(repository);
 				}
@@ -1237,7 +615,7 @@
 		} else {
 			// get repositories in subfolder
 			String folder = name.toLowerCase() + "/";
-			for (String repository : getRepositoryList()) {
+			for (String repository : getManager(IRepositoryManager.class).getRepositoryList()) {
 				if (repository.toLowerCase().startsWith(folder)) {
 					project.addRepository(repository);
 				}
@@ -1294,859 +672,6 @@
 			}
 		}
 		return new ArrayList<ProjectModel>(projects.values());
-	}
-
-	/**
-	 * Workaround JGit.  I need to access the raw config object directly in order
-	 * to see if the config is dirty so that I can reload a repository model.
-	 * If I use the stock JGit method to get the config it already reloads the
-	 * config.  If the config changes are made within Gitblit this is fine as
-	 * the returned config will still be flagged as dirty.  BUT... if the config
-	 * is manipulated outside Gitblit then it fails to recognize this as dirty.
-	 *
-	 * @param r
-	 * @return a config
-	 */
-	private StoredConfig getRepositoryConfig(Repository r) {
-		try {
-			Field f = r.getClass().getDeclaredField("repoConfig");
-			f.setAccessible(true);
-			StoredConfig config = (StoredConfig) f.get(r);
-			return config;
-		} catch (Exception e) {
-			logger.error("Failed to retrieve \"repoConfig\" via reflection", e);
-		}
-		return r.getConfig();
-	}
-
-	/**
-	 * Create a repository model from the configuration and repository data.
-	 *
-	 * @param repositoryName
-	 * @return a repositoryModel or null if the repository does not exist
-	 */
-	private RepositoryModel loadRepositoryModel(String repositoryName) {
-		Repository r = getRepository(repositoryName);
-		if (r == null) {
-			return null;
-		}
-		RepositoryModel model = new RepositoryModel();
-		model.isBare = r.isBare();
-		File basePath = getRepositoriesFolder();
-		if (model.isBare) {
-			model.name = com.gitblit.utils.FileUtils.getRelativePath(basePath, r.getDirectory());
-		} else {
-			model.name = com.gitblit.utils.FileUtils.getRelativePath(basePath, r.getDirectory().getParentFile());
-		}
-		if (StringUtils.isEmpty(model.name)) {
-			// Repository is NOT located relative to the base folder because it
-			// is symlinked.  Use the provided repository name.
-			model.name = repositoryName;
-		}
-		model.projectPath = StringUtils.getFirstPathElement(repositoryName);
-
-		StoredConfig config = r.getConfig();
-		boolean hasOrigin = !StringUtils.isEmpty(config.getString("remote", "origin", "url"));
-
-		if (config != null) {
-			// Initialize description from description file
-			if (getConfig(config,"description", null) == null) {
-				File descFile = new File(r.getDirectory(), "description");
-				if (descFile.exists()) {
-					String desc = com.gitblit.utils.FileUtils.readContent(descFile, System.getProperty("line.separator"));
-					if (!desc.toLowerCase().startsWith("unnamed repository")) {
-						config.setString(Constants.CONFIG_GITBLIT, null, "description", desc);
-					}
-				}
-			}
-			model.description = getConfig(config, "description", "");
-			model.originRepository = getConfig(config, "originRepository", null);
-			model.addOwners(ArrayUtils.fromString(getConfig(config, "owner", "")));
-			model.useIncrementalPushTags = getConfig(config, "useIncrementalPushTags", false);
-			model.incrementalPushTagPrefix = getConfig(config, "incrementalPushTagPrefix", null);
-			model.allowForks = getConfig(config, "allowForks", true);
-			model.accessRestriction = AccessRestrictionType.fromName(getConfig(config,
-					"accessRestriction", settings.getString(Keys.git.defaultAccessRestriction, "PUSH")));
-			model.authorizationControl = AuthorizationControl.fromName(getConfig(config,
-					"authorizationControl", settings.getString(Keys.git.defaultAuthorizationControl, null)));
-			model.verifyCommitter = getConfig(config, "verifyCommitter", false);
-			model.showRemoteBranches = getConfig(config, "showRemoteBranches", hasOrigin);
-			model.isFrozen = getConfig(config, "isFrozen", false);
-			model.skipSizeCalculation = getConfig(config, "skipSizeCalculation", false);
-			model.skipSummaryMetrics = getConfig(config, "skipSummaryMetrics", false);
-			model.commitMessageRenderer = CommitMessageRenderer.fromName(getConfig(config, "commitMessageRenderer",
-					settings.getString(Keys.web.commitMessageRenderer, null)));
-			model.federationStrategy = FederationStrategy.fromName(getConfig(config,
-					"federationStrategy", null));
-			model.federationSets = new ArrayList<String>(Arrays.asList(config.getStringList(
-					Constants.CONFIG_GITBLIT, null, "federationSets")));
-			model.isFederated = getConfig(config, "isFederated", false);
-			model.gcThreshold = getConfig(config, "gcThreshold", settings.getString(Keys.git.defaultGarbageCollectionThreshold, "500KB"));
-			model.gcPeriod = getConfig(config, "gcPeriod", settings.getInteger(Keys.git.defaultGarbageCollectionPeriod, 7));
-			try {
-				model.lastGC = new SimpleDateFormat(Constants.ISO8601).parse(getConfig(config, "lastGC", "1970-01-01'T'00:00:00Z"));
-			} catch (Exception e) {
-				model.lastGC = new Date(0);
-			}
-			model.maxActivityCommits = getConfig(config, "maxActivityCommits", settings.getInteger(Keys.web.maxActivityCommits, 0));
-			model.origin = config.getString("remote", "origin", "url");
-			if (model.origin != null) {
-				model.origin = model.origin.replace('\\', '/');
-				model.isMirror = config.getBoolean("remote", "origin", "mirror", false);
-			}
-			model.preReceiveScripts = new ArrayList<String>(Arrays.asList(config.getStringList(
-					Constants.CONFIG_GITBLIT, null, "preReceiveScript")));
-			model.postReceiveScripts = new ArrayList<String>(Arrays.asList(config.getStringList(
-					Constants.CONFIG_GITBLIT, null, "postReceiveScript")));
-			model.mailingLists = new ArrayList<String>(Arrays.asList(config.getStringList(
-					Constants.CONFIG_GITBLIT, null, "mailingList")));
-			model.indexedBranches = new ArrayList<String>(Arrays.asList(config.getStringList(
-					Constants.CONFIG_GITBLIT, null, "indexBranch")));
-			model.metricAuthorExclusions = new ArrayList<String>(Arrays.asList(config.getStringList(
-					Constants.CONFIG_GITBLIT, null, "metricAuthorExclusions")));
-
-			// Custom defined properties
-			model.customFields = new LinkedHashMap<String, String>();
-			for (String aProperty : config.getNames(Constants.CONFIG_GITBLIT, Constants.CONFIG_CUSTOM_FIELDS)) {
-				model.customFields.put(aProperty, config.getString(Constants.CONFIG_GITBLIT, Constants.CONFIG_CUSTOM_FIELDS, aProperty));
-			}
-		}
-		model.HEAD = JGitUtils.getHEADRef(r);
-		model.availableRefs = JGitUtils.getAvailableHeadTargets(r);
-		model.sparkleshareId = JGitUtils.getSparkleshareId(r);
-		model.hasCommits = JGitUtils.hasCommits(r);
-		updateLastChangeFields(r, model);
-		r.close();
-
-		if (StringUtils.isEmpty(model.originRepository) && model.origin != null && model.origin.startsWith("file://")) {
-			// repository was cloned locally... perhaps as a fork
-			try {
-				File folder = new File(new URI(model.origin));
-				String originRepo = com.gitblit.utils.FileUtils.getRelativePath(getRepositoriesFolder(), folder);
-				if (!StringUtils.isEmpty(originRepo)) {
-					// ensure origin still exists
-					File repoFolder = new File(getRepositoriesFolder(), originRepo);
-					if (repoFolder.exists()) {
-						model.originRepository = originRepo.toLowerCase();
-
-						// persist the fork origin
-						updateConfiguration(r, model);
-					}
-				}
-			} catch (URISyntaxException e) {
-				logger.error("Failed to determine fork for " + model, e);
-			}
-		}
-		return model;
-	}
-
-	/**
-	 * Determines if this server has the requested repository.
-	 *
-	 * @param n
-	 * @return true if the repository exists
-	 */
-	@Override
-	public boolean hasRepository(String repositoryName) {
-		return hasRepository(repositoryName, false);
-	}
-
-	/**
-	 * Determines if this server has the requested repository.
-	 *
-	 * @param n
-	 * @param caseInsensitive
-	 * @return true if the repository exists
-	 */
-	@Override
-	public boolean hasRepository(String repositoryName, boolean caseSensitiveCheck) {
-		if (!caseSensitiveCheck && settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
-			// if we are caching use the cache to determine availability
-			// otherwise we end up adding a phantom repository to the cache
-			return repositoryListCache.containsKey(repositoryName.toLowerCase());
-		}
-		Repository r = getRepository(repositoryName, false);
-		if (r == null) {
-			return false;
-		}
-		r.close();
-		return true;
-	}
-
-	/**
-	 * Determines if the specified user has a fork of the specified origin
-	 * repository.
-	 *
-	 * @param username
-	 * @param origin
-	 * @return true the if the user has a fork
-	 */
-	@Override
-	public boolean hasFork(String username, String origin) {
-		return getFork(username, origin) != null;
-	}
-
-	/**
-	 * Gets the name of a user's fork of the specified origin
-	 * repository.
-	 *
-	 * @param username
-	 * @param origin
-	 * @return the name of the user's fork, null otherwise
-	 */
-	@Override
-	public String getFork(String username, String origin) {
-		String userProject = ModelUtils.getPersonalPath(username);
-		if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
-			String userPath = userProject + "/";
-
-			// collect all origin nodes in fork network
-			Set<String> roots = new HashSet<String>();
-			roots.add(origin);
-			RepositoryModel originModel = repositoryListCache.get(origin);
-			while (originModel != null) {
-				if (!ArrayUtils.isEmpty(originModel.forks)) {
-					for (String fork : originModel.forks) {
-						if (!fork.startsWith(userPath)) {
-							roots.add(fork);
-						}
-					}
-				}
-
-				if (originModel.originRepository != null) {
-					roots.add(originModel.originRepository);
-					originModel = repositoryListCache.get(originModel.originRepository);
-				} else {
-					// break
-					originModel = null;
-				}
-			}
-
-			for (String repository : repositoryListCache.keySet()) {
-				if (repository.startsWith(userPath)) {
-					RepositoryModel model = repositoryListCache.get(repository);
-					if (!StringUtils.isEmpty(model.originRepository)) {
-						if (roots.contains(model.originRepository)) {
-							// user has a fork in this graph
-							return model.name;
-						}
-					}
-				}
-			}
-		} else {
-			// not caching
-			ProjectModel project = getProjectModel(userProject);
-			if (project == null) {
-				return null;
-			}
-			for (String repository : project.repositories) {
-				if (repository.startsWith(userProject)) {
-					RepositoryModel model = getRepositoryModel(repository);
-					if (model.originRepository.equalsIgnoreCase(origin)) {
-						// user has a fork
-						return model.name;
-					}
-				}
-			}
-		}
-		// user does not have a fork
-		return null;
-	}
-
-	/**
-	 * Returns the fork network for a repository by traversing up the fork graph
-	 * to discover the root and then down through all children of the root node.
-	 *
-	 * @param repository
-	 * @return a ForkModel
-	 */
-	@Override
-	public ForkModel getForkNetwork(String repository) {
-		if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
-			// find the root, cached
-			RepositoryModel model = repositoryListCache.get(repository.toLowerCase());
-			while (model.originRepository != null) {
-				model = repositoryListCache.get(model.originRepository);
-			}
-			ForkModel root = getForkModelFromCache(model.name);
-			return root;
-		} else {
-			// find the root, non-cached
-			RepositoryModel model = getRepositoryModel(repository.toLowerCase());
-			while (model.originRepository != null) {
-				model = getRepositoryModel(model.originRepository);
-			}
-			ForkModel root = getForkModel(model.name);
-			return root;
-		}
-	}
-
-	private ForkModel getForkModelFromCache(String repository) {
-		RepositoryModel model = repositoryListCache.get(repository.toLowerCase());
-		if (model == null) {
-			return null;
-		}
-		ForkModel fork = new ForkModel(model);
-		if (!ArrayUtils.isEmpty(model.forks)) {
-			for (String aFork : model.forks) {
-				ForkModel fm = getForkModelFromCache(aFork);
-				if (fm != null) {
-					fork.forks.add(fm);
-				}
-			}
-		}
-		return fork;
-	}
-
-	private ForkModel getForkModel(String repository) {
-		RepositoryModel model = getRepositoryModel(repository.toLowerCase());
-		if (model == null) {
-			return null;
-		}
-		ForkModel fork = new ForkModel(model);
-		if (!ArrayUtils.isEmpty(model.forks)) {
-			for (String aFork : model.forks) {
-				ForkModel fm = getForkModel(aFork);
-				if (fm != null) {
-					fork.forks.add(fm);
-				}
-			}
-		}
-		return fork;
-	}
-
-	/**
-	 * Updates the last changed fields and optionally calculates the size of the
-	 * repository.  Gitblit caches the repository sizes to reduce the performance
-	 * penalty of recursive calculation. The cache is updated if the repository
-	 * has been changed since the last calculation.
-	 *
-	 * @param model
-	 * @return size in bytes of the repository
-	 */
-	@Override
-	public long updateLastChangeFields(Repository r, RepositoryModel model) {
-		LastChange lc = JGitUtils.getLastChange(r);
-		model.lastChange = lc.when;
-		model.lastChangeAuthor = lc.who;
-
-		if (!settings.getBoolean(Keys.web.showRepositorySizes, true) || model.skipSizeCalculation) {
-			model.size = null;
-			return 0L;
-		}
-		if (!repositorySizeCache.hasCurrent(model.name, model.lastChange)) {
-			File gitDir = r.getDirectory();
-			long sz = com.gitblit.utils.FileUtils.folderSize(gitDir);
-			repositorySizeCache.updateObject(model.name, model.lastChange, sz);
-		}
-		long size = repositorySizeCache.getObject(model.name);
-		ByteFormat byteFormat = new ByteFormat();
-		model.size = byteFormat.format(size);
-		return size;
-	}
-
-	/**
-	 * Ensure that a cached repository is completely closed and its resources
-	 * are properly released.
-	 *
-	 * @param repositoryName
-	 */
-	private void closeRepository(String repositoryName) {
-		Repository repository = getRepository(repositoryName);
-		if (repository == null) {
-			return;
-		}
-		RepositoryCache.close(repository);
-
-		// assume 2 uses in case reflection fails
-		int uses = 2;
-		try {
-			// The FileResolver caches repositories which is very useful
-			// for performance until you want to delete a repository.
-			// I have to use reflection to call close() the correct
-			// number of times to ensure that the object and ref databases
-			// are properly closed before I can delete the repository from
-			// the filesystem.
-			Field useCnt = Repository.class.getDeclaredField("useCnt");
-			useCnt.setAccessible(true);
-			uses = ((AtomicInteger) useCnt.get(repository)).get();
-		} catch (Exception e) {
-			logger.warn(MessageFormat
-					.format("Failed to reflectively determine use count for repository {0}",
-							repositoryName), e);
-		}
-		if (uses > 0) {
-			logger.info(MessageFormat
-					.format("{0}.useCnt={1}, calling close() {2} time(s) to close object and ref databases",
-							repositoryName, uses, uses));
-			for (int i = 0; i < uses; i++) {
-				repository.close();
-			}
-		}
-
-		// close any open index writer/searcher in the Lucene executor
-		luceneExecutor.close(repositoryName);
-	}
-
-	/**
-	 * Returns the metrics for the default branch of the specified repository.
-	 * This method builds a metrics cache. The cache is updated if the
-	 * repository is updated. A new copy of the metrics list is returned on each
-	 * call so that modifications to the list are non-destructive.
-	 *
-	 * @param model
-	 * @param repository
-	 * @return a new array list of metrics
-	 */
-	@Override
-	public List<Metric> getRepositoryDefaultMetrics(RepositoryModel model, Repository repository) {
-		if (repositoryMetricsCache.hasCurrent(model.name, model.lastChange)) {
-			return new ArrayList<Metric>(repositoryMetricsCache.getObject(model.name));
-		}
-		List<Metric> metrics = MetricUtils.getDateMetrics(repository, null, true, null, getManager(IRuntimeManager.class).getTimezone());
-		repositoryMetricsCache.updateObject(model.name, model.lastChange, metrics);
-		return new ArrayList<Metric>(metrics);
-	}
-
-	/**
-	 * Returns the gitblit string value for the specified key. If key is not
-	 * set, returns defaultValue.
-	 *
-	 * @param config
-	 * @param field
-	 * @param defaultValue
-	 * @return field value or defaultValue
-	 */
-	private String getConfig(StoredConfig config, String field, String defaultValue) {
-		String value = config.getString(Constants.CONFIG_GITBLIT, null, field);
-		if (StringUtils.isEmpty(value)) {
-			return defaultValue;
-		}
-		return value;
-	}
-
-	/**
-	 * Returns the gitblit boolean value for the specified key. If key is not
-	 * set, returns defaultValue.
-	 *
-	 * @param config
-	 * @param field
-	 * @param defaultValue
-	 * @return field value or defaultValue
-	 */
-	private boolean getConfig(StoredConfig config, String field, boolean defaultValue) {
-		return config.getBoolean(Constants.CONFIG_GITBLIT, field, defaultValue);
-	}
-
-	/**
-	 * Returns the gitblit string value for the specified key. If key is not
-	 * set, returns defaultValue.
-	 *
-	 * @param config
-	 * @param field
-	 * @param defaultValue
-	 * @return field value or defaultValue
-	 */
-	private int getConfig(StoredConfig config, String field, int defaultValue) {
-		String value = config.getString(Constants.CONFIG_GITBLIT, null, field);
-		if (StringUtils.isEmpty(value)) {
-			return defaultValue;
-		}
-		try {
-			return Integer.parseInt(value);
-		} catch (Exception e) {
-		}
-		return defaultValue;
-	}
-
-	/**
-	 * Creates/updates the repository model keyed by reopsitoryName. Saves all
-	 * repository settings in .git/config. This method allows for renaming
-	 * repositories and will update user access permissions accordingly.
-	 *
-	 * All repositories created by this method are bare and automatically have
-	 * .git appended to their names, which is the standard convention for bare
-	 * repositories.
-	 *
-	 * @param repositoryName
-	 * @param repository
-	 * @param isCreate
-	 * @throws GitBlitException
-	 */
-	@Override
-	public void updateRepositoryModel(String repositoryName, RepositoryModel repository,
-			boolean isCreate) throws GitBlitException {
-		if (gcExecutor.isCollectingGarbage(repositoryName)) {
-			throw new GitBlitException(MessageFormat.format("sorry, Gitblit is busy collecting garbage in {0}",
-					repositoryName));
-		}
-		Repository r = null;
-		String projectPath = StringUtils.getFirstPathElement(repository.name);
-		if (!StringUtils.isEmpty(projectPath)) {
-			if (projectPath.equalsIgnoreCase(settings.getString(Keys.web.repositoryRootGroupName, "main"))) {
-				// strip leading group name
-				repository.name = repository.name.substring(projectPath.length() + 1);
-			}
-		}
-		if (isCreate) {
-			// ensure created repository name ends with .git
-			if (!repository.name.toLowerCase().endsWith(org.eclipse.jgit.lib.Constants.DOT_GIT_EXT)) {
-				repository.name += org.eclipse.jgit.lib.Constants.DOT_GIT_EXT;
-			}
-			if (hasRepository(repository.name)) {
-				throw new GitBlitException(MessageFormat.format(
-						"Can not create repository ''{0}'' because it already exists.",
-						repository.name));
-			}
-			// create repository
-			logger.info("create repository " + repository.name);
-			String shared = settings.getString(Keys.git.createRepositoriesShared, "FALSE");
-			r = JGitUtils.createRepository(repositoriesFolder, repository.name, shared);
-		} else {
-			// rename repository
-			if (!repositoryName.equalsIgnoreCase(repository.name)) {
-				if (!repository.name.toLowerCase().endsWith(
-						org.eclipse.jgit.lib.Constants.DOT_GIT_EXT)) {
-					repository.name += org.eclipse.jgit.lib.Constants.DOT_GIT_EXT;
-				}
-				if (new File(repositoriesFolder, repository.name).exists()) {
-					throw new GitBlitException(MessageFormat.format(
-							"Failed to rename ''{0}'' because ''{1}'' already exists.",
-							repositoryName, repository.name));
-				}
-				closeRepository(repositoryName);
-				File folder = new File(repositoriesFolder, repositoryName);
-				File destFolder = new File(repositoriesFolder, repository.name);
-				if (destFolder.exists()) {
-					throw new GitBlitException(
-							MessageFormat
-									.format("Can not rename repository ''{0}'' to ''{1}'' because ''{1}'' already exists.",
-											repositoryName, repository.name));
-				}
-				File parentFile = destFolder.getParentFile();
-				if (!parentFile.exists() && !parentFile.mkdirs()) {
-					throw new GitBlitException(MessageFormat.format(
-							"Failed to create folder ''{0}''", parentFile.getAbsolutePath()));
-				}
-				if (!folder.renameTo(destFolder)) {
-					throw new GitBlitException(MessageFormat.format(
-							"Failed to rename repository ''{0}'' to ''{1}''.", repositoryName,
-							repository.name));
-				}
-				// rename the roles
-				if (!getManager(IUserManager.class).renameRepositoryRole(repositoryName, repository.name)) {
-					throw new GitBlitException(MessageFormat.format(
-							"Failed to rename repository permissions ''{0}'' to ''{1}''.",
-							repositoryName, repository.name));
-				}
-
-				// rename fork origins in their configs
-				if (!ArrayUtils.isEmpty(repository.forks)) {
-					for (String fork : repository.forks) {
-						Repository rf = getRepository(fork);
-						try {
-							StoredConfig config = rf.getConfig();
-							String origin = config.getString("remote", "origin", "url");
-							origin = origin.replace(repositoryName, repository.name);
-							config.setString("remote", "origin", "url", origin);
-							config.setString(Constants.CONFIG_GITBLIT, null, "originRepository", repository.name);
-							config.save();
-						} catch (Exception e) {
-							logger.error("Failed to update repository fork config for " + fork, e);
-						}
-						rf.close();
-					}
-				}
-
-				// update this repository's origin's fork list
-				if (!StringUtils.isEmpty(repository.originRepository)) {
-					RepositoryModel origin = repositoryListCache.get(repository.originRepository);
-					if (origin != null && !ArrayUtils.isEmpty(origin.forks)) {
-						origin.forks.remove(repositoryName);
-						origin.forks.add(repository.name);
-					}
-				}
-
-				// clear the cache
-				clearRepositoryMetadataCache(repositoryName);
-				repository.resetDisplayName();
-			}
-
-			// load repository
-			logger.info("edit repository " + repository.name);
-			r = getRepository(repository.name);
-		}
-
-		// update settings
-		if (r != null) {
-			updateConfiguration(r, repository);
-			// Update the description file
-			File descFile = new File(r.getDirectory(), "description");
-			if (repository.description != null)
-			{
-				com.gitblit.utils.FileUtils.writeContent(descFile, repository.description);
-			}
-			else if (descFile.exists() && !descFile.isDirectory()) {
-				descFile.delete();
-			}
-			// only update symbolic head if it changes
-			String currentRef = JGitUtils.getHEADRef(r);
-			if (!StringUtils.isEmpty(repository.HEAD) && !repository.HEAD.equals(currentRef)) {
-				logger.info(MessageFormat.format("Relinking {0} HEAD from {1} to {2}",
-						repository.name, currentRef, repository.HEAD));
-				if (JGitUtils.setHEADtoRef(r, repository.HEAD)) {
-					// clear the cache
-					clearRepositoryMetadataCache(repository.name);
-				}
-			}
-
-			// Adjust permissions in case we updated the config files
-			JGitUtils.adjustSharedPerm(new File(r.getDirectory().getAbsolutePath(), "config"),
-					settings.getString(Keys.git.createRepositoriesShared, "FALSE"));
-			JGitUtils.adjustSharedPerm(new File(r.getDirectory().getAbsolutePath(), "HEAD"),
-					settings.getString(Keys.git.createRepositoriesShared, "FALSE"));
-
-			// close the repository object
-			r.close();
-		}
-
-		// update repository cache
-		removeFromCachedRepositoryList(repositoryName);
-		// model will actually be replaced on next load because config is stale
-		addToCachedRepositoryList(repository);
-	}
-
-	/**
-	 * Updates the Gitblit configuration for the specified repository.
-	 *
-	 * @param r
-	 *            the Git repository
-	 * @param repository
-	 *            the Gitblit repository model
-	 */
-	@Override
-	public void updateConfiguration(Repository r, RepositoryModel repository) {
-		StoredConfig config = r.getConfig();
-		config.setString(Constants.CONFIG_GITBLIT, null, "description", repository.description);
-		config.setString(Constants.CONFIG_GITBLIT, null, "originRepository", repository.originRepository);
-		config.setString(Constants.CONFIG_GITBLIT, null, "owner", ArrayUtils.toString(repository.owners));
-		config.setBoolean(Constants.CONFIG_GITBLIT, null, "useIncrementalPushTags", repository.useIncrementalPushTags);
-		if (StringUtils.isEmpty(repository.incrementalPushTagPrefix) ||
-				repository.incrementalPushTagPrefix.equals(settings.getString(Keys.git.defaultIncrementalPushTagPrefix, "r"))) {
-			config.unset(Constants.CONFIG_GITBLIT, null, "incrementalPushTagPrefix");
-		} else {
-			config.setString(Constants.CONFIG_GITBLIT, null, "incrementalPushTagPrefix", repository.incrementalPushTagPrefix);
-		}
-		config.setBoolean(Constants.CONFIG_GITBLIT, null, "allowForks", repository.allowForks);
-		config.setString(Constants.CONFIG_GITBLIT, null, "accessRestriction", repository.accessRestriction.name());
-		config.setString(Constants.CONFIG_GITBLIT, null, "authorizationControl", repository.authorizationControl.name());
-		config.setBoolean(Constants.CONFIG_GITBLIT, null, "verifyCommitter", repository.verifyCommitter);
-		config.setBoolean(Constants.CONFIG_GITBLIT, null, "showRemoteBranches", repository.showRemoteBranches);
-		config.setBoolean(Constants.CONFIG_GITBLIT, null, "isFrozen", repository.isFrozen);
-		config.setBoolean(Constants.CONFIG_GITBLIT, null, "skipSizeCalculation", repository.skipSizeCalculation);
-		config.setBoolean(Constants.CONFIG_GITBLIT, null, "skipSummaryMetrics", repository.skipSummaryMetrics);
-		config.setString(Constants.CONFIG_GITBLIT, null, "federationStrategy",
-				repository.federationStrategy.name());
-		config.setBoolean(Constants.CONFIG_GITBLIT, null, "isFederated", repository.isFederated);
-		config.setString(Constants.CONFIG_GITBLIT, null, "gcThreshold", repository.gcThreshold);
-		if (repository.gcPeriod == settings.getInteger(Keys.git.defaultGarbageCollectionPeriod, 7)) {
-			// use default from config
-			config.unset(Constants.CONFIG_GITBLIT, null, "gcPeriod");
-		} else {
-			config.setInt(Constants.CONFIG_GITBLIT, null, "gcPeriod", repository.gcPeriod);
-		}
-		if (repository.lastGC != null) {
-			config.setString(Constants.CONFIG_GITBLIT, null, "lastGC", new SimpleDateFormat(Constants.ISO8601).format(repository.lastGC));
-		}
-		if (repository.maxActivityCommits == settings.getInteger(Keys.web.maxActivityCommits, 0)) {
-			// use default from config
-			config.unset(Constants.CONFIG_GITBLIT, null, "maxActivityCommits");
-		} else {
-			config.setInt(Constants.CONFIG_GITBLIT, null, "maxActivityCommits", repository.maxActivityCommits);
-		}
-
-		CommitMessageRenderer defaultRenderer = CommitMessageRenderer.fromName(settings.getString(Keys.web.commitMessageRenderer, null));
-		if (repository.commitMessageRenderer == null || repository.commitMessageRenderer == defaultRenderer) {
-			// use default from config
-			config.unset(Constants.CONFIG_GITBLIT, null, "commitMessageRenderer");
-		} else {
-			// repository overrides default
-			config.setString(Constants.CONFIG_GITBLIT, null, "commitMessageRenderer",
-					repository.commitMessageRenderer.name());
-		}
-
-		updateList(config, "federationSets", repository.federationSets);
-		updateList(config, "preReceiveScript", repository.preReceiveScripts);
-		updateList(config, "postReceiveScript", repository.postReceiveScripts);
-		updateList(config, "mailingList", repository.mailingLists);
-		updateList(config, "indexBranch", repository.indexedBranches);
-		updateList(config, "metricAuthorExclusions", repository.metricAuthorExclusions);
-
-		// User Defined Properties
-		if (repository.customFields != null) {
-			if (repository.customFields.size() == 0) {
-				// clear section
-				config.unsetSection(Constants.CONFIG_GITBLIT, Constants.CONFIG_CUSTOM_FIELDS);
-			} else {
-				for (Entry<String, String> property : repository.customFields.entrySet()) {
-					// set field
-					String key = property.getKey();
-					String value = property.getValue();
-					config.setString(Constants.CONFIG_GITBLIT, Constants.CONFIG_CUSTOM_FIELDS, key, value);
-				}
-			}
-		}
-
-		try {
-			config.save();
-		} catch (IOException e) {
-			logger.error("Failed to save repository config!", e);
-		}
-	}
-
-	private void updateList(StoredConfig config, String field, List<String> list) {
-		// a null list is skipped, not cleared
-		// this is for RPC administration where an older manager might be used
-		if (list == null) {
-			return;
-		}
-		if (ArrayUtils.isEmpty(list)) {
-			config.unset(Constants.CONFIG_GITBLIT, null, field);
-		} else {
-			config.setStringList(Constants.CONFIG_GITBLIT, null, field, list);
-		}
-	}
-
-	/**
-	 * Deletes the repository from the file system and removes the repository
-	 * permission from all repository users.
-	 *
-	 * @param model
-	 * @return true if successful
-	 */
-	@Override
-	public boolean deleteRepositoryModel(RepositoryModel model) {
-		return deleteRepository(model.name);
-	}
-
-	/**
-	 * Deletes the repository from the file system and removes the repository
-	 * permission from all repository users.
-	 *
-	 * @param repositoryName
-	 * @return true if successful
-	 */
-	@Override
-	public boolean deleteRepository(String repositoryName) {
-		try {
-			closeRepository(repositoryName);
-			// clear the repository cache
-			clearRepositoryMetadataCache(repositoryName);
-
-			RepositoryModel model = removeFromCachedRepositoryList(repositoryName);
-			if (model != null && !ArrayUtils.isEmpty(model.forks)) {
-				resetRepositoryListCache();
-			}
-
-			File folder = new File(repositoriesFolder, repositoryName);
-			if (folder.exists() && folder.isDirectory()) {
-				FileUtils.delete(folder, FileUtils.RECURSIVE | FileUtils.RETRY);
-				if (getManager(IUserManager.class).deleteRepositoryRole(repositoryName)) {
-					logger.info(MessageFormat.format("Repository \"{0}\" deleted", repositoryName));
-					return true;
-				}
-			}
-		} catch (Throwable t) {
-			logger.error(MessageFormat.format("Failed to delete repository {0}", repositoryName), t);
-		}
-		return false;
-	}
-
-	/**
-	 * Returns an html version of the commit message with any global or
-	 * repository-specific regular expression substitution applied.
-	 *
-	 * This method uses the preferred renderer to transform the commit message.
-	 *
-	 * @param repository
-	 * @param text
-	 * @return html version of the commit message
-	 */
-	public String processCommitMessage(RepositoryModel repository, String text) {
-		switch (repository.commitMessageRenderer) {
-		case MARKDOWN:
-			try {
-				String prepared = processCommitMessageRegex(repository.name, text);
-				return MarkdownUtils.transformMarkdown(prepared);
-			} catch (Exception e) {
-				logger.error("Failed to render commit message as markdown", e);
-			}
-			break;
-		default:
-			// noop
-			break;
-		}
-
-		return processPlainCommitMessage(repository.name, text);
-	}
-
-	/**
-	 * Returns an html version of the commit message with any global or
-	 * repository-specific regular expression substitution applied.
-	 *
-	 * This method assumes the commit message is plain text.
-	 *
-	 * @param repositoryName
-	 * @param text
-	 * @return html version of the commit message
-	 */
-	public String processPlainCommitMessage(String repositoryName, String text) {
-		String html = StringUtils.escapeForHtml(text, false);
-		html = processCommitMessageRegex(repositoryName, html);
-		return StringUtils.breakLinesForHtml(html);
-
-	}
-
-	/**
-	 * Apply globally or per-repository specified regex substitutions to the
-	 * commit message.
-	 *
-	 * @param repositoryName
-	 * @param text
-	 * @return the processed commit message
-	 */
-	protected String processCommitMessageRegex(String repositoryName, String text) {
-		Map<String, String> map = new HashMap<String, String>();
-		// global regex keys
-		if (settings.getBoolean(Keys.regex.global, false)) {
-			for (String key : settings.getAllKeys(Keys.regex.global)) {
-				if (!key.equals(Keys.regex.global)) {
-					String subKey = key.substring(key.lastIndexOf('.') + 1);
-					map.put(subKey, settings.getString(key, ""));
-				}
-			}
-		}
-
-		// repository-specific regex keys
-		List<String> keys = settings.getAllKeys(Keys.regex._ROOT + "."
-				+ repositoryName.toLowerCase());
-		for (String key : keys) {
-			String subKey = key.substring(key.lastIndexOf('.') + 1);
-			map.put(subKey, settings.getString(key, ""));
-		}
-
-		for (Entry<String, String> entry : map.entrySet()) {
-			String definition = entry.getValue().trim();
-			String[] chunks = definition.split("!!!");
-			if (chunks.length == 2) {
-				text = text.replaceAll(chunks[0], chunks[1]);
-			} else {
-				logger.warn(entry.getKey()
-						+ " improperly formatted.  Use !!! to separate match from replacement: "
-						+ definition);
-			}
-		}
-		return text;
 	}
 
 	/**
@@ -2447,7 +972,7 @@
 
 		// Retrieve all available repositories
 		UserModel user = getFederationUser();
-		List<RepositoryModel> list = getRepositoryModels(user);
+		List<RepositoryModel> list = getManager(IRepositoryManager.class).getRepositoryModels(user);
 
 		// create the [cloneurl, repositoryModel] map
 		Map<String, RepositoryModel> repositories = new HashMap<String, RepositoryModel>();
@@ -2537,155 +1062,6 @@
 	}
 
 	/**
-	 * Returns the list of all Groovy push hook scripts. Script files must have
-	 * .groovy extension
-	 *
-	 * @return list of available hook scripts
-	 */
-	@Override
-	public List<String> getAllScripts() {
-		File groovyFolder = getHooksFolder();
-		File[] files = groovyFolder.listFiles(new FileFilter() {
-			@Override
-			public boolean accept(File pathname) {
-				return pathname.isFile() && pathname.getName().endsWith(".groovy");
-			}
-		});
-		List<String> scripts = new ArrayList<String>();
-		if (files != null) {
-			for (File file : files) {
-				String script = file.getName().substring(0, file.getName().lastIndexOf('.'));
-				scripts.add(script);
-			}
-		}
-		return scripts;
-	}
-
-	/**
-	 * Returns the list of pre-receive scripts the repository inherited from the
-	 * global settings and team affiliations.
-	 *
-	 * @param repository
-	 *            if null only the globally specified scripts are returned
-	 * @return a list of scripts
-	 */
-	@Override
-	public List<String> getPreReceiveScriptsInherited(RepositoryModel repository) {
-		Set<String> scripts = new LinkedHashSet<String>();
-		// Globals
-		for (String script : settings.getStrings(Keys.groovy.preReceiveScripts)) {
-			if (script.endsWith(".groovy")) {
-				scripts.add(script.substring(0, script.lastIndexOf('.')));
-			} else {
-				scripts.add(script);
-			}
-		}
-
-		// Team Scripts
-		if (repository != null) {
-			for (String teamname : getManager(IUserManager.class).getTeamNamesForRepositoryRole(repository.name)) {
-				TeamModel team = getManager(IUserManager.class).getTeamModel(teamname);
-				if (!ArrayUtils.isEmpty(team.preReceiveScripts)) {
-					scripts.addAll(team.preReceiveScripts);
-				}
-			}
-		}
-		return new ArrayList<String>(scripts);
-	}
-
-	/**
-	 * Returns the list of all available Groovy pre-receive push hook scripts
-	 * that are not already inherited by the repository. Script files must have
-	 * .groovy extension
-	 *
-	 * @param repository
-	 *            optional parameter
-	 * @return list of available hook scripts
-	 */
-	@Override
-	public List<String> getPreReceiveScriptsUnused(RepositoryModel repository) {
-		Set<String> inherited = new TreeSet<String>(getPreReceiveScriptsInherited(repository));
-
-		// create list of available scripts by excluding inherited scripts
-		List<String> scripts = new ArrayList<String>();
-		for (String script : getAllScripts()) {
-			if (!inherited.contains(script)) {
-				scripts.add(script);
-			}
-		}
-		return scripts;
-	}
-
-	/**
-	 * Returns the list of post-receive scripts the repository inherited from
-	 * the global settings and team affiliations.
-	 *
-	 * @param repository
-	 *            if null only the globally specified scripts are returned
-	 * @return a list of scripts
-	 */
-	@Override
-	public List<String> getPostReceiveScriptsInherited(RepositoryModel repository) {
-		Set<String> scripts = new LinkedHashSet<String>();
-		// Global Scripts
-		for (String script : settings.getStrings(Keys.groovy.postReceiveScripts)) {
-			if (script.endsWith(".groovy")) {
-				scripts.add(script.substring(0, script.lastIndexOf('.')));
-			} else {
-				scripts.add(script);
-			}
-		}
-		// Team Scripts
-		if (repository != null) {
-			for (String teamname : getManager(IUserManager.class).getTeamNamesForRepositoryRole(repository.name)) {
-				TeamModel team = getManager(IUserManager.class).getTeamModel(teamname);
-				if (!ArrayUtils.isEmpty(team.postReceiveScripts)) {
-					scripts.addAll(team.postReceiveScripts);
-				}
-			}
-		}
-		return new ArrayList<String>(scripts);
-	}
-
-	/**
-	 * Returns the list of unused Groovy post-receive push hook scripts that are
-	 * not already inherited by the repository. Script files must have .groovy
-	 * extension
-	 *
-	 * @param repository
-	 *            optional parameter
-	 * @return list of available hook scripts
-	 */
-	@Override
-	public List<String> getPostReceiveScriptsUnused(RepositoryModel repository) {
-		Set<String> inherited = new TreeSet<String>(getPostReceiveScriptsInherited(repository));
-
-		// create list of available scripts by excluding inherited scripts
-		List<String> scripts = new ArrayList<String>();
-		for (String script : getAllScripts()) {
-			if (!inherited.contains(script)) {
-				scripts.add(script);
-			}
-		}
-		return scripts;
-	}
-
-	/**
-	 * Search the specified repositories using the Lucene query.
-	 *
-	 * @param query
-	 * @param page
-	 * @param pageSize
-	 * @param repositories
-	 * @return
-	 */
-	@Override
-	public List<SearchResult> search(String query, int page, int pageSize, List<String> repositories) {
-		List<SearchResult> srs = luceneExecutor.search(query, page, pageSize, repositories);
-		return srs;
-	}
-
-	/**
 	 * 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.
@@ -2757,74 +1133,6 @@
 		return settingsModel;
 	}
 
-	protected void configureLuceneIndexing() {
-		scheduledExecutor.scheduleAtFixedRate(luceneExecutor, 1, 2,  TimeUnit.MINUTES);
-		logger.info("Lucene executor is scheduled to process indexed branches every 2 minutes.");
-	}
-
-	protected void configureGarbageCollector() {
-		// schedule gc engine
-		if (gcExecutor.isReady()) {
-			logger.info("GC executor is scheduled to scan repositories every 24 hours.");
-			Calendar c = Calendar.getInstance();
-			c.set(Calendar.HOUR_OF_DAY, settings.getInteger(Keys.git.garbageCollectionHour, 0));
-			c.set(Calendar.MINUTE, 0);
-			c.set(Calendar.SECOND, 0);
-			c.set(Calendar.MILLISECOND, 0);
-			Date cd = c.getTime();
-			Date now = new Date();
-			int delay = 0;
-			if (cd.before(now)) {
-				c.add(Calendar.DATE, 1);
-				cd = c.getTime();
-			}
-			delay = (int) ((cd.getTime() - now.getTime())/TimeUtils.MIN);
-			String when = delay + " mins";
-			if (delay > 60) {
-				when = MessageFormat.format("{0,number,0.0} hours", (delay)/60f);
-			}
-			logger.info(MessageFormat.format("Next scheculed GC scan is in {0}", when));
-			scheduledExecutor.scheduleAtFixedRate(gcExecutor, delay, 60*24, TimeUnit.MINUTES);
-		}
-	}
-
-	protected void configureMirrorExecutor() {
-		if (mirrorExecutor.isReady()) {
-			int mins = TimeUtils.convertFrequencyToMinutes(settings.getString(Keys.git.mirrorPeriod, "30 mins"));
-			if (mins < 5) {
-				mins = 5;
-			}
-			int delay = 1;
-			scheduledExecutor.scheduleAtFixedRate(mirrorExecutor, delay, mins,  TimeUnit.MINUTES);
-			logger.info("Mirror executor is scheduled to fetch updates every {} minutes.", mins);
-			logger.info("Next scheduled mirror fetch is in {} minutes", delay);
-		}
-	}
-
-	protected void configureJGit() {
-		// Configure JGit
-		WindowCacheConfig cfg = new WindowCacheConfig();
-
-		cfg.setPackedGitWindowSize(settings.getFilesize(Keys.git.packedGitWindowSize, cfg.getPackedGitWindowSize()));
-		cfg.setPackedGitLimit(settings.getFilesize(Keys.git.packedGitLimit, cfg.getPackedGitLimit()));
-		cfg.setDeltaBaseCacheLimit(settings.getFilesize(Keys.git.deltaBaseCacheLimit, cfg.getDeltaBaseCacheLimit()));
-		cfg.setPackedGitOpenFiles(settings.getFilesize(Keys.git.packedGitOpenFiles, cfg.getPackedGitOpenFiles()));
-		cfg.setStreamFileThreshold(settings.getFilesize(Keys.git.streamFileThreshold, cfg.getStreamFileThreshold()));
-		cfg.setPackedGitMMAP(settings.getBoolean(Keys.git.packedGitMmap, cfg.isPackedGitMMAP()));
-
-		try {
-			cfg.install();
-			logger.debug(MessageFormat.format("{0} = {1,number,0}", Keys.git.packedGitWindowSize, cfg.getPackedGitWindowSize()));
-			logger.debug(MessageFormat.format("{0} = {1,number,0}", Keys.git.packedGitLimit, cfg.getPackedGitLimit()));
-			logger.debug(MessageFormat.format("{0} = {1,number,0}", Keys.git.deltaBaseCacheLimit, cfg.getDeltaBaseCacheLimit()));
-			logger.debug(MessageFormat.format("{0} = {1,number,0}", Keys.git.packedGitOpenFiles, cfg.getPackedGitOpenFiles()));
-			logger.debug(MessageFormat.format("{0} = {1,number,0}", Keys.git.streamFileThreshold, cfg.getStreamFileThreshold()));
-			logger.debug(MessageFormat.format("{0} = {1}", Keys.git.packedGitMmap, cfg.isPackedGitMMAP()));
-		} catch (IllegalArgumentException e) {
-			logger.error("Failed to configure JGit parameters!", e);
-		}
-	}
-
 	protected void configureFanout() {
 		// startup Fanout PubSub service
 		if (settings.getInteger(Keys.fanout.port, 0) > 0) {
@@ -2864,7 +1172,7 @@
 						getManager(INotificationManager.class),
 						getManager(IUserManager.class),
 						getManager(ISessionManager.class),
-						this,
+						getManager(IRepositoryManager.class),
 						this,
 						this,
 						this);
@@ -2877,52 +1185,12 @@
 		}
 	}
 
-	protected void configureCommitCache() {
-		int daysToCache = settings.getInteger(Keys.web.activityCacheDays, 14);
-		if (daysToCache <= 0) {
-			logger.info("commit cache disabled");
-		} else {
-			long start = System.nanoTime();
-			long repoCount = 0;
-			long commitCount = 0;
-			logger.info(MessageFormat.format("preparing {0} day commit cache. please wait...", daysToCache));
-			CommitCache.instance().setCacheDays(daysToCache);
-			Date cutoff = CommitCache.instance().getCutoffDate();
-			for (String repositoryName : getRepositoryList()) {
-				RepositoryModel model = getRepositoryModel(repositoryName);
-				if (model != null && model.hasCommits && model.lastChange.after(cutoff)) {
-					repoCount++;
-					Repository repository = getRepository(repositoryName);
-					for (RefModel ref : JGitUtils.getLocalBranches(repository, true, -1)) {
-						if (!ref.getDate().after(cutoff)) {
-							// branch not recently updated
-							continue;
-						}
-						List<?> commits = CommitCache.instance().getCommits(repositoryName, repository, ref.getName());
-						if (commits.size() > 0) {
-							logger.info(MessageFormat.format("  cached {0} commits for {1}:{2}",
-									commits.size(), repositoryName, ref.getName()));
-							commitCount += commits.size();
-						}
-					}
-					repository.close();
-				}
-			}
-			logger.info(MessageFormat.format("built {0} day commit cache of {1} commits across {2} repositories in {3} msecs",
-					daysToCache, commitCount, repoCount, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)));
-		}
-	}
-
 	protected final Logger getLogger() {
 		return logger;
 	}
 
 	protected final ScheduledExecutorService getScheduledExecutor() {
 		return scheduledExecutor;
-	}
-
-	protected final LuceneExecutor getLuceneExecutor() {
-		return luceneExecutor;
 	}
 
 	/**
@@ -2973,29 +1241,9 @@
 		startManager(injector, INotificationManager.class);
 		startManager(injector, IUserManager.class);
 		startManager(injector, ISessionManager.class);
-
-		repositoriesFolder = getRepositoriesFolder();
+		startManager(injector, IRepositoryManager.class);
 
 		logger.info("Gitblit base folder     = " + baseFolder.getAbsolutePath());
-		logger.info("Git repositories folder = " + repositoriesFolder.getAbsolutePath());
-
-		// prepare service executors
-		luceneExecutor = new LuceneExecutor(runtimeSettings, getManager(IRepositoryManager.class));
-		gcExecutor = new GCExecutor(runtimeSettings, getManager(IRepositoryManager.class));
-		mirrorExecutor = new MirrorExecutor(runtimeSettings, getManager(IRepositoryManager.class));
-
-		// initialize utilities
-		String prefix = runtimeSettings.getString(Keys.git.userRepositoryPrefix, "~");
-		ModelUtils.setUserRepoPrefix(prefix);
-
-		// calculate repository list settings checksum for future config changes
-		repositoryListSettingsChecksum.set(getRepositoryListSettingsChecksum());
-
-		// build initial repository list
-		if (runtimeSettings.getBoolean(Keys.git.cacheRepositoryList,  true)) {
-			logger.info("Identifying available repositories...");
-			getRepositoryList();
-		}
 
 		loadSettingModels(runtime.getSettingsModel());
 
@@ -3003,16 +1251,11 @@
 		projectConfigs = new FileBasedConfig(runtime.getFileOrFolder(Keys.web.projectsFile, "${baseFolder}/projects.conf"), FS.detect());
 		getProjectConfigs();
 
-		configureLuceneIndexing();
-		configureGarbageCollector();
-		configureMirrorExecutor();
 		if (true/*startFederation*/) {
 			configureFederation();
 		}
-		configureJGit();
 		configureFanout();
 		configureGitDaemon();
-		configureCommitCache();
 	}
 
 	/**
@@ -3215,35 +1458,12 @@
 		}
 
 		scheduledExecutor.shutdownNow();
-		luceneExecutor.close();
-		gcExecutor.close();
-		mirrorExecutor.close();
 		if (fanoutService != null) {
 			fanoutService.stop();
 		}
 		if (gitDaemon != null) {
 			gitDaemon.stop();
 		}
-	}
-
-	/**
-	 *
-	 * @return true if we are running the gc executor
-	 */
-	@Override
-	public boolean isCollectingGarbage() {
-		return gcExecutor.isRunning();
-	}
-
-	/**
-	 * Returns true if Gitblit is actively collecting garbage in this repository.
-	 *
-	 * @param repositoryName
-	 * @return true if actively collecting garbage
-	 */
-	@Override
-	public boolean isCollectingGarbage(String repositoryName) {
-		return gcExecutor.isCollectingGarbage(repositoryName);
 	}
 
 	/**
@@ -3259,11 +1479,11 @@
 	@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}", repositoriesFolder.getAbsolutePath(), repository.name);
+		String fromUrl = MessageFormat.format("file://{0}/{1}", getManager(IRepositoryManager.class).getRepositoriesFolder().getAbsolutePath(), repository.name);
 
 		// clone the repository
 		try {
-			JGitUtils.cloneRepository(repositoriesFolder, cloneName, fromUrl, true, null);
+			JGitUtils.cloneRepository(getManager(IRepositoryManager.class).getRepositoriesFolder(), cloneName, fromUrl, true, null);
 		} catch (Exception e) {
 			throw new GitBlitException(e);
 		}
@@ -3272,7 +1492,7 @@
 		RepositoryModel cloneModel = repository.cloneAs(cloneName);
 		// owner has REWIND/RW+ permissions
 		cloneModel.addOwner(user.username);
-		updateRepositoryModel(cloneName, cloneModel, false);
+		getManager(IRepositoryManager.class).updateRepositoryModel(cloneName, cloneModel, false);
 
 		// add the owner of the source repository to the clone's access list
 		if (!ArrayUtils.isEmpty(repository.owners)) {
@@ -3286,7 +1506,7 @@
 		}
 
 		// grant origin's user list clone permission to fork
-		List<String> users = getRepositoryUsers(repository);
+		List<String> users = getManager(IRepositoryManager.class).getRepositoryUsers(repository);
 		List<UserModel> cloneUsers = new ArrayList<UserModel>();
 		for (String name : users) {
 			if (!name.equalsIgnoreCase(user.username)) {
@@ -3301,7 +1521,7 @@
 		getManager(IUserManager.class).updateUserModels(cloneUsers);
 
 		// grant origin's team list clone permission to fork
-		List<String> teams = getRepositoryTeams(repository);
+		List<String> teams = getManager(IRepositoryManager.class).getRepositoryTeams(repository);
 		List<TeamModel> cloneTeams = new ArrayList<TeamModel>();
 		for (String name : teams) {
 			TeamModel cloneTeam = getManager(IUserManager.class).getTeamModel(name);
@@ -3314,7 +1534,7 @@
 		getManager(IUserManager.class).updateTeamModels(cloneTeams);
 
 		// add this clone to the cached model
-		addToCachedRepositoryList(cloneModel);
+		getManager(IRepositoryManager.class).addToCachedRepositoryList(cloneModel);
 		return cloneModel;
 	}
 

--
Gitblit v1.9.1