blob: 8502aac0352ee7dea2660b73c2a612635774b263 [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())) {
88 int jarEntry = u.getPath().indexOf("!/");
89 if (jarEntry < 0) {
90 throw badSourceRoot(u);
91 }
92 try {
93 return findSourceRoot(new URI(u.getPath().substring(0, jarEntry)));
94 } catch (URISyntaxException e) {
95 throw badSourceRoot(u, e);
96 }
97 } else {
98 return findSourceRoot(u);
99 }
100 }
101
102 private static File findSourceRoot(URI targetUri) throws IOException {
103 if (!"file".equals(targetUri.getScheme())) {
104 throw badSourceRoot(targetUri);
105 }
106 String targetPath = targetUri.getPath();
107 // targetPath is an arbitrary path under gitiles-dev/target in the standard
108 // Maven package layout.
109 int targetIndex = targetPath.lastIndexOf("gitiles-dev/target/");
110 if (targetIndex < 0) {
111 throw badSourceRoot(targetUri);
112 }
113 String path = targetPath.substring(0, targetIndex);
114 URI u;
115 try {
116 u = new URI("file", path, null).normalize();
117 } catch (URISyntaxException e) {
118 throw new IOException(e);
119 }
120 File root = new File(u);
121 if (!root.exists() || !root.isDirectory()) {
122 throw badSourceRoot(targetUri);
123 }
124 return root;
125 }
126
127 private final File sourceRoot;
128 private final Config cfg;
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800129 private final Server httpd;
130
Dave Borowitz03397692012-12-18 17:11:16 -0800131 DevServer(File cfgFile) throws IOException, ConfigInvalidException {
132 sourceRoot = findSourceRoot();
133
134 Config cfg = defaultConfig();
135 if (cfgFile.exists() && cfgFile.isFile()) {
136 FileBasedConfig fcfg = new FileBasedConfig(cfg, cfgFile, FS.DETECTED);
137 fcfg.load();
138 cfg = fcfg;
139 } else {
140 // TODO(dborowitz): This is not getting outputted, we're probably missing
141 // some logging config.
142 log.info("Config file %s not found, using defaults", cfgFile.getPath());
143 }
144 this.cfg = cfg;
145
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800146 httpd = new Server();
Dave Borowitz03397692012-12-18 17:11:16 -0800147 httpd.setConnectors(connectors());
148 httpd.setThreadPool(threadPool());
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800149 httpd.setHandler(handler());
150 }
151
152 void start() throws Exception {
153 httpd.start();
154 httpd.join();
155 }
156
Dave Borowitz03397692012-12-18 17:11:16 -0800157 private Connector[] connectors() {
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800158 Connector c = new SelectChannelConnector();
159 c.setHost(null);
160 c.setPort(cfg.getInt("gitiles", null, "port", 8080));
161 c.setStatsOn(false);
162 return new Connector[]{c};
163 }
164
Dave Borowitz03397692012-12-18 17:11:16 -0800165 private ThreadPool threadPool() {
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800166 QueuedThreadPool pool = new QueuedThreadPool();
167 pool.setName("HTTP");
168 pool.setMinThreads(2);
169 pool.setMaxThreads(10);
170 pool.setMaxQueued(50);
171 return pool;
172 }
173
174 private Handler handler() throws IOException {
175 ContextHandlerCollection handlers = new ContextHandlerCollection();
176 handlers.addHandler(staticHandler());
177 handlers.addHandler(appHandler());
178 return handlers;
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800179 }
180
181 private Handler appHandler() {
Dave Borowitz03397692012-12-18 17:11:16 -0800182 GitilesServlet servlet = new GitilesServlet(
183 cfg,
184 new DebugRenderer(
185 STATIC_PREFIX,
186 cfg.getString("gitiles", null, "customTemplates"),
187 new File(sourceRoot, "gitiles-servlet/src/main/resources/com/google/gitiles/templates")
188 .getPath(),
189 Objects.firstNonNull(cfg.getString("gitiles", null, "siteTitle"), "Gitiles")),
190 null, null, null, null);
191
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800192 ServletContextHandler handler = new ServletContextHandler();
193 handler.setContextPath("");
Dave Borowitz03397692012-12-18 17:11:16 -0800194 handler.addServlet(new ServletHolder(servlet), "/*");
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800195 return handler;
196 }
197
Dave Borowitz03397692012-12-18 17:11:16 -0800198 private Handler staticHandler() throws IOException {
199 File staticRoot = new File(sourceRoot,
200 "gitiles-servlet/src/main/resources/com/google/gitiles/static");
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800201 ResourceHandler rh = new ResourceHandler();
202 try {
Dave Borowitz03397692012-12-18 17:11:16 -0800203 rh.setBaseResource(new FileResource(staticRoot.toURI().toURL()));
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800204 } catch (URISyntaxException e) {
Dave Borowitz03397692012-12-18 17:11:16 -0800205 throw new IOException(e);
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800206 }
207 rh.setWelcomeFiles(new String[]{});
208 rh.setDirectoriesListed(false);
209 ContextHandler handler = new ContextHandler("/+static");
210 handler.setHandler(rh);
211 return handler;
212 }
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800213}