| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 1 | // 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 | |
| 15 | package com.google.gitiles.dev; |
| 16 | |
| Dave Borowitz | c410f96 | 2014-09-23 10:49:26 -0700 | [diff] [blame] | 17 | import static com.google.common.base.MoreObjects.firstNonNull; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 18 | import static com.google.gitiles.GitilesServlet.STATIC_PREFIX; |
| 19 | |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 20 | import com.google.gitiles.DebugRenderer; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 21 | import com.google.gitiles.GitilesServlet; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 22 | import com.google.gitiles.PathServlet; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 23 | |
| 24 | import org.eclipse.jetty.server.Connector; |
| 25 | import org.eclipse.jetty.server.Handler; |
| 26 | import org.eclipse.jetty.server.Server; |
| Dave Borowitz | e1056bb | 2013-01-11 10:31:37 -0800 | [diff] [blame] | 27 | import org.eclipse.jetty.server.bio.SocketConnector; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 28 | import org.eclipse.jetty.server.handler.ContextHandler; |
| 29 | import org.eclipse.jetty.server.handler.ContextHandlerCollection; |
| 30 | import org.eclipse.jetty.server.handler.ResourceHandler; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 31 | import org.eclipse.jetty.servlet.ServletContextHandler; |
| 32 | import org.eclipse.jetty.servlet.ServletHolder; |
| 33 | import org.eclipse.jetty.util.resource.FileResource; |
| 34 | import org.eclipse.jetty.util.thread.QueuedThreadPool; |
| 35 | import org.eclipse.jetty.util.thread.ThreadPool; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 36 | import org.eclipse.jgit.errors.ConfigInvalidException; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 37 | import org.eclipse.jgit.lib.Config; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 38 | import org.eclipse.jgit.storage.file.FileBasedConfig; |
| 39 | import org.eclipse.jgit.util.FS; |
| 40 | import org.slf4j.Logger; |
| 41 | import org.slf4j.LoggerFactory; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 42 | |
| 43 | import java.io.File; |
| 44 | import java.io.FileNotFoundException; |
| 45 | import java.io.IOException; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 46 | import java.net.InetAddress; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 47 | import java.net.URI; |
| 48 | import java.net.URISyntaxException; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 49 | import java.net.UnknownHostException; |
| Dave Borowitz | 76bbefd | 2014-03-11 16:57:45 -0700 | [diff] [blame] | 50 | import java.util.Arrays; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 51 | |
| 52 | class DevServer { |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 53 | private static final Logger log = LoggerFactory.getLogger(PathServlet.class); |
| 54 | |
| Dave Borowitz | 823724a | 2013-07-30 13:18:42 -0700 | [diff] [blame] | 55 | private static Config defaultConfig() { |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 56 | Config cfg = new Config(); |
| 57 | String cwd = System.getProperty("user.dir"); |
| 58 | cfg.setString("gitiles", null, "basePath", cwd); |
| 59 | cfg.setBoolean("gitiles", null, "exportAll", true); |
| 60 | cfg.setString("gitiles", null, "baseGitUrl", "file://" + cwd + "/"); |
| Dave Borowitz | 823724a | 2013-07-30 13:18:42 -0700 | [diff] [blame] | 61 | String networkHostName; |
| 62 | try { |
| 63 | networkHostName = InetAddress.getLocalHost().getCanonicalHostName(); |
| 64 | } catch (UnknownHostException e) { |
| 65 | networkHostName = "127.0.0.1"; |
| 66 | } |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 67 | cfg.setString("gitiles", null, "siteTitle", |
| 68 | String.format("Gitiles - %s:%s", networkHostName, cwd)); |
| 69 | cfg.setString("gitiles", null, "canonicalHostName", new File(cwd).getName()); |
| 70 | return cfg; |
| 71 | } |
| 72 | |
| 73 | private static FileNotFoundException badSourceRoot(URI u) { |
| 74 | return new FileNotFoundException("Cannot find source root from " + u); |
| 75 | } |
| 76 | |
| 77 | private static FileNotFoundException badSourceRoot(URI u, Throwable cause) { |
| 78 | FileNotFoundException notFound = badSourceRoot(u); |
| 79 | notFound.initCause(cause); |
| 80 | return notFound; |
| 81 | } |
| 82 | |
| 83 | private static File findSourceRoot() throws IOException { |
| 84 | URI u; |
| 85 | try { |
| 86 | u = DevServer.class.getResource(DevServer.class.getSimpleName() + ".class").toURI(); |
| 87 | } catch (URISyntaxException e) { |
| 88 | u = null; |
| 89 | } |
| 90 | if (u == null) { |
| 91 | throw new FileNotFoundException("Cannot find Gitiles source directory"); |
| 92 | } |
| 93 | if ("jar".equals(u.getScheme())) { |
| Dave Borowitz | b2f4d56 | 2012-12-27 16:36:37 -0800 | [diff] [blame] | 94 | String path = u.getSchemeSpecificPart(); |
| 95 | int jarEntry = path.indexOf("!/"); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 96 | if (jarEntry < 0) { |
| 97 | throw badSourceRoot(u); |
| 98 | } |
| 99 | try { |
| Dave Borowitz | b2f4d56 | 2012-12-27 16:36:37 -0800 | [diff] [blame] | 100 | return findSourceRoot(new URI(path.substring(0, jarEntry))); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 101 | } catch (URISyntaxException e) { |
| 102 | throw badSourceRoot(u, e); |
| 103 | } |
| 104 | } else { |
| 105 | return findSourceRoot(u); |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | private static File findSourceRoot(URI targetUri) throws IOException { |
| 110 | if (!"file".equals(targetUri.getScheme())) { |
| 111 | throw badSourceRoot(targetUri); |
| 112 | } |
| 113 | String targetPath = targetUri.getPath(); |
| David Ostrovsky | 22c45b3 | 2014-02-23 22:22:26 +0100 | [diff] [blame] | 114 | // targetPath is an arbitrary path under buck-out/ in our Buck package |
| 115 | // layout. |
| 116 | int targetIndex = targetPath.lastIndexOf("buck-out/"); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 117 | if (targetIndex < 0) { |
| 118 | throw badSourceRoot(targetUri); |
| 119 | } |
| 120 | String path = targetPath.substring(0, targetIndex); |
| 121 | URI u; |
| 122 | try { |
| 123 | u = new URI("file", path, null).normalize(); |
| 124 | } catch (URISyntaxException e) { |
| 125 | throw new IOException(e); |
| 126 | } |
| 127 | File root = new File(u); |
| 128 | if (!root.exists() || !root.isDirectory()) { |
| 129 | throw badSourceRoot(targetUri); |
| 130 | } |
| 131 | return root; |
| 132 | } |
| 133 | |
| 134 | private final File sourceRoot; |
| 135 | private final Config cfg; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 136 | private final Server httpd; |
| 137 | |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 138 | DevServer(File cfgFile) throws IOException, ConfigInvalidException { |
| 139 | sourceRoot = findSourceRoot(); |
| 140 | |
| 141 | Config cfg = defaultConfig(); |
| 142 | if (cfgFile.exists() && cfgFile.isFile()) { |
| 143 | FileBasedConfig fcfg = new FileBasedConfig(cfg, cfgFile, FS.DETECTED); |
| 144 | fcfg.load(); |
| 145 | cfg = fcfg; |
| 146 | } else { |
| Dave Borowitz | fd25c3a | 2013-01-11 14:37:11 -0800 | [diff] [blame] | 147 | log.info("Config file {} not found, using defaults", cfgFile.getPath()); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 148 | } |
| 149 | this.cfg = cfg; |
| 150 | |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 151 | httpd = new Server(); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 152 | httpd.setConnectors(connectors()); |
| 153 | httpd.setThreadPool(threadPool()); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 154 | httpd.setHandler(handler()); |
| 155 | } |
| 156 | |
| 157 | void start() throws Exception { |
| 158 | httpd.start(); |
| 159 | httpd.join(); |
| 160 | } |
| 161 | |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 162 | private Connector[] connectors() { |
| Dave Borowitz | e1056bb | 2013-01-11 10:31:37 -0800 | [diff] [blame] | 163 | Connector c = new SocketConnector(); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 164 | c.setHost(null); |
| 165 | c.setPort(cfg.getInt("gitiles", null, "port", 8080)); |
| 166 | c.setStatsOn(false); |
| 167 | return new Connector[]{c}; |
| 168 | } |
| 169 | |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 170 | private ThreadPool threadPool() { |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 171 | QueuedThreadPool pool = new QueuedThreadPool(); |
| 172 | pool.setName("HTTP"); |
| 173 | pool.setMinThreads(2); |
| 174 | pool.setMaxThreads(10); |
| 175 | pool.setMaxQueued(50); |
| 176 | return pool; |
| 177 | } |
| 178 | |
| 179 | private Handler handler() throws IOException { |
| 180 | ContextHandlerCollection handlers = new ContextHandlerCollection(); |
| 181 | handlers.addHandler(staticHandler()); |
| 182 | handlers.addHandler(appHandler()); |
| 183 | return handlers; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 184 | } |
| 185 | |
| 186 | private Handler appHandler() { |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 187 | GitilesServlet servlet = new GitilesServlet( |
| 188 | cfg, |
| 189 | new DebugRenderer( |
| 190 | STATIC_PREFIX, |
| Dave Borowitz | 76bbefd | 2014-03-11 16:57:45 -0700 | [diff] [blame] | 191 | Arrays.asList(cfg.getStringList("gitiles", null, "customTemplates")), |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 192 | new File(sourceRoot, "gitiles-servlet/src/main/resources/com/google/gitiles/templates") |
| 193 | .getPath(), |
| Dave Borowitz | c410f96 | 2014-09-23 10:49:26 -0700 | [diff] [blame] | 194 | firstNonNull(cfg.getString("gitiles", null, "siteTitle"), "Gitiles")), |
| Dave Borowitz | 86462df | 2014-02-03 14:23:57 -0800 | [diff] [blame] | 195 | null, null, null, null, null, null, null); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 196 | |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 197 | ServletContextHandler handler = new ServletContextHandler(); |
| 198 | handler.setContextPath(""); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 199 | handler.addServlet(new ServletHolder(servlet), "/*"); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 200 | return handler; |
| 201 | } |
| 202 | |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 203 | private Handler staticHandler() throws IOException { |
| 204 | File staticRoot = new File(sourceRoot, |
| 205 | "gitiles-servlet/src/main/resources/com/google/gitiles/static"); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 206 | ResourceHandler rh = new ResourceHandler(); |
| 207 | try { |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 208 | rh.setBaseResource(new FileResource(staticRoot.toURI().toURL())); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 209 | } catch (URISyntaxException e) { |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 210 | throw new IOException(e); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 211 | } |
| 212 | rh.setWelcomeFiles(new String[]{}); |
| 213 | rh.setDirectoriesListed(false); |
| 214 | ContextHandler handler = new ContextHandler("/+static"); |
| 215 | handler.setHandler(rh); |
| 216 | return handler; |
| 217 | } |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 218 | } |