http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/GuiceServletConfig.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/GuiceServletConfig.java b/commons/src/main/java/com/twitter/common/net/http/GuiceServletConfig.java deleted file mode 100644 index ab2f110..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/GuiceServletConfig.java +++ /dev/null @@ -1,41 +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 com.twitter.common.net.http; - -import com.google.common.base.Preconditions; -import com.google.inject.Inject; -import com.google.inject.Injector; -import com.google.inject.servlet.GuiceServletContextListener; - -import javax.servlet.ServletContextEvent; -import java.util.logging.Logger; - -/** - * A wrapper around the GuiceServletContextListener that has access to the injector. - * - * @author Florian Leibert - */ -public class GuiceServletConfig extends GuiceServletContextListener { - private final Injector injector; - - @Inject - public GuiceServletConfig(Injector injector) { - this.injector = Preconditions.checkNotNull(injector); - } - - @Override - protected Injector getInjector() { - return injector; - } -}
http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/HttpServerDispatch.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/HttpServerDispatch.java b/commons/src/main/java/com/twitter/common/net/http/HttpServerDispatch.java deleted file mode 100644 index d5221a4..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/HttpServerDispatch.java +++ /dev/null @@ -1,123 +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 com.twitter.common.net.http; - -import java.util.Map; - -import javax.annotation.Nullable; -import javax.servlet.Filter; -import javax.servlet.ServletContextAttributeListener; -import javax.servlet.ServletContextListener; -import javax.servlet.ServletRequestAttributeListener; -import javax.servlet.ServletRequestListener; -import javax.servlet.http.HttpServlet; - -/** - * A HTTP server dispatcher. Supports registering handlers for different - * URI paths, which will be called when a request is received. - * - * @author Florian Leibert - */ -public interface HttpServerDispatch { - - /** - * Opens the HTTP server on the given port. - * - * @param port The port to listen on. - * @return {@code true} if the server started successfully on the port, {@code false} otherwise. - */ - boolean listen(int port); - - /** - * Opens the HTTP server on random port within the given range. - * - * @param minPort The minimum port number to listen on. - * @param maxPort The maximum port number to listen on. - * @return {@code true} if the server started successfully on the port, {@code false} otherwise. - */ - boolean listen(int minPort, int maxPort); - - /** - * @return true if the underlying HttpServer is started, false otherwise. - */ - boolean isStarted(); - - /** - * @return the port the underlying HttpServer is listening on, which requires - * the underlying HttpServer to be started and listening. - */ - int getPort(); - - /** - * Stops the HTTP server. - */ - void stop(); - - /** - * Adds an arbitrary endpoint to the root servlet. - * This can be used to include convenience links, or references to endpoints served by - * a different servlet container under this HTTP server. - * - * @param path The URI path of the endpoint. - */ - void registerIndexLink(String path); - - /** - * Registers a URI handler, replacing the existing handler if it exists. - * - * @param path The URI path that the handler should be called for. - * @param handler The handler to call. - * @param initParams An optional map of servlet init parameter names and their values. - * @param silent Whether to display the registered handler in the root "/" response. - * Useful for handlers that you want to avoid accidental clicks on. - */ - void registerHandler(String path, HttpServlet handler, - @Nullable Map<String, String> initParams, boolean silent); - - /** - * Registers a servlet filter. - * - * @param filterClass Filter class to register. - * @param pathSpec Path spec that the filter should be activated on. - */ - void registerFilter(Class<? extends Filter> filterClass, String pathSpec); - - /** - * Registers a context listener. - * - * @param servletContextListener Listener to register. - */ - void registerListener(ServletContextListener servletContextListener); - - /** - * Registers a context attribute listener. - * - * @param servletContextAttributeListener Listener to register. - */ - void registerListener(ServletContextAttributeListener servletContextAttributeListener); - - /** - * Registers a request listener. - * - * @param servletRequestListener Listener to register. - */ - void registerListener(ServletRequestListener servletRequestListener); - - /** - * Registers a request attribute listener. - * - * @param servletRequestAttributeListener Listener to register. - */ - void registerListener(ServletRequestAttributeListener servletRequestAttributeListener); -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/JettyHttpServerDispatch.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/JettyHttpServerDispatch.java b/commons/src/main/java/com/twitter/common/net/http/JettyHttpServerDispatch.java deleted file mode 100644 index 378cc0d..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/JettyHttpServerDispatch.java +++ /dev/null @@ -1,283 +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 com.twitter.common.net.http; - -import java.io.IOException; -import java.util.EventListener; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.annotation.Nullable; -import javax.servlet.Filter; -import javax.servlet.ServletContextAttributeListener; -import javax.servlet.ServletContextListener; -import javax.servlet.ServletRequestAttributeListener; -import javax.servlet.ServletRequestListener; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import com.google.common.collect.Ordering; -import com.google.common.collect.Sets; -import com.google.inject.Inject; - -import org.mortbay.jetty.AbstractConnector; -import org.mortbay.jetty.Connector; -import org.mortbay.jetty.Handler; -import org.mortbay.jetty.RequestLog; -import org.mortbay.jetty.Server; -import org.mortbay.jetty.handler.RequestLogHandler; -import org.mortbay.jetty.nio.SelectChannelConnector; -import org.mortbay.jetty.servlet.Context; -import org.mortbay.jetty.servlet.ServletHolder; - -import com.twitter.common.base.MorePreconditions; -import com.twitter.common.net.http.handlers.TextResponseHandler; - -/** - * A simple multi-threaded HTTP server dispatcher. Supports registering handlers for different - * URI paths, which will be called when a request is received. - * - * @author William Farner - */ -public class JettyHttpServerDispatch implements HttpServerDispatch { - private static final Logger LOG = Logger.getLogger(JettyHttpServerDispatch.class.getName()); - - // Registered endpoints. Used only for display. - private final Set<String> registeredEndpoints = Sets.newHashSet(); - - private final Optional<RequestLog> requestLog; - private Server server; - private Context context; - private int port; - - /** - * Creates an HTTP server. - */ - public JettyHttpServerDispatch() { - this.requestLog = Optional.absent(); - } - - /** - * Creates an HTTP server which will be configured to log requests to the provided request log. - * - * @param requestLog HTTP request log. - */ - @Inject - public JettyHttpServerDispatch(RequestLog requestLog) { - this.requestLog = Optional.of(requestLog); - } - - /** - * Opens the HTTP server on the given port. - * - * @param port The port to listen on. - * @return {@code true} if the server started successfully on the port, {@code false} otherwise. - */ - public boolean listen(int port) { - return listen(port, port); - } - - @Override - public synchronized boolean listen(int minPort, int maxPort) { - boolean state = !isStarted(); - Preconditions.checkState(state, - "HttpServerDispatch has already been started on port: %d", port); - - Connector connector = openConnector(minPort, maxPort); - if (connector == null) return false; // Couldn't open a server port. - port = connector.getLocalPort(); - - server = new Server(); - server.addConnector(connector); - context = new Context(server, "/", Context.NO_SESSIONS); - if (requestLog.isPresent()) { - RequestLogHandler logHandler = new RequestLogHandler(); - logHandler.setRequestLog(requestLog.get()); - context.addHandler(logHandler); - } - - context.addServlet(new ServletHolder(new RootHandler()), "/"); - - try { - server.start(); - LOG.info("HTTP server is listening on port " + port); - return true; - } catch (Exception e) { - LOG.log(Level.SEVERE, "HTTP server failed to start on port " + connector.getLocalPort(), e); - return false; - } - } - - @Override - public synchronized boolean isStarted() { - return (server != null) && server.isStarted(); - } - - @Override - public synchronized int getPort() { - Preconditions.checkState(isStarted(), "HttpServer must be started before port can be determined"); - return port; - } - - /** - * Opens a new Connector which is a Jetty specific way of handling the - * lifecycle and configuration of the Jetty server. The connector will - * open a Socket on an available port between minPort and maxPort. - * A subclass can override this method to modify connector configurations - * such as queue-size or header-buffer-size. - * @param minPort the minimum port number to bind to. - * @param maxPort the maximum port number to bind to. - * @return - */ - protected Connector openConnector(int minPort, int maxPort) { - if (minPort != 0 || maxPort != 0) { - Preconditions.checkState(minPort > 0, "Invalid port range."); - Preconditions.checkState(maxPort > 0, "Invalid port range."); - Preconditions.checkState(minPort <= maxPort, "Invalid port range."); - } - int attempts = 0; - int port; - - int maxAttempts = minPort == maxPort ? 1 : 5; - while (++attempts <= maxAttempts) { - if (minPort == maxPort) { - port = minPort; - } else { - port = minPort + new Random().nextInt(maxPort - minPort); - } - LOG.info("Attempting to listen on port " + port); - - try { - // TODO(John Sirois): consider making Connector impl parametrizable - AbstractConnector connector = new SelectChannelConnector(); - connector.setPort(port); - // Create the server with a maximum TCP backlog of 50, meaning that when the request queue - // exceeds 50, subsequent connections may be rejected. - connector.setAcceptQueueSize(50); - connector.open(); - return connector; - } catch (IOException e) { - LOG.log(Level.WARNING, "Failed to create HTTP server on port " + port, e); - } - } - return null; - } - - @Override - public synchronized void stop() { - if (isStarted()) { - try { - server.stop(); - } catch (Exception e) { - LOG.log(Level.SEVERE, "Error stopping HTTPServer on " + port, e); - } - } - } - - @Override - public synchronized void registerHandler( - String path, - HttpServlet handler, - @Nullable Map<String, String> initParams, - boolean silent) { - - Preconditions.checkNotNull(path); - Preconditions.checkNotNull(handler); - Preconditions.checkState(path.length() > 0); - Preconditions.checkState(path.charAt(0) == '/'); - - if (silent) { - registeredEndpoints.remove(path); - } else { - registeredEndpoints.add(path); - } - - ServletHolder servletHolder = new ServletHolder(handler); - if (initParams != null) { - servletHolder.setInitParameters(initParams); - } - getRootContext().addServlet(servletHolder, path.replaceFirst("/?$", "/*")); - } - - @Override - public synchronized void registerFilter(Class<? extends Filter> filterClass, String pathSpec) { - MorePreconditions.checkNotBlank(pathSpec); - Preconditions.checkNotNull(filterClass); - getRootContext().addFilter(filterClass, pathSpec, Handler.REQUEST); - } - - @Override - public synchronized void registerIndexLink(String path) { - MorePreconditions.checkNotBlank(path); - registeredEndpoints.add(path); - } - - @Override - public void registerListener(ServletContextListener servletContextListener) { - registerEventListener(servletContextListener); - } - - @Override - public void registerListener(ServletContextAttributeListener servletContextAttributeListener) { - registerEventListener(servletContextAttributeListener); - } - - @Override - public void registerListener(ServletRequestListener servletRequestListener) { - registerEventListener(servletRequestListener); - } - - @Override - public void registerListener(ServletRequestAttributeListener servletRequestAttributeListener) { - registerEventListener(servletRequestAttributeListener); - } - - private synchronized void registerEventListener(EventListener eventListener) { - Preconditions.checkNotNull(eventListener); - getRootContext().addEventListener(eventListener); - } - - public synchronized Context getRootContext() { - Preconditions.checkState(context != null, "Context is not yet available. " + - "Ensure that listen(...) is called prior to calling this method."); - return context; - } - - /** - * The root handler, which will display the paths at which all handlers are registered. - */ - private class RootHandler extends TextResponseHandler { - public RootHandler() { - super("text/html"); - } - - @Override - public Iterable<String> getLines(HttpServletRequest request) { - List<String> lines = Lists.newArrayList(); - lines.add("<html>"); - for (String handler : Ordering.natural().sortedCopy(registeredEndpoints)) { - lines.add(String.format("<a href='%s'>%s</a><br />", handler, handler)); - } - lines.add("</html>"); - return lines; - } - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/RequestLogger.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/RequestLogger.java b/commons/src/main/java/com/twitter/common/net/http/RequestLogger.java deleted file mode 100644 index 62e03de..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/RequestLogger.java +++ /dev/null @@ -1,130 +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 com.twitter.common.net.http; - -import java.util.Locale; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.google.common.annotations.VisibleForTesting; - -import org.mortbay.component.AbstractLifeCycle; -import org.mortbay.jetty.HttpHeaders; -import org.mortbay.jetty.Request; -import org.mortbay.jetty.RequestLog; -import org.mortbay.jetty.Response; -import org.mortbay.util.DateCache; - -import com.twitter.common.util.Clock; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * A request logger that borrows formatting code from {@link org.mortbay.jetty.NCSARequestLog}, - * but removes unneeded features (writing to file) and logging to java.util.logging. - */ -public class RequestLogger extends AbstractLifeCycle implements RequestLog { - - private static final Logger LOG = Logger.getLogger(RequestLogger.class.getName()); - - private final Clock clock; - private final LogSink sink; - private final DateCache logDateCache; - - interface LogSink { - boolean isLoggable(Level level); - void log(Level level, String messagge); - } - - RequestLogger() { - this(Clock.SYSTEM_CLOCK, new LogSink() { - @Override - public boolean isLoggable(Level level) { - return LOG.isLoggable(level); - } - - @Override public void log(Level level, String message) { - LOG.log(level, message); - } - }); - } - - @VisibleForTesting - RequestLogger(Clock clock, LogSink sink) { - this.clock = checkNotNull(clock); - this.sink = checkNotNull(sink); - logDateCache = new DateCache("dd/MMM/yyyy:HH:mm:ss Z", Locale.getDefault()); - logDateCache.setTimeZoneID("GMT"); - } - - private String formatEntry(Request request, Response response) { - StringBuilder buf = new StringBuilder(); - - buf.append(request.getServerName()); - buf.append(' '); - - String addr = request.getHeader(HttpHeaders.X_FORWARDED_FOR); - if (addr == null) { - addr = request.getRemoteAddr(); - } - - buf.append(addr); - buf.append(" ["); - buf.append(logDateCache.format(request.getTimeStamp())); - buf.append("] \""); - buf.append(request.getMethod()); - buf.append(' '); - buf.append(request.getUri().toString()); - buf.append(' '); - buf.append(request.getProtocol()); - buf.append("\" "); - buf.append(response.getStatus()); - buf.append(' '); - buf.append(response.getContentCount()); - buf.append(' '); - - String referer = request.getHeader(HttpHeaders.REFERER); - if (referer == null) { - buf.append("\"-\" "); - } else { - buf.append('"'); - buf.append(referer); - buf.append("\" "); - } - - String agent = request.getHeader(HttpHeaders.USER_AGENT); - if (agent == null) { - buf.append("\"-\" "); - } else { - buf.append('"'); - buf.append(agent); - buf.append('"'); - } - - buf.append(' '); - buf.append(clock.nowMillis() - request.getTimeStamp()); - return buf.toString(); - } - - @Override - public void log(Request request, Response response) { - int statusCategory = response.getStatus() / 100; - Level level = ((statusCategory == 2) || (statusCategory == 3)) ? Level.FINE : Level.INFO; - if (!sink.isLoggable(level)) { - return; - } - - sink.log(level, formatEntry(request, response)); - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/filters/AbstractHttpFilter.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/filters/AbstractHttpFilter.java b/commons/src/main/java/com/twitter/common/net/http/filters/AbstractHttpFilter.java deleted file mode 100644 index adb53ae..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/filters/AbstractHttpFilter.java +++ /dev/null @@ -1,63 +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 com.twitter.common.net.http.filters; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * A filter that allows subclass to omit implementations of {@link #init(FilterConfig)} and - * {@link #destroy()}. - */ -public abstract class AbstractHttpFilter implements Filter { - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - // No-op by default. - } - - @Override - public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain); - } - - /** - * Convenience method to allow subclasses to avoid type casting that may be necessary when - * implementing {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}. - * - * @param request HTTP request. - * @param response HTTP response. - * @param chain Filter chain. - * @throws IOException If there is an error reading the request or writing the response. - * @throws ServletException If the filter or chain encounters an error handling the request. - */ - public abstract void doFilter( - HttpServletRequest request, - HttpServletResponse response, - FilterChain chain) throws IOException, ServletException; - - @Override - public void destroy() { - // No-op by default. - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/filters/HttpStatsFilter.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/filters/HttpStatsFilter.java b/commons/src/main/java/com/twitter/common/net/http/filters/HttpStatsFilter.java deleted file mode 100644 index a1d80fe..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/filters/HttpStatsFilter.java +++ /dev/null @@ -1,158 +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 com.twitter.common.net.http.filters; - -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.lang.reflect.Method; -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.Logger; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.Context; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.inject.Inject; -import com.sun.jersey.api.core.ExtendedUriInfo; -import com.sun.jersey.api.model.AbstractResourceMethod; -import com.sun.jersey.spi.container.ContainerRequest; -import com.sun.jersey.spi.container.ContainerResponse; -import com.sun.jersey.spi.container.ContainerResponseFilter; - -import com.twitter.common.collections.Pair; -import com.twitter.common.stats.SlidingStats; -import com.twitter.common.stats.Stats; -import com.twitter.common.util.Clock; - -/** - * An HTTP filter that exports counts and timing for requests based on response code. - */ -public class HttpStatsFilter extends AbstractHttpFilter implements ContainerResponseFilter { - /** - * Methods tagged with this annotation will be intercepted and stats will be tracked accordingly. - */ - @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) - public @interface TrackRequestStats { - /** - * Indicates the identifier to use when tracking requests with this annotation. - */ - String value(); - } - - private static final Logger LOG = Logger.getLogger(HttpStatsFilter.class.getName()); - - @VisibleForTesting - static final String REQUEST_START_TIME = "request_start_time"; - - private final Clock clock; - @Context private ExtendedUriInfo extendedUriInfo; - - @VisibleForTesting - final LoadingCache<Pair<String, Integer>, SlidingStats> requestCounters = - CacheBuilder.newBuilder() - .build(new CacheLoader<Pair<String, Integer>, SlidingStats>() { - @Override - public SlidingStats load(Pair<String, Integer> identifierAndStatus) { - return new SlidingStats("http_" + identifierAndStatus.getFirst() + "_" - + identifierAndStatus.getSecond() + "_responses", "nanos"); - } - }); - - @Context private HttpServletRequest servletRequest; - - @VisibleForTesting - final LoadingCache<Integer, SlidingStats> statusCounters = CacheBuilder.newBuilder() - .build(new CacheLoader<Integer, SlidingStats>() { - @Override - public SlidingStats load(Integer status) { - return new SlidingStats("http_" + status + "_responses", "nanos"); - } - }); - - @VisibleForTesting - final AtomicLong exceptionCount = Stats.exportLong("http_request_exceptions"); - - @Inject - public HttpStatsFilter(Clock clock) { - this.clock = Preconditions.checkNotNull(clock); - } - - private void trackStats(int status) { - long endTime = clock.nowNanos(); - - Object startTimeAttribute = servletRequest.getAttribute(REQUEST_START_TIME); - if (startTimeAttribute == null) { - LOG.fine("No start time attribute was found on the request, this filter should be wired" - + " as both a servlet filter and a container filter."); - return; - } - - long elapsed = endTime - ((Long) startTimeAttribute).longValue(); - statusCounters.getUnchecked(status).accumulate(elapsed); - - AbstractResourceMethod matchedMethod = extendedUriInfo.getMatchedMethod(); - // It's possible for no method to have matched, e.g. in the case of a 404, don't let those - // cases lead to an exception and a 500 response. - if (matchedMethod == null) { - return; - } - - TrackRequestStats trackRequestStats = matchedMethod.getAnnotation(TrackRequestStats.class); - - if (trackRequestStats == null) { - Method method = matchedMethod.getMethod(); - LOG.fine("The method that handled this request (" + method.getDeclaringClass() + "#" - + method.getName() + ") is not annotated with " + TrackRequestStats.class.getSimpleName() - + ". No request stats will recorded."); - return; - } - - requestCounters.getUnchecked(Pair.of(trackRequestStats.value(), status)).accumulate(elapsed); - } - - @Override - public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { - trackStats(response.getStatus()); - - return response; - } - - @Override - public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) - throws IOException, ServletException { - - long startTime = clock.nowNanos(); - request.setAttribute(REQUEST_START_TIME, startTime); - - try { - chain.doFilter(request, response); - } catch (IOException e) { - exceptionCount.incrementAndGet(); - throw e; - } catch (ServletException e) { - exceptionCount.incrementAndGet(); - throw e; - } - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/AbortHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/AbortHandler.java b/commons/src/main/java/com/twitter/common/net/http/handlers/AbortHandler.java deleted file mode 100644 index cf6d25c..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/AbortHandler.java +++ /dev/null @@ -1,71 +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 com.twitter.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 com.google.common.base.Preconditions; -import com.google.inject.Inject; -import com.google.inject.name.Named; - -/** - * A servlet that provides a way to remotely terminate the running process immediately. - */ -public class AbortHandler extends HttpServlet { - - /** - * A {@literal @Named} binding key for the QuitHandler listener. - */ - public static final String ABORT_HANDLER_KEY = - "com.twitter.common.net.http.handlers.AbortHandler.listener"; - - private static final Logger LOG = Logger.getLogger(AbortHandler.class.getName()); - - private final Runnable abortListener; - - /** - * Constructs a new AbortHandler that will notify the given {@code abortListener} when the servlet - * is accessed. It is the responsibility of the listener to initiate an immediate shutdown of - * the system. - * - * @param abortListener Runnable to notify when the servlet is accessed. - */ - @Inject - public AbortHandler(@Named(ABORT_HANDLER_KEY) Runnable abortListener) { - this.abortListener = Preconditions.checkNotNull(abortListener); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) 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); - } - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/AssetHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/AssetHandler.java b/commons/src/main/java/com/twitter/common/net/http/handlers/AssetHandler.java deleted file mode 100644 index 83d139b..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/AssetHandler.java +++ /dev/null @@ -1,189 +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 com.twitter.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.ByteStreams; -import com.google.common.io.Closeables; -import com.google.common.io.InputSupplier; - -import com.twitter.common.quantity.Amount; -import com.twitter.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 InputSupplier<? extends InputStream> inputSupplier; - private final String contentType; - private final boolean cacheLocally; - - private byte[] gzipData = null; - private String hash = null; - - /** - * Creates a new static asset. - * - * @param inputSupplier Supplier of the input stream from which to load 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(InputSupplier<? extends InputStream> inputSupplier, - String contentType, boolean cacheLocally) { - this.inputSupplier = checkNotNull(inputSupplier); - 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); - ByteStreams.copy(inputSupplier, 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/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/ContentionPrinter.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/ContentionPrinter.java b/commons/src/main/java/com/twitter/common/net/http/handlers/ContentionPrinter.java deleted file mode 100644 index edde43c..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/ContentionPrinter.java +++ /dev/null @@ -1,88 +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 com.twitter.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; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * HTTP request handler that prints information about blocked threads. - * - * @author William Farner - */ -public class ContentionPrinter extends TextResponseHandler { - public ContentionPrinter() { - ManagementFactory.getThreadMXBean().setThreadContentionMonitoringEnabled(true); - } - - @Override - public Iterable<String> getLines(HttpServletRequest request) { - List<String> lines = Lists.newLinkedList(); - ThreadMXBean bean = ManagementFactory.getThreadMXBean(); - - Map<Long, StackTraceElement[]> threadStacks = Maps.newHashMap(); - for (Map.Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) { - threadStacks.put(entry.getKey().getId(), entry.getValue()); - } - - Set<Long> lockOwners = Sets.newHashSet(); - - lines.add("Locked threads:"); - for (ThreadInfo t : bean.getThreadInfo(bean.getAllThreadIds())) { - switch (t.getThreadState()) { - case BLOCKED: - case WAITING: - case TIMED_WAITING: - lines.addAll(getThreadInfo(t, threadStacks.get(t.getThreadId()))); - if (t.getLockOwnerId() != -1) lockOwners.add(t.getLockOwnerId()); - break; - } - } - - if (lockOwners.size() > 0) { - lines.add("\nLock Owners"); - for (ThreadInfo t : bean.getThreadInfo(Longs.toArray(lockOwners))) { - lines.addAll(getThreadInfo(t, threadStacks.get(t.getThreadId()))); - } - } - - return lines; - } - - private static List<String> getThreadInfo(ThreadInfo t, StackTraceElement[] stack) { - List<String> lines = Lists.newLinkedList(); - - lines.add(String.format("'%s' Id=%d %s", - t.getThreadName(), t.getThreadId(), t.getThreadState())); - lines.add("Waiting for lock: " + t.getLockName()); - lines.add("Lock is currently held by thread: " + t.getLockOwnerName()); - lines.add("Wait time: " + t.getBlockedTime() + " ms."); - for (StackTraceElement s : stack) { - lines.add(String.format(" " + s.toString())); - } - lines.add("\n"); - - return lines; - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/HealthHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/HealthHandler.java b/commons/src/main/java/com/twitter/common/net/http/handlers/HealthHandler.java deleted file mode 100644 index 30509fc..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/HealthHandler.java +++ /dev/null @@ -1,82 +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 com.twitter.common.net.http.handlers; - -import com.google.common.base.Preconditions; -import com.google.inject.Inject; -import com.google.inject.name.Named; -import com.twitter.common.base.ExceptionalSupplier; - -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 { - - /** - * A {@literal @Named} binding key for the Healthz servlet health checker. - */ - public static final String HEALTH_CHECKER_KEY = - "com.twitter.common.net.http.handlers.Healthz.checker"; - - /** - * The plain text response string this servlet returns in the body of its responses to health - * check requests when its containing service is healthy. - */ - public static final String IS_HEALTHY = "OK"; - - private static final String IS_NOT_HEALTHY = "SICK"; - - private static final Logger LOG = Logger.getLogger(HealthHandler.class.getName()); - - private final ExceptionalSupplier<Boolean, ?> healthChecker; - - /** - * Constructs a new Healthz that uses the given {@code healthChecker} to determine current health - * of the service for at the point in time of each GET request. The given {@code healthChecker} - * should return {@code true} if the service is healthy and {@code false} otherwise. If the - * {@code healthChecker} returns null or throws the service is considered unhealthy. - * - * @param healthChecker a supplier that is called to perform a health check - */ - @Inject - public HealthHandler(@Named(HEALTH_CHECKER_KEY) ExceptionalSupplier<Boolean, ?> healthChecker) { - 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); - } - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/HttpServletRequestParams.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/HttpServletRequestParams.java b/commons/src/main/java/com/twitter/common/net/http/handlers/HttpServletRequestParams.java deleted file mode 100644 index 6e75b8d..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/HttpServletRequestParams.java +++ /dev/null @@ -1,87 +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 com.twitter.common.net.http.handlers; - -import java.util.logging.Logger; -import javax.annotation.Nullable; -import javax.servlet.http.HttpServletRequest; - -/** - * Simple utility for parsing HttpServletRequest parameters by type. - */ -public class HttpServletRequestParams { - private static final Logger LOG = Logger.getLogger(HttpServletRequestParams.class.getName()); - - /** - * Parses an int param from an HttpServletRequest, returns a default value - * if the parameter is not set or is not a valid int. - */ - public static int getInt(HttpServletRequest request, String param, int defaultValue) { - final String value = request.getParameter(param); - int result = defaultValue; - if (value != null) { - try { - result = Integer.parseInt(value); - } catch (NumberFormatException e) { - LOG.warning("Invalid int for " + param + ": " + value); - } - } - return result; - } - - /** - * Parses a long param from an HttpServletRequest, returns a defualt value - * if the parameter is not set or is not a valid long. - */ - public static long getLong(HttpServletRequest request, String param, long defaultValue) { - final String value = request.getParameter(param); - long result = defaultValue; - if (value != null) { - try { - result = Long.parseLong(value); - } catch (NumberFormatException e) { - LOG.warning("Invalid long for " + param + ": " + value); - } - } - return result; - } - - /** - * Parses a bool param from an HttpServletRequest, returns a default value - * if the parameter is not set. Note that any value that is set will be - * considered a legal bool by Boolean.valueOf, defualting to false if not - * understood. - */ - public static boolean getBool(HttpServletRequest request, String param, boolean defaultValue) { - if (request.getParameter(param) != null) { - return Boolean.valueOf(request.getParameter(param)); - } else { - return defaultValue; - } - } - - /** - * Returns a string param from an HttpServletRequest if set, returns a defualt value - * if the parameter is not set. - */ - @Nullable - public static String getString(HttpServletRequest request, String param, - @Nullable String defaultValue) { - if (request.getParameter(param) != null) { - return request.getParameter(param); - } else { - return defaultValue; - } - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/LogConfig.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/LogConfig.java b/commons/src/main/java/com/twitter/common/net/http/handlers/LogConfig.java deleted file mode 100644 index b7a30a6..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/LogConfig.java +++ /dev/null @@ -1,132 +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 com.twitter.common.net.http.handlers; - -import java.io.IOException; -import java.util.List; -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 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 com.twitter.common.base.Closure; - -/** - * Servlet that allows for dynamic adjustment of the logging configuration. - * - * @author William Farner - */ -public class LogConfig extends StringTemplateServlet { - private static final List<String> LOG_LEVELS = Lists.newArrayList( - Level.SEVERE.getName(), - Level.WARNING.getName(), - Level.INFO.getName(), - Level.CONFIG.getName(), - Level.FINE.getName(), - Level.FINER.getName(), - Level.FINEST.getName(), - "INHERIT" // Display value for a null level, the logger inherits from its ancestor. - ); - - @Inject - public LogConfig(@CacheTemplates boolean cacheTemplates) { - super("logconfig", cacheTemplates); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - displayPage(req, resp, true); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - displayPage(req, resp, false); - } - - protected void displayPage(final HttpServletRequest req, HttpServletResponse resp, - final boolean posted) throws ServletException, IOException { - writeTemplate(resp, 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)); - } - } - - List<LoggerConfig> loggerConfigs = Lists.newArrayList(); - for (String logger : Ordering.natural().immutableSortedCopy(logBean.getLoggerNames())) { - loggerConfigs.add(new LoggerConfig(logger, logBean.getLoggerLevel(logger))); - } - - stringTemplate.setAttribute("loggers", loggerConfigs); - stringTemplate.setAttribute("levels", LOG_LEVELS); - } - }); - } - - private void maybeAdjustHandlerLevels(Logger logger, Level newLevel) { - do { - for (Handler handler : logger.getHandlers()) { - Level handlerLevel = handler.getLevel(); - if (newLevel.intValue() < handlerLevel.intValue()) { - handler.setLevel(newLevel); - } - } - } while (logger.getUseParentHandlers() && (logger = logger.getParent()) != null); - } - - private class LoggerConfig { - private final String name; - private final String level; - - public LoggerConfig(String name, String level) { - this.name = name; - this.level = StringUtils.isBlank(level) ? "INHERIT" : level; - } - - public String getName() { - return name; - } - - public String getLevel() { - return level; - } - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/LogPrinter.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/LogPrinter.java b/commons/src/main/java/com/twitter/common/net/http/handlers/LogPrinter.java deleted file mode 100644 index 3c69df2..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/LogPrinter.java +++ /dev/null @@ -1,427 +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 com.twitter.common.net.http.handlers; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Pattern; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Charsets; -import com.google.common.base.Joiner; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.io.Files; -import com.google.inject.Inject; -import com.google.inject.name.Named; - -import org.antlr.stringtemplate.StringTemplate; -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.commons.lang.StringUtils; - -import com.twitter.common.base.Closure; -import com.twitter.common.base.MorePreconditions; -import com.twitter.common.quantity.Amount; -import com.twitter.common.quantity.Data; - -/** - * HTTP handler to page through log files. Supports GET and POST requests. GET requests are - * responsible for fetching chrome and javascript, while the POST requests are used to fetch actual - * log data. - */ -public class LogPrinter extends StringTemplateServlet { - private static final Logger LOG = Logger.getLogger(LogPrinter.class.getName()); - - /** - * A {@literal @Named} binding key for the log directory to display by default. - */ - public static final String LOG_DIR_KEY = - "com.twitter.common.net.http.handlers.LogPrinter.log_dir"; - - private static final int DEFAULT_PAGE = 0; - - private static final int PAGE_CHUNK_SIZE_BYTES = Amount.of(512, Data.KB).as(Data.BYTES); - private static final int TAIL_START_BYTES = Amount.of(10, Data.KB).as(Data.BYTES); - private static final int PAGE_END_BUFFER_SIZE_BYTES = Amount.of(1, Data.KB).as(Data.BYTES); - - private static final String XML_RESP_FORMAT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" - + "<logchunk text=\"%s\"" - + " end_pos=\"%d\">" - + "</logchunk>"; - private final File logDir; - - @Inject - public LogPrinter(@Named(LOG_DIR_KEY) File logDir, @CacheTemplates boolean cacheTemplates) { - super("logprinter", cacheTemplates); - this.logDir = Preconditions.checkNotNull(logDir); - } - - /** - * A POST request is made from javascript, to request the contents of a log file. In order to - * fulfill the request, the 'file' parameter must be set in the request. - * - * If file starts with a '/' then the file parameter will be treated as an absolute file path. - * If file does not start with a '/' then the path will be assumed to be - * relative to the log directory. - * - * @param req Servlet request. - * @param resp Servlet response. - * @throws ServletException If there is a problem with the servlet. - * @throws IOException If there is a problem reading/writing data to the client. - */ - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - resp.setContentType("text/xml; charset=utf-8"); - - try { - LogViewRequest request = new LogViewRequest(req); - - if (request.file == null) { - // The log file is a required parameter for POST requests. - resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - resp.setStatus(HttpServletResponse.SC_OK); - PrintWriter responseBody = resp.getWriter(); - - String responseXml = fetchXmlLogContents(request); - responseBody.write(responseXml); - responseBody.close(); - } catch (Exception e) { - LOG.log(Level.SEVERE, "Unknown exception.", e); - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - } - - /** - * Fetches the chrome for the page. If a file is requested, a page will be returned that uses an - * AJAX request to fetch the log contents. If no file is specified, then a file listing is - * displayed. - * - * @param req Servlet request. - * @param resp Servlet response. - * @throws ServletException If there is a problem with the servlet. - * @throws IOException If there is a problem reading/writing data to the client. - */ - @Override - protected void doGet(final HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - final LogViewRequest request = new LogViewRequest(req); - - if (request.download) { - if (request.file == null) { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "No file requested for download."); - return; - } - - if (!request.file.isRegularFile()) { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Only regular files may be downloaded."); - return; - } - - try { - OutputStream out = resp.getOutputStream(); - ServletContext context = getServletConfig().getServletContext(); - String mimetype = context.getMimeType(request.file.getName()); - - resp.setContentType(mimetype != null ? mimetype : "application/octet-stream" ); - resp.setContentLength((int) request.file.getFile().length()); - resp.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", - request.file.getName())); - - Files.copy(request.file.getFile(), out); - } catch (Exception e) { - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to fetch file."); - LOG.warning("Failed to download file " + request.file.getPath() + ": " + e.getMessage()); - } - } else { - writeTemplate(resp, new Closure<StringTemplate>() { - @Override public void execute(StringTemplate template) { - - // TODO(William Farner): Consider using unix file utility to check if the requested file is a - // text file, and allow the user to download the file if it is not. - if (request.isFileViewRequest()) { - request.sendToTemplate(template); - - if (!request.tailing) { - long readStartPos = getReadStartPos(request.file.getFile(), request.page); - - if (readStartPos > 0) template.setAttribute("prev", request.page + 1); - if (request.page > 0) template.setAttribute("next", request.page - 1); - } - } else { - // If a file was not requested, show a list of files. - File dir = request.getListingDir(); - - List<LogFile> logFiles = Lists.newArrayList(); - for (File file : dir.listFiles()) { - logFiles.add(new LogFile(file)); - } - - // Sort by dir/file, subsort by name. - Collections.sort(logFiles, new Comparator<LogFile>() { - @Override public int compare(LogFile fileA, LogFile fileB) { - if (fileA.isDir() == fileB.isDir()) { - return fileA.file.getName().compareTo(fileB.file.getName()); - } else { - return fileA.isDir() ? -1 : 1; - } - } - }); - - template.setAttribute("dir", dir); - template.setAttribute("parent", dir.getParentFile()); - template.setAttribute("files", logFiles); - } - } - }); - } - } - - /** - * Gets the starting position for reading a page from a file. - * - * @param file The file to find a page within. - * @param page The page index, where page 0 is the last page (at the end of the file). - * @return The byte index that the page begins on, or 0 if an invalid page number was provided. - */ - private long getReadStartPos(File file, int page) { - return page < 0 ? 0 : Math.max(0, file.length() - (page + 1) * PAGE_CHUNK_SIZE_BYTES); - } - - /** - * Stores request parameters and assigns default values. - */ - private class LogViewRequest { - public static final String DIR_PARAM = "dir"; - public static final String FILE_PARAM = "file"; - public static final String PAGE_PARAM = "page"; - public static final String FILTER_PARAM = "filter"; - public static final String TAIL_PARAM = "tail"; - public static final String START_POS_PARAM = "start_pos"; - public static final String DOWNLOAD_PARAM = "download"; - - public final File dir; - public final LogFile file; - public final boolean download; - public final int page; - public final long startPos; - public final String filter; - public final boolean tailing; - - public LogViewRequest(HttpServletRequest req) { - dir = req.getParameter(DIR_PARAM) == null ? null : new File(req.getParameter(DIR_PARAM)); - file = req.getParameter(FILE_PARAM) == null ? null - : new LogFile(req.getParameter(FILE_PARAM)); - download = HttpServletRequestParams.getBool(req, DOWNLOAD_PARAM, false); - tailing = HttpServletRequestParams.getBool(req, TAIL_PARAM, false); - page = HttpServletRequestParams.getInt(req, PAGE_PARAM, DEFAULT_PAGE); - Preconditions.checkArgument(page >= 0); - - startPos = HttpServletRequestParams.getLong(req, START_POS_PARAM, -1); - if (file != null) { - Preconditions.checkArgument(startPos >= -1 && startPos <= file.getFile().length()); - } - filter = HttpServletRequestParams.getString(req, FILTER_PARAM, ""); - } - - public boolean isFileViewRequest() { - return file != null && file.isRegularFile(); - } - - public File getListingDir() { - if (file != null && file.getFile().isDirectory()) { - return file.getFile(); - } else if (dir != null) { - return dir; - } else { - return logDir; - } - } - - public void sendToTemplate(StringTemplate template) { - template.setAttribute(FILE_PARAM, file); - template.setAttribute(PAGE_PARAM, page); - template.setAttribute(FILTER_PARAM, filter); - template.setAttribute(TAIL_PARAM, tailing); - } - } - - /** - * Class to wrap a log file and offer functions to StringTemplate via reflection. - */ - @VisibleForTesting - class LogFile { - private final File file; - - public LogFile(File file) { - this.file = file; - } - - public LogFile(String filePath) { - MorePreconditions.checkNotBlank(filePath, "filePath must not be null or empty"); - this.file = filePath.startsWith("/") ? new File(filePath) : new File(logDir, filePath); - } - - public File getFile() { - return file; - } - - public boolean isDir() { - return !isRegularFile(); - } - - public boolean isRegularFile() { - return file.isFile(); - } - - public String getPath() { - return file.getAbsolutePath(); - } - - public String getName() { - return file.getName(); - } - - public String getUrlpath() throws UnsupportedEncodingException { - return URLEncoder.encode(getPath(), Charsets.UTF_8.name()); - } - - public String getSize() { - Amount<Long, Data> length = Amount.of(file.length(), Data.BYTES); - - if (length.as(Data.GB) > 0) { - return length.as(Data.GB) + " GB"; - } else if (length.as(Data.MB) > 0) { - return length.as(Data.MB) + " MB"; - } else if (length.as(Data.KB) > 0) { - return length.as(Data.KB) + " KB"; - } else { - return length.getValue() + " bytes"; - } - } - } - - /** - * Reads data from a log file and prepares an XML response which includes the (sanitized) log text - * and the last position read from the file. - * - * @param request The request parameters. - * @return A string containing the XML-formatted response. - * @throws IOException If there was a problem reading the file. - */ - private String fetchXmlLogContents(LogViewRequest request) throws IOException { - RandomAccessFile seekFile = new RandomAccessFile(request.file.getFile(), "r"); - try { - // Move to the approximate start of the page. - if (!request.tailing) { - seekFile.seek(getReadStartPos(request.file.getFile(), request.page)); - } else { - if (request.startPos < 0) { - seekFile.seek(Math.max(0, request.file.getFile().length() - TAIL_START_BYTES)); - } else { - seekFile.seek(request.startPos); - } - } - - byte[] buffer = new byte[PAGE_CHUNK_SIZE_BYTES]; - int bytesRead = seekFile.read(buffer); - long chunkStop = seekFile.getFilePointer(); - StringBuilder fileChunk = new StringBuilder(); - if (bytesRead > 0) { - fileChunk.append(new String(buffer, 0, bytesRead)); - - // Read at most 1 KB more while searching for another line break. - buffer = new byte[PAGE_END_BUFFER_SIZE_BYTES]; - int newlinePos = 0; - bytesRead = seekFile.read(buffer); - if (bytesRead > 0) { - for (byte b : buffer) { - newlinePos++; - if (b == '\n') break; - } - - fileChunk.append(new String(buffer, 0, newlinePos)); - chunkStop = seekFile.getFilePointer() - (bytesRead - newlinePos); - } - } - - return logChunkXml(filterLines(fileChunk.toString(), request.filter), chunkStop); - } finally { - seekFile.close(); - } - } - - private static String sanitize(String text) { - text = StringEscapeUtils.escapeHtml(text); - - StringBuilder newString = new StringBuilder(); - for (char ch : text.toCharArray()) { - if ((ch > 0x001F && ch < 0x00FD) || ch == '\t' || ch == '\r') { - // Directly include anything from 0x1F (SPACE) to 0xFD (tilde) - // as well as tab and carriage-return. - newString.append(ch); - } else { - // Encode everything else. - newString.append("&#").append((int) ch).append(";"); - } - } - return StringEscapeUtils.escapeXml(newString.toString()); - } - - private String logChunkXml(String text, long lastBytePosition) { - return String.format(XML_RESP_FORMAT, sanitize(text) , lastBytePosition); - } - - @VisibleForTesting - protected static String filterLines(String text, String filterRegexp) { - if (StringUtils.isEmpty(filterRegexp)) return text; - - List<String> lines = Lists.newArrayList(text.split("\n")); - final Pattern pattern = Pattern.compile(filterRegexp); - - Iterable<String> filtered = Iterables.filter(lines, new Predicate<String>() { - @Override public boolean apply(String line) { - return pattern.matcher(line).matches(); - } - }); - - return Joiner.on("\n").join(filtered); - } - - private class LogConfigException extends Exception { - public LogConfigException(String message) { - super(message); - } - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/QuitHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/QuitHandler.java b/commons/src/main/java/com/twitter/common/net/http/handlers/QuitHandler.java deleted file mode 100644 index 38f1596..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/QuitHandler.java +++ /dev/null @@ -1,71 +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 com.twitter.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 com.google.common.base.Preconditions; -import com.google.inject.Inject; -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 { - private static final Logger LOG = Logger.getLogger(QuitHandler.class.getName()); - - /** - * A {@literal @Named} binding key for the QuitHandler listener. - */ - public static final String QUIT_HANDLER_KEY = - "com.twitter.common.net.http.handlers.QuitHandler.listener"; - - private final Runnable quitListener; - - /** - * Constructs a new QuitHandler that will notify the given {@code quitListener} when the servlet - * is accessed. It is the responsibility of the listener to initiate a clean shutdown of the - * process. - * - * @param quitListener Runnable to notify when the servlet is accessed. - */ - @Inject - public QuitHandler(@Named(QUIT_HANDLER_KEY) Runnable quitListener) { - this.quitListener = Preconditions.checkNotNull(quitListener); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { - 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); - } - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/StringTemplateServlet.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/StringTemplateServlet.java b/commons/src/main/java/com/twitter/common/net/http/handlers/StringTemplateServlet.java deleted file mode 100644 index d00e7e5..0000000 --- a/commons/src/main/java/com/twitter/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 com.twitter.common.net.http.handlers; - -import com.google.common.base.Preconditions; -import com.google.inject.BindingAnnotation; - -import com.twitter.common.base.Closure; -import com.twitter.common.base.MorePreconditions; -import com.twitter.common.util.templating.StringTemplateHelper; -import com.twitter.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/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/TextResponseHandler.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/TextResponseHandler.java b/commons/src/main/java/com/twitter/common/net/http/handlers/TextResponseHandler.java deleted file mode 100644 index 514e04f..0000000 --- a/commons/src/main/java/com/twitter/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 com.twitter.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/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/ThreadStackPrinter.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/ThreadStackPrinter.java b/commons/src/main/java/com/twitter/common/net/http/handlers/ThreadStackPrinter.java deleted file mode 100644 index e5eded4..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/ThreadStackPrinter.java +++ /dev/null @@ -1,41 +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 com.twitter.common.net.http.handlers; - -import com.google.common.collect.Lists; - -import javax.servlet.http.HttpServletRequest; -import java.util.List; -import java.util.Map; - -/** - * 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) { - List<String> lines = Lists.newLinkedList(); - for (Map.Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) { - Thread t = entry.getKey(); - lines.add(String.format("Name: %s\nState: %s\nDaemon: %s\nID: %d", - t.getName(), t.getState(), t.isDaemon(), t.getId())); - for (StackTraceElement s : entry.getValue()) { - lines.add(" " + s.toString()); - } - } - return lines; - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons/src/main/java/com/twitter/common/net/http/handlers/ThriftServlet.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/com/twitter/common/net/http/handlers/ThriftServlet.java b/commons/src/main/java/com/twitter/common/net/http/handlers/ThriftServlet.java deleted file mode 100644 index bb74fcf..0000000 --- a/commons/src/main/java/com/twitter/common/net/http/handlers/ThriftServlet.java +++ /dev/null @@ -1,70 +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 com.twitter.common.net.http.handlers; - -import com.google.common.base.Preconditions; -import com.google.inject.Inject; -import com.google.inject.name.Named; -import com.twitter.common.base.Closure; -import com.twitter.common.net.monitoring.TrafficMonitor; -import org.antlr.stringtemplate.StringTemplate; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Set; - -/** - * Servlet to display live information about registered thrift clients and servers. - * - * @author William Farner - */ -public class ThriftServlet extends StringTemplateServlet { - - /** - * {@literal @Named} binding key for client monitor. - */ - public static final String THRIFT_CLIENT_MONITORS = - "com.twitter.common.net.http.handlers.ThriftServlet.THRIFT_CLIENT_MONITORS"; - - /** - * {@literal @Named} binding key for server monitor. - */ - public static final String THRIFT_SERVER_MONITORS = - "com.twitter.common.net.http.handlers.ThriftServlet.THRIFT_SERVER_MONITORS"; - - private Set<TrafficMonitor> clientMonitors; - private Set<TrafficMonitor> serverMonitors; - - @Inject - public ThriftServlet( - @Named(ThriftServlet.THRIFT_CLIENT_MONITORS) Set<TrafficMonitor> clientMonitors, - @Named(ThriftServlet.THRIFT_SERVER_MONITORS) Set<TrafficMonitor> serverMonitors) { - super("thrift", true); - this.clientMonitors = Preconditions.checkNotNull(clientMonitors); - this.serverMonitors = Preconditions.checkNotNull(serverMonitors); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - writeTemplate(resp, new Closure<StringTemplate>() { - @Override public void execute(StringTemplate template) { - template.setAttribute("clientMonitors", clientMonitors); - template.setAttribute("serverMonitors", serverMonitors); - } - }); - } -}