blob: dec9b4821a29116b029ccf03d1c2cecd674efea9 [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;
27import org.eclipse.jetty.server.handler.ContextHandler;
28import org.eclipse.jetty.server.handler.ContextHandlerCollection;
29import org.eclipse.jetty.server.handler.ResourceHandler;
30import org.eclipse.jetty.server.nio.SelectChannelConnector;
31import 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 {
141 // TODO(dborowitz): This is not getting outputted, we're probably missing
142 // some logging config.
143 log.info("Config file %s not found, using defaults", cfgFile.getPath());
144 }
145 this.cfg = cfg;
146
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800147 httpd = new Server();
Dave Borowitz03397692012-12-18 17:11:16 -0800148 httpd.setConnectors(connectors());
149 httpd.setThreadPool(threadPool());
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800150 httpd.setHandler(handler());
151 }
152
153 void start() throws Exception {
154 httpd.start();
155 httpd.join();
156 }
157
Dave Borowitz03397692012-12-18 17:11:16 -0800158 private Connector[] connectors() {
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800159 Connector c = new SelectChannelConnector();
160 c.setHost(null);
161 c.setPort(cfg.getInt("gitiles", null, "port", 8080));
162 c.setStatsOn(false);
163 return new Connector[]{c};
164 }
165
Dave Borowitz03397692012-12-18 17:11:16 -0800166 private ThreadPool threadPool() {
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800167 QueuedThreadPool pool = new QueuedThreadPool();
168 pool.setName("HTTP");
169 pool.setMinThreads(2);
170 pool.setMaxThreads(10);
171 pool.setMaxQueued(50);
172 return pool;
173 }
174
175 private Handler handler() throws IOException {
176 ContextHandlerCollection handlers = new ContextHandlerCollection();
177 handlers.addHandler(staticHandler());
178 handlers.addHandler(appHandler());
179 return handlers;
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800180 }
181
182 private Handler appHandler() {
Dave Borowitz03397692012-12-18 17:11:16 -0800183 GitilesServlet servlet = new GitilesServlet(
184 cfg,
185 new DebugRenderer(
186 STATIC_PREFIX,
187 cfg.getString("gitiles", null, "customTemplates"),
188 new File(sourceRoot, "gitiles-servlet/src/main/resources/com/google/gitiles/templates")
189 .getPath(),
190 Objects.firstNonNull(cfg.getString("gitiles", null, "siteTitle"), "Gitiles")),
Dave Borowitz14ce8282012-12-20 14:08:25 -0800191 null, null, null, null, null);
Dave Borowitz03397692012-12-18 17:11:16 -0800192
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800193 ServletContextHandler handler = new ServletContextHandler();
194 handler.setContextPath("");
Dave Borowitz03397692012-12-18 17:11:16 -0800195 handler.addServlet(new ServletHolder(servlet), "/*");
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800196 return handler;
197 }
198
Dave Borowitz03397692012-12-18 17:11:16 -0800199 private Handler staticHandler() throws IOException {
200 File staticRoot = new File(sourceRoot,
201 "gitiles-servlet/src/main/resources/com/google/gitiles/static");
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800202 ResourceHandler rh = new ResourceHandler();
203 try {
Dave Borowitz03397692012-12-18 17:11:16 -0800204 rh.setBaseResource(new FileResource(staticRoot.toURI().toURL()));
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800205 } catch (URISyntaxException e) {
Dave Borowitz03397692012-12-18 17:11:16 -0800206 throw new IOException(e);
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800207 }
208 rh.setWelcomeFiles(new String[]{});
209 rh.setDirectoriesListed(false);
210 ContextHandler handler = new ContextHandler("/+static");
211 handler.setHandler(rh);
212 return handler;
213 }
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800214}