From aa6d43e8b28ff73d69a920e9b3a7b284cfce00c3 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 SessionManager from GitBlit singleton --- src/main/java/com/gitblit/GitBlit.java | 1314 +++++++++++++---------------------------------------------- 1 files changed, 294 insertions(+), 1,020 deletions(-) diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java index 8be50fb..e012aec 100644 --- a/src/main/java/com/gitblit/GitBlit.java +++ b/src/main/java/com/gitblit/GitBlit.java @@ -29,8 +29,6 @@ import java.lang.reflect.Type; import java.net.URI; import java.net.URISyntaxException; -import java.nio.charset.Charset; -import java.security.Principal; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -47,7 +45,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.TimeZone; import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; @@ -57,20 +54,13 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMultipart; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletContext; import javax.servlet.annotation.WebListener; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.apache.wicket.RequestCycle; import org.apache.wicket.resource.ContextRelativeResource; import org.apache.wicket.util.resource.ResourceStreamNotFoundException; import org.eclipse.jgit.lib.Repository; @@ -85,8 +75,6 @@ import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; -import com.gitblit.Constants.AccountType; -import com.gitblit.Constants.AuthenticationType; import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.CommitMessageRenderer; import com.gitblit.Constants.FederationRequest; @@ -102,6 +90,7 @@ import com.gitblit.git.GitServlet; import com.gitblit.manager.IFederationManager; import com.gitblit.manager.IGitblitManager; +import com.gitblit.manager.IManager; import com.gitblit.manager.INotificationManager; import com.gitblit.manager.IProjectManager; import com.gitblit.manager.IRepositoryManager; @@ -121,12 +110,10 @@ 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; import com.gitblit.utils.ArrayUtils; -import com.gitblit.utils.Base64; import com.gitblit.utils.ByteFormat; import com.gitblit.utils.CommitCache; import com.gitblit.utils.ContainerUtils; @@ -142,14 +129,14 @@ import com.gitblit.utils.ObjectCache; import com.gitblit.utils.StringUtils; import com.gitblit.utils.TimeUtils; -import com.gitblit.utils.X509Utils.X509Metadata; -import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.GitblitWicketFilter; import com.gitblit.wicket.WicketUtils; import com.google.gson.Gson; import com.google.gson.JsonIOException; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; + +import dagger.ObjectGraph; /** * GitBlit is the servlet context listener singleton that acts as the core for @@ -165,11 +152,7 @@ */ @WebListener public class GitBlit extends DaggerContextListener - implements IRuntimeManager, - INotificationManager, - IUserManager, - ISessionManager, - IRepositoryManager, + implements IRepositoryManager, IProjectManager, IFederationManager, IGitblitManager { @@ -177,6 +160,10 @@ private static GitBlit gitblit; private final IStoredSettings goSettings; + + private final File goBaseFolder; + + private final List<IManager> managers = new ArrayList<IManager>(); private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(10); @@ -201,27 +188,15 @@ private final ObjectCache<String> projectRepositoriesMarkdownCache = new ObjectCache<String>(); - private File baseFolder; - private File repositoriesFolder; - private IUserService userService; - private IStoredSettings settings; - - private ServerSettings settingsModel; - - private ServerStatus serverStatus; - - private MailExecutor mailExecutor; private LuceneExecutor luceneExecutor; private GCExecutor gcExecutor; private MirrorExecutor mirrorExecutor; - - private TimeZone timezone; private FileBasedConfig projectConfigs; @@ -231,17 +206,12 @@ public GitBlit() { this.goSettings = null; - } - - protected GitBlit(final IUserService userService) { - this.goSettings = null; - this.userService = userService; - gitblit = this; + this.goBaseFolder = null; } public GitBlit(IStoredSettings settings, File baseFolder) { this.goSettings = settings; - this.baseFolder = baseFolder; + this.goBaseFolder = baseFolder; gitblit = this; } @@ -259,27 +229,13 @@ if (managerClass.isAssignableFrom(GitBlit.class)) { return (X) gitblit; } + + for (IManager manager : gitblit.managers) { + if (managerClass.isAssignableFrom(manager.getClass())) { + return (X) manager; + } + } return null; - } - - @Override - public File getBaseFolder() { - return baseFolder; - } - - @Override - public void setBaseFolder(File folder) { - this.baseFolder = folder; - } - - /** - * Returns the boot date of the Gitblit server. - * - * @return the boot date of Gitblit - */ - @Override - public Date getBootDate() { - return serverStatus.bootDate; } /** @@ -302,71 +258,6 @@ } /** - * Determine if this Gitblit instance is actively serving git repositories - * or if it is merely a repository viewer. - * - * @return true if Gitblit is serving repositories - */ - @Override - public boolean isServingRepositories() { - return settings.getBoolean(Keys.git.enableGitServlet, true) || (settings.getInteger(Keys.git.daemonPort, 0) > 0); - } - - /** - * Returns the preferred timezone for the Gitblit instance. - * - * @return a timezone - */ - @Override - public TimeZone getTimezone() { - if (timezone == null) { - String tzid = settings.getString("web.timezone", null); - if (StringUtils.isEmpty(tzid)) { - timezone = TimeZone.getDefault(); - return timezone; - } - timezone = TimeZone.getTimeZone(tzid); - } - return timezone; - } - - /** - * Is Gitblit running in debug mode? - * - * @return true if Gitblit is running in debug mode - */ - @Override - public boolean isDebugMode() { - return settings.getBoolean(Keys.web.debugMode, false); - } - - /** - * Returns the file object for the specified configuration key. - * - * @return the file - */ - @Override - public File getFileOrFolder(String key, String defaultFileOrFolder) { - String fileOrFolder = settings.getString(key, defaultFileOrFolder); - return getFileOrFolder(fileOrFolder); - } - - /** - * Returns the file object which may have it's base-path determined by - * environment variables for running on a cloud hosting service. All Gitblit - * file or folder retrievals are (at least initially) funneled through this - * method so it is the correct point to globally override/alter filesystem - * access based on environment or some other indicator. - * - * @return the file - */ - @Override - public File getFileOrFolder(String fileOrFolder) { - return com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, - baseFolder, fileOrFolder); - } - - /** * Returns the path of the repositories folder. This method checks to see if * Gitblit is running on a cloud service and may return an adjusted path. * @@ -374,7 +265,7 @@ */ @Override public File getRepositoriesFolder() { - return getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git"); + return getManager(IRuntimeManager.class).getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git"); } /** @@ -385,7 +276,7 @@ */ @Override public File getProposalsFolder() { - return getFileOrFolder(Keys.federation.proposalsFolder, "${baseFolder}/proposals"); + return getManager(IRuntimeManager.class).getFileOrFolder(Keys.federation.proposalsFolder, "${baseFolder}/proposals"); } /** @@ -396,7 +287,7 @@ */ @Override public File getHooksFolder() { - return getFileOrFolder(Keys.groovy.scriptsFolder, "${baseFolder}/groovy"); + return getManager(IRuntimeManager.class).getFileOrFolder(Keys.groovy.scriptsFolder, "${baseFolder}/groovy"); } /** @@ -407,36 +298,7 @@ */ @Override public File getGrapesFolder() { - return getFileOrFolder(Keys.groovy.grapeFolder, "${baseFolder}/groovy/grape"); - } - - /** - * Returns the runtime settings. - * - * @return runtime settings - */ - @Override - public IStoredSettings getSettings() { - return settings; - } - - /** - * Updates the runtime settings. - * - * @param settings - * @return true if the update succeeded - */ - @Override - public boolean updateSettings(Map<String, String> updatedSettings) { - return settings.saveSettings(updatedSettings); - } - - @Override - public ServerStatus getStatus() { - // update heap memory status - serverStatus.heapAllocated = Runtime.getRuntime().totalMemory(); - serverStatus.heapFree = Runtime.getRuntime().freeMemory(); - return serverStatus; + return getManager(IRuntimeManager.class).getFileOrFolder(Keys.groovy.grapeFolder, "${baseFolder}/groovy/grape"); } /** @@ -452,7 +314,7 @@ if (user == null) { user = UserModel.ANONYMOUS; } - String username = encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); + String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); List<RepositoryUrl> list = new ArrayList<RepositoryUrl>(); // http/https url @@ -548,7 +410,7 @@ @Override public Collection<GitClientApplication> getClientApplications() { // prefer user definitions, if they exist - File userDefs = new File(baseFolder, "clientapps.json"); + File userDefs = new File(getManager(IRuntimeManager.class).getBaseFolder(), "clientapps.json"); if (userDefs.exists()) { Date lastModified = new Date(userDefs.lastModified()); if (clientApplications.hasCurrent("user", lastModified)) { @@ -603,276 +465,6 @@ } /** - * Set the user service. The user service authenticates all users and is - * responsible for managing user permissions. - * - * @param userService - */ - public void setUserService(IUserService userService) { - logger.info("Setting up user service " + userService.toString()); - this.userService = userService; - this.userService.setup(settings); - } - - @Override - public boolean supportsAddUser() { - return supportsCredentialChanges(new UserModel("")); - } - - /** - * Returns true if the user's credentials can be changed. - * - * @param user - * @return true if the user service supports credential changes - */ - @Override - public boolean supportsCredentialChanges(UserModel user) { - if (user == null) { - return false; - } else if (AccountType.LOCAL.equals(user.accountType)) { - // local account, we can change credentials - return true; - } else { - // external account, ask user service - return userService.supportsCredentialChanges(); - } - } - - /** - * Returns true if the user's display name can be changed. - * - * @param user - * @return true if the user service supports display name changes - */ - @Override - public boolean supportsDisplayNameChanges(UserModel user) { - return (user != null && user.isLocalAccount()) || userService.supportsDisplayNameChanges(); - } - - /** - * Returns true if the user's email address can be changed. - * - * @param user - * @return true if the user service supports email address changes - */ - @Override - public boolean supportsEmailAddressChanges(UserModel user) { - return (user != null && user.isLocalAccount()) || userService.supportsEmailAddressChanges(); - } - - /** - * Returns true if the user's team memberships can be changed. - * - * @param user - * @return true if the user service supports team membership changes - */ - @Override - public boolean supportsTeamMembershipChanges(UserModel user) { - return (user != null && user.isLocalAccount()) || userService.supportsTeamMembershipChanges(); - } - - /** - * Returns true if the username represents an internal account - * - * @param username - * @return true if the specified username represents an internal account - */ - protected boolean isInternalAccount(String username) { - return !StringUtils.isEmpty(username) - && (username.equalsIgnoreCase(Constants.FEDERATION_USER) - || username.equalsIgnoreCase(UserModel.ANONYMOUS.username)); - } - - /** - * Authenticate a user based on a username and password. - * - * @see IUserService.authenticate(String, char[]) - * @param username - * @param password - * @return a user object or null - */ - @Override - public UserModel authenticate(String username, char[] password) { - if (StringUtils.isEmpty(username)) { - // can not authenticate empty username - return null; - } - String usernameDecoded = decodeUsername(username); - String pw = new String(password); - if (StringUtils.isEmpty(pw)) { - // can not authenticate empty password - return null; - } - - // check to see if this is the federation user - if (canFederate()) { - if (usernameDecoded.equalsIgnoreCase(Constants.FEDERATION_USER)) { - List<String> tokens = getFederationTokens(); - if (tokens.contains(pw)) { - return getFederationUser(); - } - } - } - - // delegate authentication to the user service - if (userService == null) { - return null; - } - return userService.authenticate(usernameDecoded, password); - } - - /** - * Authenticate a user based on their cookie. - * - * @param cookies - * @return a user object or null - */ - protected UserModel authenticate(Cookie[] cookies) { - if (userService == null) { - return null; - } - if (userService.supportsCookies()) { - if (cookies != null && cookies.length > 0) { - for (Cookie cookie : cookies) { - if (cookie.getName().equals(Constants.NAME)) { - String value = cookie.getValue(); - return userService.authenticate(value.toCharArray()); - } - } - } - } - return null; - } - - /** - * Authenticate a user based on HTTP request parameters. - * - * Authentication by X509Certificate is tried first and then by cookie. - * - * @param httpRequest - * @return a user object or null - */ - @Override - public UserModel authenticate(HttpServletRequest httpRequest) { - return authenticate(httpRequest, false); - } - - /** - * Authenticate a user based on HTTP request parameters. - * - * Authentication by X509Certificate, servlet container principal, cookie, - * and BASIC header. - * - * @param httpRequest - * @param requiresCertificate - * @return a user object or null - */ - @Override - public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) { - // try to authenticate by certificate - boolean checkValidity = settings.getBoolean(Keys.git.enforceCertificateValidity, true); - String [] oids = settings.getStrings(Keys.git.certificateUsernameOIDs).toArray(new String[0]); - UserModel model = HttpUtils.getUserModelFromCertificate(httpRequest, checkValidity, oids); - if (model != null) { - // grab real user model and preserve certificate serial number - UserModel user = getUserModel(model.username); - X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest); - if (user != null) { - flagWicketSession(AuthenticationType.CERTIFICATE); - logger.debug(MessageFormat.format("{0} authenticated by client certificate {1} from {2}", - user.username, metadata.serialNumber, httpRequest.getRemoteAddr())); - return user; - } else { - logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted client certificate ({1}) authentication from {2}", - model.username, metadata.serialNumber, httpRequest.getRemoteAddr())); - } - } - - if (requiresCertificate) { - // caller requires client certificate authentication (e.g. git servlet) - return null; - } - - // try to authenticate by servlet container principal - Principal principal = httpRequest.getUserPrincipal(); - if (principal != null) { - String username = principal.getName(); - if (!StringUtils.isEmpty(username)) { - boolean internalAccount = isInternalAccount(username); - UserModel user = getUserModel(username); - if (user != null) { - // existing user - flagWicketSession(AuthenticationType.CONTAINER); - logger.debug(MessageFormat.format("{0} authenticated by servlet container principal from {1}", - user.username, httpRequest.getRemoteAddr())); - return user; - } else if (settings.getBoolean(Keys.realm.container.autoCreateAccounts, false) - && !internalAccount) { - // auto-create user from an authenticated container principal - user = new UserModel(username.toLowerCase()); - user.displayName = username; - user.password = Constants.EXTERNAL_ACCOUNT; - userService.updateUserModel(user); - flagWicketSession(AuthenticationType.CONTAINER); - logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}", - user.username, httpRequest.getRemoteAddr())); - return user; - } else if (!internalAccount) { - logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted servlet container authentication from {1}", - principal.getName(), httpRequest.getRemoteAddr())); - } - } - } - - // try to authenticate by cookie - if (supportsCookies()) { - UserModel user = authenticate(httpRequest.getCookies()); - if (user != null) { - flagWicketSession(AuthenticationType.COOKIE); - logger.debug(MessageFormat.format("{0} authenticated by cookie from {1}", - user.username, httpRequest.getRemoteAddr())); - return user; - } - } - - // try to authenticate by BASIC - final String authorization = httpRequest.getHeader("Authorization"); - if (authorization != null && authorization.startsWith("Basic")) { - // Authorization: Basic base64credentials - String base64Credentials = authorization.substring("Basic".length()).trim(); - String credentials = new String(Base64.decode(base64Credentials), - Charset.forName("UTF-8")); - // credentials = username:password - final String[] values = credentials.split(":",2); - - if (values.length == 2) { - String username = values[0]; - char[] password = values[1].toCharArray(); - UserModel user = authenticate(username, password); - if (user != null) { - flagWicketSession(AuthenticationType.CREDENTIALS); - logger.debug(MessageFormat.format("{0} authenticated by BASIC request header from {1}", - user.username, httpRequest.getRemoteAddr())); - return user; - } else { - logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}", - username, httpRequest.getRemoteAddr())); - } - } - } - return null; - } - - protected void flagWicketSession(AuthenticationType authenticationType) { - RequestCycle requestCycle = RequestCycle.get(); - if (requestCycle != null) { - // flag the Wicket session, if this is a Wicket request - GitBlitWebSession session = GitBlitWebSession.get(); - session.authenticationType = authenticationType; - } - } - - /** * Open a file resource using the Servlet container. * @param file to open * @return InputStream of the opened file @@ -883,138 +475,12 @@ return res.getResourceStream().getInputStream(); } - /** - * Sets a cookie for the specified user. - * - * @param response - * @param user - */ - @Override - public void setCookie(HttpServletResponse response, UserModel user) { - if (userService == null) { - return; - } - GitBlitWebSession session = GitBlitWebSession.get(); - boolean standardLogin = session.authenticationType.isStandard(); - - if (userService.supportsCookies() && standardLogin) { - Cookie userCookie; - if (user == null) { - // clear cookie for logout - userCookie = new Cookie(Constants.NAME, ""); - } else { - // set cookie for login - String cookie = userService.getCookie(user); - if (StringUtils.isEmpty(cookie)) { - // create empty cookie - userCookie = new Cookie(Constants.NAME, ""); - } else { - // create real cookie - userCookie = new Cookie(Constants.NAME, cookie); - userCookie.setMaxAge(Integer.MAX_VALUE); - } - } - userCookie.setPath("/"); - response.addCookie(userCookie); - } - } - - /** - * Logout a user. - * - * @param user - */ - @Override - public void logout(UserModel user) { - if (userService == null) { - return; - } - userService.logout(user); - } - - /** - * Encode the username for user in an url. - * - * @param name - * @return the encoded name - */ - protected String encodeUsername(String name) { - return name.replace("@", "%40").replace(" ", "%20").replace("\\", "%5C"); - } - - /** - * Decode a username from an encoded url. - * - * @param name - * @return the decoded name - */ - protected String decodeUsername(String name) { - return name.replace("%40", "@").replace("%20", " ").replace("%5C", "\\"); - } - - /** - * Returns the list of all users available to the login service. - * - * @see IUserService.getAllUsernames() - * @return list of all usernames - */ - @Override - public List<String> getAllUsernames() { - List<String> names = new ArrayList<String>(userService.getAllUsernames()); - return names; - } - - /** - * Returns the list of all users available to the login service. - * - * @see IUserService.getAllUsernames() - * @return list of all usernames - */ - @Override - public List<UserModel> getAllUsers() { - List<UserModel> users = userService.getAllUsers(); - return users; - } - - /** - * Delete the user object with the specified username - * - * @see IUserService.deleteUser(String) - * @param username - * @return true if successful - */ - @Override - public boolean deleteUser(String username) { - if (StringUtils.isEmpty(username)) { - return false; - } - String usernameDecoded = decodeUsername(username); - return userService.deleteUser(usernameDecoded); - } - @Override public UserModel getFederationUser() { // the federation user is an administrator UserModel federationUser = new UserModel(Constants.FEDERATION_USER); federationUser.canAdmin = true; return federationUser; - } - - /** - * Retrieve the user object for the specified username. - * - * @see IUserService.getUserModel(String) - * @param username - * @return a user object or null - */ - @Override - public UserModel getUserModel(String username) { - if (StringUtils.isEmpty(username)) { - return null; - } - String usernameDecoded = decodeUsername(username); - UserModel user = userService.getUserModel(usernameDecoded); - return user; } /** @@ -1082,7 +548,7 @@ return list; } // NAMED users and teams - for (UserModel user : userService.getAllUsers()) { + for (UserModel user : getManager(IUserManager.class).getAllUsers()) { RegistrantAccessPermission ap = user.getRepositoryPermission(repository); if (ap.permission.exceeds(AccessPermission.NONE)) { list.add(ap); @@ -1104,12 +570,12 @@ for (RegistrantAccessPermission up : permissions) { if (up.mutable) { // only set editable defined permissions - UserModel user = userService.getUserModel(up.registrant); + UserModel user = getManager(IUserManager.class).getUserModel(up.registrant); user.setRepositoryPermission(repository.name, up.permission); users.add(user); } } - return userService.updateUserModels(users); + return getManager(IUserManager.class).updateUserModels(users); } /** @@ -1122,7 +588,7 @@ */ @Override public List<String> getRepositoryUsers(RepositoryModel repository) { - return userService.getUsernamesForRepositoryRole(repository.name); + return getManager(IUserManager.class).getUsernamesForRepositoryRole(repository.name); } /** @@ -1155,7 +621,7 @@ public void updateUserModel(String username, UserModel user, boolean isCreate) throws GitBlitException { if (!username.equalsIgnoreCase(user.username)) { - if (userService.getUserModel(user.username) != null) { + if (getManager(IUserManager.class).getUserModel(user.username) != null) { throw new GitBlitException(MessageFormat.format( "Failed to rename ''{0}'' because ''{1}'' already exists.", username, user.username)); @@ -1177,43 +643,9 @@ } } } - if (!userService.updateUserModel(username, user)) { + if (!getManager(IUserManager.class).updateUserModel(username, user)) { throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!"); } - } - - /** - * Returns the list of available teams that a user or repository may be - * assigned to. - * - * @return the list of teams - */ - public List<String> getAllTeamnames() { - List<String> teams = new ArrayList<String>(userService.getAllTeamNames()); - return teams; - } - - /** - * Returns the list of available teams that a user or repository may be - * assigned to. - * - * @return the list of teams - */ - @Override - public List<TeamModel> getAllTeams() { - List<TeamModel> teams = userService.getAllTeams(); - return teams; - } - - /** - * Returns the TeamModel object for the specified name. - * - * @param teamname - * @return a TeamModel object or null - */ - @Override - public TeamModel getTeamModel(String teamname) { - return userService.getTeamModel(teamname); } /** @@ -1227,7 +659,7 @@ @Override public List<RegistrantAccessPermission> getTeamAccessPermissions(RepositoryModel repository) { List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>(); - for (TeamModel team : userService.getAllTeams()) { + for (TeamModel team : getManager(IUserManager.class).getAllTeams()) { RegistrantAccessPermission ap = team.getRepositoryPermission(repository); if (ap.permission.exceeds(AccessPermission.NONE)) { list.add(ap); @@ -1250,12 +682,12 @@ for (RegistrantAccessPermission tp : permissions) { if (tp.mutable) { // only set explicitly defined access permissions - TeamModel team = userService.getTeamModel(tp.registrant); + TeamModel team = getManager(IUserManager.class).getTeamModel(tp.registrant); team.setRepositoryPermission(repository.name, tp.permission); teams.add(team); } } - return userService.updateTeamModels(teams); + return getManager(IUserManager.class).updateTeamModels(teams); } /** @@ -1268,7 +700,7 @@ */ @Override public List<String> getRepositoryTeams(RepositoryModel repository) { - return userService.getTeamnamesForRepositoryRole(repository.name); + return getManager(IUserManager.class).getTeamNamesForRepositoryRole(repository.name); } /** @@ -1298,27 +730,15 @@ public void updateTeamModel(String teamname, TeamModel team, boolean isCreate) throws GitBlitException { if (!teamname.equalsIgnoreCase(team.name)) { - if (userService.getTeamModel(team.name) != null) { + if (getManager(IUserManager.class).getTeamModel(team.name) != null) { throw new GitBlitException(MessageFormat.format( "Failed to rename ''{0}'' because ''{1}'' already exists.", teamname, team.name)); } } - if (!userService.updateTeamModel(teamname, team)) { + if (!getManager(IUserManager.class).updateTeamModel(teamname, team)) { throw new GitBlitException(isCreate ? "Failed to add team!" : "Failed to update team!"); } - } - - /** - * Delete the team object with the specified teamname - * - * @see IUserService.deleteTeam(String) - * @param teamname - * @return true if successful - */ - @Override - public boolean deleteTeam(String teamname) { - return userService.deleteTeam(teamname); } /** @@ -1636,7 +1056,7 @@ @Override public long getStarCount(RepositoryModel repository) { long count = 0; - for (UserModel user : getAllUsers()) { + for (UserModel user : getManager(IUserManager.class).getAllUsers()) { if (user.getPreferences().isStarredRepository(repository.name)) { count++; } @@ -1797,7 +1217,7 @@ if (project == null) { project = new ProjectModel(name); if (ModelUtils.isPersonalRepository(name)) { - UserModel user = getUserModel(ModelUtils.getUserNameFromRepoPath(name)); + UserModel user = getManager(IUserManager.class).getUserModel(ModelUtils.getUserNameFromRepoPath(name)); if (user != null) { project.title = user.getDisplayName(); project.description = "personal repositories"; @@ -1912,7 +1332,7 @@ } RepositoryModel model = new RepositoryModel(); model.isBare = r.isBare(); - File basePath = getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git"); + File basePath = getRepositoriesFolder(); if (model.isBare) { model.name = com.gitblit.utils.FileUtils.getRelativePath(basePath, r.getDirectory()); } else { @@ -2283,7 +1703,7 @@ if (repositoryMetricsCache.hasCurrent(model.name, model.lastChange)) { return new ArrayList<Metric>(repositoryMetricsCache.getObject(model.name)); } - List<Metric> metrics = MetricUtils.getDateMetrics(repository, null, true, null, getTimezone()); + List<Metric> metrics = MetricUtils.getDateMetrics(repository, null, true, null, getManager(IRuntimeManager.class).getTimezone()); repositoryMetricsCache.updateObject(model.name, model.lastChange, metrics); return new ArrayList<Metric>(metrics); } @@ -2414,7 +1834,7 @@ repository.name)); } // rename the roles - if (!userService.renameRepositoryRole(repositoryName, repository.name)) { + if (!getManager(IUserManager.class).renameRepositoryRole(repositoryName, repository.name)) { throw new GitBlitException(MessageFormat.format( "Failed to rename repository permissions ''{0}'' to ''{1}''.", repositoryName, repository.name)); @@ -2631,7 +2051,7 @@ File folder = new File(repositoriesFolder, repositoryName); if (folder.exists() && folder.isDirectory()) { FileUtils.delete(folder, FileUtils.RECURSIVE | FileUtils.RETRY); - if (userService.deleteRepositoryRole(repositoryName)) { + if (getManager(IUserManager.class).deleteRepositoryRole(repositoryName)) { logger.info(MessageFormat.format("Repository \"{0}\" deleted", repositoryName)); return true; } @@ -2970,7 +2390,7 @@ } // send an email, if possible - sendMailToAdministrators("Federation proposal from " + proposal.url, + getManager(INotificationManager.class).sendMailToAdministrators("Federation proposal from " + proposal.url, "Please review the proposal @ " + gitblitUrl + "/proposal/" + proposal.token); return true; } @@ -3163,8 +2583,8 @@ // Team Scripts if (repository != null) { - for (String teamname : userService.getTeamnamesForRepositoryRole(repository.name)) { - TeamModel team = userService.getTeamModel(teamname); + 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); } @@ -3217,8 +2637,8 @@ } // Team Scripts if (repository != null) { - for (String teamname : userService.getTeamnamesForRepositoryRole(repository.name)) { - TeamModel team = userService.getTeamModel(teamname); + 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); } @@ -3266,144 +2686,21 @@ } /** - * Notify the administrators by email. - * - * @param subject - * @param message - */ - @Override - public void sendMailToAdministrators(String subject, String message) { - List<String> toAddresses = settings.getStrings(Keys.mail.adminAddresses); - sendMail(subject, message, toAddresses); - } - - /** - * Notify users by email of something. - * - * @param subject - * @param message - * @param toAddresses - */ - @Override - public void sendMail(String subject, String message, Collection<String> toAddresses) { - this.sendMail(subject, message, toAddresses.toArray(new String[0])); - } - - /** - * Notify users by email of something. - * - * @param subject - * @param message - * @param toAddresses - */ - @Override - public void sendMail(String subject, String message, String... toAddresses) { - if (toAddresses == null || toAddresses.length == 0) { - logger.debug(MessageFormat.format("Dropping message {0} because there are no recipients", subject)); - return; - } - try { - Message mail = mailExecutor.createMessage(toAddresses); - if (mail != null) { - mail.setSubject(subject); - - MimeBodyPart messagePart = new MimeBodyPart(); - messagePart.setText(message, "utf-8"); - messagePart.setHeader("Content-Type", "text/plain; charset=\"utf-8\""); - messagePart.setHeader("Content-Transfer-Encoding", "quoted-printable"); - - MimeMultipart multiPart = new MimeMultipart(); - multiPart.addBodyPart(messagePart); - mail.setContent(multiPart); - - mailExecutor.queue(mail); - } - } catch (MessagingException e) { - logger.error("Messaging error", e); - } - } - - /** - * Notify users by email of something. - * - * @param subject - * @param message - * @param toAddresses - */ - @Override - public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) { - this.sendHtmlMail(subject, message, toAddresses.toArray(new String[0])); - } - - /** - * Notify users by email of something. - * - * @param subject - * @param message - * @param toAddresses - */ - @Override - public void sendHtmlMail(String subject, String message, String... toAddresses) { - if (toAddresses == null || toAddresses.length == 0) { - logger.debug(MessageFormat.format("Dropping message {0} because there are no recipients", subject)); - return; - } - try { - Message mail = mailExecutor.createMessage(toAddresses); - if (mail != null) { - mail.setSubject(subject); - - MimeBodyPart messagePart = new MimeBodyPart(); - messagePart.setText(message, "utf-8"); - messagePart.setHeader("Content-Type", "text/html; charset=\"utf-8\""); - messagePart.setHeader("Content-Transfer-Encoding", "quoted-printable"); - - MimeMultipart multiPart = new MimeMultipart(); - multiPart.addBodyPart(messagePart); - mail.setContent(multiPart); - - mailExecutor.queue(mail); - } - } catch (MessagingException e) { - logger.error("Messaging error", e); - } - } - - /** - * Returns the descriptions/comments of the Gitblit config settings. - * - * @return SettingsModel - */ - @Override - public ServerSettings getSettingsModel() { - // ensure that the current values are updated in the setting models - for (String key : settings.getAllKeys(null)) { - SettingModel setting = settingsModel.get(key); - if (setting == null) { - // unreferenced setting, create a setting model - setting = new SettingModel(); - setting.name = key; - settingsModel.add(setting); - } - setting.currentValue = settings.getString(key, ""); - } - settingsModel.pushScripts = getAllScripts(); - return settingsModel; - } - - /** * Parse the properties file and aggregate all the comments by the setting * key. A setting model tracks the current value, the default value, the * description of the setting and and directives about the setting. * * @return Map<String, SettingModel> */ - private ServerSettings loadSettingModels() { - ServerSettings settingsModel = new ServerSettings(); - settingsModel.supportsCredentialChanges = userService.supportsCredentialChanges(); - settingsModel.supportsDisplayNameChanges = userService.supportsDisplayNameChanges(); - settingsModel.supportsEmailAddressChanges = userService.supportsEmailAddressChanges(); - settingsModel.supportsTeamMembershipChanges = userService.supportsTeamMembershipChanges(); + private ServerSettings loadSettingModels(ServerSettings settingsModel) { + // this entire "supports" concept will go away with user service refactoring + UserModel externalUser = new UserModel(Constants.EXTERNAL_ACCOUNT); + externalUser.password = Constants.EXTERNAL_ACCOUNT; + IUserManager userManager = getManager(IUserManager.class); + settingsModel.supportsCredentialChanges = userManager.supportsCredentialChanges(externalUser); + settingsModel.supportsDisplayNameChanges = userManager.supportsDisplayNameChanges(externalUser); + settingsModel.supportsEmailAddressChanges = userManager.supportsEmailAddressChanges(externalUser); + settingsModel.supportsTeamMembershipChanges = userManager.supportsTeamMembershipChanges(externalUser); try { // Read bundled Gitblit properties to extract setting descriptions. // This copy is pristine and only used for populating the setting @@ -3458,86 +2755,6 @@ logger.error("Failed to load resource copy of gitblit.properties"); } return settingsModel; - } - - /** - * Configure the Gitblit singleton with the specified settings source. This - * source may be file settings (Gitblit GO) or may be web.xml settings - * (Gitblit WAR). - * - * @param settings - */ - public void configureContext(IStoredSettings settings, File folder, boolean startFederation) { - this.settings = settings; - this.baseFolder = folder; - - repositoriesFolder = getRepositoriesFolder(); - - logger.info("Gitblit base folder = " + folder.getAbsolutePath()); - logger.info("Git repositories folder = " + repositoriesFolder.getAbsolutePath()); - logger.info("Gitblit settings = " + settings.toString()); - - // prepare service executors - mailExecutor = new MailExecutor(settings); - luceneExecutor = new LuceneExecutor(settings, getManager(IRepositoryManager.class)); - gcExecutor = new GCExecutor(settings, getManager(IRepositoryManager.class)); - mirrorExecutor = new MirrorExecutor(settings, getManager(IRepositoryManager.class)); - - // initialize utilities - String prefix = settings.getString(Keys.git.userRepositoryPrefix, "~"); - ModelUtils.setUserRepoPrefix(prefix); - - // calculate repository list settings checksum for future config changes - repositoryListSettingsChecksum.set(getRepositoryListSettingsChecksum()); - - // build initial repository list - if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) { - logger.info("Identifying available repositories..."); - getRepositoryList(); - } - - logTimezone("JVM", TimeZone.getDefault()); - logTimezone(Constants.NAME, getTimezone()); - - serverStatus = new ServerStatus(goSettings != null); - - if (this.userService == null) { - String realm = settings.getString(Keys.realm.userService, "${baseFolder}/users.properties"); - IUserService loginService = null; - try { - // check to see if this "file" is a login service class - Class<?> realmClass = Class.forName(realm); - loginService = (IUserService) realmClass.newInstance(); - } catch (Throwable t) { - loginService = new GitblitUserService(); - } - setUserService(loginService); - } - - // load and cache the project metadata - projectConfigs = new FileBasedConfig(getFileOrFolder(Keys.web.projectsFile, "${baseFolder}/projects.conf"), FS.detect()); - getProjectConfigs(); - - configureMailExecutor(); - configureLuceneIndexing(); - configureGarbageCollector(); - configureMirrorExecutor(); - if (startFederation) { - configureFederation(); - } - configureJGit(); - configureFanout(); - configureGitDaemon(); - configureCommitCache(); - } - - protected void configureMailExecutor() { - if (mailExecutor.isReady()) { - logger.info("Mail executor is scheduled to process the message queue every 2 minutes."); - scheduledExecutor.scheduleAtFixedRate(mailExecutor, 1, 2, TimeUnit.MINUTES); - } else { - logger.warn("Mail server is not properly configured. Mail services disabled."); - } } protected void configureLuceneIndexing() { @@ -3641,7 +2858,17 @@ String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost"); if (port > 0) { try { - gitDaemon = new GitDaemon(this, this, this, this); + // HACK temporary pending manager separation and injection + Gitblit gitblit = new Gitblit( + getManager(IRuntimeManager.class), + getManager(INotificationManager.class), + getManager(IUserManager.class), + getManager(ISessionManager.class), + this, + this, + this, + this); + gitDaemon = new GitDaemon(gitblit); gitDaemon.start(); } catch (IOException e) { gitDaemon = null; @@ -3698,13 +2925,6 @@ return luceneExecutor; } - private void logTimezone(String type, TimeZone zone) { - SimpleDateFormat df = new SimpleDateFormat("z Z"); - df.setTimeZone(zone); - String offset = df.format(new Date()); - logger.info(type + " timezone is " + zone.getID() + " (" + offset + ")"); - } - /** * Configure Gitblit from the web.xml, if no configuration has already been * specified. @@ -3713,93 +2933,226 @@ */ @Override protected void beforeServletInjection(ServletContext context) { - if (settings == null) { - // Gitblit is running in a servlet container + ObjectGraph injector = getInjector(context); + + // create the runtime settings object + IStoredSettings runtimeSettings = injector.get(IStoredSettings.class); + this.settings = runtimeSettings; // XXX remove me eventually + final File baseFolder; + + if (goSettings != null) { + // Gitblit GO + logger.debug("configuring Gitblit GO"); + baseFolder = configureGO(context, goSettings, goBaseFolder, runtimeSettings); + } else { + // servlet container WebXmlSettings webxmlSettings = new WebXmlSettings(context); String contextRealPath = context.getRealPath("/"); File contextFolder = (contextRealPath != null) ? new File(contextRealPath) : null; - String openShift = System.getenv("OPENSHIFT_DATA_DIR"); - if (!StringUtils.isEmpty(openShift)) { - // Gitblit is running in OpenShift/JBoss - File base = new File(openShift); - logger.info("EXPRESS contextFolder is " + contextFolder.getAbsolutePath()); - - // gitblit.properties setting overrides - File overrideFile = new File(base, "gitblit.properties"); - webxmlSettings.applyOverrides(overrideFile); - - // Copy the included scripts to the configured groovy folder - String path = webxmlSettings.getString(Keys.groovy.scriptsFolder, "groovy"); - File localScripts = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, base, path); - if (!localScripts.exists()) { - File warScripts = new File(contextFolder, "/WEB-INF/data/groovy"); - if (!warScripts.equals(localScripts)) { - try { - com.gitblit.utils.FileUtils.copy(localScripts, warScripts.listFiles()); - } catch (IOException e) { - logger.error(MessageFormat.format( - "Failed to copy included Groovy scripts from {0} to {1}", - warScripts, localScripts)); - } - } - } - - // disable Git daemon on Express - we can't bind 9418 and we - // can't port-forward to the daemon - webxmlSettings.overrideSetting(Keys.git.daemonPort, 0); - - // configure context using the web.xml - configureContext(webxmlSettings, base, true); + if (!StringUtils.isEmpty(System.getenv("OPENSHIFT_DATA_DIR"))) { + // RedHat OpenShift + logger.debug("configuring Gitblit Express"); + baseFolder = configureExpress(context, webxmlSettings, contextFolder, runtimeSettings); } else { - // Gitblit is running in a standard servlet container - logger.info("WAR contextFolder is " + ((contextFolder != null) ? contextFolder.getAbsolutePath() : "<empty>")); - - String path = webxmlSettings.getString(Constants.baseFolder, Constants.contextFolder$ + "/WEB-INF/data"); - - if (path.contains(Constants.contextFolder$) && contextFolder == null) { - // warn about null contextFolder (issue-199) - logger.error(""); - logger.error(MessageFormat.format("\"{0}\" depends on \"{1}\" but \"{2}\" is returning NULL for \"{1}\"!", - Constants.baseFolder, Constants.contextFolder$, context.getServerInfo())); - logger.error(MessageFormat.format("Please specify a non-parameterized path for <context-param> {0} in web.xml!!", Constants.baseFolder)); - logger.error(MessageFormat.format("OR configure your servlet container to specify a \"{0}\" parameter in the context configuration!!", Constants.baseFolder)); - logger.error(""); - } - - try { - // try to lookup JNDI env-entry for the baseFolder - InitialContext ic = new InitialContext(); - Context env = (Context) ic.lookup("java:comp/env"); - String val = (String) env.lookup("baseFolder"); - if (!StringUtils.isEmpty(val)) { - path = val; - } - } catch (NamingException n) { - logger.error("Failed to get JNDI env-entry: " + n.getExplanation()); - } - - File base = com.gitblit.utils.FileUtils.resolveParameter(Constants.contextFolder$, contextFolder, path); - base.mkdirs(); - - // try to extract the data folder resource to the baseFolder - File localSettings = new File(base, "gitblit.properties"); - if (!localSettings.exists()) { - extractResources(context, "/WEB-INF/data/", base); - } - - // delegate all config to baseFolder/gitblit.properties file - FileSettings settings = new FileSettings(localSettings.getAbsolutePath()); - configureContext(settings, base, true); + // standard WAR + logger.debug("configuring Gitblit WAR"); + baseFolder = configureWAR(context, webxmlSettings, contextFolder, runtimeSettings); } - // WAR or Express is likely to be running on a Tomcat. - // Test for the forward-slash/%2F issue and auto-adjust settings. - ContainerUtils.CVE_2007_0450.test(settings); + // Test for Tomcat forward-slash/%2F issue and auto-adjust settings + ContainerUtils.CVE_2007_0450.test(runtimeSettings); } - settingsModel = loadSettingModels(); - serverStatus.servletContainer = context.getServerInfo(); + // Runtime manager is a container for settings and other parameters + IRuntimeManager runtime = startManager(injector, IRuntimeManager.class); + runtime.setBaseFolder(baseFolder); + runtime.getStatus().isGO = goSettings != null; + runtime.getStatus().servletContainer = context.getServerInfo(); + + startManager(injector, INotificationManager.class); + startManager(injector, IUserManager.class); + startManager(injector, ISessionManager.class); + + repositoriesFolder = getRepositoriesFolder(); + + 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()); + + // load and cache the project metadata + 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(); + } + + /** + * Configures Gitblit GO + * + * @param context + * @param settings + * @param baseFolder + * @param runtimeSettings + * @return the base folder + */ + protected File configureGO( + ServletContext context, + IStoredSettings goSettings, + File goBaseFolder, + IStoredSettings runtimeSettings) { + + // merge the stored settings into the runtime settings + // + // if runtimeSettings is also a FileSettings w/o a specified target file, + // the target file for runtimeSettings is set to "localSettings". + runtimeSettings.merge(goSettings); + File base = goBaseFolder; + return base; + } + + + /** + * Configures a standard WAR instance of Gitblit. + * + * @param context + * @param webxmlSettings + * @param contextFolder + * @param runtimeSettings + * @return the base folder + */ + protected File configureWAR( + ServletContext context, + WebXmlSettings webxmlSettings, + File contextFolder, + IStoredSettings runtimeSettings) { + + // Gitblit is running in a standard servlet container + logger.info("WAR contextFolder is " + ((contextFolder != null) ? contextFolder.getAbsolutePath() : "<empty>")); + + String path = webxmlSettings.getString(Constants.baseFolder, Constants.contextFolder$ + "/WEB-INF/data"); + + if (path.contains(Constants.contextFolder$) && contextFolder == null) { + // warn about null contextFolder (issue-199) + logger.error(""); + logger.error(MessageFormat.format("\"{0}\" depends on \"{1}\" but \"{2}\" is returning NULL for \"{1}\"!", + Constants.baseFolder, Constants.contextFolder$, context.getServerInfo())); + logger.error(MessageFormat.format("Please specify a non-parameterized path for <context-param> {0} in web.xml!!", Constants.baseFolder)); + logger.error(MessageFormat.format("OR configure your servlet container to specify a \"{0}\" parameter in the context configuration!!", Constants.baseFolder)); + logger.error(""); + } + + try { + // try to lookup JNDI env-entry for the baseFolder + InitialContext ic = new InitialContext(); + Context env = (Context) ic.lookup("java:comp/env"); + String val = (String) env.lookup("baseFolder"); + if (!StringUtils.isEmpty(val)) { + path = val; + } + } catch (NamingException n) { + logger.error("Failed to get JNDI env-entry: " + n.getExplanation()); + } + + File base = com.gitblit.utils.FileUtils.resolveParameter(Constants.contextFolder$, contextFolder, path); + base.mkdirs(); + + // try to extract the data folder resource to the baseFolder + File localSettings = new File(base, "gitblit.properties"); + if (!localSettings.exists()) { + extractResources(context, "/WEB-INF/data/", base); + } + + // delegate all config to baseFolder/gitblit.properties file + FileSettings fileSettings = new FileSettings(localSettings.getAbsolutePath()); + + // merge the stored settings into the runtime settings + // + // if runtimeSettings is also a FileSettings w/o a specified target file, + // the target file for runtimeSettings is set to "localSettings". + runtimeSettings.merge(fileSettings); + + return base; + } + + /** + * Configures an OpenShift instance of Gitblit. + * + * @param context + * @param webxmlSettings + * @param contextFolder + * @param runtimeSettings + * @return the base folder + */ + private File configureExpress( + ServletContext context, + WebXmlSettings webxmlSettings, + File contextFolder, + IStoredSettings runtimeSettings) { + + // Gitblit is running in OpenShift/JBoss + String openShift = System.getenv("OPENSHIFT_DATA_DIR"); + File base = new File(openShift); + logger.info("EXPRESS contextFolder is " + contextFolder.getAbsolutePath()); + + // Copy the included scripts to the configured groovy folder + String path = webxmlSettings.getString(Keys.groovy.scriptsFolder, "groovy"); + File localScripts = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, base, path); + if (!localScripts.exists()) { + File warScripts = new File(contextFolder, "/WEB-INF/data/groovy"); + if (!warScripts.equals(localScripts)) { + try { + com.gitblit.utils.FileUtils.copy(localScripts, warScripts.listFiles()); + } catch (IOException e) { + logger.error(MessageFormat.format( + "Failed to copy included Groovy scripts from {0} to {1}", + warScripts, localScripts)); + } + } + } + + // merge the WebXmlSettings into the runtime settings (for backwards-compatibilty) + runtimeSettings.merge(webxmlSettings); + + // settings are to be stored in openshift/gitblit.properties + File localSettings = new File(base, "gitblit.properties"); + FileSettings fileSettings = new FileSettings(localSettings.getAbsolutePath()); + + // merge the stored settings into the runtime settings + // + // if runtimeSettings is also a FileSettings w/o a specified target file, + // the target file for runtimeSettings is set to "localSettings". + runtimeSettings.merge(fileSettings); + + return base; } protected void extractResources(ServletContext context, String path, File toDir) { @@ -3856,6 +3209,11 @@ @Override protected void destroyContext(ServletContext context) { logger.info("Gitblit context destroyed by servlet container."); + for (IManager manager : managers) { + logger.debug("stopping {}", manager.getClass().getSimpleName()); + manager.stop(); + } + scheduledExecutor.shutdownNow(); luceneExecutor.close(); gcExecutor.close(); @@ -3919,7 +3277,7 @@ // 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 = getUserModel(owner); + UserModel originOwner = getManager(IUserManager.class).getUserModel(owner); if (originOwner != null) { originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE); updateUserModel(originOwner.username, originOwner, false); @@ -3932,7 +3290,7 @@ List<UserModel> cloneUsers = new ArrayList<UserModel>(); for (String name : users) { if (!name.equalsIgnoreCase(user.username)) { - UserModel cloneUser = getUserModel(name); + UserModel cloneUser = getManager(IUserManager.class).getUserModel(name); if (cloneUser.canClone(repository)) { // origin user can clone origin, grant clone access to fork cloneUser.setRepositoryPermission(cloneName, AccessPermission.CLONE); @@ -3940,123 +3298,39 @@ cloneUsers.add(cloneUser); } } - userService.updateUserModels(cloneUsers); + getManager(IUserManager.class).updateUserModels(cloneUsers); // grant origin's team list clone permission to fork List<String> teams = getRepositoryTeams(repository); List<TeamModel> cloneTeams = new ArrayList<TeamModel>(); for (String name : teams) { - TeamModel cloneTeam = getTeamModel(name); + TeamModel cloneTeam = getManager(IUserManager.class).getTeamModel(name); if (cloneTeam.canClone(repository)) { // origin team can clone origin, grant clone access to fork cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE); } cloneTeams.add(cloneTeam); } - userService.updateTeamModels(cloneTeams); + getManager(IUserManager.class).updateTeamModels(cloneTeams); // add this clone to the cached model addToCachedRepositoryList(cloneModel); return cloneModel; } - /** - * Allow to understand if GitBlit supports and is configured to allow - * cookie-based authentication. - * - * @return status of Cookie authentication enablement. - */ - @Override - public boolean supportsCookies() { - return settings.getBoolean(Keys.web.allowCookieAuthentication, true) && userService.supportsCookies(); - } - - @Override - public String getCookie(UserModel model) { - return userService.getCookie(model); - } - - @Override - public UserModel authenticate(char[] cookie) { - return userService.authenticate(cookie); - } - - @Override - public boolean updateUserModel(UserModel model) { - return userService.updateUserModel(model); - } - - @Override - public boolean updateUserModels(Collection<UserModel> models) { - return userService.updateUserModels(models); - } - - @Override - public boolean updateUserModel(String username, UserModel model) { - return userService.updateUserModel(username, model); - } - - @Override - public boolean deleteUserModel(UserModel model) { - return userService.deleteUserModel(model); - } - - @Override - public List<String> getAllTeamNames() { - return userService.getAllTeamNames(); - } - - @Override - public List<String> getTeamnamesForRepositoryRole(String role) { - return userService.getTeamnamesForRepositoryRole(role); - } - - @Override - public boolean updateTeamModel(TeamModel model) { - return userService.updateTeamModel(model); - } - - @Override - public boolean updateTeamModels(Collection<TeamModel> models) { - return userService.updateTeamModels(models); - } - - @Override - public boolean updateTeamModel(String teamname, TeamModel model) { - return userService.updateTeamModel(teamname, model); - } - - @Override - public boolean deleteTeamModel(TeamModel model) { - return userService.deleteTeamModel(model); - } - - @Override - public List<String> getUsernamesForRepositoryRole(String role) { - return userService.getUsernamesForRepositoryRole(role); - } - - @Override - public boolean renameRepositoryRole(String oldRole, String newRole) { - return userService.renameRepositoryRole(oldRole, newRole); - } - - @Override - public boolean deleteRepositoryRole(String role) { - return userService.deleteRepositoryRole(role); - } - - @Override - public void logout(HttpServletResponse response, UserModel user) { - setCookie(response, null); - userService.logout(user); - } - @Override protected Object [] getModules() { return new Object [] { new DaggerModule(this) }; } + protected <X extends IManager> X startManager(ObjectGraph injector, Class<X> clazz) { + logger.debug("injecting and starting {}", clazz.getSimpleName()); + X x = injector.get(clazz); + x.setup(); + managers.add(x); + return x; + } + /** * Instantiate and inject all filters and servlets into the container using * the servlet 3 specification. -- Gitblit v1.9.1