blob: 372d0e39973e6a962d1f229b8b7f3d34e8c7ed3f [file] [log] [blame]
Dave Borowitz09ff62b2012-12-17 14:09:16 -08001// Copyright 2012 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.gitiles.dev;
16
Dave Borowitz03397692012-12-18 17:11:16 -080017import static com.google.gitiles.GitilesServlet.STATIC_PREFIX;
18
19import com.google.common.base.Objects;
20import com.google.gitiles.DebugRenderer;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080021import com.google.gitiles.GitilesServlet;
Dave Borowitz03397692012-12-18 17:11:16 -080022import com.google.gitiles.PathServlet;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080023
24import org.eclipse.jetty.server.Connector;
25import org.eclipse.jetty.server.Handler;
26import org.eclipse.jetty.server.Server;
Dave Borowitze1056bb2013-01-11 10:31:37 -080027import org.eclipse.jetty.server.bio.SocketConnector;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080028import org.eclipse.jetty.server.handler.ContextHandler;
29import org.eclipse.jetty.server.handler.ContextHandlerCollection;
30import org.eclipse.jetty.server.handler.ResourceHandler;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080031import org.eclipse.jetty.servlet.ServletContextHandler;
32import org.eclipse.jetty.servlet.ServletHolder;
33import org.eclipse.jetty.util.resource.FileResource;
34import org.eclipse.jetty.util.thread.QueuedThreadPool;
35import org.eclipse.jetty.util.thread.ThreadPool;
Dave Borowitz03397692012-12-18 17:11:16 -080036import org.eclipse.jgit.errors.ConfigInvalidException;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080037import org.eclipse.jgit.lib.Config;
Dave Borowitz03397692012-12-18 17:11:16 -080038import org.eclipse.jgit.storage.file.FileBasedConfig;
39import org.eclipse.jgit.util.FS;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080042
43import java.io.File;
44import java.io.FileNotFoundException;
45import java.io.IOException;
Dave Borowitz03397692012-12-18 17:11:16 -080046import java.net.InetAddress;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080047import java.net.URI;
48import java.net.URISyntaxException;
Dave Borowitz03397692012-12-18 17:11:16 -080049import java.net.UnknownHostException;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080050
51class DevServer {
Dave Borowitz03397692012-12-18 17:11:16 -080052 private static final Logger log = LoggerFactory.getLogger(PathServlet.class);
53
54 private static Config defaultConfig() throws UnknownHostException {
55 Config cfg = new Config();
56 String cwd = System.getProperty("user.dir");
57 cfg.setString("gitiles", null, "basePath", cwd);
58 cfg.setBoolean("gitiles", null, "exportAll", true);
59 cfg.setString("gitiles", null, "baseGitUrl", "file://" + cwd + "/");
60 String networkHostName = InetAddress.getLocalHost().getCanonicalHostName();
61 cfg.setString("gitiles", null, "siteTitle",
62 String.format("Gitiles - %s:%s", networkHostName, cwd));
63 cfg.setString("gitiles", null, "canonicalHostName", new File(cwd).getName());
64 return cfg;
65 }
66
67 private static FileNotFoundException badSourceRoot(URI u) {
68 return new FileNotFoundException("Cannot find source root from " + u);
69 }
70
71 private static FileNotFoundException badSourceRoot(URI u, Throwable cause) {
72 FileNotFoundException notFound = badSourceRoot(u);
73 notFound.initCause(cause);
74 return notFound;
75 }
76
77 private static File findSourceRoot() throws IOException {
78 URI u;
79 try {
80 u = DevServer.class.getResource(DevServer.class.getSimpleName() + ".class").toURI();
81 } catch (URISyntaxException e) {
82 u = null;
83 }
84 if (u == null) {
85 throw new FileNotFoundException("Cannot find Gitiles source directory");
86 }
87 if ("jar".equals(u.getScheme())) {
Dave Borowitzb2f4d562012-12-27 16:36:37 -080088 String path = u.getSchemeSpecificPart();
89 int jarEntry = path.indexOf("!/");
Dave Borowitz03397692012-12-18 17:11:16 -080090 if (jarEntry < 0) {
91 throw badSourceRoot(u);
92 }
93 try {
Dave Borowitzb2f4d562012-12-27 16:36:37 -080094 return findSourceRoot(new URI(path.substring(0, jarEntry)));
Dave Borowitz03397692012-12-18 17:11:16 -080095 } catch (URISyntaxException e) {
96 throw badSourceRoot(u, e);
97 }
98 } else {
99 return findSourceRoot(u);
100 }
101 }
102
103 private static File findSourceRoot(URI targetUri) throws IOException {
104 if (!"file".equals(targetUri.getScheme())) {
105 throw badSourceRoot(targetUri);
106 }
107 String targetPath = targetUri.getPath();
108 // targetPath is an arbitrary path under gitiles-dev/target in the standard
109 // Maven package layout.
110 int targetIndex = targetPath.lastIndexOf("gitiles-dev/target/");
111 if (targetIndex < 0) {
112 throw badSourceRoot(targetUri);
113 }
114 String path = targetPath.substring(0, targetIndex);
115 URI u;
116 try {
117 u = new URI("file", path, null).normalize();
118 } catch (URISyntaxException e) {
119 throw new IOException(e);
120 }
121 File root = new File(u);
122 if (!root.exists() || !root.isDirectory()) {
123 throw badSourceRoot(targetUri);
124 }
125 return root;
126 }
127
128 private final File sourceRoot;
129 private final Config cfg;
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800130 private final Server httpd;
131
Dave Borowitz03397692012-12-18 17:11:16 -0800132 DevServer(File cfgFile) throws IOException, ConfigInvalidException {
133 sourceRoot = findSourceRoot();
134
135 Config cfg = defaultConfig();
136 if (cfgFile.exists() && cfgFile.isFile()) {
137 FileBasedConfig fcfg = new FileBasedConfig(cfg, cfgFile, FS.DETECTED);
138 fcfg.load();
139 cfg = fcfg;
140 } else {
Dave Borowitzfd25c3a2013-01-11 14:37:11 -0800141 log.info("Config file {} not found, using defaults", cfgFile.getPath());
Dave Borowitz03397692012-12-18 17:11:16 -0800142 }
143 this.cfg = cfg;
144
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800145 httpd = new Server();
Dave Borowitz03397692012-12-18 17:11:16 -0800146 httpd.setConnectors(connectors());
147 httpd.setThreadPool(threadPool());
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800148 httpd.setHandler(handler());
149 }
150
151 void start() throws Exception {
152 httpd.start();
153 httpd.join();
154 }
155
Dave Borowitz03397692012-12-18 17:11:16 -0800156 private Connector[] connectors() {
Dave Borowitze1056bb2013-01-11 10:31:37 -0800157 Connector c = new SocketConnector();
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800158 c.setHost(null);
159 c.setPort(cfg.getInt("gitiles", null, "port", 8080));
160 c.setStatsOn(false);
161 return new Connector[]{c};
162 }
163
Dave Borowitz03397692012-12-18 17:11:16 -0800164 private ThreadPool threadPool() {
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800165 QueuedThreadPool pool = new QueuedThreadPool();
166 pool.setName("HTTP");
167 pool.setMinThreads(2);
168 pool.setMaxThreads(10);
169 pool.setMaxQueued(50);
170 return pool;
171 }
172
173 private Handler handler() throws IOException {
174 ContextHandlerCollection handlers = new ContextHandlerCollection();
175 handlers.addHandler(staticHandler());
176 handlers.addHandler(appHandler());
177 return handlers;
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800178 }
179
180 private Handler appHandler() {
Dave Borowitz03397692012-12-18 17:11:16 -0800181 GitilesServlet servlet = new GitilesServlet(
182 cfg,
183 new DebugRenderer(
184 STATIC_PREFIX,
185 cfg.getString("gitiles", null, "customTemplates"),
186 new File(sourceRoot, "gitiles-servlet/src/main/resources/com/google/gitiles/templates")
187 .getPath(),
188 Objects.firstNonNull(cfg.getString("gitiles", null, "siteTitle"), "Gitiles")),
Dave Borowitz14ce8282012-12-20 14:08:25 -0800189 null, null, null, null, null);
Dave Borowitz03397692012-12-18 17:11:16 -0800190
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800191 ServletContextHandler handler = new ServletContextHandler();
192 handler.setContextPath("");
Dave Borowitz03397692012-12-18 17:11:16 -0800193 handler.addServlet(new ServletHolder(servlet), "/*");
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800194 return handler;
195 }
196
Dave Borowitz03397692012-12-18 17:11:16 -0800197 private Handler staticHandler() throws IOException {
198 File staticRoot = new File(sourceRoot,
199 "gitiles-servlet/src/main/resources/com/google/gitiles/static");
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800200 ResourceHandler rh = new ResourceHandler();
201 try {
Dave Borowitz03397692012-12-18 17:11:16 -0800202 rh.setBaseResource(new FileResource(staticRoot.toURI().toURL()));
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800203 } catch (URISyntaxException e) {
Dave Borowitz03397692012-12-18 17:11:16 -0800204 throw new IOException(e);
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800205 }
206 rh.setWelcomeFiles(new String[]{});
207 rh.setDirectoriesListed(false);
208 ContextHandler handler = new ContextHandler("/+static");
209 handler.setHandler(rh);
210 return handler;
211 }
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800212}