From a40cbcfc4fab2ca16304c7393a68fe95a9322edc Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Thu, 03 Jul 2014 18:07:16 -0400
Subject: [PATCH] Merged #80 "Replace Dagger with Guice"

---
 src/main/java/com/gitblit/manager/IRuntimeManager.java             |   39 
 .classpath                                                         |    8 
 src/main/java/com/gitblit/Constants.java                           |    2 
 src/main/java/com/gitblit/manager/UserManager.java                 |    4 
 src/main/java/com/gitblit/servlet/PagesFilter.java                 |   17 
 src/main/java/com/gitblit/wicket/GitBlitWebApp.java                |   36 
 src/main/java/com/gitblit/servlet/LogoServlet.java                 |   15 
 src/main/java/com/gitblit/servlet/FederationServlet.java           |   22 
 src/main/java/com/gitblit/guice/WebModule.java                     |  105 +
 src/main/java/com/gitblit/manager/ProjectManager.java              |    4 
 src/main/java/com/gitblit/transport/ssh/FileKeyManager.java        |    2 
 src/main/java/com/gitblit/manager/IGitblit.java                    |   15 
 src/main/java/com/gitblit/manager/PluginManager.java               |   57 
 src/main/java/com/gitblit/manager/FederationManager.java           |    4 
 src/main/java/com/gitblit/servlet/JsonServlet.java                 |    4 
 src/main/java/com/gitblit/manager/NotificationManager.java         |    4 
 src/main/java/com/gitblit/manager/IServicesManager.java            |   75 +
 src/main/java/com/gitblit/servlet/RpcServlet.java                  |   13 
 src/main/java/com/gitblit/wicket/pages/TicketPage.java             |    2 
 src/main/java/com/gitblit/wicket/pages/UserPage.java               |    8 
 src/main/java/com/gitblit/GitBlit.java                             |  444 --------
 src/main/java/com/gitblit/servlet/RpcFilter.java                   |   22 
 src/main/java/com/gitblit/tickets/NullTicketService.java           |    5 
 src/main/java/com/gitblit/transport/ssh/NullKeyManager.java        |    3 
 src/main/java/com/gitblit/wicket/GitblitWicketApp.java             |    3 
 src/main/java/com/gitblit/servlet/SyndicationServlet.java          |   24 
 src/main/java/com/gitblit/servlet/AuthenticationFilter.java        |   17 
 src/main/java/com/gitblit/manager/AuthenticationManager.java       |    4 
 src/main/java/com/gitblit/servlet/RawServlet.java                  |   24 
 src/main/java/com/gitblit/tickets/ITicketService.java              |    5 
 releases.moxie                                                     |    1 
 gitblit.iml                                                        |   40 
 NOTICE                                                             |    9 
 src/main/java/WEB-INF/web.xml                                      |  408 ------
 src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java     |   18 
 src/main/java/com/gitblit/manager/RuntimeManager.java              |   59 
 src/main/java/com/gitblit/servlet/SyndicationFilter.java           |   24 
 src/site/design.mkd                                                |    1 
 src/main/java/com/gitblit/guice/WorkQueueProvider.java             |   57 +
 src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java     |   72 +
 src/main/java/com/gitblit/manager/GitblitManager.java              |  163 +-
 src/main/java/com/gitblit/manager/ServicesManager.java             |  226 ++++
 src/main/java/com/gitblit/servlet/GitServlet.java                  |   18 
 src/main/java/com/gitblit/manager/RepositoryManager.java           |   34 
 src/main/java/com/gitblit/servlet/RawFilter.java                   |   16 
 src/main/java/com/gitblit/tickets/FileTicketService.java           |    5 
 src/main/java/com/gitblit/servlet/GitblitContext.java              |   71 
 src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java      |    3 
 src/main/java/com/gitblit/servlet/BranchGraphServlet.java          |   25 
 src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java    |    4 
 src/main/java/com/gitblit/servlet/PagesServlet.java                |   13 
 src/main/java/com/gitblit/wicket/GitblitWicketFilter.java          |   28 
 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java    |    2 
 src/main/java/com/gitblit/servlet/ProxyFilter.java                 |   33 
 src/main/java/com/gitblit/servlet/GitFilter.java                   |   26 
 src/main/java/com/gitblit/servlet/PtServlet.java                   |   15 
 src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java   |   26 
 /dev/null                                                          |   45 
 src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java |   34 
 src/main/java/com/gitblit/guice/ITicketServiceProvider.java        |   73 +
 src/main/java/com/gitblit/FederationClient.java                    |  378 +++---
 build.xml                                                          |   10 
 src/main/java/com/gitblit/tickets/BranchTicketService.java         |    5 
 src/main/java/com/gitblit/tickets/RedisTicketService.java          |    8 
 build.moxie                                                        |   33 
 src/main/java/com/gitblit/servlet/DownloadZipFilter.java           |   16 
 src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java       |   26 
 src/main/java/com/gitblit/guice/CoreModule.java                    |   79 +
 src/main/java/com/gitblit/servlet/RobotsTxtServlet.java            |   15 
 src/main/java/com/gitblit/servlet/DownloadZipServlet.java          |   17 
 70 files changed, 1,584 insertions(+), 1,539 deletions(-)

diff --git a/.classpath b/.classpath
index c5fe4e5..9873ddb 100644
--- a/.classpath
+++ b/.classpath
@@ -5,10 +5,11 @@
 	<classpathentry kind="src" path="src/test/java" output="bin/test-classes" />
 	<classpathentry kind="src" path="src/test/bugtraq" output="bin/test-classes" />
 	<classpathentry kind="src" path="src/main/resources" />
-	<classpathentry kind="lib" path="ext/dagger-1.1.0.jar" sourcepath="ext/src/dagger-1.1.0.jar" />
+	<classpathentry kind="lib" path="ext/guice-4.0-beta4.jar" sourcepath="ext/src/guice-4.0-beta4.jar" />
 	<classpathentry kind="lib" path="ext/javax.inject-1.jar" sourcepath="ext/src/javax.inject-1.jar" />
-	<classpathentry kind="lib" path="ext/dagger-compiler-1.1.0.jar" sourcepath="ext/src/dagger-compiler-1.1.0.jar" />
-	<classpathentry kind="lib" path="ext/javawriter-2.1.1.jar" sourcepath="ext/src/javawriter-2.1.1.jar" />
+	<classpathentry kind="lib" path="ext/aopalliance-1.0.jar" sourcepath="ext/src/aopalliance-1.0.jar" />
+	<classpathentry kind="lib" path="ext/guava-17.0.jar" sourcepath="ext/src/guava-17.0.jar" />
+	<classpathentry kind="lib" path="ext/guice-servlet-4.0-gb1.jar" sourcepath="ext/src/guice-servlet-4.0-gb1.jar" />
 	<classpathentry kind="lib" path="ext/annotations-12.0.jar" sourcepath="ext/src/annotations-12.0.jar" />
 	<classpathentry kind="lib" path="ext/log4j-1.2.17.jar" sourcepath="ext/src/log4j-1.2.17.jar" />
 	<classpathentry kind="lib" path="ext/slf4j-api-1.7.7.jar" sourcepath="ext/src/slf4j-api-1.7.7.jar" />
@@ -70,7 +71,6 @@
 	<classpathentry kind="lib" path="ext/waffle-jna-1.5.jar" sourcepath="ext/src/waffle-jna-1.5.jar" />
 	<classpathentry kind="lib" path="ext/platform-3.5.0.jar" sourcepath="ext/src/platform-3.5.0.jar" />
 	<classpathentry kind="lib" path="ext/jna-3.5.0.jar" sourcepath="ext/src/jna-3.5.0.jar" />
-	<classpathentry kind="lib" path="ext/guava-13.0.1.jar" sourcepath="ext/src/guava-13.0.1.jar" />
 	<classpathentry kind="lib" path="ext/libpam4j-1.7.jar" sourcepath="ext/src/libpam4j-1.7.jar" />
 	<classpathentry kind="lib" path="ext/args4j-2.0.26.jar" sourcepath="ext/src/args4j-2.0.26.jar" />
 	<classpathentry kind="lib" path="ext/jedis-2.3.1.jar" sourcepath="ext/src/jedis-2.3.1.jar" />
diff --git a/NOTICE b/NOTICE
index da61b20..69d7c74 100644
--- a/NOTICE
+++ b/NOTICE
@@ -358,3 +358,12 @@
    Apache License 2.0
 
    https://github.com/decebals/pf4j
+
+---------------------------------------------------------------------------
+google-guice
+---------------------------------------------------------------------------
+   google-guice, release under the 
+   Apache License 2.0
+
+   https://code.google.com/p/google-guice
+   
\ No newline at end of file
diff --git a/build.moxie b/build.moxie
index 121192e..3f18bf5 100644
--- a/build.moxie
+++ b/build.moxie
@@ -96,9 +96,10 @@
 - { id: eclipse, url: 'http://repo.eclipse.org/content/groups/releases' }
 - { id: eclipse-snapshots, url: 'http://repo.eclipse.org/content/groups/snapshots' }
 - { id: atlassian-contrib, url: 'https://maven.atlassian.com/content/repositories/atlassian-3rdparty' }
+- { id: gitblit, url: 'http://gitblit.github.io/gitblit-maven' }
 
 # Source all dependencies from the following repositories in the specified order
-repositories: central, eclipse-snapshots, eclipse, atlassian-contrib
+repositories: central, eclipse-snapshots, eclipse, atlassian-contrib, gitblit
 
 # Convenience properties for dependencies
 properties: {
@@ -112,6 +113,9 @@
   wikitext.version : 1.4
   sshd.version: 0.11.1-atlassian-1
   mina.version: 2.0.7
+  guice.version : 4.0-beta4
+  # Gitblit maintains a fork of guice-servlet
+  guice-servlet.version : 4.0-gb1
   }
 
 # Dependencies
@@ -126,15 +130,14 @@
 #
 
 dependencies:
-# Dagger dependency injection library (annotation processor)
-- compile 'com.squareup.dagger:dagger:1.1.0' :war apt
-- compile 'com.squareup.dagger:dagger-compiler:1.1.0' :war optional apt
-# Standard dependencies
+- compile 'com.google.inject:guice:${guice.version}' :war :fedclient
+- compile 'com.google.inject.extensions:guice-servlet:${guice-servlet.version}' :war
+- compile 'com.google.guava:guava:17.0' :war :fedclient
 - compile 'com.intellij:annotations:12.0' :war
-- compile 'log4j:log4j:1.2.17' :war :fedclient :authority
-- compile 'org.slf4j:slf4j-api:1.7.7' :war :fedclient :authority
-- compile 'org.slf4j:slf4j-log4j12:1.7.7' :war :fedclient :authority
-- compile 'com.sun.mail:javax.mail:1.5.1' :war :authority
+- compile 'log4j:log4j:1.2.17' :war :fedclient
+- compile 'org.slf4j:slf4j-api:1.7.7' :war :fedclient
+- compile 'org.slf4j:slf4j-log4j12:1.7.7' :war :fedclient
+- compile 'com.sun.mail:javax.mail:1.5.1' :war
 - compile 'javax.servlet:javax.servlet-api:3.1.0' :fedclient
 - compile 'org.eclipse.jetty.aggregate:jetty-all:${jetty.version}' @jar
 - compile 'org.apache.wicket:wicket:${wicket.version}' :war !org.mockito
@@ -152,11 +155,11 @@
 - compile 'org.fusesource.wikitext:tracwiki-core:${wikitext.version}' :war
 - compile 'org.fusesource.wikitext:mediawiki-core:${wikitext.version}' :war
 - compile 'org.fusesource.wikitext:confluence-core:${wikitext.version}' :war
-- compile 'org.eclipse.jgit:org.eclipse.jgit:${jgit.version}' :war :fedclient :manager :authority !junit
-- compile 'org.eclipse.jgit:org.eclipse.jgit.http.server:${jgit.version}' :war :manager :authority !junit
-- compile 'org.bouncycastle:bcprov-jdk15on:${bouncycastle.version}' :war :authority
-- compile 'org.bouncycastle:bcmail-jdk15on:${bouncycastle.version}' :war :authority
-- compile 'org.bouncycastle:bcpkix-jdk15on:${bouncycastle.version}' :war :authority
+- compile 'org.eclipse.jgit:org.eclipse.jgit:${jgit.version}' :war :fedclient :manager !junit
+- compile 'org.eclipse.jgit:org.eclipse.jgit.http.server:${jgit.version}' :war :manager !junit
+- compile 'org.bouncycastle:bcprov-jdk15on:${bouncycastle.version}' :war
+- compile 'org.bouncycastle:bcmail-jdk15on:${bouncycastle.version}' :war
+- compile 'org.bouncycastle:bcpkix-jdk15on:${bouncycastle.version}' :war
 - compile 'org.apache.sshd:sshd-core:${sshd.version}' :war !org.easymock
 - compile 'org.apache.mina:mina-core:${mina.version}' :war !org.easymock
 - compile 'rome:rome:0.9' :war :manager :api
@@ -171,7 +174,7 @@
 - compile 'org.freemarker:freemarker:2.3.20' :war
 - compile 'com.github.dblock.waffle:waffle-jna:1.5' :war
 - compile 'org.kohsuke:libpam4j:1.7' :war
-- compile 'args4j:args4j:2.0.26' :war :fedclient :authority
+- compile 'args4j:args4j:2.0.26' :war :fedclient
 - compile 'commons-codec:commons-codec:1.7' :war
 - compile 'redis.clients:jedis:2.3.1' :war
 - compile 'ro.fortsoft.pf4j:pf4j:0.8.0' :war
diff --git a/build.xml b/build.xml
index e4c7a10..8128f6f 100644
--- a/build.xml
+++ b/build.xml
@@ -295,7 +295,7 @@
 			 classes, exclude any classes in classpath jars -->
 		<mx:genjar tag="" includeresources="false" excludeClasspathJars="true"
 			destfile="${project.targetDirectory}/fedclient.jar"
-			excludes="**/.class,**/*.java, **/Thumbs.db, **/*.mkd, com/gitblit/wicket/**">
+			excludes="**/.class, **/*.java, **/Thumbs.db, **/*.mkd, **/*.md, **/*.css, com/gitblit/wicket/**">
 			<mainclass name="com.gitblit.FederationClient" />
 			<class name="com.gitblit.Keys" />
 			<launcher paths="ext" />
@@ -335,7 +335,8 @@
 		<!-- generate jar by traversing the class hierarchy of the specified
 			 classes, exclude any classes in classpath jars -->
 		<mx:genjar tag="" includeResources="false" excludeClasspathJars="true"
-			destfile="${project.targetDirectory}/manager.jar">
+			destfile="${project.targetDirectory}/manager.jar"
+			excludes="**/.class, **/*.java, **/Thumbs.db, **/*.mkd, **/*.md, **/*.css, com/gitblit/wicket/**">
 			<resource file="${project.src.dir}/com/gitblit/client/splash.png" />
 			<resource file="${project.resources.dir}/gitblt-favicon.png" />
 			<resource file="${project.resources.dir}/gitweb-favicon.png" />
@@ -411,9 +412,10 @@
 
 		<!-- Build API Library jar -->
 		<mx:genjar tag="" includeResources="false" excludeClasspathJars="true"
-			destfile="${project.targetDirectory}/gbapi-${project.version}.jar">
+			destfile="${project.targetDirectory}/gbapi-${project.version}.jar"
+			excludes="**/.class, **/*.java, **/Thumbs.db, **/*.mkd, **/*.md, **/*.css, com/gitblit/wicket/**">
+			<mainclass name="com.gitblit.client.GitblitClient" />
 			<class name="com.gitblit.Keys" />
-			<class name="com.gitblit.client.GitblitClient" />
 			<class name="com.gitblit.models.FederationModel" />
 			<class name="com.gitblit.models.FederationProposal" />
 			<class name="com.gitblit.models.FederationSet" />			
diff --git a/gitblit.iml b/gitblit.iml
index 5f985a5..878fdc3 100644
--- a/gitblit.iml
+++ b/gitblit.iml
@@ -14,13 +14,13 @@
     </content>
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="module-library">
-      <library name="dagger-1.1.0.jar">
+      <library name="guice-4.0-beta4.jar">
         <CLASSES>
-          <root url="jar://$MODULE_DIR$/ext/dagger-1.1.0.jar!/" />
+          <root url="jar://$MODULE_DIR$/ext/guice-4.0-beta4.jar!/" />
         </CLASSES>
         <JAVADOC />
         <SOURCES>
-          <root url="jar://$MODULE_DIR$/ext/src/dagger-1.1.0.jar!/" />
+          <root url="jar://$MODULE_DIR$/ext/src/guice-4.0-beta4.jar!/" />
         </SOURCES>
       </library>
     </orderEntry>
@@ -36,24 +36,35 @@
       </library>
     </orderEntry>
     <orderEntry type="module-library">
-      <library name="dagger-compiler-1.1.0.jar">
+      <library name="aopalliance-1.0.jar">
         <CLASSES>
-          <root url="jar://$MODULE_DIR$/ext/dagger-compiler-1.1.0.jar!/" />
+          <root url="jar://$MODULE_DIR$/ext/aopalliance-1.0.jar!/" />
         </CLASSES>
         <JAVADOC />
         <SOURCES>
-          <root url="jar://$MODULE_DIR$/ext/src/dagger-compiler-1.1.0.jar!/" />
+          <root url="jar://$MODULE_DIR$/ext/src/aopalliance-1.0.jar!/" />
         </SOURCES>
       </library>
     </orderEntry>
     <orderEntry type="module-library">
-      <library name="javawriter-2.1.1.jar">
+      <library name="guava-17.0.jar">
         <CLASSES>
-          <root url="jar://$MODULE_DIR$/ext/javawriter-2.1.1.jar!/" />
+          <root url="jar://$MODULE_DIR$/ext/guava-17.0.jar!/" />
         </CLASSES>
         <JAVADOC />
         <SOURCES>
-          <root url="jar://$MODULE_DIR$/ext/src/javawriter-2.1.1.jar!/" />
+          <root url="jar://$MODULE_DIR$/ext/src/guava-17.0.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library name="guice-servlet-4.0-gb1.jar">
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/ext/guice-servlet-4.0-gb1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/ext/src/guice-servlet-4.0-gb1.jar!/" />
         </SOURCES>
       </library>
     </orderEntry>
@@ -721,17 +732,6 @@
         <JAVADOC />
         <SOURCES>
           <root url="jar://$MODULE_DIR$/ext/src/jna-3.5.0.jar!/" />
-        </SOURCES>
-      </library>
-    </orderEntry>
-    <orderEntry type="module-library">
-      <library name="guava-13.0.1.jar">
-        <CLASSES>
-          <root url="jar://$MODULE_DIR$/ext/guava-13.0.1.jar!/" />
-        </CLASSES>
-        <JAVADOC />
-        <SOURCES>
-          <root url="jar://$MODULE_DIR$/ext/src/guava-13.0.1.jar!/" />
         </SOURCES>
       </library>
     </orderEntry>
diff --git a/releases.moxie b/releases.moxie
index 61c43c4..e99cbd5 100644
--- a/releases.moxie
+++ b/releases.moxie
@@ -24,6 +24,7 @@
     - Jetty 9.2.1 (pr-202)
     - Lucene 4.8.1 (pr-201)
     - JGit 3.4.0 (pr-200)
+    - Guice 4.0-beta4 (ticket-80)
     - SLF4j 1.7.7 (ticket-122)
     - gson 2.2.2 (ticket-123)
     - Freemarker 2.3.20 (ticket-124)
diff --git a/src/main/java/WEB-INF/web.xml b/src/main/java/WEB-INF/web.xml
index 13f612e..8842224 100644
--- a/src/main/java/WEB-INF/web.xml
+++ b/src/main/java/WEB-INF/web.xml
@@ -1,361 +1,49 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<web-app version="2.4"
-	xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
-
-	<!-- The base folder is used to specify the root location of your Gitblit data.
-	
-			${baseFolder}/gitblit.properties
-			${baseFolder}/users.conf
-			${baseFolder}/projects.conf
-			${baseFolder}/robots.txt
-			${baseFolder}/git
-			${baseFolder}/groovy
-			${baseFolder}/groovy/grape
-			${baseFolder}/proposals
-
-		By default, this location is WEB-INF/data.  It is recommended to set this
-		path to a location outside your webapps folder that is writable by your
-		servlet container.  Gitblit will copy the WEB-INF/data files to that
-		location for you when it restarts.  This approach makes upgrading simpler.
-		All you have to do is set this parameter for the new release and then
-		review the defaults for any new settings.  Settings are always versioned
-		with a SINCE x.y.z attribute and also noted in the release changelog.
-		-->
-	<env-entry>
-		<description>The base folder is used to specify the root location of your Gitblit data.</description>
-		<env-entry-name>baseFolder</env-entry-name>
-		<env-entry-type>java.lang.String</env-entry-type>
-		<env-entry-value>${contextFolder}/WEB-INF/data</env-entry-value>
-	</env-entry>
-	
-	<!-- Gitblit Displayname -->
-	<display-name>Gitblit - @gb.version@</display-name>
-
-	 
-<!-- Gitblit Context Listener --><!-- STRIP	 
-	<listener>
- 		<listener-class>com.gitblit.servlet.GitblitContext</listener-class>
- 	</listener>STRIP --> 	
-	
-	
-	<!-- Git Servlet
-		 <url-pattern> MUST match: 
-			* GitFilter
-			* com.gitblit.Constants.GIT_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>GitServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.GitServlet</servlet-class>
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>GitServlet</servlet-name>		
-		<url-pattern>/git/*</url-pattern>
-	</servlet-mapping>
-	<servlet-mapping>
-		<servlet-name>GitServlet</servlet-name>		
-		<url-pattern>/r/*</url-pattern>
-	</servlet-mapping>
-
-	
-	<!-- SparkleShare Invite Servlet
-		 <url-pattern> MUST match: 
-			* com.gitblit.Constants.SPARKLESHARE_INVITE_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>SparkleShareInviteServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.SparkleShareInviteServlet</servlet-class>
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>SparkleShareInviteServlet</servlet-name>		
-		<url-pattern>/sparkleshare/*</url-pattern>
-	</servlet-mapping>
-
-	
-	<!-- Syndication Servlet
-		 <url-pattern> MUST match: 
-			* SyndicationFilter
-			* com.gitblit.Constants.SYNDICATION_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>SyndicationServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.SyndicationServlet</servlet-class>		
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>SyndicationServlet</servlet-name>
-		<url-pattern>/feed/*</url-pattern>
-	</servlet-mapping>
-	
-	
-	<!-- Zip Servlet
-		 <url-pattern> MUST match: 
-			* ZipServlet
-			* com.gitblit.Constants.ZIP_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>ZipServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.DownloadZipServlet</servlet-class>		
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>ZipServlet</servlet-name>
-		<url-pattern>/zip/*</url-pattern>
-	</servlet-mapping>
-	
-	
-	<!-- Federation Servlet
-		 <url-pattern> MUST match: 
-		 	* com.gitblit.Constants.FEDERATION_PATH		 
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>FederationServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.FederationServlet</servlet-class>		
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>FederationServlet</servlet-name>
-		<url-pattern>/federation/*</url-pattern>
-	</servlet-mapping>	
-	
-	
-	<!-- Rpc Servlet
-		 <url-pattern> MUST match: 
-		 	* com.gitblit.Constants.RPC_PATH		 
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>RpcServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.RpcServlet</servlet-class>		
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>RpcServlet</servlet-name>
-		<url-pattern>/rpc/*</url-pattern>
-	</servlet-mapping>	
-
-
-	<!-- Raw Servlet
-		 <url-pattern> MUST match: 
-			* RawFilter
-			* com.gitblit.Constants.RAW_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>RawServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.RawServlet</servlet-class>
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>RawServlet</servlet-name>		
-		<url-pattern>/raw/*</url-pattern>
-	</servlet-mapping>	
-
-
-	<!-- Pages Servlet
-		 <url-pattern> MUST match: 
-			* PagesFilter
-			* com.gitblit.Constants.PAGES_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>PagesServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.PagesServlet</servlet-class>
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>PagesServlet</servlet-name>		
-		<url-pattern>/pages/*</url-pattern>
-	</servlet-mapping>	
-
-	
-	<!-- Logo Servlet
-		 <url-pattern> MUST match: 
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>LogoServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.LogoServlet</servlet-class>
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>LogoServlet</servlet-name>		
-		<url-pattern>/logo.png</url-pattern>
-	</servlet-mapping>
-
-
-	<!-- PT Servlet
-		 <url-pattern> MUST match: 
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>PtServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.PtServlet</servlet-class>
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>PtServlet</servlet-name>		
-		<url-pattern>/pt</url-pattern>
-	</servlet-mapping>
-
-
-	<!-- Branch Graph Servlet
-		 <url-pattern> MUST match: 
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>BranchGraphServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.BranchGraphServlet</servlet-class>
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>BranchGraphServlet</servlet-name>		
-		<url-pattern>/graph/*</url-pattern>
-	</servlet-mapping>
-
-	<!-- Robots.txt Servlet
-		 <url-pattern> MUST match: 
-			* Wicket Filter ignorePaths parameter -->
-	<servlet>
-		<servlet-name>RobotsTxtServlet</servlet-name>
-		<servlet-class>com.gitblit.servlet.RobotsTxtServlet</servlet-class>
-	</servlet>
-	<servlet-mapping>
-		<servlet-name>RobotsTxtServlet</servlet-name>		
-		<url-pattern>/robots.txt</url-pattern>
-	</servlet-mapping>
-
-    <filter>
-		<filter-name>ProxyFilter</filter-name>
-		<filter-class>com.gitblit.servlet.ProxyFilter</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>ProxyFilter</filter-name>
-		<url-pattern>/*</url-pattern>
-	</filter-mapping>
-	
-	<!-- Git Access Restriction Filter
-		 <url-pattern> MUST match: 
-			* GitServlet
-			* com.gitblit.Constants.GIT_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<filter>
-		<filter-name>GitFilter</filter-name>
-		<filter-class>com.gitblit.servlet.GitFilter</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>GitFilter</filter-name>
-		<url-pattern>/git/*</url-pattern>
-	</filter-mapping>
-	<filter-mapping>
-		<filter-name>GitFilter</filter-name>
-		<url-pattern>/r/*</url-pattern>
-	</filter-mapping>
-	
-	
-	<!-- Syndication Restriction Filter
-		 <url-pattern> MUST match: 
-			* SyndicationServlet
-			* com.gitblit.Constants.SYNDICATION_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<filter>
-		<filter-name>SyndicationFilter</filter-name>
-		<filter-class>com.gitblit.servlet.SyndicationFilter</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>SyndicationFilter</filter-name>
-		<url-pattern>/feed/*</url-pattern>
-	</filter-mapping>
-	
-	
-	<!-- Download Zip Restriction Filter
-		 <url-pattern> MUST match: 
-			* DownloadZipServlet
-			* com.gitblit.Constants.ZIP_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<filter>
-		<filter-name>ZipFilter</filter-name>
-		<filter-class>com.gitblit.servlet.DownloadZipFilter</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>ZipFilter</filter-name>
-		<url-pattern>/zip/*</url-pattern>
-	</filter-mapping>
-
-		
-	<!-- Rpc Restriction Filter
-		 <url-pattern> MUST match: 
-			* RpcServlet
-			* com.gitblit.Constants.RPC_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<filter>
-		<filter-name>RpcFilter</filter-name>
-		<filter-class>com.gitblit.servlet.RpcFilter</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>RpcFilter</filter-name>
-		<url-pattern>/rpc/*</url-pattern>
-	</filter-mapping>
-
-
-	<!-- Branch Restriction Filter
-		 <url-pattern> MUST match: 
-			* RawServlet
-			* com.gitblit.Constants.BRANCH_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<filter>
-		<filter-name>RawFilter</filter-name>
-		<filter-class>com.gitblit.servlet.RawFilter</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>RawFilter</filter-name>
-		<url-pattern>/raw/*</url-pattern>
-	</filter-mapping>
-	
-
-	<!-- Pages Restriction Filter
-		 <url-pattern> MUST match: 
-			* PagesServlet
-			* com.gitblit.Constants.PAGES_PATH
-			* Wicket Filter ignorePaths parameter -->
-	<filter>
-		<filter-name>PagesFilter</filter-name>
-		<filter-class>com.gitblit.servlet.PagesFilter</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>PagesFilter</filter-name>
-		<url-pattern>/pages/*</url-pattern>
-	</filter-mapping>
-	
-	<filter>
-		<filter-name>EnforceAuthenticationFilter</filter-name>
-		<filter-class>com.gitblit.servlet.EnforceAuthenticationFilter</filter-class>
-	</filter>
-	<filter-mapping>
-        <filter-name>EnforceAuthenticationFilter</filter-name>
-        <url-pattern>/*</url-pattern>
-    </filter-mapping>
-
-
-	<!-- Wicket Filter -->
-    <filter>
-        <filter-name>wicketFilter</filter-name>
-        <filter-class>
-            com.gitblit.wicket.GitblitWicketFilter
-        </filter-class>        
-        <init-param>
-            <param-name>ignorePaths</param-name>
-            <!-- Paths should match 
-             	* SyndicationFilter <url-pattern>
-             	* SyndicationServlet <url-pattern>
-             	* com.gitblit.Constants.SYNDICATION_PATH
-             	* GitFilter <url-pattern>
-             	* GitServlet <url-pattern>
-             	* com.gitblit.Constants.GIT_PATH
-             	* SparkleshareInviteServlet <url-pattern>
-             	* com.gitblit.Constants.SPARKLESHARE_INVITE_PATH
-             	* Zipfilter <url-pattern>
-             	* ZipServlet <url-pattern>
-             	* com.gitblit.Constants.ZIP_PATH
-             	* FederationServlet <url-pattern>
-             	* RpcFilter <url-pattern>
-             	* RpcServlet <url-pattern>
-             	* RawFilter <url-pattern>
-             	* RawServlet <url-pattern>
-             	* PagesFilter <url-pattern>
-             	* PagesServlet <url-pattern>
-             	* com.gitblit.Constants.PAGES_PATH -->
-            <param-value>r/,git/,pt,feed/,zip/,federation/,rpc/,raw/,pages/,robots.txt,logo.png,graph/,sparkleshare/</param-value>
-        </init-param>
-    </filter>
-    <filter-mapping>
-        <filter-name>wicketFilter</filter-name>
-        <url-pattern>/*</url-pattern>
-    </filter-mapping>
-    
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+	xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+	<!-- The base folder is used to specify the root location of your Gitblit data.
+	
+			${baseFolder}/gitblit.properties
+			${baseFolder}/users.conf
+			${baseFolder}/projects.conf
+			${baseFolder}/robots.txt
+			${baseFolder}/git
+			${baseFolder}/groovy
+			${baseFolder}/groovy/grape
+			${baseFolder}/proposals
+
+		By default, this location is WEB-INF/data.  It is recommended to set this
+		path to a location outside your webapps folder that is writable by your
+		servlet container.  Gitblit will copy the WEB-INF/data files to that
+		location for you when it restarts.  This approach makes upgrading simpler.
+		All you have to do is set this parameter for the new release and then
+		review the defaults for any new settings.  Settings are always versioned
+		with a SINCE x.y.z attribute and also noted in the release changelog.
+		-->
+	<env-entry>
+		<description>The base folder is used to specify the root location of your Gitblit data.</description>
+		<env-entry-name>baseFolder</env-entry-name>
+		<env-entry-type>java.lang.String</env-entry-type>
+		<env-entry-value>${contextFolder}/WEB-INF/data</env-entry-value>
+	</env-entry>
+	
+	<!-- Gitblit Displayname -->
+	<display-name>Gitblit - @gb.version@</display-name>
+
+	<listener>
+  		<listener-class>com.gitblit.servlet.GitblitContext</listener-class>
+	</listener>
+	
+	<filter>
+    	<filter-name>guiceFilter</filter-name>
+		<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
+	</filter>
+
+	<filter-mapping>
+		<filter-name>guiceFilter</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
+  
 </web-app>
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java
index 8d6e249..279d3c9 100644
--- a/src/main/java/com/gitblit/Constants.java
+++ b/src/main/java/com/gitblit/Constants.java
@@ -70,6 +70,8 @@
 
 	public static final String RAW_PATH = "/raw/";
 
+	public static final String PT_PATH = "/pt";
+
 	public static final String BRANCH_GRAPH_PATH = "/graph/";
 
 	public static final String BORDER = "*****************************************************************";
diff --git a/src/main/java/com/gitblit/DaggerModule.java b/src/main/java/com/gitblit/DaggerModule.java
deleted file mode 100644
index 6ad3fe6..0000000
--- a/src/main/java/com/gitblit/DaggerModule.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright 2013 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;
-
-import javax.inject.Singleton;
-
-import com.gitblit.manager.AuthenticationManager;
-import com.gitblit.manager.FederationManager;
-import com.gitblit.manager.IAuthenticationManager;
-import com.gitblit.manager.IFederationManager;
-import com.gitblit.manager.IGitblit;
-import com.gitblit.manager.INotificationManager;
-import com.gitblit.manager.IPluginManager;
-import com.gitblit.manager.IProjectManager;
-import com.gitblit.manager.IRepositoryManager;
-import com.gitblit.manager.IRuntimeManager;
-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.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.wicket.GitBlitWebApp;
-
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * DaggerModule references all injectable objects.
- *
- * @author James Moger
- *
- */
-@Module(
-	library = true,
-	injects = {
-			IStoredSettings.class,
-
-			// core managers
-			IRuntimeManager.class,
-			IPluginManager.class,
-			INotificationManager.class,
-			IUserManager.class,
-			IAuthenticationManager.class,
-			IPublicKeyManager.class,
-			IRepositoryManager.class,
-			IProjectManager.class,
-			IFederationManager.class,
-
-			// the monolithic manager
-			IGitblit.class,
-
-			// the Gitblit Wicket app
-			GitBlitWebApp.class
-		}
-)
-public class DaggerModule {
-
-	@Provides @Singleton IStoredSettings provideSettings() {
-		return new FileSettings();
-	}
-
-	@Provides @Singleton IRuntimeManager provideRuntimeManager(IStoredSettings settings) {
-		return new RuntimeManager(settings);
-	}
-
-	@Provides @Singleton IPluginManager providePluginManager(IRuntimeManager runtimeManager) {
-		return new PluginManager(runtimeManager);
-	}
-
-	@Provides @Singleton INotificationManager provideNotificationManager(IStoredSettings settings) {
-		return new NotificationManager(settings);
-	}
-
-	@Provides @Singleton IUserManager provideUserManager(
-			IRuntimeManager runtimeManager,
-			IPluginManager pluginManager) {
-
-		return new UserManager(runtimeManager, pluginManager);
-	}
-
-	@Provides @Singleton IAuthenticationManager provideAuthenticationManager(
-			IRuntimeManager runtimeManager,
-			IUserManager userManager) {
-
-		return new AuthenticationManager(
-				runtimeManager,
-				userManager);
-	}
-
-	@Provides @Singleton IPublicKeyManager providePublicKeyManager(
-			IStoredSettings settings,
-			IRuntimeManager runtimeManager) {
-
-		String clazz = settings.getString(Keys.git.sshKeysManager, FileKeyManager.class.getName());
-		if (StringUtils.isEmpty(clazz)) {
-			clazz = FileKeyManager.class.getName();
-		}
-		if (FileKeyManager.class.getName().equals(clazz)) {
-			return new FileKeyManager(runtimeManager);
-		} else if (NullKeyManager.class.getName().equals(clazz)) {
-			return new NullKeyManager();
-		} else if (MemoryKeyManager.class.getName().equals(clazz)) {
-			return new MemoryKeyManager();
-		} else {
-			try {
-				Class<?> mgrClass = Class.forName(clazz);
-				return (IPublicKeyManager) mgrClass.newInstance();
-			} catch (Exception e) {
-
-			}
-			return null;
-		}
-	}
-
-	@Provides @Singleton IRepositoryManager provideRepositoryManager(
-			IRuntimeManager runtimeManager,
-			IPluginManager pluginManager,
-			IUserManager userManager) {
-
-		return new RepositoryManager(
-				runtimeManager,
-				pluginManager,
-				userManager);
-	}
-
-	@Provides @Singleton IProjectManager provideProjectManager(
-			IRuntimeManager runtimeManager,
-			IUserManager userManager,
-			IRepositoryManager repositoryManager) {
-
-		return new ProjectManager(
-				runtimeManager,
-				userManager,
-				repositoryManager);
-	}
-
-	@Provides @Singleton IFederationManager provideFederationManager(
-			IRuntimeManager runtimeManager,
-			INotificationManager notificationManager,
-			IRepositoryManager repositoryManager) {
-
-		return new FederationManager(
-				runtimeManager,
-				notificationManager,
-				repositoryManager);
-	}
-
-	@Provides @Singleton IGitblit provideGitblit(
-			IRuntimeManager runtimeManager,
-			IPluginManager pluginManager,
-			INotificationManager notificationManager,
-			IUserManager userManager,
-			IAuthenticationManager authenticationManager,
-			IPublicKeyManager publicKeyManager,
-			IRepositoryManager repositoryManager,
-			IProjectManager projectManager,
-			IFederationManager federationManager) {
-
-		return new GitBlit(
-				runtimeManager,
-				pluginManager,
-				notificationManager,
-				userManager,
-				authenticationManager,
-				publicKeyManager,
-				repositoryManager,
-				projectManager,
-				federationManager);
-	}
-
-	@Provides @Singleton GitBlitWebApp provideWebApplication(
-			IRuntimeManager runtimeManager,
-			IPluginManager pluginManager,
-			INotificationManager notificationManager,
-			IUserManager userManager,
-			IAuthenticationManager authenticationManager,
-			IPublicKeyManager publicKeyManager,
-			IRepositoryManager repositoryManager,
-			IProjectManager projectManager,
-			IFederationManager federationManager,
-			IGitblit gitblit) {
-
-		return new GitBlitWebApp(
-				runtimeManager,
-				pluginManager,
-				notificationManager,
-				userManager,
-				authenticationManager,
-				publicKeyManager,
-				repositoryManager,
-				projectManager,
-				federationManager,
-				gitblit);
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/FederationClient.java b/src/main/java/com/gitblit/FederationClient.java
index 29cdefe..822e8a7 100644
--- a/src/main/java/com/gitblit/FederationClient.java
+++ b/src/main/java/com/gitblit/FederationClient.java
@@ -1,189 +1,189 @@
-/*
- * Copyright 2011 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;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.kohsuke.args4j.CmdLineException;
-import org.kohsuke.args4j.CmdLineParser;
-import org.kohsuke.args4j.Option;
-
-import com.gitblit.manager.FederationManager;
-import com.gitblit.manager.GitblitManager;
-import com.gitblit.manager.IGitblit;
-import com.gitblit.manager.INotificationManager;
-import com.gitblit.manager.RepositoryManager;
-import com.gitblit.manager.RuntimeManager;
-import com.gitblit.manager.UserManager;
-import com.gitblit.models.FederationModel;
-import com.gitblit.models.Mailing;
-import com.gitblit.service.FederationPullService;
-import com.gitblit.utils.FederationUtils;
-import com.gitblit.utils.StringUtils;
-
-/**
- * Command-line client to pull federated Gitblit repositories.
- *
- * @author James Moger
- *
- */
-public class FederationClient {
-
-	public static void main(String[] args) {
-		Params params = new Params();
-		CmdLineParser parser = new CmdLineParser(params);
-		try {
-			parser.parseArgument(args);
-		} catch (CmdLineException t) {
-			usage(parser, t);
-		}
-
-		System.out.println("Gitblit Federation Client v" + Constants.getVersion() + " (" + Constants.getBuildDate() + ")");
-
-		// command-line specified base folder
-		File baseFolder = new File(System.getProperty("user.dir"));
-		if (!StringUtils.isEmpty(params.baseFolder)) {
-			baseFolder = new File(params.baseFolder);
-		}
-
-		File regFile = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, baseFolder, params.registrationsFile);
-		FileSettings settings = new FileSettings(regFile.getAbsolutePath());
-		List<FederationModel> registrations = new ArrayList<FederationModel>();
-		if (StringUtils.isEmpty(params.url)) {
-			registrations.addAll(FederationUtils.getFederationRegistrations(settings));
-		} else {
-			if (StringUtils.isEmpty(params.token)) {
-				System.out.println("Must specify --token parameter!");
-				System.exit(0);
-			}
-			FederationModel model = new FederationModel("Gitblit");
-			model.url = params.url;
-			model.token = params.token;
-			model.mirror = params.mirror;
-			model.bare = params.bare;
-			model.folder = "";
-			registrations.add(model);
-		}
-		if (registrations.size() == 0) {
-			System.out.println("No Federation Registrations!  Nothing to do.");
-			System.exit(0);
-		}
-
-		// command-line specified repositories folder
-		if (!StringUtils.isEmpty(params.repositoriesFolder)) {
-			settings.overrideSetting(Keys.git.repositoriesFolder, new File(
-					params.repositoriesFolder).getAbsolutePath());
-		}
-
-		// configure the Gitblit singleton for minimal, non-server operation
-		RuntimeManager runtime = new RuntimeManager(settings, baseFolder).start();
-		NoopNotificationManager notifications = new NoopNotificationManager().start();
-		UserManager users = new UserManager(runtime, null).start();
-		RepositoryManager repositories = new RepositoryManager(runtime, null, users).start();
-		FederationManager federation = new FederationManager(runtime, notifications, repositories).start();
-		IGitblit gitblit = new GitblitManager(runtime, null, notifications, users, null, null, repositories, null, federation);
-
-		FederationPullService puller = new FederationPullService(gitblit, federation.getFederationRegistrations()) {
-			@Override
-			public void reschedule(FederationModel registration) {
-				// NOOP
-			}
-		};
-		puller.run();
-
-		System.out.println("Finished.");
-		System.exit(0);
-	}
-
-	private static void usage(CmdLineParser parser, CmdLineException t) {
-		System.out.println(Constants.getGitBlitVersion());
-		System.out.println();
-		if (t != null) {
-			System.out.println(t.getMessage());
-			System.out.println();
-		}
-
-		if (parser != null) {
-			parser.printUsage(System.out);
-		}
-		System.exit(0);
-	}
-
-	/**
-	 * Parameters class for FederationClient.
-	 */
-	private static class Params {
-
-		@Option(name = "--registrations", usage = "Gitblit Federation Registrations File", metaVar = "FILE")
-		public String registrationsFile = "${baseFolder}/federation.properties";
-
-		@Option(name = "--url", usage = "URL of Gitblit instance to mirror from", metaVar = "URL")
-		public String url;
-
-		@Option(name = "--mirror", usage = "Mirror repositories")
-		public boolean mirror;
-
-		@Option(name = "--bare", usage = "Create bare repositories")
-		public boolean bare;
-
-		@Option(name = "--token", usage = "Federation Token", metaVar = "TOKEN")
-		public String token;
-
-		@Option(name = "--baseFolder", usage = "Base folder for received data", metaVar = "PATH")
-		public String baseFolder;
-
-		@Option(name = "--repositoriesFolder", usage = "Destination folder for cloned repositories", metaVar = "PATH")
-		public String repositoriesFolder;
-
-	}
-
-	private static class NoopNotificationManager implements INotificationManager {
-
-		@Override
-		public NoopNotificationManager start() {
-			return this;
-		}
-
-		@Override
-		public NoopNotificationManager stop() {
-			return this;
-		}
-
-		@Override
-		public boolean isSendingMail() {
-			return false;
-		}
-
-		@Override
-		public void sendMailToAdministrators(String subject, String message) {
-		}
-
-		@Override
-		public void sendMail(String subject, String message, Collection<String> toAddresses) {
-		}
-
-		@Override
-		public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) {
-		}
-
-		@Override
-		public void send(Mailing mailing) {
-		}
-	}
-}
+/*
+ * Copyright 2011 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;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.Option;
+
+import com.gitblit.manager.FederationManager;
+import com.gitblit.manager.GitblitManager;
+import com.gitblit.manager.IGitblit;
+import com.gitblit.manager.INotificationManager;
+import com.gitblit.manager.RepositoryManager;
+import com.gitblit.manager.RuntimeManager;
+import com.gitblit.manager.UserManager;
+import com.gitblit.models.FederationModel;
+import com.gitblit.models.Mailing;
+import com.gitblit.service.FederationPullService;
+import com.gitblit.utils.FederationUtils;
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Command-line client to pull federated Gitblit repositories.
+ *
+ * @author James Moger
+ *
+ */
+public class FederationClient {
+
+	public static void main(String[] args) {
+		Params params = new Params();
+		CmdLineParser parser = new CmdLineParser(params);
+		try {
+			parser.parseArgument(args);
+		} catch (CmdLineException t) {
+			usage(parser, t);
+		}
+
+		System.out.println("Gitblit Federation Client v" + Constants.getVersion() + " (" + Constants.getBuildDate() + ")");
+
+		// command-line specified base folder
+		File baseFolder = new File(System.getProperty("user.dir"));
+		if (!StringUtils.isEmpty(params.baseFolder)) {
+			baseFolder = new File(params.baseFolder);
+		}
+
+		File regFile = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, baseFolder, params.registrationsFile);
+		FileSettings settings = new FileSettings(regFile.getAbsolutePath());
+		List<FederationModel> registrations = new ArrayList<FederationModel>();
+		if (StringUtils.isEmpty(params.url)) {
+			registrations.addAll(FederationUtils.getFederationRegistrations(settings));
+		} else {
+			if (StringUtils.isEmpty(params.token)) {
+				System.out.println("Must specify --token parameter!");
+				System.exit(0);
+			}
+			FederationModel model = new FederationModel("Gitblit");
+			model.url = params.url;
+			model.token = params.token;
+			model.mirror = params.mirror;
+			model.bare = params.bare;
+			model.folder = "";
+			registrations.add(model);
+		}
+		if (registrations.size() == 0) {
+			System.out.println("No Federation Registrations!  Nothing to do.");
+			System.exit(0);
+		}
+
+		// command-line specified repositories folder
+		if (!StringUtils.isEmpty(params.repositoriesFolder)) {
+			settings.overrideSetting(Keys.git.repositoriesFolder, new File(
+					params.repositoriesFolder).getAbsolutePath());
+		}
+
+		// configure the Gitblit singleton for minimal, non-server operation
+		RuntimeManager runtime = new RuntimeManager(settings, baseFolder).start();
+		NoopNotificationManager notifications = new NoopNotificationManager().start();
+		UserManager users = new UserManager(runtime, null).start();
+		RepositoryManager repositories = new RepositoryManager(runtime, null, users).start();
+		FederationManager federation = new FederationManager(runtime, notifications, repositories).start();
+		IGitblit gitblit = new GitblitManager(null, null, runtime, null, notifications, users, null, repositories, null, federation);
+
+		FederationPullService puller = new FederationPullService(gitblit, federation.getFederationRegistrations()) {
+			@Override
+			public void reschedule(FederationModel registration) {
+				// NOOP
+			}
+		};
+		puller.run();
+
+		System.out.println("Finished.");
+		System.exit(0);
+	}
+
+	private static void usage(CmdLineParser parser, CmdLineException t) {
+		System.out.println(Constants.getGitBlitVersion());
+		System.out.println();
+		if (t != null) {
+			System.out.println(t.getMessage());
+			System.out.println();
+		}
+
+		if (parser != null) {
+			parser.printUsage(System.out);
+		}
+		System.exit(0);
+	}
+
+	/**
+	 * Parameters class for FederationClient.
+	 */
+	private static class Params {
+
+		@Option(name = "--registrations", usage = "Gitblit Federation Registrations File", metaVar = "FILE")
+		public String registrationsFile = "${baseFolder}/federation.properties";
+
+		@Option(name = "--url", usage = "URL of Gitblit instance to mirror from", metaVar = "URL")
+		public String url;
+
+		@Option(name = "--mirror", usage = "Mirror repositories")
+		public boolean mirror;
+
+		@Option(name = "--bare", usage = "Create bare repositories")
+		public boolean bare;
+
+		@Option(name = "--token", usage = "Federation Token", metaVar = "TOKEN")
+		public String token;
+
+		@Option(name = "--baseFolder", usage = "Base folder for received data", metaVar = "PATH")
+		public String baseFolder;
+
+		@Option(name = "--repositoriesFolder", usage = "Destination folder for cloned repositories", metaVar = "PATH")
+		public String repositoriesFolder;
+
+	}
+
+	private static class NoopNotificationManager implements INotificationManager {
+
+		@Override
+		public NoopNotificationManager start() {
+			return this;
+		}
+
+		@Override
+		public NoopNotificationManager stop() {
+			return this;
+		}
+
+		@Override
+		public boolean isSendingMail() {
+			return false;
+		}
+
+		@Override
+		public void sendMailToAdministrators(String subject, String message) {
+		}
+
+		@Override
+		public void sendMail(String subject, String message, Collection<String> toAddresses) {
+		}
+
+		@Override
+		public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) {
+		}
+
+		@Override
+		public void send(Mailing mailing) {
+		}
+	}
+}
diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java
index f9d9be9..68a91bb 100644
--- a/src/main/java/com/gitblit/GitBlit.java
+++ b/src/main/java/com/gitblit/GitBlit.java
@@ -15,471 +15,55 @@
  */
 package com.gitblit;
 
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import javax.inject.Singleton;
-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;
-import com.gitblit.manager.IGitblit;
 import com.gitblit.manager.INotificationManager;
 import com.gitblit.manager.IPluginManager;
 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.BranchTicketService;
-import com.gitblit.tickets.FileTicketService;
 import com.gitblit.tickets.ITicketService;
-import com.gitblit.tickets.NullTicketService;
-import com.gitblit.tickets.RedisTicketService;
 import com.gitblit.transport.ssh.IPublicKeyManager;
-import com.gitblit.utils.StringUtils;
-
-import dagger.Module;
-import dagger.ObjectGraph;
-import dagger.Provides;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 /**
- * GitBlit is the aggregate manager for the Gitblit webapp.  It provides all
- * management functions and also manages some long-running services.
+ * GitBlit is the aggregate manager for the Gitblit webapp.  The parent class provides all
+ * functionality.  This class exists to not break existing Groovy push hooks.
  *
  * @author James Moger
  *
  */
+@Singleton
+@Deprecated
 public class GitBlit extends GitblitManager {
 
-	private final ObjectGraph injector;
-
-	private final ServicesManager servicesManager;
-
-	private ITicketService ticketService;
-
+	@Inject
 	public GitBlit(
+			Provider<IPublicKeyManager> publicKeyManagerProvider,
+			Provider<ITicketService> ticketServiceProvider,
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
 			INotificationManager notificationManager,
 			IUserManager userManager,
 			IAuthenticationManager authenticationManager,
-			IPublicKeyManager publicKeyManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
 			IFederationManager federationManager) {
 
-		super(runtimeManager,
+		super(
+				publicKeyManagerProvider,
+				ticketServiceProvider,
+				runtimeManager,
 				pluginManager,
 				notificationManager,
 				userManager,
 				authenticationManager,
-				publicKeyManager,
 				repositoryManager,
 				projectManager,
 				federationManager);
-
-		this.injector = ObjectGraph.create(getModules());
-
-		this.servicesManager = new ServicesManager(this);
-	}
-
-	@Override
-	public GitBlit start() {
-		super.start();
-		logger.info("Starting services manager...");
-		servicesManager.start();
-		configureTicketService();
-		return this;
-	}
-
-	@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 Object [] getModules() {
-		return new Object [] { new GitBlitModule()};
-	}
-
-	protected boolean acceptPush(Transport byTransport) {
-		if (byTransport == null) {
-			logger.info("Unknown transport, push rejected!");
-			return false;
-		}
-
-		Set<Transport> transports = new HashSet<Transport>();
-		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<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)) {
-				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<RepositoryUrl>() {
-
-			@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<RepositoryUrl> 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.
-	 */
-	@Override
-	public void updateRepositoryModel(String repositoryName, RepositoryModel repository,
-			boolean isCreate) throws GitBlitException {
-		RepositoryModel oldModel = null;
-		boolean isRename = !isCreate && !repositoryName.equalsIgnoreCase(repository.name);
-		if (isRename) {
-			oldModel = repositoryManager.getRepositoryModel(repositoryName);
-		}
-
-		super.updateRepositoryModel(repositoryName, repository, isCreate);
-
-		if (isRename && ticketService != null) {
-			ticketService.rename(oldModel, repository);
-		}
-	}
-
-	/**
-	 * Delete the user and all associated public ssh keys.
-	 */
-	@Override
-	public boolean deleteUser(String username) {
-		UserModel user = userManager.getUserModel(username);
-		return deleteUserModel(user);
-	}
-
-	@Override
-	public boolean deleteUserModel(UserModel model) {
-		boolean success = userManager.deleteUserModel(model);
-		if (success) {
-			getPublicKeyManager().removeAllKeys(model.username);
-		}
-		return success;
-	}
-
-	/**
-	 * Delete the repository and all associated tickets.
-	 */
-	@Override
-	public boolean deleteRepository(String repositoryName) {
-		RepositoryModel repository = repositoryManager.getRepositoryModel(repositoryName);
-		return deleteRepositoryModel(repository);
-	}
-
-	@Override
-	public boolean deleteRepositoryModel(RepositoryModel model) {
-		boolean success = repositoryManager.deleteRepositoryModel(model);
-		if (success && ticketService != null) {
-			ticketService.deleteAll(model);
-		}
-		return success;
-	}
-
-	/**
-	 * Returns the configured ticket service.
-	 *
-	 * @return a ticket service
-	 */
-	@Override
-	public ITicketService getTicketService() {
-		return ticketService;
-	}
-
-	protected void configureTicketService() {
-		String clazz = settings.getString(Keys.tickets.service, NullTicketService.class.getName());
-		if (StringUtils.isEmpty(clazz)) {
-			clazz = NullTicketService.class.getName();
-		}
-		try {
-			Class<? extends ITicketService> serviceClass = (Class<? extends ITicketService>) Class.forName(clazz);
-			ticketService = injector.get(serviceClass).start();
-			if (ticketService instanceof NullTicketService) {
-				logger.warn("No ticket service configured.");
-			} else if (ticketService.isReady()) {
-				logger.info("{} is ready.", ticketService);
-			} else {
-				logger.warn("{} is disabled.", ticketService);
-			}
-		} catch (Exception e) {
-			logger.error("failed to create ticket service " + clazz, e);
-			ticketService = injector.get(NullTicketService.class).start();
-		}
-	}
-
-	/**
-	 * A nested Dagger graph is used for constructor dependency injection of
-	 * complex classes.
-	 *
-	 * @author James Moger
-	 *
-	 */
-	@Module(
-			library = true,
-			injects = {
-					IStoredSettings.class,
-
-					// core managers
-					IRuntimeManager.class,
-					IPluginManager.class,
-					INotificationManager.class,
-					IUserManager.class,
-					IAuthenticationManager.class,
-					IRepositoryManager.class,
-					IProjectManager.class,
-					IFederationManager.class,
-
-					// the monolithic manager
-					IGitblit.class,
-
-					// ticket services
-					NullTicketService.class,
-					FileTicketService.class,
-					BranchTicketService.class,
-					RedisTicketService.class
-				}
-			)
-	class GitBlitModule {
-
-		@Provides @Singleton IStoredSettings provideSettings() {
-			return settings;
-		}
-
-		@Provides @Singleton IRuntimeManager provideRuntimeManager() {
-			return runtimeManager;
-		}
-
-		@Provides @Singleton IPluginManager providePluginManager() {
-			return pluginManager;
-		}
-
-		@Provides @Singleton INotificationManager provideNotificationManager() {
-			return notificationManager;
-		}
-
-		@Provides @Singleton IUserManager provideUserManager() {
-			return userManager;
-		}
-
-		@Provides @Singleton IAuthenticationManager provideAuthenticationManager() {
-			return authenticationManager;
-		}
-
-		@Provides @Singleton IRepositoryManager provideRepositoryManager() {
-			return repositoryManager;
-		}
-
-		@Provides @Singleton IProjectManager provideProjectManager() {
-			return projectManager;
-		}
-
-		@Provides @Singleton IFederationManager provideFederationManager() {
-			return federationManager;
-		}
-
-		@Provides @Singleton IGitblit provideGitblit() {
-			return GitBlit.this;
-		}
-
-		@Provides @Singleton NullTicketService provideNullTicketService() {
-			return new NullTicketService(
-					runtimeManager,
-					pluginManager,
-					notificationManager,
-					userManager,
-					repositoryManager);
-		}
-
-		@Provides @Singleton FileTicketService provideFileTicketService() {
-			return new FileTicketService(
-					runtimeManager,
-					pluginManager,
-					notificationManager,
-					userManager,
-					repositoryManager);
-		}
-
-		@Provides @Singleton BranchTicketService provideBranchTicketService() {
-			return new BranchTicketService(
-					runtimeManager,
-					pluginManager,
-					notificationManager,
-					userManager,
-					repositoryManager);
-		}
-
-		@Provides @Singleton RedisTicketService provideRedisTicketService() {
-			return new RedisTicketService(
-					runtimeManager,
-					pluginManager,
-					notificationManager,
-					userManager,
-					repositoryManager);
-		}
 	}
 }
diff --git a/src/main/java/com/gitblit/dagger/DaggerContext.java b/src/main/java/com/gitblit/dagger/DaggerContext.java
deleted file mode 100644
index 0e6a3fc..0000000
--- a/src/main/java/com/gitblit/dagger/DaggerContext.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2013 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.dagger;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import dagger.ObjectGraph;
-
-/**
- * Dagger servlet context listener is a context listener that uses Dagger to
- * instantiate and inject servlets, filters, and anything else you might want.
- *
- * @author James Moger
- *
- */
-public abstract class DaggerContext implements ServletContextListener {
-
-	public static final String INJECTOR_NAME = ObjectGraph.class.getName();
-
-	protected final Logger logger = LoggerFactory.getLogger(getClass());
-
-	protected abstract Object [] getModules();
-
-	protected abstract void destroyContext(ServletContext context);
-
-	protected ObjectGraph getInjector(ServletContext context) {
-		Object o = context.getAttribute(INJECTOR_NAME);
-		if (o == null) {
-			logger.debug("instantiating Dagger modules");
-			Object [] modules = getModules();
-			logger.debug("getting Dagger injector");
-			try {
-				o = ObjectGraph.create(modules);
-				logger.debug("setting Dagger injector into {} attribute", INJECTOR_NAME);
-				context.setAttribute(INJECTOR_NAME, o);
-			} catch (Throwable t) {
-				logger.error("an error occurred creating the Dagger injector", t);
-			}
-		}
-		return (ObjectGraph) o;
-	}
-
-	@Override
-	public final void contextDestroyed(ServletContextEvent contextEvent) {
-		ServletContext context = contextEvent.getServletContext();
-		context.removeAttribute(INJECTOR_NAME);
-		destroyContext(context);
-	}
-}
diff --git a/src/main/java/com/gitblit/dagger/DaggerFilter.java b/src/main/java/com/gitblit/dagger/DaggerFilter.java
deleted file mode 100644
index 01c07a4..0000000
--- a/src/main/java/com/gitblit/dagger/DaggerFilter.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2013 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.dagger;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-
-import dagger.ObjectGraph;
-
-/**
- * Uses Dagger to manually inject dependencies into a servlet filter.
- * This class is useful for servlet containers that offer CDI and are
- * confused by Dagger.
- *
- * @author James Moger
- *
- */
-public abstract class DaggerFilter implements Filter {
-
-	@Override
-	public final void init(FilterConfig filterConfig) throws ServletException {
-		ServletContext context = filterConfig.getServletContext();
-		ObjectGraph objectGraph = (ObjectGraph) context.getAttribute(DaggerContext.INJECTOR_NAME);
-		inject(objectGraph, filterConfig);
-	}
-
-	protected abstract void inject(ObjectGraph dagger, FilterConfig filterConfig) throws ServletException;
-
-	@Override
-	public void destroy() {
-	}
-}
diff --git a/src/main/java/com/gitblit/dagger/DaggerServlet.java b/src/main/java/com/gitblit/dagger/DaggerServlet.java
deleted file mode 100644
index 88331a4..0000000
--- a/src/main/java/com/gitblit/dagger/DaggerServlet.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2013 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.dagger;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-
-import dagger.ObjectGraph;
-
-/**
- * Uses Dagger to manually inject dependencies into a servlet.
- * This class is useful for servlet containers that offer CDI and are
- * confused by Dagger.
- *
- * @author James Moger
- *
- */
-public abstract class DaggerServlet extends HttpServlet {
-
-	private static final long serialVersionUID = 1L;
-
-	@Override
-	public final void init() throws ServletException {
-		ServletContext context = getServletContext();
-		ObjectGraph objectGraph = (ObjectGraph) context.getAttribute(DaggerContext.INJECTOR_NAME);
-		inject(objectGraph);
-	}
-
-	protected abstract void inject(ObjectGraph dagger);
-}
diff --git a/src/main/java/com/gitblit/dagger/DaggerWicketFilter.java b/src/main/java/com/gitblit/dagger/DaggerWicketFilter.java
deleted file mode 100644
index c2fd4d6..0000000
--- a/src/main/java/com/gitblit/dagger/DaggerWicketFilter.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2013 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.dagger;
-
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-
-import org.apache.wicket.protocol.http.WicketFilter;
-
-import dagger.ObjectGraph;
-
-/**
- * Uses Dagger to manually inject dependencies into a Wicket filter.
- * This class is useful for servlet containers that offer CDI and are
- * confused by Dagger.
- *
- * @author James Moger
- *
- */
-public abstract class DaggerWicketFilter extends WicketFilter {
-
-	@Override
-	public final void init(FilterConfig filterConfig) throws ServletException {
-		ServletContext context = filterConfig.getServletContext();
-		ObjectGraph objectGraph = (ObjectGraph) context.getAttribute(DaggerContext.INJECTOR_NAME);
-		inject(objectGraph);
-		super.init(filterConfig);
-	}
-
-	protected abstract void inject(ObjectGraph dagger);
-}
diff --git a/src/main/java/com/gitblit/guice/CoreModule.java b/src/main/java/com/gitblit/guice/CoreModule.java
new file mode 100644
index 0000000..c0d39e9
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/CoreModule.java
@@ -0,0 +1,79 @@
+/*
+ * 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.FileSettings;
+import com.gitblit.GitBlit;
+import com.gitblit.IStoredSettings;
+import com.gitblit.manager.AuthenticationManager;
+import com.gitblit.manager.FederationManager;
+import com.gitblit.manager.IAuthenticationManager;
+import com.gitblit.manager.IFederationManager;
+import com.gitblit.manager.IGitblit;
+import com.gitblit.manager.INotificationManager;
+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.tickets.ITicketService;
+import com.gitblit.transport.ssh.IPublicKeyManager;
+import com.gitblit.utils.WorkQueue;
+import com.google.inject.AbstractModule;
+
+/**
+ * CoreModule references all the core business objects.
+ *
+ * @author James Moger
+ *
+ */
+public class CoreModule extends AbstractModule {
+
+	@Override
+	protected void configure() {
+
+		bind(IStoredSettings.class).toInstance(new FileSettings());
+
+		// bind complex providers
+		bind(IPublicKeyManager.class).toProvider(IPublicKeyManagerProvider.class);
+		bind(ITicketService.class).toProvider(ITicketServiceProvider.class);
+		bind(WorkQueue.class).toProvider(WorkQueueProvider.class);
+
+		// core managers
+		bind(IRuntimeManager.class).to(RuntimeManager.class);
+		bind(IPluginManager.class).to(PluginManager.class);
+		bind(INotificationManager.class).to(NotificationManager.class);
+		bind(IUserManager.class).to(UserManager.class);
+		bind(IAuthenticationManager.class).to(AuthenticationManager.class);
+		bind(IRepositoryManager.class).to(RepositoryManager.class);
+		bind(IProjectManager.class).to(ProjectManager.class);
+		bind(IFederationManager.class).to(FederationManager.class);
+
+		// the monolithic manager
+		bind(IGitblit.class).to(GitBlit.class);
+
+		// manager for long-running daemons and services
+		bind(IServicesManager.class).to(ServicesManager.class);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java b/src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java
new file mode 100644
index 0000000..8075aa9
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java
@@ -0,0 +1,72 @@
+/*
+ * 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.Keys;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.transport.ssh.FileKeyManager;
+import com.gitblit.transport.ssh.IPublicKeyManager;
+import com.gitblit.transport.ssh.NullKeyManager;
+import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * Provides a lazily-instantiated IPublicKeyManager configured from IStoredSettings.
+ *
+ * @author James Moger
+ *
+ */
+@Singleton
+public class IPublicKeyManagerProvider implements Provider<IPublicKeyManager> {
+
+	private final Logger logger = LoggerFactory.getLogger(getClass());
+
+	private final IRuntimeManager runtimeManager;
+
+	private volatile IPublicKeyManager manager;
+
+	@Inject
+	public IPublicKeyManagerProvider(IRuntimeManager runtimeManager) {
+		this.runtimeManager = runtimeManager;
+	}
+
+	@Override
+	public synchronized IPublicKeyManager get() {
+		if (manager != null) {
+			return manager;
+		}
+
+		IStoredSettings settings = runtimeManager.getSettings();
+		String clazz = settings.getString(Keys.git.sshKeysManager, FileKeyManager.class.getName());
+		if (StringUtils.isEmpty(clazz)) {
+			clazz = FileKeyManager.class.getName();
+		}
+		try {
+			Class<? extends IPublicKeyManager> mgrClass = (Class<? extends IPublicKeyManager>) Class.forName(clazz);
+			manager = runtimeManager.getInjector().getInstance(mgrClass);
+		} catch (Exception e) {
+			logger.error("failed to create public key manager", e);
+			manager = new NullKeyManager();
+		}
+		return manager;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/guice/ITicketServiceProvider.java b/src/main/java/com/gitblit/guice/ITicketServiceProvider.java
new file mode 100644
index 0000000..fd39955
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/ITicketServiceProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.Keys;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.tickets.ITicketService;
+import com.gitblit.tickets.NullTicketService;
+import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * Provides a lazily-instantiated ITicketService configured from IStoredSettings.
+ *
+ * @author James Moger
+ *
+ */
+@Singleton
+public class ITicketServiceProvider implements Provider<ITicketService> {
+
+	private final Logger logger = LoggerFactory.getLogger(getClass());
+
+	private final IRuntimeManager runtimeManager;
+
+	private volatile ITicketService service;
+
+	@Inject
+	public ITicketServiceProvider(IRuntimeManager runtimeManager) {
+		this.runtimeManager = runtimeManager;
+	}
+
+	@Override
+	public synchronized ITicketService get() {
+		if (service != null) {
+			return service;
+		}
+
+		IStoredSettings settings = runtimeManager.getSettings();
+		String clazz = settings.getString(Keys.tickets.service, NullTicketService.class.getName());
+		if (StringUtils.isEmpty(clazz)) {
+			clazz = NullTicketService.class.getName();
+		}
+
+		try {
+			Class<? extends ITicketService> serviceClass = (Class<? extends ITicketService>) Class.forName(clazz);
+			service = runtimeManager.getInjector().getInstance(serviceClass);
+		} catch (Exception e) {
+			logger.error("failed to create ticket service", e);
+			service = runtimeManager.getInjector().getInstance(NullTicketService.class);
+		}
+
+		return service;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/guice/WebModule.java b/src/main/java/com/gitblit/guice/WebModule.java
new file mode 100644
index 0000000..5b56918
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/WebModule.java
@@ -0,0 +1,105 @@
+/*
+ * 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 java.util.HashMap;
+import java.util.Map;
+
+import com.gitblit.Constants;
+import com.gitblit.servlet.BranchGraphServlet;
+import com.gitblit.servlet.DownloadZipFilter;
+import com.gitblit.servlet.DownloadZipServlet;
+import com.gitblit.servlet.EnforceAuthenticationFilter;
+import com.gitblit.servlet.FederationServlet;
+import com.gitblit.servlet.GitFilter;
+import com.gitblit.servlet.GitServlet;
+import com.gitblit.servlet.LogoServlet;
+import com.gitblit.servlet.PagesFilter;
+import com.gitblit.servlet.PagesServlet;
+import com.gitblit.servlet.ProxyFilter;
+import com.gitblit.servlet.PtServlet;
+import com.gitblit.servlet.RawFilter;
+import com.gitblit.servlet.RawServlet;
+import com.gitblit.servlet.RobotsTxtServlet;
+import com.gitblit.servlet.RpcFilter;
+import com.gitblit.servlet.RpcServlet;
+import com.gitblit.servlet.SparkleShareInviteServlet;
+import com.gitblit.servlet.SyndicationFilter;
+import com.gitblit.servlet.SyndicationServlet;
+import com.gitblit.wicket.GitblitWicketFilter;
+import com.google.common.base.Joiner;
+import com.google.inject.servlet.ServletModule;
+
+/**
+ * Defines all the web servlets & filters.
+ *
+ * @author James Moger
+ *
+ */
+public class WebModule extends ServletModule {
+
+	final static String ALL = "/*";
+
+	@Override
+	protected void configureServlets() {
+		// servlets
+		serve(fuzzy(Constants.R_PATH), fuzzy(Constants.GIT_PATH)).with(GitServlet.class);
+		serve(fuzzy(Constants.RAW_PATH)).with(RawServlet.class);
+		serve(fuzzy(Constants.PAGES)).with(PagesServlet.class);
+		serve(fuzzy(Constants.RPC_PATH)).with(RpcServlet.class);
+		serve(fuzzy(Constants.ZIP_PATH)).with(DownloadZipServlet.class);
+		serve(fuzzy(Constants.SYNDICATION_PATH)).with(SyndicationServlet.class);
+
+		serve(fuzzy(Constants.FEDERATION_PATH)).with(FederationServlet.class);
+		serve(fuzzy(Constants.SPARKLESHARE_INVITE_PATH)).with(SparkleShareInviteServlet.class);
+		serve(fuzzy(Constants.BRANCH_GRAPH_PATH)).with(BranchGraphServlet.class);
+		serve(Constants.PT_PATH).with(PtServlet.class);
+		serve("/robots.txt").with(RobotsTxtServlet.class);
+		serve("/logo.png").with(LogoServlet.class);
+
+		// global filters
+		filter(ALL).through(ProxyFilter.class);
+		filter(ALL).through(EnforceAuthenticationFilter.class);
+
+		// security filters
+		filter(fuzzy(Constants.R_PATH), fuzzy(Constants.GIT_PATH)).through(GitFilter.class);
+		filter(fuzzy(Constants.RAW_PATH)).through(RawFilter.class);
+		filter(fuzzy(Constants.PAGES)).through(PagesFilter.class);
+		filter(fuzzy(Constants.RPC_PATH)).through(RpcFilter.class);
+		filter(fuzzy(Constants.ZIP_PATH)).through(DownloadZipFilter.class);
+		filter(fuzzy(Constants.SYNDICATION_PATH)).through(SyndicationFilter.class);
+
+		// Wicket
+		String toIgnore = Joiner.on(",").join(Constants.R_PATH, Constants.GIT_PATH, Constants.RAW_PATH,
+				Constants.PAGES, Constants.RPC_PATH, Constants.ZIP_PATH, Constants.SYNDICATION_PATH,
+				Constants.FEDERATION_PATH, Constants.SPARKLESHARE_INVITE_PATH, Constants.BRANCH_GRAPH_PATH,
+				Constants.PT_PATH, "/robots.txt", "/logo.png");
+
+		Map<String, String> params = new HashMap<String, String>();
+		params.put(GitblitWicketFilter.FILTER_MAPPING_PARAM, ALL);
+		params.put(GitblitWicketFilter.IGNORE_PATHS_PARAM, toIgnore);
+		filter(ALL).through(GitblitWicketFilter.class, params);
+	}
+
+	private String fuzzy(String path) {
+		if (path.endsWith(ALL)) {
+			return path;
+		} else if (path.endsWith("/")) {
+			return path + "*";
+		}
+		return path + ALL;
+	}
+}
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 0000000..cde27ea
--- /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<WorkQueue> {
+
+	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/AuthenticationManager.java b/src/main/java/com/gitblit/manager/AuthenticationManager.java
index d1b1af0..ccf03c0 100644
--- a/src/main/java/com/gitblit/manager/AuthenticationManager.java
+++ b/src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -53,6 +53,8 @@
 import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.X509Utils.X509Metadata;
 import com.gitblit.wicket.GitBlitWebSession;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * The authentication manager handles user login & logout.
@@ -60,6 +62,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class AuthenticationManager implements IAuthenticationManager {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -76,6 +79,7 @@
 
 	private final Map<String, String> legacyRedirects;
 
+	@Inject
 	public AuthenticationManager(
 			IRuntimeManager runtimeManager,
 			IUserManager userManager) {
diff --git a/src/main/java/com/gitblit/manager/FederationManager.java b/src/main/java/com/gitblit/manager/FederationManager.java
index 95d38af..f009c1c 100644
--- a/src/main/java/com/gitblit/manager/FederationManager.java
+++ b/src/main/java/com/gitblit/manager/FederationManager.java
@@ -45,6 +45,8 @@
 import com.gitblit.utils.FederationUtils;
 import com.gitblit.utils.JsonUtils;
 import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * Federation manager controls all aspects of handling federation sets, tokens,
@@ -53,6 +55,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class FederationManager implements IFederationManager {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -70,6 +73,7 @@
 
 	private final IRepositoryManager repositoryManager;
 
+	@Inject
 	public FederationManager(
 			IRuntimeManager runtimeManager,
 			INotificationManager notificationManager,
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
index 98ad33e..02b2d67 100644
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ b/src/main/java/com/gitblit/manager/GitblitManager.java
@@ -49,12 +49,10 @@
 
 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.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.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;
@@ -87,6 +83,10 @@
 import com.google.gson.JsonIOException;
 import com.google.gson.JsonSyntaxException;
 import com.google.gson.reflect.TypeToken;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.google.inject.Provider;
 
 /**
  * GitblitManager is an aggregate interface delegate.  It implements all the manager
@@ -100,11 +100,16 @@
  * @author James Moger
  *
  */
+@Singleton
 public class GitblitManager implements IGitblit {
 
 	protected final Logger logger = LoggerFactory.getLogger(getClass());
 
 	protected final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>();
+
+	protected final Provider<IPublicKeyManager> publicKeyManagerProvider;
+
+	protected final Provider<ITicketService> ticketServiceProvider;
 
 	protected final IStoredSettings settings;
 
@@ -118,24 +123,27 @@
 
 	protected final IAuthenticationManager authenticationManager;
 
-	protected final IPublicKeyManager publicKeyManager;
-
 	protected final IRepositoryManager repositoryManager;
 
 	protected final IProjectManager projectManager;
 
 	protected final IFederationManager federationManager;
 
+	@Inject
 	public GitblitManager(
+			Provider<IPublicKeyManager> publicKeyManagerProvider,
+			Provider<ITicketService> ticketServiceProvider,
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
 			INotificationManager notificationManager,
 			IUserManager userManager,
 			IAuthenticationManager authenticationManager,
-			IPublicKeyManager publicKeyManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
 			IFederationManager federationManager) {
+
+		this.publicKeyManagerProvider = publicKeyManagerProvider;
+		this.ticketServiceProvider = ticketServiceProvider;
 
 		this.settings = runtimeManager.getSettings();
 		this.runtimeManager = runtimeManager;
@@ -143,7 +151,6 @@
 		this.notificationManager = notificationManager;
 		this.userManager = userManager;
 		this.authenticationManager = authenticationManager;
-		this.publicKeyManager = publicKeyManager;
 		this.repositoryManager = repositoryManager;
 		this.projectManager = projectManager;
 		this.federationManager = federationManager;
@@ -350,66 +357,6 @@
 	}
 
 	/**
-	 * 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));
-			}
-		}
-
-		// 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;
 	 *
@@ -535,18 +482,14 @@
 		}
 	}
 
-	/**
-	 * Throws an exception if trying to get a ticket service.
-	 *
-	 */
 	@Override
 	public ITicketService getTicketService() {
-		throw new RuntimeException("This class does not have a ticket service!");
+		return ticketServiceProvider.get();
 	}
 
 	@Override
 	public IPublicKeyManager getPublicKeyManager() {
-		return publicKeyManager;
+		return publicKeyManagerProvider.get();
 	}
 
 	/*
@@ -597,26 +540,6 @@
 	}
 
 	@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();
 	}
@@ -654,6 +577,11 @@
 	@Override
 	public ServerStatus getStatus() {
 		return runtimeManager.getStatus();
+	}
+
+	@Override
+	public Injector getInjector() {
+		return runtimeManager.getInjector();
 	}
 
 	/*
@@ -781,11 +709,6 @@
 	}
 
 	@Override
-	public boolean deleteUser(String username) {
-		return userManager.deleteUser(username);
-	}
-
-	@Override
 	public UserModel getUserModel(String username) {
 		return userManager.getUserModel(username);
 	}
@@ -826,8 +749,22 @@
 	}
 
 	@Override
+	public boolean deleteUser(String username) {
+		// delegate to deleteUserModel() to delete public ssh keys
+		UserModel user = userManager.getUserModel(username);
+		return deleteUserModel(user);
+	}
+
+	/**
+	 * Delete the user and all associated public ssh keys.
+	 */
+	@Override
 	public boolean deleteUserModel(UserModel model) {
-		return userManager.deleteUserModel(model);
+		boolean success = userManager.deleteUserModel(model);
+		if (success) {
+			getPublicKeyManager().removeAllKeys(model.username);
+		}
+		return success;
 	}
 
 	@Override
@@ -1023,10 +960,23 @@
 		return repositoryManager.getRepositoryDefaultMetrics(model, repository);
 	}
 
+	/**
+	 * Detect renames and reindex as appropriate.
+	 */
 	@Override
 	public void updateRepositoryModel(String repositoryName, RepositoryModel repository,
 			boolean isCreate) throws GitBlitException {
+		RepositoryModel oldModel = null;
+		boolean isRename = !isCreate && !repositoryName.equalsIgnoreCase(repository.name);
+		if (isRename) {
+			oldModel = repositoryManager.getRepositoryModel(repositoryName);
+		}
+
 		repositoryManager.updateRepositoryModel(repositoryName, repository, isCreate);
+
+		if (isRename && ticketServiceProvider.get() != null) {
+			ticketServiceProvider.get().rename(oldModel, repository);
+		}
 	}
 
 	@Override
@@ -1039,14 +989,23 @@
 		return repositoryManager.canDelete(model);
 	}
 
+	/**
+	 * Delete the repository and all associated tickets.
+	 */
 	@Override
 	public boolean deleteRepositoryModel(RepositoryModel model) {
-		return repositoryManager.deleteRepositoryModel(model);
+		boolean success = repositoryManager.deleteRepositoryModel(model);
+		if (success && ticketServiceProvider.get() != null) {
+			ticketServiceProvider.get().deleteAll(model);
+		}
+		return success;
 	}
 
 	@Override
 	public boolean deleteRepository(String repositoryName) {
-		return repositoryManager.deleteRepository(repositoryName);
+		// delegate to deleteRepositoryModel() to destroy indexed tickets
+		RepositoryModel repository = repositoryManager.getRepositoryModel(repositoryName);
+		return deleteRepositoryModel(repository);
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/manager/IGitblit.java b/src/main/java/com/gitblit/manager/IGitblit.java
index 50ec8b1..6c5b374 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;
@@ -38,17 +34,6 @@
 									IRepositoryManager,
 									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<RepositoryUrl> 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 b2d7a2b..8322d34 100644
--- a/src/main/java/com/gitblit/manager/IRuntimeManager.java
+++ b/src/main/java/com/gitblit/manager/IRuntimeManager.java
@@ -24,8 +24,11 @@
 import com.gitblit.IStoredSettings;
 import com.gitblit.models.ServerSettings;
 import com.gitblit.models.ServerStatus;
+import com.google.inject.Injector;
 
 public interface IRuntimeManager extends IManager {
+
+	Injector getInjector();
 
 	void setBaseFolder(File folder);
 
@@ -46,42 +49,6 @@
  	 * @since 1.5.1
 	 */
 	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 0000000..5bb135d
--- /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<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/NotificationManager.java b/src/main/java/com/gitblit/manager/NotificationManager.java
index 69a611b..4bbc2ab 100644
--- a/src/main/java/com/gitblit/manager/NotificationManager.java
+++ b/src/main/java/com/gitblit/manager/NotificationManager.java
@@ -29,6 +29,8 @@
 import com.gitblit.Keys;
 import com.gitblit.models.Mailing;
 import com.gitblit.service.MailService;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * The notification manager dispatches notifications.  Currently, email is the
@@ -38,6 +40,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class NotificationManager implements INotificationManager {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -48,6 +51,7 @@
 
 	private final MailService mailService;
 
+	@Inject
 	public NotificationManager(IStoredSettings settings) {
 		this.settings = settings;
 		this.mailService = new MailService(settings);
diff --git a/src/main/java/com/gitblit/manager/PluginManager.java b/src/main/java/com/gitblit/manager/PluginManager.java
index 2ee4855..874e24b 100644
--- a/src/main/java/com/gitblit/manager/PluginManager.java
+++ b/src/main/java/com/gitblit/manager/PluginManager.java
@@ -37,7 +37,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import ro.fortsoft.pf4j.DefaultExtensionFinder;
 import ro.fortsoft.pf4j.DefaultPluginManager;
+import ro.fortsoft.pf4j.ExtensionFinder;
 import ro.fortsoft.pf4j.PluginClassLoader;
 import ro.fortsoft.pf4j.PluginState;
 import ro.fortsoft.pf4j.PluginStateEvent;
@@ -58,6 +60,8 @@
 import com.gitblit.utils.StringUtils;
 import com.google.common.io.Files;
 import com.google.common.io.InputSupplier;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * The plugin manager maintains the lifecycle of plugins. It is exposed as
@@ -68,32 +72,23 @@
  * @author James Moger
  *
  */
+@Singleton
 public class PluginManager implements IPluginManager, PluginStateListener {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
 
-	private final DefaultPluginManager pf4j;
-
 	private final IRuntimeManager runtimeManager;
+
+	private DefaultPluginManager pf4j;
 
 	// timeout defaults of Maven 3.0.4 in seconds
 	private int connectTimeout = 20;
 
 	private int readTimeout = 12800;
 
+	@Inject
 	public PluginManager(IRuntimeManager runtimeManager) {
-		File dir = runtimeManager.getFileOrFolder(Keys.plugins.folder, "${baseFolder}/plugins");
-		dir.mkdirs();
 		this.runtimeManager = runtimeManager;
-
-		this.pf4j = new DefaultPluginManager(dir);
-
-		try {
-			Version systemVersion = Version.createVersion(Constants.getVersion());
-			pf4j.setSystemVersion(systemVersion);
-		} catch (Exception e) {
-			logger.error(null, e);
-		}
 	}
 
 	@Override
@@ -108,6 +103,42 @@
 
 	@Override
 	public PluginManager start() {
+		File dir = runtimeManager.getFileOrFolder(Keys.plugins.folder, "${baseFolder}/plugins");
+		dir.mkdirs();
+		pf4j = new DefaultPluginManager(dir) {
+			@Override
+		    protected ExtensionFinder createExtensionFinder() {
+		    	DefaultExtensionFinder extensionFinder = new DefaultExtensionFinder(this) {
+		    		@Override
+					protected ExtensionFactory createExtensionFactory() {
+		    			return new ExtensionFactory() {
+		    				@Override
+		    				public Object create(Class<?> extensionType) {
+		    					// instantiate && inject the extension
+		    					logger.debug("Create instance for extension '{}'", extensionType.getName());
+		    					try {
+		    						return runtimeManager.getInjector().getInstance(extensionType);
+		    					} catch (Exception e) {
+		    						logger.error(e.getMessage(), e);
+		    					}
+		    					return null;
+		    				}
+
+		    			};
+		    		}
+		    	};
+		        addPluginStateListener(extensionFinder);
+
+		        return extensionFinder;
+		    }
+		};
+
+		try {
+			Version systemVersion = Version.createVersion(Constants.getVersion());
+			pf4j.setSystemVersion(systemVersion);
+		} catch (Exception e) {
+			logger.error(null, e);
+		}
 		pf4j.loadPlugins();
 		logger.debug("Starting plugins");
 		pf4j.startPlugins();
diff --git a/src/main/java/com/gitblit/manager/ProjectManager.java b/src/main/java/com/gitblit/manager/ProjectManager.java
index 666f521..ae46bdf 100644
--- a/src/main/java/com/gitblit/manager/ProjectManager.java
+++ b/src/main/java/com/gitblit/manager/ProjectManager.java
@@ -41,6 +41,8 @@
 import com.gitblit.utils.ModelUtils;
 import com.gitblit.utils.ObjectCache;
 import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * Project manager handles project-related functions.
@@ -48,6 +50,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class ProjectManager implements IProjectManager {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -68,6 +71,7 @@
 
 	private FileBasedConfig projectConfigs;
 
+	@Inject
 	public ProjectManager(
 			IRuntimeManager runtimeManager,
 			IUserManager userManager,
diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java
index 0160363..626dac4 100644
--- a/src/main/java/com/gitblit/manager/RepositoryManager.java
+++ b/src/main/java/com/gitblit/manager/RepositoryManager.java
@@ -89,6 +89,8 @@
 import com.gitblit.utils.ObjectCache;
 import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.TimeUtils;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * Repository manager creates, updates, deletes and caches git repositories.  It
@@ -97,6 +99,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class RepositoryManager implements IRepositoryManager {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -119,7 +122,7 @@
 
 	private final IUserManager userManager;
 
-	private final File repositoriesFolder;
+	private File repositoriesFolder;
 
 	private LuceneService luceneExecutor;
 
@@ -127,6 +130,7 @@
 
 	private MirrorService mirrorExecutor;
 
+	@Inject
 	public RepositoryManager(
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
@@ -136,11 +140,11 @@
 		this.runtimeManager = runtimeManager;
 		this.pluginManager = pluginManager;
 		this.userManager = userManager;
-		this.repositoriesFolder = runtimeManager.getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git");
 	}
 
 	@Override
 	public RepositoryManager start() {
+		repositoriesFolder = runtimeManager.getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git");
 		logger.info("Repositories folder : {}", repositoriesFolder.getAbsolutePath());
 
 		// initialize utilities
@@ -1934,21 +1938,19 @@
 	}
 
 	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 9cdc64e..95a363f 100644
--- a/src/main/java/com/gitblit/manager/RuntimeManager.java
+++ b/src/main/java/com/gitblit/manager/RuntimeManager.java
@@ -32,7 +32,11 @@
 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());
@@ -47,6 +51,10 @@
 
 	private TimeZone timezone;
 
+	@Inject
+	private Injector injector;
+
+	@Inject
 	public RuntimeManager(IStoredSettings settings) {
 		this(settings, null);
 	}
@@ -72,6 +80,11 @@
 	@Override
 	public RuntimeManager stop() {
 		return this;
+	}
+
+	@Override
+	public Injector getInjector() {
+		return injector;
 	}
 
 	@Override
@@ -109,52 +122,6 @@
 		}
 //		settingsModel.pushScripts = getAllScripts();
 		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;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/manager/ServicesManager.java b/src/main/java/com/gitblit/manager/ServicesManager.java
index 3721578..2550f66 100644
--- a/src/main/java/com/gitblit/manager/ServicesManager.java
+++ b/src/main/java/com/gitblit/manager/ServicesManager.java
@@ -18,9 +18,15 @@
 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 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.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,19 +69,18 @@
  * @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<WorkQueue> workQueueProvider;
+
 	private final IStoredSettings settings;
 
 	private final IGitblit gitblit;
-
-	private final IdGenerator idGenerator;
-
-	private final WorkQueue workQueue;
 
 	private FanoutService fanoutService;
 
@@ -77,12 +88,16 @@
 
 	private SshDaemon sshDaemon;
 
-	public ServicesManager(IGitblit gitblit) {
-		this.settings = gitblit.getSettings();
+	@Inject
+	public ServicesManager(
+			Provider<WorkQueue> 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 @@
 		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<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)) {
+				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<RepositoryUrl>() {
+
+			@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<RepositoryUrl> 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 @@
 		}
 	}
 
+	protected boolean acceptPush(Transport byTransport) {
+		if (byTransport == null) {
+			logger.info("Unknown transport, push rejected!");
+			return false;
+		}
+
+		Set<Transport> transports = new HashSet<Transport>();
+		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 @@
 		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 @@
 	 */
 	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/manager/UserManager.java b/src/main/java/com/gitblit/manager/UserManager.java
index 2b82ffb..86be8bc 100644
--- a/src/main/java/com/gitblit/manager/UserManager.java
+++ b/src/main/java/com/gitblit/manager/UserManager.java
@@ -36,6 +36,8 @@
 import com.gitblit.models.TeamModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * The user manager manages persistence and retrieval of users and teams.
@@ -43,6 +45,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class UserManager implements IUserManager {
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -57,6 +60,7 @@
 
 	private IUserService userService;
 
+	@Inject
 	public UserManager(IRuntimeManager runtimeManager, IPluginManager pluginManager) {
 		this.settings = runtimeManager.getSettings();
 		this.runtimeManager = runtimeManager;
diff --git a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
index 0e6d323..6d2efa4 100644
--- a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
+++ b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
@@ -19,20 +19,18 @@
 import java.text.MessageFormat;
 
 import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.StringUtils;
-
-import dagger.ObjectGraph;
 
 /**
  * The AccessRestrictionFilter is an AuthenticationFilter that confirms that the
@@ -54,11 +52,15 @@
 
 	protected IRepositoryManager repositoryManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
-		super.inject(dagger, filterConfig);
-		this.runtimeManager = dagger.get(IRuntimeManager.class);
-		this.repositoryManager = dagger.get(IRepositoryManager.class);
+	protected AccessRestrictionFilter(
+			IRuntimeManager runtimeManager,
+			IAuthenticationManager authenticationManager,
+			IRepositoryManager repositoryManager) {
+
+		super(authenticationManager);
+
+		this.runtimeManager = runtimeManager;
+		this.repositoryManager = repositoryManager;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/AuthenticationFilter.java b/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
index c21f869..6f13252 100644
--- a/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
+++ b/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
@@ -21,6 +21,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
@@ -35,13 +36,10 @@
 import org.slf4j.LoggerFactory;
 
 import com.gitblit.Constants;
-import com.gitblit.dagger.DaggerFilter;
 import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.DeepCopier;
 import com.gitblit.utils.StringUtils;
-
-import dagger.ObjectGraph;
 
 /**
  * The AuthenticationFilter is a servlet filter that preprocesses requests that
@@ -52,7 +50,7 @@
  * @author James Moger
  *
  */
-public abstract class AuthenticationFilter extends DaggerFilter {
+public abstract class AuthenticationFilter implements Filter {
 
 	protected static final String CHALLENGE = "Basic realm=\"" + Constants.NAME + "\"";
 
@@ -62,9 +60,16 @@
 
 	protected IAuthenticationManager authenticationManager;
 
+	protected AuthenticationFilter(IAuthenticationManager authenticationManager) {
+		this.authenticationManager = authenticationManager;
+	}
+
 	@Override
-	protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
-		this.authenticationManager = dagger.get(IAuthenticationManager.class);
+	public void init(FilterConfig filterConfig) throws ServletException {
+	}
+
+	@Override
+	public void destroy() {
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/BranchGraphServlet.java b/src/main/java/com/gitblit/servlet/BranchGraphServlet.java
index 0abe347..2c77553 100644
--- a/src/main/java/com/gitblit/servlet/BranchGraphServlet.java
+++ b/src/main/java/com/gitblit/servlet/BranchGraphServlet.java
@@ -36,7 +36,10 @@
 import java.util.TreeSet;
 
 import javax.imageio.ImageIO;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -52,12 +55,9 @@
 import com.gitblit.Constants;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
-import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.utils.JGitUtils;
 import com.gitblit.utils.StringUtils;
-
-import dagger.ObjectGraph;
 
 /**
  * Handles requests for branch graphs
@@ -65,7 +65,8 @@
  * @author James Moger
  *
  */
-public class BranchGraphServlet extends DaggerServlet {
+@Singleton
+public class BranchGraphServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
@@ -82,18 +83,18 @@
 
 	private IRepositoryManager repositoryManager;
 
-	public BranchGraphServlet() {
-		super();
+	@Inject
+	public BranchGraphServlet(
+			IStoredSettings settings,
+			IRepositoryManager repositoryManager) {
+
+		this.settings = settings;
+		this.repositoryManager = repositoryManager;
+
 		strokeCache = new Stroke[4];
 		for (int i = 1; i < strokeCache.length; i++) {
 			strokeCache[i] = new BasicStroke(i);
 		}
-	}
-
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.settings = dagger.get(IStoredSettings.class);
-		this.repositoryManager = dagger.get(IRepositoryManager.class);
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/DownloadZipFilter.java b/src/main/java/com/gitblit/servlet/DownloadZipFilter.java
index 0c7b3e5..13703a8 100644
--- a/src/main/java/com/gitblit/servlet/DownloadZipFilter.java
+++ b/src/main/java/com/gitblit/servlet/DownloadZipFilter.java
@@ -15,7 +15,13 @@
  */
 package com.gitblit.servlet;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
 import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.manager.IAuthenticationManager;
+import com.gitblit.manager.IRepositoryManager;
+import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 
@@ -27,8 +33,18 @@
  * @author James Moger
  *
  */
+@Singleton
 public class DownloadZipFilter extends AccessRestrictionFilter {
 
+	@Inject
+	public DownloadZipFilter(
+			IRuntimeManager runtimeManager,
+			IAuthenticationManager authenticationManager,
+			IRepositoryManager repositoryManager) {
+
+		super(runtimeManager, authenticationManager, repositoryManager);
+	}
+
 	/**
 	 * Extract the repository name from the url.
 	 *
diff --git a/src/main/java/com/gitblit/servlet/DownloadZipServlet.java b/src/main/java/com/gitblit/servlet/DownloadZipServlet.java
index 6a64778..0756256 100644
--- a/src/main/java/com/gitblit/servlet/DownloadZipServlet.java
+++ b/src/main/java/com/gitblit/servlet/DownloadZipServlet.java
@@ -20,7 +20,10 @@
 import java.text.ParseException;
 import java.util.Date;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jgit.lib.Repository;
@@ -31,14 +34,11 @@
 import com.gitblit.Constants;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
-import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.utils.CompressionUtils;
 import com.gitblit.utils.JGitUtils;
 import com.gitblit.utils.MarkdownUtils;
 import com.gitblit.utils.StringUtils;
-
-import dagger.ObjectGraph;
 
 /**
  * Streams out a zip file from the specified repository for any tree path at any
@@ -47,7 +47,8 @@
  * @author James Moger
  *
  */
-public class DownloadZipServlet extends DaggerServlet {
+@Singleton
+public class DownloadZipServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
@@ -76,10 +77,10 @@
 		}
 	}
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.settings = dagger.get(IStoredSettings.class);
-		this.repositoryManager = dagger.get(IRepositoryManager.class);
+	@Inject
+	public DownloadZipServlet(IStoredSettings settings, IRepositoryManager repositoryManager) {
+		this.settings = settings;
+		this.repositoryManager = repositoryManager;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java b/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
index c015021..8a3f782 100644
--- a/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
+++ b/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
@@ -18,6 +18,9 @@
 import java.io.IOException;
 import java.text.MessageFormat;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
@@ -31,11 +34,8 @@
 
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
-import com.gitblit.dagger.DaggerFilter;
 import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.models.UserModel;
-
-import dagger.ObjectGraph;
 
 /**
  * This filter enforces authentication via HTTP Basic Authentication, if the settings indicate so.
@@ -45,7 +45,8 @@
  * @author Laurens Vrijnsen
  *
  */
-public class EnforceAuthenticationFilter extends DaggerFilter {
+@Singleton
+public class EnforceAuthenticationFilter implements Filter {
 
 	protected transient Logger logger = LoggerFactory.getLogger(getClass());
 
@@ -53,10 +54,21 @@
 
 	private IAuthenticationManager authenticationManager;
 
+	@Inject
+	public EnforceAuthenticationFilter(
+			IStoredSettings settings,
+			IAuthenticationManager authenticationManager) {
+
+		this.settings = settings;
+		this.authenticationManager = authenticationManager;
+	}
+
 	@Override
-	protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
-		this.settings = dagger.get(IStoredSettings.class);
-		this.authenticationManager = dagger.get(IAuthenticationManager.class);
+	public void init(FilterConfig config) {
+	}
+
+	@Override
+	public void destroy() {
 	}
 
 	/*
@@ -86,13 +98,5 @@
 			// user is authenticated, or don't care, continue handling
 			chain.doFilter(request, response);
 		}
-	}
-
-
-	/*
-	 * @see javax.servlet.Filter#destroy()
-	 */
-	@Override
-	public void destroy() {
 	}
 }
diff --git a/src/main/java/com/gitblit/servlet/FederationServlet.java b/src/main/java/com/gitblit/servlet/FederationServlet.java
index 8dbf0e1..89ff231 100644
--- a/src/main/java/com/gitblit/servlet/FederationServlet.java
+++ b/src/main/java/com/gitblit/servlet/FederationServlet.java
@@ -25,6 +25,8 @@
 import java.util.Map;
 import java.util.Set;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.http.HttpServletResponse;
 
 import com.gitblit.Constants.FederationRequest;
@@ -43,14 +45,13 @@
 import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.TimeUtils;
 
-import dagger.ObjectGraph;
-
 /**
  * Handles federation requests.
  *
  * @author James Moger
  *
  */
+@Singleton
 public class FederationServlet extends JsonServlet {
 
 	private static final long serialVersionUID = 1L;
@@ -63,12 +64,17 @@
 
 	private IFederationManager federationManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.settings = dagger.get(IStoredSettings.class);
-		this.userManager = dagger.get(IUserManager.class);
-		this.repositoryManager = dagger.get(IRepositoryManager.class);
-		this.federationManager = dagger.get(IFederationManager.class);
+	@Inject
+	public FederationServlet(
+			IStoredSettings settings,
+			IUserManager userManager,
+			IRepositoryManager repositoryManager,
+			IFederationManager federationManager) {
+
+		this.settings = settings;
+		this.userManager = userManager;
+		this.repositoryManager = repositoryManager;
+		this.federationManager = federationManager;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/GitFilter.java b/src/main/java/com/gitblit/servlet/GitFilter.java
index bb3d321..b29fdb6 100644
--- a/src/main/java/com/gitblit/servlet/GitFilter.java
+++ b/src/main/java/com/gitblit/servlet/GitFilter.java
@@ -17,7 +17,8 @@
 
 import java.text.MessageFormat;
 
-import javax.servlet.FilterConfig;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.http.HttpServletRequest;
 
 import com.gitblit.Constants.AccessRestrictionType;
@@ -25,12 +26,13 @@
 import com.gitblit.GitBlitException;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
+import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IFederationManager;
+import com.gitblit.manager.IRepositoryManager;
+import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.StringUtils;
-
-import dagger.ObjectGraph;
 
 /**
  * The GitFilter is an AccessRestrictionFilter which ensures that Git client
@@ -40,6 +42,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class GitFilter extends AccessRestrictionFilter {
 
 	protected static final String gitReceivePack = "/git-receive-pack";
@@ -53,11 +56,18 @@
 
 	private IFederationManager federationManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
-		super.inject(dagger, filterConfig);
-		this.settings = dagger.get(IStoredSettings.class);
-		this.federationManager = dagger.get(IFederationManager.class);
+	@Inject
+	public GitFilter(
+			IStoredSettings settings,
+			IRuntimeManager runtimeManager,
+			IAuthenticationManager authenticationManager,
+			IRepositoryManager repositoryManager,
+			IFederationManager federationManager) {
+
+		super(runtimeManager, authenticationManager, repositoryManager);
+
+		this.settings = settings;
+		this.federationManager = federationManager;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/GitServlet.java b/src/main/java/com/gitblit/servlet/GitServlet.java
index 93fe31d..941b4c5 100644
--- a/src/main/java/com/gitblit/servlet/GitServlet.java
+++ b/src/main/java/com/gitblit/servlet/GitServlet.java
@@ -20,6 +20,8 @@
 import java.io.IOException;
 import java.util.Enumeration;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletConfig;
@@ -33,13 +35,10 @@
 
 import org.eclipse.jgit.http.server.GitFilter;
 
-import com.gitblit.dagger.DaggerContext;
 import com.gitblit.git.GitblitReceivePackFactory;
 import com.gitblit.git.GitblitUploadPackFactory;
 import com.gitblit.git.RepositoryResolver;
 import com.gitblit.manager.IGitblit;
-
-import dagger.ObjectGraph;
 
 /**
  * The GitServlet provides http/https access to Git repositories.
@@ -48,24 +47,23 @@
  * @author James Moger
  *
  */
+@Singleton
 public class GitServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
 	private final GitFilter gitFilter;
 
-	public GitServlet() {
+	@Inject
+	public GitServlet(IGitblit gitblit) {
 		gitFilter = new GitFilter();
+		gitFilter.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>(gitblit));
+		gitFilter.setUploadPackFactory(new GitblitUploadPackFactory<HttpServletRequest>(gitblit));
+		gitFilter.setReceivePackFactory(new GitblitReceivePackFactory<HttpServletRequest>(gitblit));
 	}
 
 	@Override
 	public void init(final ServletConfig config) throws ServletException {
-		ServletContext context = config.getServletContext();
-		ObjectGraph dagger = (ObjectGraph) context.getAttribute(DaggerContext.INJECTOR_NAME);
-		IGitblit gitblit = dagger.get(IGitblit.class);
-		gitFilter.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>(gitblit));
-		gitFilter.setUploadPackFactory(new GitblitUploadPackFactory<HttpServletRequest>(gitblit));
-		gitFilter.setReceivePackFactory(new GitblitReceivePackFactory<HttpServletRequest>(gitblit));
 
 		gitFilter.init(new FilterConfig() {
 			@Override
diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java
index d5b4092..115af65 100644
--- a/src/main/java/com/gitblit/servlet/GitblitContext.java
+++ b/src/main/java/com/gitblit/servlet/GitblitContext.java
@@ -31,14 +31,17 @@
 import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.gitblit.Constants;
-import com.gitblit.DaggerModule;
 import com.gitblit.FileSettings;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
 import com.gitblit.WebXmlSettings;
-import com.gitblit.dagger.DaggerContext;
 import com.gitblit.extensions.LifeCycleListener;
+import com.gitblit.guice.CoreModule;
+import com.gitblit.guice.WebModule;
 import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IFederationManager;
 import com.gitblit.manager.IGitblit;
@@ -48,27 +51,33 @@
 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;
 import com.gitblit.utils.ContainerUtils;
 import com.gitblit.utils.StringUtils;
-
-import dagger.ObjectGraph;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.servlet.GuiceServletContextListener;
 
 /**
  * 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.  Servlets and
- * filters are instantiated defined in web.xml and instantiated by the servlet
- * container, but those servlets and filters use Dagger to manually inject their
- * dependencies.
+ * container.  This class instantiates and starts all managers.
+ *
+ * Servlets and filters are injected which allows Gitblit to be completely
+ * code-driven.
  *
  * @author James Moger
  *
  */
-public class GitblitContext extends DaggerContext {
+public class GitblitContext extends GuiceServletContextListener {
 
 	private static GitblitContext gitblit;
+
+	protected final Logger logger = LoggerFactory.getLogger(getClass());
 
 	private final List<IManager> managers = new ArrayList<IManager>();
 
@@ -111,12 +120,16 @@
 		return null;
 	}
 
-	/**
-	 * Returns Gitblit's Dagger injection modules.
-	 */
 	@Override
-	protected Object [] getModules() {
-		return new Object [] { new DaggerModule() };
+	protected Injector getInjector() {
+		return Guice.createInjector(getModules());
+	}
+
+	/**
+	 * Returns Gitblit's Guice injection modules.
+	 */
+	protected AbstractModule [] getModules() {
+		return new AbstractModule [] { new CoreModule(), new WebModule() };
 	}
 
 	/**
@@ -127,18 +140,20 @@
 	 */
 	@Override
 	public final void contextInitialized(ServletContextEvent contextEvent) {
+		super.contextInitialized(contextEvent);
+
 		ServletContext context = contextEvent.getServletContext();
-		configureContext(context);
+		startCore(context);
 	}
 
 	/**
 	 * Prepare runtime settings and start all manager instances.
 	 */
-	protected void configureContext(ServletContext context) {
-		ObjectGraph injector = getInjector(context);
+	protected void startCore(ServletContext context) {
+		Injector injector = (Injector) context.getAttribute(Injector.class.getName());
 
 		// create the runtime settings object
-		IStoredSettings runtimeSettings = injector.get(IStoredSettings.class);
+		IStoredSettings runtimeSettings = injector.getInstance(IStoredSettings.class);
 		final File baseFolder;
 
 		if (goSettings != null) {
@@ -168,7 +183,7 @@
 
 		// Manually configure IRuntimeManager
 		logManager(IRuntimeManager.class);
-		IRuntimeManager runtime = injector.get(IRuntimeManager.class);
+		IRuntimeManager runtime = injector.getInstance(IRuntimeManager.class);
 		runtime.setBaseFolder(baseFolder);
 		runtime.getStatus().isGO = goSettings != null;
 		runtime.getStatus().servletContainer = context.getServerInfo();
@@ -186,7 +201,9 @@
 		startManager(injector, IRepositoryManager.class);
 		startManager(injector, IProjectManager.class);
 		startManager(injector, IFederationManager.class);
+		startManager(injector, ITicketService.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
@@ -196,7 +213,7 @@
 		logger.info("All managers started.");
 		logger.info("");
 
-		IPluginManager pluginManager = injector.get(IPluginManager.class);
+		IPluginManager pluginManager = injector.getInstance(IPluginManager.class);
 		for (LifeCycleListener listener : pluginManager.getExtensions(LifeCycleListener.class)) {
 			try {
 				listener.onStartup();
@@ -218,12 +235,12 @@
 		return null;
 	}
 
-	protected <X extends IManager> X loadManager(ObjectGraph injector, Class<X> clazz) {
-		X x = injector.get(clazz);
+	protected <X extends IManager> X loadManager(Injector injector, Class<X> clazz) {
+		X x = injector.getInstance(clazz);
 		return x;
 	}
 
-	protected <X extends IManager> X startManager(ObjectGraph injector, Class<X> clazz) {
+	protected <X extends IManager> X startManager(Injector injector, Class<X> clazz) {
 		X x = loadManager(injector, clazz);
 		logManager(clazz);
 		x.start();
@@ -236,11 +253,17 @@
 		logger.info("----[{}]----", clazz.getName());
 	}
 
+	@Override
+	public final void contextDestroyed(ServletContextEvent contextEvent) {
+		super.contextDestroyed(contextEvent);
+		ServletContext context = contextEvent.getServletContext();
+		destroyContext(context);
+	}
+
 	/**
 	 * 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.");
 
diff --git a/src/main/java/com/gitblit/servlet/JsonServlet.java b/src/main/java/com/gitblit/servlet/JsonServlet.java
index 4378c8a..abc0f29 100644
--- a/src/main/java/com/gitblit/servlet/JsonServlet.java
+++ b/src/main/java/com/gitblit/servlet/JsonServlet.java
@@ -21,6 +21,7 @@
 import java.text.MessageFormat;
 
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -28,7 +29,6 @@
 import org.slf4j.LoggerFactory;
 
 import com.gitblit.Constants;
-import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.utils.JsonUtils;
 import com.gitblit.utils.StringUtils;
 
@@ -38,7 +38,7 @@
  * @author James Moger
  *
  */
-public abstract class JsonServlet extends DaggerServlet {
+public abstract class JsonServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
diff --git a/src/main/java/com/gitblit/servlet/LogoServlet.java b/src/main/java/com/gitblit/servlet/LogoServlet.java
index 96f34af..d5d298b 100644
--- a/src/main/java/com/gitblit/servlet/LogoServlet.java
+++ b/src/main/java/com/gitblit/servlet/LogoServlet.java
@@ -21,16 +21,16 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import com.gitblit.Keys;
-import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.manager.IRuntimeManager;
-
-import dagger.ObjectGraph;
 
 /**
  * Handles requests for logo.png
@@ -38,7 +38,8 @@
  * @author James Moger
  *
  */
-public class LogoServlet extends DaggerServlet {
+@Singleton
+public class LogoServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
@@ -46,9 +47,9 @@
 
 	private IRuntimeManager runtimeManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.runtimeManager = dagger.get(IRuntimeManager.class);
+	@Inject
+	public LogoServlet(IRuntimeManager runtimeManager) {
+		this.runtimeManager = runtimeManager;
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/servlet/PagesFilter.java b/src/main/java/com/gitblit/servlet/PagesFilter.java
index e07d9b3..1d6c3db 100644
--- a/src/main/java/com/gitblit/servlet/PagesFilter.java
+++ b/src/main/java/com/gitblit/servlet/PagesFilter.java
@@ -15,6 +15,13 @@
  */
 package com.gitblit.servlet;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import com.gitblit.manager.IAuthenticationManager;
+import com.gitblit.manager.IRepositoryManager;
+import com.gitblit.manager.IRuntimeManager;
+
 
 /**
  * The PagesFilter is an AccessRestrictionFilter which ensures the gh-pages
@@ -23,7 +30,17 @@
  * @author James Moger
  *
  */
+
+@Singleton
 public class PagesFilter extends RawFilter {
 
+	@Inject
+	public PagesFilter(
+			IRuntimeManager runtimeManager,
+			IAuthenticationManager authenticationManager,
+			IRepositoryManager repositoryManager) {
+
+		super(runtimeManager, authenticationManager, repositoryManager);
+	}
 
 }
diff --git a/src/main/java/com/gitblit/servlet/PagesServlet.java b/src/main/java/com/gitblit/servlet/PagesServlet.java
index f578f86..ad34b3c 100644
--- a/src/main/java/com/gitblit/servlet/PagesServlet.java
+++ b/src/main/java/com/gitblit/servlet/PagesServlet.java
@@ -15,10 +15,14 @@
  */
 package com.gitblit.servlet;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import com.gitblit.Constants;
+import com.gitblit.manager.IRepositoryManager;
+import com.gitblit.manager.IRuntimeManager;
 
 /**
  * Serves the content of a gh-pages branch.
@@ -26,6 +30,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class PagesServlet extends RawServlet {
 
 	private static final long serialVersionUID = 1L;
@@ -46,6 +51,14 @@
 		return baseURL + Constants.PAGES + repository + "/" + (path == null ? "" : ("/" + path));
 	}
 
+	@Inject
+	public PagesServlet(
+			IRuntimeManager runtimeManager,
+			IRepositoryManager repositoryManager) {
+
+		super(runtimeManager, repositoryManager);
+	}
+
 	@Override
 	protected String getBranch(String repository, HttpServletRequest request) {
 		return "gh-pages";
diff --git a/src/main/java/com/gitblit/servlet/ProxyFilter.java b/src/main/java/com/gitblit/servlet/ProxyFilter.java
index 46f59de..d7f096a 100644
--- a/src/main/java/com/gitblit/servlet/ProxyFilter.java
+++ b/src/main/java/com/gitblit/servlet/ProxyFilter.java
@@ -16,9 +16,13 @@
 package com.gitblit.servlet;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
@@ -27,12 +31,9 @@
 
 import ro.fortsoft.pf4j.PluginWrapper;
 
-import com.gitblit.dagger.DaggerFilter;
 import com.gitblit.extensions.HttpRequestFilter;
 import com.gitblit.manager.IPluginManager;
 import com.gitblit.manager.IRuntimeManager;
-
-import dagger.ObjectGraph;
 
 /**
  * A request filter than allows registered extension request filters to access
@@ -41,15 +42,29 @@
  * @author David Ostrovsky
  * @since 1.6.0
  */
-public class ProxyFilter extends DaggerFilter {
-	private List<HttpRequestFilter> filters;
+@Singleton
+public class ProxyFilter implements Filter {
+	private final IRuntimeManager runtimeManager;
+
+	private final IPluginManager pluginManager;
+
+	private final List<HttpRequestFilter> filters;
+
+	@Inject
+	public ProxyFilter(
+			IRuntimeManager runtimeManager,
+			IPluginManager pluginManager) {
+
+		this.runtimeManager = runtimeManager;
+		this.pluginManager = pluginManager;
+		this.filters = new ArrayList<>();
+
+	}
 
 	@Override
-	protected void inject(ObjectGraph dagger, FilterConfig filterConfig) throws ServletException {
-		IRuntimeManager runtimeManager = dagger.get(IRuntimeManager.class);
-		IPluginManager pluginManager = dagger.get(IPluginManager.class);
+	public void init(FilterConfig filterConfig) throws ServletException {
 
-		filters = pluginManager.getExtensions(HttpRequestFilter.class);
+		filters.addAll(pluginManager.getExtensions(HttpRequestFilter.class));
 		for (HttpRequestFilter f : filters) {
 			// wrap the filter config for Gitblit settings retrieval
 			PluginWrapper pluginWrapper = pluginManager.whichPlugin(f.getClass());
diff --git a/src/main/java/com/gitblit/servlet/PtServlet.java b/src/main/java/com/gitblit/servlet/PtServlet.java
index e9cbaa5..313b284 100644
--- a/src/main/java/com/gitblit/servlet/PtServlet.java
+++ b/src/main/java/com/gitblit/servlet/PtServlet.java
@@ -21,7 +21,10 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -34,10 +37,7 @@
 import org.apache.wicket.util.io.ByteArrayOutputStream;
 import org.eclipse.jgit.lib.FileMode;
 
-import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.manager.IRuntimeManager;
-
-import dagger.ObjectGraph;
 
 /**
  * Handles requests for the Barnum pt (patchset tool).
@@ -47,7 +47,8 @@
  * @author James Moger
  *
  */
-public class PtServlet extends DaggerServlet {
+@Singleton
+public class PtServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
@@ -55,9 +56,9 @@
 
 	private IRuntimeManager runtimeManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.runtimeManager = dagger.get(IRuntimeManager.class);
+	@Inject
+	public PtServlet(IRuntimeManager runtimeManager) {
+		this.runtimeManager = runtimeManager;
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/servlet/RawFilter.java b/src/main/java/com/gitblit/servlet/RawFilter.java
index 34989c9..fe4af04 100644
--- a/src/main/java/com/gitblit/servlet/RawFilter.java
+++ b/src/main/java/com/gitblit/servlet/RawFilter.java
@@ -15,9 +15,15 @@
  */
 package com.gitblit.servlet;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
 import org.eclipse.jgit.lib.Repository;
 
 import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.manager.IAuthenticationManager;
+import com.gitblit.manager.IRepositoryManager;
+import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 
@@ -28,8 +34,18 @@
  * @author James Moger
  *
  */
+@Singleton
 public class RawFilter extends AccessRestrictionFilter {
 
+	@Inject
+	public RawFilter(
+			IRuntimeManager runtimeManager,
+			IAuthenticationManager authenticationManager,
+			IRepositoryManager repositoryManager) {
+
+		super(runtimeManager, authenticationManager, repositoryManager);
+	}
+
 	/**
 	 * Extract the repository name from the url.
 	 *
diff --git a/src/main/java/com/gitblit/servlet/RawServlet.java b/src/main/java/com/gitblit/servlet/RawServlet.java
index 0def062..7731a95 100644
--- a/src/main/java/com/gitblit/servlet/RawServlet.java
+++ b/src/main/java/com/gitblit/servlet/RawServlet.java
@@ -28,8 +28,11 @@
 import java.util.Map;
 import java.util.TreeMap;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -48,7 +51,6 @@
 
 import com.gitblit.Constants;
 import com.gitblit.Keys;
-import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.PathModel;
@@ -57,28 +59,30 @@
 import com.gitblit.utils.MarkdownUtils;
 import com.gitblit.utils.StringUtils;
 
-import dagger.ObjectGraph;
-
 /**
  * Serves the content of a branch.
  *
  * @author James Moger
  *
  */
-public class RawServlet extends DaggerServlet {
+@Singleton
+public class RawServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
 	private transient Logger logger = LoggerFactory.getLogger(RawServlet.class);
 
-	private IRuntimeManager runtimeManager;
+	private final IRuntimeManager runtimeManager;
 
-	private IRepositoryManager repositoryManager;
+	private final IRepositoryManager repositoryManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.runtimeManager = dagger.get(IRuntimeManager.class);
-		this.repositoryManager = dagger.get(IRepositoryManager.class);
+	@Inject
+	public RawServlet(
+			IRuntimeManager runtimeManager,
+			IRepositoryManager repositoryManager) {
+
+		this.runtimeManager = runtimeManager;
+		this.repositoryManager = repositoryManager;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/RobotsTxtServlet.java b/src/main/java/com/gitblit/servlet/RobotsTxtServlet.java
index 9bd3b3c..4e58d4d 100644
--- a/src/main/java/com/gitblit/servlet/RobotsTxtServlet.java
+++ b/src/main/java/com/gitblit/servlet/RobotsTxtServlet.java
@@ -18,16 +18,16 @@
 import java.io.File;
 import java.io.IOException;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import com.gitblit.Keys;
-import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.utils.FileUtils;
-
-import dagger.ObjectGraph;
 
 /**
  * Handles requests for robots.txt
@@ -35,15 +35,16 @@
  * @author James Moger
  *
  */
-public class RobotsTxtServlet extends DaggerServlet {
+@Singleton
+public class RobotsTxtServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
 	private IRuntimeManager runtimeManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.runtimeManager = dagger.get(IRuntimeManager.class);
+	@Inject
+	public RobotsTxtServlet(IRuntimeManager runtimeManager) {
+		this.runtimeManager = runtimeManager;
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/servlet/RpcFilter.java b/src/main/java/com/gitblit/servlet/RpcFilter.java
index 23bf956..34474d5 100644
--- a/src/main/java/com/gitblit/servlet/RpcFilter.java
+++ b/src/main/java/com/gitblit/servlet/RpcFilter.java
@@ -18,8 +18,9 @@
 import java.io.IOException;
 import java.text.MessageFormat;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
@@ -29,10 +30,9 @@
 import com.gitblit.Constants.RpcRequest;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
+import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.UserModel;
-
-import dagger.ObjectGraph;
 
 /**
  * The RpcFilter is a servlet filter that secures the RpcServlet.
@@ -47,17 +47,23 @@
  * @author James Moger
  *
  */
+@Singleton
 public class RpcFilter extends AuthenticationFilter {
 
 	private IStoredSettings settings;
 
 	private IRuntimeManager runtimeManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
-		super.inject(dagger, filterConfig);
-		this.settings = dagger.get(IStoredSettings.class);
-		this.runtimeManager = dagger.get(IRuntimeManager.class);
+	@Inject
+	public RpcFilter(
+			IStoredSettings settings,
+			IRuntimeManager runtimeManager,
+			IAuthenticationManager authenticationManager) {
+
+		super(authenticationManager);
+
+		this.settings = settings;
+		this.runtimeManager = runtimeManager;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/RpcServlet.java b/src/main/java/com/gitblit/servlet/RpcServlet.java
index b8cdfb0..9809a25 100644
--- a/src/main/java/com/gitblit/servlet/RpcServlet.java
+++ b/src/main/java/com/gitblit/servlet/RpcServlet.java
@@ -23,6 +23,8 @@
 import java.util.List;
 import java.util.Map;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -47,13 +49,12 @@
 import com.gitblit.utils.RpcUtils;
 import com.gitblit.utils.StringUtils;
 
-import dagger.ObjectGraph;
-
 /**
  * Handles remote procedure calls.
  *
  * @author James Moger
  */
+@Singleton
 public class RpcServlet extends JsonServlet {
 
 	private static final long serialVersionUID = 1L;
@@ -64,10 +65,10 @@
 
 	private IGitblit gitblit;
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.settings = dagger.get(IStoredSettings.class);
-		this.gitblit = dagger.get(IGitblit.class);
+	@Inject
+	public RpcServlet(IStoredSettings settings, IGitblit gitblit) {
+		this.settings = settings;
+		this.gitblit = gitblit;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java b/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java
index 150dd68..69c254c 100644
--- a/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java
+++ b/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java
@@ -19,13 +19,15 @@
 import java.net.URL;
 import java.text.MessageFormat;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
-import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IUserManager;
@@ -33,15 +35,14 @@
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.StringUtils;
 
-import dagger.ObjectGraph;
-
 /**
  * Handles requests for Sparkleshare Invites
  *
  * @author James Moger
  *
  */
-public class SparkleShareInviteServlet extends DaggerServlet {
+@Singleton
+public class SparkleShareInviteServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
@@ -53,12 +54,17 @@
 
 	private IRepositoryManager repositoryManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.settings = dagger.get(IStoredSettings.class);
-		this.userManager = dagger.get(IUserManager.class);
-		this.authenticationManager = dagger.get(IAuthenticationManager.class);
-		this.repositoryManager = dagger.get(IRepositoryManager.class);
+	@Inject
+	public SparkleShareInviteServlet(
+			IStoredSettings settings,
+			IUserManager userManager,
+			IAuthenticationManager authenticationManager,
+			IRepositoryManager repositoryManager) {
+
+		this.settings = settings;
+		this.userManager = userManager;
+		this.authenticationManager = authenticationManager;
+		this.repositoryManager = repositoryManager;
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/servlet/SyndicationFilter.java b/src/main/java/com/gitblit/servlet/SyndicationFilter.java
index 78da47e..49348d0 100644
--- a/src/main/java/com/gitblit/servlet/SyndicationFilter.java
+++ b/src/main/java/com/gitblit/servlet/SyndicationFilter.java
@@ -18,8 +18,9 @@
 import java.io.IOException;
 import java.text.MessageFormat;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
@@ -27,14 +28,13 @@
 import javax.servlet.http.HttpServletResponse;
 
 import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.ProjectModel;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
-
-import dagger.ObjectGraph;
 
 /**
  * The SyndicationFilter is an AuthenticationFilter which ensures that feed
@@ -44,18 +44,24 @@
  * @author James Moger
  *
  */
+@Singleton
 public class SyndicationFilter extends AuthenticationFilter {
 
 	private IRuntimeManager runtimeManager;
 	private IRepositoryManager repositoryManager;
 	private IProjectManager projectManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
-		super.inject(dagger, filterConfig);
-		this.runtimeManager = dagger.get(IRuntimeManager.class);
-		this.repositoryManager = dagger.get(IRepositoryManager.class);
-		this.projectManager = dagger.get(IProjectManager.class);
+	@Inject
+	public SyndicationFilter(
+			IRuntimeManager runtimeManager,
+			IAuthenticationManager authenticationManager,
+			IRepositoryManager repositoryManager,
+			IProjectManager projectManager) {
+		super(authenticationManager);
+
+		this.runtimeManager = runtimeManager;
+		this.repositoryManager = repositoryManager;
+		this.projectManager = projectManager;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/servlet/SyndicationServlet.java b/src/main/java/com/gitblit/servlet/SyndicationServlet.java
index 631df78..29db54d 100644
--- a/src/main/java/com/gitblit/servlet/SyndicationServlet.java
+++ b/src/main/java/com/gitblit/servlet/SyndicationServlet.java
@@ -22,6 +22,10 @@
 import java.util.List;
 import java.util.Map;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import javax.servlet.http.HttpServlet;
+
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -31,7 +35,6 @@
 import com.gitblit.Constants;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
-import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.models.FeedEntryModel;
@@ -46,8 +49,6 @@
 import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.SyndicationUtils;
 
-import dagger.ObjectGraph;
-
 /**
  * SyndicationServlet generates RSS 2.0 feeds and feed links.
  *
@@ -56,7 +57,8 @@
  * @author James Moger
  *
  */
-public class SyndicationServlet extends DaggerServlet {
+@Singleton
+public class SyndicationServlet extends HttpServlet {
 
 	private static final long serialVersionUID = 1L;
 
@@ -68,11 +70,15 @@
 
 	private IProjectManager projectManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.settings = dagger.get(IStoredSettings.class);
-		this.repositoryManager = dagger.get(IRepositoryManager.class);
-		this.projectManager = dagger.get(IProjectManager.class);
+	@Inject
+	public SyndicationServlet(
+			IStoredSettings settings,
+			IRepositoryManager repositoryManager,
+			IProjectManager projectManager) {
+
+		this.settings = settings;
+		this.repositoryManager = repositoryManager;
+		this.projectManager = projectManager;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/tickets/BranchTicketService.java b/src/main/java/com/gitblit/tickets/BranchTicketService.java
index 8c00055..8a2bc95 100644
--- a/src/main/java/com/gitblit/tickets/BranchTicketService.java
+++ b/src/main/java/com/gitblit/tickets/BranchTicketService.java
@@ -72,6 +72,8 @@
 import com.gitblit.utils.ArrayUtils;
 import com.gitblit.utils.JGitUtils;
 import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * Implementation of a ticket service based on an orphan branch.  All tickets
@@ -81,6 +83,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class BranchTicketService extends ITicketService implements RefsChangedListener {
 
 	public static final String BRANCH = "refs/meta/gitblit/tickets";
@@ -91,6 +94,7 @@
 
 	private final Map<String, AtomicLong> lastAssignedId;
 
+	@Inject
 	public BranchTicketService(
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
@@ -112,6 +116,7 @@
 
 	@Override
 	public BranchTicketService start() {
+		log.info("{} started", getClass().getSimpleName());
 		return this;
 	}
 
diff --git a/src/main/java/com/gitblit/tickets/FileTicketService.java b/src/main/java/com/gitblit/tickets/FileTicketService.java
index b3d8838..c8346d1 100644
--- a/src/main/java/com/gitblit/tickets/FileTicketService.java
+++ b/src/main/java/com/gitblit/tickets/FileTicketService.java
@@ -42,6 +42,8 @@
 import com.gitblit.utils.ArrayUtils;
 import com.gitblit.utils.FileUtils;
 import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * Implementation of a ticket service based on a directory within the repository.
@@ -51,6 +53,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class FileTicketService extends ITicketService {
 
 	private static final String JOURNAL = "journal.json";
@@ -59,6 +62,7 @@
 
 	private final Map<String, AtomicLong> lastAssignedId;
 
+	@Inject
 	public FileTicketService(
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
@@ -77,6 +81,7 @@
 
 	@Override
 	public FileTicketService start() {
+		log.info("{} started", getClass().getSimpleName());
 		return this;
 	}
 
diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java
index 668d0bc..7e7ea9e 100644
--- a/src/main/java/com/gitblit/tickets/ITicketService.java
+++ b/src/main/java/com/gitblit/tickets/ITicketService.java
@@ -36,6 +36,7 @@
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
 import com.gitblit.extensions.TicketHook;
+import com.gitblit.manager.IManager;
 import com.gitblit.manager.INotificationManager;
 import com.gitblit.manager.IPluginManager;
 import com.gitblit.manager.IRepositoryManager;
@@ -63,7 +64,7 @@
  * @author James Moger
  *
  */
-public abstract class ITicketService {
+public abstract class ITicketService implements IManager {
 
 	public static final String SETTING_UPDATE_DIFFSTATS = "migration.updateDiffstats";
 
@@ -176,12 +177,14 @@
 	 * Start the service.
 	 * @since 1.4.0
 	 */
+	@Override
 	public abstract ITicketService start();
 
 	/**
 	 * Stop the service.
 	 * @since 1.4.0
 	 */
+	@Override
 	public final ITicketService stop() {
 		indexer.close();
 		ticketsCache.invalidateAll();
diff --git a/src/main/java/com/gitblit/tickets/NullTicketService.java b/src/main/java/com/gitblit/tickets/NullTicketService.java
index d410cdd..3947b94 100644
--- a/src/main/java/com/gitblit/tickets/NullTicketService.java
+++ b/src/main/java/com/gitblit/tickets/NullTicketService.java
@@ -28,6 +28,8 @@
 import com.gitblit.models.TicketModel;
 import com.gitblit.models.TicketModel.Attachment;
 import com.gitblit.models.TicketModel.Change;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * Implementation of a ticket service that rejects everything.
@@ -35,8 +37,10 @@
  * @author James Moger
  *
  */
+@Singleton
 public class NullTicketService extends ITicketService {
 
+	@Inject
 	public NullTicketService(
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
@@ -58,6 +62,7 @@
 
 	@Override
 	public NullTicketService start() {
+		log.info("{} started", getClass().getSimpleName());
 		return this;
 	}
 
diff --git a/src/main/java/com/gitblit/tickets/RedisTicketService.java b/src/main/java/com/gitblit/tickets/RedisTicketService.java
index d773b0b..0f9ad17 100644
--- a/src/main/java/com/gitblit/tickets/RedisTicketService.java
+++ b/src/main/java/com/gitblit/tickets/RedisTicketService.java
@@ -43,6 +43,8 @@
 import com.gitblit.models.TicketModel.Change;
 import com.gitblit.utils.ArrayUtils;
 import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * Implementation of a ticket service based on a Redis key-value store.  All
@@ -53,6 +55,7 @@
  * @author James Moger
  *
  */
+@Singleton
 public class RedisTicketService extends ITicketService {
 
 	private final JedisPool pool;
@@ -61,6 +64,7 @@
 		journal, ticket, counter
 	}
 
+	@Inject
 	public RedisTicketService(
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
@@ -80,6 +84,10 @@
 
 	@Override
 	public RedisTicketService start() {
+		log.info("{} started", getClass().getSimpleName());
+		if (!isReady()) {
+			log.warn("{} is not ready!", getClass().getSimpleName());
+		}
 		return this;
 	}
 
diff --git a/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java b/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
index a063dc7..1a2cd68 100644
--- a/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
@@ -29,6 +29,7 @@
 import com.google.common.base.Charsets;
 import com.google.common.base.Joiner;
 import com.google.common.io.Files;
+import com.google.inject.Inject;
 
 /**
  * Manages public keys on the filesystem.
@@ -42,6 +43,7 @@
 
 	protected final Map<File, Long> lastModifieds;
 
+	@Inject
 	public FileKeyManager(IRuntimeManager runtimeManager) {
 		this.runtimeManager = runtimeManager;
 		this.lastModifieds = new ConcurrentHashMap<File, Long>();
diff --git a/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java b/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java
index 357b34a..bf78378 100644
--- a/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java
@@ -20,6 +20,8 @@
 import java.util.List;
 import java.util.Map;
 
+import com.google.inject.Inject;
+
 /**
  * Memory public key manager.
  *
@@ -30,6 +32,7 @@
 
 	final Map<String, List<SshKey>> keys;
 
+	@Inject
 	public MemoryKeyManager() {
 		keys = new HashMap<String, List<SshKey>>();
 	}
diff --git a/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java b/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
index 0761d84..fcd3e19 100644
--- a/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
@@ -17,6 +17,8 @@
 
 import java.util.List;
 
+import com.google.inject.Inject;
+
 /**
  * Rejects all public key management requests.
  *
@@ -25,6 +27,7 @@
  */
 public class NullKeyManager extends IPublicKeyManager {
 
+	@Inject
 	public NullKeyManager() {
 	}
 
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index f63ff3d..036a05a 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -43,6 +43,7 @@
 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;
@@ -89,7 +90,11 @@
 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.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
 
 	private final Class<? extends WebPage> homePageClass = MyDashboardPage.class;
@@ -97,6 +102,10 @@
 	private final Class<? extends WebPage> newRepositoryPageClass = NewRepositoryPage.class;
 
 	private final Map<String, CacheControl> cacheablePages = new HashMap<String, CacheControl>();
+
+	private final Provider<IPublicKeyManager> publicKeyManagerProvider;
+
+	private final Provider<ITicketService> ticketServiceProvider;
 
 	private final IStoredSettings settings;
 
@@ -110,8 +119,6 @@
 
 	private final IAuthenticationManager authenticationManager;
 
-	private final IPublicKeyManager publicKeyManager;
-
 	private final IRepositoryManager repositoryManager;
 
 	private final IProjectManager projectManager;
@@ -120,30 +127,37 @@
 
 	private final IGitblit gitblit;
 
+	private final IServicesManager services;
+
+	@Inject
 	public GitBlitWebApp(
+			Provider<IPublicKeyManager> publicKeyManagerProvider,
+			Provider<ITicketService> ticketServiceProvider,
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
 			INotificationManager notificationManager,
 			IUserManager userManager,
 			IAuthenticationManager authenticationManager,
-			IPublicKeyManager publicKeyManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
 			IFederationManager federationManager,
-			IGitblit gitblit) {
+			IGitblit gitblit,
+			IServicesManager services) {
 
 		super();
+		this.publicKeyManagerProvider = publicKeyManagerProvider;
+		this.ticketServiceProvider = ticketServiceProvider;
 		this.settings = runtimeManager.getSettings();
 		this.runtimeManager = runtimeManager;
 		this.pluginManager = pluginManager;
 		this.notificationManager = notificationManager;
 		this.userManager = userManager;
 		this.authenticationManager = authenticationManager;
-		this.publicKeyManager = publicKeyManager;
 		this.repositoryManager = repositoryManager;
 		this.projectManager = projectManager;
 		this.federationManager = federationManager;
 		this.gitblit = gitblit;
+		this.services = services;
 	}
 
 	@Override
@@ -380,7 +394,7 @@
 	 */
 	@Override
 	public IPublicKeyManager keys() {
-		return publicKeyManager;
+		return publicKeyManagerProvider.get();
 	}
 
 	/* (non-Javadoc)
@@ -416,11 +430,19 @@
 	}
 
 	/* (non-Javadoc)
+	 * @see com.gitblit.wicket.Webapp#services()
+	 */
+	@Override
+	public IServicesManager services() {
+		return services;
+	}
+
+	/* (non-Javadoc)
 	 * @see com.gitblit.wicket.Webapp#tickets()
 	 */
 	@Override
 	public ITicketService tickets() {
-		return gitblit.getTicketService();
+		return ticketServiceProvider.get();
 	}
 
 	/* (non-Javadoc)
diff --git a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
index a56e699..7013097 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.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 abstract IGitblit gitblit();
 
+	public abstract IServicesManager services();
+
 	public abstract ITicketService tickets();
 
 	public abstract TimeZone getTimezone();
diff --git a/src/main/java/com/gitblit/wicket/GitblitWicketFilter.java b/src/main/java/com/gitblit/wicket/GitblitWicketFilter.java
index 7865fb3..68ad84a 100644
--- a/src/main/java/com/gitblit/wicket/GitblitWicketFilter.java
+++ b/src/main/java/com/gitblit/wicket/GitblitWicketFilter.java
@@ -17,6 +17,8 @@
 
 import java.util.Date;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.wicket.protocol.http.IWebApplicationFactory;
@@ -28,7 +30,6 @@
 
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
-import com.gitblit.dagger.DaggerWicketFilter;
 import com.gitblit.manager.IProjectManager;
 import com.gitblit.manager.IRepositoryManager;
 import com.gitblit.manager.IRuntimeManager;
@@ -36,8 +37,6 @@
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.utils.JGitUtils;
 import com.gitblit.utils.StringUtils;
-
-import dagger.ObjectGraph;
 
 /**
  *
@@ -47,7 +46,8 @@
  * @author James Moger
  *
  */
-public class GitblitWicketFilter extends DaggerWicketFilter {
+@Singleton
+public class GitblitWicketFilter extends WicketFilter {
 
 	private IStoredSettings settings;
 
@@ -59,13 +59,19 @@
 
 	private GitBlitWebApp webapp;
 
-	@Override
-	protected void inject(ObjectGraph dagger) {
-		this.settings = dagger.get(IStoredSettings.class);
-		this.runtimeManager = dagger.get(IRuntimeManager.class);
-		this.repositoryManager = dagger.get(IRepositoryManager.class);
-		this.projectManager = dagger.get(IProjectManager.class);
-		this.webapp = dagger.get(GitBlitWebApp.class);
+	@Inject
+	public GitblitWicketFilter(
+			IStoredSettings settings,
+			IRuntimeManager runtimeManager,
+			IRepositoryManager repositoryManager,
+			IProjectManager projectManager,
+			GitBlitWebApp webapp) {
+
+		this.settings = settings;
+		this.runtimeManager = runtimeManager;
+		this.repositoryManager = repositoryManager;
+		this.projectManager = projectManager;
+		this.webapp = webapp;
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java
index b3c5243..72d1e1a 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 @@
 		}
 
 		HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
-		List<RepositoryUrl> repositoryUrls = app().gitblit().getRepositoryUrls(req, user, repository);
+		List<RepositoryUrl> 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 f5f63d2..e1e8162 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 @@
 	 */
 	protected RepositoryUrl getRepositoryUrl(UserModel user, RepositoryModel repository) {
 		HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
-		List<RepositoryUrl> urls = app().gitblit().getRepositoryUrls(req, user, repository);
+		List<RepositoryUrl> 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 8931d5e..e21431d 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 @@
 		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 @@
 				emailMeOnMyTicketChanges).setVisible(app().notifier().isSendingMail()));
 
 		List<Transport> 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 938226a..0666fcd 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 @@
 
 		HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
 
-		List<RepositoryUrl> repositoryUrls = app().gitblit().getRepositoryUrls(req, user, repository);
+		List<RepositoryUrl> 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 @@
 		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/site/design.mkd b/src/site/design.mkd
index cd4b1b7..9ef302c 100644
--- a/src/site/design.mkd
+++ b/src/site/design.mkd
@@ -57,6 +57,7 @@
 - [jedis](https://github.com/xetorthio/jedis) (MIT)
 - [Mina SSHD](https://mina.apache.org) (Apache 2.0)
 - [pf4j](https://github.com/decebals/pf4j) (Apache 2.0)
+- [google-guice](https://code.google.com/p/google-guice) (Apache 2.0)
 
 ### Other Build Dependencies
 - [Fancybox image viewer](http://fancybox.net) (MIT and GPL dual-licensed)
diff --git a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
index 54be539..9a71c88 100644
--- a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
+++ b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
@@ -28,6 +28,7 @@
 import com.gitblit.models.ServerSettings;
 import com.gitblit.models.ServerStatus;
 import com.gitblit.models.SettingModel;
+import com.google.inject.Injector;
 
 public class MockRuntimeManager implements IRuntimeManager {
 
@@ -57,6 +58,11 @@
 	}
 
 	@Override
+	public Injector getInjector() {
+		return null;
+	}
+
+	@Override
 	public void setBaseFolder(File folder) {
 		this.baseFolder = folder;
 	}
@@ -74,26 +80,6 @@
 	@Override
 	public Locale getLocale() {
 		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

--
Gitblit v1.9.1