Repository: aurora Updated Branches: refs/heads/master 44e472642 -> 9dff05714
Convert all of our servlet implementations to jax-rs endpoints. Reviewed at https://reviews.apache.org/r/38332/ Project: http://git-wip-us.apache.org/repos/asf/aurora/repo Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/9dff0571 Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/9dff0571 Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/9dff0571 Branch: refs/heads/master Commit: 9dff05714b3e317f9473105a6ebbcd4d1dee100d Parents: 44e4726 Author: Bill Farner <[email protected]> Authored: Tue Sep 15 19:55:46 2015 -0700 Committer: Bill Farner <[email protected]> Committed: Tue Sep 15 19:55:46 2015 -0700 ---------------------------------------------------------------------- .../aurora/build/CoverageReportCheck.groovy | 8 +- .../common/net/http/handlers/AbortHandler.java | 27 +- .../common/net/http/handlers/AssetHandler.java | 191 ---------- .../net/http/handlers/ContentionPrinter.java | 26 +- .../common/net/http/handlers/HealthHandler.java | 35 +- .../common/net/http/handlers/LogConfig.java | 83 ++-- .../common/net/http/handlers/QuitHandler.java | 29 +- .../http/handlers/StringTemplateServlet.java | 96 ----- .../net/http/handlers/TextResponseHandler.java | 58 --- .../net/http/handlers/ThreadStackPrinter.java | 21 +- .../net/http/handlers/TimeSeriesDataSource.java | 35 +- .../common/net/http/handlers/VarsHandler.java | 16 +- .../net/http/handlers/VarsJsonHandler.java | 33 +- .../net/http/handlers/AssetHandlerTest.java | 378 ------------------- .../net/http/handlers/VarsHandlerTest.java | 7 +- config/legacy_untested_classes.txt | 2 +- .../scheduler/http/JettyServerModule.java | 97 +++-- 17 files changed, 216 insertions(+), 926 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/buildSrc/src/main/groovy/org/apache/aurora/build/CoverageReportCheck.groovy ---------------------------------------------------------------------- diff --git a/buildSrc/src/main/groovy/org/apache/aurora/build/CoverageReportCheck.groovy b/buildSrc/src/main/groovy/org/apache/aurora/build/CoverageReportCheck.groovy index b996d45..b471756 100644 --- a/buildSrc/src/main/groovy/org/apache/aurora/build/CoverageReportCheck.groovy +++ b/buildSrc/src/main/groovy/org/apache/aurora/build/CoverageReportCheck.groovy @@ -85,13 +85,15 @@ class CoverageReportCheck extends DefaultTask { def isAnonymous = { c -> c.@name ==~ /.*\$\d+/ } def methodFilter = isAnonymous(cls) ? { m -> m.@name != '<init>' } : { true } - def matchedMethods = cls.method.findAll(methodFilter) - if (isAnonymous(cls) && matchedMethods.isEmpty()) { + // Always ignore static code, it should not count as test coverage. + def matchedMethods = cls.method.findAll({ m -> m.@name != '<clinit>' }).findAll(methodFilter) + if (matchedMethods.isEmpty()) { // Ignore anonymous classes that only have a constructor. This will avoid tripping for // things like TypeLiteral and Clazz. if (cls.@name in legacyClassesWithoutCoverage) { return 'Please remove ' + cls.@name + ' from the legacyClassesWithoutCoverage list' \ - + ', this check does not apply for constructor-only anonymous classes.' + + ', this check does not apply for constructor-only anonymous classes' \ + + ' or classes with only static class initialization code.' } else { return null } http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/AbortHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/AbortHandler.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/AbortHandler.java index e97bd82..42e668d 100644 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/AbortHandler.java +++ b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/AbortHandler.java @@ -14,13 +14,14 @@ package org.apache.aurora.common.net.http.handlers; import java.io.IOException; -import java.io.PrintWriter; -import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; import com.google.common.base.Preconditions; import com.google.inject.Inject; @@ -29,7 +30,8 @@ import com.google.inject.name.Named; /** * A servlet that provides a way to remotely terminate the running process immediately. */ -public class AbortHandler extends HttpServlet { +@Path("/abortabortabort") +public class AbortHandler { /** * A {@literal @Named} binding key for the QuitHandler listener. @@ -53,19 +55,12 @@ public class AbortHandler extends HttpServlet { this.abortListener = Preconditions.checkNotNull(abortListener); } - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + @POST + @Produces(MediaType.TEXT_PLAIN) + public void abort(@Context HttpServletRequest req) throws IOException { LOG.info(String.format("Received abort HTTP signal from %s (%s)", req.getRemoteAddr(), req.getRemoteHost())); - resp.setContentType("text/plain"); - PrintWriter writer = resp.getWriter(); - try { - writer.println("Aborting process NOW!"); - writer.close(); - abortListener.run(); - } catch (Exception e) { - LOG.log(Level.WARNING, "Abort failed.", e); - } + abortListener.run(); } } http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/AssetHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/AssetHandler.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/AssetHandler.java deleted file mode 100644 index 7a44f07..0000000 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/AssetHandler.java +++ /dev/null @@ -1,191 +0,0 @@ -/** - * 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 org.apache.aurora.common.net.http.handlers; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Splitter; -import com.google.common.collect.Iterables; -import com.google.common.io.ByteSource; -import com.google.common.io.ByteStreams; -import com.google.common.io.Closeables; - -import org.apache.aurora.common.quantity.Amount; -import org.apache.aurora.common.quantity.Time; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.digest.DigestUtils; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Servlet that is responsible for serving an asset. - * - * @author William Farner - */ -public class AssetHandler extends HttpServlet { - - @VisibleForTesting - static final Amount<Integer, Time> CACHE_CONTROL_MAX_AGE_SECS = Amount.of(30, Time.DAYS); - private static final String GZIP_ENCODING = "gzip"; - - private final StaticAsset staticAsset; - - public static class StaticAsset { - private final ByteSource byteSource; - private final String contentType; - private final boolean cacheLocally; - - private byte[] gzipData = null; - private String hash = null; - - /** - * Creates a new static asset. - * - * @param byteSource Source of the asset. - * @param contentType HTTP content type of the asset. - * @param cacheLocally If {@code true} the asset will be loaded once and stored in memory, if - * {@code false} it will be loaded on each request. - */ - public StaticAsset(ByteSource byteSource, - String contentType, boolean cacheLocally) { - this.byteSource = checkNotNull(byteSource); - this.contentType = checkNotNull(contentType); - this.cacheLocally = cacheLocally; - } - - public String getContentType() { - return contentType; - } - - public synchronized byte[] getRawData() throws IOException { - byte[] zipData = getGzipData(); - GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(zipData)); - return ByteStreams.toByteArray(in); - } - - public synchronized byte[] getGzipData() throws IOException { - byte[] data = gzipData; - // Ensure we don't double-read after a call to getChecksum(). - if (!cacheLocally || gzipData == null) { - load(); - data = gzipData; - } - if (!cacheLocally) { - gzipData = null; - } - - return data; - } - - public synchronized String getChecksum() throws IOException { - if (hash == null) { - load(); - } - return hash; - } - - private void load() throws IOException { - ByteArrayOutputStream gzipBaos = new ByteArrayOutputStream(); - GZIPOutputStream gzipStream = new GZIPOutputStream(gzipBaos); - try (InputStream inputStream = byteSource.openStream()) { - ByteStreams.copy(inputStream, gzipStream); - } - gzipStream.flush(); // copy() does not flush or close output stream. - gzipStream.close(); - gzipData = gzipBaos.toByteArray(); - - // Calculate a checksum of the gzipped data. - hash = Base64.encodeBase64String(DigestUtils.md5(gzipData)).trim(); - } - } - - /** - * Creates a new asset handler. - * - * @param staticAsset The asset to serve. - */ - public AssetHandler(StaticAsset staticAsset) { - this.staticAsset = checkNotNull(staticAsset); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - OutputStream responseBody = resp.getOutputStream(); - - if (checksumMatches(req)) { - resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - } else { - setPayloadHeaders(resp); - - boolean gzip = supportsGzip(req); - if (gzip) { - resp.setHeader("Content-Encoding", GZIP_ENCODING); - } - - InputStream in = new ByteArrayInputStream( - gzip ? staticAsset.getGzipData() : staticAsset.getRawData()); - ByteStreams.copy(in, responseBody); - } - - Closeables.close(responseBody, /* swallowIOException */ true); - } - - private void setPayloadHeaders(HttpServletResponse resp) throws IOException { - resp.setStatus(HttpServletResponse.SC_OK); - resp.setContentType(staticAsset.getContentType()); - resp.setHeader("Cache-Control", "public,max-age=" + CACHE_CONTROL_MAX_AGE_SECS); - - String checksum = staticAsset.getChecksum(); - if (checksum != null) { - resp.setHeader("ETag", checksum); - } - } - - private boolean checksumMatches(HttpServletRequest req) throws IOException { - // TODO(William Farner): Change this to more fully comply with - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26 - // Specifically - a response to 'If-None-Match: *' should include ETag as well as other - // cache-related headers. - String suppliedETag = req.getHeader("If-None-Match"); - if ("*".equals(suppliedETag)) { - return true; - } - - String checksum = staticAsset.getChecksum(); - // Note - this isn't a completely accurate check since the tag we end up matching against could - // theoretically be the actual tag with some extra characters appended. - return (checksum != null) && (suppliedETag != null) && suppliedETag.contains(checksum); - } - - private static boolean supportsGzip(HttpServletRequest req) { - String header = req.getHeader("Accept-Encoding"); - return (header != null) - && Iterables.contains(Splitter.on(",").trimResults().split(header), GZIP_ENCODING); - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ContentionPrinter.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ContentionPrinter.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ContentionPrinter.java index 1f8c453..8f14626 100644 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ContentionPrinter.java +++ b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ContentionPrinter.java @@ -13,12 +13,6 @@ */ package org.apache.aurora.common.net.http.handlers; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.primitives.Longs; - -import javax.servlet.http.HttpServletRequest; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; @@ -26,18 +20,30 @@ import java.util.List; import java.util.Map; import java.util.Set; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.primitives.Longs; + /** * HTTP request handler that prints information about blocked threads. * * @author William Farner */ -public class ContentionPrinter extends TextResponseHandler { +@Path("/contention") +public class ContentionPrinter { public ContentionPrinter() { ManagementFactory.getThreadMXBean().setThreadContentionMonitoringEnabled(true); } - @Override - public Iterable<String> getLines(HttpServletRequest request) { + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getContention() { List<String> lines = Lists.newLinkedList(); ThreadMXBean bean = ManagementFactory.getThreadMXBean(); @@ -67,7 +73,7 @@ public class ContentionPrinter extends TextResponseHandler { } } - return lines; + return String.join("\n", lines); } private static List<String> getThreadInfo(ThreadInfo t, StackTraceElement[] stack) { http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/HealthHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/HealthHandler.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/HealthHandler.java index cc5ad4d..731151c 100644 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/HealthHandler.java +++ b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/HealthHandler.java @@ -13,27 +13,24 @@ */ package org.apache.aurora.common.net.http.handlers; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.inject.Inject; import com.google.inject.name.Named; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.logging.Level; -import java.util.logging.Logger; - /** * A servlet that provides a crude mechanism for monitoring a service's health. If the servlet * returns {@link #IS_HEALTHY} then the containing service should be deemed healthy. * * @author John Sirois */ -public class HealthHandler extends HttpServlet { +@Path("/health") +public class HealthHandler { /** * A {@literal @Named} binding key for the Healthz servlet health checker. @@ -49,8 +46,6 @@ public class HealthHandler extends HttpServlet { private static final String IS_NOT_HEALTHY = "SICK"; - private static final Logger LOG = Logger.getLogger(HealthHandler.class.getName()); - private final Supplier<Boolean> healthChecker; /** @@ -66,17 +61,9 @@ public class HealthHandler extends HttpServlet { this.healthChecker = Preconditions.checkNotNull(healthChecker); } - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - resp.setContentType("text/plain"); - PrintWriter writer = resp.getWriter(); - try { - writer.println(Boolean.TRUE.equals(healthChecker.get()) ? IS_HEALTHY : IS_NOT_HEALTHY); - } catch (Exception e) { - writer.println(IS_NOT_HEALTHY); - LOG.log(Level.WARNING, "Health check failed.", e); - } + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getHealth() { + return healthChecker.get() ? IS_HEALTHY : IS_NOT_HEALTHY; } } http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/LogConfig.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/LogConfig.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/LogConfig.java index 5520fb6..aaaa348 100644 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/LogConfig.java +++ b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/LogConfig.java @@ -13,33 +13,38 @@ */ package org.apache.aurora.common.net.http.handlers; -import java.io.IOException; +import java.io.StringWriter; import java.util.List; +import java.util.Optional; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; import java.util.logging.LoggingMXBean; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; -import com.google.inject.Inject; import org.antlr.stringtemplate.StringTemplate; -import org.apache.commons.lang.StringUtils; - import org.apache.aurora.common.base.Closure; +import org.apache.aurora.common.util.templating.StringTemplateHelper; +import org.apache.aurora.common.util.templating.StringTemplateHelper.TemplateException; +import org.apache.commons.lang.StringUtils; /** * Servlet that allows for dynamic adjustment of the logging configuration. * * @author William Farner */ -public class LogConfig extends StringTemplateServlet { +@Path("/logconfig") +public class LogConfig { private static final List<String> LOG_LEVELS = Lists.newArrayList( Level.SEVERE.getName(), Level.WARNING.getName(), @@ -51,43 +56,45 @@ public class LogConfig extends StringTemplateServlet { "INHERIT" // Display value for a null level, the logger inherits from its ancestor. ); - @Inject - public LogConfig(@CacheTemplates boolean cacheTemplates) { - super("logconfig", cacheTemplates); - } + private final StringTemplateHelper template = + new StringTemplateHelper(getClass(), "logconfig", false); + + @POST + @Produces(MediaType.TEXT_HTML) + public String post( + @FormParam("logger") String loggerName, + @FormParam("level") String loggerLevel) throws TemplateException { + + Optional<String> configChange = Optional.empty(); + if (loggerName != null && loggerLevel != null) { + Logger logger = Logger.getLogger(loggerName); + Level newLevel = loggerLevel.equals("INHERIT") ? null : Level.parse(loggerLevel); + logger.setLevel(newLevel); + if (newLevel != null) { + maybeAdjustHandlerLevels(logger, newLevel); + } - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - displayPage(req, resp, true); + configChange = Optional.of(String.format("%s level changed to %s", loggerName, loggerLevel)); + } + + return displayPage(configChange); } - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - displayPage(req, resp, false); + @GET + @Produces(MediaType.TEXT_HTML) + public String get() throws TemplateException { + return displayPage(Optional.empty()); } - protected void displayPage(final HttpServletRequest req, HttpServletResponse resp, - final boolean posted) throws ServletException, IOException { - writeTemplate(resp, new Closure<StringTemplate>() { + protected String displayPage(Optional<String> configChange) throws TemplateException { + StringWriter writer = new StringWriter(); + + template.writeTemplate(writer, new Closure<StringTemplate>() { @Override public void execute(StringTemplate stringTemplate) { LoggingMXBean logBean = LogManager.getLoggingMXBean(); - if (posted) { - String loggerName = req.getParameter("logger"); - String loggerLevel = req.getParameter("level"); - if (loggerName != null && loggerLevel != null) { - Logger logger = Logger.getLogger(loggerName); - Level newLevel = loggerLevel.equals("INHERIT") ? null : Level.parse(loggerLevel); - logger.setLevel(newLevel); - if (newLevel != null) { - maybeAdjustHandlerLevels(logger, newLevel); - } - - stringTemplate.setAttribute("configChange", - String.format("%s level changed to %s", loggerName, loggerLevel)); - } + if (configChange.isPresent()) { + stringTemplate.setAttribute("configChange", configChange.get()); } List<LoggerConfig> loggerConfigs = Lists.newArrayList(); @@ -99,6 +106,8 @@ public class LogConfig extends StringTemplateServlet { stringTemplate.setAttribute("levels", LOG_LEVELS); } }); + + return writer.toString(); } private void maybeAdjustHandlerLevels(Logger logger, Level newLevel) { http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/QuitHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/QuitHandler.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/QuitHandler.java index 4ce3c97..40872e2 100644 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/QuitHandler.java +++ b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/QuitHandler.java @@ -13,14 +13,14 @@ */ package org.apache.aurora.common.net.http.handlers; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; import com.google.common.base.Preconditions; import com.google.inject.Inject; @@ -30,7 +30,8 @@ import com.google.inject.name.Named; * A servlet that provides a way to remotely signal the process to initiate a clean shutdown * sequence. */ -public class QuitHandler extends HttpServlet { +@Path("/quitquitquit") +public class QuitHandler { private static final Logger LOG = Logger.getLogger(QuitHandler.class.getName()); /** @@ -53,19 +54,13 @@ public class QuitHandler extends HttpServlet { this.quitListener = Preconditions.checkNotNull(quitListener); } - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + @POST + @Produces(MediaType.TEXT_PLAIN) + public String quit(@Context HttpServletRequest req) { LOG.info(String.format("Received quit HTTP signal from %s (%s)", req.getRemoteAddr(), req.getRemoteHost())); - resp.setContentType("text/plain"); - PrintWriter writer = resp.getWriter(); - try { - writer.println("Notifying quit listener."); - writer.close(); - new Thread(quitListener).start(); - } catch (Exception e) { - LOG.log(Level.WARNING, "Quit failed.", e); - } + new Thread(quitListener).start(); + return "Notifying quit listener."; } } http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/StringTemplateServlet.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/StringTemplateServlet.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/StringTemplateServlet.java deleted file mode 100644 index 60e0abb..0000000 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/StringTemplateServlet.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * 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 org.apache.aurora.common.net.http.handlers; - -import com.google.common.base.Preconditions; -import com.google.inject.BindingAnnotation; - -import org.apache.aurora.common.base.Closure; -import org.apache.aurora.common.base.MorePreconditions; -import org.apache.aurora.common.util.templating.StringTemplateHelper; -import org.apache.aurora.common.util.templating.StringTemplateHelper.TemplateException; - -import org.antlr.stringtemplate.StringTemplate; - -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * A base class for servlets that render using the string template templating system. Subclasses - * can call one of the {@link #writeTemplate} methods to render their content with the associated - * template. - */ -public abstract class StringTemplateServlet extends HttpServlet { - private static final String CONTENT_TYPE_TEXT_HTML = "text/html"; - - /** - * A {@literal @BindingAnnotation} that allows configuration of whether or not - * StringTemplateServlets should cache their templates. - */ - @BindingAnnotation - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.PARAMETER, ElementType.METHOD}) - public @interface CacheTemplates {} - - private static final Logger LOG = Logger.getLogger(StringTemplateServlet.class.getName()); - - private final StringTemplateHelper templateHelper; - - /** - * Creates a new StringTemplateServlet that expects to find its template located in the same - * package on the classpath at '{@code templateName}.st'. - * - * @param templateName The name of the string template to use. - * @param cacheTemplates {@code true} to re-use loaded templates, {@code false} to reload the - * template for each request. - */ - protected StringTemplateServlet(String templateName, boolean cacheTemplates) { - templateHelper = new StringTemplateHelper(getClass(), templateName, cacheTemplates); - } - - protected final void writeTemplate( - HttpServletResponse response, - Closure<StringTemplate> parameterSetter) throws IOException { - - writeTemplate(response, CONTENT_TYPE_TEXT_HTML, HttpServletResponse.SC_OK, parameterSetter); - } - - protected final void writeTemplate( - HttpServletResponse response, - String contentType, - int status, - Closure<StringTemplate> parameterSetter) throws IOException { - - Preconditions.checkNotNull(response); - MorePreconditions.checkNotBlank(contentType); - Preconditions.checkArgument(status > 0); - Preconditions.checkNotNull(parameterSetter); - - try { - templateHelper.writeTemplate(response.getWriter(), parameterSetter); - response.setStatus(status); - response.setContentType(contentType); - } catch (TemplateException e) { - LOG.log(Level.SEVERE, "Unknown exception.", e); - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/TextResponseHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/TextResponseHandler.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/TextResponseHandler.java deleted file mode 100644 index 23068eb..0000000 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/TextResponseHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * 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 org.apache.aurora.common.net.http.handlers; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; - -/** - * A handler that responds to all requests in HTML format. - * - * @author William Farner - */ -public abstract class TextResponseHandler extends HttpServlet { - private final String textContentType; - - public TextResponseHandler() { - this("text/plain"); - } - - public TextResponseHandler(String textContentType) { - this.textContentType = textContentType; - } - - /** - * Returns the lines to be printed as the body of the response. - * - * @return An iterable collection of lines to respond to the request with. - */ - public abstract Iterable<String> getLines(HttpServletRequest request); - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - resp.setContentType(textContentType); - resp.setStatus(HttpServletResponse.SC_OK); - PrintWriter responseBody = resp.getWriter(); - for (String line : getLines(req)) { - responseBody.println(line); - } - responseBody.close(); - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ThreadStackPrinter.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ThreadStackPrinter.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ThreadStackPrinter.java index 5dd8804..ab3af86 100644 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ThreadStackPrinter.java +++ b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/ThreadStackPrinter.java @@ -13,20 +13,27 @@ */ package org.apache.aurora.common.net.http.handlers; -import com.google.common.collect.Lists; - -import javax.servlet.http.HttpServletRequest; import java.util.List; import java.util.Map; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; + /** * HTTP handler to print the stacks of all live threads. * * @author William Farner */ -public class ThreadStackPrinter extends TextResponseHandler { - @Override - public Iterable<String> getLines(HttpServletRequest request) { +@Path("/threads") +public class ThreadStackPrinter { + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getThreadStacks() { List<String> lines = Lists.newLinkedList(); for (Map.Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) { Thread t = entry.getKey(); @@ -36,6 +43,6 @@ public class ThreadStackPrinter extends TextResponseHandler { lines.add(" " + s.toString()); } } - return lines; + return Joiner.on("\n").join(lines); } } http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/TimeSeriesDataSource.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/TimeSeriesDataSource.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/TimeSeriesDataSource.java index e87fe2c..8039def 100644 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/TimeSeriesDataSource.java +++ b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/TimeSeriesDataSource.java @@ -13,15 +13,14 @@ */ package org.apache.aurora.common.net.http.handlers; -import java.io.IOException; -import java.io.PrintWriter; import java.util.List; import javax.annotation.Nullable; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; @@ -33,7 +32,6 @@ import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import com.google.common.net.MediaType; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.inject.Inject; @@ -45,7 +43,8 @@ import org.apache.aurora.common.stats.TimeSeriesRepository; /** * A servlet that provides time series data in JSON format. */ -public class TimeSeriesDataSource extends HttpServlet { +@Path("/graphdata/") +public class TimeSeriesDataSource { @VisibleForTesting static final String TIME_METRIC = "time"; @@ -96,21 +95,17 @@ public class TimeSeriesDataSource extends HttpServlet { ResponseStruct response = new ResponseStruct( ImmutableList.<String>builder().add(TIME_METRIC).addAll(names).build(), FluentIterable.from(Iterables2.zip(tsData, 0)).filter(sinceFilter).toList()); + // TODO(wfarner): Let the jax-rs provider handle serialization. return gson.toJson(response); } - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - resp.setContentType(MediaType.JSON_UTF_8.toString()); - PrintWriter out = resp.getWriter(); - try { - out.write(getResponse(req.getParameter(METRICS), req.getParameter(SINCE))); - } catch (MetricException e) { - resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); - out.write(e.getMessage()); - } + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getData( + @QueryParam(METRICS) String metrics, + @QueryParam(SINCE) String since) throws MetricException { + + return getResponse(metrics, since); } @VisibleForTesting http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsHandler.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsHandler.java index bf04525..d1f23de 100644 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsHandler.java +++ b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsHandler.java @@ -16,9 +16,13 @@ package org.apache.aurora.common.net.http.handlers; import java.util.Collections; import java.util.List; -import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; import com.google.common.base.Function; +import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.Iterables; @@ -32,7 +36,8 @@ import org.apache.aurora.common.stats.Stat; * * @author William Farner */ -public class VarsHandler extends TextResponseHandler { +@Path("/vars") +public class VarsHandler { private static final Function<Stat, String> VAR_PRINTER = new Function<Stat, String>() { @Override public String apply(Stat stat) { @@ -52,10 +57,11 @@ public class VarsHandler extends TextResponseHandler { this.statSupplier = Preconditions.checkNotNull(statSupplier); } - @Override - public Iterable<String> getLines(HttpServletRequest request) { + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getVars() { List<String> lines = Lists.newArrayList(Iterables.transform(statSupplier.get(), VAR_PRINTER)); Collections.sort(lines); - return lines; + return Joiner.on("\n").join(lines); } } http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsJsonHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsJsonHandler.java b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsJsonHandler.java index e97ec60..850c784 100644 --- a/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsJsonHandler.java +++ b/commons/src/main/java/org/apache/aurora/common/net/http/handlers/VarsJsonHandler.java @@ -13,14 +13,13 @@ */ package org.apache.aurora.common.net.http.handlers; -import java.io.IOException; -import java.io.PrintWriter; import java.util.Map; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; @@ -45,9 +44,10 @@ import org.apache.aurora.common.stats.Stat; * If the optional URL parameter 'pretty' is used, the output will be pretty-printed * (similar to the above example). * - * @author William Farner + * TODO(wfarner): Handle this request in VarsHandler. */ -public class VarsJsonHandler extends HttpServlet { +@Path("/vars.json") +public class VarsJsonHandler { private final Supplier<Iterable<Stat<?>>> statSupplier; @@ -67,21 +67,14 @@ public class VarsJsonHandler extends HttpServlet { for (Stat<?> var : statSupplier.get()) { vars.put(var.getName(), var.read()); } + // TODO(wfarner): Let the jax-rs provider handle serialization. return getGson(pretty).toJson(vars); } - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - resp.setContentType("application/json"); - resp.setStatus(HttpServletResponse.SC_OK); - PrintWriter responseBody = resp.getWriter(); - try { - responseBody.print(getBody(req.getParameter("pretty") != null)); - } finally { - responseBody.close(); - } + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getVars(@QueryParam("pretty") boolean pretty) { + return getBody(pretty); } private Gson getGson(boolean pretty) { http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/test/java/org/apache/aurora/common/net/http/handlers/AssetHandlerTest.java ---------------------------------------------------------------------- diff --git a/commons/src/test/java/org/apache/aurora/common/net/http/handlers/AssetHandlerTest.java b/commons/src/test/java/org/apache/aurora/common/net/http/handlers/AssetHandlerTest.java deleted file mode 100644 index 740c42f..0000000 --- a/commons/src/test/java/org/apache/aurora/common/net/http/handlers/AssetHandlerTest.java +++ /dev/null @@ -1,378 +0,0 @@ -/** - * 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 org.apache.aurora.common.net.http.handlers; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.zip.GZIPInputStream; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.google.common.io.ByteSource; -import com.google.common.io.ByteStreams; - -import org.junit.Before; -import org.junit.Test; - -import org.apache.aurora.common.testing.easymock.EasyMockTest; - -import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED; -import static javax.servlet.http.HttpServletResponse.SC_OK; -import static org.easymock.EasyMock.createMockBuilder; -import static org.easymock.EasyMock.expect; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -/** - * @author William Farner - */ -public class AssetHandlerTest extends EasyMockTest { - - private static final String TEST_DATA = "here is my great test data"; - // Checksum of the gzipped TEST_DATA. - private static final String TEST_DATA_CHECKSUM = "ePvVhtAeVRu85KSOLKL0oQ=="; - private static final String CONTENT_TYPE = "text/plain"; - - private ByteSource byteSource; - - @Before - public void setUp() { - byteSource = createMock(ByteSource.class); - } - - private static class Request { - private final HttpServletRequest req; - private final HttpServletResponse resp; - private final ByteArrayOutputStream responseBody; - - Request(HttpServletRequest req, HttpServletResponse resp, ByteArrayOutputStream responseBody) { - this.req = req; - this.resp = resp; - this.responseBody = responseBody; - } - } - - private Request doGet(String suppliedChecksum, String supportedEncodings, - int expectedResponseCode, boolean expectRead) throws Exception { - HttpServletRequest req = createMock(HttpServletRequest.class); - HttpServletResponse resp = createMock(HttpServletResponse.class); - - if (expectRead) { - expect(byteSource.openStream()).andReturn(new ByteArrayInputStream(TEST_DATA.getBytes())); - } - - expect(req.getHeader("If-None-Match")).andReturn(suppliedChecksum); - - resp.setStatus(expectedResponseCode); - if (expectedResponseCode == SC_OK) { - expect(req.getHeader("Accept-Encoding")).andReturn(supportedEncodings); - resp.setHeader("Cache-Control", "public,max-age=" + AssetHandler.CACHE_CONTROL_MAX_AGE_SECS); - resp.setHeader("ETag", TEST_DATA_CHECKSUM); - resp.setContentType(CONTENT_TYPE); - - if (supportedEncodings != null && supportedEncodings.contains("gzip")) { - resp.setHeader("Content-Encoding", "gzip"); - } - } - return new Request(req, resp, expectPayload(resp)); - } - - @Test - public void testCached() throws Exception { - - // First request - no cached value - Request test1 = doGet( - null, // No local checksum. - null, // No encodings supported. - SC_OK, - true // Triggers a data read. - ); - - // Second request - client performs conditional GET with wrong checksum. - Request test2 = doGet( - "foo", // Wrong checksum. - null, // No encodings supported. - SC_OK, - false // No read. - ); - - // Third request - client performs conditional GET with correct checksum. - Request test3 = doGet( - TEST_DATA_CHECKSUM, // Correct checksum. - null, // No encodings supported. - SC_NOT_MODIFIED, - false // No read. - ); - - control.replay(); - - AssetHandler handler = new AssetHandler(new AssetHandler.StaticAsset(byteSource, CONTENT_TYPE, true)); - - handler.doGet(test1.req, test1.resp); - assertThat(new String(test1.responseBody.toByteArray()), is(TEST_DATA)); - - handler.doGet(test2.req, test2.resp); - assertThat(new String(test2.responseBody.toByteArray()), is(TEST_DATA)); - - handler.doGet(test3.req, test3.resp); - assertThat(new String(test3.responseBody.toByteArray()), is("")); - } - - @Test - public void testCachedGzipped() throws Exception { - - // First request - no cached value - Request test1 = doGet( - null, // No local checksum. - "gzip", // Supported encodings. - SC_OK, - true // Triggers a data read. - ); - - // Second request - client performs conditional GET with wrong checksum. - Request test2 = doGet( - "foo", // Wrong checksum. - "gzip,fakeencoding", // Supported encodings. - SC_OK, - false // No read. - ); - - // Third request - client performs conditional GET with correct checksum. - Request test3 = doGet( - TEST_DATA_CHECKSUM, // Correct checksum. - "gzip,deflate", // Supported encodings. - SC_NOT_MODIFIED, - false // No read. - ); - - control.replay(); - - AssetHandler handler = new AssetHandler(new AssetHandler.StaticAsset(byteSource, CONTENT_TYPE, true)); - - handler.doGet(test1.req, test1.resp); - assertThat(unzip(test1.responseBody), is(TEST_DATA)); - - handler.doGet(test2.req, test2.resp); - assertThat(unzip(test2.responseBody), is(TEST_DATA)); - - handler.doGet(test3.req, test3.resp); - assertThat(new String(test3.responseBody.toByteArray()), is("")); - } - - @Test - public void testUncached() throws Exception { - - // First request - no cached value - Request test1 = doGet( - null, // No local checksum. - null, // No encodings supported. - SC_OK, - true // Triggers a data read. - ); - - // Second request - client performs conditional GET with wrong checksum. - Request test2 = doGet( - "foo", // Wrong checksum. - null, // No encodings supported. - SC_OK, - true // Triggers a data read. - ); - - // Third request - client performs conditional GET with correct checksum. - Request test3 = doGet( - TEST_DATA_CHECKSUM, // Correct checksum. - null, // No encodings supported. - SC_NOT_MODIFIED, - true // Triggers a data read. - ); - - control.replay(); - - AssetHandler handler = new AssetHandler(new AssetHandler.StaticAsset(byteSource, CONTENT_TYPE, false)); - - handler.doGet(test1.req, test1.resp); - assertThat(new String(test1.responseBody.toByteArray()), is(TEST_DATA)); - - handler.doGet(test2.req, test2.resp); - assertThat(new String(test2.responseBody.toByteArray()), is(TEST_DATA)); - - handler.doGet(test3.req, test3.resp); - assertThat(new String(test3.responseBody.toByteArray()), is("")); - } - - @Test - public void testUncachedGzipped() throws Exception { - - // First request - no cached value - Request test1 = doGet( - null, // No local checksum. - "gzip", // Supported encodings. - SC_OK, - true // Triggers a data read. - ); - - // Second request - client performs conditional GET with wrong checksum. - Request test2 = doGet( - "foo", // Wrong checksum. - "gzip,fakeencoding", // Supported encodings. - SC_OK, - true // Triggers a data read. - ); - - // Third request - client performs conditional GET with correct checksum. - Request test3 = doGet( - TEST_DATA_CHECKSUM, // Correct checksum. - "gzip,deflate", // Supported encodings. - SC_NOT_MODIFIED, - true // Triggers a data read. - ); - - control.replay(); - - AssetHandler handler = new AssetHandler(new AssetHandler.StaticAsset(byteSource, CONTENT_TYPE, false)); - - handler.doGet(test1.req, test1.resp); - assertThat(unzip(test1.responseBody), is(TEST_DATA)); - - handler.doGet(test2.req, test2.resp); - assertThat(unzip(test2.responseBody), is(TEST_DATA)); - - handler.doGet(test3.req, test3.resp); - assertThat(new String(test3.responseBody.toByteArray()), is("")); - } - - private static ByteArrayOutputStream expectPayload(HttpServletResponse resp) throws Exception { - ByteArrayOutputStream responseBody = new ByteArrayOutputStream(); - expect(resp.getOutputStream()).andReturn(new FakeServletOutputStream(responseBody)); - return responseBody; - } - - private static String unzip(ByteArrayOutputStream streamData) throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream(streamData.toByteArray()); - GZIPInputStream unzip = new GZIPInputStream(in); - return new String(ByteStreams.toByteArray(unzip)); - } - - private static class FakeServletOutputStream extends ServletOutputStream { - private final OutputStream realStream; - - FakeServletOutputStream(OutputStream realStream) { - this.realStream = realStream; - } - - @Override - public void write(int b) throws IOException { - realStream.write(b); - } - - @Override - public void write(byte[] b) throws IOException { - realStream.write(b); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - realStream.write(b, off, len); - } - - @Override - public void flush() throws IOException { - realStream.flush(); - } - - @Override - public void close() throws IOException { - realStream.close(); - } - - @Override - public void print(String s) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void print(boolean b) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void print(char c) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void print(int i) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void print(long l) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void print(float f) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void print(double d) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void println() throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void println(String s) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void println(boolean b) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void println(char c) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void println(int i) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void println(long l) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void println(float f) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void println(double d) throws IOException { - throw new UnsupportedOperationException("Not implemented"); - } - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/commons/src/test/java/org/apache/aurora/common/net/http/handlers/VarsHandlerTest.java ---------------------------------------------------------------------- diff --git a/commons/src/test/java/org/apache/aurora/common/net/http/handlers/VarsHandlerTest.java b/commons/src/test/java/org/apache/aurora/common/net/http/handlers/VarsHandlerTest.java index 34f62fb..6c4feaf 100644 --- a/commons/src/test/java/org/apache/aurora/common/net/http/handlers/VarsHandlerTest.java +++ b/commons/src/test/java/org/apache/aurora/common/net/http/handlers/VarsHandlerTest.java @@ -20,14 +20,12 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import com.google.common.base.Supplier; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import org.apache.aurora.common.stats.Stat; import org.junit.Before; import org.junit.Test; -import org.apache.aurora.common.stats.Stat; - import static org.junit.Assert.assertEquals; /** @@ -72,7 +70,6 @@ public class VarsHandlerTest extends StatSupplierTestBase { } private void checkOutput(List<String> expectedLines) { - assertEquals(expectedLines, - ImmutableList.copyOf(vars.getLines(request))); + assertEquals(String.join("\n", expectedLines), vars.getVars()); } } http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/config/legacy_untested_classes.txt ---------------------------------------------------------------------- diff --git a/config/legacy_untested_classes.txt b/config/legacy_untested_classes.txt index 7b891b2..88a71df 100644 --- a/config/legacy_untested_classes.txt +++ b/config/legacy_untested_classes.txt @@ -9,9 +9,9 @@ org/apache/aurora/scheduler/async/OfferQueue$OfferQueueImpl$2 org/apache/aurora/scheduler/base/Conversions$1 org/apache/aurora/scheduler/base/Conversions$2 org/apache/aurora/scheduler/base/Conversions$3 -org/apache/aurora/scheduler/base/Conversions$4 org/apache/aurora/scheduler/cron/quartz/CronSchedulerImpl org/apache/aurora/scheduler/cron/quartz/CronSchedulerImpl$1 +org/apache/aurora/scheduler/http/AbortCallback org/apache/aurora/scheduler/http/JerseyTemplateServlet org/apache/aurora/scheduler/http/Maintenance org/apache/aurora/scheduler/http/Maintenance$1 http://git-wip-us.apache.org/repos/asf/aurora/blob/9dff0571/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java b/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java index c503dcc..f9b0687 100644 --- a/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java +++ b/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java @@ -17,6 +17,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.EnumSet; import java.util.Map; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -24,15 +25,19 @@ import javax.annotation.Nonnegative; import javax.inject.Inject; import javax.inject.Singleton; import javax.servlet.ServletContextListener; -import javax.servlet.http.HttpServlet; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Joiner; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimap; import com.google.common.net.HostAndPort; import com.google.common.util.concurrent.AbstractIdleService; import com.google.inject.AbstractModule; @@ -56,7 +61,6 @@ import org.apache.aurora.common.net.http.handlers.ContentionPrinter; import org.apache.aurora.common.net.http.handlers.HealthHandler; import org.apache.aurora.common.net.http.handlers.LogConfig; import org.apache.aurora.common.net.http.handlers.QuitHandler; -import org.apache.aurora.common.net.http.handlers.StringTemplateServlet; import org.apache.aurora.common.net.http.handlers.ThreadStackPrinter; import org.apache.aurora.common.net.http.handlers.TimeSeriesDataSource; import org.apache.aurora.common.net.http.handlers.VarsHandler; @@ -143,8 +147,6 @@ public class JettyServerModule extends AbstractModule { .annotatedWith(Names.named(HealthHandler.HEALTH_CHECKER_KEY)) .toInstance(Suppliers.ofInstance(true)); - bindConstant().annotatedWith(StringTemplateServlet.CacheTemplates.class).to(true); - final Optional<String> hostnameOverride = Optional.fromNullable(HOSTNAME_OVERRIDE.get()); if (hostnameOverride.isPresent()) { try { @@ -195,6 +197,48 @@ public class JettyServerModule extends AbstractModule { } }; + private static final Set<String> LEADER_ENDPOINTS = ImmutableSet.of( + "api", + "cron", + "locks", + "maintenance", + "mname", + "offers", + "pendingtasks", + "quotas", + "slaves", + "utilization" + ); + + private static final Multimap<Class<?>, String> JAX_RS_ENDPOINTS = + ImmutableMultimap.<Class<?>, String>builder() + .put(AbortHandler.class, "abortabortabort") + .put(ContentionPrinter.class, "contention") + .put(Cron.class, "cron") + .put(Locks.class, "locks") + .put(LogConfig.class, "logconfig") + .put(Maintenance.class, "maintenance") + .put(Mname.class, "mname") + .put(Offers.class, "offers") + .put(PendingTasks.class, "pendingtasks") + .put(QuitHandler.class, "quitquitquit") + .put(Quotas.class, "quotas") + .put(Services.class, "services") + .put(Slaves.class, "slaves") + .put(StructDump.class, "structdump") + .put(ThreadStackPrinter.class, "threads") + .put(TimeSeriesDataSource.class, "graphdata") + .put(Utilization.class, "utilization") + .put(VarsHandler.class, "vars") + .put(VarsJsonHandler.class, "vars.json") + .build(); + + private static String allOf(Set<String> paths) { + return "^(?:" + + Joiner.on("|").join(Iterables.transform(paths, path -> "/" + path)) + + ").*$"; + } + // TODO(ksweeney): Factor individual servlet configurations to their own ServletModules. @VisibleForTesting static ServletContextListener makeServletContextListener( @@ -207,22 +251,18 @@ public class JettyServerModule extends AbstractModule { return parentInjector.createChildInjector( childModule, new JerseyServletModule() { - private void registerJerseyEndpoint(String indexPath, Class<?> servlet) { - filter(indexPath + "*").through(LeaderRedirectFilter.class); - filter(indexPath + "*").through(GuiceContainer.class, GUICE_CONTAINER_PARAMS); - bind(servlet); - } - - private void registerServlet(String pathSpec, Class<? extends HttpServlet> servlet) { - bind(servlet).in(Singleton.class); - serve(pathSpec).with(servlet); - } - @Override protected void configureServlets() { bind(HttpStatsFilter.class).in(Singleton.class); filter("*").through(HttpStatsFilter.class); + bind(LeaderRedirectFilter.class).in(Singleton.class); + filterRegex(allOf(LEADER_ENDPOINTS)) + .through(LeaderRedirectFilter.class); + + bind(GuiceContainer.class).in(Singleton.class); + filterRegex(allOf(ImmutableSet.copyOf(JAX_RS_ENDPOINTS.values()))) + .through(GuiceContainer.class, GUICE_CONTAINER_PARAMS); filterRegex("/assets/.*").through(new GzipFilter()); filterRegex("/assets/scheduler(?:/.*)?").through(LeaderRedirectFilter.class); @@ -232,28 +272,9 @@ public class JettyServerModule extends AbstractModule { "resourceBase", STATIC_ASSETS_ROOT, "dirAllowed", "false")); - bind(GuiceContainer.class).in(Singleton.class); - registerJerseyEndpoint("/cron", Cron.class); - registerJerseyEndpoint("/locks", Locks.class); - registerJerseyEndpoint("/maintenance", Maintenance.class); - registerJerseyEndpoint("/mname", Mname.class); - registerJerseyEndpoint("/offers", Offers.class); - registerJerseyEndpoint("/pendingtasks", PendingTasks.class); - registerJerseyEndpoint("/quotas", Quotas.class); - registerJerseyEndpoint("/services", Services.class); - registerJerseyEndpoint("/slaves", Slaves.class); - registerJerseyEndpoint("/structdump", StructDump.class); - registerJerseyEndpoint("/utilization", Utilization.class); - - registerServlet("/abortabortabort", AbortHandler.class); - registerServlet("/contention", ContentionPrinter.class); - registerServlet("/health", HealthHandler.class); - registerServlet("/logconfig", LogConfig.class); - registerServlet("/quitquitquit", QuitHandler.class); - registerServlet("/threads", ThreadStackPrinter.class); - registerServlet("/graphdata/", TimeSeriesDataSource.class); - registerServlet("/vars", VarsHandler.class); - registerServlet("/vars.json", VarsJsonHandler.class); + for (Class<?> jaxRsHandler : JAX_RS_ENDPOINTS.keySet()) { + bind(jaxRsHandler); + } } }); } @@ -353,7 +374,7 @@ public class JettyServerModule extends AbstractModule { new ServletContextHandler(server, "/", ServletContextHandler.NO_SESSIONS); servletHandler.addServlet(DefaultServlet.class, "/"); - servletHandler.addFilter(GuiceFilter.class, "/*", EnumSet.allOf(DispatcherType.class)); + servletHandler.addFilter(GuiceFilter.class, "/*", EnumSet.allOf(DispatcherType.class)); servletHandler.addEventListener(servletContextListener); HandlerCollection rootHandler = new HandlerCollection();
