From 7d3a31514afbe88664081b4ea57cd7939de99014 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 2 Jul 2014 16:21:16 -0400 Subject: [PATCH] Extract services manager into a top-level injectable manager --- src/main/java/com/gitblit/GitBlit.java | 181 -------------- .../java/com/gitblit/guice/CoreModule.java | 9 + .../com/gitblit/guice/WorkQueueProvider.java | 57 +++++ .../com/gitblit/manager/GitblitManager.java | 84 ------- .../java/com/gitblit/manager/IGitblit.java | 15 -- .../com/gitblit/manager/IRuntimeManager.java | 36 --- .../com/gitblit/manager/IServicesManager.java | 75 ++++++ .../gitblit/manager/RepositoryManager.java | 26 +- .../com/gitblit/manager/RuntimeManager.java | 51 +--- .../com/gitblit/manager/ServicesManager.java | 226 ++++++++++++++++-- .../com/gitblit/servlet/GitblitContext.java | 2 + .../com/gitblit/wicket/GitBlitWebApp.java | 20 +- .../com/gitblit/wicket/GitblitWicketApp.java | 3 + .../wicket/pages/EmptyRepositoryPage.java | 2 +- .../com/gitblit/wicket/pages/TicketPage.java | 2 +- .../com/gitblit/wicket/pages/UserPage.java | 8 +- .../wicket/panels/RepositoryUrlPanel.java | 4 +- .../tests/mock/MockRuntimeManager.java | 20 -- 18 files changed, 397 insertions(+), 424 deletions(-) create mode 100644 src/main/java/com/gitblit/guice/WorkQueueProvider.java create mode 100644 src/main/java/com/gitblit/manager/IServicesManager.java diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java index a39b0fcd..edad32ef 100644 --- a/src/main/java/com/gitblit/GitBlit.java +++ b/src/main/java/com/gitblit/GitBlit.java @@ -25,10 +25,7 @@ import java.util.List; import java.util.Set; import com.google.inject.Inject; -import javax.servlet.http.HttpServletRequest; -import com.gitblit.Constants.AccessPermission; -import com.gitblit.Constants.Transport; import com.gitblit.manager.GitblitManager; import com.gitblit.manager.IAuthenticationManager; import com.gitblit.manager.IFederationManager; @@ -39,9 +36,7 @@ import com.gitblit.manager.IProjectManager; import com.gitblit.manager.IRepositoryManager; import com.gitblit.manager.IRuntimeManager; import com.gitblit.manager.IUserManager; -import com.gitblit.manager.ServicesManager; import com.gitblit.models.RepositoryModel; -import com.gitblit.models.RepositoryUrl; import com.gitblit.models.UserModel; import com.gitblit.tickets.ITicketService; import com.gitblit.tickets.NullTicketService; @@ -62,8 +57,6 @@ public class GitBlit extends GitblitManager { private final Injector injector; - private final ServicesManager servicesManager; - private ITicketService ticketService; @Inject @@ -89,15 +82,11 @@ public class GitBlit extends GitblitManager { federationManager); this.injector = Guice.createInjector(getModules()); - - this.servicesManager = new ServicesManager(this); } @Override public GitBlit start() { super.start(); - logger.info("Starting services manager..."); - servicesManager.start(); configureTicketService(); return this; } @@ -105,184 +94,14 @@ public class GitBlit extends GitblitManager { @Override public GitBlit stop() { super.stop(); - servicesManager.stop(); ticketService.stop(); return this; } - @Override - public boolean isServingRepositories() { - return servicesManager.isServingRepositories(); - } - - @Override - public boolean isServingHTTP() { - return servicesManager.isServingHTTP(); - } - - @Override - public boolean isServingGIT() { - return servicesManager.isServingGIT(); - } - - @Override - public boolean isServingSSH() { - return servicesManager.isServingSSH(); - } - protected AbstractModule [] getModules() { return new AbstractModule [] { new GitBlitModule()}; } - protected boolean acceptPush(Transport byTransport) { - if (byTransport == null) { - logger.info("Unknown transport, push rejected!"); - return false; - } - - Set transports = new HashSet(); - for (String value : getSettings().getStrings(Keys.git.acceptedPushTransports)) { - Transport transport = Transport.fromString(value); - if (transport == null) { - logger.info(String.format("Ignoring unknown registered transport %s", value)); - continue; - } - - transports.add(transport); - } - - if (transports.isEmpty()) { - // no transports are explicitly specified, all are acceptable - return true; - } - - // verify that the transport is permitted - return transports.contains(byTransport); - } - - /** - * 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 getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { - if (user == null) { - user = UserModel.ANONYMOUS; - } - String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); - - List list = new ArrayList(); - - // http/https url - if (settings.getBoolean(Keys.git.enableGitServlet, true)) { - AccessPermission permission = user.getRepositoryPermission(repository).permission; - if (permission.exceeds(AccessPermission.NONE)) { - Transport transport = Transport.fromString(request.getScheme()); - if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(transport)) { - // downgrade the repo permission for this transport - // because it is not an acceptable PUSH transport - permission = AccessPermission.CLONE; - } - list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission)); - } - } - - // ssh daemon url - String sshDaemonUrl = servicesManager.getSshDaemonUrl(request, user, repository); - if (!StringUtils.isEmpty(sshDaemonUrl)) { - AccessPermission permission = user.getRepositoryPermission(repository).permission; - if (permission.exceeds(AccessPermission.NONE)) { - if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.SSH)) { - // downgrade the repo permission for this transport - // because it is not an acceptable PUSH transport - permission = AccessPermission.CLONE; - } - - list.add(new RepositoryUrl(sshDaemonUrl, permission)); - } - } - - // git daemon url - String gitDaemonUrl = servicesManager.getGitDaemonUrl(request, user, repository); - if (!StringUtils.isEmpty(gitDaemonUrl)) { - AccessPermission permission = servicesManager.getGitDaemonAccessPermission(user, repository); - if (permission.exceeds(AccessPermission.NONE)) { - if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.GIT)) { - // downgrade the repo permission for this transport - // because it is not an acceptable PUSH transport - permission = AccessPermission.CLONE; - } - 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)); - } - } - - // sort transports by highest permission and then by transport security - Collections.sort(list, new Comparator() { - - @Override - public int compare(RepositoryUrl o1, RepositoryUrl o2) { - if (!o1.isExternal() && o2.isExternal()) { - // prefer Gitblit over external - return -1; - } else if (o1.isExternal() && !o2.isExternal()) { - // prefer Gitblit over external - return 1; - } else if (o1.isExternal() && o2.isExternal()) { - // sort by Transport ordinal - return o1.transport.compareTo(o2.transport); - } else if (o1.permission.exceeds(o2.permission)) { - // prefer highest permission - return -1; - } else if (o2.permission.exceeds(o1.permission)) { - // prefer highest permission - return 1; - } - - // prefer more secure transports - return o1.transport.compareTo(o2.transport); - } - }); - - // consider the user's transport preference - RepositoryUrl preferredUrl = null; - Transport preferredTransport = user.getPreferences().getTransport(); - if (preferredTransport != null) { - Iterator itr = list.iterator(); - while (itr.hasNext()) { - RepositoryUrl url = itr.next(); - if (url.transport.equals(preferredTransport)) { - itr.remove(); - preferredUrl = url; - break; - } - } - } - if (preferredUrl != null) { - list.add(0, preferredUrl); - } - - return list; - } - /** * Detect renames and reindex as appropriate. */ diff --git a/src/main/java/com/gitblit/guice/CoreModule.java b/src/main/java/com/gitblit/guice/CoreModule.java index 89be94f7..03cdbf22 100644 --- a/src/main/java/com/gitblit/guice/CoreModule.java +++ b/src/main/java/com/gitblit/guice/CoreModule.java @@ -31,18 +31,21 @@ import com.gitblit.manager.IPluginManager; import com.gitblit.manager.IProjectManager; import com.gitblit.manager.IRepositoryManager; import com.gitblit.manager.IRuntimeManager; +import com.gitblit.manager.IServicesManager; import com.gitblit.manager.IUserManager; import com.gitblit.manager.NotificationManager; import com.gitblit.manager.PluginManager; import com.gitblit.manager.ProjectManager; import com.gitblit.manager.RepositoryManager; import com.gitblit.manager.RuntimeManager; +import com.gitblit.manager.ServicesManager; import com.gitblit.manager.UserManager; import com.gitblit.transport.ssh.FileKeyManager; import com.gitblit.transport.ssh.IPublicKeyManager; import com.gitblit.transport.ssh.MemoryKeyManager; import com.gitblit.transport.ssh.NullKeyManager; import com.gitblit.utils.StringUtils; +import com.gitblit.utils.WorkQueue; import com.google.inject.AbstractModule; import com.google.inject.Provides; @@ -59,6 +62,9 @@ public class CoreModule extends AbstractModule { bind(IStoredSettings.class).toInstance(new FileSettings()); + // bind complex providers + bind(WorkQueue.class).toProvider(WorkQueueProvider.class); + // core managers bind(IRuntimeManager.class).to(RuntimeManager.class).in(Singleton.class); bind(IPluginManager.class).to(PluginManager.class).in(Singleton.class); @@ -71,6 +77,9 @@ public class CoreModule extends AbstractModule { // the monolithic manager bind(IGitblit.class).to(GitBlit.class).in(Singleton.class); + + // manager for long-running daemons and services + bind(IServicesManager.class).to(ServicesManager.class); } @Provides diff --git a/src/main/java/com/gitblit/guice/WorkQueueProvider.java b/src/main/java/com/gitblit/guice/WorkQueueProvider.java new file mode 100644 index 00000000..cde27ea9 --- /dev/null +++ b/src/main/java/com/gitblit/guice/WorkQueueProvider.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.guice; + +import com.gitblit.IStoredSettings; +import com.gitblit.Keys; +import com.gitblit.manager.IRuntimeManager; +import com.gitblit.utils.IdGenerator; +import com.gitblit.utils.WorkQueue; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +/** + * Provides a lazily-instantiated WorkQueue configured from IStoredSettings. + * + * @author James Moger + * + */ +@Singleton +public class WorkQueueProvider implements Provider { + + private final IRuntimeManager runtimeManager; + + private volatile WorkQueue workQueue; + + @Inject + public WorkQueueProvider(IRuntimeManager runtimeManager) { + this.runtimeManager = runtimeManager; + } + + @Override + public synchronized WorkQueue get() { + if (workQueue != null) { + return workQueue; + } + + IStoredSettings settings = runtimeManager.getSettings(); + int defaultThreadPoolSize = settings.getInteger(Keys.execution.defaultThreadPoolSize, 1); + IdGenerator idGenerator = new IdGenerator(); + workQueue = new WorkQueue(idGenerator, defaultThreadPoolSize); + return workQueue; + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java index a0718f77..2c88e405 100644 --- a/src/main/java/com/gitblit/manager/GitblitManager.java +++ b/src/main/java/com/gitblit/manager/GitblitManager.java @@ -49,12 +49,10 @@ import ro.fortsoft.pf4j.Version; import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; -import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.FederationRequest; import com.gitblit.Constants.FederationToken; import com.gitblit.GitBlitException; import com.gitblit.IStoredSettings; -import com.gitblit.Keys; import com.gitblit.models.FederationModel; import com.gitblit.models.FederationProposal; import com.gitblit.models.FederationSet; @@ -68,7 +66,6 @@ import com.gitblit.models.PluginRegistry.PluginRelease; import com.gitblit.models.ProjectModel; import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.models.RepositoryModel; -import com.gitblit.models.RepositoryUrl; import com.gitblit.models.SearchResult; import com.gitblit.models.ServerSettings; import com.gitblit.models.ServerStatus; @@ -79,7 +76,6 @@ import com.gitblit.tickets.ITicketService; import com.gitblit.transport.ssh.IPublicKeyManager; import com.gitblit.transport.ssh.SshKey; import com.gitblit.utils.ArrayUtils; -import com.gitblit.utils.HttpUtils; import com.gitblit.utils.JsonUtils; import com.gitblit.utils.ObjectCache; import com.gitblit.utils.StringUtils; @@ -350,66 +346,6 @@ public class GitblitManager implements IGitblit { } } - /** - * 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 getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { - if (user == null) { - user = UserModel.ANONYMOUS; - } - String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); - - List list = new ArrayList(); - // 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)); - } - } - - // 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) { - String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null); - if (StringUtils.isEmpty(gitblitUrl)) { - gitblitUrl = HttpUtils.getGitblitURL(request); - } - StringBuilder sb = new StringBuilder(); - sb.append(gitblitUrl); - sb.append(Constants.R_PATH); - sb.append(repository.name); - - // inject username into repository url if authentication is required - if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE) - && !StringUtils.isEmpty(username)) { - sb.insert(sb.indexOf("://") + 3, username + "@"); - } - return sb.toString(); - } - - /** * Returns the list of custom client applications to be used for the * repository url panel; @@ -597,26 +533,6 @@ public class GitblitManager implements IGitblit { return runtimeManager.getSettingsModel(); } - @Override - public boolean isServingRepositories() { - return runtimeManager.isServingRepositories(); - } - - @Override - public boolean isServingHTTP() { - return runtimeManager.isServingHTTP(); - } - - @Override - public boolean isServingGIT() { - return runtimeManager.isServingGIT(); - } - - @Override - public boolean isServingSSH() { - return runtimeManager.isServingSSH(); - } - @Override public TimeZone getTimezone() { return runtimeManager.getTimezone(); diff --git a/src/main/java/com/gitblit/manager/IGitblit.java b/src/main/java/com/gitblit/manager/IGitblit.java index 50ec8b1f..6c5b374c 100644 --- a/src/main/java/com/gitblit/manager/IGitblit.java +++ b/src/main/java/com/gitblit/manager/IGitblit.java @@ -16,14 +16,10 @@ package com.gitblit.manager; import java.util.Collection; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; import com.gitblit.GitBlitException; import com.gitblit.models.GitClientApplication; import com.gitblit.models.RepositoryModel; -import com.gitblit.models.RepositoryUrl; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.tickets.ITicketService; @@ -39,17 +35,6 @@ public interface IGitblit extends IManager, IProjectManager, IFederationManager { - /** - * Returns a list of repository URLs and the user access permission. - * - * @param request - * @param user - * @param repository - * @return a list of repository urls - * @since 1.4.0 - */ - List getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository); - /** * Creates a complete user object. * diff --git a/src/main/java/com/gitblit/manager/IRuntimeManager.java b/src/main/java/com/gitblit/manager/IRuntimeManager.java index f736a057..8322d34f 100644 --- a/src/main/java/com/gitblit/manager/IRuntimeManager.java +++ b/src/main/java/com/gitblit/manager/IRuntimeManager.java @@ -50,42 +50,6 @@ public interface IRuntimeManager extends IManager { */ Locale getLocale(); - /** - * 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 - * @since 1.4.0 - */ - boolean isServingRepositories(); - - /** - * Determine if this Gitblit instance is actively serving git repositories - * over HTTP. - * - * @return true if Gitblit is serving repositories over HTTP - * @since 1.6.0 - */ - boolean isServingHTTP(); - - /** - * Determine if this Gitblit instance is actively serving git repositories - * over the GIT Daemon protocol. - * - * @return true if Gitblit is serving repositories over the GIT Daemon protocol - * @since 1.6.0 - */ - boolean isServingGIT(); - - /** - * Determine if this Gitblit instance is actively serving git repositories - * over the SSH protocol. - * - * @return true if Gitblit is serving repositories over the SSH protocol - * @since 1.6.0 - */ - boolean isServingSSH(); - /** * Determine if this Gitblit instance is running in debug mode * diff --git a/src/main/java/com/gitblit/manager/IServicesManager.java b/src/main/java/com/gitblit/manager/IServicesManager.java new file mode 100644 index 00000000..5bb135dd --- /dev/null +++ b/src/main/java/com/gitblit/manager/IServicesManager.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.manager; + +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.RepositoryUrl; +import com.gitblit.models.UserModel; + +public interface IServicesManager extends IManager { + + /** + * 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 + * @since 1.7.0 + */ + boolean isServingRepositories(); + + /** + * Determine if this Gitblit instance is actively serving git repositories + * over HTTP. + * + * @return true if Gitblit is serving repositories over HTTP + * @since 1.7.0 + */ + boolean isServingHTTP(); + + /** + * Determine if this Gitblit instance is actively serving git repositories + * over the GIT Daemon protocol. + * + * @return true if Gitblit is serving repositories over the GIT Daemon protocol + * @since 1.7.0 + */ + boolean isServingGIT(); + + /** + * Determine if this Gitblit instance is actively serving git repositories + * over the SSH protocol. + * + * @return true if Gitblit is serving repositories over the SSH protocol + * @since 1.7.0 + */ + boolean isServingSSH(); + + /** + * Returns a list of repository URLs and the user access permission. + * + * @param request + * @param user + * @param repository + * @return a list of repository urls + * @since 1.7.0 + */ + List getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository); + +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java index 9b061e25..a417c025 100644 --- a/src/main/java/com/gitblit/manager/RepositoryManager.java +++ b/src/main/java/com/gitblit/manager/RepositoryManager.java @@ -1937,21 +1937,19 @@ public class RepositoryManager implements IRepositoryManager { } protected void confirmWriteAccess() { - if (runtimeManager.isServingRepositories()) { - try { - if (!getRepositoriesFolder().exists()) { - getRepositoriesFolder().mkdirs(); - } - File file = File.createTempFile(".test-", ".txt", getRepositoriesFolder()); - file.delete(); - } catch (Exception e) { - logger.error(""); - logger.error(Constants.BORDER2); - logger.error("Please check filesystem permissions!"); - logger.error("FAILED TO WRITE TO REPOSITORIES FOLDER!!", e); - logger.error(Constants.BORDER2); - logger.error(""); + try { + if (!getRepositoriesFolder().exists()) { + getRepositoriesFolder().mkdirs(); } + File file = File.createTempFile(".test-", ".txt", getRepositoriesFolder()); + file.delete(); + } catch (Exception e) { + logger.error(""); + logger.error(Constants.BORDER2); + logger.error("Please check filesystem permissions!"); + logger.error("FAILED TO WRITE TO REPOSITORIES FOLDER!!", e); + logger.error(Constants.BORDER2); + logger.error(""); } } } diff --git a/src/main/java/com/gitblit/manager/RuntimeManager.java b/src/main/java/com/gitblit/manager/RuntimeManager.java index 383b1dce..95a363f6 100644 --- a/src/main/java/com/gitblit/manager/RuntimeManager.java +++ b/src/main/java/com/gitblit/manager/RuntimeManager.java @@ -22,8 +22,6 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; -import com.google.inject.Inject; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,8 +32,11 @@ import com.gitblit.models.ServerSettings; import com.gitblit.models.ServerStatus; import com.gitblit.models.SettingModel; import com.gitblit.utils.StringUtils; +import com.google.inject.Inject; import com.google.inject.Injector; +import com.google.inject.Singleton; +@Singleton public class RuntimeManager implements IRuntimeManager { private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -123,52 +124,6 @@ public class RuntimeManager implements IRuntimeManager { return settingsModel; } - /** - * 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 isServingHTTP() - || isServingGIT() - || isServingSSH(); - } - - /** - * Determine if this Gitblit instance is actively serving git repositories - * over the HTTP protocol. - * - * @return true if Gitblit is serving repositories over the HTTP protocol - */ - @Override - public boolean isServingHTTP() { - return settings.getBoolean(Keys.git.enableGitServlet, true); - } - - /** - * Determine if this Gitblit instance is actively serving git repositories - * over the Git Daemon protocol. - * - * @return true if Gitblit is serving repositories over the Git Daemon protocol - */ - @Override - public boolean isServingGIT() { - return settings.getInteger(Keys.git.daemonPort, 0) > 0; - } - - /** - * Determine if this Gitblit instance is actively serving git repositories - * over the SSH protocol. - * - * @return true if Gitblit is serving repositories over the SSH protocol - */ - @Override - public boolean isServingSSH() { - return settings.getInteger(Keys.git.sshPort, 0) > 0; - } - /** * Returns the preferred timezone for the Gitblit instance. * diff --git a/src/main/java/com/gitblit/manager/ServicesManager.java b/src/main/java/com/gitblit/manager/ServicesManager.java index 37215786..2550f66f 100644 --- a/src/main/java/com/gitblit/manager/ServicesManager.java +++ b/src/main/java/com/gitblit/manager/ServicesManager.java @@ -18,9 +18,15 @@ package com.gitblit.manager; import java.io.IOException; import java.net.URI; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -30,9 +36,11 @@ import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.FederationToken; +import com.gitblit.Constants.Transport; import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.fanout.FanoutNioService; @@ -40,14 +48,18 @@ import com.gitblit.fanout.FanoutService; import com.gitblit.fanout.FanoutSocketService; import com.gitblit.models.FederationModel; import com.gitblit.models.RepositoryModel; +import com.gitblit.models.RepositoryUrl; import com.gitblit.models.UserModel; import com.gitblit.service.FederationPullService; import com.gitblit.transport.git.GitDaemon; import com.gitblit.transport.ssh.SshDaemon; -import com.gitblit.utils.IdGenerator; +import com.gitblit.utils.HttpUtils; import com.gitblit.utils.StringUtils; import com.gitblit.utils.TimeUtils; import com.gitblit.utils.WorkQueue; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; /** * Services manager manages long-running services/processes that either have no @@ -57,32 +69,35 @@ import com.gitblit.utils.WorkQueue; * @author James Moger * */ -public class ServicesManager implements IManager { +@Singleton +public class ServicesManager implements IServicesManager { private final Logger logger = LoggerFactory.getLogger(getClass()); private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(5); + private final Provider workQueueProvider; + private final IStoredSettings settings; private final IGitblit gitblit; - private final IdGenerator idGenerator; - - private final WorkQueue workQueue; - private FanoutService fanoutService; private GitDaemon gitDaemon; private SshDaemon sshDaemon; - public ServicesManager(IGitblit gitblit) { - this.settings = gitblit.getSettings(); + @Inject + public ServicesManager( + Provider workQueueProvider, + IStoredSettings settings, + IGitblit gitblit) { + + this.workQueueProvider = workQueueProvider; + + this.settings = settings; this.gitblit = gitblit; - int defaultThreadPoolSize = settings.getInteger(Keys.execution.defaultThreadPoolSize, 1); - this.idGenerator = new IdGenerator(); - this.workQueue = new WorkQueue(idGenerator, defaultThreadPoolSize); } @Override @@ -107,24 +122,181 @@ public class ServicesManager implements IManager { if (sshDaemon != null) { sshDaemon.stop(); } - workQueue.stop(); + workQueueProvider.get().stop(); return this; } + protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) { + String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null); + if (StringUtils.isEmpty(gitblitUrl)) { + gitblitUrl = HttpUtils.getGitblitURL(request); + } + StringBuilder sb = new StringBuilder(); + sb.append(gitblitUrl); + sb.append(Constants.R_PATH); + sb.append(repository.name); + + // inject username into repository url if authentication is required + if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE) + && !StringUtils.isEmpty(username)) { + sb.insert(sb.indexOf("://") + 3, username + "@"); + } + return sb.toString(); + } + + /** + * Returns 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 getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { + if (user == null) { + user = UserModel.ANONYMOUS; + } + String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); + + List list = new ArrayList(); + + // http/https url + if (settings.getBoolean(Keys.git.enableGitServlet, true)) { + AccessPermission permission = user.getRepositoryPermission(repository).permission; + if (permission.exceeds(AccessPermission.NONE)) { + Transport transport = Transport.fromString(request.getScheme()); + if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(transport)) { + // downgrade the repo permission for this transport + // because it is not an acceptable PUSH transport + permission = AccessPermission.CLONE; + } + list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission)); + } + } + + // ssh daemon url + String sshDaemonUrl = getSshDaemonUrl(request, user, repository); + if (!StringUtils.isEmpty(sshDaemonUrl)) { + AccessPermission permission = user.getRepositoryPermission(repository).permission; + if (permission.exceeds(AccessPermission.NONE)) { + if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.SSH)) { + // downgrade the repo permission for this transport + // because it is not an acceptable PUSH transport + permission = AccessPermission.CLONE; + } + + list.add(new RepositoryUrl(sshDaemonUrl, permission)); + } + } + + // git daemon url + String gitDaemonUrl = getGitDaemonUrl(request, user, repository); + if (!StringUtils.isEmpty(gitDaemonUrl)) { + AccessPermission permission = getGitDaemonAccessPermission(user, repository); + if (permission.exceeds(AccessPermission.NONE)) { + if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.GIT)) { + // downgrade the repo permission for this transport + // because it is not an acceptable PUSH transport + permission = AccessPermission.CLONE; + } + 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)); + } + } + + // sort transports by highest permission and then by transport security + Collections.sort(list, new Comparator() { + + @Override + public int compare(RepositoryUrl o1, RepositoryUrl o2) { + if (!o1.isExternal() && o2.isExternal()) { + // prefer Gitblit over external + return -1; + } else if (o1.isExternal() && !o2.isExternal()) { + // prefer Gitblit over external + return 1; + } else if (o1.isExternal() && o2.isExternal()) { + // sort by Transport ordinal + return o1.transport.compareTo(o2.transport); + } else if (o1.permission.exceeds(o2.permission)) { + // prefer highest permission + return -1; + } else if (o2.permission.exceeds(o1.permission)) { + // prefer highest permission + return 1; + } + + // prefer more secure transports + return o1.transport.compareTo(o2.transport); + } + }); + + // consider the user's transport preference + RepositoryUrl preferredUrl = null; + Transport preferredTransport = user.getPreferences().getTransport(); + if (preferredTransport != null) { + Iterator itr = list.iterator(); + while (itr.hasNext()) { + RepositoryUrl url = itr.next(); + if (url.transport.equals(preferredTransport)) { + itr.remove(); + preferredUrl = url; + break; + } + } + } + if (preferredUrl != null) { + list.add(0, preferredUrl); + } + + return list; + } + + /* (non-Javadoc) + * @see com.gitblit.manager.IServicesManager#isServingRepositories() + */ + @Override public boolean isServingRepositories() { return isServingHTTP() || isServingGIT() || isServingSSH(); } + /* (non-Javadoc) + * @see com.gitblit.manager.IServicesManager#isServingHTTP() + */ + @Override public boolean isServingHTTP() { return settings.getBoolean(Keys.git.enableGitServlet, true); } + /* (non-Javadoc) + * @see com.gitblit.manager.IServicesManager#isServingGIT() + */ + @Override public boolean isServingGIT() { return gitDaemon != null && gitDaemon.isRunning(); } + /* (non-Javadoc) + * @see com.gitblit.manager.IServicesManager#isServingSSH() + */ + @Override public boolean isServingSSH() { return sshDaemon != null && sshDaemon.isRunning(); } @@ -158,6 +330,32 @@ public class ServicesManager implements IManager { } } + protected boolean acceptPush(Transport byTransport) { + if (byTransport == null) { + logger.info("Unknown transport, push rejected!"); + return false; + } + + Set transports = new HashSet(); + for (String value : settings.getStrings(Keys.git.acceptedPushTransports)) { + Transport transport = Transport.fromString(value); + if (transport == null) { + logger.info(String.format("Ignoring unknown registered transport %s", value)); + continue; + } + + transports.add(transport); + } + + if (transports.isEmpty()) { + // no transports are explicitly specified, all are acceptable + return true; + } + + // verify that the transport is permitted + return transports.contains(byTransport); + } + protected void configureGitDaemon() { int port = settings.getInteger(Keys.git.daemonPort, 0); String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost"); @@ -179,7 +377,7 @@ public class ServicesManager implements IManager { String bindInterface = settings.getString(Keys.git.sshBindInterface, "localhost"); if (port > 0) { try { - sshDaemon = new SshDaemon(gitblit, workQueue); + sshDaemon = new SshDaemon(gitblit, workQueueProvider.get()); sshDaemon.start(); } catch (IOException e) { sshDaemon = null; @@ -285,7 +483,7 @@ public class ServicesManager implements IManager { */ protected String getHostname(HttpServletRequest request) { String hostname = request.getServerName(); - String canonicalUrl = gitblit.getSettings().getString(Keys.web.canonicalUrl, null); + String canonicalUrl = settings.getString(Keys.web.canonicalUrl, null); if (!StringUtils.isEmpty(canonicalUrl)) { try { URI uri = new URI(canonicalUrl); diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java index e0f6003c..44a857ca 100644 --- a/src/main/java/com/gitblit/servlet/GitblitContext.java +++ b/src/main/java/com/gitblit/servlet/GitblitContext.java @@ -51,6 +51,7 @@ import com.gitblit.manager.IPluginManager; import com.gitblit.manager.IProjectManager; import com.gitblit.manager.IRepositoryManager; import com.gitblit.manager.IRuntimeManager; +import com.gitblit.manager.IServicesManager; import com.gitblit.manager.IUserManager; import com.gitblit.transport.ssh.IPublicKeyManager; import com.gitblit.utils.ContainerUtils; @@ -200,6 +201,7 @@ public class GitblitContext extends GuiceServletContextListener { startManager(injector, IProjectManager.class); startManager(injector, IFederationManager.class); startManager(injector, IGitblit.class); + startManager(injector, IServicesManager.class); // start the plugin manager last so that plugins can depend on // deterministic access to all other managers in their start() methods diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java index a9073110..24468c0b 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -21,9 +21,6 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; -import com.google.inject.Inject; -import com.google.inject.Singleton; - import org.apache.wicket.Application; import org.apache.wicket.Request; import org.apache.wicket.Response; @@ -46,6 +43,7 @@ import com.gitblit.manager.IPluginManager; import com.gitblit.manager.IProjectManager; import com.gitblit.manager.IRepositoryManager; import com.gitblit.manager.IRuntimeManager; +import com.gitblit.manager.IServicesManager; import com.gitblit.manager.IUserManager; import com.gitblit.tickets.ITicketService; import com.gitblit.transport.ssh.IPublicKeyManager; @@ -92,6 +90,8 @@ import com.gitblit.wicket.pages.TicketsPage; import com.gitblit.wicket.pages.TreePage; import com.gitblit.wicket.pages.UserPage; import com.gitblit.wicket.pages.UsersPage; +import com.google.inject.Inject; +import com.google.inject.Singleton; @Singleton public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { @@ -124,6 +124,8 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { private final IGitblit gitblit; + private final IServicesManager services; + @Inject public GitBlitWebApp( IRuntimeManager runtimeManager, @@ -135,7 +137,8 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { IRepositoryManager repositoryManager, IProjectManager projectManager, IFederationManager federationManager, - IGitblit gitblit) { + IGitblit gitblit, + IServicesManager services) { super(); this.settings = runtimeManager.getSettings(); @@ -149,6 +152,7 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { this.projectManager = projectManager; this.federationManager = federationManager; this.gitblit = gitblit; + this.services = services; } @Override @@ -420,6 +424,14 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { return gitblit; } + /* (non-Javadoc) + * @see com.gitblit.wicket.Webapp#services() + */ + @Override + public IServicesManager services() { + return services; + } + /* (non-Javadoc) * @see com.gitblit.wicket.Webapp#tickets() */ diff --git a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java index a56e6996..7013097c 100644 --- a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java +++ b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java @@ -14,6 +14,7 @@ import com.gitblit.manager.IPluginManager; import com.gitblit.manager.IProjectManager; import com.gitblit.manager.IRepositoryManager; import com.gitblit.manager.IRuntimeManager; +import com.gitblit.manager.IServicesManager; import com.gitblit.manager.IUserManager; import com.gitblit.tickets.ITicketService; import com.gitblit.transport.ssh.IPublicKeyManager; @@ -65,6 +66,8 @@ public interface GitblitWicketApp { public abstract IGitblit gitblit(); + public abstract IServicesManager services(); + public abstract ITicketService tickets(); public abstract TimeZone getTimezone(); diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java index b3c52436..72d1e1a4 100644 --- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java @@ -55,7 +55,7 @@ public class EmptyRepositoryPage extends RepositoryPage { } HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest(); - List repositoryUrls = app().gitblit().getRepositoryUrls(req, user, repository); + List repositoryUrls = app().services().getRepositoryUrls(req, user, repository); RepositoryUrl primaryUrl = repositoryUrls.size() == 0 ? null : repositoryUrls.get(0); String url = primaryUrl != null ? primaryUrl.url : ""; diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.java b/src/main/java/com/gitblit/wicket/pages/TicketPage.java index f5f63d23..e1e81628 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.java @@ -1505,7 +1505,7 @@ public class TicketPage extends RepositoryPage { */ protected RepositoryUrl getRepositoryUrl(UserModel user, RepositoryModel repository) { HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest(); - List urls = app().gitblit().getRepositoryUrls(req, user, repository); + List urls = app().services().getRepositoryUrls(req, user, repository); if (ArrayUtils.isEmpty(urls)) { return null; } diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 8931d5e3..e21431d9 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -104,7 +104,7 @@ public class UserPage extends RootPage { if (isMyProfile) { addPreferences(user); - if (app().gitblit().isServingSSH()) { + if (app().services().isServingSSH()) { // show the SSH key management tab addSshKeys(user); } else { @@ -248,14 +248,14 @@ public class UserPage extends RootPage { emailMeOnMyTicketChanges).setVisible(app().notifier().isSendingMail())); List availableTransports = new ArrayList<>(); - if (app().gitblit().isServingSSH()) { + if (app().services().isServingSSH()) { availableTransports.add(Transport.SSH); } - if (app().gitblit().isServingHTTP()) { + if (app().services().isServingHTTP()) { availableTransports.add(Transport.HTTPS); availableTransports.add(Transport.HTTP); } - if (app().gitblit().isServingGIT()) { + if (app().services().isServingGIT()) { availableTransports.add(Transport.GIT); } diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java index 938226a6..0666fcd8 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java @@ -80,7 +80,7 @@ public class RepositoryUrlPanel extends BasePanel { HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest(); - List repositoryUrls = app().gitblit().getRepositoryUrls(req, user, repository); + List repositoryUrls = app().services().getRepositoryUrls(req, user, repository); // grab primary url from the top of the list primaryUrl = repositoryUrls.size() == 0 ? null : repositoryUrls.get(0); @@ -165,7 +165,7 @@ public class RepositoryUrlPanel extends BasePanel { if (repository.isMirror) { urlPanel.add(WicketUtils.newImage("accessRestrictionIcon", "mirror_16x16.png", getString("gb.isMirror"))); - } else if (app().gitblit().isServingRepositories()) { + } else if (app().services().isServingRepositories()) { switch (repository.accessRestriction) { case NONE: urlPanel.add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false)); diff --git a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java index 36a0218e..9a71c884 100644 --- a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java +++ b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java @@ -82,26 +82,6 @@ public class MockRuntimeManager implements IRuntimeManager { return Locale.getDefault(); } - @Override - public boolean isServingRepositories() { - return true; - } - - @Override - public boolean isServingHTTP() { - return true; - } - - @Override - public boolean isServingGIT() { - return true; - } - - @Override - public boolean isServingSSH() { - return true; - } - @Override public boolean isDebugMode() { return true; -- 2.39.5