diff options
Diffstat (limited to 'src/main/java/com/gitblit/GitBlit.java')
-rw-r--r-- | src/main/java/com/gitblit/GitBlit.java | 1106 |
1 files changed, 99 insertions, 1007 deletions
diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java index 493f8fce..ca676ff9 100644 --- a/src/main/java/com/gitblit/GitBlit.java +++ b/src/main/java/com/gitblit/GitBlit.java @@ -15,50 +15,25 @@ */ package com.gitblit; -import java.io.BufferedReader; import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; -import java.lang.reflect.Type; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; 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.HttpServletRequest; -import org.apache.wicket.resource.ContextRelativeResource; -import org.apache.wicket.util.resource.ResourceStreamNotFoundException; -import org.slf4j.Logger; - -import com.gitblit.Constants.AccessPermission; -import com.gitblit.Constants.AccessRestrictionType; -import com.gitblit.Constants.FederationRequest; -import com.gitblit.Constants.FederationToken; import com.gitblit.dagger.DaggerContextListener; -import com.gitblit.fanout.FanoutNioService; -import com.gitblit.fanout.FanoutService; -import com.gitblit.fanout.FanoutSocketService; -import com.gitblit.git.GitDaemon; import com.gitblit.git.GitServlet; import com.gitblit.manager.IFederationManager; import com.gitblit.manager.IGitblitManager; @@ -67,80 +42,54 @@ import com.gitblit.manager.INotificationManager; import com.gitblit.manager.IProjectManager; import com.gitblit.manager.IRepositoryManager; import com.gitblit.manager.IRuntimeManager; +import com.gitblit.manager.IServicesManager; import com.gitblit.manager.ISessionManager; import com.gitblit.manager.IUserManager; -import com.gitblit.models.FederationModel; -import com.gitblit.models.FederationProposal; -import com.gitblit.models.FederationSet; -import com.gitblit.models.GitClientApplication; -import com.gitblit.models.RepositoryModel; -import com.gitblit.models.RepositoryUrl; -import com.gitblit.models.ServerSettings; -import com.gitblit.models.SettingModel; -import com.gitblit.models.TeamModel; -import com.gitblit.models.UserModel; -import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.ContainerUtils; -import com.gitblit.utils.FederationUtils; -import com.gitblit.utils.HttpUtils; -import com.gitblit.utils.JGitUtils; -import com.gitblit.utils.JsonUtils; -import com.gitblit.utils.ObjectCache; import com.gitblit.utils.StringUtils; import com.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 - * the web ui and the servlets. This class is either directly instantiated by - * the GitBlitServer class (Gitblit GO) or is reflectively instantiated by the - * servlet 3 container (Gitblit WAR or Express). + * This class is the main entry point for the entire webapp. It is a singleton + * created manually by Gitblit GO or dynamically by the WAR/Express servlet + * container. This class instantiates and starts all managers followed by + * instantiating and registering all servlets and filters. * - * This class is the central logic processor for Gitblit. All settings, user - * object, and repository object operations pass through this class. + * Leveraging Servlet 3 and Dagger static dependency injection allows Gitblit to + * be modular and completely code-driven rather then relying on the fragility of + * a web.xml descriptor and the static & monolithic design previously used. * * @author James Moger * */ @WebListener -public class GitBlit extends DaggerContextListener - implements IFederationManager, - IGitblitManager { +public class GitBlit extends DaggerContextListener { 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); - - private final List<FederationModel> federationRegistrations = Collections - .synchronizedList(new ArrayList<FederationModel>()); - - private final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>(); - - private final Map<String, FederationModel> federationPullResults = new ConcurrentHashMap<String, FederationModel>(); - - private IStoredSettings settings; - - private FanoutService fanoutService; + private final IStoredSettings goSettings; - private GitDaemon gitDaemon; + private final File goBaseFolder; + /** + * Construct a Gitblit WAR/Express context. + */ public GitBlit() { this.goSettings = null; this.goBaseFolder = null; + gitblit = this; } + /** + * Construct a Gitblit GO context. + * + * @param settings + * @param baseFolder + */ public GitBlit(IStoredSettings settings, File baseFolder) { this.goSettings = settings; this.goBaseFolder = baseFolder; @@ -148,20 +97,13 @@ public class GitBlit extends DaggerContextListener } /** - * Returns the Gitblit singleton. + * This method is only used for unit and integration testing. * - * @return gitblit singleton + * @param managerClass + * @return a manager */ - public static GitBlit self() { - return gitblit; - } - @SuppressWarnings("unchecked") - public static <X> X getManager(Class<X> managerClass) { - if (managerClass.isAssignableFrom(GitBlit.class)) { - return (X) gitblit; - } - + public static <X extends IManager> X getManager(Class<X> managerClass) { for (IManager manager : gitblit.managers) { if (managerClass.isAssignableFrom(manager.getClass())) { return (X) manager; @@ -171,786 +113,15 @@ public class GitBlit extends DaggerContextListener } /** - * 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. - * - * @return the proposals folder path - */ - @Override - public File getProposalsFolder() { - return getManager(IRuntimeManager.class).getFileOrFolder(Keys.federation.proposalsFolder, "${baseFolder}/proposals"); - } - - /** - * Returns a list of repository URLs and the user access permission. - * - * @param request - * @param user - * @param repository - * @return a list of repository urls - */ - @Override - public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { - if (user == null) { - user = UserModel.ANONYMOUS; - } - String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); - - List<RepositoryUrl> list = new ArrayList<RepositoryUrl>(); - // http/https url - if (settings.getBoolean(Keys.git.enableGitServlet, true)) { - AccessPermission permission = user.getRepositoryPermission(repository).permission; - if (permission.exceeds(AccessPermission.NONE)) { - list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission)); - } - } - - // git daemon url - String gitDaemonUrl = getGitDaemonUrl(request, user, repository); - if (!StringUtils.isEmpty(gitDaemonUrl)) { - AccessPermission permission = getGitDaemonAccessPermission(user, repository); - if (permission.exceeds(AccessPermission.NONE)) { - list.add(new RepositoryUrl(gitDaemonUrl, permission)); - } - } - - // add all other urls - // {0} = repository - // {1} = username - for (String url : settings.getStrings(Keys.web.otherUrls)) { - if (url.contains("{1}")) { - // external url requires username, only add url IF we have one - if(!StringUtils.isEmpty(username)) { - list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null)); - } - } else { - // external url does not require username - list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null)); - } - } - return list; - } - - protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) { - StringBuilder sb = new StringBuilder(); - sb.append(HttpUtils.getGitblitURL(request)); - sb.append(Constants.GIT_PATH); - sb.append(repository.name); - - // inject username into repository url if authentication is required - if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE) - && !StringUtils.isEmpty(username)) { - sb.insert(sb.indexOf("://") + 3, username + "@"); - } - return sb.toString(); - } - - protected String getGitDaemonUrl(HttpServletRequest request, UserModel user, RepositoryModel repository) { - if (gitDaemon != null) { - String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost"); - if (bindInterface.equals("localhost") - && (!request.getServerName().equals("localhost") && !request.getServerName().equals("127.0.0.1"))) { - // git daemon is bound to localhost and the request is from elsewhere - return null; - } - if (user.canClone(repository)) { - String servername = request.getServerName(); - String url = gitDaemon.formatUrl(servername, repository.name); - return url; - } - } - return null; - } - - protected AccessPermission getGitDaemonAccessPermission(UserModel user, RepositoryModel repository) { - if (gitDaemon != null && user.canClone(repository)) { - AccessPermission gitDaemonPermission = user.getRepositoryPermission(repository).permission; - if (gitDaemonPermission.atLeast(AccessPermission.CLONE)) { - if (repository.accessRestriction.atLeast(AccessRestrictionType.CLONE)) { - // can not authenticate clone via anonymous git protocol - gitDaemonPermission = AccessPermission.NONE; - } else if (repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) { - // can not authenticate push via anonymous git protocol - gitDaemonPermission = AccessPermission.CLONE; - } else { - // normal user permission - } - } - return gitDaemonPermission; - } - return AccessPermission.NONE; - } - - /** - * Returns the list of custom client applications to be used for the - * repository url panel; - * - * @return a collection of client applications - */ - @Override - public Collection<GitClientApplication> getClientApplications() { - // prefer user definitions, if they exist - File userDefs = new File(getManager(IRuntimeManager.class).getBaseFolder(), "clientapps.json"); - if (userDefs.exists()) { - Date lastModified = new Date(userDefs.lastModified()); - if (clientApplications.hasCurrent("user", lastModified)) { - return clientApplications.getObject("user"); - } else { - // (re)load user definitions - try { - InputStream is = new FileInputStream(userDefs); - Collection<GitClientApplication> clients = readClientApplications(is); - is.close(); - if (clients != null) { - clientApplications.updateObject("user", lastModified, clients); - return clients; - } - } catch (IOException e) { - logger.error("Failed to deserialize " + userDefs.getAbsolutePath(), e); - } - } - } - - // no user definitions, use system definitions - if (!clientApplications.hasCurrent("system", new Date(0))) { - try { - InputStream is = getClass().getResourceAsStream("/clientapps.json"); - Collection<GitClientApplication> clients = readClientApplications(is); - is.close(); - if (clients != null) { - clientApplications.updateObject("system", new Date(0), clients); - } - } catch (IOException e) { - logger.error("Failed to deserialize clientapps.json resource!", e); - } - } - - return clientApplications.getObject("system"); - } - - private Collection<GitClientApplication> readClientApplications(InputStream is) { - try { - Type type = new TypeToken<Collection<GitClientApplication>>() { - }.getType(); - InputStreamReader reader = new InputStreamReader(is); - Gson gson = JsonUtils.gson(); - Collection<GitClientApplication> links = gson.fromJson(reader, type); - return links; - } catch (JsonIOException e) { - logger.error("Error deserializing client applications!", e); - } catch (JsonSyntaxException e) { - logger.error("Error deserializing client applications!", e); - } - return null; - } - - /** - * Open a file resource using the Servlet container. - * @param file to open - * @return InputStream of the opened file - * @throws ResourceStreamNotFoundException - */ - public InputStream getResourceAsStream(String file) throws ResourceStreamNotFoundException { - ContextRelativeResource res = WicketUtils.getResource(file); - return res.getResourceStream().getInputStream(); - } - - @Override - public UserModel getFederationUser() { - // the federation user is an administrator - UserModel federationUser = new UserModel(Constants.FEDERATION_USER); - federationUser.canAdmin = true; - return federationUser; - } - - /** - * Adds/updates a complete user object keyed by username. This method allows - * for renaming a user. - * - * @see IUserService.updateUserModel(String, UserModel) - * @param username - * @param user - * @param isCreate - * @throws GitBlitException - */ - @Override - public void updateUserModel(String username, UserModel user, boolean isCreate) - throws GitBlitException { - if (!username.equalsIgnoreCase(user.username)) { - if (getManager(IUserManager.class).getUserModel(user.username) != null) { - throw new GitBlitException(MessageFormat.format( - "Failed to rename ''{0}'' because ''{1}'' already exists.", username, - user.username)); - } - - // rename repositories and owner fields for all repositories - for (RepositoryModel model : 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(); - getManager(IRepositoryManager.class).updateRepositoryModel(oldRepositoryName, model, false); - } else if (model.isOwner(username)) { - // common/shared repo - model.addOwner(user.username); - 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!"); - } - } - - /** - * Updates the TeamModel object for the specified name. - * - * @param teamname - * @param team - * @param isCreate - */ - @Override - public void updateTeamModel(String teamname, TeamModel team, boolean isCreate) - throws GitBlitException { - if (!teamname.equalsIgnoreCase(team.name)) { - if (getManager(IUserManager.class).getTeamModel(team.name) != null) { - throw new GitBlitException(MessageFormat.format( - "Failed to rename ''{0}'' because ''{1}'' already exists.", teamname, - team.name)); - } - } - if (!getManager(IUserManager.class).updateTeamModel(teamname, team)) { - throw new GitBlitException(isCreate ? "Failed to add team!" : "Failed to update team!"); - } - } - - - /** - * Returns Gitblit's scheduled executor service for scheduling tasks. - * - * @return scheduledExecutor - */ - public ScheduledExecutorService executor() { - return scheduledExecutor; - } - - @Override - public boolean canFederate() { - String passphrase = settings.getString(Keys.federation.passphrase, ""); - return !StringUtils.isEmpty(passphrase); - } - - /** - * Configures this Gitblit instance to pull any registered federated gitblit - * instances. - */ - private void configureFederation() { - boolean validPassphrase = true; - String passphrase = settings.getString(Keys.federation.passphrase, ""); - if (StringUtils.isEmpty(passphrase)) { - logger.warn("Federation passphrase is blank! This server can not be PULLED from."); - validPassphrase = false; - } - if (validPassphrase) { - // standard tokens - for (FederationToken tokenType : FederationToken.values()) { - logger.info(MessageFormat.format("Federation {0} token = {1}", tokenType.name(), - getFederationToken(tokenType))); - } - - // federation set tokens - for (String set : settings.getStrings(Keys.federation.sets)) { - logger.info(MessageFormat.format("Federation Set {0} token = {1}", set, - getFederationToken(set))); - } - } - - // Schedule the federation executor - List<FederationModel> registrations = getFederationRegistrations(); - if (registrations.size() > 0) { - FederationPullExecutor executor = new FederationPullExecutor(registrations, true); - scheduledExecutor.schedule(executor, 1, TimeUnit.MINUTES); - } - } - - /** - * Returns the list of federated gitblit instances that this instance will - * try to pull. - * - * @return list of registered gitblit instances - */ - @Override - public List<FederationModel> getFederationRegistrations() { - if (federationRegistrations.isEmpty()) { - federationRegistrations.addAll(FederationUtils.getFederationRegistrations(settings)); - } - return federationRegistrations; - } - - /** - * Retrieve the specified federation registration. - * - * @param name - * the name of the registration - * @return a federation registration - */ - @Override - public FederationModel getFederationRegistration(String url, String name) { - // check registrations - for (FederationModel r : getFederationRegistrations()) { - if (r.name.equals(name) && r.url.equals(url)) { - return r; - } - } - - // check the results - for (FederationModel r : getFederationResultRegistrations()) { - if (r.name.equals(name) && r.url.equals(url)) { - return r; - } - } - return null; - } - - /** - * Returns the list of federation sets. - * - * @return list of federation sets - */ - @Override - public List<FederationSet> getFederationSets(String gitblitUrl) { - List<FederationSet> list = new ArrayList<FederationSet>(); - // generate standard tokens - for (FederationToken type : FederationToken.values()) { - FederationSet fset = new FederationSet(type.toString(), type, getFederationToken(type)); - fset.repositories = getRepositories(gitblitUrl, fset.token); - list.add(fset); - } - // generate tokens for federation sets - for (String set : settings.getStrings(Keys.federation.sets)) { - FederationSet fset = new FederationSet(set, FederationToken.REPOSITORIES, - getFederationToken(set)); - fset.repositories = getRepositories(gitblitUrl, fset.token); - list.add(fset); - } - return list; - } - - /** - * Returns the list of possible federation tokens for this Gitblit instance. - * - * @return list of federation tokens - */ - @Override - public List<String> getFederationTokens() { - List<String> tokens = new ArrayList<String>(); - // generate standard tokens - for (FederationToken type : FederationToken.values()) { - tokens.add(getFederationToken(type)); - } - // generate tokens for federation sets - for (String set : settings.getStrings(Keys.federation.sets)) { - tokens.add(getFederationToken(set)); - } - return tokens; - } - - /** - * Returns the specified federation token for this Gitblit instance. - * - * @param type - * @return a federation token - */ - @Override - public String getFederationToken(FederationToken type) { - return getFederationToken(type.name()); - } - - /** - * Returns the specified federation token for this Gitblit instance. - * - * @param value - * @return a federation token - */ - @Override - public String getFederationToken(String value) { - String passphrase = settings.getString(Keys.federation.passphrase, ""); - return StringUtils.getSHA1(passphrase + "-" + value); - } - - /** - * Compares the provided token with this Gitblit instance's tokens and - * determines if the requested permission may be granted to the token. - * - * @param req - * @param token - * @return true if the request can be executed - */ - @Override - public boolean validateFederationRequest(FederationRequest req, String token) { - String all = getFederationToken(FederationToken.ALL); - String unr = getFederationToken(FederationToken.USERS_AND_REPOSITORIES); - String jur = getFederationToken(FederationToken.REPOSITORIES); - switch (req) { - case PULL_REPOSITORIES: - return token.equals(all) || token.equals(unr) || token.equals(jur); - case PULL_USERS: - case PULL_TEAMS: - return token.equals(all) || token.equals(unr); - case PULL_SETTINGS: - case PULL_SCRIPTS: - return token.equals(all); - default: - break; - } - return false; - } - - /** - * Acknowledge and cache the status of a remote Gitblit instance. - * - * @param identification - * the identification of the pulling Gitblit instance - * @param registration - * the registration from the pulling Gitblit instance - * @return true if acknowledged - */ - @Override - public boolean acknowledgeFederationStatus(String identification, FederationModel registration) { - // reset the url to the identification of the pulling Gitblit instance - registration.url = identification; - String id = identification; - if (!StringUtils.isEmpty(registration.folder)) { - id += "-" + registration.folder; - } - federationPullResults.put(id, registration); - return true; - } - - /** - * Returns the list of registration results. - * - * @return the list of registration results - */ - @Override - public List<FederationModel> getFederationResultRegistrations() { - return new ArrayList<FederationModel>(federationPullResults.values()); - } - - /** - * Submit a federation proposal. The proposal is cached locally and the - * Gitblit administrator(s) are notified via email. - * - * @param proposal - * the proposal - * @param gitblitUrl - * the url of your gitblit instance to send an email to - * administrators - * @return true if the proposal was submitted - */ - @Override - public boolean submitFederationProposal(FederationProposal proposal, String gitblitUrl) { - // convert proposal to json - String json = JsonUtils.toJsonString(proposal); - - try { - // make the proposals folder - File proposalsFolder = getProposalsFolder(); - proposalsFolder.mkdirs(); - - // cache json to a file - File file = new File(proposalsFolder, proposal.token + Constants.PROPOSAL_EXT); - com.gitblit.utils.FileUtils.writeContent(file, json); - } catch (Exception e) { - logger.error(MessageFormat.format("Failed to cache proposal from {0}", proposal.url), e); - } - - // send an email, if possible - getManager(INotificationManager.class).sendMailToAdministrators("Federation proposal from " + proposal.url, - "Please review the proposal @ " + gitblitUrl + "/proposal/" + proposal.token); - return true; - } - - /** - * Returns the list of pending federation proposals - * - * @return list of federation proposals - */ - @Override - public List<FederationProposal> getPendingFederationProposals() { - List<FederationProposal> list = new ArrayList<FederationProposal>(); - File folder = getProposalsFolder(); - if (folder.exists()) { - File[] files = folder.listFiles(new FileFilter() { - @Override - public boolean accept(File file) { - return file.isFile() - && file.getName().toLowerCase().endsWith(Constants.PROPOSAL_EXT); - } - }); - for (File file : files) { - String json = com.gitblit.utils.FileUtils.readContent(file, null); - FederationProposal proposal = JsonUtils.fromJsonString(json, - FederationProposal.class); - list.add(proposal); - } - } - return list; - } - - /** - * Get repositories for the specified token. - * - * @param gitblitUrl - * the base url of this gitblit instance - * @param token - * the federation token - * @return a map of <cloneurl, RepositoryModel> - */ - @Override - public Map<String, RepositoryModel> getRepositories(String gitblitUrl, String token) { - Map<String, String> federationSets = new HashMap<String, String>(); - for (String set : settings.getStrings(Keys.federation.sets)) { - federationSets.put(getFederationToken(set), set); - } - - // Determine the Gitblit clone url - StringBuilder sb = new StringBuilder(); - sb.append(gitblitUrl); - sb.append(Constants.GIT_PATH); - sb.append("{0}"); - String cloneUrl = sb.toString(); - - // Retrieve all available repositories - UserModel user = getFederationUser(); - List<RepositoryModel> list = getManager(IRepositoryManager.class).getRepositoryModels(user); - - // create the [cloneurl, repositoryModel] map - Map<String, RepositoryModel> repositories = new HashMap<String, RepositoryModel>(); - for (RepositoryModel model : list) { - // by default, setup the url for THIS repository - String url = MessageFormat.format(cloneUrl, model.name); - switch (model.federationStrategy) { - case EXCLUDE: - // skip this repository - continue; - case FEDERATE_ORIGIN: - // federate the origin, if it is defined - if (!StringUtils.isEmpty(model.origin)) { - url = model.origin; - } - break; - default: - break; - } - - if (federationSets.containsKey(token)) { - // include repositories only for federation set - String set = federationSets.get(token); - if (model.federationSets.contains(set)) { - repositories.put(url, model); - } - } else { - // standard federation token for ALL - repositories.put(url, model); - } - } - return repositories; - } - - /** - * Creates a proposal from the token. - * - * @param gitblitUrl - * the url of this Gitblit instance - * @param token - * @return a potential proposal - */ - @Override - public FederationProposal createFederationProposal(String gitblitUrl, String token) { - FederationToken tokenType = FederationToken.REPOSITORIES; - for (FederationToken type : FederationToken.values()) { - if (token.equals(getFederationToken(type))) { - tokenType = type; - break; - } - } - Map<String, RepositoryModel> repositories = getRepositories(gitblitUrl, token); - FederationProposal proposal = new FederationProposal(gitblitUrl, tokenType, token, - repositories); - return proposal; - } - - /** - * Returns the proposal identified by the supplied token. - * - * @param token - * @return the specified proposal or null - */ - @Override - public FederationProposal getPendingFederationProposal(String token) { - List<FederationProposal> list = getPendingFederationProposals(); - for (FederationProposal proposal : list) { - if (proposal.token.equals(token)) { - return proposal; - } - } - return null; - } - - /** - * Deletes a pending federation proposal. - * - * @param a - * proposal - * @return true if the proposal was deleted + * Returns Gitblit's Dagger injection modules. */ @Override - public boolean deletePendingFederationProposal(FederationProposal proposal) { - File folder = getProposalsFolder(); - File file = new File(folder, proposal.token + Constants.PROPOSAL_EXT); - return file.delete(); - } - - /** - * 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) { - // 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 - // models map. - InputStream is = getClass().getResourceAsStream("/reference.properties"); - BufferedReader propertiesReader = new BufferedReader(new InputStreamReader(is)); - StringBuilder description = new StringBuilder(); - SettingModel setting = new SettingModel(); - String line = null; - while ((line = propertiesReader.readLine()) != null) { - if (line.length() == 0) { - description.setLength(0); - setting = new SettingModel(); - } else { - if (line.charAt(0) == '#') { - if (line.length() > 1) { - String text = line.substring(1).trim(); - if (SettingModel.CASE_SENSITIVE.equals(text)) { - setting.caseSensitive = true; - } else if (SettingModel.RESTART_REQUIRED.equals(text)) { - setting.restartRequired = true; - } else if (SettingModel.SPACE_DELIMITED.equals(text)) { - setting.spaceDelimited = true; - } else if (text.startsWith(SettingModel.SINCE)) { - try { - setting.since = text.split(" ")[1]; - } catch (Exception e) { - setting.since = text; - } - } else { - description.append(text); - description.append('\n'); - } - } - } else { - String[] kvp = line.split("=", 2); - String key = kvp[0].trim(); - setting.name = key; - setting.defaultValue = kvp[1].trim(); - setting.currentValue = setting.defaultValue; - setting.description = description.toString().trim(); - settingsModel.add(setting); - description.setLength(0); - setting = new SettingModel(); - } - } - } - propertiesReader.close(); - } catch (NullPointerException e) { - logger.error("Failed to find resource copy of gitblit.properties"); - } catch (IOException e) { - logger.error("Failed to load resource copy of gitblit.properties"); - } - return settingsModel; - } - - protected void configureFanout() { - // startup Fanout PubSub service - if (settings.getInteger(Keys.fanout.port, 0) > 0) { - String bindInterface = settings.getString(Keys.fanout.bindInterface, null); - int port = settings.getInteger(Keys.fanout.port, FanoutService.DEFAULT_PORT); - boolean useNio = settings.getBoolean(Keys.fanout.useNio, true); - int limit = settings.getInteger(Keys.fanout.connectionLimit, 0); - - if (useNio) { - if (StringUtils.isEmpty(bindInterface)) { - fanoutService = new FanoutNioService(port); - } else { - fanoutService = new FanoutNioService(bindInterface, port); - } - } else { - if (StringUtils.isEmpty(bindInterface)) { - fanoutService = new FanoutSocketService(port); - } else { - fanoutService = new FanoutSocketService(bindInterface, port); - } - } - - fanoutService.setConcurrentConnectionLimit(limit); - fanoutService.setAllowAllChannelAnnouncements(false); - fanoutService.start(); - } - } - - protected void configureGitDaemon() { - int port = settings.getInteger(Keys.git.daemonPort, 0); - String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost"); - if (port > 0) { - try { - // HACK temporary pending manager separation and injection - Gitblit gitblit = new Gitblit( - getManager(IRuntimeManager.class), - getManager(INotificationManager.class), - getManager(IUserManager.class), - getManager(ISessionManager.class), - getManager(IRepositoryManager.class), - getManager(IProjectManager.class), - this, - this); - gitDaemon = new GitDaemon(gitblit); - gitDaemon.start(); - } catch (IOException e) { - gitDaemon = null; - logger.error(MessageFormat.format("Failed to start Git daemon on {0}:{1,number,0}", bindInterface, port), e); - } - } - } - - protected final Logger getLogger() { - return logger; - } - - protected final ScheduledExecutorService getScheduledExecutor() { - return scheduledExecutor; + protected Object [] getModules() { + return new Object [] { new DaggerModule() }; } /** - * Configure Gitblit from the web.xml, if no configuration has already been - * specified. - * - * @see ServletContextListener.contextInitialize(ServletContextEvent) + * Prepare runtime settings and start all manager instances. */ @Override protected void beforeServletInjection(ServletContext context) { @@ -958,12 +129,10 @@ public class GitBlit extends DaggerContextListener // 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 @@ -973,11 +142,9 @@ public class GitBlit extends DaggerContextListener if (!StringUtils.isEmpty(System.getenv("OPENSHIFT_DATA_DIR"))) { // RedHat OpenShift - logger.debug("configuring Gitblit Express"); baseFolder = configureExpress(context, webxmlSettings, contextFolder, runtimeSettings); } else { // standard WAR - logger.debug("configuring Gitblit WAR"); baseFolder = configureWAR(context, webxmlSettings, contextFolder, runtimeSettings); } @@ -985,27 +152,85 @@ public class GitBlit extends DaggerContextListener ContainerUtils.CVE_2007_0450.test(runtimeSettings); } - // Runtime manager is a container for settings and other parameters - IRuntimeManager runtime = startManager(injector, IRuntimeManager.class); + // Manually configure IRuntimeManager + logManager(IRuntimeManager.class); + IRuntimeManager runtime = injector.get(IRuntimeManager.class); runtime.setBaseFolder(baseFolder); runtime.getStatus().isGO = goSettings != null; runtime.getStatus().servletContainer = context.getServerInfo(); + runtime.start(); + managers.add(runtime); + // start all other managers startManager(injector, INotificationManager.class); startManager(injector, IUserManager.class); startManager(injector, ISessionManager.class); startManager(injector, IRepositoryManager.class); startManager(injector, IProjectManager.class); + startManager(injector, IGitblitManager.class); + startManager(injector, IFederationManager.class); + startManager(injector, IServicesManager.class); + + logger.info(""); + logger.info("All managers started."); + logger.info(""); + } + + protected <X extends IManager> X startManager(ObjectGraph injector, Class<X> clazz) { + logManager(clazz); + X x = injector.get(clazz); + x.start(); + managers.add(x); + return x; + } + + protected void logManager(Class<? extends IManager> clazz) { + logger.info(""); + logger.info("----[{}]----", clazz.getName()); + } + + /** + * Instantiate and inject all filters and servlets into the container using + * the servlet 3 specification. + */ + @Override + protected void injectServlets(ServletContext context) { + // access restricted servlets + serve(context, Constants.GIT_PATH, GitServlet.class, GitFilter.class); + serve(context, Constants.PAGES, PagesServlet.class, PagesFilter.class); + serve(context, Constants.RPC_PATH, RpcServlet.class, RpcFilter.class); + serve(context, Constants.ZIP_PATH, DownloadZipServlet.class, DownloadZipFilter.class); + serve(context, Constants.SYNDICATION_PATH, SyndicationServlet.class, SyndicationFilter.class); + + // servlets + serve(context, Constants.FEDERATION_PATH, FederationServlet.class); + serve(context, Constants.SPARKLESHARE_INVITE_PATH, SparkleShareInviteServlet.class); + serve(context, Constants.BRANCH_GRAPH_PATH, BranchGraphServlet.class); + file(context, "/robots.txt", RobotsTxtServlet.class); + file(context, "/logo.png", LogoServlet.class); - logger.info("Gitblit base folder = " + baseFolder.getAbsolutePath()); + // optional force basic authentication + filter(context, "/*", EnforceAuthenticationFilter.class, null); - loadSettingModels(runtime.getSettingsModel()); + // Wicket + String toIgnore = StringUtils.flattenStrings(getRegisteredPaths(), ","); + Map<String, String> params = new HashMap<String, String>(); + params.put(GitblitWicketFilter.FILTER_MAPPING_PARAM, "/*"); + params.put(GitblitWicketFilter.IGNORE_PATHS_PARAM, toIgnore); + filter(context, "/*", GitblitWicketFilter.class, params); + } - if (true/*startFederation*/) { - configureFederation(); + /** + * Gitblit is being shutdown either because the servlet container is + * shutting down or because the servlet container is re-deploying Gitblit. + */ + @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(); } - configureFanout(); - configureGitDaemon(); } /** @@ -1023,6 +248,8 @@ public class GitBlit extends DaggerContextListener File goBaseFolder, IStoredSettings runtimeSettings) { + logger.debug("configuring Gitblit GO"); + // merge the stored settings into the runtime settings // // if runtimeSettings is also a FileSettings w/o a specified target file, @@ -1049,6 +276,7 @@ public class GitBlit extends DaggerContextListener IStoredSettings runtimeSettings) { // Gitblit is running in a standard servlet container + logger.debug("configuring Gitblit WAR"); logger.info("WAR contextFolder is " + ((contextFolder != null) ? contextFolder.getAbsolutePath() : "<empty>")); String path = webxmlSettings.getString(Constants.baseFolder, Constants.contextFolder$ + "/WEB-INF/data"); @@ -1112,6 +340,7 @@ public class GitBlit extends DaggerContextListener IStoredSettings runtimeSettings) { // Gitblit is running in OpenShift/JBoss + logger.debug("configuring Gitblit Express"); String openShift = System.getenv("OPENSHIFT_DATA_DIR"); File base = new File(openShift); logger.info("EXPRESS contextFolder is " + contextFolder.getAbsolutePath()); @@ -1194,141 +423,4 @@ public class GitBlit extends DaggerContextListener } } } - - /** - * Gitblit is being shutdown either because the servlet container is - * shutting down or because the servlet container is re-deploying Gitblit. - */ - @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(); - if (fanoutService != null) { - fanoutService.stop(); - } - if (gitDaemon != null) { - gitDaemon.stop(); - } - } - - /** - * Creates a personal fork of the specified repository. The clone is view - * restricted by default and the owner of the source repository is given - * access to the clone. - * - * @param repository - * @param user - * @return the repository model of the fork, if successful - * @throws GitBlitException - */ - @Override - public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException { - String cloneName = MessageFormat.format("{0}/{1}.git", user.getPersonalPath(), StringUtils.stripDotGit(StringUtils.getLastPathElement(repository.name))); - String fromUrl = MessageFormat.format("file://{0}/{1}", getManager(IRepositoryManager.class).getRepositoriesFolder().getAbsolutePath(), repository.name); - - // clone the repository - try { - JGitUtils.cloneRepository(getManager(IRepositoryManager.class).getRepositoriesFolder(), cloneName, fromUrl, true, null); - } catch (Exception e) { - throw new GitBlitException(e); - } - - // create a Gitblit repository model for the clone - RepositoryModel cloneModel = repository.cloneAs(cloneName); - // owner has REWIND/RW+ permissions - cloneModel.addOwner(user.username); - 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)) { - for (String owner : repository.owners) { - UserModel originOwner = getManager(IUserManager.class).getUserModel(owner); - if (originOwner != null) { - originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE); - updateUserModel(originOwner.username, originOwner, false); - } - } - } - - // grant origin's user list clone permission to fork - List<String> users = getManager(IRepositoryManager.class).getRepositoryUsers(repository); - List<UserModel> cloneUsers = new ArrayList<UserModel>(); - for (String name : users) { - if (!name.equalsIgnoreCase(user.username)) { - 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); - } - cloneUsers.add(cloneUser); - } - } - getManager(IUserManager.class).updateUserModels(cloneUsers); - - // grant origin's team list clone permission to fork - 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); - if (cloneTeam.canClone(repository)) { - // origin team can clone origin, grant clone access to fork - cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE); - } - cloneTeams.add(cloneTeam); - } - getManager(IUserManager.class).updateTeamModels(cloneTeams); - - // add this clone to the cached model - getManager(IRepositoryManager.class).addToCachedRepositoryList(cloneModel); - return cloneModel; - } - - @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. - */ - @Override - protected void injectServlets(ServletContext context) { - // access restricted servlets - serve(context, Constants.GIT_PATH, GitServlet.class, GitFilter.class); - serve(context, Constants.PAGES, PagesServlet.class, PagesFilter.class); - serve(context, Constants.RPC_PATH, RpcServlet.class, RpcFilter.class); - serve(context, Constants.ZIP_PATH, DownloadZipServlet.class, DownloadZipFilter.class); - serve(context, Constants.SYNDICATION_PATH, SyndicationServlet.class, SyndicationFilter.class); - - // servlets - serve(context, Constants.FEDERATION_PATH, FederationServlet.class); - serve(context, Constants.SPARKLESHARE_INVITE_PATH, SparkleShareInviteServlet.class); - serve(context, Constants.BRANCH_GRAPH_PATH, BranchGraphServlet.class); - file(context, "/robots.txt", RobotsTxtServlet.class); - file(context, "/logo.png", LogoServlet.class); - - // optional force basic authentication - filter(context, "/*", EnforceAuthenticationFilter.class, null); - - // Wicket - String toIgnore = StringUtils.flattenStrings(getRegisteredPaths(), ","); - Map<String, String> params = new HashMap<String, String>(); - params.put(GitblitWicketFilter.FILTER_MAPPING_PARAM, "/*"); - params.put(GitblitWicketFilter.IGNORE_PATHS_PARAM, toIgnore); - filter(context, "/*", GitblitWicketFilter.class, params); - } } |