From 4fa6144f44136f60427245671481ac68d21e670b Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 14 Nov 2011 18:28:24 -0800 Subject: [PATCH 0001/2771] Docs! --- .../example/helloworld/HelloWorldService.java | 4 +- .../yammer/dropwizard/AbstractService.java | 80 +++++++++++++++++-- .../java/com/yammer/dropwizard/Service.java | 6 ++ .../com/yammer/dropwizard/util/SizeUnit.java | 59 ++++++++++++++ .../yammer/dropwizard/tests/ServiceTest.java | 3 +- 5 files changed, 144 insertions(+), 8 deletions(-) diff --git a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java index a65ecbc0a24..d75bc74be8c 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java @@ -18,8 +18,8 @@ private HelloWorldService() { } @Override - public void initialize(HelloWorldConfiguration configuration, - Environment environment) { + protected void initialize(HelloWorldConfiguration configuration, + Environment environment) { final Template template = configuration.buildTemplate(); environment.addHealthCheck(new TemplateHealthCheck(template)); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java index 316634725a5..d2cafa6f109 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java @@ -17,9 +17,10 @@ import java.util.SortedMap; /** - * The base class for both Java and Scala services. + * The base class for both Java and Scala services. Do not extend this directly. Use {@link Service} + * instead. * - * @param the type of configuration class for this service + * @param the type of configuration class for this service */ public abstract class AbstractService { static { @@ -32,6 +33,11 @@ public abstract class AbstractService { private final SortedMap commands; private String banner = null; + /** + * Creates a new service with the given name. + * + * @param name the service's name + */ protected AbstractService(String name) { this.name = name; this.modules = Lists.newArrayList(); @@ -60,47 +66,111 @@ public final Class getConfigurationClass() { return (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } + /** + * Returns a list of registered {@link Module} instances. + * + * @return a list of modules + */ public final ImmutableList getModules() { return ImmutableList.copyOf(modules); } + /** + * Registers a {@link Module} to be used in initializing the service's {@link Environment}. + * + * @param module a module + * @see Module + */ protected final void addModule(Module module) { modules.add(module); } + /** + * Returns a list of registered {@link Command} instances. + * + * @return a list of commands + */ public final ImmutableList getCommands() { return ImmutableList.copyOf(commands.values()); } + /** + * Registers a {@link Command} which the service will provide. + * + * @param command a command + */ protected final void addCommand(Command command) { commands.put(command.getName(), command); } + /** + * Registers a {@link ConfiguredCommand} which the service will provide. + * + * @param command a command + */ protected final void addCommand(ConfiguredCommand command) { commands.put(command.getName(), command); } + /** + * Returns {@code true} if the service has a banner. + * + * @return whether or not the service has a banner + */ public final boolean hasBanner() { return banner != null; } + /** + * Returns the service's banner, if any. The banner will be printed out when the service starts + * up. + * + * @return the service's banner + */ public final String getBanner() { return banner; } + /** + * Sets the service's banner. The banner will be printed out when the service starts up. + * + * @param banner a banner + */ protected final void setBanner(String banner) { this.banner = banner; } - public abstract void initialize(T configuration, Environment environment); - - public void initializeWithModules(T configuration, Environment environment) { + /** + * When the service runs, this is called after the {@link Module}s are run. Override it to add + * providers, resources, etc. for your service. + * + * @param configuration the parsed {@link Configuration} object + * @param environment the service's {@link Environment} + */ + protected abstract void initialize(T configuration, Environment environment); + + /** + * Initializes the given {@link Environment} given a {@link Configuration} instances. First the + * modules are initialized in the order they were added, then the service's + * {@link #initialize(Configuration, Environment)} method is called. + * + * @param configuration the parsed {@link Configuration} object + * @param environment the service's {@link Environment} + */ + public final void initializeWithModules(T configuration, Environment environment) { for (Module module : modules) { module.initialize(environment); } initialize(configuration, environment); } + /** + * Parses command-line arguments and runs the service. Call this method from a + * {@code public static void main} entry point in your application. + * + * @param arguments the command-line arguments + * @throws Exception if something goes wrong + */ public final void run(String[] arguments) throws Exception { if (isHelp(arguments)) { UsagePrinter.printRootHelp(this); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/Service.java b/dropwizard/src/main/java/com/yammer/dropwizard/Service.java index 5e61183455a..1f1d5a738f5 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/Service.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/Service.java @@ -3,6 +3,12 @@ import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.modules.JavaModule; +/** + * The default Java service class. Extend this to write your own service. + * + * @param the type of configuration class to use + * @see Configuration + */ public abstract class Service extends AbstractService { protected Service(String name) { super(name); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/util/SizeUnit.java b/dropwizard/src/main/java/com/yammer/dropwizard/util/SizeUnit.java index 3a778bee03f..8002c56e63a 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/util/SizeUnit.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/util/SizeUnit.java @@ -1,10 +1,32 @@ package com.yammer.dropwizard.util; +/** + * A unit of size. + */ public enum SizeUnit { + /** + * Bytes. + */ BYTES(8), + + /** + * Kilobytes. + */ KILOBYTES(8L * 1024), + + /** + * Megabytes. + */ MEGABYTES(8L * 1024 * 1024), + + /** + * Gigabytes. + */ GIGABYTES(8L * 1024 * 1024 * 1024), + + /** + * Megabytes. + */ TERABYTES(8L * 1024 * 1024 * 1024 * 1024); private final long bits; @@ -13,26 +35,63 @@ public enum SizeUnit { this.bits = bits; } + /** + * Converts a size of the given unit into the current unit. + * + * @param size the magnitude of the size + * @param unit the unit of the size + * @return the given size in the current unit. + */ public long convert(long size, SizeUnit unit) { return (size * unit.bits) / bits; } + /** + * Converts the given number of the current units into bytes. + * + * @param l the magnitude of the size in the current unit + * @return {@code l} of the current units in bytes + */ public long toBytes(long l) { return BYTES.convert(l, this); } + /** + * Converts the given number of the current units into kilobytes. + * + * @param l the magnitude of the size in the current unit + * @return {@code l} of the current units in kilobytes + */ public long toKilobytes(long l) { return KILOBYTES.convert(l, this); } + /** + * Converts the given number of the current units into megabytes. + * + * @param l the magnitude of the size in the current unit + * @return {@code l} of the current units in megabytes + */ public long toMegabytes(long l) { return MEGABYTES.convert(l, this); } + /** + * Converts the given number of the current units into gigabytes. + * + * @param l the magnitude of the size in the current unit + * @return {@code l} of the current units in bytes + */ public long toGigabytes(long l) { return GIGABYTES.convert(l, this); } + /** + * Converts the given number of the current units into terabytes. + * + * @param l the magnitude of the size in the current unit + * @return {@code l} of the current units in terabytes + */ public long toTerabytes(long l) { return TERABYTES.convert(l, this); } diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java index d12c7e95cf5..5d8b96a5dbe 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java @@ -24,7 +24,8 @@ private class FakeService extends Service { } @Override - public void initialize(FakeConfiguration configuration, Environment environment) { + protected void initialize(FakeConfiguration configuration, + Environment environment) { } } From 71dc5d50bb269007334ebd67adeca576c5ab0bc3 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 14 Nov 2011 18:34:36 -0800 Subject: [PATCH 0002/2771] Docs and tests for CacheBustingFilter. --- .../servlets/CacheBustingFilter.java | 10 ++--- .../tests/CacheBustingFilterTest.java | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 dropwizard/src/test/java/com/yammer/dropwizard/servlets/tests/CacheBustingFilterTest.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java index fca1e61accf..5d9463ef78b 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java @@ -6,12 +6,12 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; -// TODO: 10/12/11 -- write tests for CacheBustingFilter -// TODO: 10/12/11 -- write docs for CacheBustingFilter - +/** + * Adds a no-cache header to all responses. + */ @SuppressWarnings("UnusedDeclaration") public class CacheBustingFilter implements Filter { - private static final String MUST_REVALIDATE_NO_CACHE_NO_STORE = "must-revalidate,no-cache,no-store"; + private static final String CACHE_SETTINGS = "must-revalidate,no-cache,no-store"; @Override public void doFilter(ServletRequest request, @@ -19,7 +19,7 @@ public void doFilter(ServletRequest request, FilterChain chain) throws IOException, ServletException { if (response instanceof HttpServletResponse) { final HttpServletResponse resp = (HttpServletResponse) response; - resp.setHeader(HttpHeaders.CACHE_CONTROL, MUST_REVALIDATE_NO_CACHE_NO_STORE); + resp.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_SETTINGS); } chain.doFilter(request, response); } diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/servlets/tests/CacheBustingFilterTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/servlets/tests/CacheBustingFilterTest.java new file mode 100644 index 00000000000..9779e990736 --- /dev/null +++ b/dropwizard/src/test/java/com/yammer/dropwizard/servlets/tests/CacheBustingFilterTest.java @@ -0,0 +1,40 @@ +package com.yammer.dropwizard.servlets.tests; + +import com.yammer.dropwizard.servlets.CacheBustingFilter; +import org.junit.Test; +import org.mockito.InOrder; + +import javax.servlet.FilterChain; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static org.mockito.Mockito.*; + +public class CacheBustingFilterTest { + private final HttpServletRequest request = mock(HttpServletRequest.class); + private final HttpServletResponse response = mock(HttpServletResponse.class); + private final FilterChain chain = mock(FilterChain.class); + private final CacheBustingFilter filter = new CacheBustingFilter(); + + @Test + public void passesThroughNonHttpRequests() throws Exception { + final ServletRequest req = mock(ServletRequest.class); + final ServletResponse res = mock(ServletResponse.class); + + filter.doFilter(req, res, chain); + + verify(chain).doFilter(req, res); + verifyZeroInteractions(res); + } + + @Test + public void setsACacheHeaderOnTheResponse() throws Exception { + filter.doFilter(request, response, chain); + + final InOrder inOrder = inOrder(response, chain); + inOrder.verify(response).setHeader("Cache-Control", "must-revalidate,no-cache,no-store"); + inOrder.verify(chain).doFilter(request, response); + } +} From 2e93b2c6d8e7a1858f77d1fe18dc9eeac40939eb Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 14 Nov 2011 18:39:31 -0800 Subject: [PATCH 0003/2771] Knocking out warnings. --- .../com/yammer/dropwizard/logging/LoggingBean.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/logging/LoggingBean.java b/dropwizard/src/main/java/com/yammer/dropwizard/logging/LoggingBean.java index 87165617e72..44ca89e1914 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/logging/LoggingBean.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/logging/LoggingBean.java @@ -3,11 +3,11 @@ // TODO: 10/12/11 -- test LoggingBean // TODO: 10/12/11 -- document LoggingBean +import com.google.common.collect.Lists; import org.apache.log4j.Category; import org.apache.log4j.Level; import org.apache.log4j.Logger; -import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; @@ -22,11 +22,10 @@ public String getLoggerLevel(String loggerName) { @Override public List getLoggerNames() { - final List names = new ArrayList(); - - final Enumeration loggers = Logger.getRootLogger() - .getLoggerRepository() - .getCurrentLoggers(); + final List names = Lists.newArrayList(); + final Enumeration loggers = Logger.getRootLogger() + .getLoggerRepository() + .getCurrentLoggers(); while (loggers.hasMoreElements()) { final Logger logger = (Logger) loggers.nextElement(); names.add(logger.getName()); From 7aaa1151ea87b656b667d5f89225b58ba61c6bcc Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 14 Nov 2011 19:19:30 -0800 Subject: [PATCH 0004/2771] Fixed a bunch of warnings. --- .../guava/deser/OptionalDeserializer.java | 3 +-- .../module/guava/ser/OptionalSerializer.java | 3 +-- .../yammer/dropwizard/AbstractService.java | 2 +- .../config/ConfigurationException.java | 6 ++--- .../yammer/dropwizard/config/Environment.java | 3 ++- .../dropwizard/config/HttpConfiguration.java | 16 +++++++------- .../config/LoggingConfiguration.java | 9 ++++---- .../dropwizard/config/ServerFactory.java | 22 +++++++++---------- ...{GzipHandler.java => BiDiGzipHandler.java} | 20 +++++++++-------- .../servlets/CacheBustingFilter.java | 1 - .../tests/ConfigurationFactoryTest.java | 15 +++++++------ .../tests/LoggingConfigurationTest.java | 2 +- .../dropwizard/util/tests/ValidatorTest.java | 1 - 13 files changed, 51 insertions(+), 52 deletions(-) rename dropwizard/src/main/java/com/yammer/dropwizard/jetty/{GzipHandler.java => BiDiGzipHandler.java} (83%) diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java b/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java index 7a8284d34c9..e5e0377c1a5 100644 --- a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java +++ b/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java @@ -2,7 +2,6 @@ import com.google.common.base.Optional; import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.map.DeserializationContext; import org.codehaus.jackson.map.JsonDeserializer; @@ -20,7 +19,7 @@ public OptionalDeserializer(JsonDeserializer elementDeserializer) { @Override public Optional deserialize(JsonParser jp, - DeserializationContext ctxt) throws IOException, JsonProcessingException { + DeserializationContext ctxt) throws IOException { if (jp.getCurrentToken() == JsonToken.VALUE_NULL) { return Optional.absent(); } diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java b/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java index 9d907f8937d..7394f3c4e1e 100644 --- a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java +++ b/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java @@ -2,7 +2,6 @@ import com.google.common.base.Optional; import org.codehaus.jackson.JsonGenerator; -import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.annotate.JsonCachable; @@ -14,7 +13,7 @@ public class OptionalSerializer extends JsonSerializer> { @Override public void serialize(Optional value, JsonGenerator jgen, - SerializerProvider provider) throws IOException, JsonProcessingException { + SerializerProvider provider) throws IOException { if (value.isPresent()) { jgen.writeObject(value.get()); } else { diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java index d2cafa6f109..9ccfebc4c66 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java @@ -22,6 +22,7 @@ * * @param the type of configuration class for this service */ +@SuppressWarnings("EmptyMethod") public abstract class AbstractService { static { // make sure spinning up Hibernate Validator doesn't yell at us @@ -48,7 +49,6 @@ protected AbstractService(String name) { /** * A simple reminder that this particular class isn't meant to be extended by non-DW classes. */ - @SuppressWarnings("UnusedDeclaration") protected abstract void subclassServiceInsteadOfThis(); public final String getName() { diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java b/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java index a38c0f3acaf..2e6e7450951 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java @@ -3,14 +3,12 @@ import java.io.File; public class ConfigurationException extends Exception { + private static final long serialVersionUID = 5325162099634227047L; + public ConfigurationException(File file, Iterable errors) { super(formatMessage(file, errors)); } - public ConfigurationException(Exception e) { - super(e); - } - private static String formatMessage(File file, Iterable errors) { final StringBuilder msg = new StringBuilder(file.toString()) .append(" has the following errors:\n"); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard/src/main/java/com/yammer/dropwizard/config/Environment.java index e2ff5b68641..92370a415b6 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -11,6 +11,7 @@ import com.sun.jersey.spi.container.servlet.ServletContainer; import com.yammer.dropwizard.jersey.LoggingExceptionMapper; import com.yammer.dropwizard.jetty.JettyManaged; +import com.yammer.dropwizard.jetty.NonblockingServletHolder; import com.yammer.dropwizard.lifecycle.Managed; import com.yammer.dropwizard.tasks.GarbageCollectionTask; import com.yammer.dropwizard.tasks.Task; @@ -159,7 +160,7 @@ public void manage(LifeCycle managed) { */ public ServletConfiguration addServlet(Servlet servlet, String urlPattern) { - final ServletHolder holder = new ServletHolder(checkNotNull(servlet)); + final ServletHolder holder = new NonblockingServletHolder(checkNotNull(servlet)); final ServletConfiguration configuration = new ServletConfiguration(holder, servlets); configuration.addUrlPattern(checkNotNull(urlPattern)); return configuration; diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 43b1614f60c..902a87b8649 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -13,7 +13,7 @@ // TODO: 11/7/11 -- document HttpConfiguration // TODO: 11/7/11 -- test HttpConfiguration -@SuppressWarnings("FieldCanBeLocal") +@SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal", "CanBeFinal"}) public class HttpConfiguration { public static class RequestLogConfiguration { private boolean enabled = true; @@ -82,7 +82,7 @@ public Optional> getCompressedMimeTypes() { @NotNull private GzipConfiguration gzip = new GzipConfiguration(); - public static enum ConnectorType { + public enum ConnectorType { SOCKET, BLOCKING_CHANNEL, SELECT_CHANNEL @@ -178,11 +178,11 @@ public GzipConfiguration getGzipConfiguration() { } public ConnectorType getConnectorType() { - if (connectorType.equalsIgnoreCase("blocking")) { + if ("blocking".equalsIgnoreCase(connectorType)) { return ConnectorType.BLOCKING_CHANNEL; - } else if (connectorType.equalsIgnoreCase("legacy")) { + } else if ("legacy".equalsIgnoreCase(connectorType)) { return ConnectorType.SOCKET; - } else if (connectorType.equalsIgnoreCase("nonblocking")) { + } else if ("nonblocking".equalsIgnoreCase(connectorType)) { return ConnectorType.SELECT_CHANNEL; } else { throw new IllegalStateException("Invalid connector type: " + connectorType); @@ -241,7 +241,7 @@ public Size getResponseHeaderBufferSize() { return Size.parse(responseHeaderBufferSize); } - public boolean enableReuseAddress() { + public boolean isReuseAddressEnabled() { return reuseAddress; } @@ -276,11 +276,11 @@ public Optional getBindHost() { return Optional.fromNullable(bindHost); } - public boolean enableDateHeader() { + public boolean isDateHeaderEnabled() { return useDateHeader; } - public boolean enableServerHeader() { + public boolean isServerHeaderEnabled() { return useServerHeader; } } diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java b/dropwizard/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java index 250dbade845..5370bdf1182 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java @@ -30,6 +30,7 @@ public Level getThreshold() { } } + @SuppressWarnings("CanBeFinal") public static class FileConfiguration { private boolean enabled = false; @@ -122,11 +123,11 @@ public Level getLevel() { } public ImmutableMap getLoggers() { - final ImmutableMap.Builder loggers = ImmutableMap.builder(); - for (Map.Entry entry : this.loggers.entrySet()) { - loggers.put(entry.getKey(), Level.toLevel(entry.getValue())); + final ImmutableMap.Builder builder = ImmutableMap.builder(); + for (Map.Entry entry : loggers.entrySet()) { + builder.put(entry.getKey(), Level.toLevel(entry.getValue())); } - return loggers.build(); + return builder.build(); } public ConsoleConfiguration getConsoleConfiguration() { diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index 381104e932e..4519071e9c1 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -2,7 +2,7 @@ import com.google.common.base.Optional; import com.google.common.collect.ImmutableSet; -import com.yammer.dropwizard.jetty.GzipHandler; +import com.yammer.dropwizard.jetty.BiDiGzipHandler; import com.yammer.dropwizard.jetty.QuietErrorHandler; import com.yammer.dropwizard.tasks.TaskServlet; import com.yammer.dropwizard.util.Duration; @@ -53,7 +53,7 @@ public Server buildServer(Environment env) throws ConfigurationException { } if (env.getHealthChecks().isEmpty()) { - LOGGER.warn("\n" + + LOGGER.warn('\n' + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + "! THIS SERVICE HAS NO HEALTHCHECKS. THIS MEANS YOU WILL NEVER KNOW IF IT !\n" + @@ -72,7 +72,7 @@ public Server buildServer(Environment env) throws ConfigurationException { return server; } - private Server createServer() throws ConfigurationException { + private Server createServer() { final Server server = new Server(); server.addConnector(createExternalConnector()); @@ -80,8 +80,8 @@ private Server createServer() throws ConfigurationException { server.addBean(new QuietErrorHandler()); - server.setSendDateHeader(config.enableDateHeader()); - server.setSendServerVersion(config.enableServerHeader()); + server.setSendDateHeader(config.isDateHeaderEnabled()); + server.setSendServerVersion(config.isServerHeaderEnabled()); server.setThreadPool(createThreadPool()); @@ -92,7 +92,7 @@ private Server createServer() throws ConfigurationException { return server; } - private Connector createExternalConnector() throws ConfigurationException { + private Connector createExternalConnector() { final AbstractConnector connector = createConnector(); connector.setHost(config.getBindHost().orNull()); @@ -120,7 +120,7 @@ private Connector createExternalConnector() throws ConfigurationException { connector.setResponseHeaderSize((int) config.getResponseHeaderBufferSize().toBytes()); - connector.setReuseAddress(config.enableReuseAddress()); + connector.setReuseAddress(config.isReuseAddressEnabled()); final Optional lingerTime = config.getSoLingerTime(); @@ -134,7 +134,7 @@ private Connector createExternalConnector() throws ConfigurationException { return connector; } - private AbstractConnector createConnector() throws ConfigurationException { + private AbstractConnector createConnector() { final AbstractConnector connector; switch (config.getConnectorType()) { case BLOCKING_CHANNEL: @@ -148,7 +148,7 @@ private AbstractConnector createConnector() throws ConfigurationException { ((SelectChannelConnector) connector).setLowResourcesConnections(config.getLowResourcesConnectionThreshold()); break; default: - throw new IllegalStateException(); + throw new IllegalStateException("Invalid connector type: " + config.getConnectorType()); } if (connector instanceof AbstractNIOConnector) { @@ -172,7 +172,7 @@ private Handler createHandler(Environment env) { return collection; } - private Handler createInternalServlet(Environment env) { + private static Handler createInternalServlet(Environment env) { final ServletContextHandler handler = new ServletContextHandler(); handler.addServlet(new ServletHolder(new TaskServlet(env.getTasks())), "/tasks/*"); handler.addServlet(new ServletHolder(new MetricsServlet()), "/*"); @@ -201,7 +201,7 @@ private Handler wrapHandler(ServletContextHandler handler) { final InstrumentedHandler instrumented = new InstrumentedHandler(handler); final GzipConfiguration gzip = config.getGzipConfiguration(); if (gzip.isEnabled()) { - final GzipHandler gzipHandler = new GzipHandler(instrumented); + final BiDiGzipHandler gzipHandler = new BiDiGzipHandler(instrumented); final Optional minEntitySize = gzip.getMinimumEntitySize(); if (minEntitySize.isPresent()) { diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/GzipHandler.java b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java similarity index 83% rename from dropwizard/src/main/java/com/yammer/dropwizard/jetty/GzipHandler.java rename to dropwizard/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java index 6bd2eae86b1..aaa4b8b6d22 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/GzipHandler.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java @@ -3,6 +3,7 @@ import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.GzipHandler; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; @@ -14,10 +15,11 @@ import java.io.InputStreamReader; import java.util.zip.GZIPInputStream; -// TODO: 10/12/11 -- write tests for GzipHandler -// TODO: 10/12/11 -- write docs for GzipHandler +// TODO: 10/12/11 -- write tests for BiDiGzipHandler +// TODO: 10/12/11 -- write docs for BiDiGzipHandler -public class GzipHandler extends org.eclipse.jetty.server.handler.GzipHandler { +@SuppressWarnings("IOResourceOpenedButNotSafelyClosed") +public class BiDiGzipHandler extends GzipHandler { private static final String GZIP_ENCODING = "gzip"; private static class GzipServletInputStream extends ServletInputStream { @@ -33,8 +35,8 @@ public void close() throws IOException { } @Override - public int read(byte[] buf, int off, int len) throws IOException { - return input.read(buf, off, len); + public int read(byte[] b, int off, int len) throws IOException { + return input.read(b, off, len); } @Override @@ -43,8 +45,8 @@ public int available() throws IOException { } @Override - public void mark(int limit) { - input.mark(limit); + public void mark(int readlimit) { + input.mark(readlimit); } @Override @@ -94,7 +96,7 @@ public BufferedReader getReader() throws IOException { } } - public GzipHandler(Handler underlying) { + public BiDiGzipHandler(Handler underlying) { setHandler(underlying); } @@ -106,7 +108,7 @@ public void handle(String target, if (GZIP_ENCODING.equalsIgnoreCase(request.getHeader(HttpHeaders.CONTENT_ENCODING))) { super.handle(target, baseRequest, - new GzipServletRequest(request, super.getBufferSize()), + new GzipServletRequest(request, getBufferSize()), response); } else { super.handle(target, baseRequest, request, response); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java index 5d9463ef78b..b647ec5b2a1 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java @@ -9,7 +9,6 @@ /** * Adds a no-cache header to all responses. */ -@SuppressWarnings("UnusedDeclaration") public class CacheBustingFilter implements Filter { private static final String CACHE_SETTINGS = "must-revalidate,no-cache,no-store"; diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java index b96e042e3dc..0d79302894d 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java @@ -13,13 +13,14 @@ import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.*; public class ConfigurationFactoryTest { + @SuppressWarnings("UnusedDeclaration") public static class Example { @NotNull @Pattern(regexp = "[\\w]+[\\s]+[\\w]+") - @SuppressWarnings("UnusedDeclaration") private String name; public String getName() { @@ -27,11 +28,11 @@ public String getName() { } } - final Validator validator = new Validator(); - final ConfigurationFactory factory = ConfigurationFactory.forClass(Example.class, validator); - final File malformedFile = new File(Resources.getResource("factory-test-malformed.yml").getFile()); - final File invalidFile = new File(Resources.getResource("factory-test-invalid.yml").getFile()); - final File validFile = new File(Resources.getResource("factory-test-valid.yml").getFile()); + private final Validator validator = new Validator(); + private final ConfigurationFactory factory = ConfigurationFactory.forClass(Example.class, validator); + private final File malformedFile = new File(Resources.getResource("factory-test-malformed.yml").getFile()); + private final File invalidFile = new File(Resources.getResource("factory-test-invalid.yml").getFile()); + private final File validFile = new File(Resources.getResource("factory-test-valid.yml").getFile()); @Test public void loadsValidConfigFiles() throws Exception { @@ -46,7 +47,7 @@ public void throwsAnExceptionOnMalformedFiles() throws Exception { factory.build(malformedFile); fail("expected a YAMLException to be thrown, but none was"); } catch (YAMLException e) { - assertTrue(true); + assertThat(e.getMessage(), startsWith("null")); } } diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java index ef49a780447..44608fcbce6 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java @@ -18,7 +18,7 @@ import static org.junit.Assert.assertThat; public class LoggingConfigurationTest { - private ConfigurationFactory factory = + private final ConfigurationFactory factory = ConfigurationFactory.forClass(LoggingConfiguration.class, new Validator()); private LoggingConfiguration config; diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ValidatorTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ValidatorTest.java index ffa32ca4839..7b1ec51766a 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ValidatorTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ValidatorTest.java @@ -11,7 +11,6 @@ import static org.junit.Assert.assertThat; public class ValidatorTest { - @SuppressWarnings("UnusedDeclaration") public static class Example { @NotNull private String notNull = null; From 06d517400ecfff4e29ed1360a79ac11095d739f9 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 14 Nov 2011 19:20:49 -0800 Subject: [PATCH 0005/2771] Fix BooleanParamTest. --- .../yammer/dropwizard/jersey/params/tests/BooleanParamTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/BooleanParamTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/BooleanParamTest.java index 5b11cd0e5cb..6e84a8212e1 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/BooleanParamTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/BooleanParamTest.java @@ -56,7 +56,7 @@ public void nullThrowsAnException() throws Exception { is(400)); assertThat((String) response.getEntity(), - is("\"null\" must be \"true\" or \"false\"")); + is("\"null\" must be \"true\" or \"false\".")); } } From 7541b713e6d9fc7db5ed2b4511937d419e8569bf Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 14 Nov 2011 20:48:52 -0800 Subject: [PATCH 0006/2771] Added tests and docs for NonblockingServletHolder. --- .../jetty/NonblockingServletHolder.java | 18 +++---- .../tests/NonblockingServletHolderTest.java | 49 +++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 dropwizard/src/test/java/com/yammer/dropwizard/jetty/tests/NonblockingServletHolderTest.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java index 53c1e2b1b05..54eb6ebebe1 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java @@ -6,9 +6,10 @@ import javax.servlet.*; import java.io.IOException; -// TODO: 10/12/11 -- write tests for NonblockingServletHolder -// TODO: 10/12/11 -- write docs for NonblockingServletHolder - +/** + * A {@link ServletHolder} subclass which removes the synchronization around servlet initialization + * by requiring a pre-initialized servlet holder. + */ public class NonblockingServletHolder extends ServletHolder { private final Servlet servlet; @@ -29,12 +30,11 @@ public void handle(Request baseRequest, final boolean asyncSupported = baseRequest.isAsyncSupported(); if (!isAsyncSupported()) { baseRequest.setAsyncSupported(false); - } else { - try { - servlet.service(request, response); - } finally { - baseRequest.setAsyncSupported(asyncSupported); - } + } + try { + servlet.service(request, response); + } finally { + baseRequest.setAsyncSupported(asyncSupported); } } } diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/jetty/tests/NonblockingServletHolderTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/jetty/tests/NonblockingServletHolderTest.java new file mode 100644 index 00000000000..f123ac8f8aa --- /dev/null +++ b/dropwizard/src/test/java/com/yammer/dropwizard/jetty/tests/NonblockingServletHolderTest.java @@ -0,0 +1,49 @@ +package com.yammer.dropwizard.jetty.tests; + +import com.yammer.dropwizard.jetty.NonblockingServletHolder; +import org.eclipse.jetty.server.Request; +import org.junit.Test; +import org.mockito.InOrder; + +import javax.servlet.Servlet; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class NonblockingServletHolderTest { + private final Servlet servlet = mock(Servlet.class); + private final NonblockingServletHolder holder = new NonblockingServletHolder(servlet); + private final Request baseRequest = mock(Request.class); + private final ServletRequest request = mock(ServletRequest.class); + private final ServletResponse response = mock(ServletResponse.class); + + @Test + public void hasAServlet() throws Exception { + assertThat(holder.getServlet(), + is(servlet)); + } + + @Test + public void servicesRequests() throws Exception { + holder.handle(baseRequest, request, response); + + verify(servlet).service(request, response); + } + + @Test + public void temporarilyDisablesAsyncRequestsIfDisabled() throws Exception { + holder.setAsyncSupported(false); + + holder.handle(baseRequest, request, response); + + final InOrder inOrder = inOrder(baseRequest, servlet); + + inOrder.verify(baseRequest).setAsyncSupported(false); + inOrder.verify(servlet).service(request, response); + } +} From 0825abeaf2e8b03e0a6bf4144bf3cb004173b125 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 14 Nov 2011 20:52:14 -0800 Subject: [PATCH 0007/2771] Added docs for BiDiGzipHandler. --- .../com/yammer/dropwizard/jetty/BiDiGzipHandler.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java index aaa4b8b6d22..4dda0a1768c 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java @@ -16,8 +16,12 @@ import java.util.zip.GZIPInputStream; // TODO: 10/12/11 -- write tests for BiDiGzipHandler -// TODO: 10/12/11 -- write docs for BiDiGzipHandler +/** + * A Jetty {@link Handler} which both compresses response entities to requests with {@code gzip} as + * an acceptable content-encoding and decompresses request entities with {@code gzip} as the given + * content-encoding. + */ @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") public class BiDiGzipHandler extends GzipHandler { private static final String GZIP_ENCODING = "gzip"; @@ -96,6 +100,11 @@ public BufferedReader getReader() throws IOException { } } + /** + * Creates a new {@link BiDiGzipHandler} which forwards requests to the given handler. + * + * @param underlying the underlying handler + */ public BiDiGzipHandler(Handler underlying) { setHandler(underlying); } From 79a7382a4a5a2d9472573f605bff9e6a8d041a5a Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 14 Nov 2011 22:17:16 -0800 Subject: [PATCH 0008/2771] Cleaned up QuietErrorHandler a bit and admitted defeat about trying to test it. --- .../dropwizard/jetty/QuietErrorHandler.java | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java index eb4d2fdd3f5..affe5c426d0 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java @@ -1,5 +1,6 @@ package com.yammer.dropwizard.jetty; +import com.google.common.collect.ImmutableSet; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.http.HttpMethods; @@ -16,35 +17,50 @@ import static javax.servlet.http.HttpServletResponse.*; -// TODO: 10/12/11 -- write tests for QuietErrorHandler -// TODO: 10/12/11 -- write docs for QuietErrorHandler - +/** + * An {@link ErrorHandler} subclass which returns concise, {@code text/plain} error messages. + */ public class QuietErrorHandler extends ErrorHandler { + /* + * Sadly, this class is basically untestable. + */ + private static final ImmutableSet ALLOWED_METHODS = ImmutableSet.of( + HttpMethods.GET, HttpMethods.HEAD, HttpMethods.POST, HttpMethods.PUT, HttpMethods.DELETE + ); + @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { + public void handle(String target, + Request baseRequest, + HttpServletRequest request, + HttpServletResponse response) throws IOException { final HttpConnection connection = HttpConnection.getCurrentConnection(); final Response jettyResponse = connection.getResponse(); jettyResponse.setStatus(jettyResponse.getStatus()); connection.getRequest().setHandled(true); final String method = request.getMethod(); - if (!method.equals(HttpMethods.GET) && !method.equals(HttpMethods.POST) && !method.equals( - HttpMethods.HEAD)) { + + if (!ALLOWED_METHODS.contains(method)) { return; } + response.setContentType(MimeTypes.TEXT_HTML_8859_1); if (getCacheControl() != null) { - response.setHeader(HttpHeaders.CACHE_CONTROL, this.getCacheControl()); + response.setHeader(HttpHeaders.CACHE_CONTROL, getCacheControl()); } final ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(4096); - writer.append(errorMessage(request, jettyResponse.getStatus())).append("\n\n"); - writer.flush(); - response.setContentLength(writer.size()); - writer.writeTo(response.getOutputStream()); - writer.destroy(); + try { + writer.append(errorMessage(request, jettyResponse.getStatus())).append("\n\n"); + writer.flush(); + response.setContentLength(writer.size()); + writer.writeTo(response.getOutputStream()); + } finally { + writer.close(); + writer.destroy(); + } } - private String errorMessage(HttpServletRequest request, int status) { + private static String errorMessage(HttpServletRequest request, int status) { switch (status) { case SC_BAD_REQUEST: return "Your HTTP client sent a request that this server could " + @@ -107,8 +123,8 @@ private String errorMessage(HttpServletRequest request, int status) { case SC_UNSUPPORTED_MEDIA_TYPE: return "The server does not support the media type transmitted in the request."; default: - return "Your request could not be processed: " + HttpGenerator.getReasonBuffer( - status); + return "Your request could not be processed: " + + HttpGenerator.getReasonBuffer(status); } } } From 0e52a7681567ece956bfe8b97ddbf22e92a19794 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 15 Nov 2011 12:01:11 -0800 Subject: [PATCH 0009/2771] Make sure dropwizard-example has my repo. --- dropwizard-example/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 808083f0a9f..99f21c35a30 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -8,6 +8,13 @@ dropwizard-example 0.1.0-SNAPSHOT + + + repo.codahale.com + http://repo.codahale.com/ + + + com.yammer From 9eb7f551c149d7ec361cf8a02cb35ddc4b67b5ab Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 15 Nov 2011 18:12:09 -0800 Subject: [PATCH 0010/2771] Extract HTTP error messages into a resource bundle. --- .../dropwizard/jetty/QuietErrorHandler.java | 104 +++++------------- .../resources/HttpErrorMessages.properties | 67 +++++++++++ 2 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 dropwizard/src/main/resources/HttpErrorMessages.properties diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java index affe5c426d0..f13eaf19fa1 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java @@ -1,5 +1,6 @@ package com.yammer.dropwizard.jetty; +import com.google.common.base.Charsets; import com.google.common.collect.ImmutableSet; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeaders; @@ -9,18 +10,23 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.handler.ErrorHandler; -import org.eclipse.jetty.util.ByteArrayISO8859Writer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; - -import static javax.servlet.http.HttpServletResponse.*; +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; /** * An {@link ErrorHandler} subclass which returns concise, {@code text/plain} error messages. */ public class QuietErrorHandler extends ErrorHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(QuietErrorHandler.class); + /* * Sadly, this class is basically untestable. */ @@ -44,87 +50,35 @@ public void handle(String target, return; } - response.setContentType(MimeTypes.TEXT_HTML_8859_1); + response.setContentType(MimeTypes.TEXT_PLAIN_UTF_8); if (getCacheControl() != null) { response.setHeader(HttpHeaders.CACHE_CONTROL, getCacheControl()); } - final ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(4096); + + final StringBuilder builder = new StringBuilder(4096); + builder.append(errorMessage(request, jettyResponse.getStatus())).append('\n').append('\n'); + final byte[] bytes = builder.toString().getBytes(Charsets.UTF_8); + response.setContentLength(bytes.length); + final ServletOutputStream output = response.getOutputStream(); try { - writer.append(errorMessage(request, jettyResponse.getStatus())).append("\n\n"); - writer.flush(); - response.setContentLength(writer.size()); - writer.writeTo(response.getOutputStream()); + output.write(bytes); } finally { - writer.close(); - writer.destroy(); + output.close(); } } private static String errorMessage(HttpServletRequest request, int status) { - switch (status) { - case SC_BAD_REQUEST: - return "Your HTTP client sent a request that this server could " + - "not understand."; - case SC_CONFLICT: - return "The request could not be completed due to a conflict" + - " with the return current state of the resource."; - case SC_EXPECTATION_FAILED: - return "The server could not meet the expectation given in the " + - "Expect return request header."; - case SC_FORBIDDEN: - return "You don't have permission to access the requested" + - " resource."; - case SC_GONE: - return "The requested resource used to exist but no longer" + - " does."; - case SC_INTERNAL_SERVER_ERROR: - return "The server encountered an internal error and was" + - " unable to complete your request."; - case SC_LENGTH_REQUIRED: - return "A request with the " + request.getMethod() + " method " + - "requires a valid Content-Length header."; - case SC_METHOD_NOT_ALLOWED: - return "The " + request.getMethod() + " method is not allowed" + - "for the requested resource"; - case SC_NOT_ACCEPTABLE: - return "The resource identified by the request is only capable" + - " of generating response entities which have content" + - " characteristics not acceptable according to the" + - " accept headers sent in the request."; - case SC_NOT_FOUND: - return "The requested resource could not be found on this" + - " server."; - case SC_OK: - return ""; - case SC_PRECONDITION_FAILED: - return "The precondition on the request for the resource failed" + - " positive evaluation."; - case SC_REQUEST_ENTITY_TOO_LARGE: - return "The " + request.getMethod() + " method does not allow" + - "the data transmitted, or the data volume exceeds the" + - "capacity limit."; - case SC_REQUEST_TIMEOUT: - return "The server closed the network connection because your HTTP client" + - " didn't finish the request within the specified time."; - case SC_REQUEST_URI_TOO_LONG: - return "The length of the requested URL exceeds the capacity limit for this" + - " server. The request cannot be processed."; - case SC_REQUESTED_RANGE_NOT_SATISFIABLE: - return "The server cannot serve the requested byte range."; - case SC_SERVICE_UNAVAILABLE: - return "The server is temporarily unable to service your request due to" + - " maintenance downtime or capacity problems. Please try again later."; - case SC_UNAUTHORIZED: - return "This server could not verify that you are authorized to access" + - " this resource.\n" + - "You either supplied the wrong credentials (e.g., bad password)," + - " or your HTTP client doesn't understand how to supply the" + - " required credentials."; - case SC_UNSUPPORTED_MEDIA_TYPE: - return "The server does not support the media type transmitted in the request."; - default: - return "Your request could not be processed: " + - HttpGenerator.getReasonBuffer(status); + try { + final ResourceBundle bundle = ResourceBundle.getBundle("HttpErrorMessages", + request.getLocale()); + final String message = bundle.getString(Integer.toString(status)); + if (message != null) { + final MessageFormat format = new MessageFormat(message, request.getLocale()); + return format.format(new Object[]{request.getMethod()}); + } + } catch (MissingResourceException e) { + LOGGER.error("Unable to load HttpErrorMessages.properties", e); } + return "Your request could not be processed: " + HttpGenerator.getReasonBuffer(status); } } diff --git a/dropwizard/src/main/resources/HttpErrorMessages.properties b/dropwizard/src/main/resources/HttpErrorMessages.properties new file mode 100644 index 00000000000..53e463d9138 --- /dev/null +++ b/dropwizard/src/main/resources/HttpErrorMessages.properties @@ -0,0 +1,67 @@ +# HTTP Error Messages +# {0} = request method + +# OK +200= + +# Bad Request +400=Your HTTP client sent a request that this server could not understand. + +# Unauthorized +401=This server could not verify that you are authorized to access this resource.\ + \n\ + You either supplied the wrong credentials (e.g., bad password), or your HTTP client doesn't \ + understand how to supply the required credentials. + +# Forbidden +403=You don't have permission to access the requested resource. + +# Not Found +404=The requested resource could not be found on this server. + +# Method Not Allowed +405=The {0} method is not allowed for the requested resource. + +# Not Acceptable +406=The resource identified by the request is only capable of generating response entities which \ + have content characteristics not acceptable according to the accept headers sent in the request. + +# Request Timeout +408=The server closed the network connection because your HTTP client didn't finish the request \ + within the specified time. + +# Conflict +409=The request could not be completed due to a conflict with the current state of the resource. + +# Gone +410=The requested resource used to exist but no longer does. + +# Length Required +411=A request with the {0} method requires a valid Content-Length header. + +# Precondition Failed +412=The precondition on the request for the resource failed positive evaluation. + +# Request Entity Too Large +413=The {0} method does not allow the data transmitted, or the data volume exceeds the capacity \ + limit. + +# Request URI Too Long +414=The length of the requested URL exceeds the capacity limit for this server. The request cannot \ + be processed. + +# Unsupported Media Type +415=The server does not support the media type transmitted in the request. + +# Requested Range Not Satisfiable +416=The server cannot serve the requested byte range. + +# Expectation Failed +417=The server could not meet the expectation given in the Expect request header. + +# Internal Server Error +500=The server encountered an internal error and was unable to complete your request. + +# Service Unavailable +503=The server is temporarily unable to service your request due to maintenance downtime or \ + capacity problems. Please try again later. From 4d290c3cd4e5e691606d3a517c8a916c85557715 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 15 Nov 2011 18:22:16 -0800 Subject: [PATCH 0011/2771] Make sure dw-scala is using Jackson 1.9.2. --- dropwizard_2.9.1/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dropwizard_2.9.1/pom.xml b/dropwizard_2.9.1/pom.xml index 1029c77e4aa..fe4613a070e 100644 --- a/dropwizard_2.9.1/pom.xml +++ b/dropwizard_2.9.1/pom.xml @@ -60,6 +60,10 @@ org.slf4j slf4j-api + + com.codahale + jerkson_${scala.version} + From cbc224b0cc5e128274366ac171b2f3c9453f3c15 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 00:29:58 -0800 Subject: [PATCH 0012/2771] Added dropwizard-testing. A module soon to be full of all sorts of happy testing helpers. --- dropwizard-testing/pom.xml | 38 +++++++++++ .../dropwizard/testing/FixtureHelpers.java | 39 +++++++++++ .../dropwizard/testing/JsonHelpers.java | 68 +++++++++++++++++++ .../testing/tests/FixtureHelpersTest.java | 15 ++++ .../testing/tests/JsonHelpersTest.java | 43 ++++++++++++ .../dropwizard/testing/tests/Person.java | 53 +++++++++++++++ .../src/test/resources/fixtures/fixture.txt | 1 + .../src/test/resources/fixtures/person.json | 4 ++ dropwizard/pom.xml | 18 +++++ dropwizard_2.9.1/pom.xml | 18 +++++ pom.xml | 22 +----- 11 files changed, 298 insertions(+), 21 deletions(-) create mode 100644 dropwizard-testing/pom.xml create mode 100644 dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/FixtureHelpers.java create mode 100644 dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java create mode 100644 dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/FixtureHelpersTest.java create mode 100644 dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/JsonHelpersTest.java create mode 100644 dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/Person.java create mode 100644 dropwizard-testing/src/test/resources/fixtures/fixture.txt create mode 100644 dropwizard-testing/src/test/resources/fixtures/person.json diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml new file mode 100644 index 00000000000..4fb4d7310fe --- /dev/null +++ b/dropwizard-testing/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + + com.yammer + dropwizard-parent + 0.1.0-SNAPSHOT + + + com.yammer + dropwizard-testing + + + + com.yammer + dropwizard + ${project.version} + + + junit + junit + 4.10 + + + org.mockito + mockito-all + 1.9.0-rc1 + + + org.hamcrest + hamcrest-all + 1.1 + + + diff --git a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/FixtureHelpers.java b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/FixtureHelpers.java new file mode 100644 index 00000000000..e71251716a7 --- /dev/null +++ b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/FixtureHelpers.java @@ -0,0 +1,39 @@ +package com.yammer.dropwizard.testing; + +import com.google.common.base.Charsets; +import com.google.common.io.Resources; + +import java.io.IOException; +import java.nio.charset.Charset; + +/** + * A set of helper method for fixture files. + */ +public class FixtureHelpers { + private FixtureHelpers() { /* singleton */ } + + /** + * Reads the given fixture file from {@code src/test/resources} and returns its contents as a + * UTF-8 string. + * + * @param filename the filename of the fixture file + * @return the contents of {@code src/test/resources/{filename}} + * @throws IOException if {@code filename} doesn't exist or can't be opened + */ + public static String fixture(String filename) throws IOException { + return fixture(filename, Charsets.UTF_8); + } + + /** + * Reads the given fixture file from {@code src/test/resources} and returns its contents as a + * string. + * + * @param filename the filename of the fixture file + * @param charset the character set of {@code filename} + * @return the contents of {@code src/test/resources/{filename}} + * @throws IOException if {@code filename} doesn't exist or can't be opened + */ + private static String fixture(String filename, Charset charset) throws IOException { + return Resources.toString(Resources.getResource(filename), charset).trim(); + } +} diff --git a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java new file mode 100644 index 00000000000..82fb794d10d --- /dev/null +++ b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java @@ -0,0 +1,68 @@ +package com.yammer.dropwizard.testing; + +import com.yammer.dropwizard.json.Json; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.type.TypeReference; + +import java.io.IOException; + +import static com.yammer.dropwizard.testing.FixtureHelpers.fixture; + +/** + * A set of helper methods for testing the serialization and deserialization of classes to and from + * JSON. + *

For example, a test for reading and writing a {@code Person} object as JSON:

+ *

+ * assertThat("writing a person as JSON produces the appropriate JSON object",
+ *            asJson(person),
+ *            is(jsonFixture("fixtures/person.json"));
+ *
+ * assertThat("reading a JSON object as a person produces the appropriate person",
+ *            fromJson(jsonFixture("fixtures/person.json"), Person.class),
+ *            is(person));
+ * 
+ */ +public class JsonHelpers { + private JsonHelpers() { /* singleton */ } + + /** + * Converts the given object into a JSON AST. + * + * @param object an object + * @return {@code object} as a JSON AST node + * @throws IOException if there is an error writing {@code object} as JSON + */ + public static JsonNode asJson(Object object) throws IOException { + return Json.read(Json.write(object), JsonNode.class); + } + + /** + * Converts the given JSON AST into an object of the given type. + * + * @param json a JSON AST + * @param klass the class of the type that {@code json} should be converted to + * @param the type that {@code json} should be converted to + * @return {@code json} as an instance of {@code T} + * @throws IOException if there is an error reading {@code json} as an instance of {@code T} + */ + public static T fromJson(JsonNode json, Class klass) throws IOException { + return Json.read(json, klass); + } + + /** + * Converts the given JSON AST into an object of the given type. + * + * @param json a JSON AST + * @param reference a reference of the type that {@code json} should be converted to + * @param the type that {@code json} should be converted to + * @return {@code json} as an instance of {@code T} + * @throws IOException if there is an error reading {@code json} as an instance of {@code T} + */ + public static T fromJson(JsonNode json, TypeReference reference) throws IOException { + return Json.read(json, reference); + } + + public static JsonNode jsonFixture(String filename) throws IOException { + return Json.read(fixture(filename), JsonNode.class); + } +} diff --git a/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/FixtureHelpersTest.java b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/FixtureHelpersTest.java new file mode 100644 index 00000000000..e084b35f581 --- /dev/null +++ b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/FixtureHelpersTest.java @@ -0,0 +1,15 @@ +package com.yammer.dropwizard.testing.tests; + +import org.junit.Test; + +import static com.yammer.dropwizard.testing.FixtureHelpers.fixture; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +public class FixtureHelpersTest { + @Test + public void readsTheFileAsAString() throws Exception { + assertThat(fixture("fixtures/fixture.txt"), + is("YAY FOR ME")); + } +} diff --git a/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/JsonHelpersTest.java b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/JsonHelpersTest.java new file mode 100644 index 00000000000..3ad015c9457 --- /dev/null +++ b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/JsonHelpersTest.java @@ -0,0 +1,43 @@ +package com.yammer.dropwizard.testing.tests; + +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.JsonNodeFactory; +import org.codehaus.jackson.node.ObjectNode; +import org.codehaus.jackson.type.TypeReference; +import org.junit.Test; + +import static com.yammer.dropwizard.testing.JsonHelpers.asJson; +import static com.yammer.dropwizard.testing.JsonHelpers.fromJson; +import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +public class JsonHelpersTest { + private final JsonNodeFactory factory = JsonNodeFactory.instance; + private final ObjectNode json = factory.objectNode(); + { + json.put("name", "Coda"); + json.put("email", "coda@example.com"); + } + + @Test + public void readsJsonFixturesAsJsonNodes() throws Exception { + assertThat(jsonFixture("fixtures/person.json"), + is((JsonNode) json)); + } + + @Test + public void convertsObjectsIntoJson() throws Exception { + assertThat(asJson(new Person("Coda", "coda@example.com")), + is(jsonFixture("fixtures/person.json"))); + } + + @Test + public void convertsJsonIntoObjects() throws Exception { + assertThat(fromJson(jsonFixture("fixtures/person.json"), Person.class), + is(new Person("Coda", "coda@example.com"))); + + assertThat(fromJson(jsonFixture("fixtures/person.json"), new TypeReference() {}), + is(new Person("Coda", "coda@example.com"))); + } +} diff --git a/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/Person.java b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/Person.java new file mode 100644 index 00000000000..d12d32a4d8b --- /dev/null +++ b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/Person.java @@ -0,0 +1,53 @@ +package com.yammer.dropwizard.testing.tests; + +import com.google.common.base.Objects; + +public class Person { + private String name; + private String email; + + private Person() { /* Jackson deserialization */ } + + public Person(String name, String email) { + this.name = name; + this.email = email; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { return true; } + if ((obj == null) || (getClass() != obj.getClass())) { return false; } + + final Person person = (Person) obj; + return !((email != null) ? !email.equals(person.email) : (person.email != null)) && + !((name != null) ? !name.equals(person.name) : (person.name != null)); + } + + @Override + public int hashCode() { + int result = (name != null) ? name.hashCode() : 0; + result = (31 * result) + ((email != null) ? email.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return Objects.toStringHelper(this).add("name", name).add("email", email).toString(); + } +} diff --git a/dropwizard-testing/src/test/resources/fixtures/fixture.txt b/dropwizard-testing/src/test/resources/fixtures/fixture.txt new file mode 100644 index 00000000000..cc6ef95eb0f --- /dev/null +++ b/dropwizard-testing/src/test/resources/fixtures/fixture.txt @@ -0,0 +1 @@ +YAY FOR ME diff --git a/dropwizard-testing/src/test/resources/fixtures/person.json b/dropwizard-testing/src/test/resources/fixtures/person.json new file mode 100644 index 00000000000..542f91d3dfe --- /dev/null +++ b/dropwizard-testing/src/test/resources/fixtures/person.json @@ -0,0 +1,4 @@ +{ + "name": "Coda", + "email": "coda@example.com" +} diff --git a/dropwizard/pom.xml b/dropwizard/pom.xml index 8b2559eb1ab..e04afac157d 100644 --- a/dropwizard/pom.xml +++ b/dropwizard/pom.xml @@ -117,5 +117,23 @@ snakeyaml 1.9
+ + junit + junit + 4.10 + test + + + org.mockito + mockito-all + 1.9.0-rc1 + test + + + org.hamcrest + hamcrest-all + 1.1 + test +
diff --git a/dropwizard_2.9.1/pom.xml b/dropwizard_2.9.1/pom.xml index fe4613a070e..2214b1d381f 100644 --- a/dropwizard_2.9.1/pom.xml +++ b/dropwizard_2.9.1/pom.xml @@ -91,6 +91,24 @@ metrics-scala_${scala.version} ${metrics.version} + + junit + junit + 4.10 + test + + + org.mockito + mockito-all + 1.9.0-rc1 + test + + + org.hamcrest + hamcrest-all + 1.1 + test + diff --git a/pom.xml b/pom.xml index 09a49f81fb4..c6a06c8433b 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,7 @@ dropwizard dropwizard-example + dropwizard-testing dropwizard_2.9.1 @@ -60,27 +61,6 @@ - - - junit - junit - 4.10 - test - - - org.mockito - mockito-all - 1.9.0-rc1 - test - - - org.hamcrest - hamcrest-all - 1.1 - test - - - sign From ad01545534d4bcf46a6f111b1deebbcb9700cea4 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 07:29:40 -0800 Subject: [PATCH 0013/2771] Added ConfiguredModules. --- .../yammer/dropwizard/AbstractService.java | 25 ++++++++++++------- .../yammer/dropwizard/ConfiguredModule.java | 20 +++++++++++++++ .../yammer/dropwizard/tests/ServiceTest.java | 6 ----- 3 files changed, 36 insertions(+), 15 deletions(-) create mode 100644 dropwizard/src/main/java/com/yammer/dropwizard/ConfiguredModule.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java index 9ccfebc4c66..a2cfa3abfd0 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java @@ -31,6 +31,7 @@ public abstract class AbstractService { private final String name; private final List modules; + private final List> configuredModules; private final SortedMap commands; private String banner = null; @@ -42,6 +43,7 @@ public abstract class AbstractService { protected AbstractService(String name) { this.name = name; this.modules = Lists.newArrayList(); + this.configuredModules = Lists.newArrayList(); this.commands = Maps.newTreeMap(); addCommand(new ServerCommand(getConfigurationClass())); } @@ -66,15 +68,6 @@ public final Class getConfigurationClass() { return (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } - /** - * Returns a list of registered {@link Module} instances. - * - * @return a list of modules - */ - public final ImmutableList getModules() { - return ImmutableList.copyOf(modules); - } - /** * Registers a {@link Module} to be used in initializing the service's {@link Environment}. * @@ -85,6 +78,17 @@ protected final void addModule(Module module) { modules.add(module); } + /** + * Registers a {@link ConfiguredModule} to be used in initializing the service's + * {@link Environment}. + * + * @param module a module + * @see ConfiguredModule + */ + protected final void addModule(ConfiguredModule module) { + configuredModules.add(module); + } + /** * Returns a list of registered {@link Command} instances. * @@ -161,6 +165,9 @@ public final void initializeWithModules(T configuration, Environment environment for (Module module : modules) { module.initialize(environment); } + for (ConfiguredModule module : configuredModules) { + module.initialize(configuration, environment); + } initialize(configuration, environment); } diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/ConfiguredModule.java b/dropwizard/src/main/java/com/yammer/dropwizard/ConfiguredModule.java new file mode 100644 index 00000000000..9eea1d5b3f6 --- /dev/null +++ b/dropwizard/src/main/java/com/yammer/dropwizard/ConfiguredModule.java @@ -0,0 +1,20 @@ +package com.yammer.dropwizard; + +import com.yammer.dropwizard.config.Configuration; +import com.yammer.dropwizard.config.Environment; + +/** + * A reusable module, used to define blocks of service behavior that are conditional on + * configuration parameters. + * + * @param the required configuration class + */ +public interface ConfiguredModule { + /** + * Initializes the environment. + * + * @param configuration the configuration object + * @param environment the service's {@link Environment} + */ + public void initialize(T configuration, Environment environment); +} diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java index 5d8b96a5dbe..8360884e0a0 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java @@ -38,12 +38,6 @@ public void hasAReferenceToItsTypeParameter() throws Exception { is(sameInstance(FakeConfiguration.class))); } - @Test - public void hasModules() throws Exception { - assertThat(service.getModules(), - hasItem(module)); - } - @Test public void mightHaveABanner() throws Exception { assertThat(service.hasBanner(), From 598b45a087fc3ba74ed9ad5413ca13ffdec5df77 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 13:17:24 -0800 Subject: [PATCH 0014/2771] Add dropwizard-client. --- dropwizard-client/pom.xml | 61 +++++++++++++++++++ .../client/HttpClientConfiguration.java | 56 +++++++++++++++++ .../dropwizard/client/HttpClientFactory.java | 48 +++++++++++++++ .../dropwizard/client/JerseyClient.java | 25 ++++++++ .../client/JerseyClientConfiguration.java | 32 ++++++++++ .../client/JerseyClientFactory.java | 41 +++++++++++++ dropwizard/pom.xml | 1 - pom.xml | 2 + 8 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 dropwizard-client/pom.xml create mode 100644 dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientConfiguration.java create mode 100644 dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientFactory.java create mode 100644 dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java create mode 100644 dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java create mode 100644 dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml new file mode 100644 index 00000000000..b7503f8ed73 --- /dev/null +++ b/dropwizard-client/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + + com.yammer + dropwizard-parent + 0.1.0-SNAPSHOT + + + com.yammer + dropwizard-client + + + + com.yammer + dropwizard + ${project.version} + + + com.sun.jersey + jersey-client + ${jersey.version} + + + com.sun.jersey.contribs + jersey-apache-client4 + ${jersey.version} + + + org.apache.httpcomponents + httpclient + 4.1.2 + + + com.yammer.metrics + metrics-httpclient + ${metrics.version} + + + junit + junit + 4.10 + test + + + org.mockito + mockito-all + 1.9.0-rc1 + test + + + org.hamcrest + hamcrest-all + 1.1 + test + + + diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientConfiguration.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientConfiguration.java new file mode 100644 index 00000000000..a313211d79d --- /dev/null +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientConfiguration.java @@ -0,0 +1,56 @@ +package com.yammer.dropwizard.client; + +import com.yammer.dropwizard.util.Duration; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +public class HttpClientConfiguration { + @NotNull + @Pattern(regexp = Duration.VALID_DURATION) + private String timeout = "500ms"; + + @NotNull + @Pattern(regexp = Duration.VALID_DURATION) + private String timeToLive = "1 hour"; + + private boolean cookiesEnabled = false; + + @Max(Integer.MAX_VALUE) + @Min(1) + private int maxConnections = 1024; + + public Duration getTimeout() { + return Duration.parse(timeout); + } + + public Duration getTimeToLive() { + return Duration.parse(timeToLive); + } + + public boolean isCookiesEnabled() { + return cookiesEnabled; + } + + public void setTimeout(Duration duration) { + this.timeout = duration.toString(); + } + + public void setTimeToLive(Duration timeToLive) { + this.timeToLive = timeToLive.toString(); + } + + public void setCookiesEnabled(boolean enabled) { + this.cookiesEnabled = enabled; + } + + public int getMaxConnections() { + return maxConnections; + } + + public void setMaxConnections(int maxConnections) { + this.maxConnections = maxConnections; + } +} diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientFactory.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientFactory.java new file mode 100644 index 00000000000..1445655c72e --- /dev/null +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientFactory.java @@ -0,0 +1,48 @@ +package com.yammer.dropwizard.client; + +import com.yammer.metrics.httpclient.InstrumentedClientConnManager; +import com.yammer.metrics.httpclient.InstrumentedHttpClient; +import org.apache.http.client.HttpClient; +import org.apache.http.client.params.AllClientPNames; +import org.apache.http.client.params.CookiePolicy; +import org.apache.http.impl.conn.SchemeRegistryFactory; +import org.apache.http.params.BasicHttpParams; + +import java.util.concurrent.TimeUnit; + +public class HttpClientFactory { + private final HttpClientConfiguration configuration; + + public HttpClientFactory(HttpClientConfiguration configuration) { + this.configuration = configuration; + } + + public HttpClient build() { + final BasicHttpParams params = new BasicHttpParams(); + + // TODO: 11/16/11 -- figure out the full set of options to support + + if (!configuration.isCookiesEnabled()) { + params.setParameter(AllClientPNames.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES); + } else { + params.setParameter(AllClientPNames.COOKIE_POLICY, CookiePolicy.BEST_MATCH); + } + + final Integer timeout = (int) configuration.getTimeout().toMilliseconds(); + params.setParameter(AllClientPNames.SO_TIMEOUT, timeout); + params.setParameter(AllClientPNames.CONNECTION_TIMEOUT, timeout); + + params.setParameter(AllClientPNames.TCP_NODELAY, Boolean.TRUE); + params.setParameter(AllClientPNames.STALE_CONNECTION_CHECK, Boolean.FALSE); + + final InstrumentedClientConnManager manager = new InstrumentedClientConnManager( + SchemeRegistryFactory.createDefault(), + configuration.getTimeToLive().toMilliseconds(), + TimeUnit.MILLISECONDS + ); + manager.setDefaultMaxPerRoute(configuration.getMaxConnections()); + manager.setMaxTotal(configuration.getMaxConnections()); + + return new InstrumentedHttpClient(manager, params); + } +} diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java new file mode 100644 index 00000000000..3b7e866c351 --- /dev/null +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java @@ -0,0 +1,25 @@ +package com.yammer.dropwizard.client; + +import com.sun.jersey.client.apache4.ApacheHttpClient4; +import com.sun.jersey.client.apache4.ApacheHttpClient4Handler; +import com.yammer.dropwizard.lifecycle.Managed; + +import java.util.concurrent.TimeUnit; + +public class JerseyClient extends ApacheHttpClient4 implements Managed { + public JerseyClient(ApacheHttpClient4Handler handler) { + super(handler); + } + + @Override + public void start() throws Exception { + // already started man + } + + @Override + public void stop() throws Exception { + getExecutorService().shutdown(); + getExecutorService().awaitTermination(1, TimeUnit.MINUTES); + destroy(); + } +} diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java new file mode 100644 index 00000000000..2140374035a --- /dev/null +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java @@ -0,0 +1,32 @@ +package com.yammer.dropwizard.client; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +public class JerseyClientConfiguration extends HttpClientConfiguration { + // TODO: 11/16/11 -- validate minThreads <= maxThreads + + @Max(16 * 1024) + @Min(1) + private int minThreads; + + @Max(16 * 1024) + @Min(1) + private int maxThreads; + + public int getMinThreads() { + return minThreads; + } + + public void setMinThreads(int minThreads) { + this.minThreads = minThreads; + } + + public int getMaxThreads() { + return maxThreads; + } + + public void setMaxThreads(int maxThreads) { + this.maxThreads = maxThreads; + } +} diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java new file mode 100644 index 00000000000..2ced8bfae98 --- /dev/null +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java @@ -0,0 +1,41 @@ +package com.yammer.dropwizard.client; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.sun.jersey.client.apache4.ApacheHttpClient4Handler; +import com.yammer.dropwizard.config.Environment; +import org.apache.http.client.HttpClient; + +import java.util.concurrent.*; + +public class JerseyClientFactory { + private final JerseyClientConfiguration configuration; + private final HttpClientFactory factory; + + public JerseyClientFactory(JerseyClientConfiguration configuration) { + this.configuration = configuration; + this.factory = new HttpClientFactory(configuration); + } + + public JerseyClient build(Environment environment) { + final HttpClient client = factory.build(); + + final ApacheHttpClient4Handler handler = new ApacheHttpClient4Handler(client, null, true); + + final JerseyClient jerseyClient = new JerseyClient(handler); + jerseyClient.setExecutorService(buildThreadPool()); + environment.manage(jerseyClient); + + return jerseyClient; + } + + private ExecutorService buildThreadPool() { + final ThreadFactory threadFactory = new ThreadFactoryBuilder().setDaemon(true) + .setNameFormat("jersey-client-%d") + .build(); + return new ThreadPoolExecutor(configuration.getMinThreads(), + configuration.getMaxThreads(), + 60, TimeUnit.SECONDS, + new SynchronousQueue(), + threadFactory); + } +} diff --git a/dropwizard/pom.xml b/dropwizard/pom.xml index e04afac157d..468723b446f 100644 --- a/dropwizard/pom.xml +++ b/dropwizard/pom.xml @@ -15,7 +15,6 @@ Dropwizard - 1.10 7.5.4.v20111024 1.9.2 1.6.4 diff --git a/pom.xml b/pom.xml index c6a06c8433b..fc325042eaa 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ dropwizard + dropwizard-client dropwizard-example dropwizard-testing dropwizard_2.9.1 @@ -18,6 +19,7 @@ 2.0.0-BETA18-SNAPSHOT + 1.10 From f81b112ffa9791af7b488e622aeac6baa2e134a6 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 14:35:53 -0800 Subject: [PATCH 0015/2771] Added dropwizard-templates. --- dropwizard-templates/pom.xml | 29 +++++++++ .../dropwizard/modules/TemplateModule.java | 62 +++++++++++++++++++ .../dropwizard/freemarker/example/Person.java | 13 ++++ .../freemarker/example/TemplateResource.java | 15 +++++ .../freemarker/example/TemplateService.java | 22 +++++++ .../example/TemplateResource/hello.ftl | 11 ++++ pom.xml | 1 + 7 files changed, 153 insertions(+) create mode 100644 dropwizard-templates/pom.xml create mode 100644 dropwizard-templates/src/main/java/com/yammer/dropwizard/modules/TemplateModule.java create mode 100644 dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/Person.java create mode 100644 dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateResource.java create mode 100644 dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateService.java create mode 100644 dropwizard-templates/src/test/resources/com/yammer/dropwizard/freemarker/example/TemplateResource/hello.ftl diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml new file mode 100644 index 00000000000..67f54270808 --- /dev/null +++ b/dropwizard-templates/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + + com.yammer + dropwizard-parent + 0.1.0-SNAPSHOT + + + com.yammer + dropwizard-templates + + + + com.yammer + dropwizard + ${project.version} + + + com.sun.jersey.contribs + jersey-freemarker + ${jersey.version} + + + + diff --git a/dropwizard-templates/src/main/java/com/yammer/dropwizard/modules/TemplateModule.java b/dropwizard-templates/src/main/java/com/yammer/dropwizard/modules/TemplateModule.java new file mode 100644 index 00000000000..61f23003afd --- /dev/null +++ b/dropwizard-templates/src/main/java/com/yammer/dropwizard/modules/TemplateModule.java @@ -0,0 +1,62 @@ +package com.yammer.dropwizard.modules; + +import com.sun.jersey.freemarker.FreemarkerViewProcessor; +import com.yammer.dropwizard.Module; +import com.yammer.dropwizard.config.Environment; + +/** + * A {@link Module} which enables the rendering of FreeMarker templates by your service. + * + *

A resource method with a template would looks something like this:

+ * + *

+ * \@GET
+ * public Viewable getPerson(\@PathParam("id") String id) {
+ *     final Person person = dao.find(id);
+ *     return new Viewable("index.ftl", person);
+ * }
+ * 
+ * + *

The {@code "index.ftl"} is the path of the template relative to the class name. If this + * class was {@code com.example.service.PersonResource}, Jersey would then look for the file + * {@code src/main/resources/com/example/service/PersonResource/index.ftl}, which might look + * something like this:

+ * + *
{@code
+ * 
+ *     
+ *         

Hello, ${name?html}!

+ * + * + * }
+ * + *

In this template, {@code ${name}} calls {@code Person#getName()}, and the {@code ?html} + * escapes all HTML control characters in the result.

+ * + * @see FreeMarker Manual + */ +public class TemplateModule implements Module { + private final String templatePath; + + /** + * Creates a new {@link TemplateModule} with no specified template path. + */ + public TemplateModule() { + this(null); + } + + /** + * Creates a new {@link TemplateModule} with the specified template path. + * + * @param templatePath the location, in the class path, of the FreeMarker templates + */ + public TemplateModule(String templatePath) { + this.templatePath = templatePath; + } + + @Override + public void initialize(Environment environment) { + environment.setJerseyProperty(FreemarkerViewProcessor.FREEMARKER_TEMPLATES_BASE_PATH, templatePath); + environment.addProvider(FreemarkerViewProcessor.class); + } +} diff --git a/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/Person.java b/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/Person.java new file mode 100644 index 00000000000..0643c8a220f --- /dev/null +++ b/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/Person.java @@ -0,0 +1,13 @@ +package com.yammer.dropwizard.freemarker.example; + +public class Person { + private final String name; + + public Person(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateResource.java b/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateResource.java new file mode 100644 index 00000000000..9af07c1a641 --- /dev/null +++ b/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateResource.java @@ -0,0 +1,15 @@ +package com.yammer.dropwizard.freemarker.example; + +import com.sun.jersey.api.view.Viewable; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +@Path("/hello") +@Produces(MediaType.TEXT_HTML) +public class TemplateResource { + @GET + public Viewable show(@QueryParam("name") @DefaultValue("Stranger") String name) { + return new Viewable("hello.ftl", new Person(name)); + } +} diff --git a/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateService.java b/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateService.java new file mode 100644 index 00000000000..f15e5864d7f --- /dev/null +++ b/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateService.java @@ -0,0 +1,22 @@ +package com.yammer.dropwizard.freemarker.example; + +import com.yammer.dropwizard.Service; +import com.yammer.dropwizard.config.Configuration; +import com.yammer.dropwizard.config.Environment; +import com.yammer.dropwizard.modules.TemplateModule; + +public class TemplateService extends Service { + public static void main(String[] args) throws Exception { + new TemplateService().run(args); + } + + private TemplateService() { + super("template"); + addModule(new TemplateModule()); + } + + @Override + protected void initialize(Configuration configuration, Environment environment) { + environment.addResource(new TemplateResource()); + } +} diff --git a/dropwizard-templates/src/test/resources/com/yammer/dropwizard/freemarker/example/TemplateResource/hello.ftl b/dropwizard-templates/src/test/resources/com/yammer/dropwizard/freemarker/example/TemplateResource/hello.ftl new file mode 100644 index 00000000000..d18821e4d28 --- /dev/null +++ b/dropwizard-templates/src/test/resources/com/yammer/dropwizard/freemarker/example/TemplateResource/hello.ftl @@ -0,0 +1,11 @@ + + + + Hello World! + + +

Hello!

+ +

Hello, ${name?html}!

+ + diff --git a/pom.xml b/pom.xml index fc325042eaa..c3921d7be28 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ dropwizard dropwizard-client dropwizard-example + dropwizard-templates dropwizard-testing dropwizard_2.9.1
From f59e65ad35629c066ee3771891d06453b8b3b2f5 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 16:23:00 -0800 Subject: [PATCH 0016/2771] Refactor BearerToken a bit. --- .../src/main/java/com/yammer/dropwizard/BearerToken.java | 6 +++--- .../com/yammer/dropwizard/jersey/OauthTokenProvider.java | 2 +- .../yammer/dropwizard/providers/OauthTokenProvider.scala | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/BearerToken.java b/dropwizard/src/main/java/com/yammer/dropwizard/BearerToken.java index 070eb45f3ed..bef23a8bef2 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/BearerToken.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/BearerToken.java @@ -3,12 +3,12 @@ import java.lang.annotation.*; /** - * A method parameter of type {@code Option[String]} will be populated with the - * OAuth2 Bearer Token, if one is provided by the client. + * A method parameter of type {@code Optional} will be populated with the OAuth2 Bearer + * Token, if one is provided by the client. */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface BearerToken { - String value() default "Bearer"; + String prefix() default "Bearer"; } diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OauthTokenProvider.java b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OauthTokenProvider.java index 98c33bcbc76..2055a2ce5cb 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OauthTokenProvider.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OauthTokenProvider.java @@ -25,7 +25,7 @@ public Injectable getInjectable(ComponentContext ic, BearerToken a, Parameter c) { if (c.getParameterClass().isAssignableFrom(Optional.class)) { - return new OauthTokenInjectable(a.value() + ' '); + return new OauthTokenInjectable(a.prefix() + ' '); } return null; } diff --git a/dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/providers/OauthTokenProvider.scala b/dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/providers/OauthTokenProvider.scala index 6baac90365f..19bfc8ad005 100644 --- a/dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/providers/OauthTokenProvider.scala +++ b/dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/providers/OauthTokenProvider.scala @@ -13,7 +13,7 @@ import com.yammer.dropwizard.BearerToken class OauthTokenProvider extends InjectableProvider[BearerToken, Parameter] { def getInjectable(ic: ComponentContext, a: BearerToken, c: Parameter) = if (c.getParameterClass.isAssignableFrom(classOf[Option[String]])) { - new OauthTokenInjectable(a.value() + " ") + new OauthTokenInjectable(a.prefix() + " ") } else { null } From cd27ed717d48caf90fb627db68d8a65a190608d9 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 16:37:34 -0800 Subject: [PATCH 0017/2771] Add names to modules. --- dropwizard-client/pom.xml | 1 + dropwizard-example/pom.xml | 1 + dropwizard-templates/pom.xml | 1 + dropwizard-testing/pom.xml | 1 + pom.xml | 1 + 5 files changed, 5 insertions(+) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index b7503f8ed73..ac43b898776 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -12,6 +12,7 @@ com.yammer dropwizard-client + Dropwizard HTTP Client diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 99f21c35a30..4c6c928dec4 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -7,6 +7,7 @@ com.yammer dropwizard-example 0.1.0-SNAPSHOT + Dropwizard Example Application diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 67f54270808..c7fe1aa33a1 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -12,6 +12,7 @@ com.yammer dropwizard-templates + Dropwizard Templates diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 4fb4d7310fe..20f27e7bdfb 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -12,6 +12,7 @@ com.yammer dropwizard-testing + Dropwizard Test Helpers diff --git a/pom.xml b/pom.xml index c3921d7be28..c5bd0dcea3e 100644 --- a/pom.xml +++ b/pom.xml @@ -8,6 +8,7 @@ dropwizard-parent 0.1.0-SNAPSHOT pom + Dropwizard Project dropwizard From 1bc22fbb43e149131b50c382f4d9fb44a8f28c40 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 17:44:34 -0800 Subject: [PATCH 0018/2771] First swing at dropwizard-db. --- dropwizard-db/pom.xml | 58 ++++++ .../com/yammer/dropwizard/db/Database.java | 26 +++ .../dropwizard/db/DatabaseConfiguration.java | 167 ++++++++++++++++++ .../yammer/dropwizard/db/DatabaseFactory.java | 68 +++++++ .../dropwizard/db/tests/DatabaseTest.java | 91 ++++++++++ pom.xml | 1 + 6 files changed, 411 insertions(+) create mode 100644 dropwizard-db/pom.xml create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java create mode 100644 dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml new file mode 100644 index 00000000000..9078f0494f2 --- /dev/null +++ b/dropwizard-db/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + + com.yammer + dropwizard-parent + 0.1.0-SNAPSHOT + + + com.yammer + dropwizard-db + Dropwizard Database Client + + + + com.yammer + dropwizard + ${project.version} + + + org.jdbi + jdbi + 2.27 + + + org.apache.tomcat + tomcat-dbcp + 7.0.22 + + + org.hsqldb + hsqldb + 2.2.4 + test + + + junit + junit + 4.10 + test + + + org.mockito + mockito-all + 1.9.0-rc1 + test + + + org.hamcrest + hamcrest-all + 1.1 + test + + + diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java new file mode 100644 index 00000000000..bf7ea9339d1 --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -0,0 +1,26 @@ +package com.yammer.dropwizard.db; + +import com.yammer.dropwizard.lifecycle.Managed; +import org.apache.tomcat.dbcp.pool.ObjectPool; +import org.skife.jdbi.v2.DBI; + +import javax.sql.DataSource; + +public class Database extends DBI implements Managed { + private final ObjectPool pool; + + public Database(DataSource dataSource, ObjectPool pool) { + super(dataSource); + this.pool = pool; + } + + @Override + public void start() throws Exception { + // already started, man + } + + @Override + public void stop() throws Exception { + pool.close(); + } +} diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java new file mode 100644 index 00000000000..3916d08e9c3 --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java @@ -0,0 +1,167 @@ +package com.yammer.dropwizard.db; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.yammer.dropwizard.util.Duration; +import org.hibernate.validator.constraints.URL; + +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import java.util.Map; + +@SuppressWarnings("FieldMayBeFinal") +public class DatabaseConfiguration { + public static class DatabaseConnectionConfiguration { + @NotNull + private String driverClass = null; + + @NotNull + private String user = null; + + private String password = ""; + + @NotNull + @URL(protocol = "jdbc") + private String url = null; + + @NotNull + private Map properties = Maps.newHashMap(); + + @NotNull + @Pattern(regexp = Duration.VALID_DURATION) + private String maxWaitForConnection = "8ms"; + + @NotNull + private String validationQuery = "/* Health Check */ SELECT 1"; + + // TODO: 11/16/11 -- validate minSize <= maxSize + + @Max(1024) + @Min(1) + private int minSize = 1; + + @Max(1024) + @Min(1) + private int maxSize = 1; + + private boolean checkConnectionWhileIdle; + + @NotNull + @Pattern(regexp = Duration.VALID_DURATION) + private String checkConnectionHealthWhenIdleFor = "10s"; + + @NotNull + @Pattern(regexp = Duration.VALID_DURATION) + private String closeConnectionIfIdleFor = "10m"; + + public String getDriverClass() { + return driverClass; + } + + public void setDriverClass(String driverClass) { + this.driverClass = driverClass; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = ImmutableMap.copyOf(properties); + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Duration getMaxWaitForConnection() { + return Duration.parse(maxWaitForConnection); + } + + public void setMaxWaitForConnection(Duration maxWait) { + this.maxWaitForConnection = maxWait.toString(); + } + + public String getValidationQuery() { + return validationQuery; + } + + public void setValidationQuery(String validationQuery) { + this.validationQuery = validationQuery; + } + + public int getMinSize() { + return minSize; + } + + public void setMinSize(int minSize) { + this.minSize = minSize; + } + + public int getMaxSize() { + return maxSize; + } + + public void setMaxSize(int maxSize) { + this.maxSize = maxSize; + } + + public boolean checkConnectionWhileIdle() { + return checkConnectionWhileIdle; + } + + public void setCheckConnectionWhileIdle(boolean checkConnectionWhileIdle) { + this.checkConnectionWhileIdle = checkConnectionWhileIdle; + } + + public Duration getCheckConnectionHealthWhenIdleFor() { + return Duration.parse(checkConnectionHealthWhenIdleFor); + } + + public void setCheckConnectionHealthWhenIdleFor(Duration timeout) { + this.checkConnectionHealthWhenIdleFor = timeout.toString(); + } + + public Duration getCloseConnectionIfIdleFor() { + return Duration.parse(closeConnectionIfIdleFor); + } + + public void setCloseConnectionIfIdleFor(Duration timeout) { + this.closeConnectionIfIdleFor = timeout.toString(); + } + } + + @Valid + private Map connections = Maps.newHashMap(); + + public DatabaseConnectionConfiguration getConnection(String name) { + return connections.get(name); + } + + public void addConnection(String name, DatabaseConnectionConfiguration config) { + connections.put(name, config); + } +} diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java new file mode 100644 index 00000000000..18b2f4279ba --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java @@ -0,0 +1,68 @@ +package com.yammer.dropwizard.db; + +import com.yammer.dropwizard.config.Environment; +import org.apache.tomcat.dbcp.dbcp.DriverManagerConnectionFactory; +import org.apache.tomcat.dbcp.dbcp.PoolableConnectionFactory; +import org.apache.tomcat.dbcp.dbcp.PoolingDataSource; +import org.apache.tomcat.dbcp.pool.impl.GenericObjectPool; + +import javax.sql.DataSource; +import java.util.Map; +import java.util.Properties; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.yammer.dropwizard.db.DatabaseConfiguration.DatabaseConnectionConfiguration; + +public class DatabaseFactory { + private final DatabaseConfiguration config; + + public DatabaseFactory(DatabaseConfiguration config) { + this.config = config; + } + + public Database build(String name, Environment environment) throws ClassNotFoundException { + final DatabaseConnectionConfiguration connectionConfig = config.getConnection(name); + Class.forName(connectionConfig.getDriverClass()); + checkNotNull(connectionConfig, "%s is not the name of a configured connection.", name); + final GenericObjectPool pool = buildPool(connectionConfig); + final DataSource dataSource = buildDataSource(connectionConfig, pool); + final Database database = new Database(dataSource, pool); + environment.manage(database); + return database; + } + + private DataSource buildDataSource(DatabaseConnectionConfiguration connectionConfig, GenericObjectPool pool) { + final Properties properties = new Properties(); + for (Map.Entry property : connectionConfig.getProperties().entrySet()) { + properties.setProperty(property.getKey(), property.getValue()); + } + properties.setProperty("user", connectionConfig.getUser()); + properties.setProperty("password", connectionConfig.getPassword()); + + final DriverManagerConnectionFactory factory = new DriverManagerConnectionFactory(connectionConfig.getUrl(), + properties); + + + final PoolableConnectionFactory connectionFactory = new PoolableConnectionFactory(factory, + pool, + null, + connectionConfig.getValidationQuery(), + false, + true); + connectionFactory.setPool(pool); + + return new PoolingDataSource(pool); + } + + private GenericObjectPool buildPool(DatabaseConnectionConfiguration connectionConfig) { + final GenericObjectPool pool = new GenericObjectPool(null); + pool.setMaxWait(connectionConfig.getMaxWaitForConnection().toMilliseconds()); + pool.setMinIdle(connectionConfig.getMinSize()); + pool.setMaxActive(connectionConfig.getMaxSize()); + pool.setMaxIdle(connectionConfig.getMaxSize()); + pool.setTestWhileIdle(connectionConfig.checkConnectionWhileIdle()); + pool.setTimeBetweenEvictionRunsMillis(connectionConfig.getCheckConnectionHealthWhenIdleFor().toMilliseconds()); + pool.setMinEvictableIdleTimeMillis(connectionConfig.getCloseConnectionIfIdleFor().toMilliseconds()); + return pool; + } +} diff --git a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java new file mode 100644 index 00000000000..9a84f6df8e8 --- /dev/null +++ b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java @@ -0,0 +1,91 @@ +package com.yammer.dropwizard.db.tests; + +import com.google.common.collect.ImmutableList; +import com.yammer.dropwizard.config.Environment; +import com.yammer.dropwizard.db.Database; +import com.yammer.dropwizard.db.DatabaseConfiguration; +import com.yammer.dropwizard.db.DatabaseFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.skife.jdbi.v2.Handle; +import org.skife.jdbi.v2.Query; +import org.skife.jdbi.v2.util.StringMapper; + +import java.sql.Types; + +import static com.yammer.dropwizard.db.DatabaseConfiguration.DatabaseConnectionConfiguration; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class DatabaseTest { + private DatabaseConfiguration config = new DatabaseConfiguration(); + private DatabaseConnectionConfiguration hsqlConfig = new DatabaseConnectionConfiguration(); + { + hsqlConfig.setUrl("jdbc:hsqldb:mem:DbTest-"+System.currentTimeMillis()); + hsqlConfig.setUser("sa"); + hsqlConfig.setDriverClass("org.hsqldb.jdbcDriver"); + config.addConnection("hsql", hsqlConfig); + } + private final DatabaseFactory factory = new DatabaseFactory(config); + private final Environment environment = mock(Environment.class); + private Database database; + + @Before + public void setUp() throws Exception { + this.database = factory.build("hsql", environment); + final Handle handle = database.open(); + try { + handle.createCall("DROP TABLE people IF EXISTS").invoke(); + handle.createCall( + "CREATE TABLE people (name varchar(100) primary key, email varchar(100), age int)") + .invoke(); + handle.createStatement("INSERT INTO people VALUES (?, ?, ?)") + .bind(0, "Coda Hale") + .bind(1, "chale@yammer-inc.com") + .bind(2, 30) + .execute(); + handle.createStatement("INSERT INTO people VALUES (?, ?, ?)") + .bind(0, "Kris Gale") + .bind(1, "kgale@yammer-inc.com") + .bind(2, 32) + .execute(); + handle.createStatement("INSERT INTO people VALUES (?, ?, ?)") + .bind(0, "Old Guy") + .bindNull(1, Types.VARCHAR) + .bind(2, 99) + .execute(); + } finally { + handle.close(); + } + } + + @After + public void tearDown() throws Exception { + database.stop(); + this.database = null; + } + + @Test + public void createsAValidDBI() throws Exception { + final Handle handle = database.open(); + try { + final Query names = handle.createQuery("SELECT name FROM people WHERE age < ?") + .bind(0, 50) + .map(StringMapper.FIRST); + assertThat(ImmutableList.copyOf(names), + is(ImmutableList.of("Coda Hale", "Kris Gale"))); + } finally { + handle.close(); + } + } + + @Test + public void managesTheDatabaseWithTheEnvironment() throws Exception { + final Database db = factory.build("hsql", environment); + + verify(environment).manage(db); + } +} diff --git a/pom.xml b/pom.xml index c5bd0dcea3e..e0231ad74b7 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ dropwizard dropwizard-client + dropwizard-db dropwizard-example dropwizard-templates dropwizard-testing From 77e1f4021a9fd355ca18e860733b780a0389e035 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 20:41:35 -0800 Subject: [PATCH 0019/2771] Allow service initialization to throw an exception. --- .../src/main/java/com/yammer/dropwizard/AbstractService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java index a2cfa3abfd0..3d9688bd6b5 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java @@ -151,7 +151,7 @@ protected final void setBanner(String banner) { * @param configuration the parsed {@link Configuration} object * @param environment the service's {@link Environment} */ - protected abstract void initialize(T configuration, Environment environment); + protected abstract void initialize(T configuration, Environment environment) throws Exception; /** * Initializes the given {@link Environment} given a {@link Configuration} instances. First the @@ -161,7 +161,7 @@ protected final void setBanner(String banner) { * @param configuration the parsed {@link Configuration} object * @param environment the service's {@link Environment} */ - public final void initializeWithModules(T configuration, Environment environment) { + public final void initializeWithModules(T configuration, Environment environment) throws Exception { for (Module module : modules) { module.initialize(environment); } From f684c1d471fe388e56347f039ae184db26557ac6 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 21:54:48 -0800 Subject: [PATCH 0020/2771] Ease the validations on DatabaseConfiguration#url. --- .../java/com/yammer/dropwizard/db/DatabaseConfiguration.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java index 3916d08e9c3..93ae47c9609 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java @@ -24,7 +24,6 @@ public static class DatabaseConnectionConfiguration { private String password = ""; @NotNull - @URL(protocol = "jdbc") private String url = null; @NotNull From dc8eb84aa503b218f9222f2875585fb244d89406 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 16 Nov 2011 22:10:07 -0800 Subject: [PATCH 0021/2771] Added DatabaseHealthCheck and Database#ping(). --- .../com/yammer/dropwizard/db/Database.java | 15 ++++++++++++ .../dropwizard/db/DatabaseHealthCheck.java | 24 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseHealthCheck.java diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index bf7ea9339d1..2fd7761c4b3 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -3,8 +3,11 @@ import com.yammer.dropwizard.lifecycle.Managed; import org.apache.tomcat.dbcp.pool.ObjectPool; import org.skife.jdbi.v2.DBI; +import org.skife.jdbi.v2.Handle; +import org.skife.jdbi.v2.util.IntegerMapper; import javax.sql.DataSource; +import java.sql.SQLException; public class Database extends DBI implements Managed { private final ObjectPool pool; @@ -23,4 +26,16 @@ public void start() throws Exception { public void stop() throws Exception { pool.close(); } + + public void ping() throws SQLException { + final Handle handle = open(); + try { + final Integer first = handle.createQuery("SELECT 1").map(IntegerMapper.FIRST).first(); + if (!Integer.valueOf(1).equals(first)) { + throw new SQLException("Expected 1 from 'SELECT 1', got " + first); + } + } finally { + handle.close(); + } + } } diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseHealthCheck.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseHealthCheck.java new file mode 100644 index 00000000000..c0ab25029d1 --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseHealthCheck.java @@ -0,0 +1,24 @@ +package com.yammer.dropwizard.db; + +import com.yammer.metrics.core.HealthCheck; + +public class DatabaseHealthCheck extends HealthCheck { + private final Database database; + private final String name; + + public DatabaseHealthCheck(Database database, String name) { + this.database = database; + this.name = name; + } + + @Override + public String name() { + return name + "-db"; + } + + @Override + public Result check() throws Exception { + database.ping(); + return Result.healthy(); + } +} From 6888c021dd704e81952a0a43fc4016155e002be5 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 17 Nov 2011 01:25:38 -0800 Subject: [PATCH 0022/2771] Make sure the JerseyClient gets Jackson support. --- .../java/com/yammer/dropwizard/client/JerseyClient.java | 5 +++-- .../com/yammer/dropwizard/client/JerseyClientFactory.java | 8 +++++++- .../dropwizard/jersey/JacksonMessageBodyProvider.java | 8 +++++++- .../java/com/yammer/dropwizard/modules/JavaModule.java | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java index 3b7e866c351..4dea37767ff 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java @@ -1,5 +1,6 @@ package com.yammer.dropwizard.client; +import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.client.apache4.ApacheHttpClient4; import com.sun.jersey.client.apache4.ApacheHttpClient4Handler; import com.yammer.dropwizard.lifecycle.Managed; @@ -7,8 +8,8 @@ import java.util.concurrent.TimeUnit; public class JerseyClient extends ApacheHttpClient4 implements Managed { - public JerseyClient(ApacheHttpClient4Handler handler) { - super(handler); + public JerseyClient(ApacheHttpClient4Handler root, ClientConfig config) { + super(root, config); } @Override diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java index 2ced8bfae98..f510730a2f5 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java @@ -2,7 +2,10 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sun.jersey.client.apache4.ApacheHttpClient4Handler; +import com.sun.jersey.client.apache4.config.ApacheHttpClient4Config; +import com.sun.jersey.client.apache4.config.DefaultApacheHttpClient4Config; import com.yammer.dropwizard.config.Environment; +import com.yammer.dropwizard.jersey.JacksonMessageBodyProvider; import org.apache.http.client.HttpClient; import java.util.concurrent.*; @@ -21,7 +24,10 @@ public JerseyClient build(Environment environment) { final ApacheHttpClient4Handler handler = new ApacheHttpClient4Handler(client, null, true); - final JerseyClient jerseyClient = new JerseyClient(handler); + final ApacheHttpClient4Config config = new DefaultApacheHttpClient4Config(); + config.getSingletons().add(new JacksonMessageBodyProvider(false)); + + final JerseyClient jerseyClient = new JerseyClient(handler, config); jerseyClient.setExecutorService(buildThreadPool()); environment.manage(jerseyClient); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java index 5b597b0c31e..a5cc93d438a 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java @@ -49,6 +49,12 @@ public String getReasonPhrase() { } }; + private final boolean validating; + + public JacksonMessageBodyProvider(boolean validating) { + this.validating = validating; + } + @Override public boolean isReadable(Class type, Type genericType, @@ -65,7 +71,7 @@ public Object readFrom(Class type, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { final Object value = Json.read(entityStream, genericType); - if (value.getClass().isAnnotationPresent(Validated.class)) { + if (validating && value.getClass().isAnnotationPresent(Validated.class)) { final ImmutableList errors = VALIDATOR.validate(value); if (!errors.isEmpty()) { final StringBuilder msg = new StringBuilder("The request entity had the following errors:\n"); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java b/dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java index 9ae4432c33f..dbe71236995 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java @@ -13,7 +13,7 @@ public class JavaModule implements Module { @Override public void initialize(Environment environment) { environment.addProvider(new OptionalQueryParamInjectableProvider()); - environment.addProvider(new JacksonMessageBodyProvider()); + environment.addProvider(new JacksonMessageBodyProvider(true)); environment.addProvider(new OauthTokenProvider()); } } From 377afbe1dfb46dff95289d1ed4455feea762a1b2 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 17 Nov 2011 01:42:49 -0800 Subject: [PATCH 0023/2771] Make sure the JerseryClient thread pools are sized. --- .../yammer/dropwizard/client/JerseyClientConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java index 2140374035a..a040048dac2 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java @@ -8,11 +8,11 @@ public class JerseyClientConfiguration extends HttpClientConfiguration { @Max(16 * 1024) @Min(1) - private int minThreads; + private int minThreads = 1; @Max(16 * 1024) @Min(1) - private int maxThreads; + private int maxThreads = 128; public int getMinThreads() { return minThreads; From 1cceed7aaa5bdcc0b97da003891d9c1a56b48141 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 17 Nov 2011 09:48:38 -0800 Subject: [PATCH 0024/2771] Add gzip support to JerseyClient. --- .../dropwizard/client/JerseyClientConfiguration.java | 10 ++++++++++ .../yammer/dropwizard/client/JerseyClientFactory.java | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java index a040048dac2..716477766aa 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java @@ -14,6 +14,8 @@ public class JerseyClientConfiguration extends HttpClientConfiguration { @Min(1) private int maxThreads = 128; + private boolean gzipEnabled = true; + public int getMinThreads() { return minThreads; } @@ -29,4 +31,12 @@ public int getMaxThreads() { public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } + + public boolean isGzipEnabled() { + return gzipEnabled; + } + + public void setGzipEnabled(boolean enable) { + this.gzipEnabled = enable; + } } diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java index f510730a2f5..3d99de9f55a 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java @@ -1,6 +1,7 @@ package com.yammer.dropwizard.client; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.sun.jersey.api.client.filter.GZIPContentEncodingFilter; import com.sun.jersey.client.apache4.ApacheHttpClient4Handler; import com.sun.jersey.client.apache4.config.ApacheHttpClient4Config; import com.sun.jersey.client.apache4.config.DefaultApacheHttpClient4Config; @@ -31,6 +32,10 @@ public JerseyClient build(Environment environment) { jerseyClient.setExecutorService(buildThreadPool()); environment.manage(jerseyClient); + if (configuration.isGzipEnabled()) { + jerseyClient.addFilter(new GZIPContentEncodingFilter()); + } + return jerseyClient; } From fedd9afd97dcb05406286060b8a8abaa78df2462 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 17 Nov 2011 10:05:09 -0800 Subject: [PATCH 0025/2771] Removed @Validated. Annotate the request entity parameter as @Valid to validate. This is in line with plans for JAX-RS 2.0, and allows for more sensible reuse of representation classes. --- .../dropwizard/client/JerseyClientFactory.java | 2 +- .../java/com/yammer/dropwizard/Validated.java | 17 ----------------- .../jersey/JacksonMessageBodyProvider.java | 15 +++++++-------- .../yammer/dropwizard/modules/JavaModule.java | 2 +- 4 files changed, 9 insertions(+), 27 deletions(-) delete mode 100644 dropwizard/src/main/java/com/yammer/dropwizard/Validated.java diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java index 3d99de9f55a..a26d9545c8e 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java @@ -26,7 +26,7 @@ public JerseyClient build(Environment environment) { final ApacheHttpClient4Handler handler = new ApacheHttpClient4Handler(client, null, true); final ApacheHttpClient4Config config = new DefaultApacheHttpClient4Config(); - config.getSingletons().add(new JacksonMessageBodyProvider(false)); + config.getSingletons().add(new JacksonMessageBodyProvider()); final JerseyClient jerseyClient = new JerseyClient(handler, config); jerseyClient.setExecutorService(buildThreadPool()); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/Validated.java b/dropwizard/src/main/java/com/yammer/dropwizard/Validated.java deleted file mode 100644 index 7f1f54bd132..00000000000 --- a/dropwizard/src/main/java/com/yammer/dropwizard/Validated.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.yammer.dropwizard; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An annotation for classes being parsed by - * {@link com.yammer.dropwizard.jersey.JacksonMessageBodyProvider}. If present, the class will be - * validated using {@link com.yammer.dropwizard.util.Validator}. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Validated { - // TODO: 11/10/11 -- add support for Validated for Scala -} diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java index a5cc93d438a..3c596b21d27 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java @@ -1,12 +1,12 @@ package com.yammer.dropwizard.jersey; import com.google.common.collect.ImmutableList; -import com.yammer.dropwizard.Validated; import com.yammer.dropwizard.json.Json; import com.yammer.dropwizard.util.Validator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.validation.Valid; import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; @@ -49,12 +49,6 @@ public String getReasonPhrase() { } }; - private final boolean validating; - - public JacksonMessageBodyProvider(boolean validating) { - this.validating = validating; - } - @Override public boolean isReadable(Class type, Type genericType, @@ -70,8 +64,13 @@ public Object readFrom(Class type, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { + boolean validating = false; + for (Annotation annotation : annotations) { + validating = validating || (annotation.annotationType() == Valid.class); + } + final Object value = Json.read(entityStream, genericType); - if (validating && value.getClass().isAnnotationPresent(Validated.class)) { + if (validating) { final ImmutableList errors = VALIDATOR.validate(value); if (!errors.isEmpty()) { final StringBuilder msg = new StringBuilder("The request entity had the following errors:\n"); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java b/dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java index dbe71236995..9ae4432c33f 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java @@ -13,7 +13,7 @@ public class JavaModule implements Module { @Override public void initialize(Environment environment) { environment.addProvider(new OptionalQueryParamInjectableProvider()); - environment.addProvider(new JacksonMessageBodyProvider(true)); + environment.addProvider(new JacksonMessageBodyProvider()); environment.addProvider(new OauthTokenProvider()); } } From 5db8f6336f24044ff2ac332c187b9aafb81a9de7 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 18 Nov 2011 01:17:49 -0800 Subject: [PATCH 0026/2771] Added Servlets. --- .../com/yammer/dropwizard/util/Servlets.java | 24 +++++++++++++ .../dropwizard/util/tests/ServletsTest.java | 34 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 dropwizard/src/main/java/com/yammer/dropwizard/util/Servlets.java create mode 100644 dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ServletsTest.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/util/Servlets.java b/dropwizard/src/main/java/com/yammer/dropwizard/util/Servlets.java new file mode 100644 index 00000000000..8a92c0c1ea2 --- /dev/null +++ b/dropwizard/src/main/java/com/yammer/dropwizard/util/Servlets.java @@ -0,0 +1,24 @@ +package com.yammer.dropwizard.util; + +import javax.servlet.http.HttpServletRequest; + +/** + * Utility functions for dealing with servlets. + */ +public class Servlets { + private Servlets() { /* singleton */ } + + /** + * Returns the full URL of the given request. + * + * @param request an HTTP servlet request + * @return the full URL, including the query string + */ + public static String getFullUrl(HttpServletRequest request) { + final StringBuilder url = new StringBuilder(100).append(request.getRequestURI()); + if (request.getQueryString() != null) { + url.append('?').append(request.getQueryString()); + } + return url.toString(); + } +} diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ServletsTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ServletsTest.java new file mode 100644 index 00000000000..74815b206e9 --- /dev/null +++ b/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ServletsTest.java @@ -0,0 +1,34 @@ +package com.yammer.dropwizard.util.tests; + +import com.yammer.dropwizard.util.Servlets; +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ServletsTest { + private final HttpServletRequest request = mock(HttpServletRequest.class); + private final HttpServletRequest fullRequest = mock(HttpServletRequest.class); + + { + when(request.getRequestURI()).thenReturn("/one/two"); + when(fullRequest.getRequestURI()).thenReturn("/one/two"); + when(fullRequest.getQueryString()).thenReturn("one=two&three=four"); + } + + @Test + public void formatsBasicURIs() throws Exception { + assertThat(Servlets.getFullUrl(request), + is("/one/two")); + } + + @Test + public void formatsFullURIs() throws Exception { + assertThat(Servlets.getFullUrl(fullRequest), + is("/one/two?one=two&three=four")); + } +} From 4c4ba8f8aefcddfa10d8d511cd4528e56dfab6c2 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 18 Nov 2011 01:18:16 -0800 Subject: [PATCH 0027/2771] Added SlowRequestFilter and ThreadNameFilter. --- .../servlets/SlowRequestFilter.java | 60 +++++++++++++++++++ .../dropwizard/servlets/ThreadNameFilter.java | 43 +++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 dropwizard/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java create mode 100644 dropwizard/src/main/java/com/yammer/dropwizard/servlets/ThreadNameFilter.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java new file mode 100644 index 00000000000..5fddc156269 --- /dev/null +++ b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java @@ -0,0 +1,60 @@ +package com.yammer.dropwizard.servlets; + +import com.yammer.dropwizard.util.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import static com.yammer.dropwizard.util.Servlets.getFullUrl; +import static java.lang.String.format; + +/** + * A servlet filter which logs the methods and URIs of requests which take longer than a given + * duration of time to complete. + */ +public class SlowRequestFilter implements Filter { + private static final Logger LOGGER = LoggerFactory.getLogger(SlowRequestFilter.class); + private final long threshold; + + /** + * Creates a filter which logs requests which take longer than 1 second. + */ + public SlowRequestFilter() { + this(Duration.seconds(1)); + } + + /** + * Creates a filter which logs requests which take longer than the given duration. + * + * @param threshold the threshold for considering a request slow + */ + public SlowRequestFilter(Duration threshold) { + this.threshold = threshold.toNanoseconds(); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { /* unused */ } + + @Override + public void destroy() { /* unused */ } + + @Override + public void doFilter(ServletRequest request, + ServletResponse response, + FilterChain chain) throws IOException, ServletException { + final HttpServletRequest req = (HttpServletRequest) request; + final long startTime = System.nanoTime(); + try { + chain.doFilter(request, response); + } finally { + final long elapsedMS = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime); + if (elapsedMS >= threshold) { + LOGGER.warn(format("Slow request: %s %s (%dms)", req.getMethod(), getFullUrl(req), elapsedMS)); + } + } + } +} diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/ThreadNameFilter.java b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/ThreadNameFilter.java new file mode 100644 index 00000000000..47c1f83b3d7 --- /dev/null +++ b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/ThreadNameFilter.java @@ -0,0 +1,43 @@ +package com.yammer.dropwizard.servlets; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +import static com.yammer.dropwizard.util.Servlets.getFullUrl; + +/** + * A servlet filter which adds the request method and URI to the thread name processing the request + * for the duration of the request. + */ +public class ThreadNameFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { /* unused */ } + + @Override + public void destroy() { /* unused */ } + + @Override + public void doFilter(ServletRequest request, + ServletResponse response, + FilterChain chain) throws IOException, ServletException { + final HttpServletRequest req = (HttpServletRequest) request; + final Thread current = Thread.currentThread(); + final String oldName = current.getName(); + try { + current.setName(formatName(req, oldName)); + chain.doFilter(request, response); + } finally { + current.setName(oldName); + } + } + + private static String formatName(HttpServletRequest req, String oldName) { + return new StringBuilder(150).append(oldName) + .append(" - ") + .append(req.getMethod()) + .append(' ') + .append(getFullUrl(req)) + .toString(); + } +} From 4ad3843b2ecc2b46fdb98b510a71e9a32f9bed11 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 21 Nov 2011 23:17:52 -0800 Subject: [PATCH 0028/2771] Added AssetsModule. --- .../example/helloworld/HelloWorldService.java | 3 ++ .../src/main/resources/assets/example.txt | 1 + .../dropwizard/config/ServerFactory.java | 2 + .../dropwizard/modules/AssetsModule.java | 46 +++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 dropwizard-example/src/main/resources/assets/example.txt create mode 100644 dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java diff --git a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java index d75bc74be8c..776464f7a84 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java @@ -6,6 +6,7 @@ import com.example.helloworld.resources.HelloWorldResource; import com.yammer.dropwizard.Service; import com.yammer.dropwizard.config.Environment; +import com.yammer.dropwizard.modules.AssetsModule; public class HelloWorldService extends Service { public static void main(String[] args) throws Exception { @@ -15,6 +16,7 @@ public static void main(String[] args) throws Exception { private HelloWorldService() { super("hello-world"); addCommand(new RenderCommand()); + addModule(new AssetsModule()); } @Override @@ -25,4 +27,5 @@ protected void initialize(HelloWorldConfiguration configuration, environment.addHealthCheck(new TemplateHealthCheck(template)); environment.addResource(new HelloWorldResource(template)); } + } diff --git a/dropwizard-example/src/main/resources/assets/example.txt b/dropwizard-example/src/main/resources/assets/example.txt new file mode 100644 index 00000000000..e71db1d01c4 --- /dev/null +++ b/dropwizard-example/src/main/resources/assets/example.txt @@ -0,0 +1 @@ +Hello, I'm an example static asset file. diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index 4519071e9c1..873bf4f3339 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -21,6 +21,7 @@ import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ThreadPool; import org.slf4j.Logger; @@ -183,6 +184,7 @@ private static Handler createInternalServlet(Environment env) { private Handler createExternalServlet(Map servlets, Map filters) { final ServletContextHandler handler = new ServletContextHandler(); + handler.setBaseResource(Resource.newClassPathResource(".")); for (Map.Entry entry : servlets.entrySet()) { handler.addServlet(entry.getValue(), entry.getKey()); diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java b/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java new file mode 100644 index 00000000000..c44f1fabf58 --- /dev/null +++ b/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java @@ -0,0 +1,46 @@ +package com.yammer.dropwizard.modules; + +import com.yammer.dropwizard.Module; +import com.yammer.dropwizard.config.Environment; +import org.eclipse.jetty.servlet.DefaultServlet; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * A module for serving static asset files from the classpath. + */ +public class AssetsModule implements Module { + private final String path; + + /** + * Creates a new {@link AssetsModule} which serves up static assets from + * {@code src/main/resources/assets/*} as {@code /assets/*}. + * + * @see AssetsModule#AssetsModule(String) + */ + public AssetsModule() { + this("/assets"); + } + + /** + * Creates a new {@link AssetsModule} which will configure the service to serve the static files + * located in {@code src/main/resources/${path}} as {@code /${path}}. For example, given a + * {@code path} of {@code "/assets"}, {@code src/main/resources/assets/example.js} would be + * served up from {@code /assets/example.js}. + * + * @param path the classpath and URI root of the static asset files + */ + public AssetsModule(String path) { + checkArgument(path.startsWith("/"), "%s is not an absolute path", path); + checkArgument(!"/".equals(path), "%s is the classpath root"); + this.path = path.endsWith("/") ? path : (path + '/'); + } + + @Override + public void initialize(Environment environment) { + environment.addServlet(DefaultServlet.class, path + '*') + .setInitParam("dirAllowed", "false") + .setInitParam("pathInfoOnly", "true") + .setInitParam("relativeResourceBase", path); + } +} From bb2ddfaf5bed44de8d29ad7b17e55c1106efa45c Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 23 Nov 2011 11:55:30 -0800 Subject: [PATCH 0029/2771] Bump the default max of the connection pool to 8. --- .../java/com/yammer/dropwizard/db/DatabaseConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java index 93ae47c9609..ab458bdd852 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java @@ -44,7 +44,7 @@ public static class DatabaseConnectionConfiguration { @Max(1024) @Min(1) - private int maxSize = 1; + private int maxSize = 8; private boolean checkConnectionWhileIdle; From ca88bcf15b4683178ce9cf27284ed3fea0efb4a3 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 23 Nov 2011 11:56:13 -0800 Subject: [PATCH 0030/2771] Make sure the connection pool blocks when exhausted. --- .../src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java index 18b2f4279ba..9ab3802a67b 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java @@ -63,6 +63,7 @@ private GenericObjectPool buildPool(DatabaseConnectionConfiguration connectionCo pool.setTestWhileIdle(connectionConfig.checkConnectionWhileIdle()); pool.setTimeBetweenEvictionRunsMillis(connectionConfig.getCheckConnectionHealthWhenIdleFor().toMilliseconds()); pool.setMinEvictableIdleTimeMillis(connectionConfig.getCloseConnectionIfIdleFor().toMilliseconds()); + pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); return pool; } } From 43c372a860f8eb8fb1cf6f499e53ce263de53de3 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 23 Nov 2011 11:56:29 -0800 Subject: [PATCH 0031/2771] Remove an unused import. --- .../java/com/yammer/dropwizard/db/DatabaseConfiguration.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java index ab458bdd852..2428ea1d6f4 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java @@ -3,7 +3,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.yammer.dropwizard.util.Duration; -import org.hibernate.validator.constraints.URL; import javax.validation.Valid; import javax.validation.constraints.Max; From 43d793f6b23cc283831670e504e50dfb501f6d0c Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 23 Nov 2011 14:39:37 -0800 Subject: [PATCH 0032/2771] Pull the service banner from a resource. --- .../src/main/resources/banner.txt | 8 +++++ .../yammer/dropwizard/AbstractService.java | 29 ------------------- .../yammer/dropwizard/cli/ServerCommand.java | 8 +++-- .../yammer/dropwizard/tests/ServiceTest.java | 10 ------- .../src/test/resources/banner.txt | 8 +++++ .../dropwizard/examples/ExampleService.scala | 10 ------- 6 files changed, 22 insertions(+), 51 deletions(-) create mode 100644 dropwizard-example/src/main/resources/banner.txt create mode 100644 dropwizard_2.9.1/src/test/resources/banner.txt diff --git a/dropwizard-example/src/main/resources/banner.txt b/dropwizard-example/src/main/resources/banner.txt new file mode 100644 index 00000000000..98a10e38e45 --- /dev/null +++ b/dropwizard-example/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + dP + 88 + .d8888b. dP. .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b. + 88ooood8 `8bd8' 88' `88 88'`88'`88 88' `88 88 88ooood8 + 88. ... .d88b. 88. .88 88 88 88 88. .88 88 88. ... + `88888P' dP' `dP `88888P8 dP dP dP 88Y888P' dP `88888P' + 88 + dP diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java index 3d9688bd6b5..e1bd07437e0 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java @@ -33,7 +33,6 @@ public abstract class AbstractService { private final List modules; private final List> configuredModules; private final SortedMap commands; - private String banner = null; /** * Creates a new service with the given name. @@ -116,34 +115,6 @@ protected final void addCommand(ConfiguredCommand command) { commands.put(command.getName(), command); } - /** - * Returns {@code true} if the service has a banner. - * - * @return whether or not the service has a banner - */ - public final boolean hasBanner() { - return banner != null; - } - - /** - * Returns the service's banner, if any. The banner will be printed out when the service starts - * up. - * - * @return the service's banner - */ - public final String getBanner() { - return banner; - } - - /** - * Sets the service's banner. The banner will be printed out when the service starts up. - * - * @param banner a banner - */ - protected final void setBanner(String banner) { - this.banner = banner; - } - /** * When the service runs, this is called after the {@link Module}s are run. Override it to add * providers, resources, etc. for your service. diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java index 68ae5cf6782..c092d1a9d13 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java @@ -1,5 +1,7 @@ package com.yammer.dropwizard.cli; +import com.google.common.base.Charsets; +import com.google.common.io.Resources; import com.yammer.dropwizard.AbstractService; import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.config.Environment; @@ -50,8 +52,10 @@ protected final void run(AbstractService service, final Logger logger = LoggerFactory.getLogger(ServerCommand.class); logger.info("Starting " + service.getName()); - if (service.hasBanner()) { - logger.info('\n' + service.getBanner() + '\n'); + try { + logger.info('\n' + Resources.toString(Resources.getResource("banner.txt"), Charsets.UTF_8)); + } catch (IllegalArgumentException ignored) { + // don't display the banner if there isn't one } try { diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java index 8360884e0a0..2072a0df6c5 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java @@ -20,7 +20,6 @@ private class FakeService extends Service { FakeService() { super("test"); addModule(module); - setBanner("woo"); } @Override @@ -37,13 +36,4 @@ public void hasAReferenceToItsTypeParameter() throws Exception { assertThat(service.getConfigurationClass(), is(sameInstance(FakeConfiguration.class))); } - - @Test - public void mightHaveABanner() throws Exception { - assertThat(service.hasBanner(), - is(true)); - - assertThat(service.getBanner(), - is("woo")); - } } diff --git a/dropwizard_2.9.1/src/test/resources/banner.txt b/dropwizard_2.9.1/src/test/resources/banner.txt new file mode 100644 index 00000000000..98a10e38e45 --- /dev/null +++ b/dropwizard_2.9.1/src/test/resources/banner.txt @@ -0,0 +1,8 @@ + dP + 88 + .d8888b. dP. .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b. + 88ooood8 `8bd8' 88' `88 88'`88'`88 88' `88 88 88ooood8 + 88. ... .d88b. 88. .88 88 88 88 88. .88 88 88. ... + `88888P' dP' `dP `88888P8 dP dP dP 88Y888P' dP `88888P' + 88 + dP diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala b/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala index 462a84495b4..b13dd2cc3c0 100644 --- a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala +++ b/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala @@ -6,16 +6,6 @@ import com.yammer.dropwizard.ScalaService object ExampleService extends ScalaService[ExampleConfiguration]("example") { addCommand(new SayCommand) addCommand(new SplodyCommand) - setBanner(""" - dP - 88 - .d8888b. dP. .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b. - 88ooood8 `8bd8' 88' `88 88'`88'`88 88' `88 88 88ooood8 - 88. ... .d88b. 88. .88 88 88 88 88. .88 88 88. ... - `88888P' dP' `dP `88888P8 dP dP dP 88Y888P' dP `88888P' - 88 - dP - """) def initialize(configuration: ExampleConfiguration, environment: Environment) { environment.addResource(new HelloWorldResource(configuration.saying)) From 3cd7468acd29d347bb411299e1453c5a65e3c07b Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 23 Nov 2011 14:48:59 -0800 Subject: [PATCH 0033/2771] Fix javadoc for AbstractService. --- .../src/main/java/com/yammer/dropwizard/AbstractService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java index e1bd07437e0..8b5327c2637 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java @@ -121,6 +121,7 @@ protected final void addCommand(ConfiguredCommand command) { * * @param configuration the parsed {@link Configuration} object * @param environment the service's {@link Environment} + * @throws Exception if something goes wrong */ protected abstract void initialize(T configuration, Environment environment) throws Exception; @@ -131,6 +132,7 @@ protected final void addCommand(ConfiguredCommand command) { * * @param configuration the parsed {@link Configuration} object * @param environment the service's {@link Environment} + * @throws Exception if something goes wrong */ public final void initializeWithModules(T configuration, Environment environment) throws Exception { for (Module module : modules) { From 81b945d5236d355a6bf7c1659ce3eceea86cc267 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 15:31:06 -0800 Subject: [PATCH 0034/2771] Upgrade to tomcat-dbcp 7.0.23. --- dropwizard-db/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 9078f0494f2..bb48430dfed 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -28,7 +28,7 @@ org.apache.tomcat tomcat-dbcp - 7.0.22 + 7.0.23 org.hsqldb From b2a6d9d24dce58b63729b531ed4302752bb9a14d Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 15:31:20 -0800 Subject: [PATCH 0035/2771] Upgraded to hsqldb 2.2.6. --- dropwizard-db/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index bb48430dfed..cad6d9bcd0a 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -33,7 +33,7 @@ org.hsqldb hsqldb - 2.2.4 + 2.2.6 test From 8b7221e1588bc130ade4003a5450c9b99dcf052f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 15:45:09 -0800 Subject: [PATCH 0036/2771] Add statement logging for Database. All SQL will be logged to com.yammer.dropwizard.db.Database at TRACE level. --- .../src/main/java/com/yammer/dropwizard/db/Database.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index 2fd7761c4b3..4a970fe1dde 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -1,20 +1,26 @@ package com.yammer.dropwizard.db; import com.yammer.dropwizard.lifecycle.Managed; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; import org.apache.tomcat.dbcp.pool.ObjectPool; import org.skife.jdbi.v2.DBI; import org.skife.jdbi.v2.Handle; +import org.skife.jdbi.v2.logging.Log4JLog; import org.skife.jdbi.v2.util.IntegerMapper; import javax.sql.DataSource; import java.sql.SQLException; public class Database extends DBI implements Managed { + private static final Logger LOGGER = Logger.getLogger(Database.class); + private final ObjectPool pool; public Database(DataSource dataSource, ObjectPool pool) { super(dataSource); this.pool = pool; + setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); } @Override From bb103b5c1189861fffdabbc52237d35f90efa9bf Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 15:59:54 -0800 Subject: [PATCH 0037/2771] Collect per-query metrics for Database. All non-interface queries get lumped into Database.raw-sql, since there's not a lot to distinguish them by. --- .../com/yammer/dropwizard/db/Database.java | 3 ++ .../dropwizard/db/MetricsTimingCollector.java | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/MetricsTimingCollector.java diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index 4a970fe1dde..72276372cd9 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -1,6 +1,7 @@ package com.yammer.dropwizard.db; import com.yammer.dropwizard.lifecycle.Managed; +import com.yammer.metrics.Metrics; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.tomcat.dbcp.pool.ObjectPool; @@ -21,6 +22,8 @@ public Database(DataSource dataSource, ObjectPool pool) { super(dataSource); this.pool = pool; setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); + setTimingCollector(new MetricsTimingCollector(Metrics.defaultRegistry())); + } @Override diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/MetricsTimingCollector.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/MetricsTimingCollector.java new file mode 100644 index 00000000000..ca7f3269288 --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/MetricsTimingCollector.java @@ -0,0 +1,32 @@ +package com.yammer.dropwizard.db; + +import com.yammer.metrics.core.MetricsRegistry; +import com.yammer.metrics.core.TimerMetric; +import org.skife.jdbi.v2.StatementContext; +import org.skife.jdbi.v2.TimingCollector; + +import java.util.concurrent.TimeUnit; + +class MetricsTimingCollector implements TimingCollector { + private final MetricsRegistry registry; + private final TimerMetric defaultTimer; + + MetricsTimingCollector(MetricsRegistry registry) { + this.registry = registry; + this.defaultTimer = registry.newTimer(Database.class, "raw-sql"); + } + + @Override + public void collect(long elapsedTime, StatementContext ctx) { + final TimerMetric timer = getTimer(ctx); + timer.update(elapsedTime, TimeUnit.NANOSECONDS); + } + + private TimerMetric getTimer(StatementContext ctx) { + if ((ctx.getSqlObjectType() == null) || (ctx.getSqlObjectMethod() == null)) { + return defaultTimer; + } + + return registry.newTimer(ctx.getSqlObjectType(), ctx.getSqlObjectMethod().getName()); + } +} From 4a0a8d30158aef9c975f01d6d8347e17f965cd77 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 16:03:47 -0800 Subject: [PATCH 0038/2771] Extract Database.ping() to a DAO. --- .../com/yammer/dropwizard/db/Database.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index 72276372cd9..e114de3ec59 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -6,21 +6,27 @@ import org.apache.log4j.Logger; import org.apache.tomcat.dbcp.pool.ObjectPool; import org.skife.jdbi.v2.DBI; -import org.skife.jdbi.v2.Handle; import org.skife.jdbi.v2.logging.Log4JLog; -import org.skife.jdbi.v2.util.IntegerMapper; +import org.skife.jdbi.v2.sqlobject.SqlQuery; import javax.sql.DataSource; import java.sql.SQLException; public class Database extends DBI implements Managed { + public interface Ping { + @SqlQuery("SELECT 1") + public Integer ping(); + } + private static final Logger LOGGER = Logger.getLogger(Database.class); private final ObjectPool pool; + private final Ping ping; public Database(DataSource dataSource, ObjectPool pool) { super(dataSource); this.pool = pool; + this.ping = onDemand(Ping.class); setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); setTimingCollector(new MetricsTimingCollector(Metrics.defaultRegistry())); @@ -37,14 +43,9 @@ public void stop() throws Exception { } public void ping() throws SQLException { - final Handle handle = open(); - try { - final Integer first = handle.createQuery("SELECT 1").map(IntegerMapper.FIRST).first(); - if (!Integer.valueOf(1).equals(first)) { - throw new SQLException("Expected 1 from 'SELECT 1', got " + first); - } - } finally { - handle.close(); + final Integer value = ping.ping(); + if (!Integer.valueOf(1).equals(value)) { + throw new SQLException("Expected 1 from 'SELECT 1', got " + value); } } } From a1199430eb8bdd8a33ad1f187f758d6ceb4756d1 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 16:46:43 -0800 Subject: [PATCH 0039/2771] Downgrade to hsqldb 1.8. I always forget that 2.0 is half-broken. --- dropwizard-db/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index cad6d9bcd0a..d1dc23aec5e 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -31,9 +31,9 @@ 7.0.23 - org.hsqldb + hsqldb hsqldb - 2.2.6 + 1.8.0.10 test From 78de22f42ef59f9215914e4d28d3b172107dcf0e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 16:47:26 -0800 Subject: [PATCH 0040/2771] Added NamePrependingStatementRewriter. This prepends the SQL object's class name and the method name as a comment to each SQL query. --- .../com/yammer/dropwizard/db/Database.java | 2 +- .../db/NamePrependingStatementRewriter.java | 25 +++++++++++++++++++ .../dropwizard/db/tests/DatabaseTest.java | 6 +++-- 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/NamePrependingStatementRewriter.java diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index e114de3ec59..055605224d5 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -29,7 +29,7 @@ public Database(DataSource dataSource, ObjectPool pool) { this.ping = onDemand(Ping.class); setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); setTimingCollector(new MetricsTimingCollector(Metrics.defaultRegistry())); - + setStatementRewriter(new NamePrependingStatementRewriter()); } @Override diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/NamePrependingStatementRewriter.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/NamePrependingStatementRewriter.java new file mode 100644 index 00000000000..24a942439fb --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/NamePrependingStatementRewriter.java @@ -0,0 +1,25 @@ +package com.yammer.dropwizard.db; + +import org.skife.jdbi.v2.Binding; +import org.skife.jdbi.v2.ColonPrefixNamedParamStatementRewriter; +import org.skife.jdbi.v2.StatementContext; +import org.skife.jdbi.v2.tweak.RewrittenStatement; + +class NamePrependingStatementRewriter extends ColonPrefixNamedParamStatementRewriter { + @Override + public RewrittenStatement rewrite(String sql, Binding params, StatementContext ctx) { + if ((ctx.getSqlObjectType() != null) && (ctx.getSqlObjectMethod() != null)) { + final StringBuilder query = new StringBuilder(sql.length() + 100); + query.append("/* "); + final String className = ctx.getSqlObjectType().getSimpleName(); + if (!className.isEmpty()) { + query.append(className).append('.'); + } + query.append(ctx.getSqlObjectMethod().getName()); + query.append(" */ "); + query.append(sql); + return super.rewrite(query.toString(), params, ctx); + } + return super.rewrite(sql, params, ctx); + } +} diff --git a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java index 9a84f6df8e8..c1f3b026039 100644 --- a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java +++ b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java @@ -2,6 +2,7 @@ import com.google.common.collect.ImmutableList; import com.yammer.dropwizard.config.Environment; +import com.yammer.dropwizard.config.LoggingFactory; import com.yammer.dropwizard.db.Database; import com.yammer.dropwizard.db.DatabaseConfiguration; import com.yammer.dropwizard.db.DatabaseFactory; @@ -21,9 +22,10 @@ import static org.mockito.Mockito.verify; public class DatabaseTest { - private DatabaseConfiguration config = new DatabaseConfiguration(); - private DatabaseConnectionConfiguration hsqlConfig = new DatabaseConnectionConfiguration(); + private final DatabaseConfiguration config = new DatabaseConfiguration(); + private final DatabaseConnectionConfiguration hsqlConfig = new DatabaseConnectionConfiguration(); { + LoggingFactory.bootstrap(); hsqlConfig.setUrl("jdbc:hsqldb:mem:DbTest-"+System.currentTimeMillis()); hsqlConfig.setUser("sa"); hsqlConfig.setDriverClass("org.hsqldb.jdbcDriver"); From 8728f918eb4b68368e84abb57b5764d1368e2c6e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 16:55:43 -0800 Subject: [PATCH 0041/2771] Added ScopedStatementLocator. Given an SQL object named com.example.ExampleDAO with an @SqlQuery-annotated method named findByName, ScopedStatementLocator will first look for a resource named "findByName", then "findByName.sql", then "com.example.Example.DAO.findByName.sql". This allows SQL files to be scoped by their object names, eliminating collisions. --- .../com/yammer/dropwizard/db/Database.java | 1 + .../dropwizard/db/ScopedStatementLocator.java | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/ScopedStatementLocator.java diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index 055605224d5..441acc81c4b 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -30,6 +30,7 @@ public Database(DataSource dataSource, ObjectPool pool) { setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); setTimingCollector(new MetricsTimingCollector(Metrics.defaultRegistry())); setStatementRewriter(new NamePrependingStatementRewriter()); + setStatementLocator(new ScopedStatementLocator()); } @Override diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/ScopedStatementLocator.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/ScopedStatementLocator.java new file mode 100644 index 00000000000..f22c1caf6f9 --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/ScopedStatementLocator.java @@ -0,0 +1,83 @@ +package com.yammer.dropwizard.db; + +import org.skife.jdbi.v2.StatementContext; +import org.skife.jdbi.v2.exceptions.UnableToCreateStatementException; +import org.skife.jdbi.v2.tweak.StatementLocator; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +@SuppressWarnings({"IOResourceOpenedButNotSafelyClosed", "NestedAssignment"}) +class ScopedStatementLocator implements StatementLocator { + public static boolean isSql(String sql) { + final String local = sql.substring(0, 7).toLowerCase(); + return local.startsWith("insert ") + || local.startsWith("update ") + || local.startsWith("select ") + || local.startsWith("call ") + || local.startsWith("delete ") + || local.startsWith("create ") + || local.startsWith("alter ") + || local.startsWith("drop "); + } + + @Override + public String locate(String name, StatementContext ctx) { + if (isSql(name)) { + return name; + } + final ClassLoader loader = selectClassLoader(); + InputStream input = loader.getResourceAsStream(name); + BufferedReader reader = null; + try { + if (input == null) { + input = loader.getResourceAsStream(name + ".sql"); + } + + if ((input == null) && (ctx.getSqlObjectType() != null)) { + input = loader.getResourceAsStream(ctx.getSqlObjectType() + .getCanonicalName() + '.' + name + ".sql"); + } + + if (input == null) { + return name; + } + + final StringBuilder buffer = new StringBuilder(); + reader = new BufferedReader(new InputStreamReader(input)); + try { + String line; + while ((line = reader.readLine()) != null) { + if (!isComment(line)) { + buffer.append(line).append(' '); + } + } + } catch (IOException e) { + throw new UnableToCreateStatementException(e.getMessage(), e, ctx); + } + + return buffer.toString(); + } finally { + try { + if (reader != null) { + reader.close(); + } + } catch (IOException ignored) { + // nothing we can do here :-( + } + } + } + + private static ClassLoader selectClassLoader() { + if (Thread.currentThread().getContextClassLoader() != null) { + return Thread.currentThread().getContextClassLoader(); + } + return ScopedStatementLocator.class.getClassLoader(); + } + + private static boolean isComment(final String line) { + return line.startsWith("#") || line.startsWith("--") || line.startsWith("//"); + } +} From d69abd452a5dce99b69099fbb53e43820af063ce Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 17:34:00 -0800 Subject: [PATCH 0042/2771] Added support for Optional jDBI arguments. --- .../com/yammer/dropwizard/db/Database.java | 4 +++- .../dropwizard/db/args/OptionalArgument.java | 23 +++++++++++++++++++ .../db/args/OptionalArgumentFactory.java | 22 ++++++++++++++++++ .../dropwizard/db/tests/DatabaseTest.java | 12 ++++++++++ .../yammer/dropwizard/db/tests/PersonDAO.java | 10 ++++++++ 5 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgument.java create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgumentFactory.java create mode 100644 dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/PersonDAO.java diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index 441acc81c4b..cdece07c7eb 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -1,5 +1,6 @@ package com.yammer.dropwizard.db; +import com.yammer.dropwizard.db.args.OptionalArgumentFactory; import com.yammer.dropwizard.lifecycle.Managed; import com.yammer.metrics.Metrics; import org.apache.log4j.Level; @@ -27,10 +28,11 @@ public Database(DataSource dataSource, ObjectPool pool) { super(dataSource); this.pool = pool; this.ping = onDemand(Ping.class); - setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); + setSQLLog(new Log4JLog(LOGGER, Level.ERROR)); setTimingCollector(new MetricsTimingCollector(Metrics.defaultRegistry())); setStatementRewriter(new NamePrependingStatementRewriter()); setStatementLocator(new ScopedStatementLocator()); + registerArgumentFactory(new OptionalArgumentFactory()); } @Override diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgument.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgument.java new file mode 100644 index 00000000000..4bb513e0076 --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgument.java @@ -0,0 +1,23 @@ +package com.yammer.dropwizard.db.args; + +import com.google.common.base.Optional; +import org.skife.jdbi.v2.StatementContext; +import org.skife.jdbi.v2.tweak.Argument; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class OptionalArgument implements Argument { + private final Optional value; + + public OptionalArgument(Optional value) { + this.value = value; + } + + @Override + public void apply(int position, + PreparedStatement statement, + StatementContext ctx) throws SQLException { + statement.setObject(position, value.orNull()); + } +} diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgumentFactory.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgumentFactory.java new file mode 100644 index 00000000000..40191c50b0b --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgumentFactory.java @@ -0,0 +1,22 @@ +package com.yammer.dropwizard.db.args; + +import com.google.common.base.Optional; +import org.skife.jdbi.v2.StatementContext; +import org.skife.jdbi.v2.tweak.Argument; +import org.skife.jdbi.v2.tweak.ArgumentFactory; + +public class OptionalArgumentFactory implements ArgumentFactory> { + @Override + public boolean accepts(Class> expectedType, + Object value, + StatementContext ctx) { + return value instanceof Optional; + } + + @Override + public Argument build(Class> expectedType, + Optional value, + StatementContext ctx) { + return new OptionalArgument(value); + } +} diff --git a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java index c1f3b026039..a1cf7bd6b54 100644 --- a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java +++ b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java @@ -1,5 +1,6 @@ package com.yammer.dropwizard.db.tests; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.config.LoggingFactory; @@ -90,4 +91,15 @@ public void managesTheDatabaseWithTheEnvironment() throws Exception { verify(environment).manage(db); } + + @Test + public void sqlObjectsCanReturnImmutableLists() throws Exception { + final PersonDAO dao = database.open(PersonDAO.class); + try { + assertThat(dao.findByName(Optional.of("Coda Hale")), + is("Coda Hale")); + } finally { + database.close(dao); + } + } } diff --git a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/PersonDAO.java b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/PersonDAO.java new file mode 100644 index 00000000000..fddbfe65013 --- /dev/null +++ b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/PersonDAO.java @@ -0,0 +1,10 @@ +package com.yammer.dropwizard.db.tests; + +import com.google.common.base.Optional; +import org.skife.jdbi.v2.sqlobject.Bind; +import org.skife.jdbi.v2.sqlobject.SqlQuery; + +public interface PersonDAO { + @SqlQuery("SELECT name FROM people WHERE name = :name") + public String findByName(@Bind("name") Optional name); +} From c8bfc04cfbc5c021e7a08cafa05e7758b6e1bfbf Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 18:13:19 -0800 Subject: [PATCH 0043/2771] Whoops. --- .../src/main/java/com/yammer/dropwizard/db/Database.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index cdece07c7eb..f6c730a4cbf 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -28,7 +28,7 @@ public Database(DataSource dataSource, ObjectPool pool) { super(dataSource); this.pool = pool; this.ping = onDemand(Ping.class); - setSQLLog(new Log4JLog(LOGGER, Level.ERROR)); + setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); setTimingCollector(new MetricsTimingCollector(Metrics.defaultRegistry())); setStatementRewriter(new NamePrependingStatementRewriter()); setStatementLocator(new ScopedStatementLocator()); From 27e8515bed2cccdc3b5276ede0109f1d0bf6645c Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 22:45:46 -0800 Subject: [PATCH 0044/2771] Added tests for Configuration. --- .../dropwizard/config/Configuration.java | 2 - .../config/tests/ConfigurationTest.java | 40 +++++ .../test/resources/basic-configuration.yml | 145 ++++++++++++++++++ 3 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java create mode 100644 dropwizard/src/test/resources/basic-configuration.yml diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/Configuration.java b/dropwizard/src/main/java/com/yammer/dropwizard/config/Configuration.java index 58abf90440d..3e3c2301ab8 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/config/Configuration.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/config/Configuration.java @@ -3,8 +3,6 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; -// TODO: 11/7/11 -- test Configuration - /** * An object representation of the YAML configuration file. Extend this with your own configuration * properties, and they'll be parsed from the YAML file as well. diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java new file mode 100644 index 00000000000..8715e308a9f --- /dev/null +++ b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java @@ -0,0 +1,40 @@ +package com.yammer.dropwizard.config.tests; + +import com.yammer.dropwizard.config.Configuration; +import com.yammer.dropwizard.config.ConfigurationFactory; +import com.yammer.dropwizard.util.Validator; +import org.junit.Test; + +import java.io.File; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +public class ConfigurationTest { + private final Configuration configuration = new Configuration(); + + @Test + public void hasAnHttpConfiguration() throws Exception { + assertThat(configuration.getHttpConfiguration(), + is(notNullValue())); + } + + @Test + public void hasALoggingConfiguration() throws Exception { + assertThat(configuration.getLoggingConfiguration(), + is(notNullValue())); + } + + @Test + public void loadsFromTheExampleConfiguration() throws Exception { + final ConfigurationFactory factory = new ConfigurationFactory( + Configuration.class, + new Validator()); + + final Configuration config = factory.build(new File("dropwizard/src/test/resources/basic-configuration.yml")); + + assertThat(config.getHttpConfiguration(), + is(notNullValue())); + } +} diff --git a/dropwizard/src/test/resources/basic-configuration.yml b/dropwizard/src/test/resources/basic-configuration.yml new file mode 100644 index 00000000000..b9defc5c0fc --- /dev/null +++ b/dropwizard/src/test/resources/basic-configuration.yml @@ -0,0 +1,145 @@ +# HTTP-specific options. +http: + + # The port on which the HTTP server listens for service requests. + port: 8080 + + # The port on which the HTTP server listens for administrative requests. + adminPort: 8081 + + # Maximum number of threads. + maxThreads: 100 + + # Minimum number of thread to keep alive. + minThreads: 10 + + # The type of connector to use. Other valid values are "nonblocking" or "legacy". In general, the + # blocking connector should be used for low-latency services with short request durations. The + # nonblocking connector should be used for services with long request durations or which + # specifically take advantage of Jetty's continuation support. + connectorType: blocking + + # The maximum amount of time a connection is allowed to be idle before being closed. + maxIdleTime: 1s + + # The number of threads dedicated to accepting connections. If omitted, this defaults to the + # number of logical CPUs on the current machine. + acceptorThreadCount: 3 + + # The offset of the acceptor threads' priorities. Can be [-5...5], with -5 dropping the acceptor + # threads to the lowest possible priority and with 5 raising them to the highest priority. + acceptorThreadPriorityOffset: 0 + + # The number of unaccepted requests to keep in the accept queue before refusing connections. If + # set to -1 or omitted, the system default is used. + acceptQueueSize: 100 + + # The maximum number of buffers to keep in memory. + maxBufferCount: 1024 + + # The initial buffer size for reading requests. + requestBufferSize: 32KB + + # The initial buffer size for reading request headers. + requestHeaderBufferSize: 6KB + + # The initial buffer size for writing responses. + responseBufferSize: 32KB + + # The initial buffer size for writing response headers. + responseHeaderBufferSize: 6KB + + # Enables SO_REUSEADDR on the server socket. + reuseAddress: true + + # Enables SO_LINGER on the server socket with the specified linger time. + soLingerTime: 1s + + # The number of open connections at which the server transitions to a "low-resources" mode. + lowResourcesConnectionThreshold: 25000 + + # When in low-resources mode, the maximum amount of time a connection is allowed to be idle before + # being closed. Overrides maxIdleTime. + lowResourcesMaxIdleTime: 5s + + # If non-zero, the server will allow worker threads to finish processing requests after the server + # socket has been closed for the given amount of time. + shutdownGracePeriod: 2s + + # If true, the HTTP server will prefer X-Forwarded headers over their non-forwarded equivalents. + useForwardedHeaders: true + + # If true, forces the HTTP connector to use off-heap, direct buffers. + useDirectBuffers: true + + # The hostname of the interface to which the HTTP server socket wil be found. If omitted, the + # socket will listen on all interfaces. + # bindHost: app1.example.com + + # HTTP request log settings + requestLog: + + # Whether or not to log HTTP requests. + enabled: false + + # The filename to which HTTP requests will be logged. The string 'yyyy_mm_dd' will be replaced + # with the current date, and the logs will be rolled accordingly. + filenamePattern: ./logs/yyyy_mm_dd.log + + # The maximum number of old log files to retain. + retainedFileCount: 5 + +# Logging settings. +logging: + + # The default level of all loggers. Can be OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, or ALL. + level: INFO + + # Logger-specific levels. + loggers: + + # Sets the level for 'com.example.app' to DEBUG. + com.example.app: DEBUG + + # Settings for logging to stdout. + console: + + # If true, write log statements to stdout. + enabled: true + + # Do not display log statements below this threshold to stdout. + threshold: ALL + + # Settings for logging to a file. + file: + + # If true, write log statements to a file. + enabled: false + + # Do not write log statements below this threshold to the file. + threshold: ALL + + # The file to which statements will be logged. When the log file reaches the maximum size, the + # file will be renamed example.log.1, example.log will be truncated, and new statements written + # to it. + filenamePattern: ./logs/example.log + + # The maximum size of any log file. + maxFileSize: 50MB + + # The maximum number of log files to retain. + retainedFileCount: 5 + + # Settings for logging to syslog. + syslog: + + # If true, write log statements to syslog. + enabled: false + + # The hostname of the syslog server to which statements will be sent. + # N.B.: If this is the local host, the local syslog instance will need to be configured to + # listen on an inet socket, not just a Unix socket. + host: localhost + + # The syslog facility to which statements will be sent. + facility: local0 From 18a6eced0148c5ebb2eca4dde82687096531d5db Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 28 Nov 2011 22:52:45 -0800 Subject: [PATCH 0045/2771] Added docs for ConfigurationException. --- .../yammer/dropwizard/config/ConfigurationException.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java b/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java index 2e6e7450951..7d9f2a9c50c 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java @@ -2,9 +2,18 @@ import java.io.File; +/** + * An exception thrown where there is an error parsing a configuration object. + */ public class ConfigurationException extends Exception { private static final long serialVersionUID = 5325162099634227047L; + /** + * Creates a new {@link ConfigurationException} for the given file with the given errors. + * + * @param file the bad configuration file + * @param errors the errors in the file + */ public ConfigurationException(File file, Iterable errors) { super(formatMessage(file, errors)); } From c89d8e95467d1cde0684670e4e80dcbdf1aae0a7 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 29 Nov 2011 11:57:07 -0800 Subject: [PATCH 0046/2771] Added @ValidationMethod. --- .../client/JerseyClientConfiguration.java | 9 +++- .../dropwizard/db/DatabaseConfiguration.java | 8 +++- .../dropwizard/cli/ConfiguredCommand.java | 2 +- .../config/ConfigurationFactory.java | 2 +- .../jersey/JacksonMessageBodyProvider.java | 2 +- .../validation/MethodValidator.java | 19 +++++++++ .../validation/ValidationMethod.java | 27 ++++++++++++ .../{util => validation}/Validator.java | 22 +++++++--- .../tests/ConfigurationFactoryTest.java | 2 +- .../config/tests/ConfigurationTest.java | 2 +- .../tests/LoggingConfigurationTest.java | 2 +- .../validation/tests/MethodValidatorTest.java | 42 +++++++++++++++++++ .../tests/ValidatorTest.java | 6 +-- 13 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 dropwizard/src/main/java/com/yammer/dropwizard/validation/MethodValidator.java create mode 100644 dropwizard/src/main/java/com/yammer/dropwizard/validation/ValidationMethod.java rename dropwizard/src/main/java/com/yammer/dropwizard/{util => validation}/Validator.java (53%) create mode 100644 dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/MethodValidatorTest.java rename dropwizard/src/test/java/com/yammer/dropwizard/{util => validation}/tests/ValidatorTest.java (88%) diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java index 716477766aa..af42eca964f 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientConfiguration.java @@ -1,11 +1,11 @@ package com.yammer.dropwizard.client; +import com.yammer.dropwizard.validation.ValidationMethod; + import javax.validation.constraints.Max; import javax.validation.constraints.Min; public class JerseyClientConfiguration extends HttpClientConfiguration { - // TODO: 11/16/11 -- validate minThreads <= maxThreads - @Max(16 * 1024) @Min(1) private int minThreads = 1; @@ -39,4 +39,9 @@ public boolean isGzipEnabled() { public void setGzipEnabled(boolean enable) { this.gzipEnabled = enable; } + + @ValidationMethod(message = ".minThreads must be less than or equal to maxThreads") + public boolean isThreadPoolSizedCorrectly() { + return minThreads <= maxThreads; + } } diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java index 2428ea1d6f4..efba8f6bb4d 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.yammer.dropwizard.util.Duration; +import com.yammer.dropwizard.validation.ValidationMethod; import javax.validation.Valid; import javax.validation.constraints.Max; @@ -35,8 +36,6 @@ public static class DatabaseConnectionConfiguration { @NotNull private String validationQuery = "/* Health Check */ SELECT 1"; - // TODO: 11/16/11 -- validate minSize <= maxSize - @Max(1024) @Min(1) private int minSize = 1; @@ -150,6 +149,11 @@ public Duration getCloseConnectionIfIdleFor() { public void setCloseConnectionIfIdleFor(Duration timeout) { this.closeConnectionIfIdleFor = timeout.toString(); } + + @ValidationMethod(message = ".minSize must be less than or equal to maxSize") + public boolean isPoolSizedCorrectly() { + return minSize <= maxSize; + } } @Valid diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java b/dropwizard/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java index c69bcac30cc..709373ac8ea 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java @@ -5,7 +5,7 @@ import com.yammer.dropwizard.config.ConfigurationException; import com.yammer.dropwizard.config.ConfigurationFactory; import com.yammer.dropwizard.config.LoggingFactory; -import com.yammer.dropwizard.util.Validator; +import com.yammer.dropwizard.validation.Validator; import org.apache.commons.cli.CommandLine; import java.io.File; diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java b/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java index 4caea407db0..1a7c8d33cbe 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java @@ -3,7 +3,7 @@ import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; import com.google.common.io.Files; -import com.yammer.dropwizard.util.Validator; +import com.yammer.dropwizard.validation.Validator; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.error.YAMLException; diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java index 3c596b21d27..9e64768f658 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java @@ -2,7 +2,7 @@ import com.google.common.collect.ImmutableList; import com.yammer.dropwizard.json.Json; -import com.yammer.dropwizard.util.Validator; +import com.yammer.dropwizard.validation.Validator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/validation/MethodValidator.java b/dropwizard/src/main/java/com/yammer/dropwizard/validation/MethodValidator.java new file mode 100644 index 00000000000..f508e8a81f7 --- /dev/null +++ b/dropwizard/src/main/java/com/yammer/dropwizard/validation/MethodValidator.java @@ -0,0 +1,19 @@ +package com.yammer.dropwizard.validation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * A validator for {@link ValidationMethod}-annotated methods. + */ +public class MethodValidator implements ConstraintValidator { + @Override + public void initialize(ValidationMethod constraintAnnotation) { + + } + + @Override + public boolean isValid(Boolean value, ConstraintValidatorContext context) { + return (value == null) || value; + } +} diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/validation/ValidationMethod.java b/dropwizard/src/main/java/com/yammer/dropwizard/validation/ValidationMethod.java new file mode 100644 index 00000000000..0c4eb49be3a --- /dev/null +++ b/dropwizard/src/main/java/com/yammer/dropwizard/validation/ValidationMethod.java @@ -0,0 +1,27 @@ +package com.yammer.dropwizard.validation; + +import javax.validation.Constraint; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Validates a bean predicate method as returning true. Bean predicates must be of the form + * {@code isSomething} or they'll be silently ignored. + */ +@Target({TYPE, ANNOTATION_TYPE, METHOD}) +@Retention(RUNTIME) +@Constraint(validatedBy = MethodValidator.class) +@Documented +public @interface ValidationMethod { + String message() default "is not valid"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/util/Validator.java b/dropwizard/src/main/java/com/yammer/dropwizard/validation/Validator.java similarity index 53% rename from dropwizard/src/main/java/com/yammer/dropwizard/util/Validator.java rename to dropwizard/src/main/java/com/yammer/dropwizard/validation/Validator.java index 469e3c85abc..c30f1adbf2c 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/util/Validator.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/validation/Validator.java @@ -1,10 +1,12 @@ -package com.yammer.dropwizard.util; +package com.yammer.dropwizard.validation; +import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.Ordering; import com.google.common.collect.Sets; import javax.validation.ConstraintViolation; +import javax.validation.Path; import javax.validation.Validation; import javax.validation.ValidatorFactory; import java.util.Set; @@ -21,17 +23,25 @@ public class Validator { * Validates the given object, and returns a list of error messages, if any. If the returned * list is empty, the object is valid. * - * @param o a potentially-valid object - * @param the type of object to validate + * @param o a potentially-valid object + * @param the type of object to validate * @return a list of error messages, if any, regarding {@code o}'s validity */ public ImmutableList validate(T o) { final Set errors = Sets.newHashSet(); final Set> violations = factory.getValidator().validate(o); for (ConstraintViolation v : violations) { - errors.add(format("%s %s (was %s)", v.getPropertyPath(), - v.getMessage(), - v.getInvalidValue())); + if (v.getConstraintDescriptor().getAnnotation() instanceof ValidationMethod) { + final ImmutableList nodes = ImmutableList.copyOf(v.getPropertyPath()); + final ImmutableList usefulNodes = nodes.subList(0, nodes.size() - 1); + final String msg = v.getMessage().startsWith(".") ? "%s%s" : "%s %s"; + errors.add(format(msg, Joiner.on('.').join(usefulNodes), v.getMessage()).trim()); + } else { + errors.add(format("%s %s (was %s)", + v.getPropertyPath(), + v.getMessage(), + v.getInvalidValue())); + } } return ImmutableList.copyOf(Ordering.natural().sortedCopy(errors)); } diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java index 0d79302894d..7bc948e316a 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java @@ -3,7 +3,7 @@ import com.google.common.io.Resources; import com.yammer.dropwizard.config.ConfigurationException; import com.yammer.dropwizard.config.ConfigurationFactory; -import com.yammer.dropwizard.util.Validator; +import com.yammer.dropwizard.validation.Validator; import org.junit.Test; import org.yaml.snakeyaml.error.YAMLException; diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java index 8715e308a9f..4d916186c20 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java @@ -2,7 +2,7 @@ import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.config.ConfigurationFactory; -import com.yammer.dropwizard.util.Validator; +import com.yammer.dropwizard.validation.Validator; import org.junit.Test; import java.io.File; diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java index 44608fcbce6..db681aa5bb4 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java @@ -5,7 +5,7 @@ import com.yammer.dropwizard.config.ConfigurationFactory; import com.yammer.dropwizard.config.LoggingConfiguration; import com.yammer.dropwizard.util.Size; -import com.yammer.dropwizard.util.Validator; +import com.yammer.dropwizard.validation.Validator; import org.apache.log4j.Level; import org.junit.Before; import org.junit.Test; diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/MethodValidatorTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/MethodValidatorTest.java new file mode 100644 index 00000000000..ce2c2e92caf --- /dev/null +++ b/dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/MethodValidatorTest.java @@ -0,0 +1,42 @@ +package com.yammer.dropwizard.validation.tests; + +import com.google.common.collect.ImmutableList; +import com.yammer.dropwizard.validation.ValidationMethod; +import com.yammer.dropwizard.validation.Validator; +import org.junit.Test; + +import javax.validation.Valid; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +@SuppressWarnings({"FieldMayBeFinal","MethodMayBeStatic","UnusedDeclaration"}) +public class MethodValidatorTest { + public static class SubExample { + @ValidationMethod(message = "also needs something special") + public boolean isOK() { + return false; + } + } + + public static class Example { + @Valid + private SubExample subExample = new SubExample(); + + @ValidationMethod(message = "must have a false thing") + public boolean isFalse() { + return false; + } + + @ValidationMethod(message = "must have a true thing") + public boolean isTrue() { + return true; + } + } + + @Test + public void complainsAboutMethodsWhichReturnFalse() throws Exception { + assertThat(new Validator().validate(new Example()), + is(ImmutableList.of("must have a false thing", "subExample also needs something special"))); + } +} diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ValidatorTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java similarity index 88% rename from dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ValidatorTest.java rename to dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java index 7b1ec51766a..df0b0878277 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ValidatorTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java @@ -1,7 +1,7 @@ -package com.yammer.dropwizard.util.tests; +package com.yammer.dropwizard.validation.tests; import com.google.common.collect.ImmutableList; -import com.yammer.dropwizard.util.Validator; +import com.yammer.dropwizard.validation.Validator; import org.junit.Test; import javax.validation.constraints.Max; @@ -27,7 +27,7 @@ public void setTooBig(int tooBig) { } } - final Validator validator = new Validator(); + private final Validator validator = new Validator(); @Test public void returnsASetOfErrorsForAnObject() throws Exception { From 72a88d4f910ac75fe5529ae967c325685d63cf88 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 30 Nov 2011 22:48:41 -0800 Subject: [PATCH 0047/2771] Bump to Jetty 7.6.0. --- dropwizard/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard/pom.xml b/dropwizard/pom.xml index 468723b446f..7268f86dd26 100644 --- a/dropwizard/pom.xml +++ b/dropwizard/pom.xml @@ -15,7 +15,7 @@ Dropwizard - 7.5.4.v20111024 + 7.6.0.RC0 1.9.2 1.6.4 From 9f3ab8b474ec28b14f8ae96f472c34c97701e278 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 1 Dec 2011 17:07:17 -0800 Subject: [PATCH 0048/2771] Update QuietErrorHandler for Jetty 7.6.0. --- .../java/com/yammer/dropwizard/jetty/QuietErrorHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java index f13eaf19fa1..fd6efe7f448 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java @@ -6,7 +6,7 @@ import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.http.MimeTypes; -import org.eclipse.jetty.server.HttpConnection; +import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.handler.ErrorHandler; @@ -39,7 +39,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - final HttpConnection connection = HttpConnection.getCurrentConnection(); + final AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection(); final Response jettyResponse = connection.getResponse(); jettyResponse.setStatus(jettyResponse.getStatus()); From b1c3ba537c60d2d3e4671c52a3209086a19b02ff Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 1 Dec 2011 17:07:53 -0800 Subject: [PATCH 0049/2771] Dumb down ConfigurationTest. --- .../config/tests/ConfigurationTest.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java index 4d916186c20..af64e97a9c3 100644 --- a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java +++ b/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java @@ -1,12 +1,8 @@ package com.yammer.dropwizard.config.tests; import com.yammer.dropwizard.config.Configuration; -import com.yammer.dropwizard.config.ConfigurationFactory; -import com.yammer.dropwizard.validation.Validator; import org.junit.Test; -import java.io.File; - import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; @@ -25,16 +21,4 @@ public void hasALoggingConfiguration() throws Exception { assertThat(configuration.getLoggingConfiguration(), is(notNullValue())); } - - @Test - public void loadsFromTheExampleConfiguration() throws Exception { - final ConfigurationFactory factory = new ConfigurationFactory( - Configuration.class, - new Validator()); - - final Configuration config = factory.build(new File("dropwizard/src/test/resources/basic-configuration.yml")); - - assertThat(config.getHttpConfiguration(), - is(notNullValue())); - } } From d0b0acee72db6be06f64a5c53518f174c662afd5 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 1 Dec 2011 17:09:08 -0800 Subject: [PATCH 0050/2771] Fix LogThroughputRunner for Jetty 7.6.0. --- .../com/yammer/dropwizard/experiments/LogThroughputRunner.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala b/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala index 1e9856dbdd6..13da68b5a84 100644 --- a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala +++ b/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala @@ -14,7 +14,7 @@ object LogThroughputRunner extends Instrumented { class LogWriter(log: RequestLog) extends Runnable { val fields = new HttpFields - val conn = mock(classOf[HttpConnection]) + val conn = mock(classOf[AbstractHttpConnection]) when(conn.getRequestFields).thenReturn(fields) val request = new Request(conn) From 399aad451fd25acbc622ca3ee79d698d82a56700 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 2 Dec 2011 11:39:38 -0800 Subject: [PATCH 0051/2771] Added AssetServlet. It's a super-simple replacement for DefaultServlet, which didn't play nicely with fat JARs. --- .../dropwizard/modules/AssetsModule.java | 7 +- .../dropwizard/servlets/AssetServlet.java | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java b/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java index c44f1fabf58..71c41cdfcf5 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java @@ -2,7 +2,7 @@ import com.yammer.dropwizard.Module; import com.yammer.dropwizard.config.Environment; -import org.eclipse.jetty.servlet.DefaultServlet; +import com.yammer.dropwizard.servlets.AssetServlet; import static com.google.common.base.Preconditions.checkArgument; @@ -38,9 +38,6 @@ public AssetsModule(String path) { @Override public void initialize(Environment environment) { - environment.addServlet(DefaultServlet.class, path + '*') - .setInitParam("dirAllowed", "false") - .setInitParam("pathInfoOnly", "true") - .setInitParam("relativeResourceBase", path); + environment.addServlet(new AssetServlet(path), path + '*'); } } diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java new file mode 100644 index 00000000000..c6494a23b6c --- /dev/null +++ b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java @@ -0,0 +1,71 @@ +package com.yammer.dropwizard.servlets; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.io.Resources; +import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.util.URIUtil; + +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +public class AssetServlet extends HttpServlet { + private static final long serialVersionUID = 6393345594784987908L; + + private static class AssetLoader extends CacheLoader { + private final String base; + + private AssetLoader(String base) { + this.base = base; + } + + @Override + public byte[] load(String key) throws Exception { + final String path = URIUtil.canonicalPath(key); + if (path.startsWith(base)) { + return Resources.toByteArray(Resources.getResource(path.substring(1))); + } else { + throw new RuntimeException("nope"); + } + } + } + + private final Cache cache; + private final MimeTypes mimeTypes; + + public AssetServlet(String base) { + this.cache = buildCache(base); + this.mimeTypes = new MimeTypes(); + } + + private static Cache buildCache(String base) { + return CacheBuilder.newBuilder() + .maximumSize(100) + .concurrencyLevel(16) + .expireAfterAccess(10, TimeUnit.MINUTES) + .build(new AssetLoader(base)); + } + + @Override + protected void doGet(HttpServletRequest req, + HttpServletResponse resp) throws ServletException, IOException { + try { + final byte[] resource = cache.getUnchecked(req.getRequestURI()); + resp.setContentType(mimeTypes.getMimeByExtension(req.getRequestURI()).toString()); + final ServletOutputStream output = resp.getOutputStream(); + try { + output.write(resource); + } finally { + output.close(); + } + } catch (RuntimeException ignored) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + } + } +} From 07b2015371b955e96938836ca9af9c22814136eb Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 2 Dec 2011 11:45:11 -0800 Subject: [PATCH 0052/2771] Expose the max cache size. --- .../dropwizard/modules/AssetsModule.java | 29 ++++++++++++++++--- .../dropwizard/servlets/AssetServlet.java | 11 +++---- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java b/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java index 71c41cdfcf5..ee408519cd8 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java @@ -10,16 +10,20 @@ * A module for serving static asset files from the classpath. */ public class AssetsModule implements Module { + public static final String DEFAULT_PATH = "/assets"; + public static final int DEFAULT_MAX_CACHE_SIZE = 100; + private final String path; + private final int maxCacheSize; /** * Creates a new {@link AssetsModule} which serves up static assets from * {@code src/main/resources/assets/*} as {@code /assets/*}. * - * @see AssetsModule#AssetsModule(String) + * @see AssetsModule#AssetsModule(String, int) */ public AssetsModule() { - this("/assets"); + this(DEFAULT_PATH, DEFAULT_MAX_CACHE_SIZE); } /** @@ -28,16 +32,33 @@ public AssetsModule() { * {@code path} of {@code "/assets"}, {@code src/main/resources/assets/example.js} would be * served up from {@code /assets/example.js}. * - * @param path the classpath and URI root of the static asset files + * @param path the classpath and URI root of the static asset files + * @see AssetsModule#AssetsModule(String, int) */ public AssetsModule(String path) { + this(path, DEFAULT_MAX_CACHE_SIZE); + } + + /** + * Creates a new {@link AssetsModule} which will configure the service to serve the static files + * located in {@code src/main/resources/${path}} as {@code /${path}}. For example, given a + * {@code path} of {@code "/assets"}, {@code src/main/resources/assets/example.js} would be + * served up from {@code /assets/example.js}. + * + * @param path the classpath and URI root of the static asset files + * @param maxCacheSize the maximum number of resources to cache + */ + public AssetsModule(String path, int maxCacheSize) { checkArgument(path.startsWith("/"), "%s is not an absolute path", path); checkArgument(!"/".equals(path), "%s is the classpath root"); this.path = path.endsWith("/") ? path : (path + '/'); + this.maxCacheSize = maxCacheSize; } + + @Override public void initialize(Environment environment) { - environment.addServlet(new AssetServlet(path), path + '*'); + environment.addServlet(new AssetServlet(path, maxCacheSize), path + '*'); } } diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java index c6494a23b6c..f01eb29141c 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java @@ -13,7 +13,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.concurrent.TimeUnit; public class AssetServlet extends HttpServlet { private static final long serialVersionUID = 6393345594784987908L; @@ -39,16 +38,14 @@ public byte[] load(String key) throws Exception { private final Cache cache; private final MimeTypes mimeTypes; - public AssetServlet(String base) { - this.cache = buildCache(base); + public AssetServlet(String base, int maxCacheSize) { + this.cache = buildCache(base, maxCacheSize); this.mimeTypes = new MimeTypes(); } - private static Cache buildCache(String base) { + private static Cache buildCache(String base, int maxCacheSize) { return CacheBuilder.newBuilder() - .maximumSize(100) - .concurrencyLevel(16) - .expireAfterAccess(10, TimeUnit.MINUTES) + .maximumSize(maxCacheSize) .build(new AssetLoader(base)); } From 3de8164a72e14cc11f2d8cec9d6ca10473e1f1c6 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 2 Dec 2011 16:53:22 -0800 Subject: [PATCH 0053/2771] Don't log EofExceptions when writing JSON. --- .../yammer/dropwizard/jersey/JacksonMessageBodyProvider.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java index 9e64768f658..5e139d8322f 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableList; import com.yammer.dropwizard.json.Json; import com.yammer.dropwizard.validation.Validator; +import org.eclipse.jetty.io.EofException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -113,6 +114,8 @@ public void writeTo(Object t, OutputStream entityStream) throws IOException, WebApplicationException { try { Json.write(entityStream, t); + } catch (EofException ignored) { + // we don't care about these } catch (IOException e) { LOGGER.error("Error writing response", e); } From 0b2dc86ef74091a830e059c8a1aa6084549b525a Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 2 Dec 2011 16:54:29 -0800 Subject: [PATCH 0054/2771] Fix encoding for Optional query params. --- ...MultivaluedParameterExtractorQueryParamInjectable.java | 8 ++++---- .../jersey/OptionalQueryParamInjectableProvider.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/MultivaluedParameterExtractorQueryParamInjectable.java b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/MultivaluedParameterExtractorQueryParamInjectable.java index 3aae7765ceb..df9ddc90be7 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/MultivaluedParameterExtractorQueryParamInjectable.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/MultivaluedParameterExtractorQueryParamInjectable.java @@ -11,18 +11,18 @@ public class MultivaluedParameterExtractorQueryParamInjectable extends AbstractHttpContextInjectable { private final MultivaluedParameterExtractor extractor; - private final boolean isEncoded; + private final boolean decode; public MultivaluedParameterExtractorQueryParamInjectable(MultivaluedParameterExtractor extractor, - boolean encoded) { + boolean decode) { this.extractor = extractor; - isEncoded = encoded; + this.decode = decode; } @Override public Object getValue(HttpContext c) { try { - return extractor.extract(c.getUriInfo().getQueryParameters(isEncoded)); + return extractor.extract(c.getUriInfo().getQueryParameters(decode)); } catch (ExtractorContainerException e) { throw new ParamException.QueryParamException(e.getCause(), extractor.getName(), diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OptionalQueryParamInjectableProvider.java b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OptionalQueryParamInjectableProvider.java index 220be7b68eb..aed7312c261 100644 --- a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OptionalQueryParamInjectableProvider.java +++ b/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OptionalQueryParamInjectableProvider.java @@ -29,7 +29,7 @@ public Injectable getInjectable(ComponentContext ic, c.getParameterClass().isAssignableFrom(Optional.class)) { return new MultivaluedParameterExtractorQueryParamInjectable( new OptionalExtractor(parameterName, c.getDefaultValue()), - c.isEncoded() + !c.isEncoded() ); } return null; From 3a0f9d412e5d864a6f02a07eb33acdab75abcb5d Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 2 Dec 2011 17:18:37 -0800 Subject: [PATCH 0055/2771] Use @NotEmpty over @NotNull for Strings. --- .../com/example/helloworld/HelloWorldConfiguration.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldConfiguration.java b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldConfiguration.java index 4e0a57e1cf1..363fcc7027c 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldConfiguration.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldConfiguration.java @@ -2,14 +2,13 @@ import com.example.helloworld.core.Template; import com.yammer.dropwizard.config.Configuration; - -import javax.validation.constraints.NotNull; +import org.hibernate.validator.constraints.NotEmpty; public class HelloWorldConfiguration extends Configuration { - @NotNull + @NotEmpty private String template; - @NotNull + @NotEmpty private String defaultName = "Stranger"; public String getTemplate() { From 76b2a44790d773ff724fb1625b40d845fadcdf27 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 2 Dec 2011 17:18:56 -0800 Subject: [PATCH 0056/2771] Holy crap documentation. --- docs/css/bootstrap.min.css | 356 ++++++++++++++++ docs/css/prettify.css | 105 +++++ docs/getting-started.html | 838 +++++++++++++++++++++++++++++++++++++ docs/index.html | 156 +++++++ docs/js/lang-yaml.js | 2 + docs/js/prettify.js | 28 ++ docs/manual.html | 68 +++ 7 files changed, 1553 insertions(+) create mode 100644 docs/css/bootstrap.min.css create mode 100644 docs/css/prettify.css create mode 100644 docs/getting-started.html create mode 100644 docs/index.html create mode 100644 docs/js/lang-yaml.js create mode 100644 docs/js/prettify.js create mode 100644 docs/manual.html diff --git a/docs/css/bootstrap.min.css b/docs/css/bootstrap.min.css new file mode 100644 index 00000000000..e2f7c4ae358 --- /dev/null +++ b/docs/css/bootstrap.min.css @@ -0,0 +1,356 @@ +html,body{margin:0;padding:0;} +h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,cite,code,del,dfn,em,img,q,s,samp,small,strike,strong,sub,sup,tt,var,dd,dl,dt,li,ol,ul,fieldset,form,label,legend,button,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;font-weight:normal;font-style:normal;font-size:100%;line-height:1;font-family:inherit;} +table{border-collapse:collapse;border-spacing:0;} +ol,ul{list-style:none;} +q:before,q:after,blockquote:before,blockquote:after{content:"";} +html{overflow-y:scroll;font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} +a:focus{outline:thin dotted;} +a:hover,a:active{outline:0;} +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} +audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} +audio:not([controls]){display:none;} +sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;} +sup{top:-0.5em;} +sub{bottom:-0.25em;} +img{border:0;-ms-interpolation-mode:bicubic;} +button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;} +button,input{line-height:normal;*overflow:visible;} +button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;} +button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} +input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;} +input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;} +textarea{overflow:auto;vertical-align:top;} +body{background-color:#ffffff;margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;color:#404040;} +.container{width:940px;margin-left:auto;margin-right:auto;zoom:1;}.container:before,.container:after{display:table;content:"";zoom:1;} +.container:after{clear:both;} +.container-fluid{position:relative;min-width:940px;padding-left:20px;padding-right:20px;zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";zoom:1;} +.container-fluid:after{clear:both;} +.container-fluid>.sidebar{position:absolute;top:0;left:20px;width:220px;} +.container-fluid>.content{margin-left:240px;} +a{color:#0069d6;text-decoration:none;line-height:inherit;font-weight:inherit;}a:hover{color:#00438a;text-decoration:underline;} +.pull-right{float:right;} +.pull-left{float:left;} +.hide{display:none;} +.show{display:block;} +.row{zoom:1;margin-left:-20px;}.row:before,.row:after{display:table;content:"";zoom:1;} +.row:after{clear:both;} +.row>[class*="span"]{display:inline;float:left;margin-left:20px;} +.span1{width:40px;} +.span2{width:100px;} +.span3{width:160px;} +.span4{width:220px;} +.span5{width:280px;} +.span6{width:340px;} +.span7{width:400px;} +.span8{width:460px;} +.span9{width:520px;} +.span10{width:580px;} +.span11{width:640px;} +.span12{width:700px;} +.span13{width:760px;} +.span14{width:820px;} +.span15{width:880px;} +.span16{width:940px;} +.span17{width:1000px;} +.span18{width:1060px;} +.span19{width:1120px;} +.span20{width:1180px;} +.span21{width:1240px;} +.span22{width:1300px;} +.span23{width:1360px;} +.span24{width:1420px;} +.row>.offset1{margin-left:80px;} +.row>.offset2{margin-left:140px;} +.row>.offset3{margin-left:200px;} +.row>.offset4{margin-left:260px;} +.row>.offset5{margin-left:320px;} +.row>.offset6{margin-left:380px;} +.row>.offset7{margin-left:440px;} +.row>.offset8{margin-left:500px;} +.row>.offset9{margin-left:560px;} +.row>.offset10{margin-left:620px;} +.row>.offset11{margin-left:680px;} +.row>.offset12{margin-left:740px;} +.span-one-third{width:300px;} +.span-two-thirds{width:620px;} +.row>.offset-one-third{margin-left:340px;} +.row>.offset-two-thirds{margin-left:660px;} +p{font-size:13px;font-weight:normal;line-height:18px;margin-bottom:9px;}p small{font-size:11px;color:#bfbfbf;} +h1,h2,h3,h4,h5,h6{font-weight:bold;color:#404040;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{color:#bfbfbf;} +h1{margin-bottom:18px;font-size:30px;line-height:36px;}h1 small{font-size:18px;} +h2{font-size:24px;line-height:36px;}h2 small{font-size:14px;} +h3,h4,h5,h6{line-height:36px;} +h3{font-size:18px;}h3 small{font-size:14px;} +h4{font-size:16px;}h4 small{font-size:12px;} +h5{font-size:14px;} +h6{font-size:13px;color:#bfbfbf;text-transform:uppercase;} +ul,ol{margin:0 0 18px 25px;} +ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} +ul{list-style:disc;} +ol{list-style:decimal;} +li{line-height:18px;color:#808080;} +ul.unstyled{list-style:none;margin-left:0;} +dl{margin-bottom:18px;}dl dt,dl dd{line-height:18px;} +dl dt{font-weight:bold;} +dl dd{margin-left:9px;} +hr{margin:20px 0 19px;border:0;border-bottom:1px solid #eee;} +strong{font-style:inherit;font-weight:bold;} +em{font-style:italic;font-weight:inherit;line-height:inherit;} +.muted{color:#bfbfbf;} +blockquote{margin-bottom:18px;border-left:5px solid #eee;padding-left:15px;}blockquote p{font-size:14px;font-weight:300;line-height:18px;margin-bottom:0;} +blockquote small{display:block;font-size:12px;font-weight:300;line-height:18px;color:#bfbfbf;}blockquote small:before{content:'\2014 \00A0';} +address{display:block;line-height:18px;margin-bottom:18px;} +code,pre{padding:0 3px 2px;font-family:Monaco, Andale Mono, Courier New, monospace;font-size:12px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +code{background-color:#fee9cc;color:rgba(0, 0, 0, 0.75);padding:1px 3px;} +pre{background-color:#f5f5f5;display:block;padding:8.5px;margin:0 0 18px;line-height:18px;font-size:12px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +form{margin-bottom:18px;} +fieldset{margin-bottom:18px;padding-top:18px;}fieldset legend{display:block;padding-left:150px;font-size:19.5px;line-height:1;color:#404040;*padding:0 0 5px 145px;*line-height:1.5;} +form .clearfix{margin-bottom:18px;zoom:1;}form .clearfix:before,form .clearfix:after{display:table;content:"";zoom:1;} +form .clearfix:after{clear:both;} +label,input,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:normal;} +label{padding-top:6px;font-size:13px;line-height:18px;float:left;width:130px;text-align:right;color:#404040;} +form .input{margin-left:150px;} +input[type=checkbox],input[type=radio]{cursor:pointer;} +input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;font-size:13px;line-height:18px;color:#808080;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +select{padding:initial;} +input[type=checkbox],input[type=radio]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:none;} +input[type=file]{background-color:#ffffff;padding:initial;border:initial;line-height:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +input[type=button],input[type=reset],input[type=submit]{width:auto;height:auto;} +select,input[type=file]{height:27px;*height:auto;line-height:27px;*margin-top:4px;} +select[multiple]{height:inherit;background-color:#ffffff;} +textarea{height:auto;} +.uneditable-input{background-color:#ffffff;display:block;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} +:-moz-placeholder{color:#bfbfbf;} +::-webkit-input-placeholder{color:#bfbfbf;} +input,textarea{-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);} +input:focus,textarea:focus{outline:0;border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);} +input[type=file]:focus,input[type=checkbox]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:1px dotted #666;} +form .clearfix.error>label,form .clearfix.error .help-block,form .clearfix.error .help-inline{color:#b94a48;} +form .clearfix.error input,form .clearfix.error textarea{color:#b94a48;border-color:#ee5f5b;}form .clearfix.error input:focus,form .clearfix.error textarea:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} +form .clearfix.error .input-prepend .add-on,form .clearfix.error .input-append .add-on{color:#b94a48;background-color:#fce6e6;border-color:#b94a48;} +form .clearfix.warning>label,form .clearfix.warning .help-block,form .clearfix.warning .help-inline{color:#c09853;} +form .clearfix.warning input,form .clearfix.warning textarea{color:#c09853;border-color:#ccae64;}form .clearfix.warning input:focus,form .clearfix.warning textarea:focus{border-color:#be9a3f;-webkit-box-shadow:0 0 6px #e5d6b1;-moz-box-shadow:0 0 6px #e5d6b1;box-shadow:0 0 6px #e5d6b1;} +form .clearfix.warning .input-prepend .add-on,form .clearfix.warning .input-append .add-on{color:#c09853;background-color:#d2b877;border-color:#c09853;} +form .clearfix.success>label,form .clearfix.success .help-block,form .clearfix.success .help-inline{color:#468847;} +form .clearfix.success input,form .clearfix.success textarea{color:#468847;border-color:#57a957;}form .clearfix.success input:focus,form .clearfix.success textarea:focus{border-color:#458845;-webkit-box-shadow:0 0 6px #9acc9a;-moz-box-shadow:0 0 6px #9acc9a;box-shadow:0 0 6px #9acc9a;} +form .clearfix.success .input-prepend .add-on,form .clearfix.success .input-append .add-on{color:#468847;background-color:#bcddbc;border-color:#468847;} +.input-mini,input.mini,textarea.mini,select.mini{width:60px;} +.input-small,input.small,textarea.small,select.small{width:90px;} +.input-medium,input.medium,textarea.medium,select.medium{width:150px;} +.input-large,input.large,textarea.large,select.large{width:210px;} +.input-xlarge,input.xlarge,textarea.xlarge,select.xlarge{width:270px;} +.input-xxlarge,input.xxlarge,textarea.xxlarge,select.xxlarge{width:530px;} +textarea.xxlarge{overflow-y:auto;} +input.span1,textarea.span1{display:inline-block;float:none;width:30px;margin-left:0;} +input.span2,textarea.span2{display:inline-block;float:none;width:90px;margin-left:0;} +input.span3,textarea.span3{display:inline-block;float:none;width:150px;margin-left:0;} +input.span4,textarea.span4{display:inline-block;float:none;width:210px;margin-left:0;} +input.span5,textarea.span5{display:inline-block;float:none;width:270px;margin-left:0;} +input.span6,textarea.span6{display:inline-block;float:none;width:330px;margin-left:0;} +input.span7,textarea.span7{display:inline-block;float:none;width:390px;margin-left:0;} +input.span8,textarea.span8{display:inline-block;float:none;width:450px;margin-left:0;} +input.span9,textarea.span9{display:inline-block;float:none;width:510px;margin-left:0;} +input.span10,textarea.span10{display:inline-block;float:none;width:570px;margin-left:0;} +input.span11,textarea.span11{display:inline-block;float:none;width:630px;margin-left:0;} +input.span12,textarea.span12{display:inline-block;float:none;width:690px;margin-left:0;} +input.span13,textarea.span13{display:inline-block;float:none;width:750px;margin-left:0;} +input.span14,textarea.span14{display:inline-block;float:none;width:810px;margin-left:0;} +input.span15,textarea.span15{display:inline-block;float:none;width:870px;margin-left:0;} +input.span16,textarea.span16{display:inline-block;float:none;width:930px;margin-left:0;} +input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;} +.actions{background:#f5f5f5;margin-top:18px;margin-bottom:18px;padding:17px 20px 18px 150px;border-top:1px solid #ddd;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;}.actions .secondary-action{float:right;}.actions .secondary-action a{line-height:30px;}.actions .secondary-action a:hover{text-decoration:underline;} +.help-inline,.help-block{font-size:13px;line-height:18px;color:#bfbfbf;} +.help-inline{padding-left:5px;*position:relative;*top:-5px;} +.help-block{display:block;max-width:600px;} +.inline-inputs{color:#808080;}.inline-inputs span{padding:0 2px 0 1px;} +.input-prepend input,.input-append input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.input-prepend .add-on,.input-append .add-on{position:relative;background:#f5f5f5;border:1px solid #ccc;z-index:2;float:left;display:block;width:auto;min-width:16px;height:18px;padding:4px 4px 4px 5px;margin-right:-1px;font-weight:normal;line-height:18px;color:#bfbfbf;text-align:center;text-shadow:0 1px 0 #ffffff;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-prepend .active,.input-append .active{background:#a9dba9;border-color:#46a546;} +.input-prepend .add-on{*margin-top:1px;} +.input-append input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-append .add-on{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;margin-right:0;margin-left:-1px;} +.inputs-list{margin:0 0 5px;width:100%;}.inputs-list li{display:block;padding:0;width:100%;} +.inputs-list label{display:block;float:none;width:auto;padding:0;margin-left:20px;line-height:18px;text-align:left;white-space:normal;}.inputs-list label strong{color:#808080;} +.inputs-list label small{font-size:11px;font-weight:normal;} +.inputs-list .inputs-list{margin-left:25px;margin-bottom:10px;padding-top:0;} +.inputs-list:first-child{padding-top:6px;} +.inputs-list li+li{padding-top:2px;} +.inputs-list input[type=radio],.inputs-list input[type=checkbox]{margin-bottom:0;margin-left:-20px;float:left;} +.form-stacked{padding-left:20px;}.form-stacked fieldset{padding-top:9px;} +.form-stacked legend{padding-left:0;} +.form-stacked label{display:block;float:none;width:auto;font-weight:bold;text-align:left;line-height:20px;padding-top:0;} +.form-stacked .clearfix{margin-bottom:9px;}.form-stacked .clearfix div.input{margin-left:0;} +.form-stacked .inputs-list{margin-bottom:0;}.form-stacked .inputs-list li{padding-top:0;}.form-stacked .inputs-list li label{font-weight:normal;padding-top:0;} +.form-stacked div.clearfix.error{padding-top:10px;padding-bottom:10px;padding-left:10px;margin-top:0;margin-left:-10px;} +.form-stacked .actions{margin-left:-20px;padding-left:20px;} +table{width:100%;margin-bottom:18px;padding:0;font-size:13px;border-collapse:collapse;}table th,table td{padding:10px 10px 9px;line-height:18px;text-align:left;} +table th{padding-top:9px;font-weight:bold;vertical-align:middle;} +table td{vertical-align:top;border-top:1px solid #ddd;} +table tbody th{border-top:1px solid #ddd;vertical-align:top;} +.condensed-table th,.condensed-table td{padding:5px 5px 4px;} +.bordered-table{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.bordered-table th+th,.bordered-table td+td,.bordered-table th+td{border-left:1px solid #ddd;} +.bordered-table thead tr:first-child th:first-child,.bordered-table tbody tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;} +.bordered-table thead tr:first-child th:last-child,.bordered-table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;} +.bordered-table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;} +.bordered-table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;} +table .span1{width:20px;} +table .span2{width:60px;} +table .span3{width:100px;} +table .span4{width:140px;} +table .span5{width:180px;} +table .span6{width:220px;} +table .span7{width:260px;} +table .span8{width:300px;} +table .span9{width:340px;} +table .span10{width:380px;} +table .span11{width:420px;} +table .span12{width:460px;} +table .span13{width:500px;} +table .span14{width:540px;} +table .span15{width:580px;} +table .span16{width:620px;} +.zebra-striped tbody tr:nth-child(odd) td,.zebra-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} +.zebra-striped tbody tr:hover td,.zebra-striped tbody tr:hover th{background-color:#f5f5f5;} +table .header{cursor:pointer;}table .header:after{content:"";float:right;margin-top:7px;border-width:0 4px 4px;border-style:solid;border-color:#000 transparent;visibility:hidden;} +table .headerSortUp,table .headerSortDown{background-color:rgba(141, 192, 219, 0.25);text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);} +table .header:hover:after{visibility:visible;} +table .headerSortDown:after,table .headerSortDown:hover:after{visibility:visible;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;} +table .headerSortUp:after{border-bottom:none;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000;visibility:visible;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;} +table .blue{color:#049cdb;border-bottom-color:#049cdb;} +table .headerSortUp.blue,table .headerSortDown.blue{background-color:#ade6fe;} +table .green{color:#46a546;border-bottom-color:#46a546;} +table .headerSortUp.green,table .headerSortDown.green{background-color:#cdeacd;} +table .red{color:#9d261d;border-bottom-color:#9d261d;} +table .headerSortUp.red,table .headerSortDown.red{background-color:#f4c8c5;} +table .yellow{color:#ffc40d;border-bottom-color:#ffc40d;} +table .headerSortUp.yellow,table .headerSortDown.yellow{background-color:#fff6d9;} +table .orange{color:#f89406;border-bottom-color:#f89406;} +table .headerSortUp.orange,table .headerSortDown.orange{background-color:#fee9cc;} +table .purple{color:#7a43b6;border-bottom-color:#7a43b6;} +table .headerSortUp.purple,table .headerSortDown.purple{background-color:#e2d5f0;} +.topbar{height:40px;position:fixed;top:0;left:0;right:0;z-index:10000;overflow:visible;}.topbar a{color:#bfbfbf;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} +.topbar h3 a:hover,.topbar .brand:hover,.topbar ul .active>a{background-color:#333;background-color:rgba(255, 255, 255, 0.05);color:#ffffff;text-decoration:none;} +.topbar h3{position:relative;} +.topbar h3 a,.topbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;color:#ffffff;font-size:20px;font-weight:200;line-height:1;} +.topbar p{margin:0;line-height:40px;}.topbar p a:hover{background-color:transparent;color:#ffffff;} +.topbar form{float:left;margin:5px 0 0 0;position:relative;filter:alpha(opacity=100);-khtml-opacity:1;-moz-opacity:1;opacity:1;} +.topbar form.pull-right{float:right;} +.topbar input{background-color:#444;background-color:rgba(255, 255, 255, 0.3);font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:normal;font-weight:13px;line-height:1;padding:4px 9px;color:#ffffff;color:rgba(255, 255, 255, 0.75);border:1px solid #111;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.topbar input:-moz-placeholder{color:#e6e6e6;} +.topbar input::-webkit-input-placeholder{color:#e6e6e6;} +.topbar input:hover{background-color:#bfbfbf;background-color:rgba(255, 255, 255, 0.5);color:#ffffff;} +.topbar input:focus,.topbar input.focused{outline:0;background-color:#ffffff;color:#404040;text-shadow:0 1px 0 #ffffff;border:0;padding:5px 10px;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);} +.topbar-inner,.topbar .fill{background-color:#222;background-color:#222222;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#333333), to(#222222));background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #333333), color-stop(100%, #222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);} +.topbar div>ul,.nav{display:block;float:left;margin:0 10px 0 0;position:relative;left:0;}.topbar div>ul>li,.nav>li{display:block;float:left;} +.topbar div>ul a,.nav a{display:block;float:none;padding:10px 10px 11px;line-height:19px;text-decoration:none;}.topbar div>ul a:hover,.nav a:hover{color:#ffffff;text-decoration:none;} +.topbar div>ul .active>a,.nav .active>a{background-color:#222;background-color:rgba(0, 0, 0, 0.5);} +.topbar div>ul.secondary-nav,.nav.secondary-nav{float:right;margin-left:10px;margin-right:0;}.topbar div>ul.secondary-nav .menu-dropdown,.nav.secondary-nav .menu-dropdown,.topbar div>ul.secondary-nav .dropdown-menu,.nav.secondary-nav .dropdown-menu{right:0;border:0;} +.topbar div>ul a.menu:hover,.nav a.menu:hover,.topbar div>ul li.open .menu,.nav li.open .menu,.topbar div>ul .dropdown-toggle:hover,.nav .dropdown-toggle:hover,.topbar div>ul .dropdown.open .dropdown-toggle,.nav .dropdown.open .dropdown-toggle{background:#444;background:rgba(255, 255, 255, 0.05);} +.topbar div>ul .menu-dropdown,.nav .menu-dropdown,.topbar div>ul .dropdown-menu,.nav .dropdown-menu{background-color:#333;}.topbar div>ul .menu-dropdown a.menu,.nav .menu-dropdown a.menu,.topbar div>ul .dropdown-menu a.menu,.nav .dropdown-menu a.menu,.topbar div>ul .menu-dropdown .dropdown-toggle,.nav .menu-dropdown .dropdown-toggle,.topbar div>ul .dropdown-menu .dropdown-toggle,.nav .dropdown-menu .dropdown-toggle{color:#ffffff;}.topbar div>ul .menu-dropdown a.menu.open,.nav .menu-dropdown a.menu.open,.topbar div>ul .dropdown-menu a.menu.open,.nav .dropdown-menu a.menu.open,.topbar div>ul .menu-dropdown .dropdown-toggle.open,.nav .menu-dropdown .dropdown-toggle.open,.topbar div>ul .dropdown-menu .dropdown-toggle.open,.nav .dropdown-menu .dropdown-toggle.open{background:#444;background:rgba(255, 255, 255, 0.05);} +.topbar div>ul .menu-dropdown li a,.nav .menu-dropdown li a,.topbar div>ul .dropdown-menu li a,.nav .dropdown-menu li a{color:#999;text-shadow:0 1px 0 rgba(0, 0, 0, 0.5);}.topbar div>ul .menu-dropdown li a:hover,.nav .menu-dropdown li a:hover,.topbar div>ul .dropdown-menu li a:hover,.nav .dropdown-menu li a:hover{background-color:#191919;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#292929), to(#191919));background-image:-moz-linear-gradient(top, #292929, #191919);background-image:-ms-linear-gradient(top, #292929, #191919);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #292929), color-stop(100%, #191919));background-image:-webkit-linear-gradient(top, #292929, #191919);background-image:-o-linear-gradient(top, #292929, #191919);background-image:linear-gradient(top, #292929, #191919);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#292929', endColorstr='#191919', GradientType=0);color:#ffffff;} +.topbar div>ul .menu-dropdown .active a,.nav .menu-dropdown .active a,.topbar div>ul .dropdown-menu .active a,.nav .dropdown-menu .active a{color:#ffffff;} +.topbar div>ul .menu-dropdown .divider,.nav .menu-dropdown .divider,.topbar div>ul .dropdown-menu .divider,.nav .dropdown-menu .divider{background-color:#222;border-color:#444;} +.topbar ul .menu-dropdown li a,.topbar ul .dropdown-menu li a{padding:4px 15px;} +li.menu,.dropdown{position:relative;} +a.menu:after,.dropdown-toggle:after{width:0;height:0;display:inline-block;content:"↓";text-indent:-99999px;vertical-align:top;margin-top:8px;margin-left:4px;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #ffffff;filter:alpha(opacity=50);-khtml-opacity:0.5;-moz-opacity:0.5;opacity:0.5;} +.menu-dropdown,.dropdown-menu{background-color:#ffffff;float:left;display:none;position:absolute;top:40px;z-index:900;min-width:160px;max-width:220px;_width:160px;margin-left:0;margin-right:0;padding:6px 0;zoom:1;border-color:#999;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:0 1px 1px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.menu-dropdown li,.dropdown-menu li{float:none;display:block;background-color:none;} +.menu-dropdown .divider,.dropdown-menu .divider{height:1px;margin:5px 0;overflow:hidden;background-color:#eee;border-bottom:1px solid #ffffff;} +.topbar .dropdown-menu a,.dropdown-menu a{display:block;padding:4px 15px;clear:both;font-weight:normal;line-height:18px;color:#808080;text-shadow:0 1px 0 #ffffff;}.topbar .dropdown-menu a:hover,.dropdown-menu a:hover,.topbar .dropdown-menu a.hover,.dropdown-menu a.hover{background-color:#dddddd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#eeeeee), to(#dddddd));background-image:-moz-linear-gradient(top, #eeeeee, #dddddd);background-image:-ms-linear-gradient(top, #eeeeee, #dddddd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #eeeeee), color-stop(100%, #dddddd));background-image:-webkit-linear-gradient(top, #eeeeee, #dddddd);background-image:-o-linear-gradient(top, #eeeeee, #dddddd);background-image:linear-gradient(top, #eeeeee, #dddddd);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#dddddd', GradientType=0);color:#404040;text-decoration:none;-webkit-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);} +.open .menu,.dropdown.open .menu,.open .dropdown-toggle,.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);} +.open .menu-dropdown,.dropdown.open .menu-dropdown,.open .dropdown-menu,.dropdown.open .dropdown-menu{display:block;} +.tabs,.pills{margin:0 0 18px;padding:0;list-style:none;zoom:1;}.tabs:before,.pills:before,.tabs:after,.pills:after{display:table;content:"";zoom:1;} +.tabs:after,.pills:after{clear:both;} +.tabs>li,.pills>li{float:left;}.tabs>li>a,.pills>li>a{display:block;} +.tabs{border-color:#ddd;border-style:solid;border-width:0 0 1px;}.tabs>li{position:relative;margin-bottom:-1px;}.tabs>li>a{padding:0 15px;margin-right:2px;line-height:34px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.tabs>li>a:hover{text-decoration:none;background-color:#eee;border-color:#eee #eee #ddd;} +.tabs .active>a,.tabs .active>a:hover{color:#808080;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} +.tabs .menu-dropdown,.tabs .dropdown-menu{top:35px;border-width:1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;} +.tabs a.menu:after,.tabs .dropdown-toggle:after{border-top-color:#999;margin-top:15px;margin-left:5px;} +.tabs li.open.menu .menu,.tabs .open.dropdown .dropdown-toggle{border-color:#999;} +.tabs li.open a.menu:after,.tabs .dropdown.open .dropdown-toggle:after{border-top-color:#555;} +.pills a{margin:5px 3px 5px 0;padding:0 15px;line-height:30px;text-shadow:0 1px 1px #ffffff;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}.pills a:hover{color:#ffffff;text-decoration:none;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#00438a;} +.pills .active a{color:#ffffff;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#0069d6;} +.pills-vertical>li{float:none;} +.tab-content>.tab-pane,.pill-content>.pill-pane,.tab-content>div,.pill-content>div{display:none;} +.tab-content>.active,.pill-content>.active{display:block;} +.breadcrumb{padding:7px 14px;margin:0 0 18px;background-color:#f5f5f5;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ffffff), to(#f5f5f5));background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline;text-shadow:0 1px 0 #ffffff;} +.breadcrumb .divider{padding:0 5px;color:#bfbfbf;} +.breadcrumb .active a{color:#404040;} +.hero-unit{background-color:#f5f5f5;margin-bottom:30px;padding:60px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;} +.hero-unit p{font-size:18px;font-weight:200;line-height:27px;} +footer{margin-top:17px;padding-top:17px;border-top:1px solid #eee;} +.page-header{margin-bottom:17px;border-bottom:1px solid #ddd;-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}.page-header h1{margin-bottom:8px;} +.btn.danger,.alert-message.danger,.btn.danger:hover,.alert-message.danger:hover,.btn.error,.alert-message.error,.btn.error:hover,.alert-message.error:hover,.btn.success,.alert-message.success,.btn.success:hover,.alert-message.success:hover,.btn.info,.alert-message.info,.btn.info:hover,.alert-message.info:hover{color:#ffffff;} +.btn .close,.alert-message .close{font-family:Arial,sans-serif;line-height:18px;} +.btn.danger,.alert-message.danger,.btn.error,.alert-message.error{background-color:#c43c35;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#c43c35 #c43c35 #882a25;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} +.btn.success,.alert-message.success{background-color:#57a957;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#57a957 #57a957 #3d773d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} +.btn.info,.alert-message.info{background-color:#339bb9;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#339bb9 #339bb9 #22697d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} +.btn{cursor:pointer;display:inline-block;background-color:#e6e6e6;background-repeat:no-repeat;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);padding:5px 14px 6px;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);color:#333;font-size:13px;line-height:normal;border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-webkit-transition:0.1s linear all;-moz-transition:0.1s linear all;-ms-transition:0.1s linear all;-o-transition:0.1s linear all;transition:0.1s linear all;}.btn:hover{background-position:0 -15px;color:#333;text-decoration:none;} +.btn:focus{outline:1px dotted #666;} +.btn.primary{color:#ffffff;background-color:#0064cd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd));background-image:-moz-linear-gradient(top, #049cdb, #0064cd);background-image:-ms-linear-gradient(top, #049cdb, #0064cd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd));background-image:-webkit-linear-gradient(top, #049cdb, #0064cd);background-image:-o-linear-gradient(top, #049cdb, #0064cd);background-image:linear-gradient(top, #049cdb, #0064cd);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#0064cd #0064cd #003f81;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} +.btn.active,.btn:active{-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);} +.btn.disabled{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn[disabled]{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn.large{font-size:15px;line-height:normal;padding:9px 14px 9px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.btn.small{padding:7px 9px 7px;font-size:11px;} +:root .alert-message,:root .btn{border-radius:0 \0;} +button.btn::-moz-focus-inner,input[type=submit].btn::-moz-focus-inner{padding:0;border:0;} +.close{float:right;color:#000000;font-size:20px;font-weight:bold;line-height:13.5px;text-shadow:0 1px 0 #ffffff;filter:alpha(opacity=25);-khtml-opacity:0.25;-moz-opacity:0.25;opacity:0.25;}.close:hover{color:#000000;text-decoration:none;filter:alpha(opacity=40);-khtml-opacity:0.4;-moz-opacity:0.4;opacity:0.4;} +.alert-message{position:relative;padding:7px 15px;margin-bottom:18px;color:#404040;background-color:#eedc94;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94));background-image:-moz-linear-gradient(top, #fceec1, #eedc94);background-image:-ms-linear-gradient(top, #fceec1, #eedc94);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94));background-image:-webkit-linear-gradient(top, #fceec1, #eedc94);background-image:-o-linear-gradient(top, #fceec1, #eedc94);background-image:linear-gradient(top, #fceec1, #eedc94);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#eedc94 #eedc94 #e4c652;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);border-width:1px;border-style:solid;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);}.alert-message .close{margin-top:1px;*margin-top:0;} +.alert-message a{font-weight:bold;color:#404040;} +.alert-message.danger p a,.alert-message.error p a,.alert-message.success p a,.alert-message.info p a{color:#ffffff;} +.alert-message h5{line-height:18px;} +.alert-message p{margin-bottom:0;} +.alert-message div{margin-top:5px;margin-bottom:2px;line-height:28px;} +.alert-message .btn{-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);} +.alert-message.block-message{background-image:none;background-color:#fdf5d9;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);padding:14px;border-color:#fceec1;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}.alert-message.block-message ul,.alert-message.block-message p{margin-right:30px;} +.alert-message.block-message ul{margin-bottom:0;} +.alert-message.block-message li{color:#404040;} +.alert-message.block-message .alert-actions{margin-top:5px;} +.alert-message.block-message.error,.alert-message.block-message.success,.alert-message.block-message.info{color:#404040;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} +.alert-message.block-message.error{background-color:#fddfde;border-color:#fbc7c6;} +.alert-message.block-message.success{background-color:#d1eed1;border-color:#bfe7bf;} +.alert-message.block-message.info{background-color:#ddf4fb;border-color:#c6edf9;} +.alert-message.block-message.danger p a,.alert-message.block-message.error p a,.alert-message.block-message.success p a,.alert-message.block-message.info p a{color:#404040;} +.pagination{height:36px;margin:18px 0;}.pagination ul{float:left;margin:0;border:1px solid #ddd;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} +.pagination li{display:inline;} +.pagination a{float:left;padding:0 14px;line-height:34px;border-right:1px solid;border-right-color:#ddd;border-right-color:rgba(0, 0, 0, 0.15);*border-right-color:#ddd;text-decoration:none;} +.pagination a:hover,.pagination .active a{background-color:#c7eefe;} +.pagination .disabled a,.pagination .disabled a:hover{background-color:transparent;color:#bfbfbf;} +.pagination .next a{border:0;} +.well{background-color:#f5f5f5;margin-bottom:20px;padding:19px;min-height:20px;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} +.modal-backdrop{background-color:#000000;position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000;}.modal-backdrop.fade{opacity:0;} +.modal-backdrop,.modal-backdrop.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;} +.modal{position:fixed;top:50%;left:50%;z-index:11000;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal .close{margin-top:7px;} +.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} +.modal.fade.in{top:50%;} +.modal-header{border-bottom:1px solid #eee;padding:5px 15px;} +.modal-body{padding:15px;} +.modal-body form{margin-bottom:0;} +.modal-footer{background-color:#f5f5f5;padding:14px 15px 15px;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;zoom:1;margin-bottom:0;}.modal-footer:before,.modal-footer:after{display:table;content:"";zoom:1;} +.modal-footer:after{clear:both;} +.modal-footer .btn{float:right;margin-left:5px;} +.modal .popover,.modal .twipsy{z-index:12000;} +.twipsy{display:block;position:absolute;visibility:visible;padding:5px;font-size:11px;z-index:1000;filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;}.twipsy.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;} +.twipsy.above .twipsy-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.twipsy.left .twipsy-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} +.twipsy.below .twipsy-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} +.twipsy.right .twipsy-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} +.twipsy-inner{padding:3px 8px;background-color:#000000;color:white;text-align:center;max-width:200px;text-decoration:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.twipsy-arrow{position:absolute;width:0;height:0;} +.popover{position:absolute;top:0;left:0;z-index:1000;padding:5px;display:none;}.popover.above .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} +.popover.below .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} +.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} +.popover .arrow{position:absolute;width:0;height:0;} +.popover .inner{background:#000000;background:rgba(0, 0, 0, 0.8);padding:3px;overflow:hidden;width:280px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);} +.popover .title{background-color:#f5f5f5;padding:9px 15px;line-height:1;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;border-bottom:1px solid #eee;} +.popover .content{background-color:#ffffff;padding:14px;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover .content p,.popover .content ul,.popover .content ol{margin-bottom:0;} +.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;} +.label{padding:1px 3px 2px;font-size:9.75px;font-weight:bold;color:#ffffff;text-transform:uppercase;white-space:nowrap;background-color:#bfbfbf;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}.label.important{background-color:#c43c35;} +.label.warning{background-color:#f89406;} +.label.success{background-color:#46a546;} +.label.notice{background-color:#62cffc;} +.media-grid{margin-left:-20px;margin-bottom:0;zoom:1;}.media-grid:before,.media-grid:after{display:table;content:"";zoom:1;} +.media-grid:after{clear:both;} +.media-grid li{display:inline;} +.media-grid a{float:left;padding:4px;margin:0 0 18px 20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);}.media-grid a img{display:block;} +.media-grid a:hover{border-color:#0069d6;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} diff --git a/docs/css/prettify.css b/docs/css/prettify.css new file mode 100644 index 00000000000..37734743d9b --- /dev/null +++ b/docs/css/prettify.css @@ -0,0 +1,105 @@ +.com { color: #93a1a1; } +.lit { color: #195f91; } +.pun, .opn, .clo { color: #93a1a1; } +.fun { color: #dc322f; } +.str, .atv { color: #268bd2; } +.kwd, .tag { color: #195f91; } +.typ, .atn, .dec, .var { color: #CB4B16; } +.pln { color: #93a1a1; } +.prettyprint { + overflow: scroll; + background-color: #fefbf3; + padding: 9px; + border: 1px solid rgba(0,0,0,.2); + -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.1); + -moz-box-shadow: 0 1px 2px rgba(0,0,0,.1); + box-shadow: 0 1px 2px rgba(0,0,0,.1); +} + +.uglyprint { + overflow: scroll; + background-color: #fefbf3; + padding: 9px; + border: 1px solid rgba(0, 0, 0, .2); + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .1); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, .1); + box-shadow: 0 1px 2px rgba(0, 0, 0, .1); +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin: 0 0 0 40px; +} +/* IE indents via margin-left */ +ol.linenums li { + padding: 0 5px; + color: rgba(0,0,0,.15); + line-height: 20px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +/* Alternate shading for lines */ +li.L1, li.L3, li.L5, li.L7, li.L9 { } + +/* +$base03: #002b36; +$base02: #073642; +$base01: #586e75; +$base00: #657b83; +$base0: #839496; +$base1: #93a1a1; +$base2: #eee8d5; +$base3: #fdf6e3; +$yellow: #b58900; +$orange: #cb4b16; +$red: #dc322f; +$magenta: #d33682; +$violet: #6c71c4; +$blue: #268bd2; +$cyan: #2aa198; +$green: #859900; +*/ + + +/* +#1d1f21 Background +#282a2e Current Line +#373b41 Selection +#c5c8c6 Foreground +#969896 Comment +#cc6666 Red +#de935f Orange +#f0c674 Yellow +#b5bd68 Green +#8abeb7 Aqua +#81a2be Blue +#b294bb Purple +*/ + + +/* DARK THEME */ +/* ---------- */ + +.prettyprint-dark { + background-color: #1d1f21; + border: 0; + padding: 10px; +} +.prettyprint-dark .linenums li { + color: #444; +} +.prettyprint-dark .linenums li:hover { + background-color: #282a2e; +} +/* tags in html */ +.prettyprint-dark .kwd, +.prettyprint-dark .tag { color: #cc6666; } +/* html attr */ +.prettyprint-dark .typ, +.prettyprint-dark .atn, +.prettyprint-dark .dec, +.prettyprint-dark .var { color: #de935f; } +/* html attr values */ +.prettyprint-dark .str, +.prettyprint-dark .atv { color: #b5bd68; } diff --git a/docs/getting-started.html b/docs/getting-started.html new file mode 100644 index 00000000000..73b6b1a3ba8 --- /dev/null +++ b/docs/getting-started.html @@ -0,0 +1,838 @@ + + + + + Getting Started | Dropwizard + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+

Getting Started

+ +

+ The goal of this document is to guide you through the process of creating a simple + Dropwizard project: Hello World. Along the way, we‘ll explain the various underlying + libraries and their roles, important concepts in Dropwizard, and suggest some + organizational techniques to help you as your project grows. (Or you can just skip to + the fun part.) +

+ +

Overview

+ +

+ Dropwizard straddles the line between being a library and a framework. Its goal is to + provide performant, reliable implementations of everything a production-ready web + service needs. Because this functionality is extracted into a reusable library, your + service remains lean and focused, reducing both time-to-market and maintenance burdens. +

+ +

+ Because you can't be a web service without HTTP, Dropwizard uses the + Jetty HTTP library to embed an incredibly + tuned HTTP server directly into your project. Instead of handing your service off to + a complicated application server, Dropwizard projects have a main method + which spins up an HTTP server. Running your service as a simple process eliminates a + number of unsavory aspects of Java in production (no PermGem issues, no application + server configuration and maintenance, no arcane deployment tools, no + ClassLoader troubles, no hidden application logs, no trying to tune a + single garbage collector to work with multiple application workloads) and allows you + to use all of Unix's existing process management tools instead. +

+ +

+ For building RESTful web services, + we've found nothing beats Jersey + (the JAX-RS reference implementation) + in terms of features or performance. It allows you to write clean, testable class which + gracefully map HTTP requests to simple Java objects. It supports streaming output, + matrix URI parameters, conditional GET requests, and much, much more. +

+ +

+ In terms of data formats, JSON has become the web‘s lingua franca, and + Jackson is the king of JSON on the JVM. In + addition to being lightning fast, it has a sophisticated object mapper, allowing you to + export your domain models directly. +

+ +

+ Our very own Metrics + library rounds things out, providing you with unparalleled insight into your code‘s + behavior in your production environment. +

+ +

+ In addition to Jetty, Jersey, and Jackson, Dropwizard also includes a number of + libraries that we've come to rely on: +

+ +
    +
  • + Guava, + which, in addition to highly optimized immutable data structures, provides a growing + number of classes to speed up development in Java. +
  • +
  • + Log4j and + slf4j for performant logging. +
  • +
  • + Hibernate Validator, + the JSR-303 reference + implementation, provides an easy, declarative framework for validating user input + and generating helpful, internationalizable error messages. +
  • +
  • + Apache HttpClient + and Jersey's client library allow for both low- and high-level interaction with + other web services. +
  • +
  • + JDBI is the most straight-forward way to use a + relational database with Java. +
  • +
  • + Freemarker is a simple template + system for more user-facing services. +
  • +
+ +

+ Now that you've gotten the lay of the land, let's dig in! +

+ +
+ +

Setting Up Maven

+ +

+ We recommend you use Maven for new Dropwizard + services. If you're a big + Ant/Ivy, + Buildr, + Gradle, + SBT, + or Gant fan, that‘s cool, but we use Maven and + we'll be using Maven as we go through this example service. If you have any questions + about how Maven works, + Maven: The Complete Reference + should have what you‘re looking for. (We‘re assuming you know how to create a new + Maven project.) +

+ +

+ First off, add the repository where the Dropwizard JARs are hosted: +

+ +
+<repositories>
+    <repository>
+        <id>repo.codahale.com</id>
+        <url>http://repo.codahale.com</url>
+    </repository>
+</repositories>
+ +

+ Second, add the dropwizard library as a dependency: +

+ +
+<dependencies>
+    <dependency>
+        <groupId>com.yammer</groupId>
+        <artifactId>dropwizard</artifactId>
+        <version>0.1.0-SNAPSHOT</version>
+    </dependency>
+</dependencies>
+ +

+ Alright, that‘s enough XML. We‘ve got a Maven project set up now, and it‘s time to start + writing real code. +

+ +
+ +

Creating A Configuration Class

+ +

+ Each Dropwizard service has its own subclass of the Configuration class + which specify environment-specific parameters. These parameters are specified in a + YAML configuration file which is deserialized to + an instance of your service‘s configuration class and validated. +

+ +

+ The service we‘re building is a high-performance Hello World service, and part of our + requirements is that we need to be able to vary how it says hello from environment to + environment. We‘ll need to specify at least two things to begin with: a template for + saying hello and a default name to use in case the user doesn‘t specify their name. +

+ +

+ Here's what our configuration class will look like: +

+ +
+package com.example.helloworld;
+
+import com.yammer.dropwizard.config.Configuration;
+import org.hibernate.validator.constraints.NotEmpty;
+
+public class HelloWorldConfiguration extends Configuration {
+    @NotEmpty
+    private String template;
+
+    @NotEmpty
+    private String defaultName = "Stranger";
+
+    public String getTemplate() {
+        return template;
+    }
+
+    public String getDefaultName() {
+        return defaultName;
+    }
+}
+

+ There's a lot going on here, so let‘s unpack a bit of it. +

+ +

+ When this class is deserialized from the YAML file, it will pull two root-level fields + from the YAML object: template, the template for our Hello World saying, + and defaultName, the default name to use. Both template and + defaultName are annotated with @NotEmpty, so if the YAML + configuration file has blank values for either or is missing template + entirely an informative exception will be thrown and your service won‘t start. +

+ +

+ Our YAML file, then, will look like this: +

+ +
+template: Hello, %s!
+defaultName: Stranger
+ +

+ Dropwizard has a lot more configuration parameters than that, but they all have + sane defaults so you can keep your configuration files small and focused. +

+ +

+ So save that YAML file as hello-world.yml, because we‘ll be getting up + and running pretty soon and we‘ll need it. Next up, we‘re creating our service class! +

+ +
+ +

Creating A Service Class

+ +

+ Combined with your project‘s Configuration subclass, its + Service form the core of your Dropwizard service. The Service + class pulls together the various modules and commands which provide basic functionality. + (More on that later.) For now, though, our HelloWorldService looks like + this: +

+ +
+package com.example.helloworld;
+
+import com.yammer.dropwizard.Service;
+import com.yammer.dropwizard.config.Environment;
+
+public class HelloWorldService extends Service<HelloWorldConfiguration> {
+    public static void main(String[] args) throws Exception {
+        new HelloWorldService().run(args);
+    }
+
+    private HelloWorldService() {
+        super("hello-world");
+    }
+
+    @Override
+    protected void initialize(HelloWorldConfiguration configuration,
+                              Environment environment) {
+        // nothing to do yet
+    }
+
+}
+ +

+ As you can see, HelloWorldService is parameterized with the service‘s + configuration type, HelloWorldConfiguration. + HelloWorldService‘s constructor provides the service‘s name: + hello-world. Also, we‘ve added a static main + method, which will be our service‘s entry point. Right now, we don‘t have any + functionality implemented, so our initialize method is a little boring. + Let‘s fix that! +

+ +
+ +

Creating A Representation Class

+ +

+ Before we can get into the nuts-and-bolts of our Hello World service, we need to stop + and think about our API. Luckily, our service needs to conform to an industry standard, + RFC 1149, + which specifies the following JSON representation of a Hello World saying: +

+ +
+{
+  "id": 1,
+  "content": "Hello, stranger!"
+}
+ +

+ The id field is a unique identifier for the saying, and + content is the textual representation of the saying. (Thankfully, this is a + fairly straight-forward industry standard.) +

+ +

+ To model this representation, we'll create a representation class: +

+ +
+package com.example.helloworld.core;
+
+public class Saying {
+    private final long id;
+    private final String content;
+
+    public Saying(long id, String content) {
+        this.id = id;
+        this.content = content;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public String getContent() {
+        return content;
+    }
+}
+ +

+ This is a pretty simple POJO, but there are a few things worth noting here. +

+ +

+ First, it‘s immutable. This makes Saying instances very easy to + reason about multi-threaded environments as well as single-threaded environments. + Second, it uses the Java Bean standard for the id and code + properties. This allows Jackson to serialize it to the JSON we need. The Jackson object + mapping code will populate the id field of the JSON object with the return + value of getId(), likewise with content and + getContent(). +

+ +

+ Now that we‘ve got our representation class, it makes sense to start in on the resource + it represents. +

+ +
+ +

Creating A Resource Class

+ +

+ Jersey resources are the meat-and-potatoes of a Dropwizard service. Each resource class + is associated with a URI template. For + our service, we need a resource which returns new Saying instances from + the URI /hello-world, so our resource class will look like this: +

+ +
+package com.example.helloworld.resources;
+
+import com.example.helloworld.core.Saying;
+import com.google.common.base.Optional;
+import com.yammer.metrics.Metrics;
+import com.yammer.metrics.core.TimerContext;
+import com.yammer.metrics.core.TimerMetric;
+
+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 java.util.concurrent.atomic.AtomicLong;
+
+import static java.lang.String.format;
+
+@Path("/hello-world")
+@Produces(MediaType.APPLICATION_JSON)
+public class HelloWorldResource {
+    private static final TimerMetric GETS = Metrics.newTimer(HelloWorldResource.class,
+                                                             "get-requests");
+
+    private final String template;
+    private final String defaultName;
+    private final AtomicLong counter;
+
+    public HelloWorldResource(String template, String defaultName) {
+        this.template = template;
+        this.defaultName = defaultName;
+        this.counter = new AtomicLong();
+    }
+
+    @GET
+    public Saying sayHello(@QueryParam("name") Optional<String> name) {
+        final TimerContext context = GETS.time();
+        try {
+            return new Saying(counter.incrementAndGet(), format(template, name.or(defaultName)));
+        } finally {
+            context.stop();
+        }
+    }
+}
+ +

+ Finally, we‘re in the thick of it! Let‘s start from the top and work our way down. +

+ +

+ HelloWorldResource has two annotations: @Path and + @Produces. @Path("/hello-world") tells Jersey that this + resource is accessible at the URI /hello-world, and + @Produces(MediaType.APPLICATION_JSON) lets Jersey‘s content negotiation + code know that this resource produces representations which are + application/json. +

+ +

+ GETS is a TimerMetric from the Metrics library which we use + to monitor both the latency and rate of GET requests for this resource. +

+ +

+ HelloWorldResource takes two parameters for construction: the + template it uses to produce the saying and the defaultName + used when the user declines to tell us their name. An AtomicLong provides + us with a cheap, thread-safe way of generating unique(ish) IDs. (N.B.: + resource classes are used by multiple threads concurrently. In general, we recommend + that resources be stateless/immutable, but it‘s important to keep the context in mind.) +

+ +

+ sayHello(Optional<String>) is the meat of this class, and it‘s a + fairly simple method. The @QueryParam("name") tells Jersey to map the + name parameter from the query string to the name parameter + in the method. If the client sends a request to /hello-world?name=Dougie, + sayHello will be called with Optional.of("Dougie"); if there + is no name parameter in the query string, sayHello will be + called with Option.absent(). (Support for Guava's Optional + is a little extra sauce that Dropwizard adds to Jersey's existing functionality.) +

+ +

+ Inside the sayHello method, we get a TimerContext from the + timer, which allows us to measure now much time each request takes and how many requests + per second our service is doing at any point in time. We increment the counter, format + the template using String.format(String, Object...), and return a new + Saying instance. +

+ +

+ Once sayHello has returned, Jersey takes the Saying instance + and looks for a provider class which can write Saying instances as + application/json. Dropwizard has one such provider built in which allows + for producing and consuming Java objects as JSON objects. The provider writes out the + JSON and the client receives a 200 OK response with a content type of + application/json. +

+ +

+ Before that will actually work, though, we need to go back to our + HelloWorldService and add this new resource class. In its + initialize method we can read the template and default name from the + HelloWorldConfiguration instance, create a new + HelloWorldService instance, and then add it to the service‘s environment: +

+ +
+@Override
+protected void initialize(HelloWorldConfiguration configuration,
+                          Environment environment) {
+    final String template = configuration.getTemplate();
+    final String defaultName = configuration.getDefaultName();
+    environment.addResource(new HelloWorldResource(template, defaultName));
+}
+ +

+ When our service starts, we create a new instance of our resource class with the + parameters from the configuration file and hand it off to the Environment, + which acts like a registry of all the things your service can do. +

+ +

+ Before we go too far, we should add a health check for our service. +

+ +
+ +

Adding A Health Check

+ +

+ Health checks give you a way of adding small tests to your service to allow you and your + ops team to verify that your service is functioning correctly in production. We + strongly recommend that all of your services have at least a minimal + set of health checks. (We recommend this so strongly, in fact, that Dropwizard will nag + you should you neglect to add a health check to your project.) +

+ +

+ Since formatting strings is not likely to fail while a service is running (unlike, + say, a database connection pool), we‘ll have to get a little creative here. We‘ll add + a health check to make sure we can actually format the provided template: +

+ +
+package com.example.helloworld.health;
+
+import com.yammer.metrics.core.HealthCheck;
+
+import static java.lang.String.format;
+
+public class TemplateHealthCheck extends HealthCheck {
+    private final String template;
+
+    public TemplateHealthCheck(String template) {
+        this.template = template;
+    }
+
+    @Override
+    public String name() {
+        return "template";
+    }
+
+    @Override
+    public Result check() throws Exception {
+        final String saying = format(template, "TEST");
+        if (!saying.contains("TEST")) {
+            return Result.unhealthy("template doesn't include a name");
+        }
+        return Result.healthy();
+    }
+}
+ +

+ TemplateHealthCheck checks for two things: that the provided template is + actually a well-formed format string, and that the template actually produces output + with the given name. +

+ +

+ If the string is not a well-formed format string (for example, someone accidentally put + Hello, %s% in the configuration file), then + String.format(String, Object...) will throw an + IllegalFormatException and the health check will implicitly fail. If the + rendered saying doesn‘t include the test string, the health check will explicitly fail + by returning an unhealthy Result. +

+ +

+ As with most things in Dropwizard, we create a new instance with the appropriate + parameters and add it to the Environment: +

+ +
+@Override
+protected void initialize(HelloWorldConfiguration configuration,
+                          Environment environment) {
+    final String template = configuration.getTemplate();
+    final String defaultName = configuration.getDefaultName();
+    environment.addResource(new HelloWorldResource(template, defaultName));
+    environment.addHealthCheck(new TemplateHealthCheck(template));
+}
+ +

+ Now we're almost ready to go! +

+ +
+ +

Building Fat JARs

+ +

+ We recommend that you build your Dropwizard services as “fat†JAR files—single + .jar files which contain all of the .class files + required to run your service. This allows you to build a single deployable artifact + which you can copy from your staging environment to your QA environment to your + production environment without worrying about differences in installed libraries. To + start building our Hello World service as a fat JAR, we need to configure a Maven plugin + called maven-shade. In your pom.xml file, add this: +

+ +
+<plugin>
+    <groupId>org.apache.maven.plugins</groupId>
+    <artifactId>maven-shade-plugin</artifactId>
+    <version>1.4</version>
+    <configuration>
+        <createDependencyReducedPom>true</createDependencyReducedPom>
+    </configuration>
+    <executions>
+        <execution>
+            <phase>package</phase>
+            <goals>
+                <goal>shade</goal>
+            </goals>
+            <configuration>
+                <transformers>
+                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                        <mainClass>com.example.helloworld.HelloWorldService</mainClass>
+                    </transformer>
+                </transformers>
+            </configuration>
+        </execution>
+    </executions>
+</plugin>
+        
+ +

+ This configures Maven to do a couple of things during its package phase: +

+ +
    +
  • + Produce a pom.xml file which doesn‘t include dependencies for the + libraries whose contents are included in the fat JAR. +
  • +
  • + Collate the various META-INF/services entries in the JARs instead of + overwriting them. (N.B.: Jersey doesn‘t work without those.) +
  • +
  • + Set com.example.helloworld.HelloWorldService as the JAR‘s + MainClass. +
  • +
+ +

+ Once you‘ve got that configured, go into your project directory and run + mvn package (or run the package goal from your IDE). You + should see something like this: +

+ +
+[INFO] Including org.eclipse.jetty:jetty-util:jar:7.6.0.RC0 in the shaded jar.
+[INFO] Including com.google.guava:guava:jar:10.0.1 in the shaded jar.
+[INFO] Including com.google.code.findbugs:jsr305:jar:1.3.9 in the shaded jar.
+[INFO] Including org.hibernate:hibernate-validator:jar:4.2.0.Final in the shaded jar.
+[INFO] Including javax.validation:validation-api:jar:1.0.0.GA in the shaded jar.
+[INFO] Including org.yaml:snakeyaml:jar:1.9 in the shaded jar.
+[INFO] Replacing original artifact with shaded artifact.
+[INFO] Replacing /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT.jar with /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT-shaded.jar
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD SUCCESS
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 8.415s
+[INFO] Finished at: Fri Dec 02 16:26:42 PST 2011
+[INFO] Final Memory: 11M/81M
+[INFO] ------------------------------------------------------------------------
+ +

+ Congratulations! You‘ve built your first Dropwizard project! Now it‘s + time to run it! +

+ +
+ +

Running Your Service

+ +

+ Now that you‘ve built a JAR file, it‘s time to run it. +

+ +

+ In your project directory, run + java -jar target/hello-world-0.0.1-SNAPSHOT.jar. You should see something + like the following: +

+ +
+java -jar dropwizard-example-0.1.0-SNAPSHOT.jar <command> [arg1 arg2]
+
+Commands
+========
+
+server: Starts an HTTP server running the service
+-------------------------------------------------
+usage: java -jar dropwizard-example-0.1.0-SNAPSHOT.jar server <config
+            file>
+ -h, --help   display usage information
+ +

+ Dropwizard takes the first command line argument and dispatches it to a matching + command. In this case, the only command available is server, which runs + your service as an HTTP server. The server command requires a configuration + file, so let‘s go ahead and give it + the one we previous saved: + java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml +

+ +

+ You should see something like the following: +

+ +
+INFO  [2011-12-03 00:38:32,927] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world
+INFO  [2011-12-03 00:38:32,931] org.eclipse.jetty.server.Server: jetty-7.x.y-SNAPSHOT
+INFO  [2011-12-03 00:38:32,936] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null}
+INFO  [2011-12-03 00:38:32,999] com.sun.jersey.server.impl.application.WebApplicationImpl: Initiating Jersey application, version 'Jersey: 1.10 11/02/2011 03:53 PM'
+INFO  [2011-12-03 00:38:33,041] com.yammer.dropwizard.config.Environment:
+
+    GET     /hello-world (com.example.helloworld.resources.HelloWorldResource)
+
+INFO  [2011-12-03 00:38:33,215] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null}
+INFO  [2011-12-03 00:38:33,235] org.eclipse.jetty.server.AbstractConnector: Started BlockingChannelConnector@0.0.0.0:8080 STARTING
+INFO  [2011-12-03 00:38:33,238] org.eclipse.jetty.server.AbstractConnector: Started SocketConnector@0.0.0.0:8081 STARTING
+ +

+ Your Dropwizard service is now listening on ports 8080 for service requests + and 8081 for administration requests. If you press + ^C, the service will shut down gracefully, first closing + the server socket, then allowing a few seconds for in-flight requests to be processed, + then shutting down the process itself. +

+ +

+ But while it‘s up, let‘s give it a whirl! + Click here to say hello! + Click here to get even friendlier! +

+ +

+ So, we‘re generating sayings. Awesome. But that‘s not all your service can do. One of + the main reasons for using Dropwizard is the out-of-the-box operational tools it + provides, all of which can be found + on the admin port. +

+ +

+ If you click through to + metrics, you can see all of + your service‘s metrics represented as a JSON object. +

+ +

+ The threads resource allows + you to quickly get a thread dump of all the threads running in that process. +

+ +

+ The healthcheck + resource runs the TemplateHealthCheck instance we + wrote. You should see something like this: +

+ +
+* deadlocks: OK
+* template: OK
+ +

+ template here is the result of your TemplateHealthCheck, which + unsurprisingly passed. deadlocks is a built-in health check which looks for + deadlocked JVM threads and prints out a listing if any are found. +

+ +
+ +

Next Steps

+ +

+ Well, congratulations. You‘ve got a Hello World service ready for production (except for + the lack of tests) that‘s capable of doing 15,000-20,000 requests per second. Hopefully + you've gotten a feel for how Dropwizard combines Jetty, Jersey, Jackson, and other + stable, mature libraries to provide a phenomenal platform for developing RESTful web + services. +

+ +

+ There‘s a lot more to Dropwizard than is covered here (commands, modules, servlets, + advanced configuration, validation, HTTP clients, database clients, templates, etc.), + all of which is covered in by Dropwizard's manual. +

+ +

Learn more about Dropwizard »

+ +

Learn more about Maven »

+ +

Learn more about Jetty »

+ +

Learn more about Jersey »

+ +

Learn more about Jackson »

+ +

Learn more about YAML »

+ +
+

© Yammer 2011

+
+
+
+ + + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000000..d268b9302f7 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,156 @@ + + + + + Dropwizard + + + + + + + + + + + + + +
+ +
+
+
+ +
+

Meet Dropwizard.

+ +

+ + Dropwizard is a Java framework for developing ops-friendly, + high-performance, RESTful web services. + +

+ +

+ Developed by Yammer to power their + JVM-based backend services, Dropwizard pulls together stable, mature + libraries from the Java ecosystem into a simple, light-weight package that + lets you focus on getting things done. +

+ +

+ Dropwizard has out-of-the-box support for sophisticated application metrics, + logging, operational tools, and much more, allowing you and your team to + ship a production-quality HTTP+JSON web service in the shortest time + possible. +

+ +

Get started »

+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

© Yammer 2011

+
+
+
+ + + diff --git a/docs/js/lang-yaml.js b/docs/js/lang-yaml.js new file mode 100644 index 00000000000..c38729b6cfb --- /dev/null +++ b/docs/js/lang-yaml.js @@ -0,0 +1,2 @@ +var a=null; +PR.registerLangHandler(PR.createSimpleLexer([["pun",/^[:>?|]+/,a,":|>?"],["dec",/^%(?:YAML|TAG)[^\n\r#]+/,a,"%"],["typ",/^&\S+/,a,"&"],["typ",/^!\S*/,a,"!"],["str",/^"(?:[^"\\]|\\.)*(?:"|$)/,a,'"'],["str",/^'(?:[^']|'')*(?:'|$)/,a,"'"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^\s+/,a," \t\r\n"]],[["dec",/^(?:---|\.\.\.)(?:[\n\r]|$)/],["pun",/^-/],["kwd",/^\w+:[\n\r ]/],["pln",/^\w+/]]),["yaml","yml"]); diff --git a/docs/js/prettify.js b/docs/js/prettify.js new file mode 100644 index 00000000000..eef5ad7e6a0 --- /dev/null +++ b/docs/js/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p + + + + Getting Started | Dropwizard + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+

Manual

+

+ coming soon +

+ +
+

© Yammer 2011

+
+
+
+ + + From 1df7006aa9e485993bab7effd86aacdbfc024d24 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 2 Dec 2011 22:23:00 -0800 Subject: [PATCH 0057/2771] Add some titles to break up the flow a bit. --- docs/getting-started.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/getting-started.html b/docs/getting-started.html index 73b6b1a3ba8..30cf35cbf36 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -80,6 +80,8 @@

Overview

service needs. Because this functionality is extracted into a reusable library, your service remains lean and focused, reducing both time-to-market and maintenance burdens.

+ +

Jetty for HTTP

Because you can't be a web service without HTTP, Dropwizard uses the @@ -93,6 +95,8 @@

Overview

single garbage collector to work with multiple application workloads) and allows you to use all of Unix's existing process management tools instead.

+ +

Jersey for REST

For building RESTful web services, @@ -102,6 +106,8 @@

Overview

gracefully map HTTP requests to simple Java objects. It supports streaming output, matrix URI parameters, conditional GET requests, and much, much more.

+ +

Jackson for JSON

In terms of data formats, JSON has become the web‘s lingua franca, and @@ -109,12 +115,16 @@

Overview

addition to being lightning fast, it has a sophisticated object mapper, allowing you to export your domain models directly.

+ +

Metrics for metrics (duh)

Our very own Metrics library rounds things out, providing you with unparalleled insight into your code‘s behavior in your production environment.

+ +

And Friends

In addition to Jetty, Jersey, and Jackson, Dropwizard also includes a number of From 83b2a0f3b2c92604a1113a67282947a42019eae6 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 5 Dec 2011 14:06:53 -0800 Subject: [PATCH 0058/2771] Added support for ImmutableLists to dw-db. --- dropwizard-db/pom.xml | 9 +++++- .../com/yammer/dropwizard/db/Database.java | 1 + .../db/ImmutableListContainerFactory.java | 32 +++++++++++++++++++ .../dropwizard/db/tests/DatabaseTest.java | 13 +++++++- .../yammer/dropwizard/db/tests/PersonDAO.java | 4 +++ 5 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/ImmutableListContainerFactory.java diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index d1dc23aec5e..eceda43fcab 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -14,6 +14,13 @@ dropwizard-db Dropwizard Database Client + + + sonatype-nexus-snapshots + http://oss.sonatype.org/content/repositories/snapshots + + + com.yammer @@ -23,7 +30,7 @@ org.jdbi jdbi - 2.27 + 2.28-SNAPSHOT org.apache.tomcat diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index f6c730a4cbf..1896fe951fa 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -33,6 +33,7 @@ public Database(DataSource dataSource, ObjectPool pool) { setStatementRewriter(new NamePrependingStatementRewriter()); setStatementLocator(new ScopedStatementLocator()); registerArgumentFactory(new OptionalArgumentFactory()); + registerContainerFactory(new ImmutableListContainerFactory()); } @Override diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/ImmutableListContainerFactory.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/ImmutableListContainerFactory.java new file mode 100644 index 00000000000..fe2ed8d0076 --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/ImmutableListContainerFactory.java @@ -0,0 +1,32 @@ +package com.yammer.dropwizard.db; + +import com.google.common.collect.ImmutableList; +import org.skife.jdbi.v2.ContainerBuilder; +import org.skife.jdbi.v2.tweak.ContainerFactory; + +public class ImmutableListContainerFactory implements ContainerFactory> { + @Override + public boolean accepts(Class type) { + return ImmutableList.class.isAssignableFrom(type); + } + + @Override + public ContainerBuilder> newContainerBuilderFor(Class type) { + return new ImmutableListContainerBuilder(); + } + + private static class ImmutableListContainerBuilder implements ContainerBuilder> { + private final ImmutableList.Builder builder = ImmutableList.builder(); + + @Override + public ContainerBuilder> add(Object it) { + builder.add(it); + return this; + } + + @Override + public ImmutableList build() { + return builder.build(); + } + } +} diff --git a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java index a1cf7bd6b54..a0b039ef637 100644 --- a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java +++ b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java @@ -93,7 +93,7 @@ public void managesTheDatabaseWithTheEnvironment() throws Exception { } @Test - public void sqlObjectsCanReturnImmutableLists() throws Exception { + public void sqlObjectsCanAcceptOptionalParams() throws Exception { final PersonDAO dao = database.open(PersonDAO.class); try { assertThat(dao.findByName(Optional.of("Coda Hale")), @@ -102,4 +102,15 @@ public void sqlObjectsCanReturnImmutableLists() throws Exception { database.close(dao); } } + + @Test + public void sqlObjectsCanReturnImmutableLists() throws Exception { + final PersonDAO dao = database.open(PersonDAO.class); + try { + assertThat(dao.findAllNames(), + is(ImmutableList.of("Coda Hale", "Kris Gale", "Old Guy"))); + } finally { + database.close(dao); + } + } } diff --git a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/PersonDAO.java b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/PersonDAO.java index fddbfe65013..c8a07908fd5 100644 --- a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/PersonDAO.java +++ b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/PersonDAO.java @@ -1,10 +1,14 @@ package com.yammer.dropwizard.db.tests; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; import org.skife.jdbi.v2.sqlobject.Bind; import org.skife.jdbi.v2.sqlobject.SqlQuery; public interface PersonDAO { @SqlQuery("SELECT name FROM people WHERE name = :name") public String findByName(@Bind("name") Optional name); + + @SqlQuery("SELECT name FROM people ORDER BY name ASC") + public ImmutableList findAllNames(); } From 92dae10413107904d3995905b3bbdff6c9dcae07 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 5 Dec 2011 17:13:58 -0800 Subject: [PATCH 0059/2771] Upgrade to JDBI 2.28 final. --- dropwizard-db/pom.xml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index eceda43fcab..7a081933472 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -14,13 +14,6 @@ dropwizard-db Dropwizard Database Client - - - sonatype-nexus-snapshots - http://oss.sonatype.org/content/repositories/snapshots - - - com.yammer @@ -30,7 +23,7 @@ org.jdbi jdbi - 2.28-SNAPSHOT + 2.28 org.apache.tomcat From 933be9abb384b44f8e909acae051064d287777df Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 5 Dec 2011 19:34:43 -0800 Subject: [PATCH 0060/2771] More docs work. --- docs/css/additional.css | 11 +++ docs/getting-started.html | 104 ++++++++++++++--------------- docs/index.html | 136 +++++++------------------------------- docs/manual.html | 36 ++++++---- 4 files changed, 109 insertions(+), 178 deletions(-) create mode 100644 docs/css/additional.css diff --git a/docs/css/additional.css b/docs/css/additional.css new file mode 100644 index 00000000000..a3582c66050 --- /dev/null +++ b/docs/css/additional.css @@ -0,0 +1,11 @@ +body { + padding-top: 60px; +} + +#blurb { + width: 760px ! important; +} + +#logo { + margin-top: 100px; +} diff --git a/docs/getting-started.html b/docs/getting-started.html index 30cf35cbf36..6cbb870a237 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -14,16 +14,8 @@ + - @@ -64,9 +56,9 @@
Getting Started

Getting Started

-

+

The goal of this document is to guide you through the process of creating a simple - Dropwizard project: Hello World. Along the way, we‘ll explain the various underlying + Dropwizard project: Hello World. Along the way, we’ll explain the various underlying libraries and their roles, important concepts in Dropwizard, and suggest some organizational techniques to help you as your project grows. (Or you can just skip to the fun part.) @@ -110,7 +102,7 @@

Jersey for REST

Jackson for JSON

- In terms of data formats, JSON has become the web‘s lingua franca, and + In terms of data formats, JSON has become the web’s lingua franca, and Jackson is the king of JSON on the JVM. In addition to being lightning fast, it has a sophisticated object mapper, allowing you to export your domain models directly. @@ -120,7 +112,7 @@

Metrics for metrics (duh)

Our very own Metrics - library rounds things out, providing you with unparalleled insight into your code‘s + library rounds things out, providing you with unparalleled insight into your code’s behavior in your production environment.

@@ -177,11 +169,11 @@

Setting Up Maven

Buildr, Gradle, SBT, - or Gant fan, that‘s cool, but we use Maven and + or Gant fan, that’s cool, but we use Maven and we'll be using Maven as we go through this example service. If you have any questions about how Maven works, Maven: The Complete Reference - should have what you‘re looking for. (We‘re assuming you know how to create a new + should have what you’re looking for. (We’re assuming you know how to create a new Maven project.)

@@ -211,7 +203,7 @@

Setting Up Maven

</dependencies>

- Alright, that‘s enough XML. We‘ve got a Maven project set up now, and it‘s time to start + Alright, that’s enough XML. We’ve got a Maven project set up now, and it’s time to start writing real code.

@@ -223,14 +215,14 @@

Creating A Configuration Class

Each Dropwizard service has its own subclass of the Configuration class which specify environment-specific parameters. These parameters are specified in a YAML configuration file which is deserialized to - an instance of your service‘s configuration class and validated. + an instance of your service’s configuration class and validated.

- The service we‘re building is a high-performance Hello World service, and part of our + The service we’re building is a high-performance Hello World service, and part of our requirements is that we need to be able to vary how it says hello from environment to - environment. We‘ll need to specify at least two things to begin with: a template for - saying hello and a default name to use in case the user doesn‘t specify their name. + environment. We’ll need to specify at least two things to begin with: a template for + saying hello and a default name to use in case the user doesn’t specify their name.

@@ -259,7 +251,7 @@

Creating A Configuration Class

} }

- There's a lot going on here, so let‘s unpack a bit of it. + There's a lot going on here, so let’s unpack a bit of it.

@@ -268,7 +260,7 @@

Creating A Configuration Class

and defaultName, the default name to use. Both template and defaultName are annotated with @NotEmpty, so if the YAML configuration file has blank values for either or is missing template - entirely an informative exception will be thrown and your service won‘t start. + entirely an informative exception will be thrown and your service won’t start.

@@ -285,8 +277,8 @@

Creating A Configuration Class

- So save that YAML file as hello-world.yml, because we‘ll be getting up - and running pretty soon and we‘ll need it. Next up, we‘re creating our service class! + So save that YAML file as hello-world.yml, because we’ll be getting up + and running pretty soon and we’ll need it. Next up, we’re creating our service class!


@@ -294,7 +286,7 @@

Creating A Configuration Class

Creating A Service Class

- Combined with your project‘s Configuration subclass, its + Combined with your project’s Configuration subclass, its Service form the core of your Dropwizard service. The Service class pulls together the various modules and commands which provide basic functionality. (More on that later.) For now, though, our HelloWorldService looks like @@ -325,13 +317,13 @@

Creating A Service Class

}

- As you can see, HelloWorldService is parameterized with the service‘s + As you can see, HelloWorldService is parameterized with the service’s configuration type, HelloWorldConfiguration. - HelloWorldService‘s constructor provides the service‘s name: - hello-world. Also, we‘ve added a static main - method, which will be our service‘s entry point. Right now, we don‘t have any + HelloWorldService’s constructor provides the service’s name: + hello-world. Also, we’ve added a static main + method, which will be our service’s entry point. Right now, we don’t have any functionality implemented, so our initialize method is a little boring. - Let‘s fix that! + Let’s fix that!


@@ -387,7 +379,7 @@

Creating A Representation Class

- First, it‘s immutable. This makes Saying instances very easy to + First, it’s immutable. This makes Saying instances very easy to reason about multi-threaded environments as well as single-threaded environments. Second, it uses the Java Bean standard for the id and code properties. This allows Jackson to serialize it to the JSON we need. The Jackson object @@ -397,7 +389,7 @@

Creating A Representation Class

- Now that we‘ve got our representation class, it makes sense to start in on the resource + Now that we’ve got our representation class, it makes sense to start in on the resource it represents.

@@ -458,14 +450,14 @@

Creating A Resource Class

}

- Finally, we‘re in the thick of it! Let‘s start from the top and work our way down. + Finally, we’re in the thick of it! Let’s start from the top and work our way down.

HelloWorldResource has two annotations: @Path and @Produces. @Path("/hello-world") tells Jersey that this resource is accessible at the URI /hello-world, and - @Produces(MediaType.APPLICATION_JSON) lets Jersey‘s content negotiation + @Produces(MediaType.APPLICATION_JSON) lets Jersey’s content negotiation code know that this resource produces representations which are application/json.

@@ -479,13 +471,17 @@

Creating A Resource Class

HelloWorldResource takes two parameters for construction: the template it uses to produce the saying and the defaultName used when the user declines to tell us their name. An AtomicLong provides - us with a cheap, thread-safe way of generating unique(ish) IDs. (N.B.: - resource classes are used by multiple threads concurrently. In general, we recommend - that resources be stateless/immutable, but it‘s important to keep the context in mind.) + us with a cheap, thread-safe way of generating unique(ish) IDs. +

+ +

+ Remember: Resource classes are used by multiple threads concurrently. + In general, we recommend that resources be stateless/immutable, but it’s important to + keep the context in mind.

- sayHello(Optional<String>) is the meat of this class, and it‘s a + sayHello(Optional<String>) is the meat of this class, and it’s a fairly simple method. The @QueryParam("name") tells Jersey to map the name parameter from the query string to the name parameter in the method. If the client sends a request to /hello-world?name=Dougie, @@ -517,7 +513,7 @@

Creating A Resource Class

HelloWorldService and add this new resource class. In its initialize method we can read the template and default name from the HelloWorldConfiguration instance, create a new - HelloWorldService instance, and then add it to the service‘s environment: + HelloWorldService instance, and then add it to the service’s environment:

@@ -553,7 +549,7 @@ 

Adding A Health Check

Since formatting strings is not likely to fail while a service is running (unlike, - say, a database connection pool), we‘ll have to get a little creative here. We‘ll add + say, a database connection pool), we’ll have to get a little creative here. We’ll add a health check to make sure we can actually format the provided template:

@@ -597,7 +593,7 @@

Adding A Health Check

Hello, %s% in the configuration file), then String.format(String, Object...) will throw an IllegalFormatException and the health check will implicitly fail. If the - rendered saying doesn‘t include the test string, the health check will explicitly fail + rendered saying doesn’t include the test string, the health check will explicitly fail by returning an unhealthy Result.

@@ -667,21 +663,21 @@

Building Fat JARs

  • - Produce a pom.xml file which doesn‘t include dependencies for the + Produce a pom.xml file which doesn’t include dependencies for the libraries whose contents are included in the fat JAR.
  • Collate the various META-INF/services entries in the JARs instead of - overwriting them. (N.B.: Jersey doesn‘t work without those.) + overwriting them. (Jersey doesn’t work without those.)
  • - Set com.example.helloworld.HelloWorldService as the JAR‘s + Set com.example.helloworld.HelloWorldService as the JAR’s MainClass.

- Once you‘ve got that configured, go into your project directory and run + Once you’ve got that configured, go into your project directory and run mvn package (or run the package goal from your IDE). You should see something like this:

@@ -704,7 +700,7 @@

Building Fat JARs

[INFO] ------------------------------------------------------------------------

- Congratulations! You‘ve built your first Dropwizard project! Now it‘s + Congratulations! You’ve built your first Dropwizard project! Now it’s time to run it!

@@ -713,7 +709,7 @@

Building Fat JARs

Running Your Service

- Now that you‘ve built a JAR file, it‘s time to run it. + Now that you’ve built a JAR file, it’s time to run it.

@@ -738,7 +734,7 @@

Running Your Service

Dropwizard takes the first command line argument and dispatches it to a matching command. In this case, the only command available is server, which runs your service as an HTTP server. The server command requires a configuration - file, so let‘s go ahead and give it + file, so let’s go ahead and give it the one we previous saved: java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml

@@ -769,13 +765,13 @@

Running Your Service

- But while it‘s up, let‘s give it a whirl! + But while it’s up, let’s give it a whirl! Click here to say hello! Click here to get even friendlier!

- So, we‘re generating sayings. Awesome. But that‘s not all your service can do. One of + So, we’re generating sayings. Awesome. But that’s not all your service can do. One of the main reasons for using Dropwizard is the out-of-the-box operational tools it provides, all of which can be found on the admin port. @@ -784,7 +780,7 @@

Running Your Service

If you click through to metrics, you can see all of - your service‘s metrics represented as a JSON object. + your service’s metrics represented as a JSON object.

@@ -813,15 +809,15 @@

Running Your Service

Next Steps

- Well, congratulations. You‘ve got a Hello World service ready for production (except for - the lack of tests) that‘s capable of doing 15,000-20,000 requests per second. Hopefully + Well, congratulations. You’ve got a Hello World service ready for production (except for + the lack of tests) that’s capable of doing 15,000-20,000 requests per second. Hopefully you've gotten a feel for how Dropwizard combines Jetty, Jersey, Jackson, and other stable, mature libraries to provide a phenomenal platform for developing RESTful web services.

- There‘s a lot more to Dropwizard than is covered here (commands, modules, servlets, + There’s a lot more to Dropwizard than is covered here (commands, modules, servlets, advanced configuration, validation, HTTP clients, database clients, templates, etc.), all of which is covered in by Dropwizard's manual.

diff --git a/docs/index.html b/docs/index.html index d268b9302f7..d1748cc2868 100644 --- a/docs/index.html +++ b/docs/index.html @@ -11,19 +11,7 @@ - + @@ -46,106 +34,32 @@
-
- -
-

Meet Dropwizard.

- -

- - Dropwizard is a Java framework for developing ops-friendly, - high-performance, RESTful web services. - -

- -

- Developed by Yammer to power their - JVM-based backend services, Dropwizard pulls together stable, mature - libraries from the Java ecosystem into a simple, light-weight package that - lets you focus on getting things done. -

- -

- Dropwizard has out-of-the-box support for sophisticated application metrics, - logging, operational tools, and much more, allowing you and your team to - ship a production-quality HTTP+JSON web service in the shortest time - possible. -

- -

Get started »

-
- -
+

Meet Dropwizard.

+ +

+ + Dropwizard is a Java framework for developing ops-friendly, + high-performance, RESTful web services. + +

+ +

+ Developed by Yammer to power their + JVM-based backend services, Dropwizard pulls together stable, mature + libraries from the Java ecosystem into a simple, light-weight package that + lets you focus on getting things done. +

+ +

+ Dropwizard has out-of-the-box support for sophisticated application metrics, + logging, operational tools, and much more, allowing you and your team to + ship a production-quality HTTP+JSON web service in the shortest time + possible. +

+ +

Get started »

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

© Yammer 2011

diff --git a/docs/manual.html b/docs/manual.html index b7a82c5fdd9..737f01beb38 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -2,7 +2,7 @@ - Getting Started | Dropwizard + Manual | Dropwizard @@ -15,16 +15,7 @@ - - + @@ -47,14 +38,33 @@

Manual

-

+

coming soon

From 1c2f4221268a9cd6d32cf4c9eaea54e46ad3202d Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 11:49:12 -0800 Subject: [PATCH 0061/2771] Bump Jetty to 7.6.0.RC1. --- dropwizard/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard/pom.xml b/dropwizard/pom.xml index 7268f86dd26..25dc72dc463 100644 --- a/dropwizard/pom.xml +++ b/dropwizard/pom.xml @@ -15,7 +15,7 @@ Dropwizard - 7.6.0.RC0 + 7.6.0.RC1 1.9.2 1.6.4 From 596e73395bbbc1d2513e0b1f2284c2177be03458 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 11:57:46 -0800 Subject: [PATCH 0062/2771] Push javadocs as well as sources. --- pom.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pom.xml b/pom.xml index e0231ad74b7..e1d226d44bf 100644 --- a/pom.xml +++ b/pom.xml @@ -115,6 +115,22 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + 2.8 + + UTF-8 + + + + attach-javadocs + + jar + + + + org.apache.maven.plugins maven-resources-plugin From 45947e8e29424c1e1c572f426cd85eba95ce4d42 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 12:47:39 -0800 Subject: [PATCH 0063/2771] Deploy to Sonatype OSS repos. --- pom.xml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e1d226d44bf..2d12b4810ed 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,15 @@ + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + http://oss.sonatype.org/content/repositories/snapshots + - repo.codahale.com - scp://codahale.com/home/codahale/repo.codahale.com/ + sonatype-nexus-staging + Nexus Release Repository + http://oss.sonatype.org/service/local/staging/deploy/maven2/ From 7c4111e39cbec5c030008adb6c51b5b2086d31fe Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 13:07:00 -0800 Subject: [PATCH 0064/2771] Rationalized the module names. --- dropwizard-client/pom.xml | 6 +++--- {dropwizard => dropwizard-core}/pom.xml | 6 +++--- .../jackson/module/guava/GuavaDeserializers.java | 0 .../com/fasterxml/jackson/module/guava/GuavaModule.java | 0 .../fasterxml/jackson/module/guava/GuavaSerializers.java | 0 .../module/guava/deser/GuavaCollectionDeserializer.java | 0 .../jackson/module/guava/deser/GuavaMapDeserializer.java | 0 .../module/guava/deser/HashMultisetDeserializer.java | 0 .../module/guava/deser/ImmutableListDeserializer.java | 0 .../module/guava/deser/ImmutableMapDeserializer.java | 0 .../module/guava/deser/ImmutableSetDeserializer.java | 0 .../guava/deser/ImmutableSortedSetDeserializer.java | 0 .../jackson/module/guava/deser/OptionalDeserializer.java | 0 .../jackson/module/guava/ser/OptionalSerializer.java | 0 .../main/java/com/yammer/dropwizard/AbstractService.java | 0 .../src/main/java/com/yammer/dropwizard/BearerToken.java | 0 .../main/java/com/yammer/dropwizard/ConfiguredModule.java | 0 .../src/main/java/com/yammer/dropwizard/Module.java | 0 .../src/main/java/com/yammer/dropwizard/Service.java | 0 .../src/main/java/com/yammer/dropwizard/cli/Command.java | 0 .../java/com/yammer/dropwizard/cli/ConfiguredCommand.java | 0 .../java/com/yammer/dropwizard/cli/ManagedCommand.java | 0 .../java/com/yammer/dropwizard/cli/ServerCommand.java | 0 .../main/java/com/yammer/dropwizard/cli/UsagePrinter.java | 0 .../java/com/yammer/dropwizard/config/Configuration.java | 0 .../yammer/dropwizard/config/ConfigurationException.java | 0 .../yammer/dropwizard/config/ConfigurationFactory.java | 0 .../java/com/yammer/dropwizard/config/Environment.java | 0 .../com/yammer/dropwizard/config/FilterConfiguration.java | 0 .../com/yammer/dropwizard/config/HttpConfiguration.java | 0 .../yammer/dropwizard/config/LoggingConfiguration.java | 0 .../java/com/yammer/dropwizard/config/LoggingFactory.java | 0 .../dropwizard/config/RequestLogHandlerFactory.java | 0 .../java/com/yammer/dropwizard/config/ServerFactory.java | 0 .../yammer/dropwizard/config/ServletConfiguration.java | 0 .../dropwizard/jersey/JacksonMessageBodyProvider.java | 0 .../yammer/dropwizard/jersey/LoggingExceptionMapper.java | 0 ...MultivaluedParameterExtractorQueryParamInjectable.java | 0 .../yammer/dropwizard/jersey/OauthTokenInjectable.java | 0 .../com/yammer/dropwizard/jersey/OauthTokenProvider.java | 0 .../com/yammer/dropwizard/jersey/OptionalExtractor.java | 0 .../jersey/OptionalQueryParamInjectableProvider.java | 0 .../yammer/dropwizard/jersey/params/AbstractParam.java | 0 .../com/yammer/dropwizard/jersey/params/BooleanParam.java | 0 .../com/yammer/dropwizard/jersey/params/IntParam.java | 0 .../com/yammer/dropwizard/jersey/params/LongParam.java | 0 .../java/com/yammer/dropwizard/jetty/AsyncRequestLog.java | 0 .../java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java | 0 .../java/com/yammer/dropwizard/jetty/JettyManaged.java | 0 .../yammer/dropwizard/jetty/NonblockingServletHolder.java | 0 .../com/yammer/dropwizard/jetty/QuietErrorHandler.java | 0 .../json/AnnotationSensitivePropertyNamingStrategy.java | 0 .../src/main/java/com/yammer/dropwizard/json/Json.java | 0 .../java/com/yammer/dropwizard/json/JsonSnakeCase.java | 0 .../java/com/yammer/dropwizard/lifecycle/Managed.java | 0 .../java/com/yammer/dropwizard/logging/LogFormatter.java | 0 .../java/com/yammer/dropwizard/logging/LoggingBean.java | 0 .../java/com/yammer/dropwizard/modules/AssetsModule.java | 0 .../java/com/yammer/dropwizard/modules/JavaModule.java | 0 .../java/com/yammer/dropwizard/servlets/AssetServlet.java | 0 .../yammer/dropwizard/servlets/CacheBustingFilter.java | 0 .../com/yammer/dropwizard/servlets/SlowRequestFilter.java | 0 .../com/yammer/dropwizard/servlets/ThreadNameFilter.java | 0 .../yammer/dropwizard/tasks/GarbageCollectionTask.java | 0 .../src/main/java/com/yammer/dropwizard/tasks/Task.java | 0 .../java/com/yammer/dropwizard/tasks/TaskServlet.java | 0 .../main/java/com/yammer/dropwizard/util/Duration.java | 0 .../main/java/com/yammer/dropwizard/util/JarLocation.java | 0 .../main/java/com/yammer/dropwizard/util/Servlets.java | 0 .../src/main/java/com/yammer/dropwizard/util/Size.java | 0 .../main/java/com/yammer/dropwizard/util/SizeUnit.java | 0 .../com/yammer/dropwizard/validation/MethodValidator.java | 0 .../yammer/dropwizard/validation/ValidationMethod.java | 0 .../java/com/yammer/dropwizard/validation/Validator.java | 0 .../src/main/resources/HttpErrorMessages.properties | 0 .../java/com/yammer/dropwizard/cli/tests/CommandTest.java | 0 .../config/tests/ConfigurationExceptionTest.java | 0 .../dropwizard/config/tests/ConfigurationFactoryTest.java | 0 .../yammer/dropwizard/config/tests/ConfigurationTest.java | 0 .../dropwizard/config/tests/FilterConfigurationTest.java | 0 .../dropwizard/config/tests/LoggingConfigurationTest.java | 0 .../dropwizard/config/tests/ServletConfigurationTest.java | 0 .../dropwizard/jersey/params/tests/BooleanParamTest.java | 0 .../dropwizard/jersey/params/tests/IntParamTest.java | 0 .../dropwizard/jersey/params/tests/LongParamTest.java | 0 .../yammer/dropwizard/jetty/tests/JettyManagedTest.java | 0 .../jetty/tests/NonblockingServletHolderTest.java | 0 .../yammer/dropwizard/modules/tests/JavaModuleTest.java | 0 .../dropwizard/servlets/tests/CacheBustingFilterTest.java | 0 .../dropwizard/tasks/tests/GarbageCollectionTaskTest.java | 0 .../yammer/dropwizard/tasks/tests/TaskServletTest.java | 0 .../java/com/yammer/dropwizard/tasks/tests/TaskTest.java | 0 .../java/com/yammer/dropwizard/tests/ServiceTest.java | 0 .../com/yammer/dropwizard/util/tests/DurationTest.java | 0 .../com/yammer/dropwizard/util/tests/JarLocationTest.java | 0 .../com/yammer/dropwizard/util/tests/ServletsTest.java | 0 .../java/com/yammer/dropwizard/util/tests/SizeTest.java | 0 .../com/yammer/dropwizard/util/tests/SizeUnitTest.java | 0 .../dropwizard/validation/tests/MethodValidatorTest.java | 0 .../yammer/dropwizard/validation/tests/ValidatorTest.java | 0 .../src/test/resources/basic-configuration.yml | 0 .../src/test/resources/empty.yml | 0 .../src/test/resources/example.yml | 0 .../src/test/resources/factory-test-invalid.yml | 0 .../src/test/resources/factory-test-malformed.yml | 0 .../src/test/resources/factory-test-valid.yml | 0 .../src/test/resources/logging.yml | 0 dropwizard-db/pom.xml | 6 +++--- dropwizard-example/pom.xml | 6 +++--- dropwizard-templates/pom.xml | 8 ++++---- dropwizard-testing/pom.xml | 8 ++++---- dropwizard_2.9.1/pom.xml | 4 ++-- pom.xml | 4 ++-- 113 files changed, 24 insertions(+), 24 deletions(-) rename {dropwizard => dropwizard-core}/pom.xml (97%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/GuavaDeserializers.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/GuavaModule.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/GuavaSerializers.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaCollectionDeserializer.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaMapDeserializer.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/deser/HashMultisetDeserializer.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableListDeserializer.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableMapDeserializer.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSetDeserializer.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSortedSetDeserializer.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/AbstractService.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/BearerToken.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/ConfiguredModule.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/Module.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/Service.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/cli/Command.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/cli/UsagePrinter.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/Configuration.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/Environment.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/LoggingFactory.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/RequestLogHandlerFactory.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/ServerFactory.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/MultivaluedParameterExtractorQueryParamInjectable.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/OauthTokenInjectable.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/OauthTokenProvider.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/OptionalExtractor.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/OptionalQueryParamInjectableProvider.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/params/AbstractParam.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/params/BooleanParam.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/params/IntParam.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jersey/params/LongParam.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jetty/AsyncRequestLog.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jetty/JettyManaged.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/json/AnnotationSensitivePropertyNamingStrategy.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/json/Json.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/json/JsonSnakeCase.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/lifecycle/Managed.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/logging/LogFormatter.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/logging/LoggingBean.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/modules/JavaModule.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/servlets/ThreadNameFilter.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/tasks/GarbageCollectionTask.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/tasks/Task.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/util/Duration.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/util/JarLocation.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/util/Servlets.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/util/Size.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/util/SizeUnit.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/validation/MethodValidator.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/validation/ValidationMethod.java (100%) rename {dropwizard => dropwizard-core}/src/main/java/com/yammer/dropwizard/validation/Validator.java (100%) rename {dropwizard => dropwizard-core}/src/main/resources/HttpErrorMessages.properties (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/cli/tests/CommandTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationExceptionTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/config/tests/FilterConfigurationTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/config/tests/ServletConfigurationTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/jersey/params/tests/BooleanParamTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/jersey/params/tests/IntParamTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/jersey/params/tests/LongParamTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/jetty/tests/JettyManagedTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/jetty/tests/NonblockingServletHolderTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/modules/tests/JavaModuleTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/servlets/tests/CacheBustingFilterTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/tasks/tests/GarbageCollectionTaskTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/tasks/tests/TaskServletTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/tasks/tests/TaskTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/util/tests/DurationTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/util/tests/JarLocationTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/util/tests/ServletsTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/util/tests/SizeTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/util/tests/SizeUnitTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/validation/tests/MethodValidatorTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java (100%) rename {dropwizard => dropwizard-core}/src/test/resources/basic-configuration.yml (100%) rename {dropwizard => dropwizard-core}/src/test/resources/empty.yml (100%) rename {dropwizard => dropwizard-core}/src/test/resources/example.yml (100%) rename {dropwizard => dropwizard-core}/src/test/resources/factory-test-invalid.yml (100%) rename {dropwizard => dropwizard-core}/src/test/resources/factory-test-malformed.yml (100%) rename {dropwizard => dropwizard-core}/src/test/resources/factory-test-valid.yml (100%) rename {dropwizard => dropwizard-core}/src/test/resources/logging.yml (100%) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index ac43b898776..5a283182ae0 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ 4.0.0 - com.yammer + com.yammer.dropwizard dropwizard-parent 0.1.0-SNAPSHOT @@ -16,8 +16,8 @@ - com.yammer - dropwizard + com.yammer.dropwizard + dropwizard-core ${project.version} diff --git a/dropwizard/pom.xml b/dropwizard-core/pom.xml similarity index 97% rename from dropwizard/pom.xml rename to dropwizard-core/pom.xml index 25dc72dc463..07478de3a89 100644 --- a/dropwizard/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,13 +5,13 @@ 4.0.0 - com.yammer + com.yammer.dropwizard dropwizard-parent 0.1.0-SNAPSHOT - com.yammer - dropwizard + com.yammer.dropwizard + dropwizard-core Dropwizard diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/GuavaDeserializers.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaDeserializers.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/GuavaDeserializers.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaDeserializers.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/GuavaModule.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaModule.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/GuavaModule.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaModule.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/GuavaSerializers.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaSerializers.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/GuavaSerializers.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaSerializers.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaCollectionDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaCollectionDeserializer.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaCollectionDeserializer.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaCollectionDeserializer.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaMapDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaMapDeserializer.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaMapDeserializer.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaMapDeserializer.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/HashMultisetDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/HashMultisetDeserializer.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/HashMultisetDeserializer.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/HashMultisetDeserializer.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableListDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableListDeserializer.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableListDeserializer.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableListDeserializer.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableMapDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableMapDeserializer.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableMapDeserializer.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableMapDeserializer.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSetDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSetDeserializer.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSetDeserializer.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSetDeserializer.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSortedSetDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSortedSetDeserializer.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSortedSetDeserializer.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSortedSetDeserializer.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java diff --git a/dropwizard/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java similarity index 100% rename from dropwizard/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java rename to dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/AbstractService.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/BearerToken.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/BearerToken.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/BearerToken.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/BearerToken.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/ConfiguredModule.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredModule.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/ConfiguredModule.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredModule.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/Module.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/Module.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/Module.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/Module.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/Service.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/Service.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/cli/Command.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/Command.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/cli/Command.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/cli/Command.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/cli/UsagePrinter.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/UsagePrinter.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/cli/UsagePrinter.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/cli/UsagePrinter.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/Configuration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/Configuration.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationException.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/Environment.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/LoggingFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingFactory.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/LoggingFactory.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingFactory.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/RequestLogHandlerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogHandlerFactory.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/RequestLogHandlerFactory.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogHandlerFactory.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/ServerFactory.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/MultivaluedParameterExtractorQueryParamInjectable.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/MultivaluedParameterExtractorQueryParamInjectable.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/MultivaluedParameterExtractorQueryParamInjectable.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/MultivaluedParameterExtractorQueryParamInjectable.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OauthTokenInjectable.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/OauthTokenInjectable.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/OauthTokenInjectable.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/OauthTokenInjectable.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OauthTokenProvider.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/OauthTokenProvider.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/OauthTokenProvider.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/OauthTokenProvider.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OptionalExtractor.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/OptionalExtractor.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/OptionalExtractor.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/OptionalExtractor.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/OptionalQueryParamInjectableProvider.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/OptionalQueryParamInjectableProvider.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/OptionalQueryParamInjectableProvider.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/OptionalQueryParamInjectableProvider.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/params/AbstractParam.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/params/AbstractParam.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/params/AbstractParam.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/params/AbstractParam.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/params/BooleanParam.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/params/BooleanParam.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/params/BooleanParam.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/params/BooleanParam.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/params/IntParam.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/params/IntParam.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/params/IntParam.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/params/IntParam.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jersey/params/LongParam.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/params/LongParam.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jersey/params/LongParam.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/params/LongParam.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/AsyncRequestLog.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/AsyncRequestLog.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jetty/AsyncRequestLog.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/AsyncRequestLog.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/BiDiGzipHandler.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/JettyManaged.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/JettyManaged.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jetty/JettyManaged.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/JettyManaged.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/json/AnnotationSensitivePropertyNamingStrategy.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/AnnotationSensitivePropertyNamingStrategy.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/json/AnnotationSensitivePropertyNamingStrategy.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/json/AnnotationSensitivePropertyNamingStrategy.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/json/Json.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/json/Json.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/json/JsonSnakeCase.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/JsonSnakeCase.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/json/JsonSnakeCase.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/json/JsonSnakeCase.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/lifecycle/Managed.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/lifecycle/Managed.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/lifecycle/Managed.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/lifecycle/Managed.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/logging/LogFormatter.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/LogFormatter.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/logging/LogFormatter.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/logging/LogFormatter.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/logging/LoggingBean.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/LoggingBean.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/logging/LoggingBean.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/logging/LoggingBean.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/modules/JavaModule.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/modules/JavaModule.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/modules/JavaModule.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/CacheBustingFilter.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/servlets/ThreadNameFilter.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/ThreadNameFilter.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/servlets/ThreadNameFilter.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/ThreadNameFilter.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/tasks/GarbageCollectionTask.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/GarbageCollectionTask.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/tasks/GarbageCollectionTask.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/GarbageCollectionTask.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/tasks/Task.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/Task.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/tasks/Task.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/Task.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/util/Duration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/util/Duration.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/util/JarLocation.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/JarLocation.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/util/JarLocation.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/util/JarLocation.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/util/Servlets.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Servlets.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/util/Servlets.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/util/Servlets.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/util/Size.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/util/Size.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/util/SizeUnit.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/SizeUnit.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/util/SizeUnit.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/util/SizeUnit.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/validation/MethodValidator.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/validation/MethodValidator.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/validation/MethodValidator.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/validation/MethodValidator.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/validation/ValidationMethod.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/validation/ValidationMethod.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/validation/ValidationMethod.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/validation/ValidationMethod.java diff --git a/dropwizard/src/main/java/com/yammer/dropwizard/validation/Validator.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/validation/Validator.java similarity index 100% rename from dropwizard/src/main/java/com/yammer/dropwizard/validation/Validator.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/validation/Validator.java diff --git a/dropwizard/src/main/resources/HttpErrorMessages.properties b/dropwizard-core/src/main/resources/HttpErrorMessages.properties similarity index 100% rename from dropwizard/src/main/resources/HttpErrorMessages.properties rename to dropwizard-core/src/main/resources/HttpErrorMessages.properties diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/cli/tests/CommandTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/cli/tests/CommandTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/cli/tests/CommandTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/cli/tests/CommandTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationExceptionTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationExceptionTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationExceptionTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationExceptionTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/FilterConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/FilterConfigurationTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/config/tests/FilterConfigurationTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/FilterConfigurationTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/LoggingConfigurationTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ServletConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ServletConfigurationTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/config/tests/ServletConfigurationTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ServletConfigurationTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/BooleanParamTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/jersey/params/tests/BooleanParamTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/BooleanParamTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/jersey/params/tests/BooleanParamTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/IntParamTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/jersey/params/tests/IntParamTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/IntParamTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/jersey/params/tests/IntParamTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/LongParamTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/jersey/params/tests/LongParamTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/jersey/params/tests/LongParamTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/jersey/params/tests/LongParamTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/jetty/tests/JettyManagedTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/jetty/tests/JettyManagedTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/jetty/tests/JettyManagedTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/jetty/tests/JettyManagedTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/jetty/tests/NonblockingServletHolderTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/jetty/tests/NonblockingServletHolderTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/jetty/tests/NonblockingServletHolderTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/jetty/tests/NonblockingServletHolderTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/modules/tests/JavaModuleTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/modules/tests/JavaModuleTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/modules/tests/JavaModuleTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/modules/tests/JavaModuleTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/servlets/tests/CacheBustingFilterTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/servlets/tests/CacheBustingFilterTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/servlets/tests/CacheBustingFilterTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/servlets/tests/CacheBustingFilterTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/tasks/tests/GarbageCollectionTaskTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/GarbageCollectionTaskTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/tasks/tests/GarbageCollectionTaskTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/GarbageCollectionTaskTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/tasks/tests/TaskServletTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/TaskServletTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/tasks/tests/TaskServletTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/TaskServletTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/tasks/tests/TaskTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/TaskTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/tasks/tests/TaskTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/TaskTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/DurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/DurationTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/util/tests/DurationTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/DurationTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/JarLocationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/JarLocationTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/util/tests/JarLocationTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/JarLocationTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ServletsTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/ServletsTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/util/tests/ServletsTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/ServletsTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/SizeTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/SizeTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/util/tests/SizeTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/SizeTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/util/tests/SizeUnitTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/SizeUnitTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/util/tests/SizeUnitTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/SizeUnitTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/MethodValidatorTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/validation/tests/MethodValidatorTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/MethodValidatorTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/validation/tests/MethodValidatorTest.java diff --git a/dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java similarity index 100% rename from dropwizard/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java diff --git a/dropwizard/src/test/resources/basic-configuration.yml b/dropwizard-core/src/test/resources/basic-configuration.yml similarity index 100% rename from dropwizard/src/test/resources/basic-configuration.yml rename to dropwizard-core/src/test/resources/basic-configuration.yml diff --git a/dropwizard/src/test/resources/empty.yml b/dropwizard-core/src/test/resources/empty.yml similarity index 100% rename from dropwizard/src/test/resources/empty.yml rename to dropwizard-core/src/test/resources/empty.yml diff --git a/dropwizard/src/test/resources/example.yml b/dropwizard-core/src/test/resources/example.yml similarity index 100% rename from dropwizard/src/test/resources/example.yml rename to dropwizard-core/src/test/resources/example.yml diff --git a/dropwizard/src/test/resources/factory-test-invalid.yml b/dropwizard-core/src/test/resources/factory-test-invalid.yml similarity index 100% rename from dropwizard/src/test/resources/factory-test-invalid.yml rename to dropwizard-core/src/test/resources/factory-test-invalid.yml diff --git a/dropwizard/src/test/resources/factory-test-malformed.yml b/dropwizard-core/src/test/resources/factory-test-malformed.yml similarity index 100% rename from dropwizard/src/test/resources/factory-test-malformed.yml rename to dropwizard-core/src/test/resources/factory-test-malformed.yml diff --git a/dropwizard/src/test/resources/factory-test-valid.yml b/dropwizard-core/src/test/resources/factory-test-valid.yml similarity index 100% rename from dropwizard/src/test/resources/factory-test-valid.yml rename to dropwizard-core/src/test/resources/factory-test-valid.yml diff --git a/dropwizard/src/test/resources/logging.yml b/dropwizard-core/src/test/resources/logging.yml similarity index 100% rename from dropwizard/src/test/resources/logging.yml rename to dropwizard-core/src/test/resources/logging.yml diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 7a081933472..6485aa1ab82 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ 4.0.0 - com.yammer + com.yammer.dropwizard dropwizard-parent 0.1.0-SNAPSHOT @@ -16,8 +16,8 @@ - com.yammer - dropwizard + com.yammer.dropwizard + dropwizard-core ${project.version} diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 4c6c928dec4..08bf30e5a8b 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.yammer + com.yammer.dropwizard dropwizard-example 0.1.0-SNAPSHOT Dropwizard Example Application @@ -18,8 +18,8 @@ - com.yammer - dropwizard + com.yammer.dropwizard + dropwizard-core ${project.version} diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index c7fe1aa33a1..4f8d58b51c6 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,19 +5,19 @@ 4.0.0 - com.yammer + com.yammer.dropwizard dropwizard-parent 0.1.0-SNAPSHOT - com.yammer + com.yammer.dropwizard dropwizard-templates Dropwizard Templates - com.yammer - dropwizard + com.yammer.dropwizard + dropwizard-core ${project.version} diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 20f27e7bdfb..0cae703ed98 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,19 +5,19 @@ 4.0.0 - com.yammer + com.yammer.dropwizard dropwizard-parent 0.1.0-SNAPSHOT - com.yammer + com.yammer.dropwizard dropwizard-testing Dropwizard Test Helpers - com.yammer - dropwizard + com.yammer.dropwizard + dropwizard-core ${project.version} diff --git a/dropwizard_2.9.1/pom.xml b/dropwizard_2.9.1/pom.xml index 2214b1d381f..9bc79436f88 100644 --- a/dropwizard_2.9.1/pom.xml +++ b/dropwizard_2.9.1/pom.xml @@ -5,12 +5,12 @@ 4.0.0 - com.yammer + com.yammer.dropwizard dropwizard-parent 0.1.0-SNAPSHOT - com.yammer + com.yammer.dropwizard dropwizard_2.9.1 Dropwizard for Scala ${scala.version} diff --git a/pom.xml b/pom.xml index 2d12b4810ed..fa74c253556 100644 --- a/pom.xml +++ b/pom.xml @@ -4,14 +4,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.yammer + com.yammer.dropwizard dropwizard-parent 0.1.0-SNAPSHOT pom Dropwizard Project - dropwizard + dropwizard-core dropwizard-client dropwizard-db dropwizard-example From 122c9efdc074d2477f46e7a5976f70ab526dc478 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 13:14:37 -0800 Subject: [PATCH 0065/2771] Fix groupIds for -client and -db. --- dropwizard-client/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 5a283182ae0..eed38b6b792 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -10,7 +10,7 @@ 0.1.0-SNAPSHOT - com.yammer + com.yammer.dropwizard dropwizard-client Dropwizard HTTP Client diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 6485aa1ab82..e596f36fc5d 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -10,7 +10,7 @@ 0.1.0-SNAPSHOT - com.yammer + com.yammer.dropwizard dropwizard-db Dropwizard Database Client From 361b59f3b574f228d5df0b53b8b14818370fc811 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 14:02:38 -0800 Subject: [PATCH 0066/2771] Fix Scala module. Also, rename it. --- {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/pom.xml | 10 +++++++--- .../scala/com/yammer/dropwizard/ScalaService.scala | 0 .../com/yammer/dropwizard/modules/ScalaModule.scala | 0 .../dropwizard/providers/OauthTokenProvider.scala | 0 .../src/test/resources/banner.txt | 0 .../yammer/dropwizard/examples/DumbHealthCheck.scala | 0 .../dropwizard/examples/ExampleConfiguration.scala | 0 .../yammer/dropwizard/examples/ExampleService.scala | 0 .../dropwizard/examples/HelloWorldResource.scala | 0 .../yammer/dropwizard/examples/ProtectedResource.scala | 0 .../com/yammer/dropwizard/examples/SayCommand.scala | 0 .../com/yammer/dropwizard/examples/SayingFactory.scala | 0 .../com/yammer/dropwizard/examples/SplodyCommand.scala | 0 .../yammer/dropwizard/examples/SplodyResource.scala | 0 .../yammer/dropwizard/examples/StartableObject.scala | 0 .../yammer/dropwizard/examples/UploadResource.scala | 0 .../dropwizard/experiments/LogThroughputRunner.scala | 0 pom.xml | 7 ++++--- 18 files changed, 11 insertions(+), 6 deletions(-) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/pom.xml (95%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/main/scala/com/yammer/dropwizard/ScalaService.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/main/scala/com/yammer/dropwizard/modules/ScalaModule.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/main/scala/com/yammer/dropwizard/providers/OauthTokenProvider.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/resources/banner.txt (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/DumbHealthCheck.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/ExampleConfiguration.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/ProtectedResource.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/SayCommand.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/SayingFactory.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/SplodyCommand.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/SplodyResource.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/StartableObject.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/examples/UploadResource.scala (100%) rename {dropwizard_2.9.1 => dropwizard-scala_2.9.1}/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala (100%) diff --git a/dropwizard_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml similarity index 95% rename from dropwizard_2.9.1/pom.xml rename to dropwizard-scala_2.9.1/pom.xml index 9bc79436f88..29135ef9f00 100644 --- a/dropwizard_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -11,7 +11,7 @@ com.yammer.dropwizard - dropwizard_2.9.1 + dropwizard-scala_2.9.1 Dropwizard for Scala ${scala.version} @@ -27,6 +27,10 @@ nativelibs4java http://nativelibs4java.sourceforge.net/maven + + repo.codahale.com + http://repo.codahale.com/ + @@ -43,8 +47,8 @@ ${scala.version} - com.yammer - dropwizard + com.yammer.dropwizard + dropwizard-core ${project.version} diff --git a/dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala similarity index 100% rename from dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala rename to dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala diff --git a/dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/modules/ScalaModule.scala b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/modules/ScalaModule.scala similarity index 100% rename from dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/modules/ScalaModule.scala rename to dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/modules/ScalaModule.scala diff --git a/dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/providers/OauthTokenProvider.scala b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/providers/OauthTokenProvider.scala similarity index 100% rename from dropwizard_2.9.1/src/main/scala/com/yammer/dropwizard/providers/OauthTokenProvider.scala rename to dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/providers/OauthTokenProvider.scala diff --git a/dropwizard_2.9.1/src/test/resources/banner.txt b/dropwizard-scala_2.9.1/src/test/resources/banner.txt similarity index 100% rename from dropwizard_2.9.1/src/test/resources/banner.txt rename to dropwizard-scala_2.9.1/src/test/resources/banner.txt diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/DumbHealthCheck.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/DumbHealthCheck.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/DumbHealthCheck.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/DumbHealthCheck.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleConfiguration.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleConfiguration.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleConfiguration.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleConfiguration.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ProtectedResource.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ProtectedResource.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ProtectedResource.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ProtectedResource.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SayCommand.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SayCommand.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SayCommand.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SayCommand.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SayingFactory.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SayingFactory.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SayingFactory.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SayingFactory.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyCommand.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyCommand.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyCommand.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyCommand.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyResource.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyResource.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyResource.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyResource.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/StartableObject.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/StartableObject.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/StartableObject.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/StartableObject.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/UploadResource.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/UploadResource.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/examples/UploadResource.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/UploadResource.scala diff --git a/dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala similarity index 100% rename from dropwizard_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala rename to dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala diff --git a/pom.xml b/pom.xml index fa74c253556..f0cab0c229b 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ dropwizard-example dropwizard-templates dropwizard-testing - dropwizard_2.9.1 + dropwizard-scala_2.9.1 @@ -54,8 +54,9 @@ - repo.codahale.com - http://repo.codahale.com + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + http://oss.sonatype.org/content/repositories/snapshots From f8008bd66123fca7693c636ad2fdf3b281deb80b Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 15:43:03 -0800 Subject: [PATCH 0067/2771] Fix Maven refs in the docs. --- docs/getting-started.html | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/getting-started.html b/docs/getting-started.html index 6cbb870a237..8e43cffb4eb 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -178,26 +178,28 @@

Setting Up Maven

- First off, add the repository where the Dropwizard JARs are hosted: + First off, add the repository where the Dropwizard + SNAPSHOTJARs are hosted:

 <repositories>
     <repository>
-        <id>repo.codahale.com</id>
-        <url>http://repo.codahale.com</url>
+        <id>sonatype-nexus-snapshots</id>
+        <name>Sonatype Nexus Snapshots</name>
+        <url>http://oss.sonatype.org/content/repositories/snapshots</url>
     </repository>
 </repositories>

- Second, add the dropwizard library as a dependency: + Second, add the dropwizard-core library as a dependency:

 <dependencies>
     <dependency>
-        <groupId>com.yammer</groupId>
-        <artifactId>dropwizard</artifactId>
+        <groupId>com.yammer.dropwizard</groupId>
+        <artifactId>dropwizard-core</artifactId>
         <version>0.1.0-SNAPSHOT</version>
     </dependency>
 </dependencies>
From 8a4b177e8c5dd31a86bb76f0121f55e4a68c0153 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 16:43:08 -0800 Subject: [PATCH 0068/2771] Added Makefile for docs. --- docs/Makefile | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/Makefile diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000000..3de6cbb785d --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,2 @@ +upload: + rsync -avz --delete ./ codahale.com:/home/codahale/dropwizard.codahale.com/ From 184f3b73b1b870ff20397ad2d078e627dcefef98 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 22:16:26 -0800 Subject: [PATCH 0069/2771] Aw snap! A logo! Done up in short order by the inimitable Paul Bloch. --- docs/css/additional.css | 20 ++++++++-- docs/images/dropwizard-hat-small.png | Bin 0 -> 10925 bytes docs/images/dropwizard-hat-smaller.png | Bin 0 -> 6699 bytes docs/images/dropwizard-hat.png | Bin 0 -> 15524 bytes docs/index.html | 50 ++++++++++++++----------- 5 files changed, 46 insertions(+), 24 deletions(-) create mode 100644 docs/images/dropwizard-hat-small.png create mode 100644 docs/images/dropwizard-hat-smaller.png create mode 100644 docs/images/dropwizard-hat.png diff --git a/docs/css/additional.css b/docs/css/additional.css index a3582c66050..195f6a770be 100644 --- a/docs/css/additional.css +++ b/docs/css/additional.css @@ -3,9 +3,23 @@ body { } #blurb { - width: 760px ! important; + background-color: #f5f5f5; + margin-bottom: 30px; + padding: 30px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; } -#logo { - margin-top: 100px; +#blurb h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} + +#blurb p { + font-size: 18px; + font-weight: 200; + line-height: 27px; } diff --git a/docs/images/dropwizard-hat-small.png b/docs/images/dropwizard-hat-small.png new file mode 100644 index 0000000000000000000000000000000000000000..a62158fd628ef4c9bbdd5c23a0a4dfbd73b394e8 GIT binary patch literal 10925 zcmeHtcTm&W*FH!!^j-uEp$Y*)6+-V_dJ7#AdJUl$Dbjn9B8bvNy7b;fX$nY{CL&0Y zUPM6Phq}Ap-T8g@o!Oc9{ckgq+}zJO&vVXw?zty(XA-S>PmusX3qV6dBT!b7)4m>6 zuiyT-*w>$80)dLx0}V>v5T)a4gYvdSBG9Dau2u-3va_WvLK|TT_jMmYh+Ttu?R5=N zhU#iiYgcD(%O5`6KF)5}=xZ8DA2&;DM+6FJg|M}E5eMzIc7lNRaB+}-YR&}#x`1j-WVNAwB^xkPiY8=7HSh;fHYX3PT}+Pyt@x zZ!eGp04Rop+d#GD6n+bLJrf7np-^s69v*LRZ*FgXZdar&53h)b2oHphhmViz+Jno( z*9B$i!{y?^^n>CThaAGg8fou_vUha>{@}Ep!^NJdsX6nc>zv z2q%Oy!Ug5Q!^_Rf^Jo8SCA95r?NA#oYJjlPL0O`H zF6=iE{s;<{_C(paB0V%+J?wwTb#4ElB2Wx&4gIy2pVMEmN;{!`&3;Xt?0;wpb+UA^ z6$kln!4Wo=o=zwb&u<8xAIkp@5##wQ;SYXmB*GHqiu_Xm9fbQ|1N?>Sck55CKZAde zq3lskh(A&N9{9J4_?uiMG?Df$D6yZZI@$ki;{PER`;V-89@hs@7lCy4_{U-YvaH`T z7329^Zm~aaG*tGNZnCb|g>Q{gcCm5&S=WE{v6qG;<$X|=aOCfG|Nq-%?NPpeZ`HnT z6+a8&Z`d`hUE$Yt`Kx083pon;cjUSVCj(dHb<_B-Sb1kl`~S(Vhy308Q^sGL_oowo zy&J!tU3Ze}CdTte7yGqMzxA8{v*D*&|7YyK5&s+HA1VB=T>r}Tj}-Vv&i_`|zjFN} z1^$uqzt#1>CKup8_aKDJ_2tL=`j+#?_JR%#jh<9lPFmMzcFWX0iQd3d;>7F3*yf=^ zK_3hZcb-Y%Qk7wdXNecG&H{0FVLil@Q43*Yme-3>(FcMR= zqmTuJI-5nv0#DiJAy}2KhHIdPS@qFH#RA(J_d?)qpm@Rdo3`r5#SZO3Lv7O+?H(P6 zk3DwU-{^0j5@q_{{VHv-=Neayv(e3FGpOYrfwJRwG)9Xuw~6u~DM%c@r02&1-zKq5 zSHG#c?6f%ZodMTF0+rMLjiw5ApPa@~+z|Xo%c4G+Wx;r3BjRA*1y=-TW$W#Z!AND{ zTB1zs{(+?p&6L+s+r!ECkGt}5g)fpGR(`cAD%(CeVESavyadCaQbTsL`opjmbfsN)IS7g9mO5>?G-U>pvn?ZXmZfGuM2A^MOB*{eV=^W?6V@}4H1Sz~` z$InfSR=2SiwZWeY_3mimLM&l9tC3V+ck&mQu3U|lDL>L1_M`hS7?G=RE0VKfZ}KYa z=A8tD*QeLoU>b%#_L6h`8Kjl*%Ujv!TKdZ9?~j~PkwM6(5djm1)m&zYNCZBn)}OB2$Mq(Eo4Dl| z&e>oF1v)7_S%YY8N0?X)mO|pAG`GP!Pp3OZ0VyX&L)|@>?26p$9tb0u`r5SQO#K5= z;aMV#P98}Cp(kHQ)EXb17~@mOThBiTmr@X|Tu5ZG5=e-0Fb}4|3i7V6byjtWV}6MW zo3wfhQ-PGHMAs$+J@urh4c2ku$z!aI4d}==_;NxPseae6f((W_xL_8-OPPNYpxN}e z0SxhpwO=enH8>wD4xx)1huMRX`;>>1tlfHPQmS91=})(!s1GUEU((9oTvPB1q*z~j z=IDrUQKDXQCMoeEd7nm6Qo!r0niPnO?JBP=gGo+-gJk-IQ_RnSqzHl4a6P+nA+cc5 z;_~IH&;Q2DFOcbTf8`uwaCWB7nX49jcBT#&a}J#+t9ZS9g}-P;%&*VE#D2^;G^-LY zr%;v9NiVm-y2P-b2s)Xe;MLl)ke4$GfdE1am#FsrzHyr+GGucnxMm^7nq6h2cNjEG zHNr?byX&|MWEex37OlW9x%xc961C(4Rl_D#+1j|tQ@TNROt;|{=s4+~B^jj)+jI82 zc;iJY#;XyxFfI5<9k@v?EVS(*3q+`dsLfN%CfuI3tID3fF*C{tS2Y}q3XU-+@=7vN zbC%{iuV%Zk6G9di6)7>4b=USqn5Iv@rfLSdL0{f+O-9au=QX0o`n~R=MK->hU<GV3kouo^8rooBwB1UE{7>|Up6?R(peu>God znM)h|8}EJfyQBbyIZ|PFw5=cYyu4UeP#88w%{^ns+SJKW(r|oeO`y=kzREcNWY^tz^{Y~+(cD8 z;3Zf`Pl;qHGfULc7x|3g&scSeZk@8s6;IVXdtDBVE;uV{00hK#^||Vm-P%^|-G-FB zE>7>mKe4XtLw71{@6*AZI!c2_RZ-$~kWLkWZoSjNpFKpZ8+%f3dJ@gg!th_M*7r+Y zuRfi@~b74E0%p;u{H^9e&b+6wTEkcxI5hm~NxLE$q z@|N68bP!M>a&XP6>}10iv5FPyUbIx=^w9aGM>A(+R&sf{bW^g1gMp|a1M zh6*Iy(kvJsFouETyEGOrtZO)Wqj2jMzC4Lg=S+~Q|J*v9dyvj~Xu7C<-Z(yWVdK%8 zz23Q+G9M`T%9NJoy@z7Qa*_y3;)fZZi8nSYjx&v=aW1Vd*jLdS28 zWnpZ{NU#)W5dLIq0c~=;RyQ#9PSwS3;mx~u~V|3Z|rcXQem6mo=pnj3Sfq< zvk$NQMLH8CA@?x`&etjfi?JbD9&qIDcN?;m?=Wj{-KJT>E)1T?>KYArnQ}Mw79eFi zxid1O5f`Q)2Rgegsa!J8&ZxJ)gwO=&~ipvb!sX#J&CNa#5?SBqH?B|<-Penmm3h>+OBd!6g2b|LkhgHf8~mR zi;uEcV$$aEgzh}55sLtM*I}EzUhDz0#I9r;9rqM~l$pEuF0YEO)IAp~g(kVwws@q6 ze(dnKR^emcQf2k2JJscnQ7au{pJ%Y*{oKUdOXB;#Ga~zq6aI-P4YGgVRuUp z^&=k{oyF1=;EWa9HVWc_B@kyS4Asgzghe!^>;s1>+O;Cc&j6pHQ?Wot*ybneLy@wK zpxq#&8x&IRBY^#ZOl!`R>OyG}V~Ta7@+}qEdFI<7K_AY0fe|(q0uO?q^JczQ^Glp= zo<&;d^-$3nVK4!`XTm)}L6VXgAk)+65{<(J;(S!zW5c-o)MyJ129oleN_(!FiHPis zGXZ006ti2T7|lmoKGGCXkT+D=9*?t#dAn4NC|NDSF;BdU>v6;w8qJ_!d&k#-=xcg4rc1=_8WHH($p=flQzbb0KG<_&v*`iW==ZD!lKoJR|0l z*7`7W(+%cx5-qXy*W(f)AW(`8p5cP#p8n!Y+O>CI=fXe;vQ^zxPkc;>TtKx?!Jai8 zZHLx;y{slEa+dt&(J;3U68Skkc8E zzguY3Ml4mPI=)!bQ6TN;&E>@}qm&Tx@CKo)pkcAss;2QIo3~ifE7F6@#N!Li@{!^NhBrM+ zU$ck_42JgeiCI?Oc2zU?zo5mzunCE>e=P1&CX!sIO<-~IDA4UoOhJtnr>kDl_j=0# z%jXjqjT3Z4K92SR^Y?I4RTZcYrJm41>B19YrUM=};hBL_`KaHC~z!303>-Ji=}hj9v0(V@r-2dp?#wO7dt%X>Yi$MORnIPGG-{TIrx?SHC#* z`6pxgrIq*L4kY@bk6WIhySCl*h}0PXzK%ZY+8Pk1QHIR!P)(OW!pewQm$>*=p8|+3 zz3}25ZzvCCzBH<0Fh&0$@&XS~*ls9m#bKIUKUgD&V{1mbY>o65)E~B8*QMfpOOMu{HU{XW4BA;jiyi1joKMK#RlN>q_-=>DX6rLj*zK$o(c?rIGOOg1Nqu#d8G~Op6Q@lXZa>ZOGRM&(`CqN=xYVPm8Yarqmy1b;I`7rk^1Xn zgf1|G$@!Uc>S+~sw{gOtlKg!r?6Wo(ANMJzK#SZ`!uuQbakdA7JvD%FtSRmx4oppj zYyd9?1eNNb#98zwL3s+skiL(d(g!s~p? z6((AYDefxy2wXzN*gF$DPc`Nx$^keaBY&&5H zir$(fj^nAx(1$A6VO66}$j$Sllm)+jT6LwCqPYM!7(A2I@H4nZweG8LFPJZmGk3qz zuH&nkprJo_09e4}y0oV~5XqID(0wLYB~!F4+U9xvi*c8}XTTUfydv8w?mJc;SS|&N^zb!8pz#qxZ>OjIL<6W{}kS3wzLsQZsA$5$9x)HAyYUDCpvS6#Wq7TxpG&!?MG z=O68a47>~#u%opd86HjSVzp03>{EJB!5(mOzBjpJxM4*$oJ4@_(o-4}P8;yO*FR*# zo$*F__+9*-+>kKM%1sn`!El}uYm^TGR}FR$az62W$;dT>t(*Lnmk{d*F>zw(D4%>g zS72w@c0JsP&7kN&w2j7;;4I7>&(_e2)keYyD9K=-B8s{W_C8U8Zm7 zcVZ9IBDY~tN<0c>bPRzHYVuk>^DkG%;!yQ^-!@X!su7azJKBW7Svwk}-YgfFzl6F6 z)4##w`~(dH^W%`$d@R;5Bl@IB#qp)ofA0cEsCUSfyhzg-vpI{4&p(aK$}c~4I4C}z z(GJ_NBUX%G|H3VnAcU%W-$Q=pIMykgThN@}FtuDGoB%^g&Ztp_cA2fy4B&>k^L=a0acSv2XyxL0wYXOaWtI_3 zW^m&?rIA;~5PC_qe0rZsSUw9Ai@Di=gc)Z}ipxOl`fVhdAovJjl!Jr#IEN?uij|sf(t1w1&H; z82GI1gCP!Gu2J zTXu_2r(xhU(MlbMdwSk?HEtfLOryV@KXAMTDjMsy;92{zJMxmY-dhr%#5<^jynN@0pXgP(i%!{br_E%ZHK|5{Y&s1tGjoY9Piu*D0$5Br1uxFU zGq!Gdp~x-g8U#o6hkMy1E?I>AZHS?(df@jinQ^vV)Gk{cZ=Dh#SU5Hh9Wuu(>YJiz zoC810nfrHWOl>wF(D%r+qxtyaf6qt^Rg{W%oy{+YWW4}>Xw`|GKr&Yz%I-**5qyf8 zwId0mQvBH2@m1&B^!?Ki4GZx%x;WFXK=0_7-+WLtN$jg6|1gx^vGHi|0!1tq@OT}jBLK66^o{iGJtMN!@ zx_$3FH+!BejRvN;z3QBiykf3k$=SLjkjMx&XUE0HlK|gwS;_g6FIK#}twEt$X`!pZ z-I;4*HrPsPp|PL+Nf%>8;sp27F^8-<+GEfU4SNKW7j2OQHv>)MUSKbdVlBDmJlh6m z^|QZMBXMw?mPKqJ`;64kxtcYcP-2)9YpRob9#1;`Spsa9{MILmCAH4YaO;SUk1JYE z&Ogk3F;9T?my=i{_vu>AcN0u(A`F+mey6LIfA;#$I`1>F$#1#E3(@86F!bH;G!{%$ zAw;=2`k>%VPejQfl}yu_4X*#%4Ln)x`!q71_>yf}e@3&#$%p6Fmt@w8`_>|>-+Zl2E8u!2^p-3)JzVC) zOvG->p3U=x=x~ux#i#hkqft%il*wr0kZQT<6FpF6uQqRbP-sg?9m2Mtm-sxPDi8P3 zt=QA027*}8P8F%ZWClsHMEDWG=w+!{)s=ja_6A_1_g*d(XGG!ZZON8>7&~37qkuc?HMfmAtg}J}1=;(3fr# z>68YvJKzRcX8q~o_`F9cRj4G3k_oq}JoX%~a?+kbLhSp^9uo7_HT2vGak6Fs4Av(r z$mRlx{qewKKZ0dCtwJ$b*#gWdPBJuvab{7#{Jw!gfpnH%VTRMFin&?@U^eb~{}DU; zGpbjKC}v$OHyZkA%1k$n*_SFU>t%6L2e*A6d?PD7w1kE}tNj`;GL5?-NWS6E`7-cw zhWdLq0s4I7CumcUG)`KnVE?!y!%f3{ww99}GCT4&{D)B&8l7GwX7>Z5d}_FF`)7D6 zYdGtLiZ)fFiFix{1#Q)yuH*}l#MM(}ShF$T{Bp#aPC7i3F~xWacvw#SWO#dM1U?e< z@Yq$QFX}8pVd+`GO^KRj9Bd&lT9sySwFC2V@U0gyao`O`WcvyG-SU(#4=tU_@iinp z=@>5eYhT>Ia;K&RCqMM%rX$f^boe3xlqCaovjJ4{viFSF9`8bJACLYOSn;+rl*^6PdSHs$7-~(l1k`=D>OXTCYeO1 zQt3lh>J+mSfL!x5z)I`r8&%GsMyh3--7`^!?faz+5l<@g%Q(xRd@&U&aH)5({P{ zT>)0~)W*>bV0&@xo9mfi6!icGGZs(7*^IEys{1;J&kKiB@Jy3C<2-W6bCkbWwxttI z*-q&rQaTBi_JTPDaHFZ<=!|MZ>@wBuW)`fMroxIr{Jpx^*Pxh`6K(Pt?FwBFinD{# zCH@!fhY%_@DXCi}FEI0HWogHF!(UD@${z-F<+awL4W*BS2s%=A%?jczwS=3J zVpdPZE9R`8hr}H<1MAr>l`-`vPcF>0R?caS#=W}@5pd9p<(NC$HO6*VF33L7(#bQ0 z6l!|7=eu_gVq=mxCL}ibV9~;ss6x!*d!`RQy&mZuAfv+Vmll>yzbi9h5N+sK7fq&< zMrsVyamnEgHKI2tJhCga6;LP*Oyb0C+|R2mLz_1LfT3z<>?O-nZn%i&;WwK%lWu?v z@z=gl2*i3%--L^epXda^a30kCd@LVT)~jZ~6OeNMj?$=eJ)#J6QyWYo0Rx{<&s6&vg|F zxwV<1ad(E)gJn-hoMr3im*?kHB}XNo_2y$vh;aj*5l5MF-A{!Nv+mCsHpDf9q- zK_VfIIrH8(o6VDhha&TCaFbF9MA#1`G8mKsERtDpg9niDeju1V1zROR4w$EIsLiN> zhPm%V$P(8#pd1YE+UJ1ZVcGFzi;^|Z{}dR#=n>cDo4fcOBrb7Vp1Ln*(8^t$!ooH#0af ezg%HbqcLX=G%wSdxBU16sj~b%xk?#}(EkV4Q`p)7 literal 0 HcmV?d00001 diff --git a/docs/images/dropwizard-hat-smaller.png b/docs/images/dropwizard-hat-smaller.png new file mode 100644 index 0000000000000000000000000000000000000000..553a2be2783ac78be390b7d7809028d8c0cc87f2 GIT binary patch literal 6699 zcmeHMcTiK?w+F-Mg zfxjTYo63KMz`#EeZt|nZ7$lWQ{w{z$#_z`fKX84uZgG7N-Xx>qsJ@u*sJ;gNQV~DN zRo8}$BT!*msrur6n)pBDuzzHAq%dAU2Mifc`Q@-bEbD8gFz`>gVc%~w)M#5bBO;^l zQB*j=i?~(SKlD`KxtH#_i4f?u}>c#`ZHtCt)-(@V73uy-i>G&3|p! zQtQ9Q{)PB=kY7^xw_LyF`XvQ^$@zD6{g&&O6!<0Q-_`a1CKu;F=O7G$arg;joN_v_ zYvKR^cM{y#z#*u&*45{n<4eKyCEa4}Ko6y}Pk=z~bHJ?jQ!Jd^#L>Ivci}hjzM@?V z))BYh_7N49U3z&q&y9*aIIU8(RJro}dFAfPN>|T=P7=9?lJ6KqCIUT0Qq#0QUhf$^ z7CJp&t&-JWC81JIp30z1X$`qdx(&JdWcn08Siza@M_j!Qu6qQE=%bUD{c^8oy5G`78MjrcLP_lzBM4qVTFz zeop<{`*s_dlGyyQmr_81TLY~;X z7+reimyb1+aZ_itNuGH%nS-C4F>mE#ZBI52=0@B(c;c1Dltlbew; zJn6~R9Y;hXVFq?)>B6;1ov+~+5=9AnftQrMj_Z^xiz14aZ1(oXqMU@i&$`d4x#3#&$7f zEo1pSJQ?aY&%;D&|+sf}&7@`~cq5|->(KMt+H_?RZ09wlV3#3;E?RMw1= z8|C3skuiOj3`Y2MZk3fN_nD8nd-fZOD?7-vu9DBeWDL!YCJA&+lE+P&)u;m|Jd$z7 zM$(N0L?R*Su%mFqXEC`L*4oup*Y}}oA)MtzUcs`Y76_XhTKL1h)q==sn&Km-{+Ggm z836FZN1XK$Lc?)&?@ce~L^rUPS7qcN^?Rc+r333C{wm~CQ@HHsdaU$vP?(a_Ur#e1 zh;3+A3*dJkUXGmclsS{}AEayM!TWp;qbzinrL2A)Lg(LJu3=-lPdD-M4#T8k8paCZ zbHr1k_~tEkl``ioba>w`Kav%AM!TAV1Ql21^+8^>=C$xcPBlyAn{+_RJL<#FRP{#Q zFFBC|R-EHA^wMETrnQ~QF8Yk8eUKkC?#_cCSQLYl7KM&BcoeimP5t$809L-Z^30C| zDocv1v>)1af4{mY=CN|IyT!$h?S9K zj~1|(i9SFKQkXBCT(ou9nNSVmr>aeM+R_vc!jG)z4Rjj{h8*6PlpGE0tOfPhooS^5 z1#KHwT4yK^?o4n`iT20nGpS;TZSrbde_Qd%=h5Aq9my9;_J`K93 z&~uN(HX@@k4(vW5$Wb6e8}ij_riSLK!$gvDQt2wUbvigjXqeLKSm0X$i%h!2XtnBu z+=Tt|c;^%kqfMAQyJ7*Z(gkvCQNgr%UjKW}`|QiY#6?`rvBa>mar}7+JXJqiuHz6z zkF3oUA3w_UAWgA9kKVRWcKg;-&b_%;diiw(sy@C@mkeDWHr-(sI@{M1P*3q*Y4_xB zBUIhC*iv^Ib3fC|Q8`lkjCCO*PSe2N_wEi(yl&q4taq%= zue9$qr~@3OuZpoYcbzHf{gg8EF7moqQg6w%1m-9~1(&C7(5&E3jv9&Pw_S_h2s71_ zcDp6t8^1QW;ozfw1-!;L6g;dIX|R^gefWt&*8*Q$xYaQsc!;rrzOZ8G=h0;Gf6Urn21zS7jFwhcyy2xd8r?M3+W zhZ6J(Vsb(s%^d3Zv)MTbGo=%E`=H{KaFlY^GYP{%eKUWnKWO!=5q&Kd?^G0?vNLn} z6dy2fyI(95hZh?%!1_3v745Bl>&U95!3EFsB8^B3Lcg?U6AbKe|+gLS>YE_V}g#8^H3+N*dFw!3|0iH2p)OIn znB;sh)ULI9|1(gM6?0;42G8S^=jspNmsX(d+h0D5>vF3Q1TGCYTk=k^-%$cS^swX;c6 zx1APCF}h7gHO2H^jMOzTnm#svv7|#Q;;dn{Nyf$?c)(a=e7LYdV()=nSwXifsysrK zdC!~4!Ba_#eBfX@@;b@Z&tX2v5Kmz-^f&VMu+4sPch8QL8+($Ql+>de@w=C}E5|Cu zLOXTu^Ejs8)OM3=s9KCRPu86qwU#+_*=?-3sfse;x7;zNS+cQDJnVy}si~=LVRWww zXTe;-e%sV4zH%LAJBXK@#PDmuG)WHev6fhZT|Jj)kQ>^!yuKzd)nQ;W$^Q9}E|kJ+HnheU({j@+@!I3K zF|6Oxdr5DHlaWe=H6ad73U4rNXw}p9*Y+%UkhDc+BFEk0meuO+Mmo0DD5)wPIPARW zNeGnjWp?t$8Tj~2BC6bVhpVSN;@=;5;T#P~lWXpHrK9b*0;Li+7Iuc{G~uRZx?b+Dl}3+I!EQxdV61%?#Oq zf#0&^|E0~3Y}LIHH#16)xe#(qdolm!au z9&!CWN`q>w;BAS(ATFE2-2(jNkiT{0!uja80p4 zaN*SVzdx226Zu00F6@Uo{_6i96-!149N6Ak%)1^kWg7KB1# z0)qbL;2P@szdHCAtba)V!1}xKZ!nBE295d~)IS{mwIcpatXk$l-u@VkKSD)&|J%U- z2VCQSXtfHaZa_;^kYDhB?Dk)V^^Zt3M4@d0 zf~ZO3f3>~nhxGnG$*qF^A^n5KKPT^RJDxfle||>IB-A7(|IaM;=QRD5Z~mWM{$T6> z8Twzq|8?>oG5lY;{!7B;Q=6YKYM0aN zc_;(`$g>#h>sW?QtVKuMcj$;hX4;}zSGkR0cp{PjhnmMmHUyYBGAI_I`!j*TQnq^ zcqBc6127dcyD6M+RGIRce_4{*#z5;Z6i+&rxY}JD z%G>}`752gA2>@GJ?|5cG;_b9dYOEC+Eu{%$?{f7fCw=}hOnqiI`5pE<#QgfzhlH^l zR2J`x`&TLvK>U3+9iWV9D+3>ky_%tMl?oq9v8=|(NXX>3kbq*n)|%hlQo<1IKq`Xj zt>x?Ab3RKEpZnT37?@2fE5drTGAeC^2!EXOv2Tn8dA;=U(5V>2Pd-ce^XZy}$cz=FnJ$D$1Yc zKC3!)-VXQf)TgoXJX%@kUFC$~F7aPopfggRBgVU@E(^%Md+_YhWs+Dy7r$1KV<8b? z@&I?f;RooWi8NurHL>-|Aq!iaM>3(=rIcG^F0C8+9-b`A2kv?CwB=IrV~_jf0=wFT zj}}8q5Vz8EnN$}=OQi*(WJmc4t7S$=o=u;J%<4v7qwP-~gjk>q8d5(fI7Cc03&>f_ zU3}tHQ=3ccOIj`ec;wD+YQooV6Va}Hy9UsRq!bf{X74;v)BIp#7MGC;BzXLMGOKHnW1y()*&A~jX}EZdH8e~1Wz()aHFA%L8Z`{-=tQ73GwNeVRwum8Hr9*5G5N~TeGV{&wN0ojX4}DEsgIEdYWlx%&MEw-= zE(Gz4^W5D$j~1Z<+K^0l(5Lm?(472HXNT7dCrfw`#PUae^i^q|R~R+5JsECC?l-(& z$g;9<>6Pn}c|+Ee56Zz4370$>K9aL3E3zpiExD4YA73i_m9_71Wv2Ue+`uvXLMq3Q zV2l$fS8dNH53m#SsvM%N`0B1hs<)OPc=l){8hMLNetS`tN{fzYj|Hi9{&OYItrFFi z5+42g-hRl>Gvn{xQAaU;Rpz!QBt>)UN;$E`*;5*gjAbj%r7a)b9=_~c$YJ943&={# z_A7<)l-?Xa9P~EW`^EM`lHs}I@jxJcT22zOBpXoMhL8}sc@If|;xnI3sVB=&oyG+| zYfUQ^fZZ#74mTO`*MgT@cczuJtgO!i!*-$=uU$Z1WaYtt{Y^cGiQ|u|JbcS^o)HO; zo>;8l0rvds(}nkbn#Bz#lcNWZgS4^1jI(G1rBcTsTTTPd2(rk|txhFkOQVvBK(~kN zi7(&Om^9P0ZGO;AEUu!Fbw$sYaTrAi?+6V(?gyn>n*6TNmRT{rh_hItT;Pb>Wo+D_njT96RA;aCa( z0R?vDG9rw7Yk?}XlA$n{M_FHDK@_rJL~b|*!8^g4+d zkG!*_O;p>LA*VHD_8Ysv=LWOnQzy5!U4i)1t`POv;r-w)Lh0J{opPdO4+}oZVEYxTLT#yehA(UT{J}jj4-V@#|1upGp|xRKe%EpGeRj-b#I^$|kGA}Af=Fd0 zKBeBQAQA(9j>((=e>tCw?E+hO?|NwYp2L!>>GJS89Z&4>{q(qn^ibw%>|DxKhi~Sa zn%ps9n(kBmEd#6w-cH>mJSPcukMfYct8i;TyYL}xd8EnvmuokiTcyOg3W&6^&tftY znkiyl|;{aX$w{P-d0VNdLN{UYnG$qf*_G|qW-fJ!)CY-MZ zSUXqlwMKu_P?N!7HQ}HrjP+T2L@Xt!#s!G?mqszsw5at}H!V8uKGhoErkYmZs6rUmRh%B@%pJC+J zz{rUgwME5PAj1ob#vJLVA8d_WpNZ^8^Vnz0%w3|$p1@fd$7M`faOEH8^hLDWiAt*P zy^y(Fo8k>xU5K*gpzB@}ekIGd_yG>-*}5vsZ56(ojrO!D%nPr$ip8`U5vRHxQ9hNj;C8UH~7~nVTm{Ry}N6 z!S9Tb>okRS&JYMWAabbRHJ9c52C16)AGD2^NwD1tX*WsY#m*|;kz1{2;UGaG_6;1A zG+_G~VH39bLx^BddDzFR!?3Xb18Mw>Xy*b-hTCUv(@=Lhi!?nCZ=wG;2BdO=ndfpG zw}od-3z*SyvT-oEkN~mtX_{p_9|xCCqyPaZ{jLBChn<&Y6-l|p|@=b5e-Y8+|4 zJ!Y^xCLDA0m@r?RzFvjhDpWvtmZW6FioGgYQBxR>eYC+J`*@_0<@~)SmU~vOy+iJS z^3IHrmHW;NQ@N;)eC8QjbCi3mZ0h4Wc3FuhY8+d+Zn!x?A#J?bR?EH+$e!y1N(d*x zUPL~lCiQFBD@q?8_WJ4x_OYJlDlJNOJUw~9VIlic#~xw2AN~5-sTJ=}h5q+^AVkw_O+ai_0t&pO&>UsxQUBM89Dx$Lta1yJ#P)NRN4 zrd%I7w7Nxc?mt#QTM#lF&*9;~^XZwc4!B{6J^zX;ZdkmK^BxP@wM5|aOFpN*sO61Q zO;46?hkw}RA&rBrFUJkHE8f`N?B_(B@Hr=|Rc16|TS|h@?!U2r8OdPHp0>(gEo#sI zmWb6kAF}xa;5JuwGOT6DI;X)<_&a{9r2Z!7O1kjA&Bv(q-RpixW@^go$qWGENg37V zqvH)jv^*grmrt^{l(I4DM#E4Qdxwj<ZSi>=(KEngjuRw1d`Z+uIBudyK)cg@Z#Szr8M{pf0S#QNIzsDEvmMW+SmN9Y8(4qHl077O9S)}ws+zgF>XnCOS$j>5Un`wP5jP}5#P1wX2VH314i;WJ+`YmyuLFIVHm*T?hQ+xef}$HvLjV$q1=sZ&6?gxNJ4rSZiax><49qk?=cCme>1 zP}*c&zD)uK?JNmTL_f}ywtTz26FW{8Tfqmu@7K0R6kUwsQ_NJ~EeMVy4sfF|(llBj zE`EL&0@dhvPYd6|8CsJ+W2OzgRt;hd25k!nSkc=WRI5SuDSlviKG^w;@N;jCcBa*m zbtd^RvuM{o6{plMyV=F6a1%FB!s*9Qe0i)&-BCYMs&{ti1RFLQX}5hz^!UqrY@ln9 z96E9psH#&R0I^3<_ZquBzs-q{jcynz`>h(Jq(KN6l1iD!YM`L)4rNy#Kkx+kZsGAx zvo;nkDtS%wKQdrPmqHdz;3jI5qX&6XPHz~UV#4lN7wnsj43TYZ^(M$&)cz83TZ_%M zsay#ghz1nog>lN}T=pNHOY7+p9Qb4B-fptnEh&>}Zi|(i>5XwzpdrCTC(kO|A@()> z+wu6*?Uoap+~bXdDlKI2LiaD`EjNNC7_vw`HV2Zrm*BE@p{DQ5v{HI;vQZn<apil44A!yNbUoJ-9c?Y zO|S=v`XInX<_=tTtHtj8H(`zF1a!AI+kEK~MB&v^$E(-TB-rI{i|bBBbzyaJRYN=h zpG)3)B5){%)UOQ@OXal#TQpgC}bTtNLIa6bB>W5F z*Iyi-w|zjMsLCf$yz$O{Urdmc#*uu}i_UJH`%nnil=>Y8aOml)5~8uG{Jq}U7cZQZ zy90( zTY2B@!w#%0?GYUz)?#tkJx}K?{KbkN%zGC1^3dqF;4@1Q)T-%#S6Q=UJald2iQ`eO;*$k8knFRT`L521BgbPzUN)<5-mJ}cXxnCcyJ6( zxDq1v@Jr^VPxDrxeb~=cNI+A?Ls}F3eT6G3STeM{JSu@X49bB^6$y3RuSP(iZf=R%RqwS+*S8 zW_aOnss;4@W9A688eNs}l>{QhZ8Y8vuujjqTAe{cZXN2YKbI#^;)gx#vtI@TeQ(c- z8t+0?O!<>7w_l&>1ZP6p=Y?rrglK%qT*8NrkqPbK9hbdLUB}b8H^P68oSL3_Hfnon zb=uhOtk8E;q$^R!dQSAmu&ro*faEEk(nBpgbnQz`B~cRnX7?A)qWi>tUwD6EV79W0 zRfEFYqmuDhYe8#H0sni4TDPF4=Ve##Ui|bxj?+XF9|7$OT&S{T!$0U2#tgE`jC9rN zp>j)!6J8*?ROnhqq(6)1YYwRA8NQa)&6g}Aw$g4}Vbt!*`BBx0;=5IwU1m%7;U=_Z zQ8?ZiaOf8cnxi?-*GWxAGgA>9d2e8b2hm3)LKtgcS`Qj`R%MJ@&5w|5xWZ8ly(Q*QQf zb);RGj!gEb5ZvThs`l_fK+W%#*i!Lp zoS$dE($-0)-MaZX_^iQroAIKbix3CR$R$u=#ZkVQi>Z+hoKA@PSt@6x;H z#^Ts6jgSLU$fGe4CgQ~E0SlZ}i`cKO%Sz0%^NC%tLyg5_yO!2`6XcknwM!hn{fD1E zb*3{Q70Y@EE7H@=&enj5?y7?1NQzi?yKqxExmGzM5Ryjs>m*D$|XG)87n1{NOIwShgd4xcg2z0J8u(YU*PSWG?hxT21KG8(_? z$c3iVJuN5FB3yHIjBUOY4O<~GnHV#&AM#35Fw{*NE-KY)AAS7uSBtH!_!zm1h^>lR z5>VTdrRUW1tQiH5Kycebk-k0B8#|8>)<++cUS5mQHpN-xKwE&%Di2OyP2DbP#E}T* zaM@eXwV!YHAQA)Bsf6JilZeVgCl|wayDNUklF*P%iR`LLaN(ru_fcEbhm-+H#gkQ7 zQ5?l$S?r?tTx3U&8h7)y+55KmLJw3%ThJrl>GhUxr2+?bw^ZXPw8FUI0x0Au<%DgU zv*(NKult6EbNloTj~Wm7m8k8p-=Hnd9nXp6yp!>)-}dY)>XBI@g2NV1Y@Q@wulj9A zM&5+d6BDzccs+P|dds(CIuz*}2vy6_mci>hC2gNw@gUvs3 z*~iEY=dslDGUd<{L}#8BxRBUyc>{>hcV;LR@Zulx9OixBZ$u(6!@KF=!yPK4;8HdZ zK^%jqCn{Caur8(Qt#U$q4QH3vI5U>^t{4xA9K!*`EvRu&D}0FoU?ow*Wq^d~Ze+xN zB|CN-2;zqQNH8<0i#Zv?>fY(ooU7CfUt&^M(K1jf5I*86E~tB1N`SCIYtL^jVXfEG zC3Eup=W&QGrE6j!&`Tn<0^$3i?riEZBvyZ%Odkq-uxPGg@mO8f*Q5* z<3#N)+}lvm`n{&z_%v7iuRLQ^|N{26X&%mG<>(;F@?4+ zYVGS5`5~P`ffb`{HC)Znmr#t)FU+-f+N8qFaKZPXC8ITcSQ*Zdb^funt zu;;HN(lXrm?g3i;5x77C_zvZ&MhOhloNB+>=9n}*-oA+hu+HTF8J!7HU+Uy;^{)bsIrs1=!NPLrzPrh zx=VZv3tRJJ^tvx*=IuB+$`2XkwH8b9 zktP`N|0or(#G~RaJ*Sq=MH4Fq)$~OfZMvmQB}_x%=B63coLq%yFj-EE@jZ=1Ki-hLQ78=iwE-zHxFv z35oDoX{4^k`8g2%xpGoxSoo~-V3v~;_wsp&aNdcF4fk$eDutRVWQnnl#;1CNd?%io zRk-74tr<^@1DT8-;nWSqFLPA;?L)tAM7{&yGC1wC?@{8Zk=}-yJ_sn6IEApfmuT^j z*JARe4=!Zh^0ZUb4Y%j=&+ZXo=GB|U;$+^C2+!f=wj_czn~guqpHv-qbw9gc-qc7s z4jvQe5ruI4ldCf$CA`b7Y zOESTT{b0r|KjdYBmy}N%Aq~c?~)$E;Ic+jAtT^KH)ajt2eep)8cNgHEIZxP89HNEYT zoyO$twySnNAm3>`-e>mJd+>-pZW!&7(e|BZ2gM*1KStU-<&MT);YBjh3{z|0ibJOt z5x=(to;cwH;=b^@@YzvFN|l%tfk&!&Z#tIcjK$H99NtSjzg8e9c3_ybXH7Tw3`5I?|LR)4x&Mrc1|J$#T`eTS9Yo%E%x{@J`4@69W-tjO6`kWCO!JPCQRF9 zI*Ol(tbe-TkdxR}d4cGV9_qJ=#{*buuyG!yF<&F92HAV*tyRD;4+IlMr;j&Y&^8=U zqBQwya-V^y^kzaKO@~_Nd{r0_60Dg;PXz**0nZ27oiNylo~xsjuCjoty@RO_X!|jQ zlz^<=YFvHb7&nKmMw5}GoTUgl+bGP@s0u_GQSpvmqLga_>s6{9;fbvaM!gu|FWI z0XOy$7FjS=2#a}QfyPO$%G6MRD)!lZwdK@DKDmC)o*5>9jQzdu_apZrm@HrAH6MXn z#vLBn+IoYVa=qGv0@Q>aa^a)%$7yF|nwacO=M?jLg~~RopEF&D%iNC`yc zUq?ek71m?@%Jg<3hi?}2%8`N{b{~I;><|rJ5^2E(=l9jtZl#;sD=+mIA5?|~d)z)2 zP!{qJ01=8x1)|g$AGop|sRC7+40h*&!g;MHje-U6x`-2P88Y!@x)~eBu@m~te0GjF zRNN>$h50sXQK90dFjMxMr_Yy#Oe<%YmAY-zn%_50)n0I7i24pd;pJb;@))?6Gb(Py z?cv>fz@;~S`gNm`^x8QbX4?K7EMf8+@jY95m&}o31J42)cvrfurB5sKO@P7PT{DOl zv9OiEMyKO0E1QamiTi;zD|kYLO!I+N7KK{WtnDf(-QT+(>wWCh*-YTBW^$%e4ly|9 zV}oLI9(TtsLd{Fn#8_?8^d-h`$JRZ8><;_XbiIAc({S{w|M~49{ZO3K9nQJ=CCE%> z(HV>}(pY0e5Qn8)Rus)wQ=yRbGMZ?fr#dhYesWKb$Sm2<8+GLvFHRX|R-R)(d?tU; z7o_sv#gR_Ev+uG}}fv)Y#=z58P3E|qkJwta@ zzI8nKYM33K2)(iyrDCw~3np-4BRKVL$3S|<1J1}EP*N1~HvW4<&lv^DOg9<}rJ^ri z0{5j#qB4JI^5_T7LAYkVJjCVR4%_6^9%kZe>zQDqH;)KCg}yINZ;^KCx?{zRw6o@$ zk)2bxu{zh*c|#VtCWCPkCIX(((yBTN3mXjVbv+9_6YRIK8L@yXo$Jb~3vbKI3!VMJ z`SOZ=nL_tz<@l65I$bd008nU>4NR4UOn(FRcprZ@;k$EAto!1?LFK5Cs(9{mt+v=9 zSpV*}Ui4NF*`h6_P(N{-WpnIu*SD7R{Og~LyN;$-KM^7vtFn9DNgj$h`^@7}I#zq_!{1a3j<|jY;J;fOb?aJB}uYL#cH~si{=zJ?UM>k9wBd zWA)E2iy*yXUdY>-0%}-&5==}p4eFBJ?8)~XJHDhQTH+v161S@K0O_9~mTQ~>S+O0jyZ<~0}fVvUyCj3~`_l<)FF)o;C3t^%5x zy-ts{`F`+;n{Vy}4LIW>zvp;vYw6(q>gjBh@X#XfW$j+)P7Kff z$E$&**_+?q8lfR){m6GmUPetf#M3n2Topm$1;XCG{x~4d6}T?B?|U|QyyZrsNTruj zI;)Hn&%=eDoZzn$z8!+~uBT&{)$chv@)i)I>f;CkGD^|zVNDFL1h`!+9}lm69oHc| zAf)Us0`g5_hc57aZP9qn_p67~LQ1*}We5q9;dD-u`!E@7`*LyNRFF4iVH_4KWD8C^%QP`8KOgG$b!~yR6hM zstKKclJP#r#qInHB$gK)&)NsO&c+)4V*_6Wn+PmqOKzeGj-=2Q?Ja51Tq}H1#f<=v z(_-jCnhQTP5mfV64S6!4K?e5?Mr_@cg6C)t>W2kt1HSuYU#Pq{*8*b(o1fxrWjU-9 zv==80tv=Te47$KDVy)yt7NGJsce5j)k4KAQ5OGnL#Dmn4X>7IVQ1*J0Wi zmzPgydci+B%e*Fxk=BgkP0FbFp_lsV8lr@>glpID%L2p-kTWibj-_3Zqi7?afuF3! zbNgrZ@`wi1Ruqy#QS?|L%+GuO#HnYtsMyF$!n<7f3r5>$PV7aRPXz|H0c@mf`e391 zbEAuV;b72s_Uh@vkMfN_LqVTtEHF^|5D~r3AGe+ct$&(`%9K&_In~{#a+9+so6 z13pvHz^R+B;AzG@|J~LBF<+7Bn{$5-tt*`fmYg}B9ONdK{-&$26Pku2s1#ZH}U~ql=NcO^6qa!}Zm#X_Ok2~u? z&d1L_;k-`fs7c%9U{=&lDC%((_fwO2N&}OrR!$fMtB~(>fA>6+&1D<;Vg3Bu-XYsD z&AU)--j121-q#Rp)y<|muf(gQDcG!D>=y67!rG?WZ@SJaL_2dK5-PJt~8*6qoM*mtxo5kyi zvU*A(;EF2)^L_bnhBt0fvze*Mv!lnoHH2_4_VQpF&?KpT%-t<8n``o;l*UN!WOOHJ zM0MJbW*^^FCVT)?g$U>7Gk!YU6;+Bk@zOzsL+kr85)rn5f~={5kPxJ^UC zzpyyFOD98mBja*oQ1U~H`D(0Ab%jGQ6@(ct1enP+;rZqf{d$>`7Vtk{v5rgbxg|^ehX&QTw)0XVFTj)I;X;0D$^azO$ z#MBQyYst=)h*fOWpQ+7+4P`o?^oVtBQ9$442ewxO&g8kp8Sx%X?kbiJob!P8Za>v< zPvl5dzTOq~oj_lfVZK0PfIa^FIb!U4*VVDtyZmb(!y1BTPb~Go3^fUBk;2*}`9#Wm zHYANgYa^@%2T8;1rC7ZXw!pDV_o(d$kU9!!u zV$}m=vdAQWZk~$`&kO>DWLNXphU%DS-U_{xzMxQ6?-N?fok;l#X;-qDnkwyB4Uuvf z*d7{U7^`38ryFlg5GL<^&w|rIP|l9itT~p&3ygTA%3dHm+3f`ko;<2c{nn>0{B#Nk zqh<)W*n&A~c+{*%2)rsBwL;1uEGMF1o@UdoXF=wPo#tp~*R%UV0ZZvR9@RX1Cm$so znrj#Nj;(xq^MvD`T>3cNw;d@L`SisUo8{xGU0=$CRu=7AOB~1Su+5d04q@E7MlFwk z_M=tLH%je3%I|b`r3pd7ZL5$-9&dh}N_0M{6d>1s-EolB=(az%`JFf7e5QwoYPG*s zM9&^~`5>xXwdj(1;TqYjX;rtP7lqnrIHH>Yav<}OMGNRQ(+;PAqaxh&Oh#SM^9S=+ zW4uy{J+;Wd(ld(u95PA{cYXJ_x3;9iGj4Sy(0g4UV`b9nQP!$G7~JDQN1K(!W*h)~ z3tc-5C4v5?EeUyMVeV&Q<@2)`hefL%gWk-ggMp=~)IS$ZJ(<;_;;zu@uFCo@!2s}( z7!ZH&v>QOtA-cr&OlR25)VwP?A*!{(a;}9?!<8Y?*yrJZFR#F>9zV;21x=Seoa;mG z3$^@=KIy{55yjk*h66IZvaYiJiM-jF-h%0PC@w8qIX+60{0OTr>loQ{QHx-{=M1LaGZ9e1uw7#)PEKh3tq4sb6Z@`LZAQ?XxYTY8QH{$4=Hp z?iLrVSa2ghW73!0SQn^qaBr+zSYdc9Ru$aMy!KZ69ahIS_(9*K+0K)TUw#D^XL|t& zpLN?L9GS`xDBGn-^ zCxLu@uQSvF;k(dv5vFa2UNy)ff0%VZyz$|}+ckEsXQj8e({*m76KV8Ezg*YjTw#p9 z%py0(f0;wWMDJ9DpUrnB?V7^-neJHp*$*#kzPVqtz4pG~n;e2xu=(8U>rl(%g^^D?S|8nl_;o^_zgvV_`2DD>^_h}e4+OGb* zD!KEVMqc*1wr(iDKDc0Vv@?=DJ$U!Q;EUpL;VH^OP|`=oj#D(5_pHki@5fKjbl1@9 zUo2qtOwzc5coqAWEY^XDJq3e{1Zy)%sO z0OL6r;0Z<{iCC7cx~_vYNB5g#*TU$LotICCP(`u4y07~|JtOYLrmY4*Bzz+LITKr! zN)o2(I~s7El|jVMZN}@l;Mc^T{e|qZcM9fnx(JFt?kZeKs=&q!5g{+`Zpqc}&9H3` ztF!
-
-

Meet Dropwizard.

+
+
+ +
+
-

- - Dropwizard is a Java framework for developing ops-friendly, - high-performance, RESTful web services. - -

+

Meet Dropwizard.

-

- Developed by Yammer to power their - JVM-based backend services, Dropwizard pulls together stable, mature - libraries from the Java ecosystem into a simple, light-weight package that - lets you focus on getting things done. -

+

+ + Dropwizard is a Java framework for developing ops-friendly, + high-performance, RESTful web services. + +

-

- Dropwizard has out-of-the-box support for sophisticated application metrics, - logging, operational tools, and much more, allowing you and your team to - ship a production-quality HTTP+JSON web service in the shortest time - possible. -

+

+ Developed by Yammer to power their + JVM-based backend services, Dropwizard pulls together stable, mature + libraries from the Java ecosystem into a simple, light-weight package that + lets you focus on getting things done. +

-

Get started »

+

+ Dropwizard has out-of-the-box support for sophisticated application metrics, + logging, operational tools, and much more, allowing you and your team to + ship a production-quality HTTP+JSON web service in the shortest time + possible. +

+ +

Get + started »

+ +
From 8c2a4108634851ec4b498007fd8065d95f9a1463 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 22:43:39 -0800 Subject: [PATCH 0070/2771] Rename modules to "bundles". From here on out, top-level Maven modules (e.g., dropwizard-db) are called "modules", whereas reusable chunks of DW functionality (e.g., serving static assets) are called "bundles". --- docs/getting-started.html | 4 +- .../yammer/dropwizard/AbstractService.java | 42 +++++++++---------- .../dropwizard/{Module.java => Bundle.java} | 4 +- ...guredModule.java => ConfiguredBundle.java} | 6 +-- .../java/com/yammer/dropwizard/Service.java | 4 +- .../AssetsBundle.java} | 24 +++++------ .../JavaBundle.java} | 6 +-- .../yammer/dropwizard/cli/ManagedCommand.java | 2 +- .../yammer/dropwizard/cli/ServerCommand.java | 2 +- .../tests/JavaBundleTest.java} | 14 +++---- .../yammer/dropwizard/tests/ServiceTest.java | 6 +-- .../example/helloworld/HelloWorldService.java | 4 +- .../com/yammer/dropwizard/ScalaService.scala | 4 +- .../ScalaBundle.scala} | 6 +-- .../TemplateBundle.java} | 16 +++---- .../freemarker/example/TemplateService.java | 4 +- 16 files changed, 74 insertions(+), 74 deletions(-) rename dropwizard-core/src/main/java/com/yammer/dropwizard/{Module.java => Bundle.java} (71%) rename dropwizard-core/src/main/java/com/yammer/dropwizard/{ConfiguredModule.java => ConfiguredBundle.java} (69%) rename dropwizard-core/src/main/java/com/yammer/dropwizard/{modules/AssetsModule.java => bundles/AssetsBundle.java} (75%) rename dropwizard-core/src/main/java/com/yammer/dropwizard/{modules/JavaModule.java => bundles/JavaBundle.java} (83%) rename dropwizard-core/src/test/java/com/yammer/dropwizard/{modules/tests/JavaModuleTest.java => bundles/tests/JavaBundleTest.java} (75%) rename dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/{modules/ScalaModule.scala => bundles/ScalaBundle.scala} (81%) rename dropwizard-templates/src/main/java/com/yammer/dropwizard/{modules/TemplateModule.java => bundles/TemplateBundle.java} (80%) diff --git a/docs/getting-started.html b/docs/getting-started.html index 8e43cffb4eb..53dc9dd8e1d 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -290,7 +290,7 @@

Creating A Service Class

Combined with your project’s Configuration subclass, its Service form the core of your Dropwizard service. The Service - class pulls together the various modules and commands which provide basic functionality. + class pulls together the various bundles and commands which provide basic functionality. (More on that later.) For now, though, our HelloWorldService looks like this:

@@ -819,7 +819,7 @@

Next Steps

- There’s a lot more to Dropwizard than is covered here (commands, modules, servlets, + There’s a lot more to Dropwizard than is covered here (commands, bundles, servlets, advanced configuration, validation, HTTP clients, database clients, templates, etc.), all of which is covered in by Dropwizard's manual.

diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java index 8b5327c2637..550b06897ea 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java @@ -30,8 +30,8 @@ public abstract class AbstractService { } private final String name; - private final List modules; - private final List> configuredModules; + private final List bundles; + private final List> configuredBundles; private final SortedMap commands; /** @@ -41,8 +41,8 @@ public abstract class AbstractService { */ protected AbstractService(String name) { this.name = name; - this.modules = Lists.newArrayList(); - this.configuredModules = Lists.newArrayList(); + this.bundles = Lists.newArrayList(); + this.configuredBundles = Lists.newArrayList(); this.commands = Maps.newTreeMap(); addCommand(new ServerCommand(getConfigurationClass())); } @@ -68,24 +68,24 @@ public final Class getConfigurationClass() { } /** - * Registers a {@link Module} to be used in initializing the service's {@link Environment}. + * Registers a {@link Bundle} to be used in initializing the service's {@link Environment}. * - * @param module a module - * @see Module + * @param bundle a bundle + * @see Bundle */ - protected final void addModule(Module module) { - modules.add(module); + protected final void addBundle(Bundle bundle) { + bundles.add(bundle); } /** - * Registers a {@link ConfiguredModule} to be used in initializing the service's + * Registers a {@link ConfiguredBundle} to be used in initializing the service's * {@link Environment}. * - * @param module a module - * @see ConfiguredModule + * @param bundle a bundle + * @see ConfiguredBundle */ - protected final void addModule(ConfiguredModule module) { - configuredModules.add(module); + protected final void addBundle(ConfiguredBundle bundle) { + configuredBundles.add(bundle); } /** @@ -116,7 +116,7 @@ protected final void addCommand(ConfiguredCommand command) { } /** - * When the service runs, this is called after the {@link Module}s are run. Override it to add + * When the service runs, this is called after the {@link Bundle}s are run. Override it to add * providers, resources, etc. for your service. * * @param configuration the parsed {@link Configuration} object @@ -127,19 +127,19 @@ protected final void addCommand(ConfiguredCommand command) { /** * Initializes the given {@link Environment} given a {@link Configuration} instances. First the - * modules are initialized in the order they were added, then the service's + * bundles are initialized in the order they were added, then the service's * {@link #initialize(Configuration, Environment)} method is called. * * @param configuration the parsed {@link Configuration} object * @param environment the service's {@link Environment} * @throws Exception if something goes wrong */ - public final void initializeWithModules(T configuration, Environment environment) throws Exception { - for (Module module : modules) { - module.initialize(environment); + public final void initializeWithBundles(T configuration, Environment environment) throws Exception { + for (Bundle bundle : bundles) { + bundle.initialize(environment); } - for (ConfiguredModule module : configuredModules) { - module.initialize(configuration, environment); + for (ConfiguredBundle bundle : configuredBundles) { + bundle.initialize(configuration, environment); } initialize(configuration, environment); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/Module.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/Bundle.java similarity index 71% rename from dropwizard-core/src/main/java/com/yammer/dropwizard/Module.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/Bundle.java index 973d45c8162..3fad1ba20fb 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/Module.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/Bundle.java @@ -3,9 +3,9 @@ import com.yammer.dropwizard.config.Environment; /** - * A reusable module, used to define blocks of service behavior. + * A reusable bundle of functionality, used to define blocks of service behavior. */ -public interface Module { +public interface Bundle { /** * Initializes the environment. * diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredModule.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredBundle.java similarity index 69% rename from dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredModule.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredBundle.java index 9eea1d5b3f6..b87553ba4ea 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredModule.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredBundle.java @@ -4,12 +4,12 @@ import com.yammer.dropwizard.config.Environment; /** - * A reusable module, used to define blocks of service behavior that are conditional on - * configuration parameters. + * A reusable bundle of functionality, used to define blocks of service behavior that are + * conditional on configuration parameters. * * @param the required configuration class */ -public interface ConfiguredModule { +public interface ConfiguredBundle { /** * Initializes the environment. * diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java index 1f1d5a738f5..9779b965d9f 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java @@ -1,7 +1,7 @@ package com.yammer.dropwizard; import com.yammer.dropwizard.config.Configuration; -import com.yammer.dropwizard.modules.JavaModule; +import com.yammer.dropwizard.bundles.JavaBundle; /** * The default Java service class. Extend this to write your own service. @@ -12,7 +12,7 @@ public abstract class Service extends AbstractService { protected Service(String name) { super(name); - addModule(new JavaModule()); + addBundle(new JavaBundle()); } @Override diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java similarity index 75% rename from dropwizard-core/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java index ee408519cd8..a781b53fadb 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/modules/AssetsModule.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java @@ -1,15 +1,15 @@ -package com.yammer.dropwizard.modules; +package com.yammer.dropwizard.bundles; -import com.yammer.dropwizard.Module; +import com.yammer.dropwizard.Bundle; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.servlets.AssetServlet; import static com.google.common.base.Preconditions.checkArgument; /** - * A module for serving static asset files from the classpath. + * A bundle for serving static asset files from the classpath. */ -public class AssetsModule implements Module { +public class AssetsBundle implements Bundle { public static final String DEFAULT_PATH = "/assets"; public static final int DEFAULT_MAX_CACHE_SIZE = 100; @@ -17,30 +17,30 @@ public class AssetsModule implements Module { private final int maxCacheSize; /** - * Creates a new {@link AssetsModule} which serves up static assets from + * Creates a new {@link AssetsBundle} which serves up static assets from * {@code src/main/resources/assets/*} as {@code /assets/*}. * - * @see AssetsModule#AssetsModule(String, int) + * @see AssetsBundle#AssetsBundle(String, int) */ - public AssetsModule() { + public AssetsBundle() { this(DEFAULT_PATH, DEFAULT_MAX_CACHE_SIZE); } /** - * Creates a new {@link AssetsModule} which will configure the service to serve the static files + * Creates a new {@link AssetsBundle} which will configure the service to serve the static files * located in {@code src/main/resources/${path}} as {@code /${path}}. For example, given a * {@code path} of {@code "/assets"}, {@code src/main/resources/assets/example.js} would be * served up from {@code /assets/example.js}. * * @param path the classpath and URI root of the static asset files - * @see AssetsModule#AssetsModule(String, int) + * @see AssetsBundle#AssetsBundle(String, int) */ - public AssetsModule(String path) { + public AssetsBundle(String path) { this(path, DEFAULT_MAX_CACHE_SIZE); } /** - * Creates a new {@link AssetsModule} which will configure the service to serve the static files + * Creates a new {@link AssetsBundle} which will configure the service to serve the static files * located in {@code src/main/resources/${path}} as {@code /${path}}. For example, given a * {@code path} of {@code "/assets"}, {@code src/main/resources/assets/example.js} would be * served up from {@code /assets/example.js}. @@ -48,7 +48,7 @@ public AssetsModule(String path) { * @param path the classpath and URI root of the static asset files * @param maxCacheSize the maximum number of resources to cache */ - public AssetsModule(String path, int maxCacheSize) { + public AssetsBundle(String path, int maxCacheSize) { checkArgument(path.startsWith("/"), "%s is not an absolute path", path); checkArgument(!"/".equals(path), "%s is the classpath root"); this.path = path.endsWith("/") ? path : (path + '/'); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/modules/JavaModule.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java similarity index 83% rename from dropwizard-core/src/main/java/com/yammer/dropwizard/modules/JavaModule.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java index 9ae4432c33f..8831b8ced29 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/modules/JavaModule.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java @@ -1,6 +1,6 @@ -package com.yammer.dropwizard.modules; +package com.yammer.dropwizard.bundles; -import com.yammer.dropwizard.Module; +import com.yammer.dropwizard.Bundle; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.jersey.JacksonMessageBodyProvider; import com.yammer.dropwizard.jersey.OauthTokenProvider; @@ -9,7 +9,7 @@ /** * Initializes the service with support for Java classes. */ -public class JavaModule implements Module { +public class JavaBundle implements Bundle { @Override public void initialize(Environment environment) { environment.addProvider(new OptionalQueryParamInjectableProvider()); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java index b8ed7c8f51f..f9eceb59a6c 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java @@ -26,7 +26,7 @@ protected final void run(AbstractService service, CommandLine params) throws Exception { new LoggingFactory(configuration.getLoggingConfiguration()).configure(); final Environment environment = new Environment(); - service.initializeWithModules(configuration, environment); + service.initializeWithBundles(configuration, environment); LOGGER.info("Starting " + service.getName()); environment.start(); try { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java index c092d1a9d13..34973a9f931 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java @@ -45,7 +45,7 @@ protected final void run(AbstractService service, T configuration, CommandLine params) throws Exception { final Environment environment = new Environment(); - service.initializeWithModules(configuration, environment); + service.initializeWithBundles(configuration, environment); final Server server = new ServerFactory(configuration.getHttpConfiguration()).buildServer(environment); diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/modules/tests/JavaModuleTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/bundles/tests/JavaBundleTest.java similarity index 75% rename from dropwizard-core/src/test/java/com/yammer/dropwizard/modules/tests/JavaModuleTest.java rename to dropwizard-core/src/test/java/com/yammer/dropwizard/bundles/tests/JavaBundleTest.java index 0ec37953f85..8b723968977 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/modules/tests/JavaModuleTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/bundles/tests/JavaBundleTest.java @@ -1,37 +1,37 @@ -package com.yammer.dropwizard.modules.tests; +package com.yammer.dropwizard.bundles.tests; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.jersey.JacksonMessageBodyProvider; import com.yammer.dropwizard.jersey.OauthTokenProvider; import com.yammer.dropwizard.jersey.OptionalQueryParamInjectableProvider; -import com.yammer.dropwizard.modules.JavaModule; +import com.yammer.dropwizard.bundles.JavaBundle; import org.junit.Test; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class JavaModuleTest { +public class JavaBundleTest { private final Environment environment = mock(Environment.class); - private final JavaModule module = new JavaModule(); + private final JavaBundle bundle = new JavaBundle(); @Test public void addsOAuthSupport() throws Exception { - module.initialize(environment); + bundle.initialize(environment); verify(environment).addProvider(isA(OauthTokenProvider.class)); } @Test public void addsJSONSupport() throws Exception { - module.initialize(environment); + bundle.initialize(environment); verify(environment).addProvider(isA(JacksonMessageBodyProvider.class)); } @Test public void addsOptionalQueryParamSupport() throws Exception { - module.initialize(environment); + bundle.initialize(environment); verify(environment).addProvider(isA(OptionalQueryParamInjectableProvider.class)); } diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java index 2072a0df6c5..a902524c06d 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/tests/ServiceTest.java @@ -1,6 +1,6 @@ package com.yammer.dropwizard.tests; -import com.yammer.dropwizard.Module; +import com.yammer.dropwizard.Bundle; import com.yammer.dropwizard.Service; import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.config.Environment; @@ -19,7 +19,7 @@ static class FakeConfiguration extends Configuration { private class FakeService extends Service { FakeService() { super("test"); - addModule(module); + addBundle(bundle); } @Override @@ -28,7 +28,7 @@ protected void initialize(FakeConfiguration configuration, } } - private final Module module = mock(Module.class); + private final Bundle bundle = mock(Bundle.class); private final FakeService service = new FakeService(); @Test diff --git a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java index 776464f7a84..b9ee791e19a 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java @@ -6,7 +6,7 @@ import com.example.helloworld.resources.HelloWorldResource; import com.yammer.dropwizard.Service; import com.yammer.dropwizard.config.Environment; -import com.yammer.dropwizard.modules.AssetsModule; +import com.yammer.dropwizard.bundles.AssetsBundle; public class HelloWorldService extends Service { public static void main(String[] args) throws Exception { @@ -16,7 +16,7 @@ public static void main(String[] args) throws Exception { private HelloWorldService() { super("hello-world"); addCommand(new RenderCommand()); - addModule(new AssetsModule()); + addBundle(new AssetsBundle()); } @Override diff --git a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala index 271842c684a..ab502b0dfb5 100644 --- a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala +++ b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala @@ -1,10 +1,10 @@ package com.yammer.dropwizard import config.Configuration -import modules.ScalaModule +import bundles.ScalaBundle abstract class ScalaService[T <: Configuration](name: String) extends AbstractService[T](name) { - addModule(ScalaModule) + addBundle(ScalaBundle) override final def subclassServiceInsteadOfThis() {} final def main(args: Array[String]) { diff --git a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/modules/ScalaModule.scala b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/bundles/ScalaBundle.scala similarity index 81% rename from dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/modules/ScalaModule.scala rename to dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/bundles/ScalaBundle.scala index 5bc20c59ff3..5b8838d370a 100644 --- a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/modules/ScalaModule.scala +++ b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/bundles/ScalaBundle.scala @@ -1,12 +1,12 @@ -package com.yammer.dropwizard.modules +package com.yammer.dropwizard.bundles -import com.yammer.dropwizard.Module +import com.yammer.dropwizard.Bundle import com.yammer.dropwizard.config.Environment import com.yammer.dropwizard.providers.OauthTokenProvider import com.codahale.jersey.inject.ScalaCollectionsQueryParamInjectableProvider import com.codahale.jersey.providers.JerksonProvider -object ScalaModule extends Module { +object ScalaBundle extends Bundle { def initialize(environment: Environment) { environment.addProvider(new JerksonProvider[Any]) environment.addProvider(new OauthTokenProvider) diff --git a/dropwizard-templates/src/main/java/com/yammer/dropwizard/modules/TemplateModule.java b/dropwizard-templates/src/main/java/com/yammer/dropwizard/bundles/TemplateBundle.java similarity index 80% rename from dropwizard-templates/src/main/java/com/yammer/dropwizard/modules/TemplateModule.java rename to dropwizard-templates/src/main/java/com/yammer/dropwizard/bundles/TemplateBundle.java index 61f23003afd..963a78c22b3 100644 --- a/dropwizard-templates/src/main/java/com/yammer/dropwizard/modules/TemplateModule.java +++ b/dropwizard-templates/src/main/java/com/yammer/dropwizard/bundles/TemplateBundle.java @@ -1,11 +1,11 @@ -package com.yammer.dropwizard.modules; +package com.yammer.dropwizard.bundles; import com.sun.jersey.freemarker.FreemarkerViewProcessor; -import com.yammer.dropwizard.Module; +import com.yammer.dropwizard.Bundle; import com.yammer.dropwizard.config.Environment; /** - * A {@link Module} which enables the rendering of FreeMarker templates by your service. + * A {@link Bundle} which enables the rendering of FreeMarker templates by your service. * *

A resource method with a template would looks something like this:

* @@ -35,22 +35,22 @@ * * @see FreeMarker Manual */ -public class TemplateModule implements Module { +public class TemplateBundle implements Bundle { private final String templatePath; /** - * Creates a new {@link TemplateModule} with no specified template path. + * Creates a new {@link TemplateBundle} with no specified template path. */ - public TemplateModule() { + public TemplateBundle() { this(null); } /** - * Creates a new {@link TemplateModule} with the specified template path. + * Creates a new {@link TemplateBundle} with the specified template path. * * @param templatePath the location, in the class path, of the FreeMarker templates */ - public TemplateModule(String templatePath) { + public TemplateBundle(String templatePath) { this.templatePath = templatePath; } diff --git a/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateService.java b/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateService.java index f15e5864d7f..c088de6578b 100644 --- a/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateService.java +++ b/dropwizard-templates/src/test/java/com/yammer/dropwizard/freemarker/example/TemplateService.java @@ -3,7 +3,7 @@ import com.yammer.dropwizard.Service; import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.config.Environment; -import com.yammer.dropwizard.modules.TemplateModule; +import com.yammer.dropwizard.bundles.TemplateBundle; public class TemplateService extends Service { public static void main(String[] args) throws Exception { @@ -12,7 +12,7 @@ public static void main(String[] args) throws Exception { private TemplateService() { super("template"); - addModule(new TemplateModule()); + addBundle(new TemplateBundle()); } @Override From 7623db628cf5c99aab66a1ad462f59b782d003d0 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 23:25:14 -0800 Subject: [PATCH 0071/2771] Added skeleton for the manual. --- docs/manual.html | 62 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/docs/manual.html b/docs/manual.html index 737f01beb38..a3729cd4cf2 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -36,35 +36,67 @@
-

Manual

-

+

Dropwizard User’s Manual

+ +

coming soon

From 2e39f9e4066e5de5d6f33c4c78951ec034b76e7d Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 6 Dec 2011 23:26:32 -0800 Subject: [PATCH 0072/2771] Fix links. --- docs/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index 4ff352facb4..79429a2d7f0 100644 --- a/docs/index.html +++ b/docs/index.html @@ -23,7 +23,7 @@
From 71818d76c13d6ff1c5969ea35a632beae9757f4c Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 7 Dec 2011 10:20:48 -0800 Subject: [PATCH 0073/2771] Fix Yammer link. --- docs/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index 79429a2d7f0..a91bbcdc46d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -49,7 +49,7 @@

Meet Dropwizard.

- Developed by Yammer to power their + Developed by Yammer to power their JVM-based backend services, Dropwizard pulls together stable, mature libraries from the Java ecosystem into a simple, light-weight package that lets you focus on getting things done. From 5dfcf635be76b1704f5874bff315bda9b3bc45b4 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 8 Dec 2011 19:00:10 -0800 Subject: [PATCH 0074/2771] Make dropwizard-db depend on metrics-jdbi. --- dropwizard-db/pom.xml | 5 +++ .../com/yammer/dropwizard/db/Database.java | 3 +- .../dropwizard/db/MetricsTimingCollector.java | 32 ------------------- 3 files changed, 7 insertions(+), 33 deletions(-) delete mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/MetricsTimingCollector.java diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index e596f36fc5d..61f004e10cf 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -25,6 +25,11 @@ jdbi 2.28 + + com.yammer.metrics + metrics-jdbi + ${metrics.version} + org.apache.tomcat tomcat-dbcp diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index 1896fe951fa..b6ad6864527 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -3,6 +3,7 @@ import com.yammer.dropwizard.db.args.OptionalArgumentFactory; import com.yammer.dropwizard.lifecycle.Managed; import com.yammer.metrics.Metrics; +import com.yammer.metrics.jdbi.InstrumentedTimingCollector; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.tomcat.dbcp.pool.ObjectPool; @@ -29,7 +30,7 @@ public Database(DataSource dataSource, ObjectPool pool) { this.pool = pool; this.ping = onDemand(Ping.class); setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); - setTimingCollector(new MetricsTimingCollector(Metrics.defaultRegistry())); + setTimingCollector(new InstrumentedTimingCollector(Metrics.defaultRegistry(), Database.class)); setStatementRewriter(new NamePrependingStatementRewriter()); setStatementLocator(new ScopedStatementLocator()); registerArgumentFactory(new OptionalArgumentFactory()); diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/MetricsTimingCollector.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/MetricsTimingCollector.java deleted file mode 100644 index ca7f3269288..00000000000 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/MetricsTimingCollector.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.yammer.dropwizard.db; - -import com.yammer.metrics.core.MetricsRegistry; -import com.yammer.metrics.core.TimerMetric; -import org.skife.jdbi.v2.StatementContext; -import org.skife.jdbi.v2.TimingCollector; - -import java.util.concurrent.TimeUnit; - -class MetricsTimingCollector implements TimingCollector { - private final MetricsRegistry registry; - private final TimerMetric defaultTimer; - - MetricsTimingCollector(MetricsRegistry registry) { - this.registry = registry; - this.defaultTimer = registry.newTimer(Database.class, "raw-sql"); - } - - @Override - public void collect(long elapsedTime, StatementContext ctx) { - final TimerMetric timer = getTimer(ctx); - timer.update(elapsedTime, TimeUnit.NANOSECONDS); - } - - private TimerMetric getTimer(StatementContext ctx) { - if ((ctx.getSqlObjectType() == null) || (ctx.getSqlObjectMethod() == null)) { - return defaultTimer; - } - - return registry.newTimer(ctx.getSqlObjectType(), ctx.getSqlObjectMethod().getName()); - } -} From f4934cc199972cb9ee2386091bec4103cec5b767 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 9 Dec 2011 12:39:07 -0800 Subject: [PATCH 0075/2771] Added quick ways to create managed executors. This should also cut down on the traditional "what the hell is pool-8-thread-9 doing" problems. --- .../yammer/dropwizard/config/Environment.java | 59 +++++++++++++++++++ .../lifecycle/ExecutorServiceManager.java | 27 +++++++++ 2 files changed, 86 insertions(+) create mode 100644 dropwizard-core/src/main/java/com/yammer/dropwizard/lifecycle/ExecutorServiceManager.java diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 92370a415b6..f16ea6afa11 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Ordering; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sun.jersey.api.core.DefaultResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.core.reflection.AnnotatedMethod; @@ -12,6 +13,7 @@ import com.yammer.dropwizard.jersey.LoggingExceptionMapper; import com.yammer.dropwizard.jetty.JettyManaged; import com.yammer.dropwizard.jetty.NonblockingServletHolder; +import com.yammer.dropwizard.lifecycle.ExecutorServiceManager; import com.yammer.dropwizard.lifecycle.Managed; import com.yammer.dropwizard.tasks.GarbageCollectionTask; import com.yammer.dropwizard.tasks.Task; @@ -30,6 +32,7 @@ import javax.ws.rs.HttpMethod; import javax.ws.rs.Path; import javax.ws.rs.ext.Provider; +import java.util.concurrent.*; import static com.google.common.base.Preconditions.checkNotNull; @@ -254,6 +257,62 @@ public void setJerseyProperty(String name, config.getProperties().put(checkNotNull(name), value); } + /** + * Creates a new {@link ExecutorService} instance with the given parameters whose lifecycle is + * managed by the service. + * + * @param nameFormat a {@link String#format(String, Object...)}-compatible format + * String, to which a unique integer (0, 1, etc.) will be + * supplied as the single parameter. + * @param corePoolSize the number of threads to keep in the pool, even if they are + * idle. + * @param maximumPoolSize the maximum number of threads to allow in the pool. + * @param keepAliveTime when the number of threads is greater than the core, this is + * the maximum time that excess idle threads will wait for new + * tasks before terminating. + * @param unit the time unit for the keepAliveTime argument. + * + * @return a new {@link ExecutorService} instance + */ + public ExecutorService managedExecutorService(String nameFormat, + int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit) { + final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(nameFormat) + .build(); + final ExecutorService service = new ThreadPoolExecutor(corePoolSize, + maximumPoolSize, + keepAliveTime, + unit, + new LinkedBlockingQueue(), + threadFactory); + manage(new ExecutorServiceManager(service, 5, TimeUnit.SECONDS)); + return service; + } + + /** + * Creates a new {@link ScheduledExecutorService} instance with the given parameters whose + * lifecycle is managed by the service. + * + * @param nameFormat a {@link String#format(String, Object...)}-compatible format + * String, to which a unique integer (0, 1, etc.) will be + * supplied as the single parameter. + * @param corePoolSize the number of threads to keep in the pool, even if they are + * idle. + * + * @return a new {@link ScheduledExecutorService} instance + */ + public ScheduledExecutorService managedScheduledExecutorService(String nameFormat, + int corePoolSize) { + final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(nameFormat) + .build(); + final ScheduledExecutorService service = new ScheduledThreadPoolExecutor(corePoolSize, + threadFactory); + manage(new ExecutorServiceManager(service, 5, TimeUnit.SECONDS)); + return service; + } + /* * Internal Accessors */ diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/lifecycle/ExecutorServiceManager.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/lifecycle/ExecutorServiceManager.java new file mode 100644 index 00000000000..55f764bf142 --- /dev/null +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/lifecycle/ExecutorServiceManager.java @@ -0,0 +1,27 @@ +package com.yammer.dropwizard.lifecycle; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +public class ExecutorServiceManager implements Managed { + private final ExecutorService executor; + private final long shutdownPeriod; + private final TimeUnit unit; + + public ExecutorServiceManager(ExecutorService executor, long shutdownPeriod, TimeUnit unit) { + this.executor = executor; + this.shutdownPeriod = shutdownPeriod; + this.unit = unit; + } + + @Override + public void start() throws Exception { + // OK BOSS + } + + @Override + public void stop() throws Exception { + executor.shutdown(); + executor.awaitTermination(shutdownPeriod, unit); + } +} From 190898782dae1dd2ec44e7e1a1390f5d08267f0e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 9 Dec 2011 13:00:33 -0800 Subject: [PATCH 0076/2771] Relax the constraints on ConfiguredBundle. --- .../main/java/com/yammer/dropwizard/ConfiguredBundle.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredBundle.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredBundle.java index b87553ba4ea..3a259aabc36 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredBundle.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/ConfiguredBundle.java @@ -1,15 +1,14 @@ package com.yammer.dropwizard; -import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.config.Environment; /** * A reusable bundle of functionality, used to define blocks of service behavior that are * conditional on configuration parameters. * - * @param the required configuration class + * @param the required configuration interface */ -public interface ConfiguredBundle { +public interface ConfiguredBundle { /** * Initializes the environment. * From df965508b4207698494c82d4a04677b1783b7f8e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 9 Dec 2011 13:57:34 -0800 Subject: [PATCH 0077/2771] Fix tasks. --- .../src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java index b0211cebfac..7f024f4630f 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java @@ -34,7 +34,7 @@ public class TaskServlet extends HttpServlet { public TaskServlet(Iterable tasks) { final ImmutableMap.Builder builder = ImmutableMap.builder(); for (Task task : tasks) { - builder.put('/' + task.getName(), task); + builder.put("/tasks/" + task.getName(), task); } this.tasks = builder.build(); } From 5dd6d7bb25daafe698d09c84b71e56919067154b Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 9 Dec 2011 13:57:46 -0800 Subject: [PATCH 0078/2771] Add the first bit of the manual. --- docs/manual.html | 659 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 651 insertions(+), 8 deletions(-) diff --git a/docs/manual.html b/docs/manual.html index a3729cd4cf2..ce6c0613ebc 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -38,16 +38,34 @@

@@ -97,9 +118,631 @@
Dropwizard User’s Manual

Dropwizard User’s Manual

- coming soon + This goal of this document is to provide you with all the information required to + build, organize, test, deploy, and maintain Dropwizard-based services. +

+ +

Organization

+ +

+ In general, we recommend you separate your projects into three Maven modules: + project-api, project-client, + and project-server. project-api should + contain your representation classes; + project-client should use those classes and an HTTP client from + dropwizard-client to implement a full-fledged client + for your service, and project-server should provide the actual service + implementation, including resources. +

+ +

Our services tend to look like this:

+ +
+
com.example.myservice.api
+
Representation classes
+
com.example.myservice.cli
+
Service command classes
+
com.example.myservice.client
+
Client implementation
+
com.example.myservice.core
+
Domain implementation
+
com.example.myservice.health
+
Health check classes
+
com.example.myservice.resources
+
Resource classes
+
com.example.myservice.MyService
+
The service class
+
com.example.myservice.MyServiceConfiguration
+
The configuration class
+
+ +

Services

+ +

+ The main entry point into a Dropwizard service is, unsurprisingly, the + Service class. Each Service has a name, + which is mostly used to render the command-line interface. In the constructor of your + Service you can add bundles and + commands to your service. +

+ +

Configuration

+ +

+ Each Service subclass has a single type parameter: that of its matching + Configuration subclass. These are usually at the root of your service’s + main package. For example, your User service would have two classes: + UserServiceConfiguration, extending Configuration, + and UserService, extending + Service<UserServiceConfiguration>. +

+ +

+ When your service runs a configured command like the + server command, Dropwizard parses the provided YAML configuration file and + builds an instance of your service’s configuration class by mapping YAML field names to + object field names. +

+ +

+ In order to keep your configuration file and class manageable, we recommend grouping + related configuration parameters into independent configuration classes. If your + service requires a set of configuration parameters in order to connect to a message + queue, for example, we recommend that you create a new + MessageQueueConfiguration class: +

+ +
+public class MessageQueueConfiguration {
+    @NotEmpty
+    private String host;
+
+    @Min(1)
+    @Max(65535)
+    private int port = 5672;
+
+    public String getHost() {
+        return host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+}
+ +

+ Your main Configuration subclass can then include this as a member field: +

+ +
+public class ExampleServiceConfiguration extends Configuration {
+    @NotNull
+    private MessageQueueConfiguration messageQueue = new MessageQueueConfiguration();
+
+    public MessageQueueConfiguration getMessageQueueConfiguration() {
+        return messageQueue;
+    }
+}
+ +

+ Then, in your service’s YAML file, you can use a nested messageQueue field: +

+ +
+messageQueue:
+  host: mq.example.com
+  port: 5673
+ +

+ The @NotNull, @NotEmpty, @Min, and + @Max annotations are part of Dropwizard’s + validation functionality. If your YAML configuration file’s + messageQueue.host field was missing (or was a blank string), Dropwizard + would refuse to start and would output an error message describing the issues. +

+ +

+ Once your service has parsed the YAML file and constructed its + Configuration instance, Dropwizard then calls your Service + subclass to initialize your service’s Environment. +

+ +

Environments

+ +

+ A Dropwizard Environment consists of all the + resource classes, servlets, filters, + health checks, Jersey providers, + managed objects, tasks, and Jersey + properties which your service provides. +

+ +

+ Each Service subclass implements an initialize method. This + is where you should be creating new resource instances, etc., and adding them to the + given Environment class: +

+ +
+@Override
+protected void initialize(ExampleConfiguration config,
+                          Environment environment) {
+    // encapsulate complicated setup logic in factories
+    final ThingyFactory thingyFactory = new ThingyFactory(config.getThingyConfiguration());
+
+    final Thingy thingy = thingyFactory.build();
+
+    environment.addResource(new ThingyResource(thingy));
+    environment.addHealthCheck(new ThingyHealthCheck(thingy));
+}
+ +

+ It’s important to keep the initialize method clean, so if creating an + instance of something is complicated, like the Thingy class above, extract + that logic into a factory. +

+ +

Health Checks

+ +

+ A health check is a runtime test which you can use to verify your service’s behavior + in its production environment. For example, you may want to ensure that your database + client is connected to the database: +

+ +
+public class DatabaseHealthCheck extends HealthCheck {
+    private final Database database;
+
+    public DatabaseHealthCheck(Database database) {
+        this.database = database;
+    }
+
+    @Override
+    public String name() {
+        return "database";
+    }
+
+    @Override
+    public Result check() throws Exception {
+        if (database.isConnected()) {
+            return Result.healthy();
+        } else {
+            return Result.unhealthy("Cannot connect to " + database.getUrl());
+        }
+    }
+}
+ +

+ You can then add this health check to your service’s environment: +

+ +
+environment.addHealthCheck(new DatabaseHealthCheck(database));
+ +

+ By sending a GET request to /healthcheck on the admin port you + can run these tests and view the results: +

+ +
+$ curl http://dw.example.com:8081/healthcheck
+* deadlocks: OK
+* database: OK
+ +

+ If all health checks report success, a 200 OK is returned. If any fail, + a 500 Internal Server Error is returned with the error messages and + exception stack traces (if an exception was thrown). +

+ +

+ All Dropwizard services ship with the deadlocks health check installed by + default, which uses Java 1.6's built-in thread deadlock detection to determine if any + threads are deadlocked. +

+ +

Managed Objects

+ +

+ Most services involve objects which need to be started and stopped: thread pools, + database connections, etc. Dropwizard provides the Managed interface for + this. You can either have the class in question implement Managed’s + start() and stop() methods, or write a wrapper class which + does so. Adding a Managed instance to your service’s + Environment ties that object’s lifecycle to that of the service’s HTTP + server. Before the server starts, the Managed’s start() method + is called. After the server has stopped (and after its graceful shutdown period) the + Managed’s stop() method is called. +

+ +

+ For example, given a theoretical Riak client which + needs to be started and stopped: +

+ +
+public class RiakClientManager implements Managed {
+    private final RiakClient client;
+
+    public RiakClientManager(RiakClient client) {
+        this.client = client;
+    }
+
+    @Override
+    public void start() throws Exception {
+        client.start();
+    }
+
+    @Override
+    public void stop() throws Exception {
+        client.stop();
+    }
+}
+ +

+ If RiakClientManager#start() throws an exception—e.g., an error connecting + to the server—your service will not start and a full exception will be logged. If + RiakClientManager#stop() throws an exception, the exception will be logged + but your service will still be able to shut down. +

+ +

+ It should be noted that Environment has built-in constructors for + ExecutorService and ScheduledExecutorService instances which + are managed. See Environment#managedExecutorService and + Environment#managedScheduledExecutorService for details. +

+ +

Bundles

+ +

+ A Dropwizard bundle is a reusable group of functionality, used to define blocks of a + service’s behavior. For example, AssetBundle provides a simple way to serve + static assets from your service’s src/main/resources/assets directory as + files available from /assets/* in your service. +

+ +

+ Some bundles require configuration parameters. The bundles implement + ConfiguredBundle and will require your service’s Configuration + subclass to implement a specific interface. +

+ +

Commands

+ +

+ Commands are basic actions which Dropwizard runs based on the arguments provided on the + command line. The built-in server command, for example, spins up an HTTP + server and runs your service. Each Command subclass has a name and a set + of command line options which Dropwizard will use to parse the given command line + arguments.

+

Configured Commands

+ +

+ Some commands require access to configuration parameters and should extend the + ConfiguredCommand class, using your service’s Configuration + class as its type parameter. Dropwizard will treat the first argument on the command + line as the path to a YAML configuration file, parse and validate it, and provide your + command with an instance of the configuration class. +

+ +

Managed Commands

+ +

+ Managed commands further extend configured commands by creating a lifecycle process for + your service’s managed objects. All Managed + instances registered with your service’s Environment will be started before + your command is run, and will be stopped afterward. +

+ +

Tasks

+ +

+ A Task is a run-time action your service provides access to on the + administrative port via HTTP. All Dropwizard services start with the gc + task, which explicitly triggers the JVM's garbage collection. (This is useful, for + example, for running full garbage collections during off-peak times or while the given + service is out of rotation.) +

+ +

+ Running a task can be done by sending a POST request to + /tasks/{task-name} on the admin port. For example: +

+ +
+$ curl -X POST http://dw.example.com:8081/tasks/gc
+Running GC...
+Done!
+ +

Logging

+ +

+ Dropwizard uses Log4j for its logging + backend. It provides a slf4j implementation, and + even routes all java.util.logging usage through log4j. +

+ +

Dropwizard’s log format has a few specific goals:

+ +
    +
  • Be human readable.
  • +
  • Be machine parsable.
  • +
  • + Be easy for sleepy ops folks to figure out why things are pear-shaped at 3:30AM + using standard UNIXy tools like tail and grep. +
  • +
+ +

The logging output looks like this:

+ +
+TRACE [2010-04-06 06:42:35,271] com.example.dw.Thing: Contemplating doing a thing.
+DEBUG [2010-04-06 06:42:35,274] com.example.dw.Thing: About to do a thing.
+INFO  [2010-04-06 06:42:35,274] com.example.dw.Thing: Doing a thing
+WARN  [2010-04-06 06:42:35,275] com.example.dw.Thing: Doing a thing
+ERROR [2010-04-06 06:42:35,275] com.example.dw.Thing: This may get ugly.
+FATAL [2010-04-06 06:42:35,275] com.example.dw.Thing: The thing has gone horribly wrong.
+! java.lang.RuntimeException: oh noes!
+! at com.example.dw.Thing.run(Thing.java:16)
+!
+ +

A few items of note:

+ +
    +
  • All timestamps are in UTC and ISO 8601 format.
  • +
  • + You can grep for messages of a specific level really easily: + tail -f dw.log | grep '^WARN' +
  • +
  • + You can grep for messages from a specific class or package really easily: + tail -f dw.log | grep 'com.example.dw.Thing' +
  • +
  • + You can even pull out full exception stack traces, plus the accompanying + log message: tail -f dw.log | grep -B 1 '^\!' +
  • +
+ +

+ You can specify a default logger level and even override the levels of other loggers in + your YAML configuration file: +

+ +
+# Logging settings.
+logging:
+  # The default level of all loggers. Can be OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, or ALL.
+  level: INFO
+  # Logger-specific levels.
+  loggers:
+    # Overrides the level of com.example.dw.Thing and sets it to DEBUG.
+    "com.example.dw.Thing": DEBUG
+ +

Console Logging

+ +

+ By default, Dropwizard services log INFO and higher to STDOUT. + You can configure this by editing the logging section of your YAML + configuration file: +

+ +
+logging:
+  # ...
+  # Settings for logging to stdout.
+  console:
+    # If true, write log statements to stdout.
+    enabled: true
+    # Do not display log statements below this threshold to stdout.
+    threshold: ALL
+ +

File Logging

+ +

+ Dropwizard can also log to an automatically rotated set of log files. This is the + recommended configuration for your production environment: +

+ +
+logging:
+  # ...
+  # Settings for logging to a file.
+  file:
+    # If true, write log statements to a file.
+    enabled: false
+    # Do not write log statements below this threshold to the file.
+    threshold: ALL
+    # The file to which statements will be logged. When the log file reaches the maximum size, the
+    # file will be renamed example.log.1, example.log will be truncated, and new statements written
+    # to it.
+    filenamePattern: ./logs/example.log
+    # The maximum size of any log file. Can also be "1GiB" etc
+    maxFileSize: 50MB
+    # The maximum number of log files to retain.
+    retainedFileCount: 5
+ +

Syslog Logging

+ +

+ Finally, Dropwizard can also log statements to syslog. (Note: because + Java doesn’t use the native syslog bindings, your syslog server must + have an open network socket.) +

+ +
+logging:
+  # ...
+  # Settings for logging to syslog.
+  syslog:
+    # If true, write log statements to syslog.
+    enabled: false
+    # The hostname of the syslog server to which statements will be sent.
+    # N.B.: If this is the local host, the local syslog instance will need to be configured to
+    # listen on an inet socket, not just a Unix socket.
+    host: localhost
+    # The syslog facility to which statements will be sent.
+    facility: local0
+        
+ +

Testing Services

+ +

+ All of Dropwizard’s APIs are designed with testability in mind, so even your services + can have unit tests: +

+ +
+public class MyServiceTest {
+    private final Environment environment = mock(Environment.class);
+    private final MyService service = new MyService();
+    private final MyConfiguration config = new MyConfiguration();
+
+    @Before
+    public void setup() throws Exception {
+        config.setMyParam("yay");
+    }
+
+    @Test
+    public void buildsAThingResource() throws Exception {
+        service.initialize(config, environment);
+
+        verify(environment).addResource(any(ThingResource.class));
+    }
+}
+ +

+ We highly recommend Mockito for all your + mocking needs. +

+ +

Banners

+ +

+ At Yammer, each of our services prints out a big ASCII art banner on startup. Yours + should, too. It’s fun. Just add a banner.txt class to + src/main/resources and it’ll print it out when your service starts: +

+ +
+INFO  [2011-12-09 21:56:37,209] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world
+INFO  [2011-12-09 21:56:37,214] com.yammer.dropwizard.cli.ServerCommand:
+                                                 dP
+                                                 88
+  .d8888b. dP.  .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b.
+  88ooood8  `8bd8'  88'  `88 88'`88'`88 88'  `88 88 88ooood8
+  88.  ...  .d88b.  88.  .88 88  88  88 88.  .88 88 88.  ...
+  `88888P' dP'  `dP `88888P8 dP  dP  dP 88Y888P' dP `88888P'
+                                        88
+                                        dP
+
+INFO  [2011-12-09 21:56:37,214] org.eclipse.jetty.server.Server: jetty-7.6.0.RC1
+...
+ +

Resources

+ +

TODO

+ +

Paths

+ +

TODO

+ +

Parameters

+ +

TODO

+ +

Media Types

+ +

TODO

+ +

Request Entities

+ +

TODO

+ +

Responses

+ +

TODO

+ +

Error Handling

+ +

TODO

+ +

URIs

+ +

TODO

+ +

Testing

+ +

TODO

+ +

OAuth2

+ +

TODO

+ +

Representations

+ +

TODO

+ +

Basic JSON

+ +

TODO

+ +

Advanced JSON

+ +

TODO

+ +

snake_case

+ +

TODO

+ +

Validation

+ +

TODO

+ +

Basic

+ +

TODO

+ +

Advanced

+ +

TODO

+ +

Streaming Output

+ +

TODO

+ +

Testing

+ +

TODO

+ +

Running Services

+ +

TODO

+ +

In Production

+ +

TODO

+ +

Dropwizard Client

+ +

TODO

+ +

Dropwizard DB

+ +

TODO

+ +

Dropwizard Templates

+ +

TODO

+ +

Dropwizard & Scala

+ +

TODO

+

© Yammer 2011

From 4b895f3006cbe61df40b463f8220810429b2317a Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 9 Dec 2011 18:50:24 -0800 Subject: [PATCH 0079/2771] More docs. --- docs/manual.html | 259 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 247 insertions(+), 12 deletions(-) diff --git a/docs/manual.html b/docs/manual.html index ce6c0613ebc..2ed4fa14bbb 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -72,9 +72,10 @@
Dropwizard User’s Manual
Resources
  • Paths
  • +
  • Methods
  • Parameters
  • -
  • Media Types
  • Request Entities
  • +
  • Media Types
  • Responses
  • Error Handling
  • URIs
  • @@ -643,41 +644,275 @@

    Banners

    INFO [2011-12-09 21:56:37,214] org.eclipse.jetty.server.Server: jetty-7.6.0.RC1 ... +

    + We could probably make up an argument about why this is a serious devops best practice + with high ROI and an Agile Tool, but honestly we just enjoy this. +

    +

    Resources

    -

    TODO

    +

    + Unsurprisingly, most of your day-to-day work with a Dropwizard service will be in the + resource classes, which model the resources exposed in your RESTful API. Dropwizard + uses Jersey for this, so most of this section is + just re-hashing or collecting various bits of Jersey documentation. +

    + +

    + Jersey is a framework for mapping various aspects of incoming HTTP requests to POJOs and + then mapping various aspects of POJOs to outgoing HTTP responses. Here’s a basic + resource class: +

    + +
    +@Path("/{user}/notifications")
    +@Produces(MediaType.APPLICATION_JSON)
    +@Consumes(MediaType.APPLICATION_JSON)
    +public class NotificationsResource {
    +    private final NotificationStore store;
    +
    +    public NotificationsResource(NotificationStore store) {
    +        this.store = store;
    +    }
    +
    +    @GET
    +    public NotificationList fetch(@PathParam("user") LongParam userId,
    +                                  @QueryParam("count") @DefaultValue("20") IntParam count) {
    +        final List<Notification> notifications = store.fetch(userId.get(), count.get());
    +        if (notifications != null) {
    +            return new NotificationList(userId, notifications);
    +        }
    +        throw new WebApplicationException(Status.NOT_FOUND);
    +    }
    +
    +    @POST
    +    public Response add(@PathParam("user") LongParam userId,
    +                        @Valid Notification notification) {
    +        final long id = store.add(userId.get(), notification);
    +        return Response.created(UriBuilder.fromResource(NotificationResource.class)
    +                                          .build(userId.get(), id)
    +                       .build();
    +    }
    +}
    + +

    + This class provides a resource (a user’s list of notifications) which responds to + GET and POST requests to /{user}/notifications, + providing and consuming application/json representations. There’s quite a + lot of functionality on display here, and this section will explain in detail what’s + in play and how to use these features in your service. +

    Paths

    -

    TODO

    +

    + Every resource class must have a @Path annotation. The + @Path annotation isn’t just a static string, it's a + URI Template. The + {user} part denotes a named variable, and when the template matches a URI + the value of that variable will be accessible via @PathParam-annotated + method parameters. +

    + +

    + For example, an incoming request for /1001/notifications would match the + URI template, and the value 1001 would be available as the path parameter + named user. +

    + +

    + If your service doesn’t have a resource class whose @Path URI template + matches the URI of an incoming request, Jersey will automatically return a + 404 Not Found to the client. +

    + +

    Methods

    + +

    + Methods on a resource class which accept incoming requests are annotated with the HTTP + methods they handle: @GET, @POST, @PUT, + @DELETE, @HEAD, @OPTIONS, and even + @HttpMethod for arbitrary new methods. +

    + +

    + If a request comes in which matches a resource class’s path but has a method which the + class doesn’t support, Jersey will automatically return a + 405 Method Not Allowed to the client. +

    + +

    + The return value of the method (in this case, a NotificationList instance) + is then mapped to the negotiated content type. In this case, our + resource only supports JSON, and so the NotificationList is serialized to + JSON using Jackson. +

    Parameters

    -

    TODO

    +

    + The annotated methods on a resource class can accept parameters which are mapped to from + aspects of the incoming request. The *Param annotations determine which + part of the request the data is mapped, and the parameter type determines how + the data is mapped. +

    -

    Media Types

    +

    + For example: +

    -

    TODO

    +
      +
    • + A @PathParam("user")-annotated String takes the raw value + from the user variable in the matched URI template and passes it into + the method as a String. +
    • +
    • + A @QueryParam("count")-annotated IntParam parameter takes + the first count value from the request’s query string and passes it as + a String to IntParam’s constructor. IntParam + (and all other com.yammer.dropwizard.jersey.params.* classes) parses + the string as an Integer, returning a 400 Bad Request if + the value is malformed. +
    • +
    • + A @FormParam("name")-annotated Set<String> parameter + takes all the name values from a posted form and passes them to the + method as a set of strings. +
    • +
    -

    Request Entities

    +

    + What’s noteworthy here is that you can actually encapsulate the vast majority of your + validation logic using specialized parameter objects. See AbstractParam for + details. +

    -

    TODO

    +

    Request Entities

    +

    + If you’re handling request entities (e.g., an application/json object on + a PUT request), you can model this as a parameter without a + *Param annotation. In the example code, + the add method provides a good example of this: +

    + +
    +@POST
    +public Response add(@PathParam("user") LongParam userId,
    +                    @Valid Notification notification) {
    +    final long id = store.add(userId.get(), notification);
    +    return Response.created(UriBuilder.fromResource(NotificationResource.class)
    +                                      .build(userId.get(), id)
    +                   .build();
    +}
    + +

    + Jersey maps the request entity to any single, unbound parameter. In this case, because + the resource is annotated with @Consumes(MediaType.APPLICATION_JSON), it + uses the Dropwizard-provided Jackson support which, in addition to parsing the JSON and + mapping it to an instance of Notification, also runs it through + Dropwizard’s validation. +

    + +

    + If the deserialized Notification isn’t valid, Dropwizard returns a + 422 Unprocessable Entity response to the client. +

    + +

    Media Types

    + +

    + Jersey also provides full content negotiation, so if your resource class consumes + application/json but the client sends a text/plain entity, + Jersey will automatically reply with a 406 Not Acceptable. Jersey’s even + smart enough to use client-provided q-values in their Accept + headers to pick the best response content type based on what both the client and server + will support. +

    +

    Responses

    -

    TODO

    +

    + If your clients are expecting custom headers or additional information (or, if you + simply desire an additional degree of control over your responses), you can return + explicitly-built Response objects: +

    + +
    +return Response.noContent().language(Locale.GERMAN).build();
    + +

    + In general, though, we recommend you return actual domain objects if at all possible. + It makes testing resources much easier. +

    Error Handling

    -

    TODO

    +

    + If your resource class unintentionally throws an exception, Dropwizard will log that + exception (including stack traces) and return a terse, safe 500 response. +

    + +

    + If your resource class needs to return an error to the client (e.g., the requested + record doesn’t exist), you have two options: throw a + WebApplicationException or restructure your method to return a + Response. +

    + +

    + If at all possible, prefer throwing WebApplicationException instances to + returning Response objects. +

    URIs

    -

    TODO

    +

    + While Jersey doesn’t quite have first-class support for hyperlink-driven services, the + provided UriBuilder functionality does quite well. +

    + +

    + Rather than duplicate resource URIs, it’s possible (and recommended!) to initialize a + UriBuilder with the path from the resource class itself: +

    + +
    +UriBuilder.fromResource(UserResource.class).build(user.getId());

    Testing

    -

    TODO

    +

    + As with just about everything in Dropwizard, we recommend you design your resources to + be testable. Dependencies which aren’t request-injected should be passed in via the + constructor and assigned to final fields. +

    + +

    + Testing, then, consists of creating an instance of your resource class and passing it + a mock. (Again: Mockito.) +

    + +
    +public class NotificationsResourceTest {
    +    private final NotificationStore store = mock(NotificationStore.class);
    +    private final NotificationsResource resource = new NotificationsResource(store);
    +
    +    @Test
    +    public void getsReturnNotifications() {
    +        final List<Notification> notifications = mock(List.class);
    +        when(store.fetch(1, 20)).thenReturn(notifications);
    +
    +        final NotificationList list = resource.fetch(new LongParam("1"), new IntParam("20"));
    +
    +        assertThat(list.getUserId(),
    +                  is(1L));
    +
    +        assertThat(list.getNotifications(),
    +                   is(notifications));
    +    }
    +}

    OAuth2

    From 5abdc95b1688f7bee43b9a201e8c46915ad16661 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 9 Dec 2011 22:01:12 -0800 Subject: [PATCH 0080/2771] MOAR DOCS --- docs/manual.html | 258 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 244 insertions(+), 14 deletions(-) diff --git a/docs/manual.html b/docs/manual.html index 2ed4fa14bbb..6fa8a2535b6 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -96,12 +96,12 @@
    Dropwizard User’s Manual
  • Validation
  • Streaming Output
  • Testing
  • +
  • Custom Representations
  • Running Services
  • @@ -916,43 +916,273 @@

    Testing

    OAuth2

    -

    TODO

    +

    + Dropwizard provides some super-minimalist support for + Oauth 2: +

    + +
    +public Blah doAThing(@BearerToken String token) {
    +    // etc
    +}
    + +

    + The Oauth 2 bearer token will be passed in via token. +

    Representations

    -

    TODO

    +

    + Representation classes are classes which, when handled to various Jersey + MessageBodyReader and MessageBodyWriter providers, become the + entities in your service’s API. Dropwizard heavily favors JSON, but it’s possible to + map from any POJO to custom formats and back. +

    Basic JSON

    -

    TODO

    +

    + Jackson is awesome at converting regular POJOs to JSON and back. This file: +

    + +
    +public class Notification {
    +    @JsonProperty
    +    private String text;
    +
    +    public Notification(String text) {
    +        this.text = text;
    +    }
    +
    +    public String getText() {
    +        return text;
    +    }
    +
    +    public String setText(String text) {
    +        this.text = text;
    +    }
    +}
    + +

    + gets converted into this JSON: +

    -

    Advanced JSON

    +
    +{
    +    "text": "hey it's the value of the text field"
    +}
    -

    TODO

    +

    + If, at some point, you need to change the JSON field name or the Java field without + affecting the other, you can add an explicit field name to the + @JsonProperty annotation. +

    + +

    + If you prefer immutable objects rather than JavaBeans, that’s also doable: +

    + +
    +public class Notification {
    +    @JsonProperty
    +    private final String text;
    +
    +    public Notification(@JsonProperty("text") String text) {
    +        this.text = text;
    +    }
    +
    +    public String getText() {
    +        return text;
    +    }
    +}
    +

    Advanced JSON

    + +

    + Not all JSON representations map nicely to the objects your service deals with, so it’s + sometimes necessary to use custom serializers and deserializers. Just annotate your + object like this: +

    + +
    +@JsonSerialize(using=FunkySerializer.class)
    +@JsonDeserialize(using=FunkyDeserializer.class)
    +public class Funky {
    +    // ...
    +}
    + +

    + Then make a FunkySerializer class which implements + JsonSerializer<Funky> and a FunkyDeserializer class + which implements JsonDeserializer<Funky>. +

    +

    snake_case

    -

    TODO

    - +

    + A common issue with JSON is the disagreement between camelCase and + snake_case field names. Java and Javascript folks tend to like + camelCase; Ruby, Python, and Perl folks insist on snake_case. + To make Dropwizard automatically convert field names to snake_case (and + back), just annotate the class with @JsonSnakeCase: +

    + + + +
    +@JsonSnakeCase
    +public class Person {
    +    @JsonProperty
    +    private String firstName;
    +
    +    public Person(String firstName) {
    +        this.firstName = firstName;
    +    }
    +
    +    public String getFirstName() {
    +        return firstName;
    +    }
    +}
    + +

    + gets converted into this JSON: +

    + +
    +{
    +    "first_name": "Coda"
    +}
    +

    Validation

    -

    TODO

    +

    + Like configuration classes, you can add validation + annotations to fields of your representation classes and validate them. If we‘re + accepting client-provided Person objects, we probably want to ensure that + the name field of the object isn’t null or blank. We can do + this as follows: +

    -

    Basic

    +
    +public class Person {
    +    @NotEmpty // ensure that name isn't null or blank
    +    @JsonProperty
    +    private final String name;
     
    -        

    TODO

    + public Person(@JsonProperty("name") String name) { + this.name = name; + } + + public String getName() { + return name; + } +}
    + +

    + Then, in our resource class, we can add the @Valid annotation to the + Person annotation: +

    + +
    +@PUT
    +public Response replace(@Valid Person person) {
    +    // ...
    +}
    + +

    + If the name field is missing, Dropwizard will return a + text/plain 422 Unprocessable Entity response detailing the + validation errors: +

    + +
    +* name may not be empty

    Advanced

    -

    TODO

    +

    + More complex validations (for example, cross-field comparisons) are often hard to + do using declarative annotations. As an emergency maneuver, add the + @ValidationMethod to any boolean-returning method which + begins with is: +

    + +
    +@ValidationMethod(message="may not be Coda")
    +public boolean isNotCoda() {
    +    return !("Coda".equals(name));
    +}
    + +

    + Due to the rather daft JavaBeans conventions, the method must begin with + is. This is a limitation of Hibernate Validator, + not Dropwizard. +

    Streaming Output

    -

    TODO

    +

    + If your service happens to return lots of information, you may get a big performance + and efficiency bump by using streaming output. By returning an object which implements + Jersey’s StreamingOutput interface, your method can stream the response + entity in a chunk-encoded output stream. Otherwise, you’ll need to fully construct your + return value and then hand it off to be sent to the client. +

    Testing

    -

    TODO

    +

    + The dropwizard-testing module contains a number of helper methods for + testing JSON parsing and generating. Given a JSON fixture file (e.g., + src/test/resources/fixtures/person.json), you can test that a + Person instance generates the same JSON as the fixture with the following: +

    + +
    +import static com.yammer.dropwizard.testing.JsonHelpers.asJson;
    +import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture;
    +
    +@Test
    +public void producesTheExpectedJson() throws Exception {
    +    assertThat("rendering a person as JSON produces a valid API representation",
    +               asJson(person),
    +               is(jsonFixture("fixtures/person.json")));
    +}
    + +

    + This does a whitespace- and comment-insensitive comparison of the generated JSON and the + JSON in the file. If they’re different, both JSON representations are helpfully + displayed in the assertion error. +

    + +

    + Likewise, you can also test the parsing of the same JSON file to guarantee round-trip + compatibility: +

    + +
    +import static com.yammer.dropwizard.testing.JsonHelpers.fromJson;
    +
    +@Test
    +public void consumesTheExpectedJson() throws Exception {
    +    assertThat("parsing a valid API representation produces a person",
    +               fromJson(jsonFixture("fixtures/person.json"), Person.class),
    +               is(person));
    +}
    + +

    Custom Representations

    + +

    + Sometimes, though, you’ve got some wacky output format you need to produce or consume + and no amount of arguing will make JSON acceptable. That’s unfortunate but OK. You can + add support for arbitrary input and output formats by creating classes which implement + Jersey’s MessageBodyReader<T> and + MessageBodyWriter<T> interfaces. (Make sure they’re annotated with + @Provider and @Produces("text/gibberish") or + @Consumes("text/gibberish").) Once you’re done, just add instances of them + (or their classes if they depend on Jersey’s @Context injection) with your + service’s Environment on initialization. +

    Running Services

    From 7192ad8cc88669077d22d4853c9530cf5e436cfe Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 9 Dec 2011 23:29:08 -0800 Subject: [PATCH 0081/2771] Make links to other pages open in new tabs. --- docs/getting-started.html | 61 ++++++++++++++++++++------------------- docs/manual.html | 29 ++++++++++--------- 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/docs/getting-started.html b/docs/getting-started.html index 53dc9dd8e1d..1a7add06a9c 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -77,7 +77,7 @@

    Jetty for HTTP

    Because you can't be a web service without HTTP, Dropwizard uses the - Jetty HTTP library to embed an incredibly + Jetty HTTP library to embed an incredibly tuned HTTP server directly into your project. Instead of handing your service off to a complicated application server, Dropwizard projects have a main method which spins up an HTTP server. Running your service as a simple process eliminates a @@ -92,20 +92,21 @@

    Jersey for REST

    For building RESTful web services, - we've found nothing beats Jersey - (the JAX-RS reference implementation) - in terms of features or performance. It allows you to write clean, testable class which - gracefully map HTTP requests to simple Java objects. It supports streaming output, - matrix URI parameters, conditional GET requests, and much, much more. + we've found nothing beats Jersey + (the JAX-RS reference + implementation) in terms of features or performance. It allows you to write clean, + testable class which gracefully map HTTP requests to simple Java objects. It supports + streaming output, matrix URI parameters, conditional GET requests, and + much, much more.

    Jackson for JSON

    In terms of data formats, JSON has become the web’s lingua franca, and - Jackson is the king of JSON on the JVM. In - addition to being lightning fast, it has a sophisticated object mapper, allowing you to - export your domain models directly. + Jackson is the king of JSON + on the JVM. In addition to being lightning fast, it has a sophisticated object mapper, + allowing you to export your domain models directly.

    Metrics for metrics (duh)

    @@ -125,32 +126,32 @@

    And Friends

    • - Guava, + Guava, which, in addition to highly optimized immutable data structures, provides a growing number of classes to speed up development in Java.
    • - Log4j and - slf4j for performant logging. + Log4j and + slf4j for performant logging.
    • - Hibernate Validator, - the JSR-303 reference + Hibernate Validator, + the JSR-303 reference implementation, provides an easy, declarative framework for validating user input and generating helpful, internationalizable error messages.
    • - Apache HttpClient + Apache HttpClient and Jersey's client library allow for both low- and high-level interaction with other web services.
    • - JDBI is the most straight-forward way to use a - relational database with Java. + JDBI is the most straight-forward + way to use a relational database with Java.
    • - Freemarker is a simple template - system for more user-facing services. + Freemarker is a + simple template system for more user-facing services.
    @@ -163,16 +164,16 @@

    And Friends

    Setting Up Maven

    - We recommend you use Maven for new Dropwizard - services. If you're a big - Ant/Ivy, - Buildr, - Gradle, + We recommend you use Maven for new + Dropwizard services. If you're a big + Ant/Ivy, + Buildr, + Gradle, SBT, - or Gant fan, that’s cool, but we use Maven and - we'll be using Maven as we go through this example service. If you have any questions - about how Maven works, - Maven: The Complete Reference + or Gant fan, that’s cool, but we + use Maven and we'll be using Maven as we go through this example service. If you have + any questions about how Maven works, + Maven: The Complete Reference should have what you’re looking for. (We’re assuming you know how to create a new Maven project.)

    @@ -216,8 +217,8 @@

    Creating A Configuration Class

    Each Dropwizard service has its own subclass of the Configuration class which specify environment-specific parameters. These parameters are specified in a - YAML configuration file which is deserialized to - an instance of your service’s configuration class and validated. + YAML configuration file which is + deserialized to an instance of your service’s configuration class and validated.

    diff --git a/docs/manual.html b/docs/manual.html index 6fa8a2535b6..a9feb87a583 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -358,8 +358,9 @@

    Managed Objects

    - For example, given a theoretical Riak client which - needs to be started and stopped: + For example, given a theoretical + Riak client which needs to be + started and stopped:

    @@ -462,9 +463,10 @@ 

    Tasks

    Logging

    - Dropwizard uses Log4j for its logging - backend. It provides a slf4j implementation, and - even routes all java.util.logging usage through log4j. + Dropwizard uses Log4j for + its logging backend. It provides an + slf4j implementation, and even + routes all java.util.logging usage through log4j.

    Dropwizard’s log format has a few specific goals:

    @@ -617,7 +619,8 @@

    Testing Services

    }

    - We highly recommend Mockito for all your + We highly recommend + Mockito for all your mocking needs.

    @@ -654,8 +657,8 @@

    Resources

    Unsurprisingly, most of your day-to-day work with a Dropwizard service will be in the resource classes, which model the resources exposed in your RESTful API. Dropwizard - uses Jersey for this, so most of this section is - just re-hashing or collecting various bits of Jersey documentation. + uses Jersey for this, so most of + this section is just re-hashing or collecting various bits of Jersey documentation.

    @@ -708,9 +711,9 @@

    Paths

    Every resource class must have a @Path annotation. The @Path annotation isn’t just a static string, it's a - URI Template. The - {user} part denotes a named variable, and when the template matches a URI - the value of that variable will be accessible via @PathParam-annotated + URI Template. + The {user} part denotes a named variable, and when the template matches a + URI the value of that variable will be accessible via @PathParam-annotated method parameters.

    @@ -891,7 +894,7 @@

    Testing

    Testing, then, consists of creating an instance of your resource class and passing it - a mock. (Again: Mockito.) + a mock. (Again: Mockito.)

    @@ -918,7 +921,7 @@ 

    OAuth2

    Dropwizard provides some super-minimalist support for - Oauth 2: + Oauth 2:

    
    From 3236771d53b42c4b5341de5350967cdb1f08fe01 Mon Sep 17 00:00:00 2001
    From: Coda Hale 
    Date: Fri, 9 Dec 2011 23:29:20 -0800
    Subject: [PATCH 0082/2771] Don't static import String.format.
    
    ---
     docs/getting-started.html | 9 +++------
     1 file changed, 3 insertions(+), 6 deletions(-)
    
    diff --git a/docs/getting-started.html b/docs/getting-started.html
    index 1a7add06a9c..9db2161c5b7 100644
    --- a/docs/getting-started.html
    +++ b/docs/getting-started.html
    @@ -423,8 +423,6 @@ 

    Creating A Resource Class

    import javax.ws.rs.core.MediaType; import java.util.concurrent.atomic.AtomicLong; -import static java.lang.String.format; - @Path("/hello-world") @Produces(MediaType.APPLICATION_JSON) public class HelloWorldResource { @@ -445,7 +443,8 @@

    Creating A Resource Class

    public Saying sayHello(@QueryParam("name") Optional<String> name) { final TimerContext context = GETS.time(); try { - return new Saying(counter.incrementAndGet(), format(template, name.or(defaultName))); + return new Saying(counter.incrementAndGet(), + String.format(template, name.or(defaultName))); } finally { context.stop(); } @@ -561,8 +560,6 @@

    Adding A Health Check

    import com.yammer.metrics.core.HealthCheck; -import static java.lang.String.format; - public class TemplateHealthCheck extends HealthCheck { private final String template; @@ -577,7 +574,7 @@

    Adding A Health Check

    @Override public Result check() throws Exception { - final String saying = format(template, "TEST"); + final String saying = String.format(template, "TEST"); if (!saying.contains("TEST")) { return Result.unhealthy("template doesn't include a name"); } From edb38ae95f67c0bf867b9837b4f07690b58e128f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sun, 11 Dec 2011 22:45:01 -0800 Subject: [PATCH 0083/2771] Added link to real docs. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c040ee26511..ef1ad4bb377 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,5 @@ historically not sucked: [Yammer](https://www.yammer.com)'s high-performance, low-latency, Java and Scala services all use Dropwizard. In fact, Dropwizard is really just a simple extraction of [Yammer](https://www.yammer.com)'s glue code. + +Read more at [dropwizard.github.com]. From 5c0dce90d5cede71102a1fe4c60d02479df0f4a5 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sun, 11 Dec 2011 22:46:02 -0800 Subject: [PATCH 0084/2771] But this time try it without broken links. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef1ad4bb377..bc30425d8f5 100644 --- a/README.md +++ b/README.md @@ -19,4 +19,4 @@ historically not sucked: Dropwizard. In fact, Dropwizard is really just a simple extraction of [Yammer](https://www.yammer.com)'s glue code. -Read more at [dropwizard.github.com]. +Read more at [dropwizard.codahale.com](http://dropwizard.codahale.com). From fe2943eaf8e687ea5b01c013b26f62590db95608 Mon Sep 17 00:00:00 2001 From: Adam Marcus Date: Mon, 12 Dec 2011 08:20:23 -0500 Subject: [PATCH 0085/2771] Text change: code->content --- docs/getting-started.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.html b/docs/getting-started.html index 9db2161c5b7..933ff137973 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -384,7 +384,7 @@

    Creating A Representation Class

    First, it’s immutable. This makes Saying instances very easy to reason about multi-threaded environments as well as single-threaded environments. - Second, it uses the Java Bean standard for the id and code + Second, it uses the Java Bean standard for the id and content properties. This allows Jackson to serialize it to the JSON we need. The Jackson object mapping code will populate the id field of the JSON object with the return value of getId(), likewise with content and From a32f6ff567b22e091a3e9ec0319a93838b6159db Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 12 Dec 2011 16:20:34 -0800 Subject: [PATCH 0086/2771] Fix TaskServletTest. --- .../yammer/dropwizard/tasks/tests/TaskServletTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/TaskServletTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/TaskServletTest.java index ceac5e423a0..f309ce8f238 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/TaskServletTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/tasks/tests/TaskServletTest.java @@ -37,7 +37,7 @@ public void setUp() throws Exception { @Test public void returnsA404WhenNotFound() throws Exception { when(request.getMethod()).thenReturn("POST"); - when(request.getRequestURI()).thenReturn("/test"); + when(request.getRequestURI()).thenReturn("/tasks/test"); servlet.service(request, response); @@ -49,7 +49,7 @@ public void runsATestWhenFound() throws Exception { final PrintWriter output = mock(PrintWriter.class); when(request.getMethod()).thenReturn("POST"); - when(request.getRequestURI()).thenReturn("/gc"); + when(request.getRequestURI()).thenReturn("/tasks/gc"); when(request.getParameterNames()).thenReturn(Collections.enumeration(ImmutableList.of())); when(response.getWriter()).thenReturn(output); @@ -63,7 +63,7 @@ public void passesQueryStringParamsAlong() throws Exception { final PrintWriter output = mock(PrintWriter.class); when(request.getMethod()).thenReturn("POST"); - when(request.getRequestURI()).thenReturn("/gc"); + when(request.getRequestURI()).thenReturn("/tasks/gc"); when(request.getParameterNames()).thenReturn(Collections.enumeration(ImmutableList.of("runs"))); when(request.getParameterValues("runs")).thenReturn(new String[]{"1"}); when(response.getWriter()).thenReturn(output); @@ -77,7 +77,7 @@ public void passesQueryStringParamsAlong() throws Exception { @SuppressWarnings("unchecked") public void returnsA500OnExceptions() throws Exception { when(request.getMethod()).thenReturn("POST"); - when(request.getRequestURI()).thenReturn("/gc"); + when(request.getRequestURI()).thenReturn("/tasks/gc"); when(request.getParameterNames()).thenReturn(Collections.enumeration(ImmutableList.of())); final RuntimeException ex = new RuntimeException("whoops"); From 0388bdeedb8e3b8ab16c317e287a29c5d2eabcd9 Mon Sep 17 00:00:00 2001 From: Ted Nyman Date: Mon, 12 Dec 2011 23:38:54 -0800 Subject: [PATCH 0087/2771] Link to SnakeYaml instead of yaml for ruby --- docs/getting-started.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.html b/docs/getting-started.html index 933ff137973..b280c9d8b8d 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -832,7 +832,7 @@

    Next Steps

    Learn more about Jackson »

    -

    Learn more about YAML »

    +

    Learn more about YAML »

    © Yammer 2011

    From 23558f7afa5b6075d45a98c1d77c7246b971b32e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 13 Dec 2011 10:48:06 -0800 Subject: [PATCH 0088/2771] Upgrade to Jersey 1.11. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f0cab0c229b..2c299809f6e 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 2.0.0-BETA18-SNAPSHOT - 1.10 + 1.11 From 813ba7c52d6c4c6b168ba35f0f4812c3f4c948ec Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 13 Dec 2011 13:50:41 -0800 Subject: [PATCH 0089/2771] Automatically add healthchecks for Databases. --- .../src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java index 9ab3802a67b..98cbddd5bb6 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java @@ -28,6 +28,7 @@ public Database build(String name, Environment environment) throws ClassNotFound final DataSource dataSource = buildDataSource(connectionConfig, pool); final Database database = new Database(dataSource, pool); environment.manage(database); + environment.addHealthCheck(new DatabaseHealthCheck(database, name)); return database; } From 2bca004455f0d2fd90dca05beadfe953fdc808f5 Mon Sep 17 00:00:00 2001 From: Tom Crayford Date: Wed, 14 Dec 2011 14:13:43 +0000 Subject: [PATCH 0090/2771] Fix a grammar error --- docs/getting-started.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.html b/docs/getting-started.html index b280c9d8b8d..875025cb02d 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -95,7 +95,7 @@

    Jersey for REST

    we've found nothing beats Jersey (the JAX-RS reference implementation) in terms of features or performance. It allows you to write clean, - testable class which gracefully map HTTP requests to simple Java objects. It supports + testable classes which gracefully map HTTP requests to simple Java objects. It supports streaming output, matrix URI parameters, conditional GET requests, and much, much more.

    From df7a23724b8c8c641682fc383aaa119507b7a0b9 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 13 Dec 2011 15:03:36 -0800 Subject: [PATCH 0091/2771] Pretty up some Javadocs. --- .../main/java/com/yammer/dropwizard/bundles/AssetsBundle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java index a781b53fadb..14b0c404486 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java @@ -32,7 +32,7 @@ public AssetsBundle() { * {@code path} of {@code "/assets"}, {@code src/main/resources/assets/example.js} would be * served up from {@code /assets/example.js}. * - * @param path the classpath and URI root of the static asset files + * @param path the classpath and URI root of the static asset files * @see AssetsBundle#AssetsBundle(String, int) */ public AssetsBundle(String path) { From a60da8f05a3a6a5389207f43b2d9c6b013936d4f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 14 Dec 2011 10:50:51 -0800 Subject: [PATCH 0092/2771] Fix Database w.r.t. the new metrics-jdbi. --- .../src/main/java/com/yammer/dropwizard/db/Database.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index b6ad6864527..b9f4a3bfbbf 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -30,7 +30,7 @@ public Database(DataSource dataSource, ObjectPool pool) { this.pool = pool; this.ping = onDemand(Ping.class); setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); - setTimingCollector(new InstrumentedTimingCollector(Metrics.defaultRegistry(), Database.class)); + setTimingCollector(new InstrumentedTimingCollector(Metrics.defaultRegistry())); setStatementRewriter(new NamePrependingStatementRewriter()); setStatementLocator(new ScopedStatementLocator()); registerArgumentFactory(new OptionalArgumentFactory()); From 596cf2503c3164f532a2b563d89e5496908b990f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 14 Dec 2011 12:35:47 -0800 Subject: [PATCH 0093/2771] Make a few methods in DatabaseFactory static. --- .../main/java/com/yammer/dropwizard/db/DatabaseFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java index 98cbddd5bb6..920c6105b51 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java @@ -32,7 +32,7 @@ public Database build(String name, Environment environment) throws ClassNotFound return database; } - private DataSource buildDataSource(DatabaseConnectionConfiguration connectionConfig, GenericObjectPool pool) { + private static DataSource buildDataSource(DatabaseConnectionConfiguration connectionConfig, GenericObjectPool pool) { final Properties properties = new Properties(); for (Map.Entry property : connectionConfig.getProperties().entrySet()) { properties.setProperty(property.getKey(), property.getValue()); @@ -55,7 +55,7 @@ private DataSource buildDataSource(DatabaseConnectionConfiguration connectionCon return new PoolingDataSource(pool); } - private GenericObjectPool buildPool(DatabaseConnectionConfiguration connectionConfig) { + private static GenericObjectPool buildPool(DatabaseConnectionConfiguration connectionConfig) { final GenericObjectPool pool = new GenericObjectPool(null); pool.setMaxWait(connectionConfig.getMaxWaitForConnection().toMilliseconds()); pool.setMinIdle(connectionConfig.getMinSize()); From 539a0f9bba3016794e437a949ef0e92bd3a9f417 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 14 Dec 2011 12:36:05 -0800 Subject: [PATCH 0094/2771] Default to waiting for 1s for a connection. --- .../java/com/yammer/dropwizard/db/DatabaseConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java index efba8f6bb4d..42fc9b58781 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java @@ -31,7 +31,7 @@ public static class DatabaseConnectionConfiguration { @NotNull @Pattern(regexp = Duration.VALID_DURATION) - private String maxWaitForConnection = "8ms"; + private String maxWaitForConnection = "1s"; @NotNull private String validationQuery = "/* Health Check */ SELECT 1"; From 3c36d14784ab603328736aedbe4caf0e6bc2c408 Mon Sep 17 00:00:00 2001 From: Chris Gray Date: Wed, 14 Dec 2011 17:58:27 -0800 Subject: [PATCH 0095/2771] Adding the DBIExceptionsBundle --- .../bundles/DBIExceptionsBundle.java | 17 ++++++++ .../jersey/LoggingDBIExceptionMapper.java | 42 +++++++++++++++++++ .../jersey/LoggingSQLExceptionMapper.java | 35 ++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/bundles/DBIExceptionsBundle.java create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java create mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/bundles/DBIExceptionsBundle.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/bundles/DBIExceptionsBundle.java new file mode 100644 index 00000000000..8b32301f9dd --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/bundles/DBIExceptionsBundle.java @@ -0,0 +1,17 @@ +package com.yammer.dropwizard.bundles; + +import com.yammer.dropwizard.Bundle; +import com.yammer.dropwizard.config.Environment; +import com.yammer.dropwizard.jersey.LoggingDBIExceptionMapper; +import com.yammer.dropwizard.jersey.LoggingSQLExceptionMapper; + +/** + * A bundle for logging SQLExceptions and DBIExceptions so that their actual causes aren't overlooked. + */ +public class DBIExceptionsBundle implements Bundle { + @Override + public void initialize(Environment environment) { + environment.addProvider(new LoggingSQLExceptionMapper()); + environment.addProvider(new LoggingDBIExceptionMapper()); + } +} diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java new file mode 100644 index 00000000000..e6c00c8991b --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java @@ -0,0 +1,42 @@ +package com.yammer.dropwizard.jersey; + +import org.skife.jdbi.v2.exceptions.DBIException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import java.sql.SQLException; +import java.util.Random; + +/** + * Iterates through a DBIException's cause if it's a SQLException otherwise log as normal. + */ +@Provider +public class LoggingDBIExceptionMapper implements ExceptionMapper { + private final Logger logger = LoggerFactory.getLogger(LoggingDBIExceptionMapper.class); + private final Random random = new Random(); + + @Override + public Response toResponse(DBIException exception) { + final Throwable cause = exception.getCause(); + final long id = random.nextLong(); + + if (cause instanceof SQLException) { + for (Throwable throwable : (SQLException)cause) + logger.error(String.format("Error handling a request: %016x", id), throwable); + } + else + logger.error(String.format("Error handling a request: %016x", id), exception); + + + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .type(MediaType.TEXT_PLAIN_TYPE) + .entity(String.format( + "There was an error processing your request. It has been logged (ID %016x).\n", + id)) + .build(); + } +} diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java new file mode 100644 index 00000000000..300ef45cd52 --- /dev/null +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java @@ -0,0 +1,35 @@ +package com.yammer.dropwizard.jersey; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import java.sql.SQLException; +import java.util.Random; + +/** + * Iterates through SQLExceptions to log all causes + */ +@Provider +public class LoggingSQLExceptionMapper implements ExceptionMapper { + private final Logger logger = LoggerFactory.getLogger(LoggingSQLExceptionMapper.class); + private final Random random = new Random(); + + @Override + public Response toResponse(SQLException exception) { + final long id = random.nextLong(); + + for (Throwable throwable : exception) + logger.error(String.format("Error handling a request: %016x", id), throwable); + + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .type(MediaType.TEXT_PLAIN_TYPE) + .entity(String.format( + "There was an error processing your request. It has been logged (ID %016x).\n", + id)) + .build(); + } +} From 5b2630f065f6282a20861e24a9d4cdfcedca190a Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 14 Dec 2011 18:50:45 -0800 Subject: [PATCH 0096/2771] Refactor the exception mappers a bit. --- .../yammer/dropwizard/config/Environment.java | 2 +- .../jersey/LoggingExceptionMapper.java | 34 +++++++++++++------ .../jersey/LoggingDBIExceptionMapper.java | 30 +++++----------- .../jersey/LoggingSQLExceptionMapper.java | 26 ++++---------- 4 files changed, 39 insertions(+), 53 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index f16ea6afa11..377cb1ba92e 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -70,7 +70,7 @@ public Environment() { this.lifeCycle = new AggregateLifeCycle(); enableJerseyFeature(ResourceConfig.FEATURE_DISABLE_WADL); - addProvider(new LoggingExceptionMapper()); + addProvider(new LoggingExceptionMapper() {}); // create a subclass to pin it to Throwable addServlet(new ServletContainer(config), ROOT_PATH).setInitOrder(Integer.MAX_VALUE); addTask(new GarbageCollectionTask()); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java index 1bc3937c353..1b55c7e4339 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java @@ -14,24 +14,36 @@ // TODO: 10/12/11 -- write docs for LoggingExceptionMapper @Provider -public class LoggingExceptionMapper implements ExceptionMapper { - private final Logger logger = LoggerFactory.getLogger(LoggingExceptionMapper.class); - private final Random random = new Random(); +public class LoggingExceptionMapper implements ExceptionMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggingExceptionMapper.class); + private static final Random RANDOM = new Random(); @Override - public Response toResponse(Throwable exception) { + public Response toResponse(E exception) { if (exception instanceof WebApplicationException) { return ((WebApplicationException) exception).getResponse(); } - - final long id = random.nextLong(); - logger.error(String.format("Error handling a request: %016x", id), exception); - + final long id = randomId(); + logException(id, exception); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .type(MediaType.TEXT_PLAIN_TYPE) - .entity(String.format( - "There was an error processing your request. It has been logged (ID %016x).\n", - id)) + .entity(formatResponseEntity(id, exception)) .build(); } + + protected void logException(long id, E exception) { + LOGGER.error(formatLogMessage(id, exception), exception); + } + + protected String formatResponseEntity(long id, Throwable exception) { + return String.format("There was an error processing your request. It has been logged (ID %016x).\n", id); + } + + protected String formatLogMessage(long id, Throwable exception) { + return String.format("Error handling a request: %016x", id); + } + + protected static long randomId() { + return RANDOM.nextLong(); + } } diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java index e6c00c8991b..34d48c6faf3 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java @@ -4,39 +4,25 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; import java.sql.SQLException; -import java.util.Random; /** * Iterates through a DBIException's cause if it's a SQLException otherwise log as normal. */ @Provider -public class LoggingDBIExceptionMapper implements ExceptionMapper { - private final Logger logger = LoggerFactory.getLogger(LoggingDBIExceptionMapper.class); - private final Random random = new Random(); +public class LoggingDBIExceptionMapper extends LoggingExceptionMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggingDBIExceptionMapper.class); @Override - public Response toResponse(DBIException exception) { + protected void logException(long id, DBIException exception) { final Throwable cause = exception.getCause(); - final long id = random.nextLong(); - if (cause instanceof SQLException) { - for (Throwable throwable : (SQLException)cause) - logger.error(String.format("Error handling a request: %016x", id), throwable); + for (Throwable throwable : (SQLException)cause) { + LOGGER.error(formatLogMessage(id, throwable), throwable); + } + } else { + LOGGER.error(formatLogMessage(id, exception), exception); } - else - logger.error(String.format("Error handling a request: %016x", id), exception); - - - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .type(MediaType.TEXT_PLAIN_TYPE) - .entity(String.format( - "There was an error processing your request. It has been logged (ID %016x).\n", - id)) - .build(); } } diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java index 300ef45cd52..6d7efd967a2 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java @@ -3,33 +3,21 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; import java.sql.SQLException; -import java.util.Random; /** * Iterates through SQLExceptions to log all causes */ @Provider -public class LoggingSQLExceptionMapper implements ExceptionMapper { - private final Logger logger = LoggerFactory.getLogger(LoggingSQLExceptionMapper.class); - private final Random random = new Random(); +public class LoggingSQLExceptionMapper extends LoggingExceptionMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggingSQLExceptionMapper.class); @Override - public Response toResponse(SQLException exception) { - final long id = random.nextLong(); - - for (Throwable throwable : exception) - logger.error(String.format("Error handling a request: %016x", id), throwable); - - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .type(MediaType.TEXT_PLAIN_TYPE) - .entity(String.format( - "There was an error processing your request. It has been logged (ID %016x).\n", - id)) - .build(); + protected void logException(long id, SQLException exception) { + final String message = formatLogMessage(id, exception); + for (Throwable throwable : exception) { + LOGGER.error(message, throwable); + } } } From 54b22fd4203495a6b4e4cc6a88874d5b354f276e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 14 Dec 2011 18:50:48 -0800 Subject: [PATCH 0097/2771] Make dw-example use metrics-aop. --- dropwizard-example/pom.xml | 5 +++++ .../com/example/helloworld/HelloWorldService.java | 6 ++++-- .../helloworld/resources/HelloWorldResource.java | 15 +++------------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 08bf30e5a8b..891fce9a931 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -22,6 +22,11 @@ dropwizard-core ${project.version} + + com.yammer.metrics + metrics-aop + 2.0.0-BETA18-SNAPSHOT + junit junit diff --git a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java index b9ee791e19a..919682a960a 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java @@ -5,8 +5,10 @@ import com.example.helloworld.health.TemplateHealthCheck; import com.example.helloworld.resources.HelloWorldResource; import com.yammer.dropwizard.Service; -import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.bundles.AssetsBundle; +import com.yammer.dropwizard.config.Environment; + +import static com.yammer.metrics.aop.Instrumentation.instrument; public class HelloWorldService extends Service { public static void main(String[] args) throws Exception { @@ -25,7 +27,7 @@ protected void initialize(HelloWorldConfiguration configuration, final Template template = configuration.buildTemplate(); environment.addHealthCheck(new TemplateHealthCheck(template)); - environment.addResource(new HelloWorldResource(template)); + environment.addResource(instrument(new HelloWorldResource(template))); } } diff --git a/dropwizard-example/src/main/java/com/example/helloworld/resources/HelloWorldResource.java b/dropwizard-example/src/main/java/com/example/helloworld/resources/HelloWorldResource.java index a782a2c3f5a..24657965468 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/resources/HelloWorldResource.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/resources/HelloWorldResource.java @@ -3,9 +3,7 @@ import com.example.helloworld.core.Saying; import com.example.helloworld.core.Template; import com.google.common.base.Optional; -import com.yammer.metrics.Metrics; -import com.yammer.metrics.core.TimerContext; -import com.yammer.metrics.core.TimerMetric; +import com.yammer.metrics.aop.annotation.Timed; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -17,9 +15,6 @@ @Path("/hello-world") @Produces(MediaType.APPLICATION_JSON) public class HelloWorldResource { - private static final TimerMetric GETS = Metrics.newTimer(HelloWorldResource.class, - "get-requests"); - private final Template template; private final AtomicLong counter; @@ -29,12 +24,8 @@ public HelloWorldResource(Template template) { } @GET + @Timed(name = "get-requests") public Saying sayHello(@QueryParam("name") Optional name) { - final TimerContext context = GETS.time(); - try { - return new Saying(counter.incrementAndGet(), template.render(name)); - } finally { - context.stop(); - } + return new Saying(counter.incrementAndGet(), template.render(name)); } } From 61bc12a1190f1fa7badbec202aebed94a282b357 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 14 Dec 2011 19:51:19 -0800 Subject: [PATCH 0098/2771] Bump to jdbi 2.29. --- dropwizard-db/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 61f004e10cf..c07ee57fa2d 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -23,7 +23,7 @@ org.jdbi jdbi - 2.28 + 2.29 com.yammer.metrics From 60713321a7f85c45a410c26789ed5206dca65982 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 16 Dec 2011 14:05:41 -0800 Subject: [PATCH 0099/2771] Added links to the mailing list. God help me. --- docs/getting-started.html | 1 + docs/index.html | 1 + docs/manual.html | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/getting-started.html b/docs/getting-started.html index 875025cb02d..38b1a626f57 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -28,6 +28,7 @@
  • Home
  • Getting Started
  • Manual
  • +
  • Mailing List
  • Code
  • diff --git a/docs/index.html b/docs/index.html index a91bbcdc46d..fd191122702 100644 --- a/docs/index.html +++ b/docs/index.html @@ -24,6 +24,7 @@
  • Home
  • Getting Started
  • Manual
  • +
  • Mailing List
  • Code
  • diff --git a/docs/manual.html b/docs/manual.html index a9feb87a583..65e931a2e42 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -27,6 +27,7 @@
  • Home
  • Getting Started
  • Manual
  • +
  • Mailing List
  • Code
  • From 3d2935228cd1d4e24822122f31cde018e472ef1b Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 16 Dec 2011 17:20:06 -0800 Subject: [PATCH 0100/2771] Upgrade to Guava 11rc1. --- dropwizard-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 07478de3a89..b2dec5c9078 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -104,7 +104,7 @@ com.google.guava guava - 10.0.1 + 11.0-rc1 org.hibernate From ca46b75d0cfb95525f528b38c33cd9356e1439dc Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 17 Dec 2011 08:44:57 -0800 Subject: [PATCH 0101/2771] Bump to Jackson 1.9.3. --- dropwizard-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index b2dec5c9078..63dc50fa533 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -16,7 +16,7 @@ 7.6.0.RC1 - 1.9.2 + 1.9.3 1.6.4 From e76970da6dbf249040bce33ea0e34d9033291a30 Mon Sep 17 00:00:00 2001 From: Ted Nyman Date: Sun, 18 Dec 2011 15:02:49 -0800 Subject: [PATCH 0102/2771] More .gitignore updating. --- .gitignore | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.gitignore b/.gitignore index 89f5244dd77..dce44572f55 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,4 @@ .idea -lib_managed -src_managed -project/boot target -src/main/java/com/yammer/streamie/data/pb -streamie.conf atlassian-ide-plugin.xml -project/plugins/project/build.properties logs From 90ad2a24d5a486acd956c5d3400e4fc1fd43b6f3 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sun, 18 Dec 2011 17:32:02 -0800 Subject: [PATCH 0103/2771] Upgrade to Guava 11.0. --- dropwizard-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 63dc50fa533..0240f1e7f15 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -104,7 +104,7 @@ com.google.guava guava - 11.0-rc1 + 11.0 org.hibernate From 95116c5a5c2e3d68387187ca92c34148d8124d23 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 19 Dec 2011 10:34:02 -0800 Subject: [PATCH 0104/2771] Bump to Metrics 2.0.0-BETA18. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2c299809f6e..ef3034dc9dd 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ - 2.0.0-BETA18-SNAPSHOT + 2.0.0-BETA18 1.11 From 2c9ab089f7b9c8e17398522ee5a96daa593062b7 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 19 Dec 2011 10:41:33 -0800 Subject: [PATCH 0105/2771] Also bump the example app. --- dropwizard-example/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 891fce9a931..e1a4c8ed78e 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -25,7 +25,7 @@ com.yammer.metrics metrics-aop - 2.0.0-BETA18-SNAPSHOT + 2.0.0-BETA18 junit From 55c5bcb04eb936512b1fb4df663fd5a208400a93 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 19 Dec 2011 10:40:27 -0800 Subject: [PATCH 0106/2771] Use a forked path for releases. This allows me to actually enter my GPG passphrase when releasing signed artifacts. --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index ef3034dc9dd..6fd589fe577 100644 --- a/pom.xml +++ b/pom.xml @@ -153,6 +153,7 @@ 2.2.1 true + forked-path v@{project.version} From 0fc579629eeeefad7fd5dccdf7ed25560a428e0f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 19 Dec 2011 10:49:10 -0800 Subject: [PATCH 0107/2771] Automatically sign artifacts when releasing. --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 6fd589fe577..035b86a7cec 100644 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,12 @@ sign + + + performRelease + true + + @@ -155,6 +161,7 @@ true forked-path v@{project.version} + clean verify gpg:sign From 0332012fc5f95d37cba67cdd5cfc9f2c49ad55ef Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 20 Dec 2011 08:45:39 -0800 Subject: [PATCH 0108/2771] Bump to JDBI 2.30. This also means we can remove ScopedStatementLocator, as 2.30 incorporates a patch to allow for nesting .sql files under the full class name. --- dropwizard-db/pom.xml | 2 +- .../com/yammer/dropwizard/db/Database.java | 1 - .../dropwizard/db/ScopedStatementLocator.java | 83 ------------------- 3 files changed, 1 insertion(+), 85 deletions(-) delete mode 100644 dropwizard-db/src/main/java/com/yammer/dropwizard/db/ScopedStatementLocator.java diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index c07ee57fa2d..8f28a8f35e3 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -23,7 +23,7 @@ org.jdbi jdbi - 2.29 + 2.30 com.yammer.metrics diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index b9f4a3bfbbf..d92cf63d77e 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -32,7 +32,6 @@ public Database(DataSource dataSource, ObjectPool pool) { setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); setTimingCollector(new InstrumentedTimingCollector(Metrics.defaultRegistry())); setStatementRewriter(new NamePrependingStatementRewriter()); - setStatementLocator(new ScopedStatementLocator()); registerArgumentFactory(new OptionalArgumentFactory()); registerContainerFactory(new ImmutableListContainerFactory()); } diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/ScopedStatementLocator.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/ScopedStatementLocator.java deleted file mode 100644 index f22c1caf6f9..00000000000 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/ScopedStatementLocator.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.yammer.dropwizard.db; - -import org.skife.jdbi.v2.StatementContext; -import org.skife.jdbi.v2.exceptions.UnableToCreateStatementException; -import org.skife.jdbi.v2.tweak.StatementLocator; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -@SuppressWarnings({"IOResourceOpenedButNotSafelyClosed", "NestedAssignment"}) -class ScopedStatementLocator implements StatementLocator { - public static boolean isSql(String sql) { - final String local = sql.substring(0, 7).toLowerCase(); - return local.startsWith("insert ") - || local.startsWith("update ") - || local.startsWith("select ") - || local.startsWith("call ") - || local.startsWith("delete ") - || local.startsWith("create ") - || local.startsWith("alter ") - || local.startsWith("drop "); - } - - @Override - public String locate(String name, StatementContext ctx) { - if (isSql(name)) { - return name; - } - final ClassLoader loader = selectClassLoader(); - InputStream input = loader.getResourceAsStream(name); - BufferedReader reader = null; - try { - if (input == null) { - input = loader.getResourceAsStream(name + ".sql"); - } - - if ((input == null) && (ctx.getSqlObjectType() != null)) { - input = loader.getResourceAsStream(ctx.getSqlObjectType() - .getCanonicalName() + '.' + name + ".sql"); - } - - if (input == null) { - return name; - } - - final StringBuilder buffer = new StringBuilder(); - reader = new BufferedReader(new InputStreamReader(input)); - try { - String line; - while ((line = reader.readLine()) != null) { - if (!isComment(line)) { - buffer.append(line).append(' '); - } - } - } catch (IOException e) { - throw new UnableToCreateStatementException(e.getMessage(), e, ctx); - } - - return buffer.toString(); - } finally { - try { - if (reader != null) { - reader.close(); - } - } catch (IOException ignored) { - // nothing we can do here :-( - } - } - } - - private static ClassLoader selectClassLoader() { - if (Thread.currentThread().getContextClassLoader() != null) { - return Thread.currentThread().getContextClassLoader(); - } - return ScopedStatementLocator.class.getClassLoader(); - } - - private static boolean isComment(final String line) { - return line.startsWith("#") || line.startsWith("--") || line.startsWith("//"); - } -} From fed3a639e49930574704d9ebdb8612d30f7e9bbb Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 21 Dec 2011 19:26:35 -0800 Subject: [PATCH 0109/2771] Make sure we're not throwing NPEs during shutdown. --- .../dropwizard/jetty/QuietErrorHandler.java | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java index fd6efe7f448..a820942b732 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java @@ -26,6 +26,7 @@ */ public class QuietErrorHandler extends ErrorHandler { private static final Logger LOGGER = LoggerFactory.getLogger(QuietErrorHandler.class); + private static final int RESPONSE_BUFFER_SIZE = 4096; /* * Sadly, this class is basically untestable. @@ -40,30 +41,35 @@ public void handle(String target, HttpServletRequest request, HttpServletResponse response) throws IOException { final AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection(); - final Response jettyResponse = connection.getResponse(); - jettyResponse.setStatus(jettyResponse.getStatus()); + if (connection != null) { + connection.getRequest().setHandled(true); + final Response jettyResponse = connection.getResponse(); + jettyResponse.setStatus(jettyResponse.getStatus()); - connection.getRequest().setHandled(true); - final String method = request.getMethod(); - - if (!ALLOWED_METHODS.contains(method)) { - return; - } + connection.getRequest().setHandled(true); + final String method = request.getMethod(); - response.setContentType(MimeTypes.TEXT_PLAIN_UTF_8); - if (getCacheControl() != null) { - response.setHeader(HttpHeaders.CACHE_CONTROL, getCacheControl()); - } + if (!ALLOWED_METHODS.contains(method)) { + return; + } - final StringBuilder builder = new StringBuilder(4096); - builder.append(errorMessage(request, jettyResponse.getStatus())).append('\n').append('\n'); - final byte[] bytes = builder.toString().getBytes(Charsets.UTF_8); - response.setContentLength(bytes.length); - final ServletOutputStream output = response.getOutputStream(); - try { - output.write(bytes); - } finally { - output.close(); + response.setContentType(MimeTypes.TEXT_PLAIN_UTF_8); + if (getCacheControl() != null) { + response.setHeader(HttpHeaders.CACHE_CONTROL, getCacheControl()); + } + + final StringBuilder builder = new StringBuilder(RESPONSE_BUFFER_SIZE); + builder.append(errorMessage(request, jettyResponse.getStatus())) + .append('\n') + .append('\n'); + final byte[] bytes = builder.toString().getBytes(Charsets.UTF_8); + response.setContentLength(bytes.length); + final ServletOutputStream output = response.getOutputStream(); + try { + output.write(bytes); + } finally { + output.close(); + } } } From e4a5da7b406fb1867eb46b50f263976dba8ca50f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 21 Dec 2011 19:32:14 -0800 Subject: [PATCH 0110/2771] Enable mixed-source compilation for dw-scala. --- dropwizard-scala_2.9.1/pom.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 29135ef9f00..356eedcecd8 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -123,10 +123,24 @@ 2.15.2 + compile compile + + compile + + + test-compile + testCompile + test-compile + + + process-resources + + compile + From b6e066778e8ff92c432e09f3f2d18b46d46958d2 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 21 Dec 2011 19:32:33 -0800 Subject: [PATCH 0111/2771] Move ScalaBundle to Java. It's not that Java is somehow better than Scala for this, but rather that in order to release via Sonatype's OSS repo I need to have each module produce a -javadocs artifact, and Maven doesn't do that unless there's a Java file. lulz --- .../yammer/dropwizard/bundles/ScalaBundle.java | 16 ++++++++++++++++ .../com/yammer/dropwizard/ScalaService.scala | 2 +- .../yammer/dropwizard/bundles/ScalaBundle.scala | 15 --------------- 3 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 dropwizard-scala_2.9.1/src/main/java/com/yammer/dropwizard/bundles/ScalaBundle.java delete mode 100644 dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/bundles/ScalaBundle.scala diff --git a/dropwizard-scala_2.9.1/src/main/java/com/yammer/dropwizard/bundles/ScalaBundle.java b/dropwizard-scala_2.9.1/src/main/java/com/yammer/dropwizard/bundles/ScalaBundle.java new file mode 100644 index 00000000000..b4f479fc21c --- /dev/null +++ b/dropwizard-scala_2.9.1/src/main/java/com/yammer/dropwizard/bundles/ScalaBundle.java @@ -0,0 +1,16 @@ +package com.yammer.dropwizard.bundles; + +import com.codahale.jersey.inject.ScalaCollectionsQueryParamInjectableProvider; +import com.codahale.jersey.providers.JerksonProvider; +import com.yammer.dropwizard.Bundle; +import com.yammer.dropwizard.config.Environment; +import com.yammer.dropwizard.providers.OauthTokenProvider; + +public class ScalaBundle implements Bundle { + @Override + public void initialize(Environment environment) { + environment.addProvider(new JerksonProvider()); + environment.addProvider(new OauthTokenProvider()); + environment.addProvider(new ScalaCollectionsQueryParamInjectableProvider()); + } +} diff --git a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala index ab502b0dfb5..783ea83c9ed 100644 --- a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala +++ b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala @@ -4,7 +4,7 @@ import config.Configuration import bundles.ScalaBundle abstract class ScalaService[T <: Configuration](name: String) extends AbstractService[T](name) { - addBundle(ScalaBundle) + addBundle(new ScalaBundle) override final def subclassServiceInsteadOfThis() {} final def main(args: Array[String]) { diff --git a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/bundles/ScalaBundle.scala b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/bundles/ScalaBundle.scala deleted file mode 100644 index 5b8838d370a..00000000000 --- a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/bundles/ScalaBundle.scala +++ /dev/null @@ -1,15 +0,0 @@ -package com.yammer.dropwizard.bundles - -import com.yammer.dropwizard.Bundle -import com.yammer.dropwizard.config.Environment -import com.yammer.dropwizard.providers.OauthTokenProvider -import com.codahale.jersey.inject.ScalaCollectionsQueryParamInjectableProvider -import com.codahale.jersey.providers.JerksonProvider - -object ScalaBundle extends Bundle { - def initialize(environment: Environment) { - environment.addProvider(new JerksonProvider[Any]) - environment.addProvider(new OauthTokenProvider) - environment.addProvider(new ScalaCollectionsQueryParamInjectableProvider) - } -} From 590b436f1b50b571aafab679f6062dfc58248ef7 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 21 Dec 2011 19:39:31 -0800 Subject: [PATCH 0112/2771] Added a URL and description to the parent. --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 035b86a7cec..73416722376 100644 --- a/pom.xml +++ b/pom.xml @@ -9,6 +9,11 @@ 0.1.0-SNAPSHOT pom Dropwizard Project + http://dropwizard.codahale.com/ + + Dropwizard is a Java framework for developing ops-friendly, high-performance, RESTful web + services. + dropwizard-core From 5ff8b4c4917c88da896da1fbd47fb3a333e079a4 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 21 Dec 2011 19:42:32 -0800 Subject: [PATCH 0113/2771] Fix SCM and issues links. --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 73416722376..67943ffabd1 100644 --- a/pom.xml +++ b/pom.xml @@ -47,14 +47,14 @@ - scm:git:git://github.com/codahale/com.yammer.dropwizard.git - scm:git:git@github.com:codahale/com.yammer.dropwizard.git - http://github.com/codahale/com.yammer.dropwizard/ + scm:git:git://github.com/codahale/dropwizard.git + scm:git:git@github.com:codahale/dropwizard.git + http://github.com/codahale/dropwizard/ github - http://github.com/codahale/com.yammer.dropwizard/issues#issue/ + http://github.com/codahale/dropwizard/issues#issue/ From 5b484dceb4dc0990e9a67dcf143dc77baf27799d Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 21 Dec 2011 19:44:52 -0800 Subject: [PATCH 0114/2771] [maven-release-plugin] prepare release v0.1.0 --- dropwizard-client/pom.xml | 6 ++---- dropwizard-core/pom.xml | 6 ++---- dropwizard-db/pom.xml | 6 ++---- dropwizard-example/pom.xml | 10 ++++------ dropwizard-scala_2.9.1/pom.xml | 6 ++---- dropwizard-templates/pom.xml | 6 ++---- dropwizard-testing/pom.xml | 6 ++---- pom.xml | 8 +++----- 8 files changed, 19 insertions(+), 35 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index eed38b6b792..6635481fa5a 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -1,13 +1,11 @@ - + 4.0.0 com.yammer.dropwizard dropwizard-parent - 0.1.0-SNAPSHOT + 0.1.0 com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 0240f1e7f15..796fd4f5e40 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -1,13 +1,11 @@ - + 4.0.0 com.yammer.dropwizard dropwizard-parent - 0.1.0-SNAPSHOT + 0.1.0 com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 8f28a8f35e3..72b5fad4965 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -1,13 +1,11 @@ - + 4.0.0 com.yammer.dropwizard dropwizard-parent - 0.1.0-SNAPSHOT + 0.1.0 com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index e1a4c8ed78e..3c63c209a84 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -1,12 +1,10 @@ - + 4.0.0 com.yammer.dropwizard dropwizard-example - 0.1.0-SNAPSHOT + 0.1.0 Dropwizard Example Application @@ -77,7 +75,7 @@ maven-resources-plugin 2.5 - + UTF-8 @@ -96,7 +94,7 @@ - + com.example.helloworld.HelloWorldService diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 356eedcecd8..cd33d921be8 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -1,13 +1,11 @@ - + 4.0.0 com.yammer.dropwizard dropwizard-parent - 0.1.0-SNAPSHOT + 0.1.0 com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 4f8d58b51c6..4bac254b7fa 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -1,13 +1,11 @@ - + 4.0.0 com.yammer.dropwizard dropwizard-parent - 0.1.0-SNAPSHOT + 0.1.0 com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 0cae703ed98..475afb45240 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -1,13 +1,11 @@ - + 4.0.0 com.yammer.dropwizard dropwizard-parent - 0.1.0-SNAPSHOT + 0.1.0 com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 67943ffabd1..e2205d44033 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,10 @@ - + 4.0.0 com.yammer.dropwizard dropwizard-parent - 0.1.0-SNAPSHOT + 0.1.0 pom Dropwizard Project http://dropwizard.codahale.com/ @@ -154,7 +152,7 @@ maven-resources-plugin 2.5 - + UTF-8 From 7c517a0964fa652cd679b9a03ed2fc142f294adb Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 21 Dec 2011 19:45:00 -0800 Subject: [PATCH 0115/2771] [maven-release-plugin] prepare for next development iteration --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 6635481fa5a..e19112765b3 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.0 + 0.1.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 796fd4f5e40..1f98d52cabc 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.0 + 0.1.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 72b5fad4965..9938700e2b3 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.0 + 0.1.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 3c63c209a84..d1996a31973 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.1.0 + 0.1.1-SNAPSHOT Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index cd33d921be8..12d6dd87e06 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.0 + 0.1.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 4bac254b7fa..65feff37620 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.0 + 0.1.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 475afb45240..916276cb8be 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.0 + 0.1.1-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index e2205d44033..a9522603502 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.0 + 0.1.1-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From 63454b18888ccfeb45f591d913a7954b08700327 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 21 Dec 2011 19:48:23 -0800 Subject: [PATCH 0116/2771] Update docs for 0.1.0. --- docs/getting-started.html | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/docs/getting-started.html b/docs/getting-started.html index 38b1a626f57..a1eede74938 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -180,21 +180,7 @@

    Setting Up Maven

    - First off, add the repository where the Dropwizard - SNAPSHOTJARs are hosted: -

    - -
    -<repositories>
    -    <repository>
    -        <id>sonatype-nexus-snapshots</id>
    -        <name>Sonatype Nexus Snapshots</name>
    -        <url>http://oss.sonatype.org/content/repositories/snapshots</url>
    -    </repository>
    -</repositories>
    - -

    - Second, add the dropwizard-core library as a dependency: + Add the dropwizard-core library as a dependency:

    @@ -202,7 +188,7 @@ 

    Setting Up Maven

    <dependency> <groupId>com.yammer.dropwizard</groupId> <artifactId>dropwizard-core</artifactId> - <version>0.1.0-SNAPSHOT</version> + <version>0.1.0</version> </dependency> </dependencies>
    From 6929b57a536d2637333b62218bbedd597648112f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 22 Dec 2011 16:30:22 -0800 Subject: [PATCH 0117/2771] Fix ManagedCommand. --- .../main/java/com/yammer/dropwizard/cli/ManagedCommand.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java index f9eceb59a6c..ff00b4f70f0 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java @@ -30,12 +30,13 @@ protected final void run(AbstractService service, LOGGER.info("Starting " + service.getName()); environment.start(); try { - run(configuration, params); + run(configuration, environment, params); } finally { environment.stop(); } } - protected abstract void run(Configuration configuration, + protected abstract void run(T configuration, + Environment environment, CommandLine params) throws Exception; } From 2bd12ec77aa1a8ddc100073841e2274b47b22b78 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 23 Dec 2011 22:15:36 -0800 Subject: [PATCH 0118/2771] Make JerseyClient thread pools managed. --- .../yammer/dropwizard/client/JerseyClient.java | 17 +---------------- .../dropwizard/client/JerseyClientFactory.java | 7 +++++-- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java index 4dea37767ff..762346457b2 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java @@ -3,24 +3,9 @@ import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.client.apache4.ApacheHttpClient4; import com.sun.jersey.client.apache4.ApacheHttpClient4Handler; -import com.yammer.dropwizard.lifecycle.Managed; -import java.util.concurrent.TimeUnit; - -public class JerseyClient extends ApacheHttpClient4 implements Managed { +public class JerseyClient extends ApacheHttpClient4 { public JerseyClient(ApacheHttpClient4Handler root, ClientConfig config) { super(root, config); } - - @Override - public void start() throws Exception { - // already started man - } - - @Override - public void stop() throws Exception { - getExecutorService().shutdown(); - getExecutorService().awaitTermination(1, TimeUnit.MINUTES); - destroy(); - } } diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java index a26d9545c8e..58c83d48ed2 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java @@ -29,8 +29,11 @@ public JerseyClient build(Environment environment) { config.getSingletons().add(new JacksonMessageBodyProvider()); final JerseyClient jerseyClient = new JerseyClient(handler, config); - jerseyClient.setExecutorService(buildThreadPool()); - environment.manage(jerseyClient); + jerseyClient.setExecutorService(environment.managedExecutorService("jersey-client-%d", + configuration.getMinThreads(), + configuration.getMaxThreads(), + 60, + TimeUnit.SECONDS)); if (configuration.isGzipEnabled()) { jerseyClient.addFilter(new GZIPContentEncodingFilter()); From f73d0bf25da6580d2a29a2ad9f615759397e5f49 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 23 Dec 2011 22:58:01 -0800 Subject: [PATCH 0119/2771] Added a changelog. --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000000..90c2f74edfa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +v0.1.1: TBD +=================== + +* Fixed `ManagedCommand` to provide access to the `Environment`, among other things. +* Made `JerseyClient`'s thread pool managed. + + +v0.1.0: Dec 21 2011 +=================== + +* Initial release From a19774f9332dd991d196e3d3ba4e9e00701be420 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 23 Dec 2011 23:49:07 -0800 Subject: [PATCH 0120/2771] Oy. metrics-aop doesn't proxy the annotations quite right. --- .../main/java/com/example/helloworld/HelloWorldService.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java index 919682a960a..1945f20e2eb 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldService.java @@ -8,8 +8,6 @@ import com.yammer.dropwizard.bundles.AssetsBundle; import com.yammer.dropwizard.config.Environment; -import static com.yammer.metrics.aop.Instrumentation.instrument; - public class HelloWorldService extends Service { public static void main(String[] args) throws Exception { new HelloWorldService().run(args); @@ -27,7 +25,7 @@ protected void initialize(HelloWorldConfiguration configuration, final Template template = configuration.buildTemplate(); environment.addHealthCheck(new TemplateHealthCheck(template)); - environment.addResource(instrument(new HelloWorldResource(template))); + environment.addResource(new HelloWorldResource(template)); } } From c398c318b2c3e0cfe300e59a0f07ec73a56f01fb Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 23 Dec 2011 23:50:01 -0800 Subject: [PATCH 0121/2771] Add single-arg constructors to Size and Duration. This allows us to ditch all the wonky pattern-matching and validations. Invalid sizes and durations will explode on parsing like invalid integers, etc. --- CHANGELOG.md | 1 + .../client/HttpClientConfiguration.java | 15 +++---- .../dropwizard/config/HttpConfiguration.java | 43 +++++++------------ .../config/LoggingConfiguration.java | 5 +-- .../com/yammer/dropwizard/util/Duration.java | 34 +++++++-------- .../java/com/yammer/dropwizard/util/Size.java | 28 ++++++------ .../dropwizard/db/DatabaseConfiguration.java | 22 ++++------ 7 files changed, 64 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90c2f74edfa..8c94d27260f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ v0.1.1: TBD * Fixed `ManagedCommand` to provide access to the `Environment`, among other things. * Made `JerseyClient`'s thread pool managed. +* Improved ease of use for `Duration` and `Size` configuration parameters. v0.1.0: Dec 21 2011 diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientConfiguration.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientConfiguration.java index a313211d79d..750eace6018 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientConfiguration.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/HttpClientConfiguration.java @@ -5,16 +5,13 @@ import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; public class HttpClientConfiguration { @NotNull - @Pattern(regexp = Duration.VALID_DURATION) - private String timeout = "500ms"; + private Duration timeout = Duration.milliseconds(500); @NotNull - @Pattern(regexp = Duration.VALID_DURATION) - private String timeToLive = "1 hour"; + private Duration timeToLive = Duration.hours(1); private boolean cookiesEnabled = false; @@ -23,11 +20,11 @@ public class HttpClientConfiguration { private int maxConnections = 1024; public Duration getTimeout() { - return Duration.parse(timeout); + return timeout; } public Duration getTimeToLive() { - return Duration.parse(timeToLive); + return timeToLive; } public boolean isCookiesEnabled() { @@ -35,11 +32,11 @@ public boolean isCookiesEnabled() { } public void setTimeout(Duration duration) { - this.timeout = duration.toString(); + this.timeout = duration; } public void setTimeToLive(Duration timeToLive) { - this.timeToLive = timeToLive.toString(); + this.timeToLive = timeToLive; } public void setCookiesEnabled(boolean enabled) { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 902a87b8649..874d5c2c2b2 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -110,8 +110,7 @@ public enum ConnectorType { private String connectorType = "blocking"; @NotNull - @Pattern(regexp = Duration.VALID_DURATION) - private String maxIdleTime = "1s"; + private Duration maxIdleTime = Duration.seconds(1); @Min(1) @Max(128) @@ -128,36 +127,29 @@ public enum ConnectorType { private int maxBufferCount = 1024; @NotNull - @Pattern(regexp = Size.VALID_SIZE) - private String requestBufferSize = "32KiB"; + private Size requestBufferSize = Size.kilobytes(32); @NotNull - @Pattern(regexp = Size.VALID_SIZE) - private String requestHeaderBufferSize = "3KiB"; + private Size requestHeaderBufferSize = Size.kilobytes(3); @NotNull - @Pattern(regexp = Size.VALID_SIZE) - private String responseBufferSize = "32KiB"; + private Size responseBufferSize = Size.kilobytes(32); @NotNull - @Pattern(regexp = Size.VALID_SIZE) - private String responseHeaderBufferSize = "6KiB"; + private Size responseHeaderBufferSize = Size.kilobytes(6); private boolean reuseAddress = true; - @Pattern(regexp = Duration.VALID_DURATION) - private String soLingerTime = null; + private Duration soLingerTime = null; @Min(1) private int lowResourcesConnectionThreshold = 25000; @NotNull - @Pattern(regexp = Duration.VALID_DURATION) - private String lowResourcesMaxIdleTime = "5s"; + private Duration lowResourcesMaxIdleTime = Duration.seconds(5); @NotNull - @Pattern(regexp = Duration.VALID_DURATION) - private String shutdownGracePeriod = "2s"; + private Duration shutdownGracePeriod = Duration.seconds(2); private boolean useServerHeader = false; @@ -206,7 +198,7 @@ public int getMinThreads() { } public Duration getMaxIdleTime() { - return Duration.parse(maxIdleTime); + return maxIdleTime; } public int getAcceptorThreadCount() { @@ -226,19 +218,19 @@ public int getMaxBufferCount() { } public Size getRequestBufferSize() { - return Size.parse(requestBufferSize); + return requestBufferSize; } public Size getRequestHeaderBufferSize() { - return Size.parse(requestHeaderBufferSize); + return requestHeaderBufferSize; } public Size getResponseBufferSize() { - return Size.parse(responseBufferSize); + return responseBufferSize; } public Size getResponseHeaderBufferSize() { - return Size.parse(responseHeaderBufferSize); + return responseHeaderBufferSize; } public boolean isReuseAddressEnabled() { @@ -246,10 +238,7 @@ public boolean isReuseAddressEnabled() { } public Optional getSoLingerTime() { - if (soLingerTime == null) { - return Optional.absent(); - } - return Optional.of(Duration.parse(soLingerTime)); + return Optional.fromNullable(soLingerTime); } public int getLowResourcesConnectionThreshold() { @@ -257,11 +246,11 @@ public int getLowResourcesConnectionThreshold() { } public Duration getLowResourcesMaxIdleTime() { - return Duration.parse(lowResourcesMaxIdleTime); + return lowResourcesMaxIdleTime; } public Duration getShutdownGracePeriod() { - return Duration.parse(shutdownGracePeriod); + return shutdownGracePeriod; } public boolean useForwardedHeaders() { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java index 5370bdf1182..28ca75e4f50 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java @@ -42,8 +42,7 @@ public static class FileConfiguration { private String filenamePattern = "./logs/example.log"; @NotNull - @Pattern(regexp = Size.VALID_SIZE) - private String maxFileSize = "50MB"; + private Size maxFileSize = Size.megabytes(50); @Min(1) @Max(50) @@ -62,7 +61,7 @@ public String getFilenamePattern() { } public Size getMaxFileSize() { - return Size.parse(maxFileSize); + return maxFileSize; } public int getRetainedFileCount() { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java index 83bd568fb14..d6a2bea50bd 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java @@ -6,17 +6,19 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; public class Duration { - public static final String VALID_DURATION = "[\\d]+[\\s]*(ns|nanosecond(s)?|" + - "us|microsecond(s)?|" + - "ms|millisecond(s)?|" + - "s|second(s)?|" + - "m|minute(s)?|" + - "h|hour(s)?|" + - "d|day(s)?)"; - private static final Pattern DURATION_PATTERN = Pattern.compile(VALID_DURATION); + private static final Pattern PATTERN = Pattern.compile("[\\d]+[\\s]*(" + + "ns|nanosecond(s)?|" + + "us|microsecond(s)?|" + + "ms|millisecond(s)?|" + + "s|second(s)?|" + + "m|minute(s)?|" + + "h|hour(s)?|" + + "d|day(s)?" + + ')'); private static final ImmutableMap SUFFIXES; static { @@ -82,6 +84,7 @@ public static Duration days(long count) { } private static long parseCount(String s) { + checkArgument(PATTERN.matcher(s).matches(), "Invalid duration: %s", s); final String value = CharMatcher.WHITESPACE.removeFrom(s); return Long.parseLong(CharMatcher.JAVA_LETTER.trimTrailingFrom(value)); } @@ -89,22 +92,19 @@ private static long parseCount(String s) { private static TimeUnit parseUnit(String s) { final String value = CharMatcher.WHITESPACE.removeFrom(s); final String suffix = CharMatcher.DIGIT.trimLeadingFrom(value); - final TimeUnit unit = SUFFIXES.get(suffix); - if (unit != null) { - return unit; - } - throw new IllegalArgumentException("Unable to parse as duration: " + s); + return SUFFIXES.get(suffix); } public static Duration parse(String duration) { - if (DURATION_PATTERN.matcher(duration).matches()) { - return new Duration(parseCount(duration), parseUnit(duration)); - } - throw new IllegalArgumentException("Unable to parse as duration: " + duration); + return new Duration(parseCount(duration), parseUnit(duration)); } private final long count; private final TimeUnit unit; + + public Duration(String duration) { + this(parseCount(duration), parseUnit(duration)); + } private Duration(long count, TimeUnit unit) { this.count = count; diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java index e54a4062311..d31795f97ed 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java @@ -5,15 +5,15 @@ import java.util.regex.Pattern; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; public class Size { - public static final String VALID_SIZE = "[\\d]+[\\s]*(B|byte(s)?|" + - "KB|KiB|kilobyte(s)?|" + - "MB|MiB|megabyte(s)?|" + - "GB|GiB|gigabyte(s)?|" + - "TB|TiB|terabyte(s)?)"; - private static final Pattern SIZE_PATTERN = Pattern.compile(VALID_SIZE); + private static final Pattern PATTERN = Pattern.compile("[\\d]+[\\s]*(B|byte(s)?|" + + "KB|KiB|kilobyte(s)?|" + + "MB|MiB|megabyte(s)?|" + + "GB|GiB|gigabyte(s)?|" + + "TB|TiB|terabyte(s)?)"); private static final ImmutableMap SUFFIXES; @@ -67,6 +67,7 @@ public static Size terabytes(long count) { } private static long parseCount(String s) { + checkArgument(PATTERN.matcher(s).matches(), "Invalid size: %s", s); final String value = CharMatcher.WHITESPACE.removeFrom(s); return Long.parseLong(CharMatcher.JAVA_LETTER.trimTrailingFrom(value)); } @@ -74,22 +75,19 @@ private static long parseCount(String s) { private static SizeUnit parseUnit(String s) { final String value = CharMatcher.WHITESPACE.removeFrom(s); final String suffix = CharMatcher.DIGIT.trimLeadingFrom(value).trim(); - final SizeUnit unit = SUFFIXES.get(suffix); - if (unit != null) { - return unit; - } - throw new IllegalArgumentException("Unable to parse as size: " + s); + return SUFFIXES.get(suffix); } public static Size parse(String size) { - if (SIZE_PATTERN.matcher(size).matches()) { - return new Size(parseCount(size), parseUnit(size)); - } - throw new IllegalArgumentException("Unable to parse size: " + size); + return new Size(parseCount(size), parseUnit(size)); } private final long count; private final SizeUnit unit; + + public Size(String size) { + this(parseCount(size), parseUnit(size)); + } private Size(long count, SizeUnit unit) { this.count = count; diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java index 42fc9b58781..e5cb04c9e42 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java @@ -9,7 +9,6 @@ import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; import java.util.Map; @SuppressWarnings("FieldMayBeFinal") @@ -30,8 +29,7 @@ public static class DatabaseConnectionConfiguration { private Map properties = Maps.newHashMap(); @NotNull - @Pattern(regexp = Duration.VALID_DURATION) - private String maxWaitForConnection = "1s"; + private Duration maxWaitForConnection = Duration.seconds(1); @NotNull private String validationQuery = "/* Health Check */ SELECT 1"; @@ -47,12 +45,10 @@ public static class DatabaseConnectionConfiguration { private boolean checkConnectionWhileIdle; @NotNull - @Pattern(regexp = Duration.VALID_DURATION) - private String checkConnectionHealthWhenIdleFor = "10s"; + private Duration checkConnectionHealthWhenIdleFor = Duration.seconds(10); @NotNull - @Pattern(regexp = Duration.VALID_DURATION) - private String closeConnectionIfIdleFor = "10m"; + private Duration closeConnectionIfIdleFor = Duration.minutes(1); public String getDriverClass() { return driverClass; @@ -95,11 +91,11 @@ public void setUrl(String url) { } public Duration getMaxWaitForConnection() { - return Duration.parse(maxWaitForConnection); + return maxWaitForConnection; } public void setMaxWaitForConnection(Duration maxWait) { - this.maxWaitForConnection = maxWait.toString(); + this.maxWaitForConnection = maxWait; } public String getValidationQuery() { @@ -135,19 +131,19 @@ public void setCheckConnectionWhileIdle(boolean checkConnectionWhileIdle) { } public Duration getCheckConnectionHealthWhenIdleFor() { - return Duration.parse(checkConnectionHealthWhenIdleFor); + return checkConnectionHealthWhenIdleFor; } public void setCheckConnectionHealthWhenIdleFor(Duration timeout) { - this.checkConnectionHealthWhenIdleFor = timeout.toString(); + this.checkConnectionHealthWhenIdleFor = timeout; } public Duration getCloseConnectionIfIdleFor() { - return Duration.parse(closeConnectionIfIdleFor); + return closeConnectionIfIdleFor; } public void setCloseConnectionIfIdleFor(Duration timeout) { - this.closeConnectionIfIdleFor = timeout.toString(); + this.closeConnectionIfIdleFor = timeout; } @ValidationMethod(message = ".minSize must be less than or equal to maxSize") From 25f5ea68b6f6fcaed8012ed6e30c2b6aa0f2f94d Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 24 Dec 2011 12:00:32 -0800 Subject: [PATCH 0122/2771] Fixed NPE for old, description-less constructors. --- .../com/yammer/dropwizard/cli/ConfiguredCommand.java | 9 --------- .../java/com/yammer/dropwizard/cli/ManagedCommand.java | 4 ---- 2 files changed, 13 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java index 709373ac8ea..2a771003ac1 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java @@ -20,15 +20,6 @@ * @see Configuration */ public abstract class ConfiguredCommand extends Command { - /** - * Creates a new {@link ConfiguredCommand} with the given name. - * - * @param name the command's name - */ - protected ConfiguredCommand(String name) { - super(name, null); - } - /** * Creates a new {@link ConfiguredCommand} with the given name and configuration. * diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java index ff00b4f70f0..b69aa56dff7 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java @@ -11,10 +11,6 @@ public abstract class ManagedCommand extends ConfiguredCommand { private static final Logger LOGGER = LoggerFactory.getLogger(ManagedCommand.class); - protected ManagedCommand(String name) { - super(name); - } - protected ManagedCommand(String name, String description) { super(name, description); From a30dd61eb8b727dc9eecc97ba7e8b6878ba539ff Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 24 Dec 2011 12:02:32 -0800 Subject: [PATCH 0123/2771] Mark AssetServlet fields as transient. --- .../java/com/yammer/dropwizard/servlets/AssetServlet.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java index f01eb29141c..8a1f8d46cac 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java @@ -35,8 +35,8 @@ public byte[] load(String key) throws Exception { } } - private final Cache cache; - private final MimeTypes mimeTypes; + private final transient Cache cache; + private final transient MimeTypes mimeTypes; public AssetServlet(String base, int maxCacheSize) { this.cache = buildCache(base, maxCacheSize); From 43f206ddbf4fbceb7f858c981ec4504c88b687e4 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 24 Dec 2011 12:03:35 -0800 Subject: [PATCH 0124/2771] Upgrade AssetServlet to use LoadingCache. --- .../java/com/yammer/dropwizard/servlets/AssetServlet.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java index 8a1f8d46cac..943d6873f33 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java @@ -1,8 +1,8 @@ package com.yammer.dropwizard.servlets; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.io.Resources; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.util.URIUtil; @@ -35,7 +35,7 @@ public byte[] load(String key) throws Exception { } } - private final transient Cache cache; + private final transient LoadingCache cache; private final transient MimeTypes mimeTypes; public AssetServlet(String base, int maxCacheSize) { @@ -43,7 +43,7 @@ public AssetServlet(String base, int maxCacheSize) { this.mimeTypes = new MimeTypes(); } - private static Cache buildCache(String base, int maxCacheSize) { + private static LoadingCache buildCache(String base, int maxCacheSize) { return CacheBuilder.newBuilder() .maximumSize(maxCacheSize) .build(new AssetLoader(base)); From d1fee4797073b15e9b0b7193062d81c9c150124a Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sun, 25 Dec 2011 17:04:56 -0800 Subject: [PATCH 0125/2771] Add some basic JSON tests. --- .../src/main/java/com/yammer/dropwizard/json/Json.java | 9 ++++++++- .../java/com/yammer/dropwizard/json/tests/JsonTest.java | 5 +++++ dropwizard-core/src/test/resources/json/string.json | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 dropwizard-core/src/test/java/com/yammer/dropwizard/json/tests/JsonTest.java create mode 100644 dropwizard-core/src/test/resources/json/string.json diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java index 020d903bc7f..e204fc79bb2 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java @@ -138,5 +138,12 @@ public static T read(String json, Class klass) throws IOException { public static T read(String json, TypeReference ref) throws IOException { return mapper.readValue(json, ref); } - + + public static T read(byte[] json, Class klass) throws IOException { + return mapper.readValue(json, constructType(klass)); + } + + public static T read(byte[] json, TypeReference ref) throws IOException { + return mapper.readValue(json, ref); + } } diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/json/tests/JsonTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/json/tests/JsonTest.java new file mode 100644 index 00000000000..c8f1c3a578e --- /dev/null +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/json/tests/JsonTest.java @@ -0,0 +1,5 @@ +package com.yammer.dropwizard.json.tests; + +public class JsonTest { + +} diff --git a/dropwizard-core/src/test/resources/json/string.json b/dropwizard-core/src/test/resources/json/string.json new file mode 100644 index 00000000000..3e68cc54150 --- /dev/null +++ b/dropwizard-core/src/test/resources/json/string.json @@ -0,0 +1 @@ +"wahoo" From 62e7496db41514d701f81a07d6d28c349478c881 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sun, 25 Dec 2011 17:19:21 -0800 Subject: [PATCH 0126/2771] Added a Maven site target. --- docs/Makefile | 2 +- dropwizard-example/pom.xml | 9 +++++++++ pom.xml | 19 ++++++++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 3de6cbb785d..acd5cb79719 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,2 +1,2 @@ upload: - rsync -avz --delete ./ codahale.com:/home/codahale/dropwizard.codahale.com/ + rsync -avz ./ codahale.com:/home/codahale/dropwizard.codahale.com/ diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index d1996a31973..a9389f3b916 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -113,6 +113,15 @@ true
    + + org.apache.maven.plugins + maven-site-plugin + 3.0 + + true + true + +
    diff --git a/pom.xml b/pom.xml index a9522603502..9bba347868a 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,10 @@ Nexus Release Repository http://oss.sonatype.org/service/local/staging/deploy/maven2/ + + dropwizard-codahale.com + scpexe://codahale.com/home/codahale/dropwizard.codahale.com/maven/ + @@ -167,11 +171,24 @@ clean verify gpg:sign + + org.apache.maven.plugins + maven-site-plugin + 3.0 + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.4 + org.apache.maven.wagon - wagon-ssh + wagon-ssh-external 1.0-beta-7 From 3777efa9f7478b62757bec9f7cff1e8df8ef09b3 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 27 Dec 2011 13:37:16 -0800 Subject: [PATCH 0127/2771] Upgrade to Jetty 7.6.0.RC2. --- dropwizard-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 1f98d52cabc..0b53e935ff0 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -13,7 +13,7 @@ Dropwizard - 7.6.0.RC1 + 7.6.0.RC2 1.9.3 1.6.4 From 939f6b936149520c1c962f59e201cf61e0b8b406 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 27 Dec 2011 13:37:39 -0800 Subject: [PATCH 0128/2771] Upgrade to Mockito 1.9.0 final. --- dropwizard-testing/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 916276cb8be..3019d9294fc 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -26,7 +26,7 @@ org.mockito mockito-all - 1.9.0-rc1 + 1.9.0 org.hamcrest From 7b7fd6ecff7a2a8c9b373b5dc873c1487c1470f6 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 27 Dec 2011 15:23:56 -0800 Subject: [PATCH 0129/2771] Added Log and moved off of SLF4J's Logger. This doesn't change the logging infrastructure -- DW still uses SLF4J with a Log4J backend -- it just offers a saner API for the functionality. --- .../yammer/dropwizard/cli/ManagedCommand.java | 7 +- .../yammer/dropwizard/cli/ServerCommand.java | 7 +- .../yammer/dropwizard/config/Environment.java | 15 +- .../dropwizard/config/ServerFactory.java | 25 +- .../jersey/JacksonMessageBodyProvider.java | 7 +- .../jersey/LoggingExceptionMapper.java | 7 +- .../dropwizard/jetty/AsyncRequestLog.java | 7 +- .../dropwizard/jetty/QuietErrorHandler.java | 7 +- .../com/yammer/dropwizard/logging/Log.java | 257 ++++++++++++++++++ .../servlets/SlowRequestFilter.java | 10 +- .../yammer/dropwizard/tasks/TaskServlet.java | 9 +- .../jersey/LoggingDBIExceptionMapper.java | 9 +- .../jersey/LoggingSQLExceptionMapper.java | 7 +- .../example/helloworld/cli/RenderCommand.java | 9 +- 14 files changed, 314 insertions(+), 69 deletions(-) create mode 100644 dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java index b69aa56dff7..4723654e267 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java @@ -4,12 +4,11 @@ import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.config.LoggingFactory; +import com.yammer.dropwizard.logging.Log; import org.apache.commons.cli.CommandLine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public abstract class ManagedCommand extends ConfiguredCommand { - private static final Logger LOGGER = LoggerFactory.getLogger(ManagedCommand.class); + private static final Log LOG = Log.forClass(ManagedCommand.class); protected ManagedCommand(String name, String description) { @@ -23,7 +22,7 @@ protected final void run(AbstractService service, new LoggingFactory(configuration.getLoggingConfiguration()).configure(); final Environment environment = new Environment(); service.initializeWithBundles(configuration, environment); - LOGGER.info("Starting " + service.getName()); + LOG.info("Starting {}", service.getName()); environment.start(); try { run(configuration, environment, params); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java index 34973a9f931..43a7f64b1ea 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java @@ -6,10 +6,9 @@ import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.config.ServerFactory; +import com.yammer.dropwizard.logging.Log; import org.apache.commons.cli.CommandLine; import org.eclipse.jetty.server.Server; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; // TODO: 10/12/11 -- write tests for ServerCommand @@ -49,8 +48,8 @@ protected final void run(AbstractService service, final Server server = new ServerFactory(configuration.getHttpConfiguration()).buildServer(environment); - final Logger logger = LoggerFactory.getLogger(ServerCommand.class); - logger.info("Starting " + service.getName()); + final Log logger = Log.forClass(ServerCommand.class); + logger.info("Starting {}", service.getName()); try { logger.info('\n' + Resources.toString(Resources.getResource("banner.txt"), Charsets.UTF_8)); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 377cb1ba92e..32cab86fae3 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -15,6 +15,7 @@ import com.yammer.dropwizard.jetty.NonblockingServletHolder; import com.yammer.dropwizard.lifecycle.ExecutorServiceManager; import com.yammer.dropwizard.lifecycle.Managed; +import com.yammer.dropwizard.logging.Log; import com.yammer.dropwizard.tasks.GarbageCollectionTask; import com.yammer.dropwizard.tasks.Task; import com.yammer.metrics.core.HealthCheck; @@ -23,8 +24,6 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.AggregateLifeCycle; import org.eclipse.jetty.util.component.LifeCycle; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import javax.servlet.Filter; @@ -48,7 +47,7 @@ * A Dropwizard service's environment. */ public class Environment extends AbstractLifeCycle { - private static final Logger LOGGER = LoggerFactory.getLogger(Environment.class); + private static final Log LOG = Log.forClass(Environment.class); private static final String ROOT_PATH = "/*"; private final ResourceConfig config; @@ -349,7 +348,7 @@ private void logManagedObjects() { for (Object bean : lifeCycle.getBeans()) { builder.add(bean.getClass().getCanonicalName()); } - LOGGER.debug("managed objects = {}", builder.build()); + LOG.debug("managed objects = {}", builder.build()); } private void logHealthChecks() { @@ -357,7 +356,7 @@ private void logHealthChecks() { for (HealthCheck healthCheck : healthChecks.build()) { builder.add(healthCheck.getClass().getCanonicalName()); } - LOGGER.debug("health checks = {}", builder.build()); + LOG.debug("health checks = {}", builder.build()); } private void logResources() { @@ -375,7 +374,7 @@ private void logResources() { } } - LOGGER.debug("resources = {}", builder.build()); + LOG.debug("resources = {}", builder.build()); } private void logProviders() { @@ -393,7 +392,7 @@ private void logProviders() { } } - LOGGER.debug("providers = {}", builder.build()); + LOG.debug("providers = {}", builder.build()); } private void logEndpoints() { @@ -429,7 +428,7 @@ private void logEndpoints() { } } - LOGGER.info(stringBuilder.toString()); + LOG.info(stringBuilder.toString()); } private MethodList annotatedMethods(Class resource) { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index 873bf4f3339..d0a0a3bad24 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableSet; import com.yammer.dropwizard.jetty.BiDiGzipHandler; import com.yammer.dropwizard.jetty.QuietErrorHandler; +import com.yammer.dropwizard.logging.Log; import com.yammer.dropwizard.tasks.TaskServlet; import com.yammer.dropwizard.util.Duration; import com.yammer.dropwizard.util.Size; @@ -24,8 +25,6 @@ import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ThreadPool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.EnumSet; import java.util.List; @@ -37,7 +36,7 @@ // TODO: 11/7/11 -- document ServerFactory public class ServerFactory { - private static final Logger LOGGER = LoggerFactory.getLogger(ServerFactory.class); + private static final Log LOG = Log.forClass(ServerFactory.class); private final HttpConfiguration config; private final RequestLogHandlerFactory requestLogHandlerFactory; @@ -54,16 +53,16 @@ public Server buildServer(Environment env) throws ConfigurationException { } if (env.getHealthChecks().isEmpty()) { - LOGGER.warn('\n' + - "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + - "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + - "! THIS SERVICE HAS NO HEALTHCHECKS. THIS MEANS YOU WILL NEVER KNOW IF IT !\n" + - "! DIES IN PRODUCTION, WHICH MEANS YOU WILL NEVER KNOW IF YOU'RE LETTING !\n" + - "! YOUR USERS DOWN. YOU SHOULD ADD A HEALTHCHECK FOR EACH DEPENDENCY OF !\n" + - "! YOUR SERVICE WHICH FULLY (BUT LIGHTLY) TESTS YOUR SERVICE'S ABILITY TO !\n" + - "! USE THAT SERVICE. THINK OF IT AS A CONTINUOUS INTEGRATION TEST. !\n" + - "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + - "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + LOG.warn('\n' + + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + + "! THIS SERVICE HAS NO HEALTHCHECKS. THIS MEANS YOU WILL NEVER KNOW IF IT !\n" + + "! DIES IN PRODUCTION, WHICH MEANS YOU WILL NEVER KNOW IF YOU'RE LETTING !\n" + + "! YOUR USERS DOWN. YOU SHOULD ADD A HEALTHCHECK FOR EACH DEPENDENCY OF !\n" + + "! YOUR SERVICE WHICH FULLY (BUT LIGHTLY) TESTS YOUR SERVICE'S ABILITY TO !\n" + + "! USE THAT SERVICE. THINK OF IT AS A CONTINUOUS INTEGRATION TEST. !\n" + + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" ); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java index 5e139d8322f..38082d3b89e 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java @@ -2,10 +2,9 @@ import com.google.common.collect.ImmutableList; import com.yammer.dropwizard.json.Json; +import com.yammer.dropwizard.logging.Log; import com.yammer.dropwizard.validation.Validator; import org.eclipse.jetty.io.EofException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.validation.Valid; import javax.ws.rs.Consumes; @@ -31,7 +30,7 @@ @Consumes("application/json") public class JacksonMessageBodyProvider implements MessageBodyReader, MessageBodyWriter { - private static final Logger LOGGER = LoggerFactory.getLogger(JacksonMessageBodyProvider.class); + private static final Log LOG = Log.forClass(JacksonMessageBodyProvider.class); private static final Validator VALIDATOR = new Validator(); private static final Response.StatusType UNPROCESSABLE_ENTITY = new Response.StatusType() { @Override @@ -117,7 +116,7 @@ public void writeTo(Object t, } catch (EofException ignored) { // we don't care about these } catch (IOException e) { - LOGGER.error("Error writing response", e); + LOG.error(e, "Error writing response"); } } } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java index 1b55c7e4339..89bdbea34b7 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/LoggingExceptionMapper.java @@ -1,7 +1,6 @@ package com.yammer.dropwizard.jersey; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.yammer.dropwizard.logging.Log; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; @@ -15,7 +14,7 @@ @Provider public class LoggingExceptionMapper implements ExceptionMapper { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggingExceptionMapper.class); + private static final Log LOG = Log.forClass(LoggingExceptionMapper.class); private static final Random RANDOM = new Random(); @Override @@ -32,7 +31,7 @@ public Response toResponse(E exception) { } protected void logException(long id, E exception) { - LOGGER.error(formatLogMessage(id, exception), exception); + LOG.error(exception, formatLogMessage(id, exception)); } protected String formatResponseEntity(long id, Throwable exception) { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/AsyncRequestLog.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/AsyncRequestLog.java index c87442a4907..56b31cdbf37 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/AsyncRequestLog.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/AsyncRequestLog.java @@ -2,6 +2,7 @@ // TODO: 10/12/11 -- write tests for AsyncRequestLog +import com.yammer.dropwizard.logging.Log; import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.server.Authentication; import org.eclipse.jetty.server.Request; @@ -10,8 +11,6 @@ import org.eclipse.jetty.util.DateCache; import org.eclipse.jetty.util.RolloverFileOutputStream; import org.eclipse.jetty.util.component.AbstractLifeCycle; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.PrintWriter; import java.util.ArrayList; @@ -30,7 +29,7 @@ */ public class AsyncRequestLog extends AbstractLifeCycle implements RequestLog { private static final AtomicInteger THREAD_COUNTER = new AtomicInteger(); - private static final Logger LOGGER = LoggerFactory.getLogger(AsyncRequestLog.class); + private static final Log LOG = Log.forClass(AsyncRequestLog.class); private static final int BATCH_SIZE = 10000; private class Dispatcher implements Runnable { @@ -111,7 +110,7 @@ protected void doStart() throws Exception { numberOfFilesToRetain, TimeZone.getTimeZone("UTC")); this.writer = new PrintWriter(outputStream); - LOGGER.info("Opened {}", outputStream.getDatedFilename()); + LOG.info("Opened {}", outputStream.getDatedFilename()); } dispatchThread.start(); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java index a820942b732..96fa73ee39a 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/QuietErrorHandler.java @@ -2,6 +2,7 @@ import com.google.common.base.Charsets; import com.google.common.collect.ImmutableSet; +import com.yammer.dropwizard.logging.Log; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.http.HttpMethods; @@ -10,8 +11,6 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.handler.ErrorHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; @@ -25,7 +24,7 @@ * An {@link ErrorHandler} subclass which returns concise, {@code text/plain} error messages. */ public class QuietErrorHandler extends ErrorHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(QuietErrorHandler.class); + private static final Log LOG = Log.forClass(QuietErrorHandler.class); private static final int RESPONSE_BUFFER_SIZE = 4096; /* @@ -83,7 +82,7 @@ private static String errorMessage(HttpServletRequest request, int status) { return format.format(new Object[]{request.getMethod()}); } } catch (MissingResourceException e) { - LOGGER.error("Unable to load HttpErrorMessages.properties", e); + LOG.error(e, "Unable to load HttpErrorMessages.properties"); } return "Your request could not be processed: " + HttpGenerator.getReasonBuffer(status); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java new file mode 100644 index 00000000000..6811300c006 --- /dev/null +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java @@ -0,0 +1,257 @@ +package com.yammer.dropwizard.logging; + +import org.apache.log4j.Logger; +import org.slf4j.helpers.MessageFormatter; + +/** + * A logger class which provides SLF4J-style formatting without SLF4J's less-than-pleasant API. + * + * + * private static final Log LOG = Log.forClass(Thingy.class); + * + * ... + * + * LOG.debug("Simple usage: {} / {}", a, b); + * LOG.debug("No need for manual arrays: {} - {} - {} - {}", a, b, c, d); + * LOG.warn(exception, "Exceptions go first but don't prevent message formatting: {}", otherStuff); + * + */ +public class Log { + public static Log forClass(Class klass) { + return new Log(Logger.getLogger(klass)); + } + + private Logger logger; + + private Log(Logger logger) { + this.logger = logger; + } + + // TRACE + + public boolean isTraceEnabled() { + return logger.isTraceEnabled(); + } + + public void trace(String message) { + logger.trace(message); + } + + public void trace(String message, Object arg) { + if (isTraceEnabled()) { + logger.trace(MessageFormatter.format(message, arg).getMessage()); + } + } + + public void trace(String message, Object arg1, Object arg2) { + if (isTraceEnabled()) { + logger.trace(MessageFormatter.format(message, arg1, arg2).getMessage()); + } + } + + public void trace(String message, Object... args) { + if (isTraceEnabled()) { + logger.trace(MessageFormatter.arrayFormat(message, args).getMessage()); + } + } + + public void trace(Throwable e, String message, Object arg) { + if (isTraceEnabled()) { + logger.trace(MessageFormatter.format(message, arg).getMessage(), e); + } + } + + public void trace(Throwable e, String message, Object arg1, Object arg2) { + if (isTraceEnabled()) { + logger.trace(MessageFormatter.format(message, arg1, arg2).getMessage(), e); + } + } + + public void trace(Throwable e, String message, Object... args) { + if (isTraceEnabled()) { + logger.trace(MessageFormatter.arrayFormat(message, args).getMessage(), e); + } + } + + // DEBUG + + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + public void debug(String message) { + logger.debug(message); + } + + public void debug(String message, Object arg) { + if (isDebugEnabled()) { + logger.trace(MessageFormatter.format(message, arg).getMessage()); + } + } + + public void debug(String message, Object arg1, Object arg2) { + if (isDebugEnabled()) { + logger.trace(MessageFormatter.format(message, arg1, arg2).getMessage()); + } + } + + public void debug(String message, Object... args) { + if (isDebugEnabled()) { + logger.trace(MessageFormatter.arrayFormat(message, args).getMessage()); + } + } + + public void debug(Throwable e, String message, Object arg) { + if (isDebugEnabled()) { + logger.debug(MessageFormatter.format(message, arg).getMessage(), e); + } + } + + public void debug(Throwable e, String message, Object arg1, Object arg2) { + if (isDebugEnabled()) { + logger.debug(MessageFormatter.format(message, arg1, arg2).getMessage(), e); + } + } + + public void debug(Throwable e, String message, Object... args) { + if (isDebugEnabled()) { + logger.debug(MessageFormatter.arrayFormat(message, args).getMessage(), e); + } + } + + // INFO + + public boolean isInfoEnabled() { + return logger.isInfoEnabled(); + } + + public void info(String message) { + logger.info(message); + } + + public void info(String message, Object arg) { + if (isInfoEnabled()) { + logger.info(MessageFormatter.format(message, arg).getMessage()); + } + } + + public void info(String message, Object arg1, Object arg2) { + if (isInfoEnabled()) { + logger.info(MessageFormatter.format(message, arg1, arg2).getMessage()); + } + } + + public void info(String message, Object... args) { + if (isInfoEnabled()) { + logger.info(MessageFormatter.arrayFormat(message, args).getMessage()); + } + } + + public void info(Throwable e, String message, Object arg) { + if (isInfoEnabled()) { + logger.info(MessageFormatter.format(message, arg).getMessage(), e); + } + } + + public void info(Throwable e, String message, Object arg1, Object arg2) { + if (isInfoEnabled()) { + logger.info(MessageFormatter.format(message, arg1, arg2).getMessage(), e); + } + } + + public void info(Throwable e, String message, Object... args) { + if (isInfoEnabled()) { + logger.info(MessageFormatter.arrayFormat(message, args).getMessage(), e); + } + } + + // WARN + + public void warn(String message) { + logger.warn(message); + } + + public void warn(String message, Object arg) { + logger.warn(MessageFormatter.format(message, arg).getMessage()); + } + + public void warn(String message, Object arg1, Object arg2) { + logger.warn(MessageFormatter.format(message, arg1, arg2).getMessage()); + } + + public void warn(String message, Object... args) { + logger.warn(MessageFormatter.arrayFormat(message, args).getMessage()); + } + + public void warn(Throwable e, String message, Object arg) { + logger.warn(MessageFormatter.format(message, arg).getMessage(), e); + } + + public void warn(Throwable e, String message, Object arg1, Object arg2) { + logger.warn(MessageFormatter.format(message, arg1, arg2).getMessage(), e); + } + + public void warn(Throwable e, String message, Object... args) { + logger.warn(MessageFormatter.arrayFormat(message, args).getMessage(), e); + } + + // ERROR + + public void error(String message) { + logger.error(message); + } + + public void error(String message, Object arg) { + logger.error(MessageFormatter.format(message, arg).getMessage()); + } + + public void error(String message, Object arg1, Object arg2) { + logger.error(MessageFormatter.format(message, arg1, arg2).getMessage()); + } + + public void error(String message, Object... args) { + logger.error(MessageFormatter.arrayFormat(message, args).getMessage()); + } + + public void error(Throwable e, String message, Object arg) { + logger.error(MessageFormatter.format(message, arg).getMessage(), e); + } + + public void error(Throwable e, String message, Object arg1, Object arg2) { + logger.error(MessageFormatter.format(message, arg1, arg2).getMessage(), e); + } + + public void error(Throwable e, String message, Object... args) { + logger.error(MessageFormatter.arrayFormat(message, args).getMessage(), e); + } + + // FATAL + + public void fatal(String message) { + logger.fatal(message); + } + + public void fatal(String message, Object arg) { + logger.fatal(MessageFormatter.format(message, arg).getMessage()); + } + + public void fatal(String message, Object arg1, Object arg2) { + logger.fatal(MessageFormatter.format(message, arg1, arg2).getMessage()); + } + + public void fatal(String message, Object... args) { + logger.fatal(MessageFormatter.arrayFormat(message, args).getMessage()); + } + + public void fatal(Throwable e, String message, Object arg) { + logger.fatal(MessageFormatter.format(message, arg).getMessage(), e); + } + + public void fatal(Throwable e, String message, Object arg1, Object arg2) { + logger.fatal(MessageFormatter.format(message, arg1, arg2).getMessage(), e); + } + + public void fatal(Throwable e, String message, Object... args) { + logger.fatal(MessageFormatter.arrayFormat(message, args).getMessage(), e); + } +} diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java index 5fddc156269..8349f30cc42 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/SlowRequestFilter.java @@ -1,8 +1,7 @@ package com.yammer.dropwizard.servlets; +import com.yammer.dropwizard.logging.Log; import com.yammer.dropwizard.util.Duration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; @@ -10,14 +9,13 @@ import java.util.concurrent.TimeUnit; import static com.yammer.dropwizard.util.Servlets.getFullUrl; -import static java.lang.String.format; /** * A servlet filter which logs the methods and URIs of requests which take longer than a given * duration of time to complete. */ public class SlowRequestFilter implements Filter { - private static final Logger LOGGER = LoggerFactory.getLogger(SlowRequestFilter.class); + private static final Log LOG = Log.forClass(SlowRequestFilter.class); private final long threshold; /** @@ -53,7 +51,9 @@ public void doFilter(ServletRequest request, } finally { final long elapsedMS = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime); if (elapsedMS >= threshold) { - LOGGER.warn(format("Slow request: %s %s (%dms)", req.getMethod(), getFullUrl(req), elapsedMS)); + LOG.warn("Slow request: {} {} ({}ms)", + req.getMethod(), + getFullUrl(req), elapsedMS); } } } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java index 7f024f4630f..d68803b9345 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/tasks/TaskServlet.java @@ -2,8 +2,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.yammer.dropwizard.logging.Log; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -12,7 +11,7 @@ import javax.ws.rs.core.MediaType; import java.io.IOException; import java.io.PrintWriter; -import java.util.*; +import java.util.Enumeration; /** * A servlet which provides access to administrative {@link Task}s. It only responds to {@code POST} @@ -23,7 +22,7 @@ */ public class TaskServlet extends HttpServlet { private static final long serialVersionUID = 7404713218661358124L; - private static final Logger LOGGER = LoggerFactory.getLogger(TaskServlet.class); + private static final Log LOG = Log.forClass(TaskServlet.class); private final ImmutableMap tasks; /** @@ -53,7 +52,7 @@ protected void doPost(HttpServletRequest req, output.close(); } } catch (Exception e) { - LOGGER.error("Error running " + task.getName(), e); + LOG.error(e, "Error running {}", task.getName()); resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } else { diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java index 34d48c6faf3..542e3f26a91 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingDBIExceptionMapper.java @@ -1,8 +1,7 @@ package com.yammer.dropwizard.jersey; +import com.yammer.dropwizard.logging.Log; import org.skife.jdbi.v2.exceptions.DBIException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.ws.rs.ext.Provider; import java.sql.SQLException; @@ -12,17 +11,17 @@ */ @Provider public class LoggingDBIExceptionMapper extends LoggingExceptionMapper { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggingDBIExceptionMapper.class); + private static final Log LOG = Log.forClass(LoggingDBIExceptionMapper.class); @Override protected void logException(long id, DBIException exception) { final Throwable cause = exception.getCause(); if (cause instanceof SQLException) { for (Throwable throwable : (SQLException)cause) { - LOGGER.error(formatLogMessage(id, throwable), throwable); + LOG.error(throwable, formatLogMessage(id, throwable)); } } else { - LOGGER.error(formatLogMessage(id, exception), exception); + LOG.error(exception, formatLogMessage(id, exception)); } } } diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java index 6d7efd967a2..b351242776a 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/jersey/LoggingSQLExceptionMapper.java @@ -1,7 +1,6 @@ package com.yammer.dropwizard.jersey; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.yammer.dropwizard.logging.Log; import javax.ws.rs.ext.Provider; import java.sql.SQLException; @@ -11,13 +10,13 @@ */ @Provider public class LoggingSQLExceptionMapper extends LoggingExceptionMapper { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggingSQLExceptionMapper.class); + private static final Log LOG = Log.forClass(LoggingSQLExceptionMapper.class); @Override protected void logException(long id, SQLException exception) { final String message = formatLogMessage(id, exception); for (Throwable throwable : exception) { - LOGGER.error(message, throwable); + LOG.error(throwable, message); } } } diff --git a/dropwizard-example/src/main/java/com/example/helloworld/cli/RenderCommand.java b/dropwizard-example/src/main/java/com/example/helloworld/cli/RenderCommand.java index aa0599d6e88..674d662cab9 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/cli/RenderCommand.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/cli/RenderCommand.java @@ -5,13 +5,12 @@ import com.google.common.base.Optional; import com.yammer.dropwizard.AbstractService; import com.yammer.dropwizard.cli.ConfiguredCommand; +import com.yammer.dropwizard.logging.Log; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class RenderCommand extends ConfiguredCommand { - private static final Logger LOGGER = LoggerFactory.getLogger(RenderCommand.class); + private static final Log LOG = Log.forClass(RenderCommand.class); public RenderCommand() { super("render", "Renders the configured template to the console."); @@ -37,11 +36,11 @@ protected void run(AbstractService service, final Template template = configuration.buildTemplate(); if (params.hasOption("include-default")) { - LOGGER.info("DEFAULT => {}", template.render(Optional.absent())); + LOG.info("DEFAULT => {}", template.render(Optional.absent())); } for (String name : params.getArgs()) { - LOGGER.info("{} => {}", name, template.render(Optional.of(name))); + LOG.info("{} => {}", name, template.render(Optional.of(name))); } } } From 2316a9a0a52ac240d24340b4c131631f0122de8c Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 27 Dec 2011 15:33:51 -0800 Subject: [PATCH 0130/2771] Update changelog. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c94d27260f..a03ebfae910 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ v0.1.1: TBD * Fixed `ManagedCommand` to provide access to the `Environment`, among other things. * Made `JerseyClient`'s thread pool managed. * Improved ease of use for `Duration` and `Size` configuration parameters. +* Upgraded to Mockito 1.9.0. +* Upgraded to Jetty 7.6.0.RC2. +* Removed single-arg constructors for `ConfiguredCommand`. +* Added `Log`, a simple front-end for logging. v0.1.0: Dec 21 2011 From b594599bcfcdd5deafa76b7e2262038f731bab3d Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 11:08:46 -0800 Subject: [PATCH 0131/2771] Added docs and more factory methods to Log. --- .../com/yammer/dropwizard/logging/Log.java | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java index 6811300c006..530003ea63d 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java @@ -16,12 +16,61 @@ * LOG.warn(exception, "Exceptions go first but don't prevent message formatting: {}", otherStuff); * */ +@SuppressWarnings("UnusedDeclaration") public class Log { + /** + * Returns a {@link Log} instance for the given class. + * + * @param klass a given class + * @return a {@link Log} instance with {@code klass}'s name + */ public static Log forClass(Class klass) { - return new Log(Logger.getLogger(klass)); + return forLog4jLogger(Logger.getLogger(klass)); + } + + /** + * Returns a {@link Log} instance with the given name. + * + * @param name a given name + * @return a {@link Log} instance with the given name + */ + public static Log named(String name) { + return forLog4jLogger(Logger.getLogger(name)); + } + + /** + * Returns a {@link Log} instance with the same name as the given Log4j {@link Logger} instance. + * + * @param logger a Log4j {@link Logger} + * @return a {@link Log} instance with the same name as {@code logger} + */ + public static Log forLog4jLogger(Logger logger) { + return new Log(logger); + } + + /** + * Returns a {@link Log} instance with the same name as the given slf4j {@link org.slf4j.Logger} + * instance. + * + * @param logger an Slf4j {@link org.slf4j.Logger} + * @return a {@link Log} instance with the same name as {@code logger} + */ + public static Log forSlf4jLogger(org.slf4j.Logger logger) { + return named(logger.getName()); + } + + /** + * Returns a {@link Log} instance with the same name as the given {@code java.util.logging} + * {@link java.util.logging.Logger} instance. + * + * @param logger a {@code java.util.logging} {@link java.util.logging.Logger} instance + * @return a {@link Log} instance with the same name as {@code logger} + */ + public static Log forJulLogger(java.util.logging.Logger logger) { + return named(logger.getName()); } - private Logger logger; + private final Logger logger; private Log(Logger logger) { this.logger = logger; From 58374ec3b7c8cee2952f516ac4ff137cd85a69ed Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 12:00:33 -0800 Subject: [PATCH 0132/2771] Upgrade everything to Mockito 1.9.0. --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 12 ------------ pom.xml | 2 +- 6 files changed, 5 insertions(+), 17 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index e19112765b3..0fc1c993192 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -47,7 +47,7 @@ org.mockito mockito-all - 1.9.0-rc1 + 1.9.0 test diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 0b53e935ff0..3ef96ae17fc 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -123,7 +123,7 @@ org.mockito mockito-all - 1.9.0-rc1 + 1.9.0 test diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 9938700e2b3..b414afae3b7 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -48,7 +48,7 @@ org.mockito mockito-all - 1.9.0-rc1 + 1.9.0 test diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index a9389f3b916..8ca21459931 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -34,7 +34,7 @@ org.mockito mockito-all - 1.9.0-rc1 + 1.9.0 test diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 12d6dd87e06..3322d0b20b5 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -93,18 +93,6 @@ metrics-scala_${scala.version} ${metrics.version} - - junit - junit - 4.10 - test - - - org.mockito - mockito-all - 1.9.0-rc1 - test - org.hamcrest hamcrest-all diff --git a/pom.xml b/pom.xml index 9bba347868a..d2b39f0a99e 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ scpexe://codahale.com/home/codahale/dropwizard.codahale.com/maven/ - + sign From 456d07614ecfc33ed4b4254c98ee549b0584bd5f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 12:12:18 -0800 Subject: [PATCH 0133/2771] Prep for 0.1.1. --- CHANGELOG.md | 2 +- docs/getting-started.html | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a03ebfae910..a93149e1ae0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -v0.1.1: TBD +v0.1.1: Dec 28 2011 =================== * Fixed `ManagedCommand` to provide access to the `Environment`, among other things. diff --git a/docs/getting-started.html b/docs/getting-started.html index a1eede74938..899d484b1e4 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -188,7 +188,7 @@

    Setting Up Maven

    <dependency> <groupId>com.yammer.dropwizard</groupId> <artifactId>dropwizard-core</artifactId> - <version>0.1.0</version> + <version>0.1.1</version> </dependency> </dependencies> diff --git a/pom.xml b/pom.xml index d2b39f0a99e..9bba347868a 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ scpexe://codahale.com/home/codahale/dropwizard.codahale.com/maven/ - + sign From 444dae4e8e5c9a13ae9635d5bfbb1992440ad3f4 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 12:16:47 -0800 Subject: [PATCH 0134/2771] Fix Scala build. --- dropwizard-scala_2.9.1/pom.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 3322d0b20b5..5cbde38d230 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -93,6 +93,18 @@ metrics-scala_${scala.version} ${metrics.version}
    + + junit + junit + 4.10 + test + + + org.mockito + mockito-all + 1.9.0 + test + org.hamcrest hamcrest-all From 15e37f08ee5e8e6692bc64e3ca41695913a76f18 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 12:16:54 -0800 Subject: [PATCH 0135/2771] Drop the compiler plugin and optimizations for Scala. --- dropwizard-scala_2.9.1/pom.xml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 5cbde38d230..0186a7e950b 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -21,10 +21,6 @@ scala-tools-releases http://scala-tools.org/repo-releases/ - - nativelibs4java - http://nativelibs4java.sourceforge.net/maven - repo.codahale.com http://repo.codahale.com/ @@ -142,18 +138,6 @@ - - -optimise - -unchecked - -deprecation - - - - com.nativelibs4java - scalacl-compiler-plugin - 0.2 - - UTF-8 From 2d5e71c2d2137e20e1e3249cc30e28b02d36c567 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 12:27:01 -0800 Subject: [PATCH 0136/2771] Do a better job of configuring maven-release. --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9bba347868a..d6eb2f1382a 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,7 @@ - sign + release-sign-artifacts performRelease @@ -168,7 +168,7 @@ true forked-path v@{project.version} - clean verify gpg:sign + clean From 037baeff84b3327171d2daaec6100d51167ac4de Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 12:27:46 -0800 Subject: [PATCH 0137/2771] [maven-release-plugin] prepare release v0.1.1 --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 0fc1c993192..f9980fd3021 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1-SNAPSHOT + 0.1.1 com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 3ef96ae17fc..78d88e1d09c 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1-SNAPSHOT + 0.1.1 com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index b414afae3b7..a63d91f23a1 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1-SNAPSHOT + 0.1.1 com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 8ca21459931..b5780f23b2a 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.1.1-SNAPSHOT + 0.1.1 Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 0186a7e950b..1f13229ca7d 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1-SNAPSHOT + 0.1.1 com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 65feff37620..ded693b9314 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1-SNAPSHOT + 0.1.1 com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 3019d9294fc..49fe1a92a8c 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1-SNAPSHOT + 0.1.1 com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index d6eb2f1382a..234c4711572 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1-SNAPSHOT + 0.1.1 pom Dropwizard Project http://dropwizard.codahale.com/ From 5811ca443838ead3bbb2132d671aa1c75302421b Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 12:27:54 -0800 Subject: [PATCH 0138/2771] [maven-release-plugin] prepare for next development iteration --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index f9980fd3021..005ae8862f9 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1 + 0.1.2-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 78d88e1d09c..72e9047e3f8 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1 + 0.1.2-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index a63d91f23a1..0124571d100 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1 + 0.1.2-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index b5780f23b2a..f526da0adc0 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.1.1 + 0.1.2-SNAPSHOT Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 1f13229ca7d..9ceb337ba26 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1 + 0.1.2-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index ded693b9314..2239407afb8 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1 + 0.1.2-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 49fe1a92a8c..792c6156ac2 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1 + 0.1.2-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 234c4711572..e1d3ccea32b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.1 + 0.1.2-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From 5992d9a7fbfad94e6ba629f8cb94864b9c332ece Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 12:34:44 -0800 Subject: [PATCH 0139/2771] Test before releasing. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e1d3ccea32b..f53b1673e70 100644 --- a/pom.xml +++ b/pom.xml @@ -168,7 +168,7 @@ true forked-path v@{project.version} - clean + clean test From 9c994b64feda9cee9e222eb279e567cb1095f110 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 17:26:48 -0800 Subject: [PATCH 0140/2771] Make sure the example app can pull snapshots. --- dropwizard-example/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index f526da0adc0..8226d9f9daa 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -8,6 +8,11 @@ Dropwizard Example Application + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + http://oss.sonatype.org/content/repositories/snapshots + repo.codahale.com http://repo.codahale.com/ From a030c42cdb8e1623eb01df6cfd490062b0ec020b Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 17:27:22 -0800 Subject: [PATCH 0141/2771] Upgrade to Metrics 2.0.0-BETA19-SNAPSHOT. Also, add metrics-jersey in by default. --- dropwizard-core/pom.xml | 5 +++++ .../main/java/com/yammer/dropwizard/config/Environment.java | 2 ++ dropwizard-example/pom.xml | 5 ----- .../com/example/helloworld/resources/HelloWorldResource.java | 2 +- pom.xml | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 72e9047e3f8..d394ba9f9fd 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -54,6 +54,11 @@ metrics-log4j ${metrics.version} + + com.yammer.metrics + metrics-jersey + ${metrics.version} + org.codehaus.jackson jackson-core-asl diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 32cab86fae3..c5ed8e22702 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -19,6 +19,7 @@ import com.yammer.dropwizard.tasks.GarbageCollectionTask; import com.yammer.dropwizard.tasks.Task; import com.yammer.metrics.core.HealthCheck; +import com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.component.AbstractLifeCycle; @@ -70,6 +71,7 @@ public Environment() { enableJerseyFeature(ResourceConfig.FEATURE_DISABLE_WADL); addProvider(new LoggingExceptionMapper() {}); // create a subclass to pin it to Throwable + addProvider(InstrumentedResourceMethodDispatchProvider.class); addServlet(new ServletContainer(config), ROOT_PATH).setInitOrder(Integer.MAX_VALUE); addTask(new GarbageCollectionTask()); } diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 8226d9f9daa..f240f118494 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -25,11 +25,6 @@ dropwizard-core ${project.version} - - com.yammer.metrics - metrics-aop - 2.0.0-BETA18 - junit junit diff --git a/dropwizard-example/src/main/java/com/example/helloworld/resources/HelloWorldResource.java b/dropwizard-example/src/main/java/com/example/helloworld/resources/HelloWorldResource.java index 24657965468..bf375c4a983 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/resources/HelloWorldResource.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/resources/HelloWorldResource.java @@ -3,7 +3,7 @@ import com.example.helloworld.core.Saying; import com.example.helloworld.core.Template; import com.google.common.base.Optional; -import com.yammer.metrics.aop.annotation.Timed; +import com.yammer.metrics.annotation.Timed; import javax.ws.rs.GET; import javax.ws.rs.Path; diff --git a/pom.xml b/pom.xml index f53b1673e70..da43d85bc24 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ - 2.0.0-BETA18 + 2.0.0-BETA19-SNAPSHOT 1.11 From 82dac276eb87668a10c5277eaeb28d31bdf24be9 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 28 Dec 2011 17:57:53 -0800 Subject: [PATCH 0142/2771] Update changelog. --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a93149e1ae0..dca5ad6a582 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v0.1.2: TBD +=================== + +* All Jersey resource methods annotated with `@Timed`, `@Metered`, or `@ExceptionMetered` are now + instrumented via `metrics-jersey`. + + v0.1.1: Dec 28 2011 =================== From 97db036276389553cb4bdd0bed2736a311703dc2 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 29 Dec 2011 00:15:29 -0800 Subject: [PATCH 0143/2771] Remove LogThroughputRunner. --- .../experiments/LogThroughputRunner.scala | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala diff --git a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala deleted file mode 100644 index 13da68b5a84..00000000000 --- a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/experiments/LogThroughputRunner.scala +++ /dev/null @@ -1,57 +0,0 @@ -package com.yammer.dropwizard.experiments - -import java.util.concurrent.{TimeUnit, Executors} -import com.yammer.metrics.Instrumented -import com.yammer.metrics.reporting.ConsoleReporter -import org.eclipse.jetty.server._ -import org.mockito.Mockito._ -import org.eclipse.jetty.http.{HttpFields, HttpURI} -import com.yammer.dropwizard.jetty.AsyncRequestLog - -object LogThroughputRunner extends Instrumented { - val timer = metrics.timer("log", durationUnit = TimeUnit.MICROSECONDS) - - class LogWriter(log: RequestLog) extends Runnable { - val fields = new HttpFields - - val conn = mock(classOf[AbstractHttpConnection]) - when(conn.getRequestFields).thenReturn(fields) - - val request = new Request(conn) - request.setRemoteAddr("127.0.0.1") - request.setUri(new HttpURI("/one/two/three")) - request.setMethod("GET") - request.setProtocol("HTTP/1.1") - - val response = new Response(conn) - response.setStatus(200) - - def run() { - try { - for (i <- 1 to 10000) { - timer.time { log.log(request, response) } - } - } catch { - case e => e.printStackTrace() - } - } - } - - def newLog() = { -// new NCSARequestLog("./logs/ncsa_request_log_yyyy_mm_dd.log") - new AsyncRequestLog("./logs/async_request_log_yyyy_mm_dd.log", 1) - } - - def main(args: Array[String]) { - ConsoleReporter.enable(1, TimeUnit.SECONDS) - val log = newLog() - log.start() - val pool = Executors.newFixedThreadPool(1000) - for (i <- 1 to 1000) { - pool.execute(new LogWriter(log)) - } - pool.shutdown() - pool.awaitTermination(10, TimeUnit.MINUTES) - log.stop() - } -} From 45c36b53076c500ba564e15d7b69c3eb5cfa4726 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 29 Dec 2011 00:15:37 -0800 Subject: [PATCH 0144/2771] Make sure all our Scala resources are timed. --- .../com/yammer/dropwizard/examples/HelloWorldResource.scala | 4 ++++ .../com/yammer/dropwizard/examples/ProtectedResource.scala | 2 ++ .../scala/com/yammer/dropwizard/examples/SplodyResource.scala | 3 +++ .../scala/com/yammer/dropwizard/examples/UploadResource.scala | 2 ++ 4 files changed, 11 insertions(+) diff --git a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala index 5e17e668325..e08f5f938ab 100644 --- a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala +++ b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala @@ -3,16 +3,20 @@ package com.yammer.dropwizard.examples import javax.ws.rs._ import core.Response.Status import core.{Response, MediaType} +import com.yammer.metrics.annotation.Timed @Path("/hello-world") @Produces(Array(MediaType.APPLICATION_JSON)) class HelloWorldResource(saying: String) { @GET + @Timed def sayHello(@QueryParam("opt") opt: Option[String]) = Seq(saying) @POST + @Timed def intentionalError = Response.status(Status.BAD_REQUEST).build() @PUT + @Timed def unintentionalError = None.get } diff --git a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ProtectedResource.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ProtectedResource.scala index 265d3ab3815..28bc8965282 100644 --- a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ProtectedResource.scala +++ b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ProtectedResource.scala @@ -4,11 +4,13 @@ import javax.ws.rs.{WebApplicationException, Produces, GET, Path} import javax.ws.rs.core.MediaType import javax.ws.rs.core.Response.Status import com.yammer.dropwizard.BearerToken +import com.yammer.metrics.annotation.Timed @Path("/secret") @Produces(Array(MediaType.APPLICATION_JSON)) class ProtectedResource { @GET + @Timed def access(@BearerToken token: Option[String]) = { if (token.isDefined) { Map("you" -> ("You are ok, Mr. " + token.get)) diff --git a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyResource.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyResource.scala index 5708c441ad3..4e7ad1e2f19 100644 --- a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyResource.scala +++ b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/SplodyResource.scala @@ -3,6 +3,7 @@ package com.yammer.dropwizard.examples import javax.ws.rs.core.StreamingOutput import javax.ws.rs.{POST, GET, Path} import java.io.OutputStream +import com.yammer.metrics.annotation.Timed @Path("/splode") class SplodyResource { @@ -12,12 +13,14 @@ class SplodyResource { * An error which happens inside a Jersey resource. */ @GET + @Timed def splode() = dumb.toString /** * An error which happens outside of a Jersey resource. */ @POST + @Timed def sneakySplode(): StreamingOutput = new StreamingOutput { def write(output: OutputStream) { throw new RuntimeException("OH SWEET GOD WHAT") diff --git a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/UploadResource.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/UploadResource.scala index 6931bf6a4f3..ea076b54e43 100644 --- a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/UploadResource.scala +++ b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/UploadResource.scala @@ -3,11 +3,13 @@ package com.yammer.dropwizard.examples import javax.ws.rs.core.MediaType import javax.ws.rs.{POST, Consumes, Path} import com.codahale.logula.Logging +import com.yammer.metrics.annotation.Timed @Path("/upload") @Consumes(Array(MediaType.WILDCARD)) class UploadResource extends Logging { @POST + @Timed def upload(body: String) { log.info("New upload: %s", body) } From 8fad79a9b206488ec7d1442a402b093ac27f66dc Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 29 Dec 2011 00:28:52 -0800 Subject: [PATCH 0145/2771] Update docs for Metrics B19. --- docs/getting-started.html | 33 +++++++++++---------------------- docs/manual.html | 9 +++++++++ 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/docs/getting-started.html b/docs/getting-started.html index 899d484b1e4..a587d87f342 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -399,9 +399,7 @@

    Creating A Resource Class

    import com.example.helloworld.core.Saying; import com.google.common.base.Optional; -import com.yammer.metrics.Metrics; -import com.yammer.metrics.core.TimerContext; -import com.yammer.metrics.core.TimerMetric; +import com.yammer.metrics.annotation.Timed; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -413,9 +411,6 @@

    Creating A Resource Class

    @Path("/hello-world") @Produces(MediaType.APPLICATION_JSON) public class HelloWorldResource { - private static final TimerMetric GETS = Metrics.newTimer(HelloWorldResource.class, - "get-requests"); - private final String template; private final String defaultName; private final AtomicLong counter; @@ -427,14 +422,10 @@

    Creating A Resource Class

    } @GET + @Timed public Saying sayHello(@QueryParam("name") Optional<String> name) { - final TimerContext context = GETS.time(); - try { - return new Saying(counter.incrementAndGet(), - String.format(template, name.or(defaultName))); - } finally { - context.stop(); - } + return new Saying(counter.incrementAndGet(), + String.format(template, name.or(defaultName))); } } @@ -450,11 +441,6 @@

    Creating A Resource Class

    code know that this resource produces representations which are application/json.

    - -

    - GETS is a TimerMetric from the Metrics library which we use - to monitor both the latency and rate of GET requests for this resource. -

    HelloWorldResource takes two parameters for construction: the @@ -481,12 +467,15 @@

    Creating A Resource Class

    - Inside the sayHello method, we get a TimerContext from the - timer, which allows us to measure now much time each request takes and how many requests - per second our service is doing at any point in time. We increment the counter, format - the template using String.format(String, Object...), and return a new + Inside the sayHello method, we increment the counter, format the template + using String.format(String, Object...), and return a new Saying instance.

    + +

    + Because sayHello is annotated with @Timed, Dropwizard + automatically records the duration and rate of its invocations as a Metrics Timer. +

    Once sayHello has returned, Jersey takes the Saying instance diff --git a/docs/manual.html b/docs/manual.html index 65e931a2e42..bc4acc46275 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -74,6 +74,7 @@

    Dropwizard User’s Manual
    • Paths
    • Methods
    • +
    • Metrics
    • Parameters
    • Request Entities
    • Media Types
    • @@ -751,6 +752,14 @@

      Methods

      resource only supports JSON, and so the NotificationList is serialized to JSON using Jackson.

      + +

      Metrics

      + +

      + Every resource method can be annotated with @Timed, @Metered, + and @ExceptionMetered. Dropwizard augments Jersey to automatically record + runtime information about your resource methods. +

      Parameters

      From 71777816073e69eb4ec9e493636e5e95ca531953 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 29 Dec 2011 00:47:14 -0800 Subject: [PATCH 0146/2771] Switch from MIT to ASL2.0. --- LICENSE | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NOTICE | 4 ++ pom.xml | 4 +- 3 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 LICENSE create mode 100644 NOTICE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000000..2a3121b8640 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2011 Coda Hale and Yammer, Inc. + + 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. diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000000..315c62ea9d8 --- /dev/null +++ b/NOTICE @@ -0,0 +1,4 @@ +Metrics +Copyright 2011 Coda Hale and Yammer, Inc. + +This product includes software developed by Coda Hale and Yammer, Inc. diff --git a/pom.xml b/pom.xml index da43d85bc24..620094c152a 100644 --- a/pom.xml +++ b/pom.xml @@ -38,8 +38,8 @@ - http://codahale.com/mit.txt - The MIT License + Apache License 2.0 + http://www.apache.org/licenses/LICENSE-2.0.html repo From 6f732991570fd1a68d6f55630d3b4dbff18ce76a Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 29 Dec 2011 00:48:20 -0800 Subject: [PATCH 0147/2771] Update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dca5ad6a582..7bf17bbc72f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ v0.1.2: TBD * All Jersey resource methods annotated with `@Timed`, `@Metered`, or `@ExceptionMetered` are now instrumented via `metrics-jersey`. +* Now licensed under Apache License 2.0. v0.1.1: Dec 28 2011 From edf58b797632b121af986ab9976dd8917dffa891 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 29 Dec 2011 19:42:43 -0800 Subject: [PATCH 0148/2771] Update metrics-jetty usage. --- .../main/java/com/yammer/dropwizard/config/Environment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index c5ed8e22702..159f49aa618 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -19,7 +19,7 @@ import com.yammer.dropwizard.tasks.GarbageCollectionTask; import com.yammer.dropwizard.tasks.Task; import com.yammer.metrics.core.HealthCheck; -import com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider; +import com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchAdapter; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.component.AbstractLifeCycle; @@ -71,7 +71,7 @@ public Environment() { enableJerseyFeature(ResourceConfig.FEATURE_DISABLE_WADL); addProvider(new LoggingExceptionMapper() {}); // create a subclass to pin it to Throwable - addProvider(InstrumentedResourceMethodDispatchProvider.class); + addProvider(InstrumentedResourceMethodDispatchAdapter.class); addServlet(new ServletContainer(config), ROOT_PATH).setInitOrder(Integer.MAX_VALUE); addTask(new GarbageCollectionTask()); } From ecdae56e3b9e20f45d8c9dcacf1c5066c88fa196 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 2 Jan 2012 15:41:22 -0800 Subject: [PATCH 0149/2771] Track new changes in Metrics BETA19-SNAPSHOT. --- docs/getting-started.html | 8 ++------ docs/manual.html | 8 ++------ .../com/yammer/dropwizard/config/ServerFactory.java | 2 +- .../yammer/dropwizard/db/DatabaseHealthCheck.java | 12 +++--------- .../helloworld/health/TemplateHealthCheck.java | 8 ++------ .../yammer/dropwizard/examples/DumbHealthCheck.scala | 4 +--- 6 files changed, 11 insertions(+), 31 deletions(-) diff --git a/docs/getting-started.html b/docs/getting-started.html index a587d87f342..a49990c2a82 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -540,16 +540,12 @@

      Adding A Health Check

      private final String template; public TemplateHealthCheck(String template) { + super("template"); this.template = template; } @Override - public String name() { - return "template"; - } - - @Override - public Result check() throws Exception { + protected Result check() throws Exception { final String saying = String.format(template, "TEST"); if (!saying.contains("TEST")) { return Result.unhealthy("template doesn't include a name"); diff --git a/docs/manual.html b/docs/manual.html index bc4acc46275..01763dc177c 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -298,16 +298,12 @@

      Health Checks

      private final Database database; public DatabaseHealthCheck(Database database) { + super("database"); this.database = database; } @Override - public String name() { - return "database"; - } - - @Override - public Result check() throws Exception { + protected Result check() throws Exception { if (database.isConnected()) { return Result.healthy(); } else { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index d0a0a3bad24..1149255da6c 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -9,10 +9,10 @@ import com.yammer.dropwizard.util.Duration; import com.yammer.dropwizard.util.Size; import com.yammer.metrics.HealthChecks; -import com.yammer.metrics.core.DeadlockHealthCheck; import com.yammer.metrics.core.HealthCheck; import com.yammer.metrics.jetty.InstrumentedHandler; import com.yammer.metrics.reporting.MetricsServlet; +import com.yammer.metrics.util.DeadlockHealthCheck; import org.eclipse.jetty.server.*; import org.eclipse.jetty.server.bio.SocketConnector; import org.eclipse.jetty.server.handler.HandlerCollection; diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseHealthCheck.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseHealthCheck.java index c0ab25029d1..d6a306c67df 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseHealthCheck.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseHealthCheck.java @@ -4,20 +4,14 @@ public class DatabaseHealthCheck extends HealthCheck { private final Database database; - private final String name; - + public DatabaseHealthCheck(Database database, String name) { + super(name + "-db"); this.database = database; - this.name = name; - } - - @Override - public String name() { - return name + "-db"; } @Override - public Result check() throws Exception { + protected Result check() throws Exception { database.ping(); return Result.healthy(); } diff --git a/dropwizard-example/src/main/java/com/example/helloworld/health/TemplateHealthCheck.java b/dropwizard-example/src/main/java/com/example/helloworld/health/TemplateHealthCheck.java index ebc40c03e09..21513defb35 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/health/TemplateHealthCheck.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/health/TemplateHealthCheck.java @@ -8,16 +8,12 @@ public class TemplateHealthCheck extends HealthCheck { private final Template template; public TemplateHealthCheck(Template template) { + super("template"); this.template = template; } @Override - public String name() { - return "template"; - } - - @Override - public Result check() throws Exception { + protected Result check() throws Exception { template.render(Optional.of("woo")); template.render(Optional.absent()); return Result.healthy(); diff --git a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/DumbHealthCheck.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/DumbHealthCheck.scala index 63b457ed91d..e5f629364df 100644 --- a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/DumbHealthCheck.scala +++ b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/DumbHealthCheck.scala @@ -3,8 +3,6 @@ package com.yammer.dropwizard.examples import com.yammer.metrics.core.HealthCheck import com.yammer.metrics.core.HealthCheck.Result -class DumbHealthCheck extends HealthCheck { - def name = "dumb" - +class DumbHealthCheck extends HealthCheck("dumb") { def check = Result.healthy } From a340ace0e0881ec8225e7bbfef17022dc0a95c09 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 4 Jan 2012 18:34:29 -0800 Subject: [PATCH 0150/2771] Added helper methods for JerseyClient. --- .../dropwizard/client/JerseyClient.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java index 762346457b2..e1832bc7aa1 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClient.java @@ -4,8 +4,27 @@ import com.sun.jersey.client.apache4.ApacheHttpClient4; import com.sun.jersey.client.apache4.ApacheHttpClient4Handler; +import javax.ws.rs.core.MediaType; +import java.net.URI; + public class JerseyClient extends ApacheHttpClient4 { public JerseyClient(ApacheHttpClient4Handler root, ClientConfig config) { super(root, config); } + + public T get(URI uri, MediaType acceptedMediaType, Class klass) { + return resource(uri).accept(acceptedMediaType).get(klass); + } + + public T put(URI uri, MediaType contentType, Object entity, Class returnType) { + return resource(uri).type(contentType).put(returnType, entity); + } + + public T post(URI uri, MediaType contentType, Object entity, Class returnType) { + return resource(uri).type(contentType).post(returnType, entity); + } + + public T delete(URI uri, Class klass) { + return resource(uri).delete(klass); + } } From 5ef25ba4f33b82c11390bb33e12521d2c3d4b640 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 5 Jan 2012 11:30:26 -0800 Subject: [PATCH 0151/2771] Don't make ServerCommand#run() final. --- .../main/java/com/yammer/dropwizard/cli/ServerCommand.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java index 43a7f64b1ea..9bb89783db6 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java @@ -40,9 +40,9 @@ protected Class getConfigurationClass() { } @Override - protected final void run(AbstractService service, - T configuration, - CommandLine params) throws Exception { + protected void run(AbstractService service, + T configuration, + CommandLine params) throws Exception { final Environment environment = new Environment(); service.initializeWithBundles(configuration, environment); From 7f96a9683db110dccabbc89f901371be681f5efd Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 5 Jan 2012 11:35:03 -0800 Subject: [PATCH 0152/2771] Fix ServerCommand logging. --- .../java/com/yammer/dropwizard/cli/ServerCommand.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java index 9bb89783db6..70af298b531 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java @@ -48,11 +48,11 @@ protected void run(AbstractService service, final Server server = new ServerFactory(configuration.getHttpConfiguration()).buildServer(environment); - final Log logger = Log.forClass(ServerCommand.class); - logger.info("Starting {}", service.getName()); + final Log log = Log.forClass(ServerCommand.class); + log.info("Starting {}", service.getName()); try { - logger.info('\n' + Resources.toString(Resources.getResource("banner.txt"), Charsets.UTF_8)); + log.info("{}\n", Resources.toString(Resources.getResource("banner.txt"), Charsets.UTF_8)); } catch (IllegalArgumentException ignored) { // don't display the banner if there isn't one } @@ -61,7 +61,7 @@ protected void run(AbstractService service, server.start(); server.join(); } catch (Exception e) { - logger.error("Unable to start server, shutting down", e); + log.error(e, "Unable to start server, shutting down"); server.stop(); } } From 6c9f899b62d0cdcf852b75fe0960dfa34f300886 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 5 Jan 2012 12:38:53 -0800 Subject: [PATCH 0153/2771] Upgrade to Jetty 7.6.0.RC3. --- dropwizard-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index d394ba9f9fd..a19abbbf218 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -13,7 +13,7 @@ Dropwizard - 7.6.0.RC2 + 7.6.0.RC3 1.9.3 1.6.4 From c325a3125a741e3933644baadfa918a0ad453af4 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 7 Jan 2012 18:56:47 -0800 Subject: [PATCH 0154/2771] Upgrade to Metrics B19 final. --- pom.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 620094c152a..83758788c04 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ - 2.0.0-BETA19-SNAPSHOT + 2.0.0-BETA19 1.11 @@ -55,13 +55,13 @@ http://github.com/codahale/dropwizard/issues#issue/ - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - http://oss.sonatype.org/content/repositories/snapshots - - + + + + + + + From a2a19b6b13390e492a658568135fa1659b054f69 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 7 Jan 2012 18:57:59 -0800 Subject: [PATCH 0155/2771] Update version in docs. --- docs/getting-started.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.html b/docs/getting-started.html index a49990c2a82..ad916dad23d 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -188,7 +188,7 @@

      Setting Up Maven

      <dependency> <groupId>com.yammer.dropwizard</groupId> <artifactId>dropwizard-core</artifactId> - <version>0.1.1</version> + <version>0.1.2-SNAPSHOT</version> </dependency> </dependencies> From a3c95f29a7801e53ebe868692f160cc84479bea2 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 7 Jan 2012 18:58:16 -0800 Subject: [PATCH 0156/2771] Added documentation for Log. --- docs/manual.html | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/docs/manual.html b/docs/manual.html index 01763dc177c..0f138eabef9 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -60,6 +60,8 @@
      Dropwizard User’s Manual
    • Logging
        +
      • The Log class
      • +
      • Log Format
      • Console Logging
      • File Logging
      • Syslog Logging
      • @@ -467,6 +469,78 @@

        Logging

        routes all java.util.logging usage through log4j.

        +

        The Log class

        + +

        + Dropwizard comes with a Log convenience class, since most of the logging + APIs are horrendous. +

        + +
        +public class Example {
        +    private static final Log LOG = Log.forClass(Example.class);
        +
        +    public long fetchAge(long userId) {
        +        LOG.debug("Fetching age for user {}", userId);
        +
        +        try {
        +            final User user = users.find(userId);
        +            return user.getAge();
        +        } catch (IOException e) {
        +            LOG.error(e, "Error connecting to user store for user {}", userId);
        +        } catch (UserNotFoundException e) {
        +            LOG.warn(e, "Unable to fetch age for user {}", userId);
        +        }
        +    }
        +}
        + +

        + Log provides the same statement formatting amenities as SLF4J, so you can + pass arbitrary objects in without having to concatenate strings. Instances of + {} in the log message are replaced with the string representation of the + objects. To log exceptions, just pass the Throwable instance as the first + parameter and it'll log the exception type, message, and stack trace. +

        + +

        + The Log class also provides the following logging levels: +

        + +
        +
        FATAL
        +
        + Very severe error events that will presumably lead the application to abort. +
        + +
        ERROR
        +
        + Error events that might still allow the application to continue running. +
        + +
        WARN
        +
        + Potentially harmful situations. +
        + +
        INFO
        +
        + Informational messages that highlight the progress of the application at + coarse-grained level. +
        + +
        DEBUG
        +
        + Fine-grained informational events that are most useful to debug an application. +
        + +
        TRACE
        +
        + Finer-grained informational events than the DEBUG level. +
        +
        + +

        Log Format

        +

        Dropwizard’s log format has a few specific goals:

          From a75de914d48991ebfbab42c99c5f962f702167a2 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 7 Jan 2012 18:59:40 -0800 Subject: [PATCH 0157/2771] Updated changelog. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bf17bbc72f..6747cc8e8de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ v0.1.2: TBD * All Jersey resource methods annotated with `@Timed`, `@Metered`, or `@ExceptionMetered` are now instrumented via `metrics-jersey`. * Now licensed under Apache License 2.0. +* Upgraded to Jetty 7.6.0.RC3. +* Upgraded to Metrics 2.0.0-BETA19. +* Fixed logging in `ServerCommand`. +* Made `ServerCommand#run()` non-`final`. v0.1.1: Dec 28 2011 From 9e8917f81f2a740bd66dd6196eb46e86f3893c2e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 7 Jan 2012 19:02:42 -0800 Subject: [PATCH 0158/2771] [maven-release-plugin] prepare release v0.1.2 --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 005ae8862f9..0300056dadc 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2-SNAPSHOT + 0.1.2 com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index a19abbbf218..67bf3772049 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2-SNAPSHOT + 0.1.2 com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 0124571d100..cbdc5243aba 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2-SNAPSHOT + 0.1.2 com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index f240f118494..1b41026d0cf 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.1.2-SNAPSHOT + 0.1.2 Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 9ceb337ba26..4c487f5b21a 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2-SNAPSHOT + 0.1.2 com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 2239407afb8..700e2701b33 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2-SNAPSHOT + 0.1.2 com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 792c6156ac2..46d8b5c8c07 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2-SNAPSHOT + 0.1.2 com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 83758788c04..233af564e33 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2-SNAPSHOT + 0.1.2 pom Dropwizard Project http://dropwizard.codahale.com/ From d1b7c94e516e51f1b073f71e15969297d8de6801 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 7 Jan 2012 19:02:54 -0800 Subject: [PATCH 0159/2771] [maven-release-plugin] prepare for next development iteration --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 0300056dadc..7c87566a520 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2 + 0.1.3-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 67bf3772049..38682414fdb 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2 + 0.1.3-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index cbdc5243aba..1856503b9ab 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2 + 0.1.3-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 1b41026d0cf..0efb23b805c 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.1.2 + 0.1.3-SNAPSHOT Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 4c487f5b21a..6dfe7f92e40 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2 + 0.1.3-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 700e2701b33..fcc495f0ab1 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2 + 0.1.3-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 46d8b5c8c07..8185cc1d0d2 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2 + 0.1.3-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 233af564e33..9d0c32717c1 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.2 + 0.1.3-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From 5d6b178f68868d21982584cf497f3b27d8039cd5 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 7 Jan 2012 19:09:30 -0800 Subject: [PATCH 0160/2771] Update docs and changelogs for 0.1.2. --- CHANGELOG.md | 7 ++++++- docs/getting-started.html | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6747cc8e8de..ae1e0b842e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ -v0.1.2: TBD +v0.1.3: TBD +=================== + + + +v0.1.2: Jan 07 2012 =================== * All Jersey resource methods annotated with `@Timed`, `@Metered`, or `@ExceptionMetered` are now diff --git a/docs/getting-started.html b/docs/getting-started.html index ad916dad23d..7f66155920b 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -188,7 +188,7 @@

          Setting Up Maven

          <dependency> <groupId>com.yammer.dropwizard</groupId> <artifactId>dropwizard-core</artifactId> - <version>0.1.2-SNAPSHOT</version> + <version>0.1.2</version> </dependency> </dependencies> From 8a025677fd56a3a1692a5ac5e8a2f310d71517a2 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 9 Jan 2012 14:14:12 -0800 Subject: [PATCH 0161/2771] Upgraded to Guava 11.0.1. --- CHANGELOG.md | 2 +- dropwizard-core/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae1e0b842e3..399a418919a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ v0.1.3: TBD =================== - +* Upgraded to Guava 11.0.1. v0.1.2: Jan 07 2012 =================== diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 38682414fdb..9f41bd99dd5 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -107,7 +107,7 @@ com.google.guava guava - 11.0 + 11.0.1 org.hibernate From 9956e5074c5fc1ded2cacaaee1b942a1af33b119 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 9 Jan 2012 15:28:16 -0800 Subject: [PATCH 0162/2771] No really, fix ServerCommand logging. Fixes a dumb regression in 7f96a9683db110dccabbc89f901371be681f5efd. --- .../src/main/java/com/yammer/dropwizard/cli/ServerCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java index 70af298b531..311abb2d0c3 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java @@ -52,7 +52,7 @@ protected void run(AbstractService service, log.info("Starting {}", service.getName()); try { - log.info("{}\n", Resources.toString(Resources.getResource("banner.txt"), Charsets.UTF_8)); + log.info("\n{}", Resources.toString(Resources.getResource("banner.txt"), Charsets.UTF_8)); } catch (IllegalArgumentException ignored) { // don't display the banner if there isn't one } From d2af16f05130d202388b90214d53375091065d35 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 10 Jan 2012 21:51:37 -0800 Subject: [PATCH 0163/2771] Simplify encodings for Maven. --- pom.xml | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 9d0c32717c1..b2de171c86a 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,8 @@ + UTF-8 + UTF-8 2.0.0-BETA19 1.11 @@ -119,7 +121,6 @@ 1.6 1.6 - UTF-8 @@ -139,9 +140,6 @@ org.apache.maven.plugins maven-javadoc-plugin 2.8 - - UTF-8 - attach-javadocs @@ -151,15 +149,6 @@ - - org.apache.maven.plugins - maven-resources-plugin - 2.5 - - - UTF-8 - - org.apache.maven.plugins maven-release-plugin From 4360c96c2d9bede59babd37fe8bf0a31621180c1 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 10 Jan 2012 21:51:49 -0800 Subject: [PATCH 0164/2771] Use the instrumented Jetty connectors. --- .../yammer/dropwizard/config/ServerFactory.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index 1149255da6c..83d3a8755f5 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -10,14 +10,16 @@ import com.yammer.dropwizard.util.Size; import com.yammer.metrics.HealthChecks; import com.yammer.metrics.core.HealthCheck; +import com.yammer.metrics.jetty.InstrumentedBlockingChannelConnector; import com.yammer.metrics.jetty.InstrumentedHandler; +import com.yammer.metrics.jetty.InstrumentedSelectChannelConnector; +import com.yammer.metrics.jetty.InstrumentedSocketConnector; import com.yammer.metrics.reporting.MetricsServlet; import com.yammer.metrics.util.DeadlockHealthCheck; import org.eclipse.jetty.server.*; import org.eclipse.jetty.server.bio.SocketConnector; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.nio.AbstractNIOConnector; -import org.eclipse.jetty.server.nio.BlockingChannelConnector; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -93,7 +95,7 @@ private Server createServer() { } private Connector createExternalConnector() { - final AbstractConnector connector = createConnector(); + final AbstractConnector connector = createConnector(config.getPort()); connector.setHost(config.getBindHost().orNull()); @@ -134,17 +136,17 @@ private Connector createExternalConnector() { return connector; } - private AbstractConnector createConnector() { + private AbstractConnector createConnector(int port) { final AbstractConnector connector; switch (config.getConnectorType()) { case BLOCKING_CHANNEL: - connector = new BlockingChannelConnector(); + connector = new InstrumentedBlockingChannelConnector(port); break; case SOCKET: - connector = new SocketConnector(); + connector = new InstrumentedSocketConnector(port); break; case SELECT_CHANNEL: - connector = new SelectChannelConnector(); + connector = new InstrumentedSelectChannelConnector(port); ((SelectChannelConnector) connector).setLowResourcesConnections(config.getLowResourcesConnectionThreshold()); break; default: From 5e31cd71d9bfe0ee66129805f6e0c1e3617d48d9 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 11 Jan 2012 16:03:59 -0800 Subject: [PATCH 0165/2771] Override NonblockingServletHolder's equals and hashCode. --- .../dropwizard/jetty/NonblockingServletHolder.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java index 54eb6ebebe1..4b101f48e24 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java @@ -18,6 +18,18 @@ public NonblockingServletHolder(Servlet servlet) { this.servlet = servlet; } + @Override + public boolean equals(Object o) { + return (o instanceof NonblockingServletHolder) && (this.compareTo(o) == 0); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = (31 * result) + servlet.hashCode(); + return result; + } + @Override public Servlet getServlet() throws ServletException { return servlet; From bb7539f65299490769238ca54f97de4a7cb0ff52 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 11 Jan 2012 16:04:47 -0800 Subject: [PATCH 0166/2771] Add FindBugs to the build process. --- findbugs-exclude.xml | 36 ++++++++++++++++++++++++++++++++++++ pom.xml | 18 ++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 findbugs-exclude.xml diff --git a/findbugs-exclude.xml b/findbugs-exclude.xml new file mode 100644 index 00000000000..122cf8b0ed0 --- /dev/null +++ b/findbugs-exclude.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index b2de171c86a..90c7a40939a 100644 --- a/pom.xml +++ b/pom.xml @@ -160,6 +160,24 @@ clean test + + org.codehaus.mojo + findbugs-maven-plugin + 2.3.3 + + Max + Default + true + ${basedir}/../findbugs-exclude.xml + + + + + check + + + + org.apache.maven.plugins maven-site-plugin From bc6126054f0f29f737dd901d4c3f9a5aea9de595 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 11 Jan 2012 16:48:13 -0800 Subject: [PATCH 0167/2771] Fix the Maven site generation. --- pom.xml | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 90c7a40939a..a9bac455a04 100644 --- a/pom.xml +++ b/pom.xml @@ -183,14 +183,34 @@ maven-site-plugin 3.0 - + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.4 + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.8 + + + org.codehaus.mojo + findbugs-maven-plugin + 2.3.2 + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.8 + + http://codahale.com/checkstyle.xml + UTF-8 + + + - - org.apache.maven.plugins - maven-project-info-reports-plugin - 2.4 - From fbdb02b6590d80058d0db274e7637465f4814bdb Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 12 Jan 2012 14:46:21 -0800 Subject: [PATCH 0168/2771] Fix NonblockingServletHolder. --- .../com/yammer/dropwizard/jetty/NonblockingServletHolder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java index 4b101f48e24..d1f8ffd75d5 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jetty/NonblockingServletHolder.java @@ -26,7 +26,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = (31 * result) + servlet.hashCode(); + result = (31 * result) + ((servlet != null) ? servlet.hashCode() : 0); return result; } From a23a7f3788d836fe52445e5c70be1c3ede2e21dd Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 12 Jan 2012 15:24:00 -0800 Subject: [PATCH 0169/2771] Fix Scala exclusions. Lambdas, man. Lambdas. --- findbugs-exclude.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/findbugs-exclude.xml b/findbugs-exclude.xml index 122cf8b0ed0..929129c9d72 100644 --- a/findbugs-exclude.xml +++ b/findbugs-exclude.xml @@ -30,7 +30,7 @@ - - - + + + From 62fea0a423ace9bff03a25be09c3935a06c68bed Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 13 Jan 2012 23:01:45 -0800 Subject: [PATCH 0170/2771] Added ResourceTest. This required a little bit of refactoring of Environment and JavaBundle that I'm still mulling over. --- CHANGELOG.md | 2 + .../yammer/dropwizard/bundles/JavaBundle.java | 16 +- .../config/DropwizardResourceConfig.java | 15 ++ .../yammer/dropwizard/config/Environment.java | 160 +++++++++--------- dropwizard-testing/pom.xml | 5 + .../dropwizard/testing/ResourceTest.java | 54 ++++++ .../testing/tests/service/PeopleStore.java | 7 + .../testing/tests/service/PersonResource.java | 26 +++ .../tests/service/PersonResourceTest.java | 35 ++++ 9 files changed, 233 insertions(+), 87 deletions(-) create mode 100644 dropwizard-core/src/main/java/com/yammer/dropwizard/config/DropwizardResourceConfig.java create mode 100644 dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/ResourceTest.java create mode 100644 dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PeopleStore.java create mode 100644 dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PersonResource.java create mode 100644 dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PersonResourceTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 399a418919a..ab86a2262c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ v0.1.3: TBD =================== * Upgraded to Guava 11.0.1. +* Added `ResourceTest` to `dropwizard-testing`, which uses the Jersey Test Framework to provide + full testing of resources. v0.1.2: Jan 07 2012 =================== diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java index 8831b8ced29..3a2b0ffbb33 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java @@ -6,14 +6,24 @@ import com.yammer.dropwizard.jersey.OauthTokenProvider; import com.yammer.dropwizard.jersey.OptionalQueryParamInjectableProvider; +import java.util.List; + +import static java.util.Arrays.asList; + /** * Initializes the service with support for Java classes. */ public class JavaBundle implements Bundle { + public static final List DEFAULT_PROVIDERS = asList( + new OptionalQueryParamInjectableProvider(), + new JacksonMessageBodyProvider(), + new OauthTokenProvider() + ); + @Override public void initialize(Environment environment) { - environment.addProvider(new OptionalQueryParamInjectableProvider()); - environment.addProvider(new JacksonMessageBodyProvider()); - environment.addProvider(new OauthTokenProvider()); + for (Object provider : DEFAULT_PROVIDERS) { + environment.addProvider(provider); + } } } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/DropwizardResourceConfig.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/DropwizardResourceConfig.java new file mode 100644 index 00000000000..0f481dbd021 --- /dev/null +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/DropwizardResourceConfig.java @@ -0,0 +1,15 @@ +package com.yammer.dropwizard.config; + +import com.sun.jersey.api.core.DefaultResourceConfig; +import com.sun.jersey.api.core.ResourceConfig; +import com.yammer.dropwizard.jersey.LoggingExceptionMapper; +import com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchAdapter; + +public class DropwizardResourceConfig extends DefaultResourceConfig { + public DropwizardResourceConfig() { + super(); + getFeatures().put(ResourceConfig.FEATURE_DISABLE_WADL, Boolean.TRUE); + getSingletons().add(new LoggingExceptionMapper() { }); // create a subclass to pin it to Throwable + getClasses().add(InstrumentedResourceMethodDispatchAdapter.class); + } +} diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 159f49aa618..1338a84d65a 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -5,12 +5,10 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Ordering; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.sun.jersey.api.core.DefaultResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.core.reflection.AnnotatedMethod; import com.sun.jersey.core.reflection.MethodList; import com.sun.jersey.spi.container.servlet.ServletContainer; -import com.yammer.dropwizard.jersey.LoggingExceptionMapper; import com.yammer.dropwizard.jetty.JettyManaged; import com.yammer.dropwizard.jetty.NonblockingServletHolder; import com.yammer.dropwizard.lifecycle.ExecutorServiceManager; @@ -19,7 +17,6 @@ import com.yammer.dropwizard.tasks.GarbageCollectionTask; import com.yammer.dropwizard.tasks.Task; import com.yammer.metrics.core.HealthCheck; -import com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchAdapter; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.component.AbstractLifeCycle; @@ -62,16 +59,23 @@ public class Environment extends AbstractLifeCycle { * Creates a new environment. */ public Environment() { - this.config = new DropwizardResourceConfig(); + this.config = new DropwizardResourceConfig() { + @Override + public void validate() { + super.validate(); + logResources(); + logProviders(); + logHealthChecks(); + logManagedObjects(); + logEndpoints(); + } + }; this.healthChecks = ImmutableSet.builder(); this.servlets = ImmutableMap.builder(); this.filters = ImmutableMap.builder(); this.tasks = ImmutableSet.builder(); this.lifeCycle = new AggregateLifeCycle(); - enableJerseyFeature(ResourceConfig.FEATURE_DISABLE_WADL); - addProvider(new LoggingExceptionMapper() {}); // create a subclass to pin it to Throwable - addProvider(InstrumentedResourceMethodDispatchAdapter.class); addServlet(new ServletContainer(config), ROOT_PATH).setInitOrder(Integer.MAX_VALUE); addTask(new GarbageCollectionTask()); } @@ -334,107 +338,95 @@ ImmutableSet getTasks() { return tasks.build(); } - private class DropwizardResourceConfig extends DefaultResourceConfig { - @Override - public void validate() { - super.validate(); - logResources(); - logProviders(); - logHealthChecks(); - logManagedObjects(); - logEndpoints(); - } - - private void logManagedObjects() { - final ImmutableSet.Builder builder = ImmutableSet.builder(); - for (Object bean : lifeCycle.getBeans()) { - builder.add(bean.getClass().getCanonicalName()); - } - LOG.debug("managed objects = {}", builder.build()); + private void logManagedObjects() { + final ImmutableSet.Builder builder = ImmutableSet.builder(); + for (Object bean : lifeCycle.getBeans()) { + builder.add(bean.getClass().getCanonicalName()); } + LOG.debug("managed objects = {}", builder.build()); + } - private void logHealthChecks() { - final ImmutableSet.Builder builder = ImmutableSet.builder(); - for (HealthCheck healthCheck : healthChecks.build()) { - builder.add(healthCheck.getClass().getCanonicalName()); - } - LOG.debug("health checks = {}", builder.build()); + private void logHealthChecks() { + final ImmutableSet.Builder builder = ImmutableSet.builder(); + for (HealthCheck healthCheck : healthChecks.build()) { + builder.add(healthCheck.getClass().getCanonicalName()); } + LOG.debug("health checks = {}", builder.build()); + } - private void logResources() { - final ImmutableSet.Builder builder = ImmutableSet.builder(); + private void logResources() { + final ImmutableSet.Builder builder = ImmutableSet.builder(); - for (Class klass : config.getClasses()) { - if (klass.isAnnotationPresent(Path.class)) { - builder.add(klass.getCanonicalName()); - } + for (Class klass : config.getClasses()) { + if (klass.isAnnotationPresent(Path.class)) { + builder.add(klass.getCanonicalName()); } + } - for (Object o : config.getSingletons()) { - if (o.getClass().isAnnotationPresent(Path.class)) { - builder.add(o.getClass().getCanonicalName()); - } + for (Object o : config.getSingletons()) { + if (o.getClass().isAnnotationPresent(Path.class)) { + builder.add(o.getClass().getCanonicalName()); } - - LOG.debug("resources = {}", builder.build()); } - private void logProviders() { - final ImmutableSet.Builder builder = ImmutableSet.builder(); + LOG.debug("resources = {}", builder.build()); + } - for (Class klass : config.getClasses()) { - if (klass.isAnnotationPresent(Provider.class)) { - builder.add(klass.getCanonicalName()); - } - } + private void logProviders() { + final ImmutableSet.Builder builder = ImmutableSet.builder(); - for (Object o : config.getSingletons()) { - if (o.getClass().isAnnotationPresent(Provider.class)) { - builder.add(o.getClass().getCanonicalName()); - } + for (Class klass : config.getClasses()) { + if (klass.isAnnotationPresent(Provider.class)) { + builder.add(klass.getCanonicalName()); } + } - LOG.debug("providers = {}", builder.build()); + for (Object o : config.getSingletons()) { + if (o.getClass().isAnnotationPresent(Provider.class)) { + builder.add(o.getClass().getCanonicalName()); + } } - private void logEndpoints() { - final StringBuilder stringBuilder = new StringBuilder(1024).append("\n\n"); + LOG.debug("providers = {}", builder.build()); + } - final ImmutableList.Builder> builder = ImmutableList.builder(); - for (Object o : config.getSingletons()) { - if (o.getClass().isAnnotationPresent(Path.class)) { - builder.add(o.getClass()); - } + private void logEndpoints() { + final StringBuilder stringBuilder = new StringBuilder(1024).append("\n\n"); + + final ImmutableList.Builder> builder = ImmutableList.builder(); + for (Object o : config.getSingletons()) { + if (o.getClass().isAnnotationPresent(Path.class)) { + builder.add(o.getClass()); } - for (Class klass : config.getClasses()) { - if (klass.isAnnotationPresent(Path.class)) { - builder.add(klass); - } + } + for (Class klass : config.getClasses()) { + if (klass.isAnnotationPresent(Path.class)) { + builder.add(klass); } + } - for (Class klass : builder.build()) { - final String path = klass.getAnnotation(Path.class).value(); - final ImmutableList.Builder endpoints = ImmutableList.builder(); - for (AnnotatedMethod method : annotatedMethods(klass)) { - for (HttpMethod verb : method.getMetaMethodAnnotations(HttpMethod.class)) { - endpoints.add(String.format(" %-7s %s (%s)", - verb.value(), - path, - klass.getCanonicalName())); - } - } - - for (String line : Ordering.natural() - .sortedCopy(endpoints.build())) { - stringBuilder.append(line).append('\n'); + for (Class klass : builder.build()) { + final String path = klass.getAnnotation(Path.class).value(); + final ImmutableList.Builder endpoints = ImmutableList.builder(); + for (AnnotatedMethod method : annotatedMethods(klass)) { + for (HttpMethod verb : method.getMetaMethodAnnotations(HttpMethod.class)) { + endpoints.add(String.format(" %-7s %s (%s)", + verb.value(), + path, + klass.getCanonicalName())); } } - LOG.info(stringBuilder.toString()); + for (String line : Ordering.natural() + .sortedCopy(endpoints.build())) { + stringBuilder.append(line).append('\n'); + } } - private MethodList annotatedMethods(Class resource) { - return new MethodList(resource, true).hasMetaAnnotation(HttpMethod.class); - } + LOG.info(stringBuilder.toString()); + } + + private MethodList annotatedMethods(Class resource) { + return new MethodList(resource, true).hasMetaAnnotation(HttpMethod.class); } } diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 8185cc1d0d2..876922fdd62 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -18,6 +18,11 @@ dropwizard-core ${project.version} + + com.sun.jersey.jersey-test-framework + jersey-test-framework-inmemory + ${jersey.version} + junit junit diff --git a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/ResourceTest.java b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/ResourceTest.java new file mode 100644 index 00000000000..4b07bce2f4f --- /dev/null +++ b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/ResourceTest.java @@ -0,0 +1,54 @@ +package com.yammer.dropwizard.testing; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.test.framework.AppDescriptor; +import com.sun.jersey.test.framework.JerseyTest; +import com.sun.jersey.test.framework.LowLevelAppDescriptor; +import com.yammer.dropwizard.bundles.JavaBundle; +import com.yammer.dropwizard.config.DropwizardResourceConfig; +import org.junit.After; +import org.junit.Before; + +import java.util.HashSet; +import java.util.Set; + +/** + * A base test class for testing Dropwizard resources. + */ +public abstract class ResourceTest { + private final Set singletons = new HashSet(10); + + private JerseyTest test; + + protected abstract void setUpResources() throws Exception; + + protected void addResource(Object resource) { + singletons.add(resource); + } + + protected Client client() { + return test.client(); + } + + @Before + public void setUpJersey() throws Exception { + setUpResources(); + this.test = new JerseyTest() { + @Override + protected AppDescriptor configure() { + final DropwizardResourceConfig config = new DropwizardResourceConfig(); + for (Object provider : JavaBundle.DEFAULT_PROVIDERS) { // sorry, Scala folks + config.getSingletons().add(provider); + } + config.getSingletons().addAll(singletons); + return new LowLevelAppDescriptor.Builder(config).build(); + } + }; + test.setUp(); + } + + @After + public void tearDownJersey() throws Exception { + test.tearDown(); + } +} diff --git a/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PeopleStore.java b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PeopleStore.java new file mode 100644 index 00000000000..b40575b6cda --- /dev/null +++ b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PeopleStore.java @@ -0,0 +1,7 @@ +package com.yammer.dropwizard.testing.tests.service; + +import com.yammer.dropwizard.testing.tests.Person; + +public interface PeopleStore { + Person fetchPerson(String name); +} diff --git a/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PersonResource.java b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PersonResource.java new file mode 100644 index 00000000000..fdd01f9b081 --- /dev/null +++ b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PersonResource.java @@ -0,0 +1,26 @@ +package com.yammer.dropwizard.testing.tests.service; + +import com.yammer.dropwizard.testing.tests.Person; +import com.yammer.metrics.annotation.Timed; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("/person/{name}") +@Produces(MediaType.APPLICATION_JSON) +public class PersonResource { + private final PeopleStore store; + + public PersonResource(PeopleStore store) { + this.store = store; + } + + @GET + @Timed + public Person getPerson(@PathParam("name") String name) { + return store.fetchPerson(name); + } +} diff --git a/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PersonResourceTest.java b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PersonResourceTest.java new file mode 100644 index 00000000000..558a0cdb0d5 --- /dev/null +++ b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/service/PersonResourceTest.java @@ -0,0 +1,35 @@ +package com.yammer.dropwizard.testing.tests.service; + +import com.yammer.dropwizard.testing.ResourceTest; +import com.yammer.dropwizard.testing.tests.Person; +import org.junit.Test; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PersonResourceTest extends ResourceTest { + static { + Logger.getLogger("com.sun.jersey").setLevel(Level.OFF); + } + + private final Person person = new Person("blah", "blah@example.com"); + private final PeopleStore store = mock(PeopleStore.class); + + @Override + protected void setUpResources() { + when(store.fetchPerson(anyString())).thenReturn(person); + addResource(new PersonResource(store)); + } + + @Test + public void simpleResourceTest() throws Exception { + assertThat(client().resource("/person/blah").get(Person.class), + is(person)); + } +} From b83aee30f3fd3e316c1ad746446c4533d27fc637 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 13 Jan 2012 23:04:42 -0800 Subject: [PATCH 0171/2771] Updated the changelog with some other stuff. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab86a2262c4..819e5cd3cf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ v0.1.3: TBD =================== * Upgraded to Guava 11.0.1. +* Fixed logging in `ServerCommand`. For the last time. +* Switched to using the instrumented connectors from `metrics-jetty`. This allows for much + lower-level metrics about your service, including whether or not your thread pools are overloaded. +* Added FindBugs to the build process. * Added `ResourceTest` to `dropwizard-testing`, which uses the Jersey Test Framework to provide full testing of resources. From a9d0701a68e54895878060c256b6f6c1ff15b097 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 13 Jan 2012 23:34:19 -0800 Subject: [PATCH 0172/2771] Upgraded to Jetty 7.6.0.RC4. --- CHANGELOG.md | 1 + dropwizard-core/pom.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 819e5cd3cf9..c249c436486 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ v0.1.3: TBD * Added FindBugs to the build process. * Added `ResourceTest` to `dropwizard-testing`, which uses the Jersey Test Framework to provide full testing of resources. +* Upgraded to Jetty 7.6.0.RC4. v0.1.2: Jan 07 2012 =================== diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 9f41bd99dd5..1ce324b2616 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -13,7 +13,7 @@ Dropwizard - 7.6.0.RC3 + 7.6.0.RC4 1.9.3 1.6.4 From edfe4a1aa57ec0ae80df0a183fc5dd47b4a04c02 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 13 Jan 2012 23:40:39 -0800 Subject: [PATCH 0173/2771] Start tracking Metrics 2.0.0-RC0-SNAPSHOT. --- .../yammer/dropwizard/config/LoggingFactory.java | 7 ++----- pom.xml | 16 ++++++++-------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingFactory.java index 29a428f05d3..62ae63d1cc2 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingFactory.java @@ -5,7 +5,6 @@ import com.yammer.metrics.log4j.InstrumentedAppender; import org.apache.log4j.*; import org.apache.log4j.net.SyslogAppender; -import org.apache.log4j.varia.NullAppender; import org.slf4j.bridge.SLF4JBridgeHandler; import javax.management.MBeanServer; @@ -13,9 +12,7 @@ import java.lang.management.ManagementFactory; import java.util.Map; -import static com.yammer.dropwizard.config.LoggingConfiguration.ConsoleConfiguration; -import static com.yammer.dropwizard.config.LoggingConfiguration.FileConfiguration; -import static com.yammer.dropwizard.config.LoggingConfiguration.SyslogConfiguration; +import static com.yammer.dropwizard.config.LoggingConfiguration.*; // TODO: 11/7/11 -- document LoggingFactory // TODO: 11/7/11 -- test LoggingFactory @@ -54,7 +51,7 @@ public void configure() { } // add in an instrumented null appender to get full logging stats - LogManager.getRootLogger().addAppender(new InstrumentedAppender(new NullAppender())); + LogManager.getRootLogger().addAppender(new InstrumentedAppender()); } private void hijackJDKLogging() { diff --git a/pom.xml b/pom.xml index a9bac455a04..e1513335fef 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ UTF-8 UTF-8 - 2.0.0-BETA19 + 2.0.0-RC0-SNAPSHOT 1.11 @@ -57,13 +57,13 @@ http://github.com/codahale/dropwizard/issues#issue/ - - - - - - - + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + http://oss.sonatype.org/content/repositories/snapshots + + From 85411f64d69f9786fdd029ad5a0de49f150c0b4d Mon Sep 17 00:00:00 2001 From: Brian ONeill Date: Wed, 18 Jan 2012 15:43:06 -0500 Subject: [PATCH 0174/2771] Update to AssetBundle to allow user to specify the urlPath where they want the resources available. --- .../dropwizard/bundles/AssetsBundle.java | 49 +++++++++++++++---- .../dropwizard/servlets/AssetServlet.java | 26 +++++----- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java index 14b0c404486..3a19878adce 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java @@ -13,7 +13,8 @@ public class AssetsBundle implements Bundle { public static final String DEFAULT_PATH = "/assets"; public static final int DEFAULT_MAX_CACHE_SIZE = 100; - private final String path; + private final String resourcePath; + private final String uriPath; private final int maxCacheSize; /** @@ -36,7 +37,21 @@ public AssetsBundle() { * @see AssetsBundle#AssetsBundle(String, int) */ public AssetsBundle(String path) { - this(path, DEFAULT_MAX_CACHE_SIZE); + this(path, DEFAULT_MAX_CACHE_SIZE, path); + } + + /** + * Creates a new {@link AssetsBundle} which will configure the service to serve the static files + * located in {@code src/main/resources/${resourcePath}} as {@code /${uriPath}}. For example, given a + * {@code resourcePath} of {@code "/assets"} and a uriPath of {@code "/js"}, + * {@code src/main/resources/assets/example.js} would be served up from {@code /js/example.js}. + * + * @param resourcePath the resource path (in the classpath) of the static asset files + * @param uriPath the uri path for the static asset files + * @see AssetsBundle#AssetsBundle(String, int) + */ + public AssetsBundle(String resourcePath, String uriPath) { + this(resourcePath, DEFAULT_MAX_CACHE_SIZE, uriPath); } /** @@ -45,20 +60,34 @@ public AssetsBundle(String path) { * {@code path} of {@code "/assets"}, {@code src/main/resources/assets/example.js} would be * served up from {@code /assets/example.js}. * - * @param path the classpath and URI root of the static asset files + * @param resourcePath the resource path (in the classpath) of the static asset files * @param maxCacheSize the maximum number of resources to cache + * @param uriPath the uri path for the static asset files */ - public AssetsBundle(String path, int maxCacheSize) { - checkArgument(path.startsWith("/"), "%s is not an absolute path", path); - checkArgument(!"/".equals(path), "%s is the classpath root"); - this.path = path.endsWith("/") ? path : (path + '/'); - this.maxCacheSize = maxCacheSize; + public AssetsBundle(String resourcePath, int maxCacheSize) { + this(resourcePath, maxCacheSize, resourcePath); } - + /** + * Creates a new {@link AssetsBundle} which will configure the service to serve the static files + * located in {@code src/main/resources/${resourcePath}} as {@code /${uriPath}}. For example, given a + * {@code resourcePath} of {@code "/assets"} and a uriPath of {@code "/js"}, + * {@code src/main/resources/assets/example.js} would be served up from {@code /js/example.js}. + * + * @param resourcePath the resource path (in the classpath) of the static asset files + * @param maxCacheSize the maximum number of resources to cache + * @param uriPath the uri path for the static asset files + */ + public AssetsBundle(String resourcePath, int maxCacheSize, String uriPath) { + checkArgument(resourcePath.startsWith("/"), "%s is not an absolute path", resourcePath); + checkArgument(!"/".equals(resourcePath), "%s is the classpath root"); + this.resourcePath = resourcePath.endsWith("/") ? resourcePath : (resourcePath + '/'); + this.uriPath = uriPath.endsWith("/") ? uriPath : (uriPath + '/'); + this.maxCacheSize = maxCacheSize; + } @Override public void initialize(Environment environment) { - environment.addServlet(new AssetServlet(path, maxCacheSize), path + '*'); + environment.addServlet(new AssetServlet(resourcePath, maxCacheSize, uriPath), uriPath + '*'); } } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java index 943d6873f33..51091e5cfae 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java @@ -18,35 +18,35 @@ public class AssetServlet extends HttpServlet { private static final long serialVersionUID = 6393345594784987908L; private static class AssetLoader extends CacheLoader { - private final String base; + private final String resourcePath; + private final String uriPath; - private AssetLoader(String base) { - this.base = base; + private AssetLoader(String resourcePath, String uriPath) { + this.resourcePath = resourcePath; + this.uriPath = uriPath; } @Override public byte[] load(String key) throws Exception { - final String path = URIUtil.canonicalPath(key); - if (path.startsWith(base)) { - return Resources.toByteArray(Resources.getResource(path.substring(1))); - } else { - throw new RuntimeException("nope"); - } + final String resource = key.substring(uriPath.length()); + String fullResourcePath = this.resourcePath + resource; + + return Resources.toByteArray(Resources.getResource(fullResourcePath.substring(1))); } } private final transient LoadingCache cache; private final transient MimeTypes mimeTypes; - public AssetServlet(String base, int maxCacheSize) { - this.cache = buildCache(base, maxCacheSize); + public AssetServlet(String resourcePath, int maxCacheSize, String uriPath) { + this.cache = buildCache(resourcePath, maxCacheSize, uriPath); this.mimeTypes = new MimeTypes(); } - private static LoadingCache buildCache(String base, int maxCacheSize) { + private static LoadingCache buildCache(String resourecePath, int maxCacheSize, String uriPath) { return CacheBuilder.newBuilder() .maximumSize(maxCacheSize) - .build(new AssetLoader(base)); + .build(new AssetLoader(resourecePath, uriPath)); } @Override From 99332c6b0db0546a751ad4cd3c6662c366a3a28c Mon Sep 17 00:00:00 2001 From: Brian ONeill Date: Wed, 18 Jan 2012 15:55:52 -0500 Subject: [PATCH 0175/2771] Added ability to move the REST services to a different url (off of the root). Introduced a new parameter to the yamnl file, rootPath. For example, if set to "/services/*", all JAX-RS classes will be available down from that url. --- .../com/yammer/dropwizard/cli/ManagedCommand.java | 2 +- .../java/com/yammer/dropwizard/cli/ServerCommand.java | 2 +- .../com/yammer/dropwizard/config/Environment.java | 5 ++--- .../yammer/dropwizard/config/HttpConfiguration.java | 11 +++++++++++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java index 4723654e267..e54cd96732a 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java @@ -20,7 +20,7 @@ protected final void run(AbstractService service, T configuration, CommandLine params) throws Exception { new LoggingFactory(configuration.getLoggingConfiguration()).configure(); - final Environment environment = new Environment(); + final Environment environment = new Environment(configuration); service.initializeWithBundles(configuration, environment); LOG.info("Starting {}", service.getName()); environment.start(); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java index 311abb2d0c3..f258356b270 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java @@ -43,7 +43,7 @@ protected Class getConfigurationClass() { protected void run(AbstractService service, T configuration, CommandLine params) throws Exception { - final Environment environment = new Environment(); + final Environment environment = new Environment(configuration); service.initializeWithBundles(configuration, environment); final Server server = new ServerFactory(configuration.getHttpConfiguration()).buildServer(environment); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 1338a84d65a..2a3468787d0 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -46,7 +46,6 @@ */ public class Environment extends AbstractLifeCycle { private static final Log LOG = Log.forClass(Environment.class); - private static final String ROOT_PATH = "/*"; private final ResourceConfig config; private final ImmutableSet.Builder healthChecks; @@ -58,7 +57,7 @@ public class Environment extends AbstractLifeCycle { /** * Creates a new environment. */ - public Environment() { + public Environment(Configuration configuration) { this.config = new DropwizardResourceConfig() { @Override public void validate() { @@ -76,7 +75,7 @@ public void validate() { this.tasks = ImmutableSet.builder(); this.lifeCycle = new AggregateLifeCycle(); - addServlet(new ServletContainer(config), ROOT_PATH).setInitOrder(Integer.MAX_VALUE); + addServlet(new ServletContainer(config), configuration.getHttpConfiguration().getRootPath()).setInitOrder(Integer.MAX_VALUE); addTask(new GarbageCollectionTask()); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 874d5c2c2b2..bafae14245f 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -104,6 +104,9 @@ public enum ConnectorType { @Max(20000) private int minThreads = 10; + @NotNull + private String rootPath = "/*"; + @NotNull @Pattern(regexp = "(blocking|nonblocking|legacy)", flags = {Pattern.Flag.CASE_INSENSITIVE}) @@ -272,4 +275,12 @@ public boolean isDateHeaderEnabled() { public boolean isServerHeaderEnabled() { return useServerHeader; } + + public String getRootPath() { + return rootPath; + } + + public void setRootPath(String rootPath) { + this.rootPath = rootPath; + } } From 0035291bd2a67674ac447e288f2a91e45efd55c0 Mon Sep 17 00:00:00 2001 From: Brian ONeill Date: Wed, 18 Jan 2012 16:12:41 -0500 Subject: [PATCH 0176/2771] Ability to serve up a default html file from the root of the uri/resource path. Presently it is hardcoded to serve up "index.htm", we should make that configurable. Also needed to set a default mimetype when it can't find one. --- .../dropwizard/servlets/AssetServlet.java | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java index 51091e5cfae..9f72ad4daea 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java @@ -1,18 +1,20 @@ package com.yammer.dropwizard.servlets; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.io.Resources; -import org.eclipse.jetty.http.MimeTypes; -import org.eclipse.jetty.util.URIUtil; +import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; + +import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.io.Buffer; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.io.Resources; public class AssetServlet extends HttpServlet { private static final long serialVersionUID = 6393345594784987908L; @@ -20,7 +22,8 @@ public class AssetServlet extends HttpServlet { private static class AssetLoader extends CacheLoader { private final String resourcePath; private final String uriPath; - + private final static String INDEX_FILENAME = "index.htm"; // TODO: Make this configurable. + private AssetLoader(String resourcePath, String uriPath) { this.resourcePath = resourcePath; this.uriPath = uriPath; @@ -30,13 +33,16 @@ private AssetLoader(String resourcePath, String uriPath) { public byte[] load(String key) throws Exception { final String resource = key.substring(uriPath.length()); String fullResourcePath = this.resourcePath + resource; - - return Resources.toByteArray(Resources.getResource(fullResourcePath.substring(1))); + if (key.equals(this.uriPath)) { + fullResourcePath = resourcePath + INDEX_FILENAME; + } + return Resources.toByteArray(Resources.getResource(fullResourcePath.substring(1))); } } private final transient LoadingCache cache; private final transient MimeTypes mimeTypes; + private final static String DEFAULT_MIME_TYPE = "text/html"; public AssetServlet(String resourcePath, int maxCacheSize, String uriPath) { this.cache = buildCache(resourcePath, maxCacheSize, uriPath); @@ -54,7 +60,12 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { final byte[] resource = cache.getUnchecked(req.getRequestURI()); - resp.setContentType(mimeTypes.getMimeByExtension(req.getRequestURI()).toString()); + Buffer mimeType = mimeTypes.getMimeByExtension(req.getRequestURI()); + if (mimeType == null) { + resp.setContentType(DEFAULT_MIME_TYPE); + } else { + resp.setContentType(mimeType.toString()); + } final ServletOutputStream output = resp.getOutputStream(); try { output.write(resource); From a0d263e68a5ec187e66d52144453ea638a8e5c60 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 18 Jan 2012 14:52:58 -0800 Subject: [PATCH 0177/2771] Fix a Javadoc issue in AssetsBundle. --- .../main/java/com/yammer/dropwizard/bundles/AssetsBundle.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java index 3a19878adce..790fdf7e724 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/AssetsBundle.java @@ -62,7 +62,6 @@ public AssetsBundle(String resourcePath, String uriPath) { * * @param resourcePath the resource path (in the classpath) of the static asset files * @param maxCacheSize the maximum number of resources to cache - * @param uriPath the uri path for the static asset files */ public AssetsBundle(String resourcePath, int maxCacheSize) { this(resourcePath, maxCacheSize, resourcePath); From c7c58e3ddb5dec3b9103820b69fbc18dc54ed15d Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 18 Jan 2012 14:54:09 -0800 Subject: [PATCH 0178/2771] Fix a Javadoc issue in Environment. --- .../src/main/java/com/yammer/dropwizard/config/Environment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 2a3468787d0..d06daf9597c 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -56,6 +56,8 @@ public class Environment extends AbstractLifeCycle { /** * Creates a new environment. + * + * @param configuration the service's {@link Configuration} */ public Environment(Configuration configuration) { this.config = new DropwizardResourceConfig() { From e0c878c3e3bcacd6d9864bf89a61bc2ebc36b8f0 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 18 Jan 2012 14:54:36 -0800 Subject: [PATCH 0179/2771] Remove unused setter from HttpConfiguration. --- .../java/com/yammer/dropwizard/config/HttpConfiguration.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index bafae14245f..1dc6122c2bd 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -279,8 +279,4 @@ public boolean isServerHeaderEnabled() { public String getRootPath() { return rootPath; } - - public void setRootPath(String rootPath) { - this.rootPath = rootPath; - } } From d7a88fe930f3c6ae0706b523032b1e1d5d54142c Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 18 Jan 2012 14:55:21 -0800 Subject: [PATCH 0180/2771] Style fixes for AssetServlet. --- .../dropwizard/servlets/AssetServlet.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java index 9f72ad4daea..39b9ba97e9e 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/servlets/AssetServlet.java @@ -1,29 +1,28 @@ package com.yammer.dropwizard.servlets; -import java.io.IOException; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.io.Resources; +import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.io.Buffer; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.MimeTypes; -import org.eclipse.jetty.io.Buffer; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.io.Resources; +import java.io.IOException; public class AssetServlet extends HttpServlet { private static final long serialVersionUID = 6393345594784987908L; private static class AssetLoader extends CacheLoader { + private static final String INDEX_FILENAME = "index.htm"; // TODO: Make this configurable. + private final String resourcePath; private final String uriPath; - private final static String INDEX_FILENAME = "index.htm"; // TODO: Make this configurable. - + private AssetLoader(String resourcePath, String uriPath) { this.resourcePath = resourcePath; this.uriPath = uriPath; @@ -39,20 +38,21 @@ public byte[] load(String key) throws Exception { return Resources.toByteArray(Resources.getResource(fullResourcePath.substring(1))); } } - + + private static final String DEFAULT_MIME_TYPE = "text/html"; + private final transient LoadingCache cache; private final transient MimeTypes mimeTypes; - private final static String DEFAULT_MIME_TYPE = "text/html"; public AssetServlet(String resourcePath, int maxCacheSize, String uriPath) { this.cache = buildCache(resourcePath, maxCacheSize, uriPath); this.mimeTypes = new MimeTypes(); } - private static LoadingCache buildCache(String resourecePath, int maxCacheSize, String uriPath) { + private static LoadingCache buildCache(String resourcePath, int maxCacheSize, String uriPath) { return CacheBuilder.newBuilder() .maximumSize(maxCacheSize) - .build(new AssetLoader(resourecePath, uriPath)); + .build(new AssetLoader(resourcePath, uriPath)); } @Override @@ -60,7 +60,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { final byte[] resource = cache.getUnchecked(req.getRequestURI()); - Buffer mimeType = mimeTypes.getMimeByExtension(req.getRequestURI()); + final Buffer mimeType = mimeTypes.getMimeByExtension(req.getRequestURI()); if (mimeType == null) { resp.setContentType(DEFAULT_MIME_TYPE); } else { From ab77b8f71aa6ba7035f38fc52104f16a60e57120 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 18 Jan 2012 15:04:32 -0800 Subject: [PATCH 0181/2771] Updated the changelog. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c249c436486..bd98557efa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ v0.1.3: TBD * Added `ResourceTest` to `dropwizard-testing`, which uses the Jersey Test Framework to provide full testing of resources. * Upgraded to Jetty 7.6.0.RC4. +* Decoupled URIs and resource paths in `AssetServlet` and `AssetsBundle`. +* Added `rootPath` to `Configuration`. It allows you to serve Jersey assets off a specific path + (e.g., `/resources/*` vs `/*`). +* `AssetServlet` now looks for `index.htm` when handling requests for the root URI. + v0.1.2: Jan 07 2012 =================== From f353c6d016a2c2893c686220e5bd8313eed84d1a Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 19 Jan 2012 10:32:38 -0800 Subject: [PATCH 0182/2771] Use AdminServlet instead of MetricsServlet. --- .../main/java/com/yammer/dropwizard/config/ServerFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index 83d3a8755f5..ec39eaaca18 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -14,7 +14,7 @@ import com.yammer.metrics.jetty.InstrumentedHandler; import com.yammer.metrics.jetty.InstrumentedSelectChannelConnector; import com.yammer.metrics.jetty.InstrumentedSocketConnector; -import com.yammer.metrics.reporting.MetricsServlet; +import com.yammer.metrics.reporting.AdminServlet; import com.yammer.metrics.util.DeadlockHealthCheck; import org.eclipse.jetty.server.*; import org.eclipse.jetty.server.bio.SocketConnector; @@ -177,7 +177,7 @@ private Handler createHandler(Environment env) { private static Handler createInternalServlet(Environment env) { final ServletContextHandler handler = new ServletContextHandler(); handler.addServlet(new ServletHolder(new TaskServlet(env.getTasks())), "/tasks/*"); - handler.addServlet(new ServletHolder(new MetricsServlet()), "/*"); + handler.addServlet(new ServletHolder(new AdminServlet()), "/*"); handler.setConnectorNames(new String[]{"internal"}); return handler; } From 19c5fcf83fb5949918a4a1a147b240739e72ef47 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 19 Jan 2012 14:00:23 -0800 Subject: [PATCH 0183/2771] Upgraded to Metrics 2.0.0-RC0. --- CHANGELOG.md | 1 + pom.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd98557efa0..0a1e46e16ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ v0.1.3: TBD * Added `rootPath` to `Configuration`. It allows you to serve Jersey assets off a specific path (e.g., `/resources/*` vs `/*`). * `AssetServlet` now looks for `index.htm` when handling requests for the root URI. +* Upgraded to Metrics 2.0.0-RC0. v0.1.2: Jan 07 2012 diff --git a/pom.xml b/pom.xml index e1513335fef..8ebc9331be6 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ UTF-8 UTF-8 - 2.0.0-RC0-SNAPSHOT + 2.0.0-RC0 1.11 From 7fa15b84aa2dfca6b8cd91314e669c4a64be023d Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 19 Jan 2012 14:03:49 -0800 Subject: [PATCH 0184/2771] [maven-release-plugin] prepare release v0.1.3 --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 7c87566a520..b4c2d0af8e2 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3-SNAPSHOT + 0.1.3 com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 1ce324b2616..f6dc5729037 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3-SNAPSHOT + 0.1.3 com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 1856503b9ab..e13583354b7 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3-SNAPSHOT + 0.1.3 com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 0efb23b805c..1602d6ce4c1 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.1.3-SNAPSHOT + 0.1.3 Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 6dfe7f92e40..f3dc53dfc9f 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3-SNAPSHOT + 0.1.3 com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index fcc495f0ab1..b7c72b28d99 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3-SNAPSHOT + 0.1.3 com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 876922fdd62..5027e6ad4de 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3-SNAPSHOT + 0.1.3 com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 8ebc9331be6..5b79cdaae13 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3-SNAPSHOT + 0.1.3 pom Dropwizard Project http://dropwizard.codahale.com/ From a089f26e38687d35109ac894d151e0e835937eca Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 19 Jan 2012 14:03:58 -0800 Subject: [PATCH 0185/2771] [maven-release-plugin] prepare for next development iteration --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index b4c2d0af8e2..20b2acd00fc 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3 + 0.1.4-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index f6dc5729037..2440c401157 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3 + 0.1.4-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index e13583354b7..d16abef6efb 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3 + 0.1.4-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 1602d6ce4c1..cadbb9e8d89 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.1.3 + 0.1.4-SNAPSHOT Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index f3dc53dfc9f..bcb44c95103 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3 + 0.1.4-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index b7c72b28d99..d4f0b08c038 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3 + 0.1.4-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 5027e6ad4de..d5de97deb7c 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3 + 0.1.4-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 5b79cdaae13..3ea842f07e9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.3 + 0.1.4-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From 7edacd0c580518c24e22edef9bfb31912e9de310 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 19 Jan 2012 14:18:10 -0800 Subject: [PATCH 0186/2771] Updated changelog and docs. --- CHANGELOG.md | 2 +- docs/getting-started.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a1e46e16ad..396bb4fd41d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -v0.1.3: TBD +v0.1.3: Jan 19 2012 =================== * Upgraded to Guava 11.0.1. diff --git a/docs/getting-started.html b/docs/getting-started.html index 7f66155920b..24c8ce8275c 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -188,7 +188,7 @@

          Setting Up Maven

          <dependency> <groupId>com.yammer.dropwizard</groupId> <artifactId>dropwizard-core</artifactId> - <version>0.1.2</version> + <version>0.1.3</version> </dependency> </dependencies> From d358be05ab16cc13668661d21fef4e16109f8684 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 19 Jan 2012 17:57:33 -0800 Subject: [PATCH 0187/2771] Switched to using jackson-datatype-guava. --- CHANGELOG.md | 6 + dropwizard-core/pom.xml | 5 + .../module/guava/GuavaDeserializers.java | 174 ------------------ .../jackson/module/guava/GuavaModule.java | 28 --- .../module/guava/GuavaSerializers.java | 19 -- .../deser/GuavaCollectionDeserializer.java | 76 -------- .../guava/deser/GuavaMapDeserializer.java | 89 --------- .../guava/deser/HashMultisetDeserializer.java | 46 ----- .../deser/ImmutableListDeserializer.java | 47 ----- .../guava/deser/ImmutableMapDeserializer.java | 54 ------ .../guava/deser/ImmutableSetDeserializer.java | 47 ----- .../deser/ImmutableSortedSetDeserializer.java | 53 ------ .../guava/deser/OptionalDeserializer.java | 38 ---- .../module/guava/ser/OptionalSerializer.java | 23 --- .../java/com/yammer/dropwizard/json/Json.java | 2 +- findbugs-exclude.xml | 3 - 16 files changed, 12 insertions(+), 698 deletions(-) delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaDeserializers.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaModule.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaSerializers.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaCollectionDeserializer.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaMapDeserializer.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/HashMultisetDeserializer.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableListDeserializer.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableMapDeserializer.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSetDeserializer.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSortedSetDeserializer.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java delete mode 100644 dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 396bb4fd41d..352fee2d8f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v0.1.4: TBD +=================== + +* Switched to using `jackson-datatype-guava` for JSON serialization/deserialization of Guava types. + + v0.1.3: Jan 19 2012 =================== diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 2440c401157..827e6069c59 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -69,6 +69,11 @@ jackson-mapper-asl ${jackson.version} + + com.fasterxml.jackson + jackson-datatype-guava + 0.6.0 + commons-cli commons-cli diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaDeserializers.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaDeserializers.java deleted file mode 100644 index 84af148d074..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaDeserializers.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.fasterxml.jackson.module.guava; - -import com.fasterxml.jackson.module.guava.deser.*; -import com.google.common.base.Optional; -import com.google.common.collect.*; -import org.codehaus.jackson.map.*; -import org.codehaus.jackson.map.type.CollectionType; -import org.codehaus.jackson.map.type.MapType; -import org.codehaus.jackson.type.JavaType; - -/** - * Custom deserializers module offers. - * - * @author tsaloranta - */ -public class GuavaDeserializers - extends Deserializers.Base -{ - @Override - public JsonDeserializer findBeanDeserializer(JavaType type, - DeserializationConfig config, - DeserializerProvider provider, - BeanDescription beanDesc, - BeanProperty property) throws JsonMappingException { - if (Optional.class.isAssignableFrom(type.getRawClass())) { - final JavaType elementType = type.containedType(0); - return new OptionalDeserializer( - provider.findTypedValueDeserializer(config, elementType, property)); - } - return super.findBeanDeserializer(type, config, provider, beanDesc, property); - } - - /** - * Concrete implementation class to use for properties declared as - * {@link Multiset}s. - * Defaults to using - */ -// protected Class> _cfgDefaultMultiset; - -// protected Class> _cfgDefaultMultimap; - - /* - * No bean types to support yet; may need to add? - */ - /* - public JsonDeserializer findBeanDeserializer(JavaType type, - DeserializationConfig config, DeserializerProvider provider, - BeanDescription beanDesc) { - return null; - } - */ - - @Override - public JsonDeserializer findCollectionDeserializer(CollectionType type, - DeserializationConfig config, DeserializerProvider provider, - BeanDescription beanDesc, BeanProperty property, - TypeDeserializer elementTypeDeser, JsonDeserializer elementDeser) - throws JsonMappingException - { - Class raw = type.getRawClass(); - - // Multi-xxx collections? - if (Multiset.class.isAssignableFrom(raw)) { - // Quite a few variations... - if (LinkedHashMultiset.class.isAssignableFrom(raw)) { - // !!! TODO - } - if (HashMultiset.class.isAssignableFrom(raw)) { - return new HashMultisetDeserializer(type, elementTypeDeser, - _verifyElementDeserializer(elementDeser, type, config, provider)); - } - if (ImmutableMultiset.class.isAssignableFrom(raw)) { - // !!! TODO - } - if (EnumMultiset.class.isAssignableFrom(raw)) { - // !!! TODO - } - if (TreeMultiset.class.isAssignableFrom(raw)) { - // !!! TODO - } - - // TODO: make configurable (for now just default blindly) - return new HashMultisetDeserializer(type, elementTypeDeser, - _verifyElementDeserializer(elementDeser, type, config, provider)); - } - - // ImmutableXxx types? - if (ImmutableCollection.class.isAssignableFrom(raw)) { - if (ImmutableList.class.isAssignableFrom(raw)) { - return new ImmutableListDeserializer(type, elementTypeDeser, - _verifyElementDeserializer(elementDeser, type, config, provider)); - } - if (ImmutableSet.class.isAssignableFrom(raw)) { - // sorted one? - if (ImmutableSortedSet.class.isAssignableFrom(raw)) { - /* 28-Nov-2010, tatu: With some more work would be able to use other things - * than natural ordering; but that'll have to do for now... - */ - Class elemType = type.getContentType().getRawClass(); - if (!Comparable.class.isAssignableFrom(elemType)) { - throw new IllegalArgumentException("Can not handle ImmutableSortedSet with elements that are not Comparable (" - +raw.getName()+")"); - } - return new ImmutableSortedSetDeserializer(type, elementTypeDeser, - _verifyElementDeserializer(elementDeser, type, config, provider)); - } - // nah, just regular one - return new ImmutableSetDeserializer(type, elementTypeDeser, - _verifyElementDeserializer(elementDeser, type, config, provider)); - } - } - return null; - } - - /** - * A few Map types to support. - */ - @Override - public JsonDeserializer findMapDeserializer(MapType type, - DeserializationConfig config, DeserializerProvider provider, - BeanDescription beanDesc, BeanProperty property, KeyDeserializer keyDeser, - TypeDeserializer elementTypeDeser, JsonDeserializer elementDeser) - throws JsonMappingException - { - Class raw = type.getRawClass(); - // ImmutableXxxMap types? - if (ImmutableMap.class.isAssignableFrom(raw)) { - if (ImmutableSortedMap.class.isAssignableFrom(raw)) { - // !!! TODO - } - if (ImmutableBiMap.class.isAssignableFrom(raw)) { - // !!! TODO - } - // Otherwise, plain old ImmutableMap... - return new ImmutableMapDeserializer(type, keyDeser, elementTypeDeser, - _verifyElementDeserializer(elementDeser, type, config, provider)); - } - // Multimaps? - if (Multimap.class.isAssignableFrom(raw)) { - if (ListMultimap.class.isAssignableFrom(raw)) { - // !!! TODO - } - if (SetMultimap.class.isAssignableFrom(raw)) { - // !!! TODO - } - if (SortedSetMultimap.class.isAssignableFrom(raw)) { - // !!! TODO - } - } - return null; - } - - /* - /********************************************************************** - /* Helper methods - /********************************************************************** - */ - - /** - * Helper method used to ensure that we have a deserializer for elements - * of collection being deserialized. - */ - JsonDeserializer _verifyElementDeserializer(JsonDeserializer deser, - JavaType type, - DeserializationConfig config, DeserializerProvider provider) - throws JsonMappingException - { - if (deser == null) { - // 'null' -> collections have no referring fields - deser = provider.findValueDeserializer(config, type.getContentType(), null); - } - return deser; - } -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaModule.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaModule.java deleted file mode 100644 index 42d1fb89622..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaModule.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.fasterxml.jackson.module.guava; - -import org.codehaus.jackson.Version; -import org.codehaus.jackson.map.*; - -public class GuavaModule extends Module // can't use just SimpleModule, due to generic types -{ - private static final String NAME = "GuavaModule"; - - // Should externalize this, probably... - private final static Version VERSION = new Version(0, 1, 0, null); // 0.1.0 - - public GuavaModule() - { - - } - - @Override public String getModuleName() { return NAME; } - @Override public Version version() { return VERSION; } - - @Override - public void setupModule(SetupContext context) - { - context.addDeserializers(new GuavaDeserializers()); - context.addSerializers(new GuavaSerializers()); - } - -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaSerializers.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaSerializers.java deleted file mode 100644 index 008e75969b7..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/GuavaSerializers.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.fasterxml.jackson.module.guava; - -import com.fasterxml.jackson.module.guava.ser.OptionalSerializer; -import com.google.common.base.Optional; -import org.codehaus.jackson.map.*; -import org.codehaus.jackson.type.JavaType; - -public class GuavaSerializers extends Serializers.Base { - @Override - public JsonSerializer findSerializer(SerializationConfig config, - JavaType type, - BeanDescription beanDesc, - BeanProperty property) { - if (Optional.class.isAssignableFrom(type.getRawClass())) { - return new OptionalSerializer(); - } - return super.findSerializer(config, type, beanDesc, property); - } -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaCollectionDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaCollectionDeserializer.java deleted file mode 100644 index dd4c8880d33..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaCollectionDeserializer.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.fasterxml.jackson.module.guava.deser; - -import java.io.IOException; - -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.JsonToken; -import org.codehaus.jackson.map.DeserializationContext; -import org.codehaus.jackson.map.JsonDeserializer; -import org.codehaus.jackson.map.TypeDeserializer; -import org.codehaus.jackson.map.type.CollectionType; - -public abstract class GuavaCollectionDeserializer extends JsonDeserializer -{ - protected final CollectionType _containerType; - - /** - * Deserializer used for values contained in collection being deserialized; - * null if it can not be dynamically determined. - */ - protected final JsonDeserializer _valueDeserializer; - - /** - * If value instances have polymorphic type information, this - * is the type deserializer that can deserialize required type - * information - */ - protected final TypeDeserializer _typeDeserializerForValue; - - protected GuavaCollectionDeserializer(CollectionType type, - TypeDeserializer typeDeser, JsonDeserializer deser) - { - _containerType = type; - _typeDeserializerForValue = typeDeser; - _valueDeserializer = deser; - } - - /** - * Base implementation that does not assume specific type - * inclusion mechanism. Sub-classes are expected to override - * this method if they are to handle type information. - */ - @Override - public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, - TypeDeserializer typeDeserializer) - throws IOException, JsonProcessingException - { - return typeDeserializer.deserializeTypedFromArray(jp, ctxt); - } - - @Override - public T deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException, JsonProcessingException - { - // Ok: must point to START_ARRAY - if (jp.getCurrentToken() != JsonToken.START_ARRAY) { - throw ctxt.mappingException(_containerType.getRawClass()); - } - return _deserializeContents(jp, ctxt); - } - - /* - /********************************************************************** - /* Abstract methods for impl classes - /********************************************************************** - */ - - protected abstract T _deserializeContents(JsonParser jp, DeserializationContext ctxt) - throws IOException, JsonProcessingException; - - /* - /********************************************************************** - /* Helper methods - /********************************************************************** - */ -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaMapDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaMapDeserializer.java deleted file mode 100644 index 0e6308da325..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/GuavaMapDeserializer.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.fasterxml.jackson.module.guava.deser; - -import java.io.IOException; - -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.JsonToken; -import org.codehaus.jackson.map.DeserializationContext; -import org.codehaus.jackson.map.JsonDeserializer; -import org.codehaus.jackson.map.KeyDeserializer; -import org.codehaus.jackson.map.TypeDeserializer; -import org.codehaus.jackson.map.type.MapType; - -public abstract class GuavaMapDeserializer extends JsonDeserializer -{ - protected final MapType _mapType; - - /** - * Key deserializer used, if not null. If null, String from JSON - * content is used as is. - */ - protected final KeyDeserializer _keyDeserializer; - - /** - * Value deserializer. - */ - protected final JsonDeserializer _valueDeserializer; - - /** - * If value instances have polymorphic type information, this - * is the type deserializer that can handle it - */ - protected final TypeDeserializer _typeDeserializerForValue; - - protected GuavaMapDeserializer(MapType type, KeyDeserializer keyDeser, - TypeDeserializer typeDeser, JsonDeserializer deser) - { - _mapType = type; - _keyDeserializer = keyDeser; - _typeDeserializerForValue = typeDeser; - _valueDeserializer = deser; - } - - /** - * Base implementation that does not assume specific type - * inclusion mechanism. Sub-classes are expected to override - * this method if they are to handle type information. - */ - @Override - public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, - TypeDeserializer typeDeserializer) - throws IOException, JsonProcessingException - { - return typeDeserializer.deserializeTypedFromArray(jp, ctxt); - } - - @Override - public T deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException, JsonProcessingException - { - // Ok: must point to START_OBJECT or FIELD_NAME - JsonToken t = jp.getCurrentToken(); - if (t == JsonToken.START_OBJECT) { // If START_OBJECT, move to next; may also be END_OBJECT - t = jp.nextToken(); - if (t != JsonToken.FIELD_NAME && t != JsonToken.END_OBJECT) { - throw ctxt.mappingException(_mapType.getRawClass()); - } - } else if (t != JsonToken.FIELD_NAME) { - throw ctxt.mappingException(_mapType.getRawClass()); - } - return _deserializeEntries(jp, ctxt); - } - - /* - /********************************************************************** - /* Abstract methods for impl classes - /********************************************************************** - */ - - protected abstract T _deserializeEntries(JsonParser jp, DeserializationContext ctxt) - throws IOException, JsonProcessingException; - - /* - /********************************************************************** - /* Helper methods - /********************************************************************** - */ - -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/HashMultisetDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/HashMultisetDeserializer.java deleted file mode 100644 index 6d7068068b3..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/HashMultisetDeserializer.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.fasterxml.jackson.module.guava.deser; - -import com.google.common.collect.HashMultiset; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.JsonToken; -import org.codehaus.jackson.map.DeserializationContext; -import org.codehaus.jackson.map.JsonDeserializer; -import org.codehaus.jackson.map.TypeDeserializer; -import org.codehaus.jackson.map.annotate.JsonCachable; -import org.codehaus.jackson.map.type.CollectionType; - -import java.io.IOException; - -@JsonCachable -public class HashMultisetDeserializer extends GuavaCollectionDeserializer> -{ - public HashMultisetDeserializer(CollectionType type, TypeDeserializer typeDeser, JsonDeserializer deser) - { - super(type, typeDeser, deser); - } - - @Override - protected HashMultiset _deserializeContents(JsonParser jp, DeserializationContext ctxt) - throws IOException, JsonProcessingException - { - JsonDeserializer valueDes = _valueDeserializer; - JsonToken t; - final TypeDeserializer typeDeser = _typeDeserializerForValue; - HashMultiset set = HashMultiset.create(); - - while ((t = jp.nextToken()) != JsonToken.END_ARRAY) { - Object value; - - if (t == JsonToken.VALUE_NULL) { - value = null; - } else if (typeDeser == null) { - value = valueDes.deserialize(jp, ctxt); - } else { - value = valueDes.deserializeWithType(jp, ctxt, typeDeser); - } - set.add(value); - } - return set; - } -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableListDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableListDeserializer.java deleted file mode 100644 index 778d66d387e..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableListDeserializer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.fasterxml.jackson.module.guava.deser; - -import com.google.common.collect.ImmutableList; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.JsonToken; -import org.codehaus.jackson.map.DeserializationContext; -import org.codehaus.jackson.map.JsonDeserializer; -import org.codehaus.jackson.map.TypeDeserializer; -import org.codehaus.jackson.map.annotate.JsonCachable; -import org.codehaus.jackson.map.type.CollectionType; - -import java.io.IOException; - -@JsonCachable -public class ImmutableListDeserializer extends GuavaCollectionDeserializer> -{ - public ImmutableListDeserializer(CollectionType type, TypeDeserializer typeDeser, JsonDeserializer deser) - { - super(type, typeDeser, deser); - } - - @Override - protected ImmutableList _deserializeContents(JsonParser jp, DeserializationContext ctxt) - throws IOException, JsonProcessingException - { - JsonDeserializer valueDes = _valueDeserializer; - JsonToken t; - final TypeDeserializer typeDeser = _typeDeserializerForValue; - // No way to pass actual type parameter; but does not matter, just compiler-time fluff: - ImmutableList.Builder builder = ImmutableList.builder(); - - while ((t = jp.nextToken()) != JsonToken.END_ARRAY) { - Object value; - - if (t == JsonToken.VALUE_NULL) { - value = null; - } else if (typeDeser == null) { - value = valueDes.deserialize(jp, ctxt); - } else { - value = valueDes.deserializeWithType(jp, ctxt, typeDeser); - } - builder.add(value); - } - return builder.build(); - } -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableMapDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableMapDeserializer.java deleted file mode 100644 index 4a1c85a4673..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableMapDeserializer.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.fasterxml.jackson.module.guava.deser; - -import com.google.common.collect.ImmutableMap; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.JsonToken; -import org.codehaus.jackson.map.DeserializationContext; -import org.codehaus.jackson.map.JsonDeserializer; -import org.codehaus.jackson.map.KeyDeserializer; -import org.codehaus.jackson.map.TypeDeserializer; -import org.codehaus.jackson.map.annotate.JsonCachable; -import org.codehaus.jackson.map.type.MapType; - -import java.io.IOException; - -@JsonCachable -public class ImmutableMapDeserializer extends GuavaMapDeserializer> -{ - public ImmutableMapDeserializer(MapType type, KeyDeserializer keyDeser, - TypeDeserializer typeDeser, JsonDeserializer deser) - { - super(type, keyDeser, typeDeser, deser); - } - - @Override - protected ImmutableMap _deserializeEntries(JsonParser jp, - DeserializationContext ctxt) throws IOException, JsonProcessingException - { - final KeyDeserializer keyDes = _keyDeserializer; - final JsonDeserializer valueDes = _valueDeserializer; - final TypeDeserializer typeDeser = _typeDeserializerForValue; - - ImmutableMap.Builder builder = ImmutableMap.builder(); - for (; jp.getCurrentToken() == JsonToken.FIELD_NAME; jp.nextToken()) { - // Must point to field name now - String fieldName = jp.getCurrentName(); - Object key = (keyDes == null) ? fieldName : keyDes.deserializeKey(fieldName, ctxt); - // And then the value... - JsonToken t = jp.nextToken(); - // 28-Nov-2010, tatu: Should probably support "ignorable properties" in future... - Object value; - if (t == JsonToken.VALUE_NULL) { - value = null; - } else if (typeDeser == null) { - value = valueDes.deserialize(jp, ctxt); - } else { - value = valueDes.deserializeWithType(jp, ctxt, typeDeser); - } - builder.put(key, value); - } - return builder.build(); - } - -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSetDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSetDeserializer.java deleted file mode 100644 index 112c2a193a1..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSetDeserializer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.fasterxml.jackson.module.guava.deser; - -import com.google.common.collect.ImmutableSet; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.JsonToken; -import org.codehaus.jackson.map.DeserializationContext; -import org.codehaus.jackson.map.JsonDeserializer; -import org.codehaus.jackson.map.TypeDeserializer; -import org.codehaus.jackson.map.annotate.JsonCachable; -import org.codehaus.jackson.map.type.CollectionType; - -import java.io.IOException; - -@JsonCachable -public class ImmutableSetDeserializer extends GuavaCollectionDeserializer> -{ - public ImmutableSetDeserializer(CollectionType type, TypeDeserializer typeDeser, JsonDeserializer deser) - { - super(type, typeDeser, deser); - } - - @Override - protected ImmutableSet _deserializeContents(JsonParser jp, DeserializationContext ctxt) - throws IOException, JsonProcessingException - { - JsonDeserializer valueDes = _valueDeserializer; - JsonToken t; - final TypeDeserializer typeDeser = _typeDeserializerForValue; - // No way to pass actual type parameter; but does not matter, just compiler-time fluff: - ImmutableSet.Builder builder = ImmutableSet.builder(); - - while ((t = jp.nextToken()) != JsonToken.END_ARRAY) { - Object value; - - if (t == JsonToken.VALUE_NULL) { - value = null; - } else if (typeDeser == null) { - value = valueDes.deserialize(jp, ctxt); - } else { - value = valueDes.deserializeWithType(jp, ctxt, typeDeser); - } - builder.add(value); - } - return builder.build(); - } -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSortedSetDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSortedSetDeserializer.java deleted file mode 100644 index fabddb5ef40..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/ImmutableSortedSetDeserializer.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.fasterxml.jackson.module.guava.deser; - -import com.google.common.collect.ImmutableSortedSet; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.JsonToken; -import org.codehaus.jackson.map.DeserializationContext; -import org.codehaus.jackson.map.JsonDeserializer; -import org.codehaus.jackson.map.TypeDeserializer; -import org.codehaus.jackson.map.annotate.JsonCachable; -import org.codehaus.jackson.map.type.CollectionType; - -import java.io.IOException; - -@JsonCachable -public class ImmutableSortedSetDeserializer extends GuavaCollectionDeserializer> -{ - public ImmutableSortedSetDeserializer(CollectionType type, TypeDeserializer typeDeser, JsonDeserializer deser) - { - super(type, typeDeser, deser); - } - - @Override - protected ImmutableSortedSet _deserializeContents(JsonParser jp, DeserializationContext ctxt) - throws IOException, JsonProcessingException - { - JsonDeserializer valueDes = _valueDeserializer; - JsonToken t; - final TypeDeserializer typeDeser = _typeDeserializerForValue; - /* Not quite sure what to do with sorting/ordering; may require better support either - * via annotations, or via custom serialization (bean style that includes ordering - * aspects) - */ - @SuppressWarnings("unchecked") - ImmutableSortedSet.Builder builderComp = ImmutableSortedSet.naturalOrder(); - @SuppressWarnings("unchecked") - ImmutableSortedSet.Builder builder = (ImmutableSortedSet.Builder) builderComp; - - while ((t = jp.nextToken()) != JsonToken.END_ARRAY) { - Object value; - - if (t == JsonToken.VALUE_NULL) { - value = null; - } else if (typeDeser == null) { - value = valueDes.deserialize(jp, ctxt); - } else { - value = valueDes.deserializeWithType(jp, ctxt, typeDeser); - } - builder.add(value); - } - return builder.build(); - } -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java deleted file mode 100644 index e5e0377c1a5..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/deser/OptionalDeserializer.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.fasterxml.jackson.module.guava.deser; - -import com.google.common.base.Optional; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonToken; -import org.codehaus.jackson.map.DeserializationContext; -import org.codehaus.jackson.map.JsonDeserializer; -import org.codehaus.jackson.map.annotate.JsonCachable; - -import java.io.IOException; - -@JsonCachable -public class OptionalDeserializer extends JsonDeserializer> { - private final JsonDeserializer elementDeserializer; - - public OptionalDeserializer(JsonDeserializer elementDeserializer) { - this.elementDeserializer = elementDeserializer; - } - - @Override - public Optional deserialize(JsonParser jp, - DeserializationContext ctxt) throws IOException { - if (jp.getCurrentToken() == JsonToken.VALUE_NULL) { - return Optional.absent(); - } - return Optional.fromNullable(elementDeserializer.deserialize(jp, ctxt)); - } - - @Override - public Optional getNullValue() { - return Optional.absent(); - } - - @Override - public Optional getEmptyValue() { - return Optional.absent(); - } -} diff --git a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java b/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java deleted file mode 100644 index 7394f3c4e1e..00000000000 --- a/dropwizard-core/src/main/java/com/fasterxml/jackson/module/guava/ser/OptionalSerializer.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.fasterxml.jackson.module.guava.ser; - -import com.google.common.base.Optional; -import org.codehaus.jackson.JsonGenerator; -import org.codehaus.jackson.map.JsonSerializer; -import org.codehaus.jackson.map.SerializerProvider; -import org.codehaus.jackson.map.annotate.JsonCachable; - -import java.io.IOException; - -@JsonCachable -public class OptionalSerializer extends JsonSerializer> { - @Override - public void serialize(Optional value, - JsonGenerator jgen, - SerializerProvider provider) throws IOException { - if (value.isPresent()) { - jgen.writeObject(value.get()); - } else { - jgen.writeNull(); - } - } -} diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java index e204fc79bb2..2acbacdfb66 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java @@ -1,6 +1,6 @@ package com.yammer.dropwizard.json; -import com.fasterxml.jackson.module.guava.GuavaModule; +import com.fasterxml.jackson.datatype.guava.GuavaModule; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonNode; diff --git a/findbugs-exclude.xml b/findbugs-exclude.xml index 929129c9d72..a11c68a9bf0 100644 --- a/findbugs-exclude.xml +++ b/findbugs-exclude.xml @@ -14,9 +14,6 @@ - - - From 4879496b52a84a69a2bdbf89a359bee78431e420 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 19 Jan 2012 21:30:38 -0800 Subject: [PATCH 0188/2771] Use InstrumentedQueuedThreadPool from metrics-jetty. --- CHANGELOG.md | 1 + .../java/com/yammer/dropwizard/config/ServerFactory.java | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 352fee2d8f4..b27ad458626 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ v0.1.4: TBD =================== * Switched to using `jackson-datatype-guava` for JSON serialization/deserialization of Guava types. +* Use `InstrumentedQueuedThreadPool` from `metrics-jetty`. v0.1.3: Jan 19 2012 diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index ec39eaaca18..0c24315f02f 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -10,10 +10,7 @@ import com.yammer.dropwizard.util.Size; import com.yammer.metrics.HealthChecks; import com.yammer.metrics.core.HealthCheck; -import com.yammer.metrics.jetty.InstrumentedBlockingChannelConnector; -import com.yammer.metrics.jetty.InstrumentedHandler; -import com.yammer.metrics.jetty.InstrumentedSelectChannelConnector; -import com.yammer.metrics.jetty.InstrumentedSocketConnector; +import com.yammer.metrics.jetty.*; import com.yammer.metrics.reporting.AdminServlet; import com.yammer.metrics.util.DeadlockHealthCheck; import org.eclipse.jetty.server.*; @@ -232,7 +229,7 @@ private Handler wrapHandler(ServletContextHandler handler) { } private ThreadPool createThreadPool() { - final QueuedThreadPool pool = new QueuedThreadPool(); + final InstrumentedQueuedThreadPool pool = new InstrumentedQueuedThreadPool(); pool.setMinThreads(config.getMinThreads()); pool.setMaxThreads(config.getMaxThreads()); return pool; From dbf5d47a1462b88ecfb5dc972ade64e32df44143 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 20 Jan 2012 21:14:06 -0800 Subject: [PATCH 0189/2771] Upgrade to Jackson 1.9.4. --- dropwizard-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 827e6069c59..5c83f65d58a 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -14,7 +14,7 @@ 7.6.0.RC4 - 1.9.3 + 1.9.4 1.6.4 From 0ec6cfc042afb46c894304a2b01557bd83c070aa Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 20 Jan 2012 23:04:16 -0800 Subject: [PATCH 0190/2771] Upgrade to Jetty 7.6.0.RC5. --- dropwizard-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 5c83f65d58a..ce557c3983d 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -13,7 +13,7 @@ Dropwizard - 7.6.0.RC4 + 7.6.0.RC5 1.9.4 1.6.4 From b4bf401be7e6ffaba7215c22d9f3cc4c48ed3ff8 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 20 Jan 2012 23:05:12 -0800 Subject: [PATCH 0191/2771] Upgrade to tomcat-dbcp 7.0.25. --- dropwizard-db/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index d16abef6efb..99340178133 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -31,7 +31,7 @@ org.apache.tomcat tomcat-dbcp - 7.0.23 + 7.0.25 hsqldb From a85a33c35e713423de18a35c1946068eb581d368 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 20 Jan 2012 23:06:39 -0800 Subject: [PATCH 0192/2771] Updated changelog. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b27ad458626..3da2013b616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ v0.1.4: TBD * Switched to using `jackson-datatype-guava` for JSON serialization/deserialization of Guava types. * Use `InstrumentedQueuedThreadPool` from `metrics-jetty`. +* Upgraded to Jackson 1.9.4. +* Upgraded to Jetty 7.6.0.RC5. +* Upgraded to tomcat-dbcp 7.0.25. v0.1.3: Jan 19 2012 From 58302dc1e46ffb334df1673f9728588aebc2446e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 25 Jan 2012 09:13:55 +0200 Subject: [PATCH 0193/2771] Throw an exception if a Scala class tries to extend Service. Scala projects need to extend ScalaService, which adds a different set of Jersey providers. --- .../main/java/com/yammer/dropwizard/Service.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java index 9779b965d9f..0d3237ff24d 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java @@ -1,7 +1,7 @@ package com.yammer.dropwizard; -import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.bundles.JavaBundle; +import com.yammer.dropwizard.config.Configuration; /** * The default Java service class. Extend this to write your own service. @@ -13,10 +13,24 @@ public abstract class Service extends AbstractService scalaObject = Class.forName("scala.ScalaObject"); + final Class klass = getClass(); + if (scalaObject.isAssignableFrom(klass)) { + throw new IllegalStateException(klass.getCanonicalName() + " is a Scala class. " + + "It should extend ScalaService, not Service."); + } + } catch (ClassNotFoundException ignored) { + // definitely not a Scala project + } + } } From 16dba34131a308df8ef45945794e7329e5c36653 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sat, 28 Jan 2012 08:27:07 +0000 Subject: [PATCH 0194/2771] Upgrade to Jetty 7.6.0 final. --- CHANGELOG.md | 2 +- dropwizard-core/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3da2013b616..0a7bd33058e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ v0.1.4: TBD * Switched to using `jackson-datatype-guava` for JSON serialization/deserialization of Guava types. * Use `InstrumentedQueuedThreadPool` from `metrics-jetty`. * Upgraded to Jackson 1.9.4. -* Upgraded to Jetty 7.6.0.RC5. +* Upgraded to Jetty 7.6.0 final. * Upgraded to tomcat-dbcp 7.0.25. diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index ce557c3983d..8d910e8d654 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -13,7 +13,7 @@ Dropwizard - 7.6.0.RC5 + 7.6.0.v20120127 1.9.4 1.6.4 From c51d94af1a6bbde66b2dac6b2188235ee73b1244 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 1 Feb 2012 17:40:21 -0800 Subject: [PATCH 0195/2771] Use Jackson to deserialize Configuration objects. SnakeYAML is really not very good at object mapping, and Jackson is awesome at that. So I use SnakeYAML to parse the YAML, build up a JSON equivalent object, and then parse that with Jackson. It's not exactly straight-forward, but it's easier to do than write my own YAML parser for Jackson. --- .../dropwizard/config/Configuration.java | 4 + .../config/ConfigurationFactory.java | 33 +-- .../dropwizard/config/GzipConfiguration.java | 44 ++++ .../dropwizard/config/HttpConfiguration.java | 94 +++------ .../config/LoggingConfiguration.java | 62 +++--- .../config/RequestLogConfiguration.java | 34 ++++ .../config/RequestLogHandlerFactory.java | 2 - .../dropwizard/config/ServerFactory.java | 11 +- .../java/com/yammer/dropwizard/json/Json.java | 6 +- .../dropwizard/json/LevelDeserializer.java | 16 ++ .../java/com/yammer/dropwizard/json/Yaml.java | 70 +++++++ .../com/yammer/dropwizard/util/Duration.java | 6 +- .../java/com/yammer/dropwizard/util/Size.java | 8 +- .../tests/ConfigurationFactoryTest.java | 13 +- .../config/tests/GzipConfigurationTest.java | 56 ++++++ .../config/tests/HttpConfigurationTest.java | 188 ++++++++++++++++++ .../tests/RequestLogConfigurationTest.java | 29 +++ .../src/test/resources/yaml/gzip.yml | 5 + .../src/test/resources/yaml/http.yml | 29 +++ .../src/test/resources/yaml/requestLog.yml | 3 + .../helloworld/HelloWorldConfiguration.java | 9 +- 21 files changed, 570 insertions(+), 152 deletions(-) create mode 100644 dropwizard-core/src/main/java/com/yammer/dropwizard/config/GzipConfiguration.java create mode 100644 dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogConfiguration.java create mode 100644 dropwizard-core/src/main/java/com/yammer/dropwizard/json/LevelDeserializer.java create mode 100644 dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java create mode 100644 dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/GzipConfigurationTest.java create mode 100644 dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java create mode 100644 dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/RequestLogConfigurationTest.java create mode 100644 dropwizard-core/src/test/resources/yaml/gzip.yml create mode 100644 dropwizard-core/src/test/resources/yaml/http.yml create mode 100644 dropwizard-core/src/test/resources/yaml/requestLog.yml diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java index 3e3c2301ab8..919b81c8ee8 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java @@ -1,5 +1,7 @@ package com.yammer.dropwizard.config; +import org.codehaus.jackson.annotate.JsonProperty; + import javax.validation.Valid; import javax.validation.constraints.NotNull; @@ -42,10 +44,12 @@ public class Configuration { @NotNull @Valid + @JsonProperty private HttpConfiguration http = new HttpConfiguration(); @NotNull @Valid + @JsonProperty private LoggingConfiguration logging = new LoggingConfiguration(); /** diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java index 1a7c8d33cbe..f622a1f9b36 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java @@ -3,11 +3,8 @@ import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; import com.google.common.io.Files; +import com.yammer.dropwizard.json.Yaml; import com.yammer.dropwizard.validation.Validator; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.Constructor; -import org.yaml.snakeyaml.error.YAMLException; -import org.yaml.snakeyaml.introspector.BeanAccess; import java.io.BufferedReader; import java.io.File; @@ -26,11 +23,10 @@ public ConfigurationFactory(Class klass, Validator validator) { this.validator = validator; } - public T build(File file) throws IOException, ConfigurationException, YAMLException { + public T build(File file) throws IOException, ConfigurationException { final BufferedReader reader = Files.newReader(file, Charsets.UTF_8); try { - final Yaml yaml = buildYamlParser(); - final T config = loadYaml(reader, yaml); + final T config = new Yaml(file).read(klass); validate(file, config); return config; } finally { @@ -38,33 +34,10 @@ public T build(File file) throws IOException, ConfigurationException, YAMLExcept } } - private T defaultInstance() { - try { - return klass.newInstance(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - private void validate(File file, T config) throws ConfigurationException { final ImmutableList errors = validator.validate(config); if (!errors.isEmpty()) { throw new ConfigurationException(file, errors); } } - - @SuppressWarnings("unchecked") - private T loadYaml(BufferedReader reader, Yaml yaml) { - final T config = (T) yaml.load(reader); - if (config == null) { - return defaultInstance(); - } - return config; - } - - private Yaml buildYamlParser() { - final Yaml yaml = new Yaml(new Constructor(klass)); - yaml.setBeanAccess(BeanAccess.FIELD); - return yaml; - } } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/GzipConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/GzipConfiguration.java new file mode 100644 index 00000000000..84a176be3bc --- /dev/null +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/GzipConfiguration.java @@ -0,0 +1,44 @@ +package com.yammer.dropwizard.config; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; +import com.yammer.dropwizard.util.Size; +import org.codehaus.jackson.annotate.JsonProperty; + +@SuppressWarnings({ "FieldMayBeFinal", "FieldCanBeLocal" }) +public class GzipConfiguration { + @JsonProperty + private boolean enabled = true; + + @JsonProperty + private Size minimumEntitySize = null; + + @JsonProperty + private Size bufferSize = null; + + @JsonProperty + private ImmutableSet excludedUserAgents = null; + + @JsonProperty + private ImmutableSet compressedMimeTypes = null; + + public boolean isEnabled() { + return enabled; + } + + public Optional getMinimumEntitySize() { + return Optional.fromNullable(minimumEntitySize); + } + + public Optional getBufferSize() { + return Optional.fromNullable(bufferSize); + } + + public Optional> getExcludedUserAgents() { + return Optional.fromNullable(excludedUserAgents); + } + + public Optional> getCompressedMimeTypes() { + return Optional.fromNullable(compressedMimeTypes); + } +} diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 1dc6122c2bd..34f3f4be660 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -3,83 +3,26 @@ import com.google.common.base.Optional; import com.yammer.dropwizard.util.Duration; import com.yammer.dropwizard.util.Size; +import org.codehaus.jackson.annotate.JsonProperty; +import javax.validation.Valid; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; -import java.util.List; // TODO: 11/7/11 -- document HttpConfiguration -// TODO: 11/7/11 -- test HttpConfiguration @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal", "CanBeFinal"}) public class HttpConfiguration { - public static class RequestLogConfiguration { - private boolean enabled = true; - - @NotNull - private String filenamePattern = "./logs/yyyy_mm_dd.log"; - - @Min(1) - @Max(50) - private int retainedFileCount = 5; - - public boolean isEnabled() { - return enabled; - } - - public String getFilenamePattern() { - return filenamePattern; - } - - public int getRetainedFileCount() { - return retainedFileCount; - } - } - - public static class GzipConfiguration { - private boolean enabled = true; - - private String minimumEntitySize = null; - - private String bufferSize = null; - - private List excludedUserAgents = null; - - private List compressedMimeTypes = null; - - public boolean isEnabled() { - return enabled; - } - - public Optional getMinimumEntitySize() { - if (minimumEntitySize == null) { - return Optional.absent(); - } - return Optional.of(Size.parse(minimumEntitySize)); - } - - public Optional getBufferSize() { - if (bufferSize == null) { - return Optional.absent(); - } - return Optional.of(Size.parse(bufferSize)); - } - - public Optional> getExcludedUserAgents() { - return Optional.fromNullable(excludedUserAgents); - } - - public Optional> getCompressedMimeTypes() { - return Optional.fromNullable(compressedMimeTypes); - } - } - + @Valid @NotNull + @JsonProperty private RequestLogConfiguration requestLog = new RequestLogConfiguration(); + @Valid @NotNull + @JsonProperty private GzipConfiguration gzip = new GzipConfiguration(); public enum ConnectorType { @@ -90,78 +33,103 @@ public enum ConnectorType { @Min(1025) @Max(65535) + @JsonProperty private int port = 8080; @Min(1025) @Max(65535) + @JsonProperty private int adminPort = 8081; @Min(10) @Max(20000) + @JsonProperty private int maxThreads = 100; @Min(10) @Max(20000) + @JsonProperty private int minThreads = 10; @NotNull + @JsonProperty private String rootPath = "/*"; @NotNull @Pattern(regexp = "(blocking|nonblocking|legacy)", flags = {Pattern.Flag.CASE_INSENSITIVE}) + @JsonProperty private String connectorType = "blocking"; @NotNull + @JsonProperty private Duration maxIdleTime = Duration.seconds(1); @Min(1) @Max(128) + @JsonProperty private int acceptorThreadCount = Runtime.getRuntime().availableProcessors(); @Min(-Thread.NORM_PRIORITY) @Max(Thread.NORM_PRIORITY) + @JsonProperty private int acceptorThreadPriorityOffset = 0; @Min(-1) + @JsonProperty private int acceptQueueSize = -1; @Min(1) + @JsonProperty private int maxBufferCount = 1024; @NotNull + @JsonProperty private Size requestBufferSize = Size.kilobytes(32); @NotNull + @JsonProperty private Size requestHeaderBufferSize = Size.kilobytes(3); @NotNull + @JsonProperty private Size responseBufferSize = Size.kilobytes(32); @NotNull + @JsonProperty private Size responseHeaderBufferSize = Size.kilobytes(6); + @JsonProperty private boolean reuseAddress = true; + @JsonProperty private Duration soLingerTime = null; @Min(1) + @JsonProperty private int lowResourcesConnectionThreshold = 25000; @NotNull + @JsonProperty private Duration lowResourcesMaxIdleTime = Duration.seconds(5); @NotNull + @JsonProperty private Duration shutdownGracePeriod = Duration.seconds(2); + @JsonProperty private boolean useServerHeader = false; + @JsonProperty private boolean useDateHeader = true; + @JsonProperty private boolean useForwardedHeaders = true; + @JsonProperty private boolean useDirectBuffers = true; + @JsonProperty private String bindHost = null; public RequestLogConfiguration getRequestLogConfiguration() { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java index 28ca75e4f50..0d6b9539c25 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java @@ -1,51 +1,59 @@ package com.yammer.dropwizard.config; import com.google.common.collect.ImmutableMap; +import com.yammer.dropwizard.json.LevelDeserializer; import com.yammer.dropwizard.util.Size; import org.apache.log4j.Level; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonDeserialize; +import javax.validation.Valid; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; -import java.util.Map; @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) public class LoggingConfiguration { - private static final String VALID_LEVEL = "(OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE|ALL)"; - public static class ConsoleConfiguration { + @JsonProperty private boolean enabled = true; @NotNull - @Pattern(regexp = VALID_LEVEL, flags = {Pattern.Flag.CASE_INSENSITIVE}) - private String threshold = "ALL"; + @JsonProperty + @JsonDeserialize(using = LevelDeserializer.class) + private Level threshold = Level.ALL; public boolean isEnabled() { return enabled; } public Level getThreshold() { - return Level.toLevel(threshold); + return threshold; } } @SuppressWarnings("CanBeFinal") public static class FileConfiguration { + @JsonProperty private boolean enabled = false; @NotNull - @Pattern(regexp = VALID_LEVEL, flags = {Pattern.Flag.CASE_INSENSITIVE}) - private String threshold = "ALL"; + @JsonProperty + @JsonDeserialize(using = LevelDeserializer.class) + private Level threshold = Level.ALL; @NotNull + @JsonProperty private String filenamePattern = "./logs/example.log"; @NotNull + @JsonProperty private Size maxFileSize = Size.megabytes(50); @Min(1) @Max(50) + @JsonProperty private int retainedFileCount = 5; public boolean isEnabled() { @@ -53,7 +61,7 @@ public boolean isEnabled() { } public Level getThreshold() { - return Level.toLevel(threshold); + return threshold; } public String getFilenamePattern() { @@ -70,17 +78,21 @@ public int getRetainedFileCount() { } public static class SyslogConfiguration { + @JsonProperty private boolean enabled = true; @NotNull - @Pattern(regexp = VALID_LEVEL, flags = {Pattern.Flag.CASE_INSENSITIVE}) - private String threshold = "ALL"; + @JsonProperty + @JsonDeserialize(using = LevelDeserializer.class) + private Level threshold = Level.ALL; @NotNull + @JsonProperty private String host = "localhost"; - @Pattern(regexp = "auth|authpriv|daemon|cron|ftp|lpr|kern|mail|news|syslog|user|uucp|local[0-7]]") @NotNull + @JsonProperty + @Pattern(regexp = "(auth|authpriv|daemon|cron|ftp|lpr|kern|mail|news|syslog|user|uucp|local[0-7])") private String facility = "local0"; public boolean isEnabled() { @@ -88,7 +100,7 @@ public boolean isEnabled() { } public Level getThreshold() { - return Level.toLevel(threshold); + return threshold; } public String getHost() { @@ -101,32 +113,36 @@ public String getFacility() { } @NotNull - @Pattern(regexp = VALID_LEVEL, flags = {Pattern.Flag.CASE_INSENSITIVE}) - private String level = "INFO"; + @JsonProperty + @JsonDeserialize(using = LevelDeserializer.class) + private Level level = Level.INFO; @NotNull - // TODO: 11/7/11 -- figure out how to validate these values - private Map loggers = ImmutableMap.of(); + @JsonProperty + @JsonDeserialize(contentUsing = LevelDeserializer.class) + private ImmutableMap loggers = ImmutableMap.of(); + @Valid @NotNull + @JsonProperty private ConsoleConfiguration console = new ConsoleConfiguration(); + @Valid @NotNull + @JsonProperty private FileConfiguration file = new FileConfiguration(); + @Valid @NotNull + @JsonProperty private SyslogConfiguration syslog = new SyslogConfiguration(); public Level getLevel() { - return Level.toLevel(level); + return level; } public ImmutableMap getLoggers() { - final ImmutableMap.Builder builder = ImmutableMap.builder(); - for (Map.Entry entry : loggers.entrySet()) { - builder.put(entry.getKey(), Level.toLevel(entry.getValue())); - } - return builder.build(); + return loggers; } public ConsoleConfiguration getConsoleConfiguration() { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogConfiguration.java new file mode 100644 index 00000000000..c83b1d401ba --- /dev/null +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogConfiguration.java @@ -0,0 +1,34 @@ +package com.yammer.dropwizard.config; + +import org.codehaus.jackson.annotate.JsonProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@SuppressWarnings({ "FieldMayBeFinal", "FieldCanBeLocal" }) +public class RequestLogConfiguration { + @JsonProperty + private boolean enabled = false; + + @NotNull + @JsonProperty + private String filenamePattern = "./logs/yyyy_mm_dd.log"; + + @Min(1) + @Max(50) + @JsonProperty + private int retainedFileCount = 5; + + public boolean isEnabled() { + return enabled; + } + + public String getFilenamePattern() { + return filenamePattern; + } + + public int getRetainedFileCount() { + return retainedFileCount; + } +} diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogHandlerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogHandlerFactory.java index a286f67731c..b7b16cbcde1 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogHandlerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/RequestLogHandlerFactory.java @@ -3,8 +3,6 @@ import com.yammer.dropwizard.jetty.AsyncRequestLog; import org.eclipse.jetty.server.handler.RequestLogHandler; -import static com.yammer.dropwizard.config.HttpConfiguration.RequestLogConfiguration; - // TODO: 11/7/11 -- document RequestLogHandlerFactory // TODO: 11/7/11 -- test RequestLogHandlerFactory diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index 0c24315f02f..91fe6a03a1d 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -26,11 +26,8 @@ import org.eclipse.jetty.util.thread.ThreadPool; import java.util.EnumSet; -import java.util.List; import java.util.Map; -import static com.yammer.dropwizard.config.HttpConfiguration.GzipConfiguration; - // TODO: 11/7/11 -- document ServerFactory // TODO: 11/7/11 -- document ServerFactory @@ -213,14 +210,14 @@ private Handler wrapHandler(ServletContextHandler handler) { gzipHandler.setBufferSize((int) bufferSize.get().toBytes()); } - final Optional> userAgents = gzip.getExcludedUserAgents(); + final Optional> userAgents = gzip.getExcludedUserAgents(); if (userAgents.isPresent()) { - gzipHandler.setExcluded(ImmutableSet.copyOf(userAgents.get())); + gzipHandler.setExcluded(userAgents.get()); } - final Optional> mimeTypes = gzip.getCompressedMimeTypes(); + final Optional> mimeTypes = gzip.getCompressedMimeTypes(); if (mimeTypes.isPresent()) { - gzipHandler.setMimeTypes(ImmutableSet.copyOf(mimeTypes.get())); + gzipHandler.setMimeTypes(mimeTypes.get()); } return gzipHandler; diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java index 2acbacdfb66..1b769fae918 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java @@ -37,9 +37,9 @@ private Json() { // singleton } - private static final JsonFactory factory; - private static final ObjectMapper mapper; - private static final TypeFactory typeFactory; + static final JsonFactory factory; + static final ObjectMapper mapper; + static final TypeFactory typeFactory; static { factory = new MappingJsonFactory(); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/LevelDeserializer.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/LevelDeserializer.java new file mode 100644 index 00000000000..916edec0d61 --- /dev/null +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/LevelDeserializer.java @@ -0,0 +1,16 @@ +package com.yammer.dropwizard.json; + +import org.apache.log4j.Level; +import org.codehaus.jackson.JsonParser; +import org.codehaus.jackson.map.DeserializationContext; +import org.codehaus.jackson.map.JsonDeserializer; + +import java.io.IOException; + +public class LevelDeserializer extends JsonDeserializer { + @Override + public Level deserialize(JsonParser jp, + DeserializationContext ctxt) throws IOException { + return Level.toLevel(jp.getText()); + } +} diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java new file mode 100644 index 00000000000..5fc89378a1e --- /dev/null +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java @@ -0,0 +1,70 @@ +package com.yammer.dropwizard.json; + +import com.yammer.dropwizard.logging.Log; +import org.codehaus.jackson.JsonGenerator; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.type.TypeReference; +import org.yaml.snakeyaml.nodes.*; + +import java.io.*; + +public class Yaml { + private static final Log LOG = Log.forClass(Yaml.class); + private final JsonNode node; + + public Yaml(File file) throws IOException { + final FileReader reader = new FileReader(file); + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + final JsonGenerator json = Json.factory.createJsonGenerator(output).useDefaultPrettyPrinter(); + try { + final Node yaml = new org.yaml.snakeyaml.Yaml().compose(reader); + build(yaml, json); + json.close(); + LOG.debug("Parsed {} as:\n {}", file, output.toString()); + this.node = Json.read(output.toByteArray(), JsonNode.class); + } finally { + reader.close(); + } + } + + private static void build(Node yaml, JsonGenerator json) throws IOException { + if (yaml instanceof MappingNode) { + final MappingNode mappingNode = (MappingNode) yaml; + json.writeStartObject(); + for (NodeTuple tuple : mappingNode.getValue()) { + if (tuple.getKeyNode() instanceof ScalarNode) { + json.writeFieldName(((ScalarNode) tuple.getKeyNode()).getValue()); + } + + build(tuple.getValueNode(), json); + } + json.writeEndObject(); + } else if (yaml instanceof SequenceNode) { + json.writeStartArray(); + for (Node node : ((SequenceNode) yaml).getValue()) { + build(node, json); + } + json.writeEndArray(); + } else if (yaml instanceof ScalarNode) { + final ScalarNode scalarNode = (ScalarNode) yaml; + final String className = scalarNode.getTag().getClassName(); + if ("bool".equals(className)) { + json.writeBoolean(Boolean.parseBoolean(scalarNode.getValue())); + } else if ("int".equals(className)) { + json.writeNumber(Long.parseLong(scalarNode.getValue())); + } else if ("float".equals(className)) { + json.writeNumber(Double.parseDouble(scalarNode.getValue())); + } else { + json.writeString(scalarNode.getValue()); + } + } + } + + public T read(Class klass) throws IOException { + return Json.read(node, klass); + } + + public T read(TypeReference ref) throws IOException { + return Json.read(node, ref); + } +} diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java index d6a2bea50bd..6c6d15db134 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Duration.java @@ -2,6 +2,7 @@ import com.google.common.base.CharMatcher; import com.google.common.collect.ImmutableMap; +import org.codehaus.jackson.annotate.JsonCreator; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -95,16 +96,13 @@ private static TimeUnit parseUnit(String s) { return SUFFIXES.get(suffix); } + @JsonCreator public static Duration parse(String duration) { return new Duration(parseCount(duration), parseUnit(duration)); } private final long count; private final TimeUnit unit; - - public Duration(String duration) { - this(parseCount(duration), parseUnit(duration)); - } private Duration(long count, TimeUnit unit) { this.count = count; diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java index d31795f97ed..09b170aaf9d 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/Size.java @@ -2,6 +2,7 @@ import com.google.common.base.CharMatcher; import com.google.common.collect.ImmutableMap; +import org.codehaus.jackson.annotate.JsonCreator; import java.util.regex.Pattern; @@ -77,17 +78,14 @@ private static SizeUnit parseUnit(String s) { final String suffix = CharMatcher.DIGIT.trimLeadingFrom(value).trim(); return SUFFIXES.get(suffix); } - + + @JsonCreator public static Size parse(String size) { return new Size(parseCount(size), parseUnit(size)); } private final long count; private final SizeUnit unit; - - public Size(String size) { - this(parseCount(size), parseUnit(size)); - } private Size(long count, SizeUnit unit) { this.count = count; diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java index 7bc948e316a..a669bb9eb15 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java @@ -5,16 +5,15 @@ import com.yammer.dropwizard.config.ConfigurationFactory; import com.yammer.dropwizard.validation.Validator; import org.junit.Test; -import org.yaml.snakeyaml.error.YAMLException; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import java.io.File; +import java.io.IOException; -import static org.hamcrest.Matchers.endsWith; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; public class ConfigurationFactoryTest { @SuppressWarnings("UnusedDeclaration") @@ -46,8 +45,8 @@ public void throwsAnExceptionOnMalformedFiles() throws Exception { try { factory.build(malformedFile); fail("expected a YAMLException to be thrown, but none was"); - } catch (YAMLException e) { - assertThat(e.getMessage(), startsWith("null")); + } catch (IOException e) { + assertThat(e.getMessage(), startsWith("Can not instantiate")); } } diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/GzipConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/GzipConfigurationTest.java new file mode 100644 index 00000000000..9f760f57333 --- /dev/null +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/GzipConfigurationTest.java @@ -0,0 +1,56 @@ +package com.yammer.dropwizard.config.tests; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; +import com.google.common.io.Resources; +import com.yammer.dropwizard.config.ConfigurationFactory; +import com.yammer.dropwizard.config.GzipConfiguration; +import com.yammer.dropwizard.util.Size; +import com.yammer.dropwizard.validation.Validator; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +public class GzipConfigurationTest { + private GzipConfiguration gzip; + + @Before + public void setUp() throws Exception { + this.gzip = new ConfigurationFactory(GzipConfiguration.class, + new Validator()).build(new File(Resources.getResource("yaml/gzip.yml").getFile())); + } + + @Test + public void canBeEnabled() throws Exception { + assertThat(gzip.isEnabled(), + is(false)); + } + + @Test + public void hasAMinimumEntitySize() throws Exception { + assertThat(gzip.getMinimumEntitySize(), + is(Optional.of(Size.kilobytes(12)))); + } + + @Test + public void hasABufferSize() throws Exception { + assertThat(gzip.getBufferSize(), + is(Optional.of(Size.kilobytes(32)))); + } + + @Test + public void hasExcludedUserAgents() throws Exception { + assertThat(gzip.getExcludedUserAgents(), + is(Optional.of(ImmutableSet.of("IE")))); + } + + @Test + public void hasCompressedMimeTypes() throws Exception { + assertThat(gzip.getCompressedMimeTypes(), + is(Optional.of(ImmutableSet.of("text/plain")))); + } +} diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java new file mode 100644 index 00000000000..15058afb9fe --- /dev/null +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java @@ -0,0 +1,188 @@ +package com.yammer.dropwizard.config.tests; + +import com.google.common.base.Optional; +import com.google.common.io.Resources; +import com.yammer.dropwizard.config.ConfigurationFactory; +import com.yammer.dropwizard.config.HttpConfiguration; +import com.yammer.dropwizard.util.Duration; +import com.yammer.dropwizard.util.Size; +import com.yammer.dropwizard.validation.Validator; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +public class HttpConfigurationTest { + private HttpConfiguration http; + + @Before + public void setUp() throws Exception { + this.http = new ConfigurationFactory(HttpConfiguration.class, + new Validator()).build(new File(Resources.getResource("yaml/http.yml").getFile())); + } + + @Test + public void loadsGzipConfig() throws Exception { + assertThat(http.getGzipConfiguration().isEnabled(), + is(false)); + } + + @Test + public void loadsRequestLogConfig() throws Exception { + assertThat(http.getRequestLogConfiguration().isEnabled(), + is(true)); + } + + @Test + public void hasAServicePort() throws Exception { + assertThat(http.getPort(), + is(9080)); + } + + @Test + public void hasAnAdminPort() throws Exception { + assertThat(http.getAdminPort(), + is(9081)); + } + + @Test + public void hasAMaximumNumberOfThreads() throws Exception { + assertThat(http.getMaxThreads(), + is(101)); + } + + @Test + public void hasAMinimumNumberOfThreads() throws Exception { + assertThat(http.getMinThreads(), + is(89)); + } + + @Test + public void hasARootPath() throws Exception { + assertThat(http.getRootPath(), + is("/services/*")); + } + + @Test + public void hasAConnectorType() throws Exception { + assertThat(http.getConnectorType(), + is(HttpConfiguration.ConnectorType.SOCKET)); + } + + @Test + public void hasAMaxIdleTime() throws Exception { + assertThat(http.getMaxIdleTime(), + is(Duration.seconds(2))); + } + + @Test + public void hasAnAcceptorThreadCount() throws Exception { + assertThat(http.getAcceptorThreadCount(), + is(2)); + } + + @Test + public void hasAnAcceptorThreadPriorityOffset() throws Exception { + assertThat(http.getAcceptorThreadPriorityOffset(), + is(-3)); + } + + @Test + public void hasAnAcceptQueueSize() throws Exception { + assertThat(http.getAcceptQueueSize(), + is(100)); + } + + @Test + public void hasAMaxBufferCount() throws Exception { + assertThat(http.getMaxBufferCount(), + is(512)); + } + + @Test + public void hasARequestBufferSize() throws Exception { + assertThat(http.getRequestBufferSize(), + is(Size.kilobytes(16))); + } + + @Test + public void hasARequestHeaderBufferSize() throws Exception { + assertThat(http.getRequestHeaderBufferSize(), + is(Size.kilobytes(17))); + } + + @Test + public void hasAResponseBufferSize() throws Exception { + assertThat(http.getResponseBufferSize(), + is(Size.kilobytes(18))); + } + + @Test + public void hasAResponseHeaderBufferSize() throws Exception { + assertThat(http.getResponseHeaderBufferSize(), + is(Size.kilobytes(19))); + } + + @Test + public void canReuseAddresses() throws Exception { + assertThat(http.isReuseAddressEnabled(), + is(false)); + } + + @Test + public void hasAnSoLingerTime() throws Exception { + assertThat(http.getSoLingerTime(), + is(Optional.of(Duration.seconds(2)))); + } + + @Test + public void hasALowResourcesConnectionThreshold() throws Exception { + assertThat(http.getLowResourcesConnectionThreshold(), + is(1000)); + } + + @Test + public void hasALowResourcesMaxIdleTime() throws Exception { + assertThat(http.getLowResourcesMaxIdleTime(), + is(Duration.seconds(1))); + } + + @Test + public void hasAShutdownGracePeriod() throws Exception { + assertThat(http.getShutdownGracePeriod(), + is(Duration.seconds(5))); + } + + @Test + public void canSendAServerHeader() throws Exception { + assertThat(http.isServerHeaderEnabled(), + is(true)); + } + + @Test + public void canSendADateHeader() throws Exception { + assertThat(http.isDateHeaderEnabled(), + is(false)); + } + + @Test + public void canForwardHeaders() throws Exception { + assertThat(http.useForwardedHeaders(), + is(false)); + } + + @Test + public void canUseDirectBuffers() throws Exception { + assertThat(http.useDirectBuffers(), + is(false)); + } + + @Test + public void hasABindHost() throws Exception { + assertThat(http.getBindHost(), + is(Optional.of("localhost"))); + } +} diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/RequestLogConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/RequestLogConfigurationTest.java new file mode 100644 index 00000000000..26d9c5343c2 --- /dev/null +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/RequestLogConfigurationTest.java @@ -0,0 +1,29 @@ +package com.yammer.dropwizard.config.tests; + +import com.google.common.io.Resources; +import com.yammer.dropwizard.config.ConfigurationFactory; +import com.yammer.dropwizard.config.RequestLogConfiguration; +import com.yammer.dropwizard.validation.Validator; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +public class RequestLogConfigurationTest { + private RequestLogConfiguration requestLog; + + @Before + public void setUp() throws Exception { + this.requestLog = new ConfigurationFactory(RequestLogConfiguration.class, + new Validator()).build(new File(Resources.getResource("yaml/requestLog.yml").getFile())); + } + + @Test + public void canBeEnabled() throws Exception { + assertThat(requestLog.isEnabled(), + is(true)); + } +} diff --git a/dropwizard-core/src/test/resources/yaml/gzip.yml b/dropwizard-core/src/test/resources/yaml/gzip.yml new file mode 100644 index 00000000000..4ec438af641 --- /dev/null +++ b/dropwizard-core/src/test/resources/yaml/gzip.yml @@ -0,0 +1,5 @@ +enabled: false +minimumEntitySize: 12KB +bufferSize: 32KB +excludedUserAgents: ["IE"] +compressedMimeTypes: ["text/plain"] diff --git a/dropwizard-core/src/test/resources/yaml/http.yml b/dropwizard-core/src/test/resources/yaml/http.yml new file mode 100644 index 00000000000..16c01b64508 --- /dev/null +++ b/dropwizard-core/src/test/resources/yaml/http.yml @@ -0,0 +1,29 @@ +requestLog: + enabled: true +gzip: + enabled: false +port: 9080 +adminPort: 9081 +maxThreads: 101 +minThreads: 89 +rootPath: "/services/*" +connectorType: legacy +maxIdleTime: 2s +acceptorThreadCount: 2 +acceptorThreadPriorityOffset: -3 +acceptQueueSize: 100 +maxBufferCount: 512 +requestBufferSize: 16KB +requestHeaderBufferSize: 17KB +responseBufferSize: 18KB +responseHeaderBufferSize: 19KB +reuseAddress: false +soLingerTime: 2s +lowResourcesConnectionThreshold: 1000 +lowResourcesMaxIdleTime: 1s +shutdownGracePeriod: 5s +useServerHeader: true +useDateHeader: false +useForwardedHeaders: false +useDirectBuffers: false +bindHost: "localhost" diff --git a/dropwizard-core/src/test/resources/yaml/requestLog.yml b/dropwizard-core/src/test/resources/yaml/requestLog.yml new file mode 100644 index 00000000000..d4c65efca94 --- /dev/null +++ b/dropwizard-core/src/test/resources/yaml/requestLog.yml @@ -0,0 +1,3 @@ +enabled: true +filenamePattern: "/var/log/dingo/logs/yyyy_mm_dd.log" +retainedFileCount: 20 diff --git a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldConfiguration.java b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldConfiguration.java index 363fcc7027c..c985f3ef850 100644 --- a/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldConfiguration.java +++ b/dropwizard-example/src/main/java/com/example/helloworld/HelloWorldConfiguration.java @@ -4,6 +4,7 @@ import com.yammer.dropwizard.config.Configuration; import org.hibernate.validator.constraints.NotEmpty; +@SuppressWarnings("FieldMayBeFinal") public class HelloWorldConfiguration extends Configuration { @NotEmpty private String template; @@ -19,14 +20,6 @@ public String getDefaultName() { return defaultName; } - public void setTemplate(String template) { - this.template = template; - } - - public void setDefaultName(String defaultName) { - this.defaultName = defaultName; - } - public Template buildTemplate() { return new Template(template, defaultName); } From 6e61441e40b4a6e7f32b02cb6d3a85a05beb5d10 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 1 Feb 2012 17:49:24 -0800 Subject: [PATCH 0196/2771] Make sure we're closing our Reader. --- .../src/main/java/com/yammer/dropwizard/json/Yaml.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java index 5fc89378a1e..9d701a034c8 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java @@ -13,9 +13,9 @@ public class Yaml { private final JsonNode node; public Yaml(File file) throws IOException { - final FileReader reader = new FileReader(file); final ByteArrayOutputStream output = new ByteArrayOutputStream(); final JsonGenerator json = Json.factory.createJsonGenerator(output).useDefaultPrettyPrinter(); + final FileReader reader = new FileReader(file); try { final Node yaml = new org.yaml.snakeyaml.Yaml().compose(reader); build(yaml, json); From 485521d2dd8afa3f40f343c4e20330e45fab0dbe Mon Sep 17 00:00:00 2001 From: Chris Gray Date: Thu, 2 Feb 2012 13:21:32 -0800 Subject: [PATCH 0197/2771] Removing unused Reader from ConfigurationFactory#build --- .../dropwizard/config/ConfigurationFactory.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java index f622a1f9b36..eb23a97373a 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java @@ -1,12 +1,9 @@ package com.yammer.dropwizard.config; -import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; -import com.google.common.io.Files; import com.yammer.dropwizard.json.Yaml; import com.yammer.dropwizard.validation.Validator; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -24,14 +21,9 @@ public ConfigurationFactory(Class klass, Validator validator) { } public T build(File file) throws IOException, ConfigurationException { - final BufferedReader reader = Files.newReader(file, Charsets.UTF_8); - try { - final T config = new Yaml(file).read(klass); - validate(file, config); - return config; - } finally { - reader.close(); - } + final T config = new Yaml(file).read(klass); + validate(file, config); + return config; } private void validate(File file, T config) throws ConfigurationException { From 5204e5f9de42446668d1326324528bdac1fc9968 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 3 Feb 2012 09:53:50 -0800 Subject: [PATCH 0198/2771] Tinker with ServerCommand's logging. --- .../main/java/com/yammer/dropwizard/cli/ServerCommand.java | 6 +++--- dropwizard-example/src/main/resources/banner.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java index f258356b270..6f1769d4080 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java @@ -49,12 +49,12 @@ protected void run(AbstractService service, final Server server = new ServerFactory(configuration.getHttpConfiguration()).buildServer(environment); final Log log = Log.forClass(ServerCommand.class); - log.info("Starting {}", service.getName()); - try { - log.info("\n{}", Resources.toString(Resources.getResource("banner.txt"), Charsets.UTF_8)); + final String banner = Resources.toString(Resources.getResource("banner.txt"), Charsets.UTF_8); + log.info("Starting {}\n{}", service.getName(), banner); } catch (IllegalArgumentException ignored) { // don't display the banner if there isn't one + log.info("Starting {}", service.getName()); } try { diff --git a/dropwizard-example/src/main/resources/banner.txt b/dropwizard-example/src/main/resources/banner.txt index 98a10e38e45..1cbdb95aa4e 100644 --- a/dropwizard-example/src/main/resources/banner.txt +++ b/dropwizard-example/src/main/resources/banner.txt @@ -1,4 +1,4 @@ - dP + web-scale hello world dP for the web 88 .d8888b. dP. .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b. 88ooood8 `8bd8' 88' `88 88'`88'`88 88' `88 88 88ooood8 From 233dec3bfb6a7069ec631da9e6bb970dd14782ce Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 3 Feb 2012 19:08:41 -0800 Subject: [PATCH 0199/2771] Extract and improve JSON support. * Json is no longer a singleton. * It's now fully tested. * It now supports enabling/disabling features. * Limited YAML parsing is handled. --- .../config/ConfigurationFactory.java | 14 +- .../jersey/JacksonMessageBodyProvider.java | 10 +- ...tationSensitivePropertyNamingStrategy.java | 7 +- .../java/com/yammer/dropwizard/json/Json.java | 509 +++++++++++++++--- .../json/{Yaml.java => YamlConverter.java} | 39 +- .../dropwizard/json/tests/JsonTest.java | 298 ++++++++++ .../src/test/resources/json/string.json | 2 +- .../src/test/resources/yaml/string.yml | 1 + .../dropwizard/testing/JsonHelpers.java | 10 +- 9 files changed, 790 insertions(+), 100 deletions(-) rename dropwizard-core/src/main/java/com/yammer/dropwizard/json/{Yaml.java => YamlConverter.java} (72%) create mode 100644 dropwizard-core/src/test/resources/yaml/string.yml diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java index eb23a97373a..4afff1544d9 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java @@ -1,7 +1,7 @@ package com.yammer.dropwizard.config; import com.google.common.collect.ImmutableList; -import com.yammer.dropwizard.json.Yaml; +import com.yammer.dropwizard.json.Json; import com.yammer.dropwizard.validation.Validator; import java.io.File; @@ -13,19 +13,29 @@ public static ConfigurationFactory forClass(Class klass, Validator val } private final Class klass; + private final Json json; private final Validator validator; public ConfigurationFactory(Class klass, Validator validator) { this.klass = klass; + this.json = new Json(); + json.enable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES); this.validator = validator; } public T build(File file) throws IOException, ConfigurationException { - final T config = new Yaml(file).read(klass); + final T config = parse(file); validate(file, config); return config; } + private T parse(File file) throws IOException { + if (file.getName().endsWith(".yaml") || file.getName().endsWith(".yml")) { + return json.readYamlValue(file, klass); + } + return json.readValue(file, klass); + } + private void validate(File file, T config) throws ConfigurationException { final ImmutableList errors = validator.validate(config); if (!errors.isEmpty()) { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java index 38082d3b89e..6a0d34a7926 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java @@ -49,12 +49,14 @@ public String getReasonPhrase() { } }; + private final Json json = new Json(); + @Override public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { - return Json.canDeserialize(type); + return json.canDeserialize(type); } @Override @@ -69,7 +71,7 @@ public Object readFrom(Class type, validating = validating || (annotation.annotationType() == Valid.class); } - final Object value = Json.read(entityStream, genericType); + final Object value = json.readValue(entityStream, genericType); if (validating) { final ImmutableList errors = VALIDATOR.validate(value); if (!errors.isEmpty()) { @@ -91,7 +93,7 @@ public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { - return Json.canSerialize(type); + return json.canSerialize(type); } @Override @@ -112,7 +114,7 @@ public void writeTo(Object t, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { try { - Json.write(entityStream, t); + json.writeValue(entityStream, t); } catch (EofException ignored) { // we don't care about these } catch (IOException e) { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/AnnotationSensitivePropertyNamingStrategy.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/AnnotationSensitivePropertyNamingStrategy.java index 6ec6ba74c28..ef46f8c8126 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/AnnotationSensitivePropertyNamingStrategy.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/AnnotationSensitivePropertyNamingStrategy.java @@ -6,15 +6,12 @@ import org.codehaus.jackson.map.introspect.AnnotatedMethod; import org.codehaus.jackson.map.introspect.AnnotatedParameter; -// TODO: 10/12/11 -- write tests for AnnotationSensitivePropertyNamingStrategy -// TODO: 10/12/11 -- write docs for AnnotationSensitivePropertyNamingStrategy - -public class AnnotationSensitivePropertyNamingStrategy extends PropertyNamingStrategy { +class AnnotationSensitivePropertyNamingStrategy extends PropertyNamingStrategy { static final AnnotationSensitivePropertyNamingStrategy INSTANCE = new AnnotationSensitivePropertyNamingStrategy(); private final PropertyNamingStrategy snakeCase; - public AnnotationSensitivePropertyNamingStrategy() { + AnnotationSensitivePropertyNamingStrategy() { super(); this.snakeCase = PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES; } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java index 1b769fae918..8fa81b28837 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java @@ -1,26 +1,19 @@ package com.yammer.dropwizard.json; import com.fasterxml.jackson.datatype.guava.GuavaModule; -import org.codehaus.jackson.JsonFactory; -import org.codehaus.jackson.JsonGenerator; -import org.codehaus.jackson.JsonNode; -import org.codehaus.jackson.JsonParser; +import org.codehaus.jackson.*; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.type.TypeReference; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import java.lang.reflect.Type; -// TODO: 10/12/11 -- write tests for JSON -// TODO: 10/12/11 -- write docs for JSON - /** - * It's configured to: + * A basic class for JSON parsing and generating. + * + *

          By default, {@link Json} is configured to:

          *
            *
          • Automatically close JSON content, if possible.
          • *
          • Automatically close input and output streams.
          • @@ -33,117 +26,503 @@ *
          */ public class Json { - private Json() { - // singleton - } - - static final JsonFactory factory; - static final ObjectMapper mapper; - static final TypeFactory typeFactory; + final JsonFactory factory; + final ObjectMapper mapper; + final TypeFactory typeFactory; - static { - factory = new MappingJsonFactory(); + /** + * Creates a new {@link Json} instance. + */ + public Json() { + this.factory = new MappingJsonFactory(); factory.enable(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT); factory.enable(JsonGenerator.Feature.AUTO_CLOSE_TARGET); factory.enable(JsonGenerator.Feature.QUOTE_FIELD_NAMES); factory.enable(JsonParser.Feature.ALLOW_COMMENTS); factory.enable(JsonParser.Feature.AUTO_CLOSE_SOURCE); - mapper = (ObjectMapper) factory.getCodec(); + this.mapper = (ObjectMapper) factory.getCodec(); mapper.setPropertyNamingStrategy(AnnotationSensitivePropertyNamingStrategy.INSTANCE); mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES); mapper.disable(SerializationConfig.Feature.WRITE_ENUMS_USING_TO_STRING); mapper.disable(DeserializationConfig.Feature.READ_ENUMS_USING_TO_STRING); mapper.registerModule(new GuavaModule()); - typeFactory = mapper.getTypeFactory(); + this.typeFactory = mapper.getTypeFactory(); } - private static JavaType constructType(Type type) { - return typeFactory.constructType(type); + /** + * Registers a module that can extend functionality provided by this class; for example, by + * adding providers for custom serializers and deserializers. + * + * @param module Module to register + * @see ObjectMapper#registerModule(org.codehaus.jackson.map.Module) + */ + public void registerModule(Module module) { + mapper.registerModule(module); } - public static void registerModule(Module module) { - mapper.registerModule(module); + /** + * Returns true if the given {@link DeserializationConfig.Feature} is enabled. + * + * @param feature a given feature + * @return {@code true} if {@code feature} is enabled + * @see ObjectMapper#isEnabled(org.codehaus.jackson.map.DeserializationConfig.Feature) + */ + public boolean isEnabled(DeserializationConfig.Feature feature) { + return mapper.isEnabled(feature); } - public static void configure(JsonGenerator.Feature feature, boolean enabled) { - mapper.configure(feature, enabled); + /** + * Enables the given {@link DeserializationConfig.Feature}s. + * + * @param features a set of features to enable + * @see ObjectMapper#enable(org.codehaus.jackson.map.DeserializationConfig.Feature...) + */ + public void enable(DeserializationConfig.Feature... features) { + mapper.enable(features); } - public static void configure(JsonParser.Feature feature, boolean enabled) { - mapper.configure(feature, enabled); + /** + * Disables the given {@link DeserializationConfig.Feature}s. + * + * @param features a set of features to disable + * @see ObjectMapper#disable(org.codehaus.jackson.map.DeserializationConfig.Feature...) + */ + public void disable(DeserializationConfig.Feature... features) { + mapper.disable(features); } - public static void configure(SerializationConfig.Feature feature, boolean enabled) { - mapper.configure(feature, enabled); + /** + * Returns true if the given {@link SerializationConfig.Feature} is enabled. + * + * @param feature a given feature + * @return {@code true} if {@code feature} is enabled + * @see ObjectMapper#isEnabled(org.codehaus.jackson.map.SerializationConfig.Feature) + */ + public boolean isEnabled(SerializationConfig.Feature feature) { + return mapper.isEnabled(feature); } - public static void configure(DeserializationConfig.Feature feature, boolean enabled) { - mapper.configure(feature, enabled); + /** + * Enables the given {@link SerializationConfig.Feature}s. + * + * @param features a set of features to enable + * @see ObjectMapper#enable(org.codehaus.jackson.map.SerializationConfig.Feature...) + */ + public void enable(SerializationConfig.Feature... features) { + mapper.enable(features); } - public static boolean canSerialize(Class type) { + /** + * Disables the given {@link SerializationConfig.Feature}s. + * + * @param features a set of features to disable + * @see ObjectMapper#disable(org.codehaus.jackson.map.SerializationConfig.Feature...) + */ + public void disable(SerializationConfig.Feature... features) { + mapper.disable(features); + } + + /** + * Returns true if the given {@link JsonGenerator.Feature} is enabled. + * + * @param feature a given feature + * @return {@code true} if {@code feature} is enabled + * @see ObjectMapper#isEnabled(org.codehaus.jackson.JsonGenerator.Feature) + */ + public boolean isEnabled(JsonGenerator.Feature feature) { + return mapper.isEnabled(feature); + } + + /** + * Enables the given {@link JsonGenerator.Feature}s. + * + * @param features a set of features to enable + * @see JsonFactory#enable(org.codehaus.jackson.JsonGenerator.Feature) + */ + public void enable(JsonGenerator.Feature... features) { + for (JsonGenerator.Feature feature : features) { + factory.enable(feature); + } + } + + /** + * Disables the given {@link JsonGenerator.Feature}s. + * + * @param features a set of features to disable + * @see JsonFactory#disable(org.codehaus.jackson.JsonGenerator.Feature) + */ + public void disable(JsonGenerator.Feature... features) { + for (JsonGenerator.Feature feature : features) { + factory.disable(feature); + } + } + + /** + * Returns true if the given {@link JsonParser.Feature} is enabled. + * + * @param feature a given feature + * @return {@code true} if {@code feature} is enabled + * @see ObjectMapper#isEnabled(org.codehaus.jackson.JsonParser.Feature) + */ + public boolean isEnabled(JsonParser.Feature feature) { + return mapper.isEnabled(feature); + } + + /** + * Enables the given {@link JsonParser.Feature}s. + * + * @param features a set of features to enable + * @see JsonFactory#enable(org.codehaus.jackson.JsonParser.Feature) + */ + public void enable(JsonParser.Feature... features) { + for (JsonParser.Feature feature : features) { + factory.enable(feature); + } + } + + /** + * Disables the given {@link JsonParser.Feature}s. + * + * @param features a set of features to disable + * @see JsonFactory#disable(org.codehaus.jackson.JsonParser.Feature) + */ + public void disable(JsonParser.Feature... features) { + for (JsonParser.Feature feature : features) { + factory.disable(feature); + } + } + + /** + * Returns {@code true} if the mapper can find a serializer for instances of given class + * (potentially serializable), {@code false} otherwise (not serializable). + * + * @param type the type of object to serialize + * @return {@code true} if instances of {@code type} are potentially serializable + */ + public boolean canSerialize(Class type) { return mapper.canSerialize(type); } - public static boolean canDeserialize(Class type) { + /** + * Returns {@code true} if the mapper can find a deserializer for instances of given class + * (potentially deserializable), {@code false} otherwise (not deserializable). + * + * @param type the type of object to deserialize + * @return {@code true} if instances of {@code type} are potentially deserializable + */ + public boolean canDeserialize(Class type) { return mapper.canDeserialize(constructType(type)); } - public static void write(OutputStream output, Object o) throws IOException { - mapper.writeValue(output, o); + /** + * Deserializes the given {@link File} as an instance of the given type. + * + * @param src a JSON {@link File} + * @param valueType the {@link Class} to deserialize {@code src} as + * @param the type of {@code valueType} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error reading from {@code src} or parsing its contents + */ + public T readValue(File src, Class valueType) throws IOException { + return mapper.readValue(src, valueType); } - public static void write(File file, Object o) throws IOException { - mapper.writeValue(file, o); + /** + * Deserializes the given {@link File} as an instance of the given type. + * + * @param src a JSON {@link File} + * @param valueTypeRef a {@link TypeReference} of the type to deserialize {@code src} as + * @param the type of {@code valueTypeRef} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error reading from {@code src} or parsing its contents + */ + public T readValue(File src, TypeReference valueTypeRef) throws IOException { + return mapper.readValue(src, valueTypeRef); } - public static String write(Object o) throws IOException { - return mapper.writeValueAsString(o); + /** + * Deserializes the given {@link String} as an instance of the given type. + * + * @param content a JSON {@link String} + * @param valueType the {@link Class} to deserialize {@code content} as + * @param the type of {@code valueType} + * @return {@code content} as an instance of {@code T} + * @throws IOException if there is an error parsing {@code content} + */ + public T readValue(String content, Class valueType) throws IOException { + return mapper.readValue(content, valueType); } - public static T read(InputStream input, Class type) throws IOException { - return mapper.readValue(input, constructType(type)); + /** + * Deserializes the given {@link String} as an instance of the given type. + * + * @param content a JSON {@link String} + * @param valueTypeRef a {@link TypeReference} of the type to deserialize {@code content} as + * @param the type of {@code valueTypeRef} + * @return {@code content} as an instance of {@code T} + * @throws IOException if there is an error parsing {@code content} + */ + public T readValue(String content, TypeReference valueTypeRef) throws IOException { + return mapper.readValue(content, valueTypeRef); } - public static T read(InputStream input, Type type) throws IOException { - return mapper.readValue(input, constructType(type)); + /** + * Deserializes the given {@link Reader} as an instance of the given type. + * + * @param src a JSON {@link Reader} + * @param valueType the {@link Class} to deserialize {@code src} as + * @param the type of {@code valueType} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error reading from {@code src} or parsing its contents + */ + public T readValue(Reader src, Class valueType) throws IOException { + return mapper.readValue(src, valueType); } - public static T read(InputStream input, TypeReference ref) throws IOException { - return mapper.readValue(input, ref); + /** + * Deserializes the given {@link Reader} as an instance of the given type. + * + * @param src a JSON {@link Reader} + * @param valueTypeRef a {@link TypeReference} of the type to deserialize {@code src} as + * @param the type of {@code valueTypeRef} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error reading from {@code src} or parsing its contents + */ + public T readValue(Reader src, TypeReference valueTypeRef) throws IOException { + return mapper.readValue(src, valueTypeRef); } - public static T read(JsonNode json, Class klass) throws IOException { - return mapper.readValue(json, constructType(klass)); + /** + * Deserializes the given {@link InputStream} as an instance of the given type. + * + * @param src a JSON {@link InputStream} + * @param valueType the {@link Class} to deserialize {@code src} as + * @param the type of {@code valueType} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error reading from {@code src} or parsing its contents + */ + public T readValue(InputStream src, Class valueType) throws IOException { + return mapper.readValue(src, valueType); } - public static T read(JsonNode json, TypeReference ref) throws IOException { - return mapper.readValue(json, ref); + /** + * Deserializes the given {@link InputStream} as an instance of the given type. + * + * @param src a JSON {@link InputStream} + * @param valueTypeRef a {@link TypeReference} of the type to deserialize {@code src} as + * @param the type of {@code valueTypeRef} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error reading from {@code src} or parsing its contents + */ + public T readValue(InputStream src, TypeReference valueTypeRef) throws IOException { + return mapper.readValue(src, valueTypeRef); } - public static T read(File file, Class klass) throws IOException { - return mapper.readValue(file, constructType(klass)); + /** + * Deserializes the given {@link InputStream} as an instance of the given type. + * + * @param src a JSON {@link InputStream} + * @param valueType the {@link Type} to deserialize {@code src} as + * @param the type of {@code valueType} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error reading from {@code src} or parsing its contents + */ + public T readValue(InputStream src, Type valueType) throws IOException { + return mapper.readValue(src, constructType(valueType)); } - public static T read(File file, TypeReference ref) throws IOException { - return mapper.readValue(file, ref); + /** + * Deserializes the given byte array as an instance of the given type. + * + * @param src a JSON byte array + * @param valueType the {@link Class} to deserialize {@code src} as + * @param the type of {@code valueType} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error parsing {@code src} + */ + public T readValue(byte[] src, Class valueType) throws IOException { + return mapper.readValue(src, valueType); } - public static T read(String json, Class klass) throws IOException { - return mapper.readValue(json, constructType(klass)); + /** + * Deserializes a subset of the given byte array as an instance of the given type. + * + * @param src a JSON byte array + * @param offset the offset into {@code src} of the subset + * @param len the length of the subset of {@code src} + * @param valueType the {@link Class} to deserialize {@code src} as + * @param the type of {@code valueType} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error parsing {@code src} + */ + public T readValue(byte[] src, int offset, int len, Class valueType) throws IOException { + return mapper.readValue(src, offset, len, valueType); } - public static T read(String json, TypeReference ref) throws IOException { - return mapper.readValue(json, ref); + /** + * Deserializes the given byte array as an instance of the given type. + * + * @param src a JSON byte array + * @param valueTypeRef a {@link TypeReference} of the type to deserialize {@code src} as + * @param the type of {@code valueTypeRef} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error parsing {@code src} + */ + public T readValue(byte[] src, TypeReference valueTypeRef) throws IOException { + return mapper.readValue(src, valueTypeRef); } - public static T read(byte[] json, Class klass) throws IOException { - return mapper.readValue(json, constructType(klass)); + /** + * Deserializes a subset of the given byte array as an instance of the given type. + * + * @param src a JSON byte array + * @param offset the offset into {@code src} of the subset + * @param len the length of the subset of {@code src} + * @param valueTypeRef a {@link TypeReference} of the type to deserialize {@code src} as + * @param the type of {@code valueTypeRef} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error parsing {@code src} + */ + public T readValue(byte[] src, int offset, int len, TypeReference valueTypeRef) throws IOException { + return mapper.readValue(src, offset, len, valueTypeRef); } - public static T read(byte[] json, TypeReference ref) throws IOException { - return mapper.readValue(json, ref); + /** + * Deserializes the given {@link JsonNode} as an instance of the given type. + * + * @param root a {@link JsonNode} + * @param valueType the {@link Class} to deserialize {@code src} as + * @param the type of {@code valueType} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error mapping {@code src} to {@code T} + */ + public T readValue(JsonNode root, Class valueType) throws IOException { + return mapper.readValue(root, valueType); + } + + /** + * Deserializes the given {@link JsonNode} as an instance of the given type. + * + * @param root a {@link JsonNode} + * @param valueTypeRef a {@link TypeReference} of the type to deserialize {@code src} as + * @param the type of {@code valueTypeRef} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error mapping {@code src} to {@code T} + */ + public T readValue(JsonNode root, TypeReference valueTypeRef) throws IOException { + return mapper.readValue(root, valueTypeRef); + } + + /** + * Serializes the given object to the given {@link File}. + * + * @param output the {@link File} to which the JSON will be written + * @param value the object to serialize into {@code output} + * @throws IOException if there is an error writing to {@code output} or serializing {@code + * value} + */ + public void writeValue(File output, Object value) throws IOException { + mapper.writeValue(output, value); + } + + /** + * Serializes the given object to the given {@link OutputStream}. + * + * @param output the {@link OutputStream} to which the JSON will be written + * @param value the object to serialize into {@code output} + * @throws IOException if there is an error writing to {@code output} or serializing {@code + * value} + */ + public void writeValue(OutputStream output, Object value) throws IOException { + mapper.writeValue(output, value); + } + + /** + * Serializes the given object to the given {@link Writer}. + * + * @param output the {@link Writer} to which the JSON will be written + * @param value the object to serialize into {@code output} + * @throws IOException if there is an error writing to {@code output} or serializing {@code + * value} + */ + public void writeValue(Writer output, Object value) throws IOException { + mapper.writeValue(output, value); + } + + /** + * Returns the given object as a JSON string. + * + * @param value an object + * @return {@code value} as a JSON string + * @throws IllegalArgumentException if there is an error encoding {@code value} + */ + public String writeValueAsString(Object value) throws IllegalArgumentException { + try { + return mapper.writeValueAsString(value); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Returns the given object as a JSON byte array. + * + * @param value an object + * @return {@code value} as a JSON byte array + * @throws IllegalArgumentException if there is an error encoding {@code value} + */ + public byte[] writeValueAsBytes(Object value) throws IllegalArgumentException { + try { + return mapper.writeValueAsBytes(value); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Returns the given object as a {@link JsonNode}. + * + * @param value an object + * @return {@code value} as a {@link JsonNode} + * @throws IllegalArgumentException if there is an error encoding {@code value} + */ + public JsonNode writeValueAsTree(Object value) throws IllegalArgumentException { + return mapper.valueToTree(value); + } + + /** + * Deserializes the given YAML {@link File} as an instance of the given type. + *

          N.B.: All tags, comments, and non-JSON elements of the YAML file will be elided.

          + * + * @param src a YAML {@link File} + * @param valueType the {@link Class} to deserialize {@code src} as + * @param the type of {@code valueType} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error reading from {@code src} or parsing its contents + */ + public T readYamlValue(File src, Class valueType) throws IOException { + final YamlConverter converter = new YamlConverter(this, factory); + return mapper.readValue(converter.convert(src), valueType); + } + + /** + * Deserializes the given YAML {@link File} as an instance of the given type. + *

          N.B.: All tags, comments, and non-JSON elements of the YAML file will be elided.

          + * + * @param src a YAML {@link File} + * @param valueTypeRef a {@link TypeReference} of the type to deserialize {@code src} as + * @param the type of {@code valueTypeRef} + * @return the contents of {@code src} as an instance of {@code T} + * @throws IOException if there is an error reading from {@code src} or parsing its contents + */ + public T readYamlValue(File src, TypeReference valueTypeRef) throws IOException { + final YamlConverter converter = new YamlConverter(this, factory); + return mapper.readValue(converter.convert(src), valueTypeRef); + } + + private JavaType constructType(Type type) { + return typeFactory.constructType(type); } } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/YamlConverter.java similarity index 72% rename from dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java rename to dropwizard-core/src/main/java/com/yammer/dropwizard/json/YamlConverter.java index 9d701a034c8..730711e3036 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Yaml.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/YamlConverter.java @@ -1,33 +1,42 @@ package com.yammer.dropwizard.json; import com.yammer.dropwizard.logging.Log; +import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonNode; -import org.codehaus.jackson.type.TypeReference; import org.yaml.snakeyaml.nodes.*; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; -public class Yaml { - private static final Log LOG = Log.forClass(Yaml.class); - private final JsonNode node; +class YamlConverter { + private static final Log LOG = Log.forClass(YamlConverter.class); + private final Json json; + private final JsonFactory factory; - public Yaml(File file) throws IOException { + YamlConverter(Json json, JsonFactory factory) { + this.factory = factory; + this.json = json; + } + + JsonNode convert(File file) throws IOException { final ByteArrayOutputStream output = new ByteArrayOutputStream(); - final JsonGenerator json = Json.factory.createJsonGenerator(output).useDefaultPrettyPrinter(); + final JsonGenerator generator = factory.createJsonGenerator(output).useDefaultPrettyPrinter(); final FileReader reader = new FileReader(file); try { final Node yaml = new org.yaml.snakeyaml.Yaml().compose(reader); - build(yaml, json); - json.close(); + build(yaml, generator); + generator.close(); LOG.debug("Parsed {} as:\n {}", file, output.toString()); - this.node = Json.read(output.toByteArray(), JsonNode.class); + return json.readValue(output.toByteArray(), JsonNode.class); } finally { reader.close(); } } - private static void build(Node yaml, JsonGenerator json) throws IOException { + private void build(Node yaml, JsonGenerator json) throws IOException { if (yaml instanceof MappingNode) { final MappingNode mappingNode = (MappingNode) yaml; json.writeStartObject(); @@ -59,12 +68,4 @@ private static void build(Node yaml, JsonGenerator json) throws IOException { } } } - - public T read(Class klass) throws IOException { - return Json.read(node, klass); - } - - public T read(TypeReference ref) throws IOException { - return Json.read(node, ref); - } } diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/json/tests/JsonTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/json/tests/JsonTest.java index c8f1c3a578e..610eca11232 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/json/tests/JsonTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/json/tests/JsonTest.java @@ -1,5 +1,303 @@ package com.yammer.dropwizard.json.tests; +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import com.google.common.io.Resources; +import com.yammer.dropwizard.json.Json; +import com.yammer.dropwizard.json.JsonSnakeCase; +import org.codehaus.jackson.JsonGenerator; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.JsonParser; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.SerializationConfig; +import org.codehaus.jackson.node.TextNode; +import org.codehaus.jackson.type.TypeReference; +import org.junit.Test; + +import java.io.*; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + public class JsonTest { + @JsonSnakeCase + private static class SnakeCaseExample { + @JsonProperty + private String firstName; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + } + + private final Json json = new Json(); + + @Test + public void itCanSerializeSupportedClasses() throws Exception { + assertThat(json.canSerialize(String.class), + is(true)); + } + + @Test + public void itCanDeserializeSupportedClasses() throws Exception { + assertThat(json.canDeserialize(String.class), + is(true)); + } + + @Test + public void enablesAndDisablesJsonGeneratorFeatures() throws Exception { + assertThat(json.isEnabled(JsonGenerator.Feature.ESCAPE_NON_ASCII), + is(false)); + + json.enable(JsonGenerator.Feature.ESCAPE_NON_ASCII); + + assertThat(json.isEnabled(JsonGenerator.Feature.ESCAPE_NON_ASCII), + is(true)); + + json.disable(JsonGenerator.Feature.ESCAPE_NON_ASCII); + + assertThat(json.isEnabled(JsonGenerator.Feature.ESCAPE_NON_ASCII), + is(false)); + } + + @Test + public void enablesAndDisablesJsonParserFeatures() throws Exception { + assertThat(json.isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER), + is(false)); + + json.enable(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER); + + assertThat(json.isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER), + is(true)); + + json.disable(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER); + + assertThat(json.isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER), + is(false)); + } + + @Test + public void enablesAndDisablesJsonSerializationFeatures() throws Exception { + assertThat(json.isEnabled(SerializationConfig.Feature.INDENT_OUTPUT), + is(false)); + + json.enable(SerializationConfig.Feature.INDENT_OUTPUT); + + assertThat(json.isEnabled(SerializationConfig.Feature.INDENT_OUTPUT), + is(true)); + + json.disable(SerializationConfig.Feature.INDENT_OUTPUT); + + assertThat(json.isEnabled(SerializationConfig.Feature.INDENT_OUTPUT), + is(false)); + } + + @Test + public void enablesAndDisablesJsonDeserializationFeatures() throws Exception { + assertThat(json.isEnabled(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY), + is(false)); + + json.enable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY); + + assertThat(json.isEnabled(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY), + is(true)); + + json.disable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY); + + assertThat(json.isEnabled(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY), + is(false)); + } + + @Test + public void closesJsonContentByDefault() throws Exception { + assertThat(json.isEnabled(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT), + is(true)); + } + + @Test + public void closesTargetsByDefault() throws Exception { + assertThat(json.isEnabled(JsonGenerator.Feature.AUTO_CLOSE_TARGET), + is(true)); + } + + @Test + public void quotesFieldNamesByDefault() throws Exception { + assertThat(json.isEnabled(JsonGenerator.Feature.QUOTE_FIELD_NAMES), + is(true)); + } + + @Test + public void allowsCommentsByDefault() throws Exception { + assertThat(json.isEnabled(JsonParser.Feature.ALLOW_COMMENTS), + is(true)); + } + + @Test + public void closesSourcesByDefault() throws Exception { + assertThat(json.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE), + is(true)); + } + + @Test + public void readsValuesFromFiles() throws Exception { + assertThat(json.readValue(new File(Resources.getResource("json/string.json").getFile()), + String.class), + is("a string")); + + assertThat(json.readValue(new File(Resources.getResource("json/string.json").getFile()), + new TypeReference() {}), + is("a string")); + } + + @Test + public void readsValuesFromStrings() throws Exception { + assertThat(json.readValue(Resources.toString(Resources.getResource("json/string.json"), + Charsets.UTF_8), + String.class), + is("a string")); + + assertThat(json.readValue(Resources.toString(Resources.getResource("json/string.json"), + Charsets.UTF_8), + new TypeReference() {}), + is("a string")); + } + + @Test + public void readsValuesFromReaders() throws Exception { + assertThat(json.readValue(new FileReader(Resources.getResource("json/string.json").getFile()), + String.class), + is("a string")); + + assertThat(json.readValue(new FileReader(Resources.getResource("json/string.json").getFile()), + new TypeReference() {}), + is("a string")); + } + + @Test + public void readsValuesFromInputStreams() throws Exception { + assertThat(json.readValue(new FileInputStream(Resources.getResource("json/string.json").getFile()), + String.class), + is("a string")); + + assertThat(json.readValue(new FileInputStream(Resources.getResource("json/string.json").getFile()), + new TypeReference() {}), + is("a string")); + } + + @Test + public void readsValuesFromByteArrays() throws Exception { + assertThat(json.readValue(Resources.toByteArray(Resources.getResource("json/string.json")), + String.class), + is("a string")); + + assertThat(json.readValue(Resources.toByteArray(Resources.getResource("json/string.json")), + 0, 10, String.class), + is("a string")); + + assertThat(json.readValue(Resources.toByteArray(Resources.getResource("json/string.json")), + new TypeReference() {}), + is("a string")); + + assertThat(json.readValue(Resources.toByteArray(Resources.getResource("json/string.json")), + 0, 10, new TypeReference() {}), + is("a string")); + } + + @Test + public void readsValuesFromJsonNodes() throws Exception { + final JsonNode node = json.readValue(Resources.toByteArray(Resources.getResource( + "json/string.json")), JsonNode.class); + + assertThat(json.readValue(node, String.class), + is("a string")); + + assertThat(json.readValue(node, new TypeReference() {}), + is("a string")); + } + + @Test + public void serializesObjectsToJsonNodes() throws Exception { + assertThat(json.writeValueAsTree("a string"), + is((JsonNode) TextNode.valueOf("a string"))); + } + + @Test + public void serializesObjectsToStrings() throws Exception { + assertThat(json.writeValueAsString("a string"), + is("\"a string\"")); + } + + @Test + public void serializesObjectsToByteArrays() throws Exception { + assertThat(json.writeValueAsBytes("a string"), + is("\"a string\"".getBytes(Charsets.UTF_8))); + } + + @Test + public void serializesObjectsToOutputStreams() throws Exception { + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + + json.writeValue(output, "a string"); + + assertThat(output.toString(), + is("\"a string\"")); + } + + @Test + public void serializesObjectsToWriters() throws Exception { + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + final OutputStreamWriter writer = new OutputStreamWriter(output); + + json.writeValue(writer, "a string"); + + assertThat(output.toString(), + is("\"a string\"")); + } + + @Test + public void serializesObjectsToFiles() throws Exception { + final File tmp = File.createTempFile("json-test", "json"); + try { + json.writeValue(tmp, "a string"); + + assertThat(Files.toString(tmp, Charsets.UTF_8), + is("\"a string\"")); + } finally { + tmp.deleteOnExit(); + } + } + + @Test + public void readsValuesFromYamlFiles() throws Exception { + assertThat(json.readYamlValue(new File(Resources.getResource("yaml/string.yml").getFile()), + String.class), + is("a string")); + + assertThat(json.readYamlValue(new File(Resources.getResource("yaml/string.yml").getFile()), + new TypeReference() {}), + is("a string")); + } + + @Test + public void deserializesSnakeCaseFieldNames() throws Exception { + final SnakeCaseExample example = json.readValue("{\"first_name\":\"Coda\"}", + SnakeCaseExample.class); + + assertThat(example.getFirstName(), + is("Coda")); + } + + @Test + public void serializesSnakeCaseFieldNames() throws Exception { + final SnakeCaseExample example = new SnakeCaseExample(); + example.setFirstName("Coda"); + assertThat(json.writeValueAsString(example), + is("{\"first_name\":\"Coda\"}")); + } } diff --git a/dropwizard-core/src/test/resources/json/string.json b/dropwizard-core/src/test/resources/json/string.json index 3e68cc54150..9be5b8874f7 100644 --- a/dropwizard-core/src/test/resources/json/string.json +++ b/dropwizard-core/src/test/resources/json/string.json @@ -1 +1 @@ -"wahoo" +"a string" diff --git a/dropwizard-core/src/test/resources/yaml/string.yml b/dropwizard-core/src/test/resources/yaml/string.yml new file mode 100644 index 00000000000..9be5b8874f7 --- /dev/null +++ b/dropwizard-core/src/test/resources/yaml/string.yml @@ -0,0 +1 @@ +"a string" diff --git a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java index 82fb794d10d..25f318a4556 100644 --- a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java +++ b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java @@ -23,6 +23,8 @@ * */ public class JsonHelpers { + private static final Json JSON = new Json(); + private JsonHelpers() { /* singleton */ } /** @@ -33,7 +35,7 @@ private JsonHelpers() { /* singleton */ } * @throws IOException if there is an error writing {@code object} as JSON */ public static JsonNode asJson(Object object) throws IOException { - return Json.read(Json.write(object), JsonNode.class); + return JSON.writeValueAsTree(object); } /** @@ -46,7 +48,7 @@ public static JsonNode asJson(Object object) throws IOException { * @throws IOException if there is an error reading {@code json} as an instance of {@code T} */ public static T fromJson(JsonNode json, Class klass) throws IOException { - return Json.read(json, klass); + return JSON.readValue(json, klass); } /** @@ -59,10 +61,10 @@ public static T fromJson(JsonNode json, Class klass) throws IOException { * @throws IOException if there is an error reading {@code json} as an instance of {@code T} */ public static T fromJson(JsonNode json, TypeReference reference) throws IOException { - return Json.read(json, reference); + return JSON.readValue(json, reference); } public static JsonNode jsonFixture(String filename) throws IOException { - return Json.read(fixture(filename), JsonNode.class); + return JSON.readValue(fixture(filename), JsonNode.class); } } From 8accd66a54e59b8ea98ee29eba4be764c289afe7 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 3 Feb 2012 19:19:36 -0800 Subject: [PATCH 0200/2771] Move Level deserialization into its own module. --- .../config/LoggingConfiguration.java | 7 --- .../java/com/yammer/dropwizard/json/Json.java | 1 + .../dropwizard/json/LevelDeserializer.java | 16 ------ .../yammer/dropwizard/json/Log4jModule.java | 49 +++++++++++++++++++ 4 files changed, 50 insertions(+), 23 deletions(-) delete mode 100644 dropwizard-core/src/main/java/com/yammer/dropwizard/json/LevelDeserializer.java create mode 100644 dropwizard-core/src/main/java/com/yammer/dropwizard/json/Log4jModule.java diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java index 0d6b9539c25..87de43ed24a 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/LoggingConfiguration.java @@ -1,11 +1,9 @@ package com.yammer.dropwizard.config; import com.google.common.collect.ImmutableMap; -import com.yammer.dropwizard.json.LevelDeserializer; import com.yammer.dropwizard.util.Size; import org.apache.log4j.Level; import org.codehaus.jackson.annotate.JsonProperty; -import org.codehaus.jackson.map.annotate.JsonDeserialize; import javax.validation.Valid; import javax.validation.constraints.Max; @@ -21,7 +19,6 @@ public static class ConsoleConfiguration { @NotNull @JsonProperty - @JsonDeserialize(using = LevelDeserializer.class) private Level threshold = Level.ALL; public boolean isEnabled() { @@ -40,7 +37,6 @@ public static class FileConfiguration { @NotNull @JsonProperty - @JsonDeserialize(using = LevelDeserializer.class) private Level threshold = Level.ALL; @NotNull @@ -83,7 +79,6 @@ public static class SyslogConfiguration { @NotNull @JsonProperty - @JsonDeserialize(using = LevelDeserializer.class) private Level threshold = Level.ALL; @NotNull @@ -114,12 +109,10 @@ public String getFacility() { @NotNull @JsonProperty - @JsonDeserialize(using = LevelDeserializer.class) private Level level = Level.INFO; @NotNull @JsonProperty - @JsonDeserialize(contentUsing = LevelDeserializer.class) private ImmutableMap loggers = ImmutableMap.of(); @Valid diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java index 8fa81b28837..bdf35a96308 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java @@ -47,6 +47,7 @@ public Json() { mapper.disable(SerializationConfig.Feature.WRITE_ENUMS_USING_TO_STRING); mapper.disable(DeserializationConfig.Feature.READ_ENUMS_USING_TO_STRING); mapper.registerModule(new GuavaModule()); + mapper.registerModule(new Log4jModule()); this.typeFactory = mapper.getTypeFactory(); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/LevelDeserializer.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/LevelDeserializer.java deleted file mode 100644 index 916edec0d61..00000000000 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/LevelDeserializer.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.yammer.dropwizard.json; - -import org.apache.log4j.Level; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.map.DeserializationContext; -import org.codehaus.jackson.map.JsonDeserializer; - -import java.io.IOException; - -public class LevelDeserializer extends JsonDeserializer { - @Override - public Level deserialize(JsonParser jp, - DeserializationContext ctxt) throws IOException { - return Level.toLevel(jp.getText()); - } -} diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Log4jModule.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Log4jModule.java new file mode 100644 index 00000000000..7260e39fd5f --- /dev/null +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Log4jModule.java @@ -0,0 +1,49 @@ +package com.yammer.dropwizard.json; + +import org.apache.log4j.Level; +import org.codehaus.jackson.JsonParser; +import org.codehaus.jackson.Version; +import org.codehaus.jackson.map.*; +import org.codehaus.jackson.type.JavaType; + +import java.io.IOException; + +class Log4jModule extends Module { + private static class LevelDeserializer extends JsonDeserializer { + @Override + public Level deserialize(JsonParser jp, + DeserializationContext ctxt) throws IOException { + return Level.toLevel(jp.getText()); + } + } + + private static class Log4jDeserializers extends Deserializers.Base { + @Override + public JsonDeserializer findBeanDeserializer(JavaType type, + DeserializationConfig config, + DeserializerProvider provider, + BeanDescription beanDesc, + BeanProperty property) throws JsonMappingException { + if (Level.class.isAssignableFrom(type.getRawClass())) { + return new LevelDeserializer(); + } + + return super.findBeanDeserializer(type, config, provider, beanDesc, property); + } + } + + @Override + public String getModuleName() { + return "log4j"; + } + + @Override + public Version version() { + return Version.unknownVersion(); + } + + @Override + public void setupModule(SetupContext context) { + context.addDeserializers(new Log4jDeserializers()); + } +} From 4291d037a5a26c6d5bca520a92813589facd2cb8 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 3 Feb 2012 19:41:07 -0800 Subject: [PATCH 0201/2771] Add service-specific Jackson modules. This allows each service to specify Jackson modules used to parse configuration files and JSON request entities and to generate JSON response entities. --- .../client/JerseyClientFactory.java | 2 +- .../yammer/dropwizard/AbstractService.java | 24 +++ .../java/com/yammer/dropwizard/Service.java | 2 +- .../yammer/dropwizard/bundles/JavaBundle.java | 16 +- .../dropwizard/cli/ConfiguredCommand.java | 6 +- .../yammer/dropwizard/cli/ManagedCommand.java | 2 +- .../yammer/dropwizard/cli/ServerCommand.java | 2 +- .../config/ConfigurationFactory.java | 13 +- .../yammer/dropwizard/config/Environment.java | 10 +- .../jersey/JacksonMessageBodyProvider.java | 10 +- .../bundles/tests/JavaBundleTest.java | 14 +- .../config/tests/GzipConfigurationTest.java | 4 +- .../config/tests/HttpConfigurationTest.java | 4 +- .../tests/RequestLogConfigurationTest.java | 4 +- .../dropwizard/bundles/ScalaBundle.java | 11 +- .../com/yammer/dropwizard/ScalaService.scala | 4 +- .../examples/ExampleConfiguration.scala | 2 + .../dropwizard/examples/ExampleService.scala | 3 +- .../src/test/scala/scala-example.yml | 147 ++++++++++++++++++ .../dropwizard/testing/ResourceTest.java | 14 +- 20 files changed, 264 insertions(+), 30 deletions(-) create mode 100644 dropwizard-scala_2.9.1/src/test/scala/scala-example.yml diff --git a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java index 58c83d48ed2..97db28193bf 100644 --- a/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java +++ b/dropwizard-client/src/main/java/com/yammer/dropwizard/client/JerseyClientFactory.java @@ -26,7 +26,7 @@ public JerseyClient build(Environment environment) { final ApacheHttpClient4Handler handler = new ApacheHttpClient4Handler(client, null, true); final ApacheHttpClient4Config config = new DefaultApacheHttpClient4Config(); - config.getSingletons().add(new JacksonMessageBodyProvider()); + config.getSingletons().add(new JacksonMessageBodyProvider(environment.getService().getJacksonModules())); final JerseyClient jerseyClient = new JerseyClient(handler, config); jerseyClient.setExecutorService(environment.managedExecutorService("jersey-client-%d", diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java index 550b06897ea..619747731f1 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java @@ -10,6 +10,7 @@ import com.yammer.dropwizard.config.Configuration; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.config.LoggingFactory; +import org.codehaus.jackson.map.Module; import java.lang.reflect.ParameterizedType; import java.util.Arrays; @@ -24,6 +25,8 @@ */ @SuppressWarnings("EmptyMethod") public abstract class AbstractService { + private static final Module[] NO_MODULES = new Module[0]; + static { // make sure spinning up Hibernate Validator doesn't yell at us LoggingFactory.bootstrap(); @@ -32,6 +35,7 @@ public abstract class AbstractService { private final String name; private final List bundles; private final List> configuredBundles; + private final List modules; private final SortedMap commands; /** @@ -43,6 +47,7 @@ protected AbstractService(String name) { this.name = name; this.bundles = Lists.newArrayList(); this.configuredBundles = Lists.newArrayList(); + this.modules = Lists.newArrayList(); this.commands = Maps.newTreeMap(); addCommand(new ServerCommand(getConfigurationClass())); } @@ -115,6 +120,16 @@ protected final void addCommand(ConfiguredCommand command) { commands.put(command.getName(), command); } + /** + * Registers a Jackson {@link Module} which the service will use to parse the configuration file + * and to parse/generate any {@code application/json} entities. + * + * @param module a {@link Module} + */ + protected final void addJacksonModule(Module module) { + modules.add(module); + } + /** * When the service runs, this is called after the {@link Bundle}s are run. Override it to add * providers, resources, etc. for your service. @@ -164,6 +179,15 @@ public final void run(String[] arguments) throws Exception { } } + /** + * Returns a list of Jackson {@link Module}s used to parse JSON (and the configuration files). + * + * @return a list of {@link Module}s + */ + public ImmutableList getJacksonModules() { + return ImmutableList.copyOf(modules); + } + private static boolean isHelp(String[] arguments) { return (arguments.length == 0) || ((arguments.length == 1) && diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java index 0d3237ff24d..e73fbf617d3 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/Service.java @@ -12,7 +12,7 @@ public abstract class Service extends AbstractService { protected Service(String name) { super(name); - addBundle(new JavaBundle()); + addBundle(new JavaBundle(this)); checkForScalaExtensions(); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java index 3a2b0ffbb33..4eaf38764d9 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/bundles/JavaBundle.java @@ -1,27 +1,31 @@ package com.yammer.dropwizard.bundles; +import com.google.common.collect.ImmutableList; import com.yammer.dropwizard.Bundle; +import com.yammer.dropwizard.Service; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.jersey.JacksonMessageBodyProvider; import com.yammer.dropwizard.jersey.OauthTokenProvider; import com.yammer.dropwizard.jersey.OptionalQueryParamInjectableProvider; -import java.util.List; - -import static java.util.Arrays.asList; - /** * Initializes the service with support for Java classes. */ public class JavaBundle implements Bundle { - public static final List DEFAULT_PROVIDERS = asList( + public static final ImmutableList DEFAULT_PROVIDERS = ImmutableList.of( new OptionalQueryParamInjectableProvider(), - new JacksonMessageBodyProvider(), new OauthTokenProvider() ); + private final Service service; + + public JavaBundle(Service service) { + this.service = service; + } + @Override public void initialize(Environment environment) { + environment.addProvider(new JacksonMessageBodyProvider(service.getJacksonModules())); for (Object provider : DEFAULT_PROVIDERS) { environment.addProvider(provider); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java index 2a771003ac1..75b250038f3 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java @@ -7,6 +7,7 @@ import com.yammer.dropwizard.config.LoggingFactory; import com.yammer.dropwizard.validation.Validator; import org.apache.commons.cli.CommandLine; +import org.codehaus.jackson.map.Module; import java.io.File; import java.lang.reflect.ParameterizedType; @@ -59,8 +60,9 @@ protected final String getSyntax() { @SuppressWarnings("unchecked") protected final void run(AbstractService service, CommandLine params) throws Exception { - final ConfigurationFactory factory = new ConfigurationFactory(getConfigurationClass(), - new Validator()); + final ConfigurationFactory factory = ConfigurationFactory.forClass(getConfigurationClass(), + new Validator(), + service.getJacksonModules()); final String[] args = params.getArgs(); if (args.length >= 1) { params.getArgList().remove(0); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java index e54cd96732a..d858ec69dd2 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ManagedCommand.java @@ -20,7 +20,7 @@ protected final void run(AbstractService service, T configuration, CommandLine params) throws Exception { new LoggingFactory(configuration.getLoggingConfiguration()).configure(); - final Environment environment = new Environment(configuration); + final Environment environment = new Environment(configuration, service); service.initializeWithBundles(configuration, environment); LOG.info("Starting {}", service.getName()); environment.start(); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java index 6f1769d4080..e92a7d2091f 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ServerCommand.java @@ -43,7 +43,7 @@ protected Class getConfigurationClass() { protected void run(AbstractService service, T configuration, CommandLine params) throws Exception { - final Environment environment = new Environment(configuration); + final Environment environment = new Environment(configuration, service); service.initializeWithBundles(configuration, environment); final Server server = new ServerFactory(configuration.getHttpConfiguration()).buildServer(environment); diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java index 4afff1544d9..2b5a9e82243 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ConfigurationFactory.java @@ -3,23 +3,32 @@ import com.google.common.collect.ImmutableList; import com.yammer.dropwizard.json.Json; import com.yammer.dropwizard.validation.Validator; +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.Module; import java.io.File; import java.io.IOException; public class ConfigurationFactory { + public static ConfigurationFactory forClass(Class klass, Validator validator, Iterable modules) { + return new ConfigurationFactory(klass, validator, modules); + } + public static ConfigurationFactory forClass(Class klass, Validator validator) { - return new ConfigurationFactory(klass, validator); + return new ConfigurationFactory(klass, validator, ImmutableList.of()); } private final Class klass; private final Json json; private final Validator validator; - public ConfigurationFactory(Class klass, Validator validator) { + private ConfigurationFactory(Class klass, Validator validator, Iterable modules) { this.klass = klass; this.json = new Json(); json.enable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES); + for (Module module : modules) { + json.registerModule(module); + } this.validator = validator; } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index d06daf9597c..4a03a8c0a73 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -9,6 +9,7 @@ import com.sun.jersey.core.reflection.AnnotatedMethod; import com.sun.jersey.core.reflection.MethodList; import com.sun.jersey.spi.container.servlet.ServletContainer; +import com.yammer.dropwizard.AbstractService; import com.yammer.dropwizard.jetty.JettyManaged; import com.yammer.dropwizard.jetty.NonblockingServletHolder; import com.yammer.dropwizard.lifecycle.ExecutorServiceManager; @@ -47,6 +48,7 @@ public class Environment extends AbstractLifeCycle { private static final Log LOG = Log.forClass(Environment.class); + private final AbstractService service; private final ResourceConfig config; private final ImmutableSet.Builder healthChecks; private final ImmutableMap.Builder servlets; @@ -58,8 +60,10 @@ public class Environment extends AbstractLifeCycle { * Creates a new environment. * * @param configuration the service's {@link Configuration} + * @param service the service */ - public Environment(Configuration configuration) { + public Environment(Configuration configuration, AbstractService service) { + this.service = service; this.config = new DropwizardResourceConfig() { @Override public void validate() { @@ -430,4 +434,8 @@ private void logEndpoints() { private MethodList annotatedMethods(Class resource) { return new MethodList(resource, true).hasMetaAnnotation(HttpMethod.class); } + + public AbstractService getService() { + return service; + } } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java index 6a0d34a7926..f848fec7735 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/jersey/JacksonMessageBodyProvider.java @@ -4,6 +4,7 @@ import com.yammer.dropwizard.json.Json; import com.yammer.dropwizard.logging.Log; import com.yammer.dropwizard.validation.Validator; +import org.codehaus.jackson.map.Module; import org.eclipse.jetty.io.EofException; import javax.validation.Valid; @@ -49,7 +50,14 @@ public String getReasonPhrase() { } }; - private final Json json = new Json(); + private final Json json; + + public JacksonMessageBodyProvider(Iterable modules) { + this.json = new Json(); + for (Module module : modules) { + json.registerModule(module); + } + } @Override public boolean isReadable(Class type, diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/bundles/tests/JavaBundleTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/bundles/tests/JavaBundleTest.java index 8b723968977..a6af893e0b4 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/bundles/tests/JavaBundleTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/bundles/tests/JavaBundleTest.java @@ -1,19 +1,29 @@ package com.yammer.dropwizard.bundles.tests; +import com.google.common.collect.ImmutableList; +import com.yammer.dropwizard.Service; +import com.yammer.dropwizard.bundles.JavaBundle; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.jersey.JacksonMessageBodyProvider; import com.yammer.dropwizard.jersey.OauthTokenProvider; import com.yammer.dropwizard.jersey.OptionalQueryParamInjectableProvider; -import com.yammer.dropwizard.bundles.JavaBundle; +import org.junit.Before; import org.junit.Test; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class JavaBundleTest { private final Environment environment = mock(Environment.class); - private final JavaBundle bundle = new JavaBundle(); + private final Service service = mock(Service.class); + private final JavaBundle bundle = new JavaBundle(service); + + @Before + public void setUp() throws Exception { + when(service.getJacksonModules()).thenReturn(ImmutableList.of()); + } @Test public void addsOAuthSupport() throws Exception { diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/GzipConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/GzipConfigurationTest.java index 9f760f57333..6c6a4d51cad 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/GzipConfigurationTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/GzipConfigurationTest.java @@ -20,8 +20,8 @@ public class GzipConfigurationTest { @Before public void setUp() throws Exception { - this.gzip = new ConfigurationFactory(GzipConfiguration.class, - new Validator()).build(new File(Resources.getResource("yaml/gzip.yml").getFile())); + this.gzip = ConfigurationFactory.forClass(GzipConfiguration.class, + new Validator()).build(new File(Resources.getResource("yaml/gzip.yml").getFile())); } @Test diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java index 15058afb9fe..fb250c42cfd 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java @@ -20,8 +20,8 @@ public class HttpConfigurationTest { @Before public void setUp() throws Exception { - this.http = new ConfigurationFactory(HttpConfiguration.class, - new Validator()).build(new File(Resources.getResource("yaml/http.yml").getFile())); + this.http = ConfigurationFactory.forClass(HttpConfiguration.class, + new Validator()).build(new File(Resources.getResource("yaml/http.yml").getFile())); } @Test diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/RequestLogConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/RequestLogConfigurationTest.java index 26d9c5343c2..6418f628da3 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/RequestLogConfigurationTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/RequestLogConfigurationTest.java @@ -17,8 +17,8 @@ public class RequestLogConfigurationTest { @Before public void setUp() throws Exception { - this.requestLog = new ConfigurationFactory(RequestLogConfiguration.class, - new Validator()).build(new File(Resources.getResource("yaml/requestLog.yml").getFile())); + this.requestLog = ConfigurationFactory.forClass(RequestLogConfiguration.class, + new Validator()).build(new File(Resources.getResource("yaml/requestLog.yml").getFile())); } @Test diff --git a/dropwizard-scala_2.9.1/src/main/java/com/yammer/dropwizard/bundles/ScalaBundle.java b/dropwizard-scala_2.9.1/src/main/java/com/yammer/dropwizard/bundles/ScalaBundle.java index b4f479fc21c..8d5b1acfe6e 100644 --- a/dropwizard-scala_2.9.1/src/main/java/com/yammer/dropwizard/bundles/ScalaBundle.java +++ b/dropwizard-scala_2.9.1/src/main/java/com/yammer/dropwizard/bundles/ScalaBundle.java @@ -1,15 +1,22 @@ package com.yammer.dropwizard.bundles; import com.codahale.jersey.inject.ScalaCollectionsQueryParamInjectableProvider; -import com.codahale.jersey.providers.JerksonProvider; import com.yammer.dropwizard.Bundle; +import com.yammer.dropwizard.ScalaService; import com.yammer.dropwizard.config.Environment; +import com.yammer.dropwizard.jersey.JacksonMessageBodyProvider; import com.yammer.dropwizard.providers.OauthTokenProvider; public class ScalaBundle implements Bundle { + private final ScalaService service; + + public ScalaBundle(ScalaService service) { + this.service = service; + } + @Override public void initialize(Environment environment) { - environment.addProvider(new JerksonProvider()); + environment.addProvider(new JacksonMessageBodyProvider(service.getJacksonModules())); environment.addProvider(new OauthTokenProvider()); environment.addProvider(new ScalaCollectionsQueryParamInjectableProvider()); } diff --git a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala index 783ea83c9ed..1d53c96d30f 100644 --- a/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala +++ b/dropwizard-scala_2.9.1/src/main/scala/com/yammer/dropwizard/ScalaService.scala @@ -2,9 +2,11 @@ package com.yammer.dropwizard import config.Configuration import bundles.ScalaBundle +import com.codahale.jerkson.ScalaModule abstract class ScalaService[T <: Configuration](name: String) extends AbstractService[T](name) { - addBundle(new ScalaBundle) + addBundle(new ScalaBundle(this)) + addJacksonModule(new ScalaModule(Thread.currentThread().getContextClassLoader)) override final def subclassServiceInsteadOfThis() {} final def main(args: Array[String]) { diff --git a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleConfiguration.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleConfiguration.scala index 831e5e627aa..21025553c29 100644 --- a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleConfiguration.scala +++ b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleConfiguration.scala @@ -1,7 +1,9 @@ package com.yammer.dropwizard.examples import com.yammer.dropwizard.config.Configuration +import org.codehaus.jackson.annotate.JsonProperty class ExampleConfiguration extends Configuration { + @JsonProperty var saying: String = "Hello, world!" } diff --git a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala index b13dd2cc3c0..62f6469ee3c 100644 --- a/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala +++ b/dropwizard-scala_2.9.1/src/test/scala/com/yammer/dropwizard/examples/ExampleService.scala @@ -2,8 +2,9 @@ package com.yammer.dropwizard.examples import com.yammer.dropwizard.config.Environment import com.yammer.dropwizard.ScalaService +import com.codahale.logula.Logging -object ExampleService extends ScalaService[ExampleConfiguration]("example") { +object ExampleService extends ScalaService[ExampleConfiguration]("example") with Logging { addCommand(new SayCommand) addCommand(new SplodyCommand) diff --git a/dropwizard-scala_2.9.1/src/test/scala/scala-example.yml b/dropwizard-scala_2.9.1/src/test/scala/scala-example.yml new file mode 100644 index 00000000000..c8dd4ac5989 --- /dev/null +++ b/dropwizard-scala_2.9.1/src/test/scala/scala-example.yml @@ -0,0 +1,147 @@ +saying: Hello, world! + +# HTTP-specific options. +http: + + # The port on which the HTTP server listens for service requests. + port: 8080 + + # The port on which the HTTP server listens for administrative requests. + adminPort: 8081 + + # Maximum number of threads. + maxThreads: 100 + + # Minimum number of thread to keep alive. + minThreads: 10 + + # The type of connector to use. Other valid values are "nonblocking" or "legacy". In general, the + # blocking connector should be used for low-latency services with short request durations. The + # nonblocking connector should be used for services with long request durations or which + # specifically take advantage of Jetty's continuation support. + connectorType: blocking + + # The maximum amount of time a connection is allowed to be idle before being closed. + maxIdleTime: 1s + + # The number of threads dedicated to accepting connections. If omitted, this defaults to the + # number of logical CPUs on the current machine. + acceptorThreadCount: 3 + + # The offset of the acceptor threads' priorities. Can be [-5...5], with -5 dropping the acceptor + # threads to the lowest possible priority and with 5 raising them to the highest priority. + acceptorThreadPriorityOffset: 0 + + # The number of unaccepted requests to keep in the accept queue before refusing connections. If + # set to -1 or omitted, the system default is used. + acceptQueueSize: 100 + + # The maximum number of buffers to keep in memory. + maxBufferCount: 1024 + + # The initial buffer size for reading requests. + requestBufferSize: 32KB + + # The initial buffer size for reading request headers. + requestHeaderBufferSize: 6KB + + # The initial buffer size for writing responses. + responseBufferSize: 32KB + + # The initial buffer size for writing response headers. + responseHeaderBufferSize: 6KB + + # Enables SO_REUSEADDR on the server socket. + reuseAddress: true + + # Enables SO_LINGER on the server socket with the specified linger time. + soLingerTime: 1s + + # The number of open connections at which the server transitions to a "low-resources" mode. + lowResourcesConnectionThreshold: 25000 + + # When in low-resources mode, the maximum amount of time a connection is allowed to be idle before + # being closed. Overrides maxIdleTime. + lowResourcesMaxIdleTime: 5s + + # If non-zero, the server will allow worker threads to finish processing requests after the server + # socket has been closed for the given amount of time. + shutdownGracePeriod: 2s + + # If true, the HTTP server will prefer X-Forwarded headers over their non-forwarded equivalents. + useForwardedHeaders: true + + # If true, forces the HTTP connector to use off-heap, direct buffers. + useDirectBuffers: true + + # The hostname of the interface to which the HTTP server socket wil be found. If omitted, the + # socket will listen on all interfaces. + # bindHost: app1.example.com + + # HTTP request log settings + requestLog: + + # Whether or not to log HTTP requests. + enabled: false + + # The filename to which HTTP requests will be logged. The string 'yyyy_mm_dd' will be replaced + # with the current date, and the logs will be rolled accordingly. + filenamePattern: ./logs/yyyy_mm_dd.log + + # The maximum number of old log files to retain. + retainedFileCount: 5 + +# Logging settings. +logging: + + # The default level of all loggers. Can be OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, or ALL. + level: INFO + + # Logger-specific levels. + loggers: + + # Sets the level for 'com.example.app' to DEBUG. + com.example.app: DEBUG + + # Settings for logging to stdout. + console: + + # If true, write log statements to stdout. + enabled: true + + # Do not display log statements below this threshold to stdout. + threshold: ALL + + # Settings for logging to a file. + file: + + # If true, write log statements to a file. + enabled: false + + # Do not write log statements below this threshold to the file. + threshold: ALL + + # The file to which statements will be logged. When the log file reaches the maximum size, the + # file will be renamed example.log.1, example.log will be truncated, and new statements written + # to it. + filenamePattern: ./logs/example.log + + # The maximum size of any log file. + maxFileSize: 50MB + + # The maximum number of log files to retain. + retainedFileCount: 5 + + # Settings for logging to syslog. + syslog: + + # If true, write log statements to syslog. + enabled: false + + # The hostname of the syslog server to which statements will be sent. + # N.B.: If this is the local host, the local syslog instance will need to be configured to + # listen on an inet socket, not just a Unix socket. + host: localhost + + # The syslog facility to which statements will be sent. + facility: local0 diff --git a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/ResourceTest.java b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/ResourceTest.java index 4b07bce2f4f..a7e1d0f85d7 100644 --- a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/ResourceTest.java +++ b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/ResourceTest.java @@ -1,22 +1,27 @@ package com.yammer.dropwizard.testing; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.sun.jersey.api.client.Client; import com.sun.jersey.test.framework.AppDescriptor; import com.sun.jersey.test.framework.JerseyTest; import com.sun.jersey.test.framework.LowLevelAppDescriptor; import com.yammer.dropwizard.bundles.JavaBundle; import com.yammer.dropwizard.config.DropwizardResourceConfig; +import com.yammer.dropwizard.jersey.JacksonMessageBodyProvider; +import org.codehaus.jackson.map.Module; import org.junit.After; import org.junit.Before; -import java.util.HashSet; +import java.util.List; import java.util.Set; /** * A base test class for testing Dropwizard resources. */ public abstract class ResourceTest { - private final Set singletons = new HashSet(10); + private final Set singletons = Sets.newHashSet(); + private final List modules = Lists.newArrayList(); private JerseyTest test; @@ -26,6 +31,10 @@ protected void addResource(Object resource) { singletons.add(resource); } + protected void addJacksonModule(Module module) { + modules.add(module); + } + protected Client client() { return test.client(); } @@ -40,6 +49,7 @@ protected AppDescriptor configure() { for (Object provider : JavaBundle.DEFAULT_PROVIDERS) { // sorry, Scala folks config.getSingletons().add(provider); } + config.getSingletons().add(new JacksonMessageBodyProvider(modules)); config.getSingletons().addAll(singletons); return new LowLevelAppDescriptor.Builder(config).build(); } From ce6613cf2fef31f5ea2ed17684195765fc61ffe6 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 3 Feb 2012 19:41:12 -0800 Subject: [PATCH 0202/2771] Run tests in parallel. --- pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pom.xml b/pom.xml index 3ea842f07e9..afa85a69a8a 100644 --- a/pom.xml +++ b/pom.xml @@ -123,6 +123,14 @@ 1.6 + + org.apache.maven.plugins + maven-surefire-plugin + 2.5 + + classes + + org.apache.maven.plugins maven-source-plugin From f09c1d33157699c1d0f9fc9193768dd32d3b6a4c Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 3 Feb 2012 19:55:55 -0800 Subject: [PATCH 0203/2771] Convert JsonHelpers to use strings. AST comparison was an awesome idea, but IntNode<->LongNode negates that. --- .../dropwizard/testing/JsonHelpers.java | 24 +++++++++---------- .../testing/tests/JsonHelpersTest.java | 16 +++---------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java index 25f318a4556..0ba2be2edf6 100644 --- a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java +++ b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java @@ -28,43 +28,43 @@ public class JsonHelpers { private JsonHelpers() { /* singleton */ } /** - * Converts the given object into a JSON AST. + * Converts the given object into a canonical JSON string. * * @param object an object - * @return {@code object} as a JSON AST node + * @return {@code object} as a JSON string * @throws IOException if there is an error writing {@code object} as JSON */ - public static JsonNode asJson(Object object) throws IOException { - return JSON.writeValueAsTree(object); + public static String asJson(Object object) throws IOException { + return JSON.writeValueAsString(object); } /** - * Converts the given JSON AST into an object of the given type. + * Converts the given JSON string into an object of the given type. * - * @param json a JSON AST + * @param json a JSON string * @param klass the class of the type that {@code json} should be converted to * @param the type that {@code json} should be converted to * @return {@code json} as an instance of {@code T} * @throws IOException if there is an error reading {@code json} as an instance of {@code T} */ - public static T fromJson(JsonNode json, Class klass) throws IOException { + public static T fromJson(String json, Class klass) throws IOException { return JSON.readValue(json, klass); } /** - * Converts the given JSON AST into an object of the given type. + * Converts the given JSON string into an object of the given type. * - * @param json a JSON AST + * @param json a JSON string * @param reference a reference of the type that {@code json} should be converted to * @param the type that {@code json} should be converted to * @return {@code json} as an instance of {@code T} * @throws IOException if there is an error reading {@code json} as an instance of {@code T} */ - public static T fromJson(JsonNode json, TypeReference reference) throws IOException { + public static T fromJson(String json, TypeReference reference) throws IOException { return JSON.readValue(json, reference); } - public static JsonNode jsonFixture(String filename) throws IOException { - return JSON.readValue(fixture(filename), JsonNode.class); + public static String jsonFixture(String filename) throws IOException { + return JSON.writeValueAsString(JSON.readValue(fixture(filename), JsonNode.class)); } } diff --git a/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/JsonHelpersTest.java b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/JsonHelpersTest.java index 3ad015c9457..4d993044497 100644 --- a/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/JsonHelpersTest.java +++ b/dropwizard-testing/src/test/java/com/yammer/dropwizard/testing/tests/JsonHelpersTest.java @@ -1,29 +1,19 @@ package com.yammer.dropwizard.testing.tests; -import org.codehaus.jackson.JsonNode; -import org.codehaus.jackson.node.JsonNodeFactory; -import org.codehaus.jackson.node.ObjectNode; import org.codehaus.jackson.type.TypeReference; import org.junit.Test; -import static com.yammer.dropwizard.testing.JsonHelpers.asJson; -import static com.yammer.dropwizard.testing.JsonHelpers.fromJson; -import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture; +import static com.yammer.dropwizard.testing.JsonHelpers.*; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; public class JsonHelpersTest { - private final JsonNodeFactory factory = JsonNodeFactory.instance; - private final ObjectNode json = factory.objectNode(); - { - json.put("name", "Coda"); - json.put("email", "coda@example.com"); - } + private final String json = "{\"name\":\"Coda\",\"email\":\"coda@example.com\"}"; @Test public void readsJsonFixturesAsJsonNodes() throws Exception { assertThat(jsonFixture("fixtures/person.json"), - is((JsonNode) json)); + is(json)); } @Test From 5b158f1d0cde438929d420a2984bdf09a88b2ab5 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 3 Feb 2012 20:03:48 -0800 Subject: [PATCH 0204/2771] Make Json's fields private. --- .../src/main/java/com/yammer/dropwizard/json/Json.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java index bdf35a96308..ed505a919b3 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/json/Json.java @@ -26,9 +26,9 @@ * */ public class Json { - final JsonFactory factory; - final ObjectMapper mapper; - final TypeFactory typeFactory; + private final JsonFactory factory; + private final ObjectMapper mapper; + private final TypeFactory typeFactory; /** * Creates a new {@link Json} instance. From a6e3cf98a60a9dcf8de13232df29a6b059d46442 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 3 Feb 2012 20:15:44 -0800 Subject: [PATCH 0205/2771] Fix JsonHelpers#asJson throws clause. --- .../main/java/com/yammer/dropwizard/testing/JsonHelpers.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java index 0ba2be2edf6..1a87955feef 100644 --- a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java +++ b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java @@ -32,9 +32,9 @@ private JsonHelpers() { /* singleton */ } * * @param object an object * @return {@code object} as a JSON string - * @throws IOException if there is an error writing {@code object} as JSON + * @throws IllegalArgumentException if there is an error encoding {@code object} */ - public static String asJson(Object object) throws IOException { + public static String asJson(Object object) throws IllegalArgumentException { return JSON.writeValueAsString(object); } From d56583250c096e58654c99ccebe28e068cc94dc3 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 3 Feb 2012 20:52:52 -0800 Subject: [PATCH 0206/2771] Added docs for JsonHelpers#jsonFixture. --- .../java/com/yammer/dropwizard/testing/JsonHelpers.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java index 1a87955feef..1d00144e24f 100644 --- a/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java +++ b/dropwizard-testing/src/main/java/com/yammer/dropwizard/testing/JsonHelpers.java @@ -64,6 +64,13 @@ public static T fromJson(String json, TypeReference reference) throws IOE return JSON.readValue(json, reference); } + /** + * Loads the given fixture resource as a normalized JSON string. + * + * @param filename the filename of the fixture + * @return the contents of {@code filename} as a normalized JSON string + * @throws IOException if there is an error parsing {@code filename} + */ public static String jsonFixture(String filename) throws IOException { return JSON.writeValueAsString(JSON.readValue(fixture(filename), JsonNode.class)); } From 1557dc478dc53ea9844ecf780c8b7e2689a913b8 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Sun, 5 Feb 2012 13:31:37 -0800 Subject: [PATCH 0207/2771] Switch to using Mook for docs. --- docs/Makefile | 5 +- docs/README.md | 11 + docs/css/additional.css | 25 - docs/css/prettify.css | 105 -- docs/getting-started.html | 816 ----------- docs/index.html | 79 - docs/js/lang-yaml.js | 2 - docs/js/prettify.js | 28 - docs/manual.html | 1301 ----------------- docs/pages/getting-started.md | 642 ++++++++ docs/pages/index.md | 19 + docs/pages/manual.md | 992 +++++++++++++ docs/static/css/additional.css | 36 + docs/{ => static}/css/bootstrap.min.css | 0 .../images/dropwizard-hat-small.png | Bin .../images/dropwizard-hat-smaller.png | Bin docs/{ => static}/images/dropwizard-hat.png | Bin docs/templates/_toolbar.erb | 18 + docs/templates/landing.html.erb | 43 + docs/templates/manual.html.erb | 39 + 20 files changed, 1804 insertions(+), 2357 deletions(-) create mode 100644 docs/README.md delete mode 100644 docs/css/additional.css delete mode 100644 docs/css/prettify.css delete mode 100644 docs/getting-started.html delete mode 100644 docs/index.html delete mode 100644 docs/js/lang-yaml.js delete mode 100644 docs/js/prettify.js delete mode 100644 docs/manual.html create mode 100644 docs/pages/getting-started.md create mode 100644 docs/pages/index.md create mode 100644 docs/pages/manual.md create mode 100644 docs/static/css/additional.css rename docs/{ => static}/css/bootstrap.min.css (100%) rename docs/{ => static}/images/dropwizard-hat-small.png (100%) rename docs/{ => static}/images/dropwizard-hat-smaller.png (100%) rename docs/{ => static}/images/dropwizard-hat.png (100%) create mode 100644 docs/templates/_toolbar.erb create mode 100644 docs/templates/landing.html.erb create mode 100644 docs/templates/manual.html.erb diff --git a/docs/Makefile b/docs/Makefile index acd5cb79719..198757ab85a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,2 +1,5 @@ +default: + mook + upload: - rsync -avz ./ codahale.com:/home/codahale/dropwizard.codahale.com/ + rsync -avz target/ codahale.com:/home/codahale/dropwizard.codahale.com/ diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000000..d6cf30e689c --- /dev/null +++ b/docs/README.md @@ -0,0 +1,11 @@ +# Building The Docs + +You'll need `mook`: + + gem install mook + +Then, run `mook`: + + mook + +The goodie will be in the `target` directory. \ No newline at end of file diff --git a/docs/css/additional.css b/docs/css/additional.css deleted file mode 100644 index 195f6a770be..00000000000 --- a/docs/css/additional.css +++ /dev/null @@ -1,25 +0,0 @@ -body { - padding-top: 60px; -} - -#blurb { - background-color: #f5f5f5; - margin-bottom: 30px; - padding: 30px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} - -#blurb h1 { - margin-bottom: 0; - font-size: 60px; - line-height: 1; - letter-spacing: -1px; -} - -#blurb p { - font-size: 18px; - font-weight: 200; - line-height: 27px; -} diff --git a/docs/css/prettify.css b/docs/css/prettify.css deleted file mode 100644 index 37734743d9b..00000000000 --- a/docs/css/prettify.css +++ /dev/null @@ -1,105 +0,0 @@ -.com { color: #93a1a1; } -.lit { color: #195f91; } -.pun, .opn, .clo { color: #93a1a1; } -.fun { color: #dc322f; } -.str, .atv { color: #268bd2; } -.kwd, .tag { color: #195f91; } -.typ, .atn, .dec, .var { color: #CB4B16; } -.pln { color: #93a1a1; } -.prettyprint { - overflow: scroll; - background-color: #fefbf3; - padding: 9px; - border: 1px solid rgba(0,0,0,.2); - -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.1); - -moz-box-shadow: 0 1px 2px rgba(0,0,0,.1); - box-shadow: 0 1px 2px rgba(0,0,0,.1); -} - -.uglyprint { - overflow: scroll; - background-color: #fefbf3; - padding: 9px; - border: 1px solid rgba(0, 0, 0, .2); - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .1); - -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, .1); - box-shadow: 0 1px 2px rgba(0, 0, 0, .1); -} - -/* Specify class=linenums on a pre to get line numbering */ -ol.linenums { - margin: 0 0 0 40px; -} -/* IE indents via margin-left */ -ol.linenums li { - padding: 0 5px; - color: rgba(0,0,0,.15); - line-height: 20px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; -} -/* Alternate shading for lines */ -li.L1, li.L3, li.L5, li.L7, li.L9 { } - -/* -$base03: #002b36; -$base02: #073642; -$base01: #586e75; -$base00: #657b83; -$base0: #839496; -$base1: #93a1a1; -$base2: #eee8d5; -$base3: #fdf6e3; -$yellow: #b58900; -$orange: #cb4b16; -$red: #dc322f; -$magenta: #d33682; -$violet: #6c71c4; -$blue: #268bd2; -$cyan: #2aa198; -$green: #859900; -*/ - - -/* -#1d1f21 Background -#282a2e Current Line -#373b41 Selection -#c5c8c6 Foreground -#969896 Comment -#cc6666 Red -#de935f Orange -#f0c674 Yellow -#b5bd68 Green -#8abeb7 Aqua -#81a2be Blue -#b294bb Purple -*/ - - -/* DARK THEME */ -/* ---------- */ - -.prettyprint-dark { - background-color: #1d1f21; - border: 0; - padding: 10px; -} -.prettyprint-dark .linenums li { - color: #444; -} -.prettyprint-dark .linenums li:hover { - background-color: #282a2e; -} -/* tags in html */ -.prettyprint-dark .kwd, -.prettyprint-dark .tag { color: #cc6666; } -/* html attr */ -.prettyprint-dark .typ, -.prettyprint-dark .atn, -.prettyprint-dark .dec, -.prettyprint-dark .var { color: #de935f; } -/* html attr values */ -.prettyprint-dark .str, -.prettyprint-dark .atv { color: #b5bd68; } diff --git a/docs/getting-started.html b/docs/getting-started.html deleted file mode 100644 index 24c8ce8275c..00000000000 --- a/docs/getting-started.html +++ /dev/null @@ -1,816 +0,0 @@ - - - - - Getting Started | Dropwizard - - - - - - - - - - - - - - - - - -
          - - -
          -

          Getting Started

          - -

          - The goal of this document is to guide you through the process of creating a simple - Dropwizard project: Hello World. Along the way, we’ll explain the various underlying - libraries and their roles, important concepts in Dropwizard, and suggest some - organizational techniques to help you as your project grows. (Or you can just skip to - the fun part.) -

          - -

          Overview

          - -

          - Dropwizard straddles the line between being a library and a framework. Its goal is to - provide performant, reliable implementations of everything a production-ready web - service needs. Because this functionality is extracted into a reusable library, your - service remains lean and focused, reducing both time-to-market and maintenance burdens. -

          - -

          Jetty for HTTP

          - -

          - Because you can't be a web service without HTTP, Dropwizard uses the - Jetty HTTP library to embed an incredibly - tuned HTTP server directly into your project. Instead of handing your service off to - a complicated application server, Dropwizard projects have a main method - which spins up an HTTP server. Running your service as a simple process eliminates a - number of unsavory aspects of Java in production (no PermGem issues, no application - server configuration and maintenance, no arcane deployment tools, no - ClassLoader troubles, no hidden application logs, no trying to tune a - single garbage collector to work with multiple application workloads) and allows you - to use all of Unix's existing process management tools instead. -

          - -

          Jersey for REST

          - -

          - For building RESTful web services, - we've found nothing beats Jersey - (the JAX-RS reference - implementation) in terms of features or performance. It allows you to write clean, - testable classes which gracefully map HTTP requests to simple Java objects. It supports - streaming output, matrix URI parameters, conditional GET requests, and - much, much more. -

          - -

          Jackson for JSON

          - -

          - In terms of data formats, JSON has become the web’s lingua franca, and - Jackson is the king of JSON - on the JVM. In addition to being lightning fast, it has a sophisticated object mapper, - allowing you to export your domain models directly. -

          - -

          Metrics for metrics (duh)

          - -

          - Our very own Metrics - library rounds things out, providing you with unparalleled insight into your code’s - behavior in your production environment. -

          - -

          And Friends

          - -

          - In addition to Jetty, Jersey, and Jackson, Dropwizard also includes a number of - libraries that we've come to rely on: -

          - -
            -
          • - Guava, - which, in addition to highly optimized immutable data structures, provides a growing - number of classes to speed up development in Java. -
          • -
          • - Log4j and - slf4j for performant logging. -
          • -
          • - Hibernate Validator, - the JSR-303 reference - implementation, provides an easy, declarative framework for validating user input - and generating helpful, internationalizable error messages. -
          • -
          • - Apache HttpClient - and Jersey's client library allow for both low- and high-level interaction with - other web services. -
          • -
          • - JDBI is the most straight-forward - way to use a relational database with Java. -
          • -
          • - Freemarker is a - simple template system for more user-facing services. -
          • -
          - -

          - Now that you've gotten the lay of the land, let's dig in! -

          - -
          - -

          Setting Up Maven

          - -

          - We recommend you use Maven for new - Dropwizard services. If you're a big - Ant/Ivy, - Buildr, - Gradle, - SBT, - or Gant fan, that’s cool, but we - use Maven and we'll be using Maven as we go through this example service. If you have - any questions about how Maven works, - Maven: The Complete Reference - should have what you’re looking for. (We’re assuming you know how to create a new - Maven project.) -

          - -

          - Add the dropwizard-core library as a dependency: -

          - -
          -<dependencies>
          -    <dependency>
          -        <groupId>com.yammer.dropwizard</groupId>
          -        <artifactId>dropwizard-core</artifactId>
          -        <version>0.1.3</version>
          -    </dependency>
          -</dependencies>
          - -

          - Alright, that’s enough XML. We’ve got a Maven project set up now, and it’s time to start - writing real code. -

          - -
          - -

          Creating A Configuration Class

          - -

          - Each Dropwizard service has its own subclass of the Configuration class - which specify environment-specific parameters. These parameters are specified in a - YAML configuration file which is - deserialized to an instance of your service’s configuration class and validated. -

          - -

          - The service we’re building is a high-performance Hello World service, and part of our - requirements is that we need to be able to vary how it says hello from environment to - environment. We’ll need to specify at least two things to begin with: a template for - saying hello and a default name to use in case the user doesn’t specify their name. -

          - -

          - Here's what our configuration class will look like: -

          - -
          -package com.example.helloworld;
          -
          -import com.yammer.dropwizard.config.Configuration;
          -import org.hibernate.validator.constraints.NotEmpty;
          -
          -public class HelloWorldConfiguration extends Configuration {
          -    @NotEmpty
          -    private String template;
          -
          -    @NotEmpty
          -    private String defaultName = "Stranger";
          -
          -    public String getTemplate() {
          -        return template;
          -    }
          -
          -    public String getDefaultName() {
          -        return defaultName;
          -    }
          -}
          -

          - There's a lot going on here, so let’s unpack a bit of it. -

          - -

          - When this class is deserialized from the YAML file, it will pull two root-level fields - from the YAML object: template, the template for our Hello World saying, - and defaultName, the default name to use. Both template and - defaultName are annotated with @NotEmpty, so if the YAML - configuration file has blank values for either or is missing template - entirely an informative exception will be thrown and your service won’t start. -

          - -

          - Our YAML file, then, will look like this: -

          - -
          -template: Hello, %s!
          -defaultName: Stranger
          - -

          - Dropwizard has a lot more configuration parameters than that, but they all have - sane defaults so you can keep your configuration files small and focused. -

          - -

          - So save that YAML file as hello-world.yml, because we’ll be getting up - and running pretty soon and we’ll need it. Next up, we’re creating our service class! -

          - -
          - -

          Creating A Service Class

          - -

          - Combined with your project’s Configuration subclass, its - Service form the core of your Dropwizard service. The Service - class pulls together the various bundles and commands which provide basic functionality. - (More on that later.) For now, though, our HelloWorldService looks like - this: -

          - -
          -package com.example.helloworld;
          -
          -import com.yammer.dropwizard.Service;
          -import com.yammer.dropwizard.config.Environment;
          -
          -public class HelloWorldService extends Service<HelloWorldConfiguration> {
          -    public static void main(String[] args) throws Exception {
          -        new HelloWorldService().run(args);
          -    }
          -
          -    private HelloWorldService() {
          -        super("hello-world");
          -    }
          -
          -    @Override
          -    protected void initialize(HelloWorldConfiguration configuration,
          -                              Environment environment) {
          -        // nothing to do yet
          -    }
          -
          -}
          - -

          - As you can see, HelloWorldService is parameterized with the service’s - configuration type, HelloWorldConfiguration. - HelloWorldService’s constructor provides the service’s name: - hello-world. Also, we’ve added a static main - method, which will be our service’s entry point. Right now, we don’t have any - functionality implemented, so our initialize method is a little boring. - Let’s fix that! -

          - -
          - -

          Creating A Representation Class

          - -

          - Before we can get into the nuts-and-bolts of our Hello World service, we need to stop - and think about our API. Luckily, our service needs to conform to an industry standard, - RFC 1149, - which specifies the following JSON representation of a Hello World saying: -

          - -
          -{
          -  "id": 1,
          -  "content": "Hello, stranger!"
          -}
          - -

          - The id field is a unique identifier for the saying, and - content is the textual representation of the saying. (Thankfully, this is a - fairly straight-forward industry standard.) -

          - -

          - To model this representation, we'll create a representation class: -

          - -
          -package com.example.helloworld.core;
          -
          -public class Saying {
          -    private final long id;
          -    private final String content;
          -
          -    public Saying(long id, String content) {
          -        this.id = id;
          -        this.content = content;
          -    }
          -
          -    public long getId() {
          -        return id;
          -    }
          -
          -    public String getContent() {
          -        return content;
          -    }
          -}
          - -

          - This is a pretty simple POJO, but there are a few things worth noting here. -

          - -

          - First, it’s immutable. This makes Saying instances very easy to - reason about multi-threaded environments as well as single-threaded environments. - Second, it uses the Java Bean standard for the id and content - properties. This allows Jackson to serialize it to the JSON we need. The Jackson object - mapping code will populate the id field of the JSON object with the return - value of getId(), likewise with content and - getContent(). -

          - -

          - Now that we’ve got our representation class, it makes sense to start in on the resource - it represents. -

          - -
          - -

          Creating A Resource Class

          - -

          - Jersey resources are the meat-and-potatoes of a Dropwizard service. Each resource class - is associated with a URI template. For - our service, we need a resource which returns new Saying instances from - the URI /hello-world, so our resource class will look like this: -

          - -
          -package com.example.helloworld.resources;
          -
          -import com.example.helloworld.core.Saying;
          -import com.google.common.base.Optional;
          -import com.yammer.metrics.annotation.Timed;
          -
          -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 java.util.concurrent.atomic.AtomicLong;
          -
          -@Path("/hello-world")
          -@Produces(MediaType.APPLICATION_JSON)
          -public class HelloWorldResource {
          -    private final String template;
          -    private final String defaultName;
          -    private final AtomicLong counter;
          -
          -    public HelloWorldResource(String template, String defaultName) {
          -        this.template = template;
          -        this.defaultName = defaultName;
          -        this.counter = new AtomicLong();
          -    }
          -
          -    @GET
          -    @Timed
          -    public Saying sayHello(@QueryParam("name") Optional<String> name) {
          -        return new Saying(counter.incrementAndGet(),
          -                          String.format(template, name.or(defaultName)));
          -    }
          -}
          - -

          - Finally, we’re in the thick of it! Let’s start from the top and work our way down. -

          - -

          - HelloWorldResource has two annotations: @Path and - @Produces. @Path("/hello-world") tells Jersey that this - resource is accessible at the URI /hello-world, and - @Produces(MediaType.APPLICATION_JSON) lets Jersey’s content negotiation - code know that this resource produces representations which are - application/json. -

          - -

          - HelloWorldResource takes two parameters for construction: the - template it uses to produce the saying and the defaultName - used when the user declines to tell us their name. An AtomicLong provides - us with a cheap, thread-safe way of generating unique(ish) IDs. -

          - -

          - Remember: Resource classes are used by multiple threads concurrently. - In general, we recommend that resources be stateless/immutable, but it’s important to - keep the context in mind. -

          - -

          - sayHello(Optional<String>) is the meat of this class, and it’s a - fairly simple method. The @QueryParam("name") tells Jersey to map the - name parameter from the query string to the name parameter - in the method. If the client sends a request to /hello-world?name=Dougie, - sayHello will be called with Optional.of("Dougie"); if there - is no name parameter in the query string, sayHello will be - called with Option.absent(). (Support for Guava's Optional - is a little extra sauce that Dropwizard adds to Jersey's existing functionality.) -

          - -

          - Inside the sayHello method, we increment the counter, format the template - using String.format(String, Object...), and return a new - Saying instance. -

          - -

          - Because sayHello is annotated with @Timed, Dropwizard - automatically records the duration and rate of its invocations as a Metrics Timer. -

          - -

          - Once sayHello has returned, Jersey takes the Saying instance - and looks for a provider class which can write Saying instances as - application/json. Dropwizard has one such provider built in which allows - for producing and consuming Java objects as JSON objects. The provider writes out the - JSON and the client receives a 200 OK response with a content type of - application/json. -

          - -

          - Before that will actually work, though, we need to go back to our - HelloWorldService and add this new resource class. In its - initialize method we can read the template and default name from the - HelloWorldConfiguration instance, create a new - HelloWorldService instance, and then add it to the service’s environment: -

          - -
          -@Override
          -protected void initialize(HelloWorldConfiguration configuration,
          -                          Environment environment) {
          -    final String template = configuration.getTemplate();
          -    final String defaultName = configuration.getDefaultName();
          -    environment.addResource(new HelloWorldResource(template, defaultName));
          -}
          - -

          - When our service starts, we create a new instance of our resource class with the - parameters from the configuration file and hand it off to the Environment, - which acts like a registry of all the things your service can do. -

          - -

          - Before we go too far, we should add a health check for our service. -

          - -
          - -

          Adding A Health Check

          - -

          - Health checks give you a way of adding small tests to your service to allow you and your - ops team to verify that your service is functioning correctly in production. We - strongly recommend that all of your services have at least a minimal - set of health checks. (We recommend this so strongly, in fact, that Dropwizard will nag - you should you neglect to add a health check to your project.) -

          - -

          - Since formatting strings is not likely to fail while a service is running (unlike, - say, a database connection pool), we’ll have to get a little creative here. We’ll add - a health check to make sure we can actually format the provided template: -

          - -
          -package com.example.helloworld.health;
          -
          -import com.yammer.metrics.core.HealthCheck;
          -
          -public class TemplateHealthCheck extends HealthCheck {
          -    private final String template;
          -
          -    public TemplateHealthCheck(String template) {
          -        super("template");
          -        this.template = template;
          -    }
          -
          -    @Override
          -    protected Result check() throws Exception {
          -        final String saying = String.format(template, "TEST");
          -        if (!saying.contains("TEST")) {
          -            return Result.unhealthy("template doesn't include a name");
          -        }
          -        return Result.healthy();
          -    }
          -}
          - -

          - TemplateHealthCheck checks for two things: that the provided template is - actually a well-formed format string, and that the template actually produces output - with the given name. -

          - -

          - If the string is not a well-formed format string (for example, someone accidentally put - Hello, %s% in the configuration file), then - String.format(String, Object...) will throw an - IllegalFormatException and the health check will implicitly fail. If the - rendered saying doesn’t include the test string, the health check will explicitly fail - by returning an unhealthy Result. -

          - -

          - As with most things in Dropwizard, we create a new instance with the appropriate - parameters and add it to the Environment: -

          - -
          -@Override
          -protected void initialize(HelloWorldConfiguration configuration,
          -                          Environment environment) {
          -    final String template = configuration.getTemplate();
          -    final String defaultName = configuration.getDefaultName();
          -    environment.addResource(new HelloWorldResource(template, defaultName));
          -    environment.addHealthCheck(new TemplateHealthCheck(template));
          -}
          - -

          - Now we're almost ready to go! -

          - -
          - -

          Building Fat JARs

          - -

          - We recommend that you build your Dropwizard services as “fat†JAR files—single - .jar files which contain all of the .class files - required to run your service. This allows you to build a single deployable artifact - which you can copy from your staging environment to your QA environment to your - production environment without worrying about differences in installed libraries. To - start building our Hello World service as a fat JAR, we need to configure a Maven plugin - called maven-shade. In your pom.xml file, add this: -

          - -
          -<plugin>
          -    <groupId>org.apache.maven.plugins</groupId>
          -    <artifactId>maven-shade-plugin</artifactId>
          -    <version>1.4</version>
          -    <configuration>
          -        <createDependencyReducedPom>true</createDependencyReducedPom>
          -    </configuration>
          -    <executions>
          -        <execution>
          -            <phase>package</phase>
          -            <goals>
          -                <goal>shade</goal>
          -            </goals>
          -            <configuration>
          -                <transformers>
          -                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
          -                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
          -                        <mainClass>com.example.helloworld.HelloWorldService</mainClass>
          -                    </transformer>
          -                </transformers>
          -            </configuration>
          -        </execution>
          -    </executions>
          -</plugin>
          -        
          - -

          - This configures Maven to do a couple of things during its package phase: -

          - -
            -
          • - Produce a pom.xml file which doesn’t include dependencies for the - libraries whose contents are included in the fat JAR. -
          • -
          • - Collate the various META-INF/services entries in the JARs instead of - overwriting them. (Jersey doesn’t work without those.) -
          • -
          • - Set com.example.helloworld.HelloWorldService as the JAR’s - MainClass. -
          • -
          - -

          - Once you’ve got that configured, go into your project directory and run - mvn package (or run the package goal from your IDE). You - should see something like this: -

          - -
          -[INFO] Including org.eclipse.jetty:jetty-util:jar:7.6.0.RC0 in the shaded jar.
          -[INFO] Including com.google.guava:guava:jar:10.0.1 in the shaded jar.
          -[INFO] Including com.google.code.findbugs:jsr305:jar:1.3.9 in the shaded jar.
          -[INFO] Including org.hibernate:hibernate-validator:jar:4.2.0.Final in the shaded jar.
          -[INFO] Including javax.validation:validation-api:jar:1.0.0.GA in the shaded jar.
          -[INFO] Including org.yaml:snakeyaml:jar:1.9 in the shaded jar.
          -[INFO] Replacing original artifact with shaded artifact.
          -[INFO] Replacing /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT.jar with /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT-shaded.jar
          -[INFO] ------------------------------------------------------------------------
          -[INFO] BUILD SUCCESS
          -[INFO] ------------------------------------------------------------------------
          -[INFO] Total time: 8.415s
          -[INFO] Finished at: Fri Dec 02 16:26:42 PST 2011
          -[INFO] Final Memory: 11M/81M
          -[INFO] ------------------------------------------------------------------------
          - -

          - Congratulations! You’ve built your first Dropwizard project! Now it’s - time to run it! -

          - -
          - -

          Running Your Service

          - -

          - Now that you’ve built a JAR file, it’s time to run it. -

          - -

          - In your project directory, run - java -jar target/hello-world-0.0.1-SNAPSHOT.jar. You should see something - like the following: -

          - -
          -java -jar dropwizard-example-0.1.0-SNAPSHOT.jar <command> [arg1 arg2]
          -
          -Commands
          -========
          -
          -server: Starts an HTTP server running the service
          --------------------------------------------------
          -usage: java -jar dropwizard-example-0.1.0-SNAPSHOT.jar server <config
          -            file>
          - -h, --help   display usage information
          - -

          - Dropwizard takes the first command line argument and dispatches it to a matching - command. In this case, the only command available is server, which runs - your service as an HTTP server. The server command requires a configuration - file, so let’s go ahead and give it - the one we previous saved: - java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml -

          - -

          - You should see something like the following: -

          - -
          -INFO  [2011-12-03 00:38:32,927] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world
          -INFO  [2011-12-03 00:38:32,931] org.eclipse.jetty.server.Server: jetty-7.x.y-SNAPSHOT
          -INFO  [2011-12-03 00:38:32,936] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null}
          -INFO  [2011-12-03 00:38:32,999] com.sun.jersey.server.impl.application.WebApplicationImpl: Initiating Jersey application, version 'Jersey: 1.10 11/02/2011 03:53 PM'
          -INFO  [2011-12-03 00:38:33,041] com.yammer.dropwizard.config.Environment:
          -
          -    GET     /hello-world (com.example.helloworld.resources.HelloWorldResource)
          -
          -INFO  [2011-12-03 00:38:33,215] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null}
          -INFO  [2011-12-03 00:38:33,235] org.eclipse.jetty.server.AbstractConnector: Started BlockingChannelConnector@0.0.0.0:8080 STARTING
          -INFO  [2011-12-03 00:38:33,238] org.eclipse.jetty.server.AbstractConnector: Started SocketConnector@0.0.0.0:8081 STARTING
          - -

          - Your Dropwizard service is now listening on ports 8080 for service requests - and 8081 for administration requests. If you press - ^C, the service will shut down gracefully, first closing - the server socket, then allowing a few seconds for in-flight requests to be processed, - then shutting down the process itself. -

          - -

          - But while it’s up, let’s give it a whirl! - Click here to say hello! - Click here to get even friendlier! -

          - -

          - So, we’re generating sayings. Awesome. But that’s not all your service can do. One of - the main reasons for using Dropwizard is the out-of-the-box operational tools it - provides, all of which can be found - on the admin port. -

          - -

          - If you click through to - metrics, you can see all of - your service’s metrics represented as a JSON object. -

          - -

          - The threads resource allows - you to quickly get a thread dump of all the threads running in that process. -

          - -

          - The healthcheck - resource runs the TemplateHealthCheck instance we - wrote. You should see something like this: -

          - -
          -* deadlocks: OK
          -* template: OK
          - -

          - template here is the result of your TemplateHealthCheck, which - unsurprisingly passed. deadlocks is a built-in health check which looks for - deadlocked JVM threads and prints out a listing if any are found. -

          - -
          - -

          Next Steps

          - -

          - Well, congratulations. You’ve got a Hello World service ready for production (except for - the lack of tests) that’s capable of doing 15,000-20,000 requests per second. Hopefully - you've gotten a feel for how Dropwizard combines Jetty, Jersey, Jackson, and other - stable, mature libraries to provide a phenomenal platform for developing RESTful web - services. -

          - -

          - There’s a lot more to Dropwizard than is covered here (commands, bundles, servlets, - advanced configuration, validation, HTTP clients, database clients, templates, etc.), - all of which is covered in by Dropwizard's manual. -

          - -

          Learn more about Dropwizard »

          - -

          Learn more about Maven »

          - -

          Learn more about Jetty »

          - -

          Learn more about Jersey »

          - -

          Learn more about Jackson »

          - -

          Learn more about YAML »

          - -
          -

          © Yammer 2011

          -
          -
          -
          - - - diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index fd191122702..00000000000 --- a/docs/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - Dropwizard - - - - - - - - - - - - - -
          - -
          -
          -
          - -
          -
          - -

          Meet Dropwizard.

          - -

          - - Dropwizard is a Java framework for developing ops-friendly, - high-performance, RESTful web services. - -

          - -

          - Developed by Yammer to power their - JVM-based backend services, Dropwizard pulls together stable, mature - libraries from the Java ecosystem into a simple, light-weight package that - lets you focus on getting things done. -

          - -

          - Dropwizard has out-of-the-box support for sophisticated application metrics, - logging, operational tools, and much more, allowing you and your team to - ship a production-quality HTTP+JSON web service in the shortest time - possible. -

          - -

          Get - started »

          - -
          -
          - -
          -

          © Yammer 2011

          -
          -
          -
          - - - diff --git a/docs/js/lang-yaml.js b/docs/js/lang-yaml.js deleted file mode 100644 index c38729b6cfb..00000000000 --- a/docs/js/lang-yaml.js +++ /dev/null @@ -1,2 +0,0 @@ -var a=null; -PR.registerLangHandler(PR.createSimpleLexer([["pun",/^[:>?|]+/,a,":|>?"],["dec",/^%(?:YAML|TAG)[^\n\r#]+/,a,"%"],["typ",/^&\S+/,a,"&"],["typ",/^!\S*/,a,"!"],["str",/^"(?:[^"\\]|\\.)*(?:"|$)/,a,'"'],["str",/^'(?:[^']|'')*(?:'|$)/,a,"'"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^\s+/,a," \t\r\n"]],[["dec",/^(?:---|\.\.\.)(?:[\n\r]|$)/],["pun",/^-/],["kwd",/^\w+:[\n\r ]/],["pln",/^\w+/]]),["yaml","yml"]); diff --git a/docs/js/prettify.js b/docs/js/prettify.js deleted file mode 100644 index eef5ad7e6a0..00000000000 --- a/docs/js/prettify.js +++ /dev/null @@ -1,28 +0,0 @@ -var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; -(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= -[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), -l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, -q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, -q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, -"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), -a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} -for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], -"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], -H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], -J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ -I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), -["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", -/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), -["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", -hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= -!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p - - - - Manual | Dropwizard - - - - - - - - - - - - - - - - -
          - - -
          -

          Dropwizard User’s Manual

          - -

          - This goal of this document is to provide you with all the information required to - build, organize, test, deploy, and maintain Dropwizard-based services. -

          - -

          Organization

          - -

          - In general, we recommend you separate your projects into three Maven modules: - project-api, project-client, - and project-server. project-api should - contain your representation classes; - project-client should use those classes and an HTTP client from - dropwizard-client to implement a full-fledged client - for your service, and project-server should provide the actual service - implementation, including resources. -

          - -

          Our services tend to look like this:

          - -
          -
          com.example.myservice.api
          -
          Representation classes
          -
          com.example.myservice.cli
          -
          Service command classes
          -
          com.example.myservice.client
          -
          Client implementation
          -
          com.example.myservice.core
          -
          Domain implementation
          -
          com.example.myservice.health
          -
          Health check classes
          -
          com.example.myservice.resources
          -
          Resource classes
          -
          com.example.myservice.MyService
          -
          The service class
          -
          com.example.myservice.MyServiceConfiguration
          -
          The configuration class
          -
          - -

          Services

          - -

          - The main entry point into a Dropwizard service is, unsurprisingly, the - Service class. Each Service has a name, - which is mostly used to render the command-line interface. In the constructor of your - Service you can add bundles and - commands to your service. -

          - -

          Configuration

          - -

          - Each Service subclass has a single type parameter: that of its matching - Configuration subclass. These are usually at the root of your service’s - main package. For example, your User service would have two classes: - UserServiceConfiguration, extending Configuration, - and UserService, extending - Service<UserServiceConfiguration>. -

          - -

          - When your service runs a configured command like the - server command, Dropwizard parses the provided YAML configuration file and - builds an instance of your service’s configuration class by mapping YAML field names to - object field names. -

          - -

          - In order to keep your configuration file and class manageable, we recommend grouping - related configuration parameters into independent configuration classes. If your - service requires a set of configuration parameters in order to connect to a message - queue, for example, we recommend that you create a new - MessageQueueConfiguration class: -

          - -
          -public class MessageQueueConfiguration {
          -    @NotEmpty
          -    private String host;
          -
          -    @Min(1)
          -    @Max(65535)
          -    private int port = 5672;
          -
          -    public String getHost() {
          -        return host;
          -    }
          -
          -    public int getPort() {
          -        return port;
          -    }
          -}
          - -

          - Your main Configuration subclass can then include this as a member field: -

          - -
          -public class ExampleServiceConfiguration extends Configuration {
          -    @NotNull
          -    private MessageQueueConfiguration messageQueue = new MessageQueueConfiguration();
          -
          -    public MessageQueueConfiguration getMessageQueueConfiguration() {
          -        return messageQueue;
          -    }
          -}
          - -

          - Then, in your service’s YAML file, you can use a nested messageQueue field: -

          - -
          -messageQueue:
          -  host: mq.example.com
          -  port: 5673
          - -

          - The @NotNull, @NotEmpty, @Min, and - @Max annotations are part of Dropwizard’s - validation functionality. If your YAML configuration file’s - messageQueue.host field was missing (or was a blank string), Dropwizard - would refuse to start and would output an error message describing the issues. -

          - -

          - Once your service has parsed the YAML file and constructed its - Configuration instance, Dropwizard then calls your Service - subclass to initialize your service’s Environment. -

          - -

          Environments

          - -

          - A Dropwizard Environment consists of all the - resource classes, servlets, filters, - health checks, Jersey providers, - managed objects, tasks, and Jersey - properties which your service provides. -

          - -

          - Each Service subclass implements an initialize method. This - is where you should be creating new resource instances, etc., and adding them to the - given Environment class: -

          - -
          -@Override
          -protected void initialize(ExampleConfiguration config,
          -                          Environment environment) {
          -    // encapsulate complicated setup logic in factories
          -    final ThingyFactory thingyFactory = new ThingyFactory(config.getThingyConfiguration());
          -
          -    final Thingy thingy = thingyFactory.build();
          -
          -    environment.addResource(new ThingyResource(thingy));
          -    environment.addHealthCheck(new ThingyHealthCheck(thingy));
          -}
          - -

          - It’s important to keep the initialize method clean, so if creating an - instance of something is complicated, like the Thingy class above, extract - that logic into a factory. -

          - -

          Health Checks

          - -

          - A health check is a runtime test which you can use to verify your service’s behavior - in its production environment. For example, you may want to ensure that your database - client is connected to the database: -

          - -
          -public class DatabaseHealthCheck extends HealthCheck {
          -    private final Database database;
          -
          -    public DatabaseHealthCheck(Database database) {
          -        super("database");
          -        this.database = database;
          -    }
          -
          -    @Override
          -    protected Result check() throws Exception {
          -        if (database.isConnected()) {
          -            return Result.healthy();
          -        } else {
          -            return Result.unhealthy("Cannot connect to " + database.getUrl());
          -        }
          -    }
          -}
          - -

          - You can then add this health check to your service’s environment: -

          - -
          -environment.addHealthCheck(new DatabaseHealthCheck(database));
          - -

          - By sending a GET request to /healthcheck on the admin port you - can run these tests and view the results: -

          - -
          -$ curl http://dw.example.com:8081/healthcheck
          -* deadlocks: OK
          -* database: OK
          - -

          - If all health checks report success, a 200 OK is returned. If any fail, - a 500 Internal Server Error is returned with the error messages and - exception stack traces (if an exception was thrown). -

          - -

          - All Dropwizard services ship with the deadlocks health check installed by - default, which uses Java 1.6's built-in thread deadlock detection to determine if any - threads are deadlocked. -

          - -

          Managed Objects

          - -

          - Most services involve objects which need to be started and stopped: thread pools, - database connections, etc. Dropwizard provides the Managed interface for - this. You can either have the class in question implement Managed’s - start() and stop() methods, or write a wrapper class which - does so. Adding a Managed instance to your service’s - Environment ties that object’s lifecycle to that of the service’s HTTP - server. Before the server starts, the Managed’s start() method - is called. After the server has stopped (and after its graceful shutdown period) the - Managed’s stop() method is called. -

          - -

          - For example, given a theoretical - Riak client which needs to be - started and stopped: -

          - -
          -public class RiakClientManager implements Managed {
          -    private final RiakClient client;
          -
          -    public RiakClientManager(RiakClient client) {
          -        this.client = client;
          -    }
          -
          -    @Override
          -    public void start() throws Exception {
          -        client.start();
          -    }
          -
          -    @Override
          -    public void stop() throws Exception {
          -        client.stop();
          -    }
          -}
          - -

          - If RiakClientManager#start() throws an exception—e.g., an error connecting - to the server—your service will not start and a full exception will be logged. If - RiakClientManager#stop() throws an exception, the exception will be logged - but your service will still be able to shut down. -

          - -

          - It should be noted that Environment has built-in constructors for - ExecutorService and ScheduledExecutorService instances which - are managed. See Environment#managedExecutorService and - Environment#managedScheduledExecutorService for details. -

          - -

          Bundles

          - -

          - A Dropwizard bundle is a reusable group of functionality, used to define blocks of a - service’s behavior. For example, AssetBundle provides a simple way to serve - static assets from your service’s src/main/resources/assets directory as - files available from /assets/* in your service. -

          - -

          - Some bundles require configuration parameters. The bundles implement - ConfiguredBundle and will require your service’s Configuration - subclass to implement a specific interface. -

          - -

          Commands

          - -

          - Commands are basic actions which Dropwizard runs based on the arguments provided on the - command line. The built-in server command, for example, spins up an HTTP - server and runs your service. Each Command subclass has a name and a set - of command line options which Dropwizard will use to parse the given command line - arguments. -

          - -

          Configured Commands

          - -

          - Some commands require access to configuration parameters and should extend the - ConfiguredCommand class, using your service’s Configuration - class as its type parameter. Dropwizard will treat the first argument on the command - line as the path to a YAML configuration file, parse and validate it, and provide your - command with an instance of the configuration class. -

          - -

          Managed Commands

          - -

          - Managed commands further extend configured commands by creating a lifecycle process for - your service’s managed objects. All Managed - instances registered with your service’s Environment will be started before - your command is run, and will be stopped afterward. -

          - -

          Tasks

          - -

          - A Task is a run-time action your service provides access to on the - administrative port via HTTP. All Dropwizard services start with the gc - task, which explicitly triggers the JVM's garbage collection. (This is useful, for - example, for running full garbage collections during off-peak times or while the given - service is out of rotation.) -

          - -

          - Running a task can be done by sending a POST request to - /tasks/{task-name} on the admin port. For example: -

          - -
          -$ curl -X POST http://dw.example.com:8081/tasks/gc
          -Running GC...
          -Done!
          - -

          Logging

          - -

          - Dropwizard uses Log4j for - its logging backend. It provides an - slf4j implementation, and even - routes all java.util.logging usage through log4j. -

          - -

          The Log class

          - -

          - Dropwizard comes with a Log convenience class, since most of the logging - APIs are horrendous. -

          - -
          -public class Example {
          -    private static final Log LOG = Log.forClass(Example.class);
          -
          -    public long fetchAge(long userId) {
          -        LOG.debug("Fetching age for user {}", userId);
          -
          -        try {
          -            final User user = users.find(userId);
          -            return user.getAge();
          -        } catch (IOException e) {
          -            LOG.error(e, "Error connecting to user store for user {}", userId);
          -        } catch (UserNotFoundException e) {
          -            LOG.warn(e, "Unable to fetch age for user {}", userId);
          -        }
          -    }
          -}
          - -

          - Log provides the same statement formatting amenities as SLF4J, so you can - pass arbitrary objects in without having to concatenate strings. Instances of - {} in the log message are replaced with the string representation of the - objects. To log exceptions, just pass the Throwable instance as the first - parameter and it'll log the exception type, message, and stack trace. -

          - -

          - The Log class also provides the following logging levels: -

          - -
          -
          FATAL
          -
          - Very severe error events that will presumably lead the application to abort. -
          - -
          ERROR
          -
          - Error events that might still allow the application to continue running. -
          - -
          WARN
          -
          - Potentially harmful situations. -
          - -
          INFO
          -
          - Informational messages that highlight the progress of the application at - coarse-grained level. -
          - -
          DEBUG
          -
          - Fine-grained informational events that are most useful to debug an application. -
          - -
          TRACE
          -
          - Finer-grained informational events than the DEBUG level. -
          -
          - -

          Log Format

          - -

          Dropwizard’s log format has a few specific goals:

          - -
            -
          • Be human readable.
          • -
          • Be machine parsable.
          • -
          • - Be easy for sleepy ops folks to figure out why things are pear-shaped at 3:30AM - using standard UNIXy tools like tail and grep. -
          • -
          - -

          The logging output looks like this:

          - -
          -TRACE [2010-04-06 06:42:35,271] com.example.dw.Thing: Contemplating doing a thing.
          -DEBUG [2010-04-06 06:42:35,274] com.example.dw.Thing: About to do a thing.
          -INFO  [2010-04-06 06:42:35,274] com.example.dw.Thing: Doing a thing
          -WARN  [2010-04-06 06:42:35,275] com.example.dw.Thing: Doing a thing
          -ERROR [2010-04-06 06:42:35,275] com.example.dw.Thing: This may get ugly.
          -FATAL [2010-04-06 06:42:35,275] com.example.dw.Thing: The thing has gone horribly wrong.
          -! java.lang.RuntimeException: oh noes!
          -! at com.example.dw.Thing.run(Thing.java:16)
          -!
          - -

          A few items of note:

          - -
            -
          • All timestamps are in UTC and ISO 8601 format.
          • -
          • - You can grep for messages of a specific level really easily: - tail -f dw.log | grep '^WARN' -
          • -
          • - You can grep for messages from a specific class or package really easily: - tail -f dw.log | grep 'com.example.dw.Thing' -
          • -
          • - You can even pull out full exception stack traces, plus the accompanying - log message: tail -f dw.log | grep -B 1 '^\!' -
          • -
          - -

          - You can specify a default logger level and even override the levels of other loggers in - your YAML configuration file: -

          - -
          -# Logging settings.
          -logging:
          -  # The default level of all loggers. Can be OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, or ALL.
          -  level: INFO
          -  # Logger-specific levels.
          -  loggers:
          -    # Overrides the level of com.example.dw.Thing and sets it to DEBUG.
          -    "com.example.dw.Thing": DEBUG
          - -

          Console Logging

          - -

          - By default, Dropwizard services log INFO and higher to STDOUT. - You can configure this by editing the logging section of your YAML - configuration file: -

          - -
          -logging:
          -  # ...
          -  # Settings for logging to stdout.
          -  console:
          -    # If true, write log statements to stdout.
          -    enabled: true
          -    # Do not display log statements below this threshold to stdout.
          -    threshold: ALL
          - -

          File Logging

          - -

          - Dropwizard can also log to an automatically rotated set of log files. This is the - recommended configuration for your production environment: -

          - -
          -logging:
          -  # ...
          -  # Settings for logging to a file.
          -  file:
          -    # If true, write log statements to a file.
          -    enabled: false
          -    # Do not write log statements below this threshold to the file.
          -    threshold: ALL
          -    # The file to which statements will be logged. When the log file reaches the maximum size, the
          -    # file will be renamed example.log.1, example.log will be truncated, and new statements written
          -    # to it.
          -    filenamePattern: ./logs/example.log
          -    # The maximum size of any log file. Can also be "1GiB" etc
          -    maxFileSize: 50MB
          -    # The maximum number of log files to retain.
          -    retainedFileCount: 5
          - -

          Syslog Logging

          - -

          - Finally, Dropwizard can also log statements to syslog. (Note: because - Java doesn’t use the native syslog bindings, your syslog server must - have an open network socket.) -

          - -
          -logging:
          -  # ...
          -  # Settings for logging to syslog.
          -  syslog:
          -    # If true, write log statements to syslog.
          -    enabled: false
          -    # The hostname of the syslog server to which statements will be sent.
          -    # N.B.: If this is the local host, the local syslog instance will need to be configured to
          -    # listen on an inet socket, not just a Unix socket.
          -    host: localhost
          -    # The syslog facility to which statements will be sent.
          -    facility: local0
          -        
          - -

          Testing Services

          - -

          - All of Dropwizard’s APIs are designed with testability in mind, so even your services - can have unit tests: -

          - -
          -public class MyServiceTest {
          -    private final Environment environment = mock(Environment.class);
          -    private final MyService service = new MyService();
          -    private final MyConfiguration config = new MyConfiguration();
          -
          -    @Before
          -    public void setup() throws Exception {
          -        config.setMyParam("yay");
          -    }
          -
          -    @Test
          -    public void buildsAThingResource() throws Exception {
          -        service.initialize(config, environment);
          -
          -        verify(environment).addResource(any(ThingResource.class));
          -    }
          -}
          - -

          - We highly recommend - Mockito for all your - mocking needs. -

          - -

          Banners

          - -

          - At Yammer, each of our services prints out a big ASCII art banner on startup. Yours - should, too. It’s fun. Just add a banner.txt class to - src/main/resources and it’ll print it out when your service starts: -

          - -
          -INFO  [2011-12-09 21:56:37,209] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world
          -INFO  [2011-12-09 21:56:37,214] com.yammer.dropwizard.cli.ServerCommand:
          -                                                 dP
          -                                                 88
          -  .d8888b. dP.  .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b.
          -  88ooood8  `8bd8'  88'  `88 88'`88'`88 88'  `88 88 88ooood8
          -  88.  ...  .d88b.  88.  .88 88  88  88 88.  .88 88 88.  ...
          -  `88888P' dP'  `dP `88888P8 dP  dP  dP 88Y888P' dP `88888P'
          -                                        88
          -                                        dP
          -
          -INFO  [2011-12-09 21:56:37,214] org.eclipse.jetty.server.Server: jetty-7.6.0.RC1
          -...
          - -

          - We could probably make up an argument about why this is a serious devops best practice - with high ROI and an Agile Tool, but honestly we just enjoy this. -

          - -

          Resources

          - -

          - Unsurprisingly, most of your day-to-day work with a Dropwizard service will be in the - resource classes, which model the resources exposed in your RESTful API. Dropwizard - uses Jersey for this, so most of - this section is just re-hashing or collecting various bits of Jersey documentation. -

          - -

          - Jersey is a framework for mapping various aspects of incoming HTTP requests to POJOs and - then mapping various aspects of POJOs to outgoing HTTP responses. Here’s a basic - resource class: -

          - -
          -@Path("/{user}/notifications")
          -@Produces(MediaType.APPLICATION_JSON)
          -@Consumes(MediaType.APPLICATION_JSON)
          -public class NotificationsResource {
          -    private final NotificationStore store;
          -
          -    public NotificationsResource(NotificationStore store) {
          -        this.store = store;
          -    }
          -
          -    @GET
          -    public NotificationList fetch(@PathParam("user") LongParam userId,
          -                                  @QueryParam("count") @DefaultValue("20") IntParam count) {
          -        final List<Notification> notifications = store.fetch(userId.get(), count.get());
          -        if (notifications != null) {
          -            return new NotificationList(userId, notifications);
          -        }
          -        throw new WebApplicationException(Status.NOT_FOUND);
          -    }
          -
          -    @POST
          -    public Response add(@PathParam("user") LongParam userId,
          -                        @Valid Notification notification) {
          -        final long id = store.add(userId.get(), notification);
          -        return Response.created(UriBuilder.fromResource(NotificationResource.class)
          -                                          .build(userId.get(), id)
          -                       .build();
          -    }
          -}
          - -

          - This class provides a resource (a user’s list of notifications) which responds to - GET and POST requests to /{user}/notifications, - providing and consuming application/json representations. There’s quite a - lot of functionality on display here, and this section will explain in detail what’s - in play and how to use these features in your service. -

          - -

          Paths

          - -

          - Every resource class must have a @Path annotation. The - @Path annotation isn’t just a static string, it's a - URI Template. - The {user} part denotes a named variable, and when the template matches a - URI the value of that variable will be accessible via @PathParam-annotated - method parameters. -

          - -

          - For example, an incoming request for /1001/notifications would match the - URI template, and the value 1001 would be available as the path parameter - named user. -

          - -

          - If your service doesn’t have a resource class whose @Path URI template - matches the URI of an incoming request, Jersey will automatically return a - 404 Not Found to the client. -

          - -

          Methods

          - -

          - Methods on a resource class which accept incoming requests are annotated with the HTTP - methods they handle: @GET, @POST, @PUT, - @DELETE, @HEAD, @OPTIONS, and even - @HttpMethod for arbitrary new methods. -

          - -

          - If a request comes in which matches a resource class’s path but has a method which the - class doesn’t support, Jersey will automatically return a - 405 Method Not Allowed to the client. -

          - -

          - The return value of the method (in this case, a NotificationList instance) - is then mapped to the negotiated content type. In this case, our - resource only supports JSON, and so the NotificationList is serialized to - JSON using Jackson. -

          - -

          Metrics

          - -

          - Every resource method can be annotated with @Timed, @Metered, - and @ExceptionMetered. Dropwizard augments Jersey to automatically record - runtime information about your resource methods. -

          - -

          Parameters

          - -

          - The annotated methods on a resource class can accept parameters which are mapped to from - aspects of the incoming request. The *Param annotations determine which - part of the request the data is mapped, and the parameter type determines how - the data is mapped. -

          - -

          - For example: -

          - -
            -
          • - A @PathParam("user")-annotated String takes the raw value - from the user variable in the matched URI template and passes it into - the method as a String. -
          • -
          • - A @QueryParam("count")-annotated IntParam parameter takes - the first count value from the request’s query string and passes it as - a String to IntParam’s constructor. IntParam - (and all other com.yammer.dropwizard.jersey.params.* classes) parses - the string as an Integer, returning a 400 Bad Request if - the value is malformed. -
          • -
          • - A @FormParam("name")-annotated Set<String> parameter - takes all the name values from a posted form and passes them to the - method as a set of strings. -
          • -
          - -

          - What’s noteworthy here is that you can actually encapsulate the vast majority of your - validation logic using specialized parameter objects. See AbstractParam for - details. -

          - -

          Request Entities

          - -

          - If you’re handling request entities (e.g., an application/json object on - a PUT request), you can model this as a parameter without a - *Param annotation. In the example code, - the add method provides a good example of this: -

          - -
          -@POST
          -public Response add(@PathParam("user") LongParam userId,
          -                    @Valid Notification notification) {
          -    final long id = store.add(userId.get(), notification);
          -    return Response.created(UriBuilder.fromResource(NotificationResource.class)
          -                                      .build(userId.get(), id)
          -                   .build();
          -}
          - -

          - Jersey maps the request entity to any single, unbound parameter. In this case, because - the resource is annotated with @Consumes(MediaType.APPLICATION_JSON), it - uses the Dropwizard-provided Jackson support which, in addition to parsing the JSON and - mapping it to an instance of Notification, also runs it through - Dropwizard’s validation. -

          - -

          - If the deserialized Notification isn’t valid, Dropwizard returns a - 422 Unprocessable Entity response to the client. -

          - -

          Media Types

          - -

          - Jersey also provides full content negotiation, so if your resource class consumes - application/json but the client sends a text/plain entity, - Jersey will automatically reply with a 406 Not Acceptable. Jersey’s even - smart enough to use client-provided q-values in their Accept - headers to pick the best response content type based on what both the client and server - will support. -

          - -

          Responses

          - -

          - If your clients are expecting custom headers or additional information (or, if you - simply desire an additional degree of control over your responses), you can return - explicitly-built Response objects: -

          - -
          -return Response.noContent().language(Locale.GERMAN).build();
          - -

          - In general, though, we recommend you return actual domain objects if at all possible. - It makes testing resources much easier. -

          - -

          Error Handling

          - -

          - If your resource class unintentionally throws an exception, Dropwizard will log that - exception (including stack traces) and return a terse, safe 500 response. -

          - -

          - If your resource class needs to return an error to the client (e.g., the requested - record doesn’t exist), you have two options: throw a - WebApplicationException or restructure your method to return a - Response. -

          - -

          - If at all possible, prefer throwing WebApplicationException instances to - returning Response objects. -

          - -

          URIs

          - -

          - While Jersey doesn’t quite have first-class support for hyperlink-driven services, the - provided UriBuilder functionality does quite well. -

          - -

          - Rather than duplicate resource URIs, it’s possible (and recommended!) to initialize a - UriBuilder with the path from the resource class itself: -

          - -
          -UriBuilder.fromResource(UserResource.class).build(user.getId());
          - -

          Testing

          - -

          - As with just about everything in Dropwizard, we recommend you design your resources to - be testable. Dependencies which aren’t request-injected should be passed in via the - constructor and assigned to final fields. -

          - -

          - Testing, then, consists of creating an instance of your resource class and passing it - a mock. (Again: Mockito.) -

          - -
          -public class NotificationsResourceTest {
          -    private final NotificationStore store = mock(NotificationStore.class);
          -    private final NotificationsResource resource = new NotificationsResource(store);
          -
          -    @Test
          -    public void getsReturnNotifications() {
          -        final List<Notification> notifications = mock(List.class);
          -        when(store.fetch(1, 20)).thenReturn(notifications);
          -
          -        final NotificationList list = resource.fetch(new LongParam("1"), new IntParam("20"));
          -
          -        assertThat(list.getUserId(),
          -                  is(1L));
          -
          -        assertThat(list.getNotifications(),
          -                   is(notifications));
          -    }
          -}
          - -

          OAuth2

          - -

          - Dropwizard provides some super-minimalist support for - Oauth 2: -

          - -
          -public Blah doAThing(@BearerToken String token) {
          -    // etc
          -}
          - -

          - The Oauth 2 bearer token will be passed in via token. -

          - -

          Representations

          - -

          - Representation classes are classes which, when handled to various Jersey - MessageBodyReader and MessageBodyWriter providers, become the - entities in your service’s API. Dropwizard heavily favors JSON, but it’s possible to - map from any POJO to custom formats and back. -

          - -

          Basic JSON

          - -

          - Jackson is awesome at converting regular POJOs to JSON and back. This file: -

          - -
          -public class Notification {
          -    @JsonProperty
          -    private String text;
          -
          -    public Notification(String text) {
          -        this.text = text;
          -    }
          -
          -    public String getText() {
          -        return text;
          -    }
          -
          -    public String setText(String text) {
          -        this.text = text;
          -    }
          -}
          - -

          - gets converted into this JSON: -

          - -
          -{
          -    "text": "hey it's the value of the text field"
          -}
          - -

          - If, at some point, you need to change the JSON field name or the Java field without - affecting the other, you can add an explicit field name to the - @JsonProperty annotation. -

          - -

          - If you prefer immutable objects rather than JavaBeans, that’s also doable: -

          - -
          -public class Notification {
          -    @JsonProperty
          -    private final String text;
          -
          -    public Notification(@JsonProperty("text") String text) {
          -        this.text = text;
          -    }
          -
          -    public String getText() {
          -        return text;
          -    }
          -}
          - -

          Advanced JSON

          - -

          - Not all JSON representations map nicely to the objects your service deals with, so it’s - sometimes necessary to use custom serializers and deserializers. Just annotate your - object like this: -

          - -
          -@JsonSerialize(using=FunkySerializer.class)
          -@JsonDeserialize(using=FunkyDeserializer.class)
          -public class Funky {
          -    // ...
          -}
          - -

          - Then make a FunkySerializer class which implements - JsonSerializer<Funky> and a FunkyDeserializer class - which implements JsonDeserializer<Funky>. -

          - -

          snake_case

          - -

          - A common issue with JSON is the disagreement between camelCase and - snake_case field names. Java and Javascript folks tend to like - camelCase; Ruby, Python, and Perl folks insist on snake_case. - To make Dropwizard automatically convert field names to snake_case (and - back), just annotate the class with @JsonSnakeCase: -

          - - - -
          -@JsonSnakeCase
          -public class Person {
          -    @JsonProperty
          -    private String firstName;
          -
          -    public Person(String firstName) {
          -        this.firstName = firstName;
          -    }
          -
          -    public String getFirstName() {
          -        return firstName;
          -    }
          -}
          - -

          - gets converted into this JSON: -

          - -
          -{
          -    "first_name": "Coda"
          -}
          - -

          Validation

          - -

          - Like configuration classes, you can add validation - annotations to fields of your representation classes and validate them. If we‘re - accepting client-provided Person objects, we probably want to ensure that - the name field of the object isn’t null or blank. We can do - this as follows: -

          - -
          -public class Person {
          -    @NotEmpty // ensure that name isn't null or blank
          -    @JsonProperty
          -    private final String name;
          -
          -    public Person(@JsonProperty("name") String name) {
          -        this.name = name;
          -    }
          -
          -    public String getName() {
          -        return name;
          -    }
          -}
          - -

          - Then, in our resource class, we can add the @Valid annotation to the - Person annotation: -

          - -
          -@PUT
          -public Response replace(@Valid Person person) {
          -    // ...
          -}
          - -

          - If the name field is missing, Dropwizard will return a - text/plain 422 Unprocessable Entity response detailing the - validation errors: -

          - -
          -* name may not be empty
          - -

          Advanced

          - -

          - More complex validations (for example, cross-field comparisons) are often hard to - do using declarative annotations. As an emergency maneuver, add the - @ValidationMethod to any boolean-returning method which - begins with is: -

          - -
          -@ValidationMethod(message="may not be Coda")
          -public boolean isNotCoda() {
          -    return !("Coda".equals(name));
          -}
          - -

          - Due to the rather daft JavaBeans conventions, the method must begin with - is. This is a limitation of Hibernate Validator, - not Dropwizard. -

          - -

          Streaming Output

          - -

          - If your service happens to return lots of information, you may get a big performance - and efficiency bump by using streaming output. By returning an object which implements - Jersey’s StreamingOutput interface, your method can stream the response - entity in a chunk-encoded output stream. Otherwise, you’ll need to fully construct your - return value and then hand it off to be sent to the client. -

          - -

          Testing

          - -

          - The dropwizard-testing module contains a number of helper methods for - testing JSON parsing and generating. Given a JSON fixture file (e.g., - src/test/resources/fixtures/person.json), you can test that a - Person instance generates the same JSON as the fixture with the following: -

          - -
          -import static com.yammer.dropwizard.testing.JsonHelpers.asJson;
          -import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture;
          -
          -@Test
          -public void producesTheExpectedJson() throws Exception {
          -    assertThat("rendering a person as JSON produces a valid API representation",
          -               asJson(person),
          -               is(jsonFixture("fixtures/person.json")));
          -}
          - -

          - This does a whitespace- and comment-insensitive comparison of the generated JSON and the - JSON in the file. If they’re different, both JSON representations are helpfully - displayed in the assertion error. -

          - -

          - Likewise, you can also test the parsing of the same JSON file to guarantee round-trip - compatibility: -

          - -
          -import static com.yammer.dropwizard.testing.JsonHelpers.fromJson;
          -
          -@Test
          -public void consumesTheExpectedJson() throws Exception {
          -    assertThat("parsing a valid API representation produces a person",
          -               fromJson(jsonFixture("fixtures/person.json"), Person.class),
          -               is(person));
          -}
          - -

          Custom Representations

          - -

          - Sometimes, though, you’ve got some wacky output format you need to produce or consume - and no amount of arguing will make JSON acceptable. That’s unfortunate but OK. You can - add support for arbitrary input and output formats by creating classes which implement - Jersey’s MessageBodyReader<T> and - MessageBodyWriter<T> interfaces. (Make sure they’re annotated with - @Provider and @Produces("text/gibberish") or - @Consumes("text/gibberish").) Once you’re done, just add instances of them - (or their classes if they depend on Jersey’s @Context injection) with your - service’s Environment on initialization. -

          - -

          Running Services

          - -

          TODO

          - -

          In Production

          - -

          TODO

          - -

          Dropwizard Client

          - -

          TODO

          - -

          Dropwizard DB

          - -

          TODO

          - -

          Dropwizard Templates

          - -

          TODO

          - -

          Dropwizard & Scala

          - -

          TODO

          - -
          -

          © Yammer 2011

          -
          -
          -
          - - - diff --git a/docs/pages/getting-started.md b/docs/pages/getting-started.md new file mode 100644 index 00000000000..d54ddcb4254 --- /dev/null +++ b/docs/pages/getting-started.md @@ -0,0 +1,642 @@ +Title: Getting Started +Template: manual.html.erb +Order: 2 +* * * + +The goal of this document is to guide you through the process of +creating a simple Dropwizard project: Hello World. Along the way, we’ll +explain the various underlying libraries and their roles, important +concepts in Dropwizard, and suggest some organizational techniques to +help you as your project grows. (Or you can just skip to the +[fun part](#maven).) + +## Overview #overview + +Dropwizard straddles the line between being a library and a framework. +Its goal is to provide performant, reliable implementations of +everything a production-ready web service needs. Because this +functionality is extracted into a reusable library, your service remains +lean and focused, reducing both time-to-market and maintenance burdens. + +### Jetty for HTTP + +Because you can't be a web service without HTTP, Dropwizard uses the +[Jetty](http://www.eclipse.org/jetty/) HTTP library to embed an +incredibly tuned HTTP server directly into your project. Instead of +handing your service off to a complicated application server, Dropwizard +projects have a `main` method which spins up an HTTP server. Running +your service as a simple process eliminates a number of unsavory aspects +of Java in production (no PermGem issues, no application server +configuration and maintenance, no arcane deployment tools, no +`ClassLoader` troubles, no hidden application logs, no trying to tune a +single garbage collector to work with multiple application workloads) +and allows you to use all of Unix's existing process management tools +instead. + +### Jersey for REST + +For building RESTful web services, we've found nothing beats +[Jersey](http://jersey.java.net) (the +[JAX-RS](http://jcp.org/en/jsr/detail?id=311) reference implementation) +in terms of features or performance. It allows you to write clean, +testable classes which gracefully map HTTP requests to simple Java +objects. It supports streaming output, matrix URI parameters, +conditional `GET` requests, and much, much more. + +### Jackson for JSON + +In terms of data formats, JSON has become the web’s *lingua franca*, and +[Jackson](http://jackson.codehaus.org/) is the king of JSON on the JVM. +In addition to being lightning fast, it has a sophisticated object +mapper, allowing you to export your domain models directly. + +### Metrics for metrics + +Our very own [Metrics](https://github.com/codahale/metrics) library +rounds things out, providing you with unparalleled insight into your +code’s behavior in your production environment. + +### And Friends + +In addition to Jetty, Jersey, and Jackson, Dropwizard also includes a +number of libraries that we've come to rely on: + +- [Guava](http://code.google.com/p/guava-libraries/), which, in + addition to highly optimized immutable data structures, provides a + growing number of classes to speed up development in Java. +- [Log4j](http://logging.apache.org/log4j/1.2/) and + [slf4j](http://www.slf4j.org/) for performant logging. +- [Hibernate + Validator](http://www.hibernate.org/subprojects/validator.html), the + [JSR-303](http://jcp.org/en/jsr/detail?id=303) reference + implementation, provides an easy, declarative framework for + validating user input and generating helpful, internationalizable + error messages. +- [Apache + HttpClient](http://hc.apache.org/httpcomponents-client-ga/index.html) + and Jersey's client library allow for both low- and high-level + interaction with other web services. +- [JDBI](http://www.jdbi.org) is the most straight-forward way to use + a relational database with Java. +- [Freemarker](http://freemarker.sourceforge.net/) is a simple + template system for more user-facing services. + +Now that you've gotten the lay of the land, let's dig in! + +* * * * * + +## Setting Up Maven #maven + +We recommend you use [Maven](http://maven.apache.org) for new Dropwizard +services. If you're a big +[Ant](http://ant.apache.org/)/[Ivy](http://ant.apache.org/ivy/), +[Buildr](http://buildr.apache.org/), [Gradle](http://www.gradle.org/), +[SBT](https://github.com/harrah/xsbt/wiki), or +[Gant](http://gant.codehaus.org/) fan, that’s cool, but we use Maven and +we'll be using Maven as we go through this example service. If you have +any questions about how Maven works, [Maven: The Complete +Reference](http://www.sonatype.com/books/mvnref-book/reference/) should +have what you’re looking for. (We’re assuming you know how to create a +new Maven project.) + +Add the `dropwizard-core` library as a dependency: + +``` xml + + + com.yammer.dropwizard + dropwizard-core + 0.1.3 + + +``` + +Alright, that’s enough XML. We’ve got a Maven project set up now, and +it’s time to start writing real code. + +* * * * * + +## Creating A Configuration Class #configuration + +Each Dropwizard service has its own subclass of the `Configuration` +class which specify environment-specific parameters. These parameters +are specified in a [YAML](http://www.yaml.org/) configuration file which +is deserialized to an instance of your service’s configuration class and +validated. + +The service we’re building is a high-performance Hello World service, +and part of our requirements is that we need to be able to vary how it +says hello from environment to environment. We’ll need to specify at +least two things to begin with: a template for saying hello and a +default name to use in case the user doesn’t specify their name. + +Here's what our configuration class will look like: + +``` java +package com.example.helloworld; + +import com.yammer.dropwizard.config.Configuration; +import org.hibernate.validator.constraints.NotEmpty; + +public class HelloWorldConfiguration extends Configuration { + @NotEmpty + private String template; + + @NotEmpty + private String defaultName = "Stranger"; + + public String getTemplate() { + return template; + } + + public String getDefaultName() { + return defaultName; + } +} +``` + +There's a lot going on here, so let’s unpack a bit of it. + +When this class is deserialized from the YAML file, it will pull two +root-level fields from the YAML object: `template`, the template for our +Hello World saying, and `defaultName`, the default name to use. Both +`template` and `defaultName` are annotated with `@NotEmpty`, so if the +YAML configuration file has blank values for either or is missing +`template` entirely an informative exception will be thrown and your +service won’t start. + +Our YAML file, then, will look like this: + +``` yaml +template: Hello, %s! +defaultName: Stranger +``` + +Dropwizard has a *lot* more configuration parameters than that, but they +all have sane defaults so you can keep your configuration files small +and focused. + +So save that YAML file as `hello-world.yml`, because we’ll be getting up +and running pretty soon and we’ll need it. Next up, we’re creating our +service class! + +* * * * * + +## Creating A Service Class #service + +Combined with your project’s `Configuration` subclass, its `Service` +form the core of your Dropwizard service. The `Service` class pulls +together the various bundles and commands which provide basic +functionality. (More on that later.) For now, though, our +`HelloWorldService` looks like this: + +``` java +package com.example.helloworld; + +import com.yammer.dropwizard.Service; +import com.yammer.dropwizard.config.Environment; + +public class HelloWorldService extends Service { + public static void main(String[] args) throws Exception { + new HelloWorldService().run(args); + } + + private HelloWorldService() { + super("hello-world"); + } + + @Override + protected void initialize(HelloWorldConfiguration configuration, + Environment environment) { + // nothing to do yet + } + +} +``` + +As you can see, `HelloWorldService` is parameterized with the service’s +configuration type, `HelloWorldConfiguration`. `HelloWorldService`’s +constructor provides the service’s name: `hello-world`. Also, we’ve +added a `static` `main` method, which will be our service’s entry point. +Right now, we don’t have any functionality implemented, so our +`initialize` method is a little boring. Let’s fix that! + +* * * * * + +## Creating A Representation Class #representation + +Before we can get into the nuts-and-bolts of our Hello World service, we +need to stop and think about our API. Luckily, our service needs to +conform to an industry standard, [RFC +1149](http://www.ietf.org/rfc/rfc1149.txt "This is a joke."), which +specifies the following JSON representation of a Hello World saying: + +``` javascript +{ + "id": 1, + "content": "Hello, stranger!" +} +``` + +The `id` field is a unique identifier for the saying, and `content` is +the textual representation of the saying. (Thankfully, this is a fairly +straight-forward industry standard.) + +To model this representation, we'll create a representation class: + +``` javascript +package com.example.helloworld.core; + +public class Saying { + private final long id; + private final String content; + + public Saying(long id, String content) { + this.id = id; + this.content = content; + } + + public long getId() { + return id; + } + + public String getContent() { + return content; + } +} +``` + +This is a pretty simple POJO, but there are a few things worth noting +here. + +First, it’s immutable. This makes `Saying` instances *very* easy to +reason about multi-threaded environments as well as single-threaded +environments. Second, it uses the Java Bean standard for the `id` and +`content` properties. This allows Jackson to serialize it to the JSON we +need. The Jackson object mapping code will populate the `id` field of +the JSON object with the return value of `getId()`, likewise with +`content` and `getContent()`. + +Now that we’ve got our representation class, it makes sense to start in +on the resource it represents. + +* * * * * + +## Creating A Resource Class #resource + +Jersey resources are the meat-and-potatoes of a Dropwizard service. Each +resource class is associated with a URI template. For our service, we +need a resource which returns new `Saying` instances from the URI +`/hello-world`, so our resource class will look like this: + +``` java +package com.example.helloworld.resources; + +import com.example.helloworld.core.Saying; +import com.google.common.base.Optional; +import com.yammer.metrics.annotation.Timed; + +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 java.util.concurrent.atomic.AtomicLong; + +@Path("/hello-world") +@Produces(MediaType.APPLICATION_JSON) +public class HelloWorldResource { + private final String template; + private final String defaultName; + private final AtomicLong counter; + + public HelloWorldResource(String template, String defaultName) { + this.template = template; + this.defaultName = defaultName; + this.counter = new AtomicLong(); + } + + @GET + @Timed + public Saying sayHello(@QueryParam("name") Optional name) { + return new Saying(counter.incrementAndGet(), + String.format(template, name.or(defaultName))); + } +} +``` + +Finally, we’re in the thick of it! Let’s start from the top and work our +way down. + +`HelloWorldResource` has two annotations: `@Path` and `@Produces`. +`@Path("/hello-world")` tells Jersey that this resource is accessible at +the URI `/hello-world`, and `@Produces(MediaType.APPLICATION_JSON)` lets +Jersey’s content negotiation code know that this resource produces +representations which are `application/json`. + +`HelloWorldResource` takes two parameters for construction: the +`template` it uses to produce the saying and the `defaultName` used when +the user declines to tell us their name. An `AtomicLong` provides us +with a cheap, thread-safe way of generating unique(ish) IDs. + +**Remember**: Resource classes are used by multiple threads +concurrently. In general, we recommend that resources be +stateless/immutable, but it’s important to keep the context in mind. + +`sayHello(Optional)` is the meat of this class, and it’s a +fairly simple method. The `@QueryParam("name")` tells Jersey to map the +`name` parameter from the query string to the `name` parameter in the +method. If the client sends a request to `/hello-world?name=Dougie`, +`sayHello` will be called with `Optional.of("Dougie")`; if there is no +`name` parameter in the query string, `sayHello` will be called with +`Option.absent()`. (Support for Guava's `Optional` is a little extra +sauce that Dropwizard adds to Jersey's existing functionality.) + +Inside the `sayHello` method, we increment the counter, format the +template using `String.format(String, Object...)`, and return a new +`Saying` instance. + +Because `sayHello` is annotated with `@Timed`, Dropwizard automatically +records the duration and rate of its invocations as a Metrics Timer. + +Once `sayHello` has returned, Jersey takes the `Saying` instance and +looks for a provider class which can write `Saying` instances as +`application/json`. Dropwizard has one such provider built in which +allows for producing and consuming Java objects as JSON objects. The +provider writes out the JSON and the client receives a `200 OK` response +with a content type of `application/json`. + +Before that will actually work, though, we need to go back to our +`HelloWorldService` and add this new resource class. In its `initialize` +method we can read the template and default name from the +`HelloWorldConfiguration` instance, create a new `HelloWorldService` +instance, and then add it to the service’s environment: + +``` java +@Override +protected void initialize(HelloWorldConfiguration configuration, + Environment environment) { + final String template = configuration.getTemplate(); + final String defaultName = configuration.getDefaultName(); + environment.addResource(new HelloWorldResource(template, defaultName)); +} +``` + +When our service starts, we create a new instance of our resource class +with the parameters from the configuration file and hand it off to the +`Environment`, which acts like a registry of all the things your service +can do. + +Before we go too far, we should add a health check for our service. + +* * * * * + +## Adding A Health Check #healthcheck + +Health checks give you a way of adding small tests to your service to +allow you and your ops team to verify that your service is functioning +correctly in production. We **strongly** recommend that all of your +services have at least a minimal set of health checks. (We recommend +this so strongly, in fact, that Dropwizard will nag you should you +neglect to add a health check to your project.) + +Since formatting strings is not likely to fail while a service is +running (unlike, say, a database connection pool), we’ll have to get a +little creative here. We’ll add a health check to make sure we can +actually format the provided template: + +``` java +package com.example.helloworld.health; + +import com.yammer.metrics.core.HealthCheck; + +public class TemplateHealthCheck extends HealthCheck { + private final String template; + + public TemplateHealthCheck(String template) { + super("template"); + this.template = template; + } + + @Override + protected Result check() throws Exception { + final String saying = String.format(template, "TEST"); + if (!saying.contains("TEST")) { + return Result.unhealthy("template doesn't include a name"); + } + return Result.healthy(); + } +} +``` + +`TemplateHealthCheck` checks for two things: that the provided template +is actually a well-formed format string, and that the template actually +produces output with the given name. + +If the string is not a well-formed format string (for example, someone +accidentally put `Hello, %s%` in the configuration file), then +`String.format(String, Object...)` will throw an +`IllegalFormatException` and the health check will implicitly fail. If +the rendered saying doesn’t include the test string, the health check +will explicitly fail by returning an unhealthy `Result`. + +As with most things in Dropwizard, we create a new instance with the +appropriate parameters and add it to the `Environment`: + +``` java +@Override +protected void initialize(HelloWorldConfiguration configuration, + Environment environment) { + final String template = configuration.getTemplate(); + final String defaultName = configuration.getDefaultName(); + environment.addResource(new HelloWorldResource(template, defaultName)); + environment.addHealthCheck(new TemplateHealthCheck(template)); +} +``` + +Now we're almost ready to go! + +* * * * * + +## Building Fat JARs #building + +We recommend that you build your Dropwizard services as “fat†JAR +files—single `.jar` files which contain *all* of the `.class` files +required to run your service. This allows you to build a single +deployable artifact which you can copy from your staging environment to +your QA environment to your production environment without worrying +about differences in installed libraries. To start building our Hello +World service as a fat JAR, we need to configure a Maven plugin called +`maven-shade`. In your `pom.xml` file, add this: + +``` xml + + org.apache.maven.plugins + maven-shade-plugin + 1.4 + + true + + + + package + + shade + + + + + + com.example.helloworld.HelloWorldService + + + + + + + +``` + +This configures Maven to do a couple of things during its `package` +phase: + +- Produce a `pom.xml` file which doesn’t include dependencies for the + libraries whose contents are included in the fat JAR. +- Collate the various `META-INF/services` entries in the JARs instead + of overwriting them. (Jersey doesn’t work without those.) +- Set `com.example.helloworld.HelloWorldService` as the JAR’s + `MainClass`. + +Once you’ve got that configured, go into your project directory and run +`mvn package` (or run the `package` goal from your IDE). You should see +something like this: + +``` +[INFO] Including org.eclipse.jetty:jetty-util:jar:7.6.0.RC0 in the shaded jar. +[INFO] Including com.google.guava:guava:jar:10.0.1 in the shaded jar. +[INFO] Including com.google.code.findbugs:jsr305:jar:1.3.9 in the shaded jar. +[INFO] Including org.hibernate:hibernate-validator:jar:4.2.0.Final in the shaded jar. +[INFO] Including javax.validation:validation-api:jar:1.0.0.GA in the shaded jar. +[INFO] Including org.yaml:snakeyaml:jar:1.9 in the shaded jar. +[INFO] Replacing original artifact with shaded artifact. +[INFO] Replacing /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT.jar with /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT-shaded.jar +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 8.415s +[INFO] Finished at: Fri Dec 02 16:26:42 PST 2011 +[INFO] Final Memory: 11M/81M +[INFO] ------------------------------------------------------------------------ +``` + +**Congratulations!** You’ve built your first Dropwizard project! Now +it’s time to run it! + +* * * * * + +## Running Your Service #running + +Now that you’ve built a JAR file, it’s time to run it. + +In your project directory, run +`java -jar target/hello-world-0.0.1-SNAPSHOT.jar`. You should see +something like the following: + +``` +java -jar dropwizard-example-0.1.0-SNAPSHOT.jar [arg1 arg2] + +Commands +======== + +server: Starts an HTTP server running the service +------------------------------------------------- +usage: java -jar dropwizard-example-0.1.0-SNAPSHOT.jar server + -h, --help display usage information +``` + +Dropwizard takes the first command line argument and dispatches it to a +matching command. In this case, the only command available is `server`, +which runs your service as an HTTP server. The `server` command requires +a configuration file, so let’s go ahead and give it +[the one we previous saved](#configuration): +`java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml` + +You should see something like the following: + +``` +INFO [2011-12-03 00:38:32,927] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world +INFO [2011-12-03 00:38:32,931] org.eclipse.jetty.server.Server: jetty-7.x.y-SNAPSHOT +INFO [2011-12-03 00:38:32,936] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null} +INFO [2011-12-03 00:38:32,999] com.sun.jersey.server.impl.application.WebApplicationImpl: Initiating Jersey application, version 'Jersey: 1.10 11/02/2011 03:53 PM' +INFO [2011-12-03 00:38:33,041] com.yammer.dropwizard.config.Environment: + + GET /hello-world (com.example.helloworld.resources.HelloWorldResource) + +INFO [2011-12-03 00:38:33,215] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null} +INFO [2011-12-03 00:38:33,235] org.eclipse.jetty.server.AbstractConnector: Started BlockingChannelConnector@0.0.0.0:8080 STARTING +INFO [2011-12-03 00:38:33,238] org.eclipse.jetty.server.AbstractConnector: Started SocketConnector@0.0.0.0:8081 STARTING +``` + +Your Dropwizard service is now listening on ports `8080` for service +requests and `8081` for administration requests. If you press \^C, the +service will shut down gracefully, first closing the server socket, then +allowing a few seconds for in-flight requests to be processed, then +shutting down the process itself. + +But while it’s up, let’s give it a whirl! [Click here to say +hello!](http://localhost:8080/hello-world) [Click here to get even +friendlier!](http://localhost:8080/hello-world?name=Successful+Dropwizard+User) + +So, we’re generating sayings. Awesome. But that’s not all your service +can do. One of the main reasons for using Dropwizard is the +out-of-the-box operational tools it provides, all of which can be found +[on the admin port](http://localhost:8081/). + +If you click through to [metrics](http://localhost:8081/metrics), you +can see all of your service’s metrics represented as a JSON object. + +The [threads](http://localhost:8081/threads) resource allows you to +quickly get a thread dump of all the threads running in that process. + +The [healthcheck](http://localhost:8081/healthcheck) resource runs the +[`TemplateHealthCheck` instance we wrote](#healthcheck). You should see +something like this: + +``` +* deadlocks: OK +* template: OK +``` + +`template` here is the result of your `TemplateHealthCheck`, which +unsurprisingly passed. `deadlocks` is a built-in health check which +looks for deadlocked JVM threads and prints out a listing if any are +found. + +* * * * * + +## Next Steps #next + +Well, congratulations. You’ve got a Hello World service ready for +production (except for the lack of tests) that’s capable of doing +15,000-20,000 requests per second. Hopefully you've gotten a feel for +how Dropwizard combines Jetty, Jersey, Jackson, and other stable, mature +libraries to provide a phenomenal platform for developing RESTful web +services. + +There’s a lot more to Dropwizard than is covered here (commands, +bundles, servlets, advanced configuration, validation, HTTP clients, +database clients, templates, etc.), all of which is covered in +[by Dropwizard's manual.](manual.html) + +

          Learn more about Dropwizard »

          + +

          Learn more about Maven »

          + +

          Learn more about Jetty »

          + +

          Learn more about Jersey »

          + +

          Learn more about Jackson »

          + +

          Learn more about YAML »

          \ No newline at end of file diff --git a/docs/pages/index.md b/docs/pages/index.md new file mode 100644 index 00000000000..ecc2c505896 --- /dev/null +++ b/docs/pages/index.md @@ -0,0 +1,19 @@ +Title: Home +Template: landing.html.erb +Order: 1 +* * * + +# Meet Dropwizard. + +**Dropwizard is a Java framework for developing ops-friendly, +high-performance, RESTful web services.** + +Developed by [Yammer](https://www.yammer.com) to power their JVM-based +backend services, Dropwizard pulls together stable, mature libraries +from the Java ecosystem into a simple, light-weight package that lets +you focus on getting things done. + +Dropwizard has out-of-the-box support for sophisticated application +metrics, logging, operational tools, and much more, allowing you and +your team to ship a production-quality HTTP+JSON web service in the +shortest time possible. \ No newline at end of file diff --git a/docs/pages/manual.md b/docs/pages/manual.md new file mode 100644 index 00000000000..4dd10cf2cf7 --- /dev/null +++ b/docs/pages/manual.md @@ -0,0 +1,992 @@ +Title: User's Manual +Template: manual.html.erb +Order: 3 +* * * + +This goal of this document is to provide you with all the information +required to build, organize, test, deploy, and maintain Dropwizard-based +services. + +## Organization + +In general, we recommend you separate your projects into three Maven +modules: `project-api`, `project-client`, and `project-server`. +`project-api` should contain your [representation +classes](#representations); `project-client` should use those classes +and an HTTP client from [`dropwizard-client`](#client) to implement a +full-fledged client for your service, and `project-server` should +provide the actual service implementation, including +[resources](#resources). + +Our services tend to look like this: + +* `com.example.myservice` + * `api`: [Representation](#representations) classes + * `cli`: Service [command](#commands) classes + * `client`: [Client](#client) implementation + * `core`: Domain implementation + * `health`: [Health check](#health-checks) classes + * `resources`: [Resource](#resources) classes + * `MyService`: The [service](#services) class + * `MyServiceConfiguration`: The [configuration](#configuration) class + +## Services #services + +The main entry point into a Dropwizard service is, unsurprisingly, the +`Service` class. Each `Service` has a **name**, which is mostly used to +render the command-line interface. In the constructor of your `Service` +you can add [bundles](#bundles) and [commands](#commands) to your +service. + +### Configuration #configuration + +Each `Service` subclass has a single type parameter: that of its +matching `Configuration` subclass. These are usually at the root of your +service's main package. For example, your User service would have two +classes: `UserServiceConfiguration`, extending `Configuration`, and +`UserService`, extending `Service`. + +When your service runs a [configured command](#configured-commands) like +the `server` command, Dropwizard parses the provided YAML configuration +file and builds an instance of your service's configuration class by +mapping YAML field names to object field names. + +In order to keep your configuration file and class manageable, we +recommend grouping related configuration parameters into independent +configuration classes. If your service requires a set of configuration +parameters in order to connect to a message queue, for example, we +recommend that you create a new `MessageQueueConfiguration` class: + +``` java +public class MessageQueueConfiguration { + @NotEmpty + private String host; + + @Min(1) + @Max(65535) + private int port = 5672; + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } +} +``` + +Your main `Configuration` subclass can then include this as a member +field: + +``` java +public class ExampleServiceConfiguration extends Configuration { + @NotNull + private MessageQueueConfiguration messageQueue = new MessageQueueConfiguration(); + + public MessageQueueConfiguration getMessageQueueConfiguration() { + return messageQueue; + } +} +``` + +Then, in your service's YAML file, you can use a nested `messageQueue` +field: + +``` yaml +messageQueue: + host: mq.example.com + port: 5673 +``` + +The `@NotNull`, `@NotEmpty`, `@Min`, and `@Max` annotations are part of +Dropwizard's [validation](#validation) functionality. If your YAML +configuration file's `messageQueue.host` field was missing (or was a +blank string), Dropwizard would refuse to start and would output an +error message describing the issues. + +Once your service has parsed the YAML file and constructed its +`Configuration` instance, Dropwizard then calls your `Service` subclass +to initialize your service's `Environment`. + +### Environments + +A Dropwizard `Environment` consists of all the [resource +classes](#resources), servlets, filters, [health +checks](#health-checks), Jersey providers, [managed objects](#managed), +[tasks](#tasks), and Jersey properties which your service provides. + +Each `Service` subclass implements an `initialize` method. This is where +you should be creating new resource instances, etc., and adding them to +the given `Environment` class: + +``` java +@Override +protected void initialize(ExampleConfiguration config, + Environment environment) { + // encapsulate complicated setup logic in factories + final ThingyFactory thingyFactory = new ThingyFactory(config.getThingyConfiguration()); + + final Thingy thingy = thingyFactory.build(); + + environment.addResource(new ThingyResource(thingy)); + environment.addHealthCheck(new ThingyHealthCheck(thingy)); +} +``` + +It's important to keep the `initialize` method clean, so if creating an +instance of something is complicated, like the `Thingy` class above, +extract that logic into a factory. + +### Health Checks #health-checks + +A health check is a runtime test which you can use to verify your +service's behavior in its production environment. For example, you may +want to ensure that your database client is connected to the database: + +``` java +public class DatabaseHealthCheck extends HealthCheck { + private final Database database; + + public DatabaseHealthCheck(Database database) { + super("database"); + this.database = database; + } + + @Override + protected Result check() throws Exception { + if (database.isConnected()) { + return Result.healthy(); + } else { + return Result.unhealthy("Cannot connect to " + database.getUrl()); + } + } +} +``` + +You can then add this health check to your service's environment: + +``` java +environment.addHealthCheck(new DatabaseHealthCheck(database)); +``` + +By sending a `GET` request to `/healthcheck` on the admin port you can +run these tests and view the results: + +``` +$ curl http://dw.example.com:8081/healthcheck +* deadlocks: OK +* database: OK +``` + +If all health checks report success, a `200 OK` is returned. If any +fail, a `500 Internal Server Error` is returned with the error messages +and exception stack traces (if an exception was thrown). + +All Dropwizard services ship with the `deadlocks` health check installed +by default, which uses Java 1.6's built-in thread deadlock detection to +determine if any threads are deadlocked. + +### Managed Objects #managed + +Most services involve objects which need to be started and stopped: +thread pools, database connections, etc. Dropwizard provides the +`Managed` interface for this. You can either have the class in question +implement `Managed`'s `start()` and `stop()` methods, or write a wrapper +class which does so. Adding a `Managed` instance to your service's +`Environment` ties that object's lifecycle to that of the service's HTTP +server. Before the server starts, the `Managed`'s `start()` method is +called. After the server has stopped (and after its graceful shutdown +period) the `Managed`'s `stop()` method is called. + +For example, given a theoretical [Riak](http://riak.basho.com) client +which needs to be started and stopped: + +``` java +public class RiakClientManager implements Managed { + private final RiakClient client; + + public RiakClientManager(RiakClient client) { + this.client = client; + } + + @Override + public void start() throws Exception { + client.start(); + } + + @Override + public void stop() throws Exception { + client.stop(); + } +} +``` + +If `RiakClientManager#start()` throws an exception—e.g., an error +connecting to the server—your service will not start and a full +exception will be logged. If `RiakClientManager#stop()` throws an +exception, the exception will be logged but your service will still be +able to shut down. + +It should be noted that `Environment` has built-in constructors for +`ExecutorService` and `ScheduledExecutorService` instances which are +managed. See `Environment#managedExecutorService` and +`Environment#managedScheduledExecutorService` for details. + +### Bundles #bundles + +A Dropwizard bundle is a reusable group of functionality, used to define +blocks of a service's behavior. For example, `AssetBundle` provides a +simple way to serve static assets from your service's +`src/main/resources/assets` directory as files available from +`/assets/*` in your service. + +Some bundles require configuration parameters. The bundles implement +`ConfiguredBundle` and will require your service's `Configuration` +subclass to implement a specific interface. + +### Commands #commands + +Commands are basic actions which Dropwizard runs based on the arguments +provided on the command line. The built-in `server` command, for +example, spins up an HTTP server and runs your service. Each `Command` +subclass has a name and a set of command line options which Dropwizard +will use to parse the given command line arguments. + +#### Configured Commands #configured-commands + +Some commands require access to configuration parameters and should +extend the `ConfiguredCommand` class, using your service's +`Configuration` class as its type parameter. Dropwizard will treat the +first argument on the command line as the path to a YAML configuration +file, parse and validate it, and provide your command with an instance +of the configuration class. + +#### Managed Commands + +Managed commands further extend configured commands by creating a +lifecycle process for your service's [managed objects](#managed). All +`Managed` instances registered with your service's `Environment` will be +started before your command is run, and will be stopped afterward. + +### Tasks #tasks + +A `Task` is a run-time action your service provides access to on the +administrative port via HTTP. All Dropwizard services start with the +`gc` task, which explicitly triggers the JVM's garbage collection. (This +is useful, for example, for running full garbage collections during +off-peak times or while the given service is out of rotation.) + +Running a task can be done by sending a `POST` request to +`/tasks/{task-name}` on the admin port. For example: + +``` +$ curl -X POST http://dw.example.com:8081/tasks/gc +Running GC... +Done! +``` + +### Logging + +Dropwizard uses [Log4j](http://logging.apache.org/log4j) for its logging +backend. It provides an [slf4j](http://www.slf4j.org/) implementation, +and even routes all `java.util.logging` usage through log4j. + +#### The `Log` class + +Dropwizard comes with a `Log` convenience class, since most of the +logging APIs are horrendous. + +``` java +public class Example { + private static final Log LOG = Log.forClass(Example.class); + + public long fetchAge(long userId) { + LOG.debug("Fetching age for user {}", userId); + + try { + final User user = users.find(userId); + return user.getAge(); + } catch (IOException e) { + LOG.error(e, "Error connecting to user store for user {}", userId); + } catch (UserNotFoundException e) { + LOG.warn(e, "Unable to fetch age for user {}", userId); + } + } +} +``` + +`Log` provides the same statement formatting amenities as SLF4J, so you +can pass arbitrary objects in without having to concatenate strings. +Instances of `{}` in the log message are replaced with the string +representation of the objects. To log exceptions, just pass the +`Throwable` instance as the first parameter and it'll log the exception +type, message, and stack trace. + +The `Log` class also provides the following logging levels: + +* `FATAL`: Very severe error events that will presumably lead the application + to abort. +* `ERROR`: Error events that might still allow the application to continue + running. +* `WARN`: Potentially harmful situations. +* `INFO` :Informational messages that highlight the progress of the + application at coarse-grained level. +* `DEBUG`: Fine-grained informational events that are most useful to debug an + application. +* `TRACE`: Finer-grained informational events than the `DEBUG` level. + +#### Log Format + +Dropwizard's log format has a few specific goals: + +- Be human readable. +- Be machine parsable. +- Be easy for sleepy ops folks to figure out why things are + pear-shaped at 3:30AM using standard UNIXy tools like `tail` and + `grep`. + +The logging output looks like this: + +``` +TRACE [2010-04-06 06:42:35,271] com.example.dw.Thing: Contemplating doing a thing. +DEBUG [2010-04-06 06:42:35,274] com.example.dw.Thing: About to do a thing. +INFO [2010-04-06 06:42:35,274] com.example.dw.Thing: Doing a thing +WARN [2010-04-06 06:42:35,275] com.example.dw.Thing: Doing a thing +ERROR [2010-04-06 06:42:35,275] com.example.dw.Thing: This may get ugly. +FATAL [2010-04-06 06:42:35,275] com.example.dw.Thing: The thing has gone horribly wrong. +! java.lang.RuntimeException: oh noes! +! at com.example.dw.Thing.run(Thing.java:16) +! +``` + +A few items of note: + +- All timestamps are in UTC and ISO 8601 format. +- You can grep for messages of a specific level really easily: + `tail -f dw.log | grep '^WARN'` +- You can grep for messages from a specific class or package really + easily: `tail -f dw.log | grep 'com.example.dw.Thing'` +- You can even pull out full exception stack traces, plus the + accompanying log message: `tail -f dw.log | grep -B 1 '^\!'` + +You can specify a default logger level and even override the levels of +other loggers in your YAML configuration file: + +``` yaml +# Logging settings. +logging: + # The default level of all loggers. Can be OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, or ALL. + level: INFO + # Logger-specific levels. + loggers: + # Overrides the level of com.example.dw.Thing and sets it to DEBUG. + "com.example.dw.Thing": DEBUG +``` + +#### Console Logging + +By default, Dropwizard services log `INFO` and higher to `STDOUT`. You +can configure this by editing the `logging` section of your YAML +configuration file: + +``` yaml +logging: + # ... + # Settings for logging to stdout. + console: + # If true, write log statements to stdout. + enabled: true + # Do not display log statements below this threshold to stdout. + threshold: ALL +``` + +#### File Logging + +Dropwizard can also log to an automatically rotated set of log files. +This is the recommended configuration for your production environment: + +``` yaml +logging: + # ... + # Settings for logging to a file. + file: + # If true, write log statements to a file. + enabled: false + # Do not write log statements below this threshold to the file. + threshold: ALL + # The file to which statements will be logged. When the log file reaches the maximum size, the + # file will be renamed example.log.1, example.log will be truncated, and new statements written + # to it. + filenamePattern: ./logs/example.log + # The maximum size of any log file. Can also be "1GiB" etc + maxFileSize: 50MB + # The maximum number of log files to retain. + retainedFileCount: 5 +``` + +#### Syslog Logging + +Finally, Dropwizard can also log statements to syslog. (**Note:** +because Java doesn't use the native syslog bindings, your syslog server +**must** have an open network socket.) + +``` yaml +logging: + # ... + # Settings for logging to syslog. + syslog: + # If true, write log statements to syslog. + enabled: false + # The hostname of the syslog server to which statements will be sent. + # N.B.: If this is the local host, the local syslog instance will need to be configured to + # listen on an inet socket, not just a Unix socket. + host: localhost + # The syslog facility to which statements will be sent. + facility: local0 + +``` + +### Testing Services + +All of Dropwizard's APIs are designed with testability in mind, so even +your services can have unit tests: + +``` java +public class MyServiceTest { + private final Environment environment = mock(Environment.class); + private final MyService service = new MyService(); + private final MyConfiguration config = new MyConfiguration(); + + @Before + public void setup() throws Exception { + config.setMyParam("yay"); + } + + @Test + public void buildsAThingResource() throws Exception { + service.initialize(config, environment); + + verify(environment).addResource(any(ThingResource.class)); + } +} +``` + +We highly recommend [Mockito](http://code.google.com/p/mockito/) for all +your mocking needs. + +### Banners + +At Yammer, each of our services prints out a big ASCII art banner on +startup. Yours should, too. It's fun. Just add a `banner.txt` class to +`src/main/resources` and it'll print it out when your service starts: + +``` +INFO [2011-12-09 21:56:37,209] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world + dP + 88 + .d8888b. dP. .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b. + 88ooood8 `8bd8' 88' `88 88'`88'`88 88' `88 88 88ooood8 + 88. ... .d88b. 88. .88 88 88 88 88. .88 88 88. ... + `88888P' dP' `dP `88888P8 dP dP dP 88Y888P' dP `88888P' + 88 + dP + +INFO [2011-12-09 21:56:37,214] org.eclipse.jetty.server.Server: jetty-7.6.0.RC1 +... +``` + +We could probably make up an argument about why this is a serious devops +best practice with high ROI and an Agile Tool, but honestly we just +enjoy this. + +## Resources #resources + +Unsurprisingly, most of your day-to-day work with a Dropwizard service +will be in the resource classes, which model the resources exposed in +your RESTful API. Dropwizard uses [Jersey](http://jersey.java.net/) for +this, so most of this section is just re-hashing or collecting various +bits of Jersey documentation. + +Jersey is a framework for mapping various aspects of incoming HTTP +requests to POJOs and then mapping various aspects of POJOs to outgoing +HTTP responses. Here's a basic resource class: + + + +``` java +@Path("/{user}/notifications") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class NotificationsResource { + private final NotificationStore store; + + public NotificationsResource(NotificationStore store) { + this.store = store; + } + + @GET + public NotificationList fetch(@PathParam("user") LongParam userId, + @QueryParam("count") @DefaultValue("20") IntParam count) { + final List notifications = store.fetch(userId.get(), count.get()); + if (notifications != null) { + return new NotificationList(userId, notifications); + } + throw new WebApplicationException(Status.NOT_FOUND); + } + + @POST + public Response add(@PathParam("user") LongParam userId, + @Valid Notification notification) { + final long id = store.add(userId.get(), notification); + return Response.created(UriBuilder.fromResource(NotificationResource.class) + .build(userId.get(), id) + .build(); + } +} +``` + +This class provides a resource (a user's list of notifications) which +responds to `GET` and `POST` requests to `/{user}/notifications`, +providing and consuming `application/json` representations. There's +quite a lot of functionality on display here, and this section will +explain in detail what's in play and how to use these features in your +service. + +### Paths + +**Every resource class must have a `@Path` annotation.** The `@Path` +annotation isn't just a static string, it's a [URI +Template](http://tools.ietf.org/html/draft-gregorio-uritemplate-07). The +`{user}` part denotes a named variable, and when the template matches a +URI the value of that variable will be accessible via +`@PathParam`-annotated method parameters. + +For example, an incoming request for `/1001/notifications` would match +the URI template, and the value `1001` would be available as the path +parameter named `user`. + +If your service doesn't have a resource class whose `@Path` URI template +matches the URI of an incoming request, Jersey will automatically return +a `404 Not Found` to the client. + +### Methods + +Methods on a resource class which accept incoming requests are annotated +with the HTTP methods they handle: `@GET`, `@POST`, `@PUT`, `@DELETE`, +`@HEAD`, `@OPTIONS`, and even `@HttpMethod` for arbitrary new methods. + +If a request comes in which matches a resource class's path but has a +method which the class doesn't support, Jersey will automatically return +a `405 Method Not Allowed` to the client. + +The return value of the method (in this case, a `NotificationList` +instance) is then mapped to the [negotiated content type](#conneg). In +this case, our resource only supports JSON, and so the +`NotificationList` is serialized to JSON using Jackson. + +### Metrics + +Every resource method can be annotated with `@Timed`, `@Metered`, and +`@ExceptionMetered`. Dropwizard augments Jersey to automatically record +runtime information about your resource methods. + +### Parameters + +The annotated methods on a resource class can accept parameters which +are mapped to from aspects of the incoming request. The `*Param` +annotations determine which part of the request the data is mapped, and +the parameter *type* determines how the data is mapped. + +For example: + +- A `@PathParam("user")`-annotated `String` takes the raw value from + the `user` variable in the matched URI template and passes it into + the method as a `String`. +- A `@QueryParam("count")`-annotated `IntParam` parameter takes the + first `count` value from the request's query string and passes it as + a `String` to `IntParam`'s constructor. `IntParam` (and all other + `com.yammer.dropwizard.jersey.params.*` classes) parses the string + as an `Integer`, returning a `400 Bad Request` if the value is + malformed. +- A `@FormParam("name")`-annotated `Set` parameter takes all + the `name` values from a posted form and passes them to the method + as a set of strings. + +What's noteworthy here is that you can actually encapsulate the vast +majority of your validation logic using specialized parameter objects. +See `AbstractParam` for details. + +### Request Entities + +If you're handling request entities (e.g., an `application/json` object +on a `PUT` request), you can model this as a parameter without a +`*Param` annotation. In the [example code](#resource-example), the `add` +method provides a good example of this: + +``` java +@POST +public Response add(@PathParam("user") LongParam userId, + @Valid Notification notification) { + final long id = store.add(userId.get(), notification); + return Response.created(UriBuilder.fromResource(NotificationResource.class) + .build(userId.get(), id) + .build(); +} +``` + +Jersey maps the request entity to any single, unbound parameter. In this +case, because the resource is annotated with +`@Consumes(MediaType.APPLICATION_JSON)`, it uses the Dropwizard-provided +Jackson support which, in addition to parsing the JSON and mapping it to +an instance of `Notification`, also runs it through Dropwizard's +[validation](#validation). + +If the deserialized `Notification` isn't valid, Dropwizard returns a +`422 Unprocessable Entity` response to the client. + +### Media Types #conneg + +Jersey also provides full content negotiation, so if your resource class +consumes `application/json` but the client sends a `text/plain` entity, +Jersey will automatically reply with a `406 Not Acceptable`. Jersey's +even smart enough to use client-provided `q`-values in their `Accept` +headers to pick the best response content type based on what both the +client and server will support. + +### Responses + +If your clients are expecting custom headers or additional information +(or, if you simply desire an additional degree of control over your +responses), you can return explicitly-built `Response` objects: + +``` java +return Response.noContent().language(Locale.GERMAN).build(); +``` + +In general, though, we recommend you return actual domain objects if at +all possible. It makes [testing resources](#testing-resources) much +easier. + +### Error Handling + +If your resource class unintentionally throws an exception, Dropwizard +will log that exception (including stack traces) and return a terse, +safe `500` response. + +If your resource class needs to return an error to the client (e.g., the +requested record doesn't exist), you have two options: throw a +`WebApplicationException` or restructure your method to return a +`Response`. + +If at all possible, prefer throwing `WebApplicationException` instances +to returning `Response` objects. + +### URIs + +While Jersey doesn't quite have first-class support for hyperlink-driven +services, the provided `UriBuilder` functionality does quite well. + +Rather than duplicate resource URIs, it's possible (and recommended!) to +initialize a `UriBuilder` with the path from the resource class itself: + +``` java +UriBuilder.fromResource(UserResource.class).build(user.getId()); +``` + +### Testing #testing-resources + +As with just about everything in Dropwizard, we recommend you design +your resources to be testable. Dependencies which aren't +request-injected should be passed in via the constructor and assigned to +`final` fields. + +Testing, then, consists of creating an instance of your resource class +and passing it a mock. (Again: +[Mockito](http://code.google.com/p/mockito/).) + +``` java +public class NotificationsResourceTest { + private final NotificationStore store = mock(NotificationStore.class); + private final NotificationsResource resource = new NotificationsResource(store); + + @Test + public void getsReturnNotifications() { + final List notifications = mock(List.class); + when(store.fetch(1, 20)).thenReturn(notifications); + + final NotificationList list = resource.fetch(new LongParam("1"), new IntParam("20")); + + assertThat(list.getUserId(), + is(1L)); + + assertThat(list.getNotifications(), + is(notifications)); + } +} +``` + +### OAuth2 + +Dropwizard provides some super-minimalist support for [Oauth +2](http://tools.ietf.org/html/draft-ietf-oauth-v2-22): + +``` java +public Blah doAThing(@BearerToken String token) { + // etc +} +``` + +The Oauth 2 bearer token will be passed in via `token`. + +## Representations #representations + +Representation classes are classes which, when handled to various Jersey +`MessageBodyReader` and `MessageBodyWriter` providers, become the +entities in your service's API. Dropwizard heavily favors JSON, but it's +possible to map from any POJO to custom formats and back. + +### Basic JSON + +Jackson is awesome at converting regular POJOs to JSON and back. This +file: + +``` java +public class Notification { + @JsonProperty + private String text; + + public Notification(String text) { + this.text = text; + } + + public String getText() { + return text; + } + + public String setText(String text) { + this.text = text; + } +} +``` + +gets converted into this JSON: + +``` javascript +{ + "text": "hey it's the value of the text field" +} +``` + +If, at some point, you need to change the JSON field name or the Java +field without affecting the other, you can add an explicit field name to +the `@JsonProperty` annotation. + +If you prefer immutable objects rather than JavaBeans, that's also +doable: + +``` java +public class Notification { + @JsonProperty + private final String text; + + public Notification(@JsonProperty("text") String text) { + this.text = text; + } + + public String getText() { + return text; + } +} +``` + +### Advanced JSON + +Not all JSON representations map nicely to the objects your service +deals with, so it's sometimes necessary to use custom serializers and +deserializers. Just annotate your object like this: + +``` java +@JsonSerialize(using=FunkySerializer.class) +@JsonDeserialize(using=FunkyDeserializer.class) +public class Funky { + // ... +} +``` + +Then make a `FunkySerializer` class which implements +`JsonSerializer` and a `FunkyDeserializer` class which implements +`JsonDeserializer`. + +#### snake\_case + +A common issue with JSON is the disagreement between `camelCase` and +`snake_case` field names. Java and Javascript folks tend to like +`camelCase`; Ruby, Python, and Perl folks insist on `snake_case`. To +make Dropwizard automatically convert field names to `snake_case` (and +back), just annotate the class with `@JsonSnakeCase`: + +``` java +@JsonSnakeCase +public class Person { + @JsonProperty + private String firstName; + + public Person(String firstName) { + this.firstName = firstName; + } + + public String getFirstName() { + return firstName; + } +} +``` + +gets converted into this JSON: + +``` javascript +{ + "first_name": "Coda" +} +``` + +### Validation #validation + +Like [configuration classes](#configuration), you can add validation +annotations to fields of your representation classes and validate them. +If we're accepting client-provided `Person` objects, we probably want to +ensure that the `name` field of the object isn't `null` or blank. We can +do this as follows: + +``` java +public class Person { + @NotEmpty // ensure that name isn't null or blank + @JsonProperty + private final String name; + + public Person(@JsonProperty("name") String name) { + this.name = name; + } + + public String getName() { + return name; + } +} +``` + +Then, in our resource class, we can add the `@Valid` annotation to the +`Person` annotation: + +``` java +@PUT +public Response replace(@Valid Person person) { + // ... +} +``` + +If the `name` field is missing, Dropwizard will return a `text/plain` +`422 Unprocessable Entity` response detailing the validation errors: + +``` +* name may not be empty +``` + +#### Advanced + +More complex validations (for example, cross-field comparisons) are +often hard to do using declarative annotations. As an emergency +maneuver, add the `@ValidationMethod` to any `boolean`-returning method +which begins with `is`: + +``` java +@ValidationMethod(message="may not be Coda") +public boolean isNotCoda() { + return !("Coda".equals(name)); +} +``` + +Due to the rather daft JavaBeans conventions, **the method must begin +with `is`**. This is a limitation of Hibernate Validator, not +Dropwizard. + +### Streaming Output + +If your service happens to return lots of information, you may get a big +performance and efficiency bump by using streaming output. By returning +an object which implements Jersey's `StreamingOutput` interface, your +method can stream the response entity in a chunk-encoded output stream. +Otherwise, you'll need to fully construct your return value and *then* +hand it off to be sent to the client. + +### Testing + +The `dropwizard-testing` module contains a number of helper methods for +testing JSON parsing and generating. Given a JSON fixture file (e.g., +`src/test/resources/fixtures/person.json`), you can test that a `Person` +instance generates the same JSON as the fixture with the following: + +``` java +import static com.yammer.dropwizard.testing.JsonHelpers.asJson; +import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture; + +@Test +public void producesTheExpectedJson() throws Exception { + assertThat("rendering a person as JSON produces a valid API representation", + asJson(person), + is(jsonFixture("fixtures/person.json"))); +} +``` + +This does a whitespace- and comment-insensitive comparison of the +generated JSON and the JSON in the file. If they're different, both JSON +representations are helpfully displayed in the assertion error. + +Likewise, you can also test the parsing of the same JSON file to +guarantee round-trip compatibility: + +``` java +import static com.yammer.dropwizard.testing.JsonHelpers.fromJson; + +@Test +public void consumesTheExpectedJson() throws Exception { + assertThat("parsing a valid API representation produces a person", + fromJson(jsonFixture("fixtures/person.json"), Person.class), + is(person)); +} +``` + +### Custom Representations + +Sometimes, though, you've got some wacky output format you need to +produce or consume and no amount of arguing will make JSON acceptable. +That's unfortunate but OK. You can add support for arbitrary input and +output formats by creating classes which implement Jersey's +`MessageBodyReader` and `MessageBodyWriter` interfaces. (Make sure +they're annotated with `@Provider` and `@Produces("text/gibberish")` or +`@Consumes("text/gibberish")`.) Once you're done, just add instances of +them (or their classes if they depend on Jersey's `@Context` injection) +with your service's `Environment` on initialization. + +## Running Services + +TODO + +## In Production + +TODO + +## Dropwizard Client #client + +TODO + +## Dropwizard DB + +TODO + +## Dropwizard Templates + +TODO + +## Dropwizard & Scala + +TODO diff --git a/docs/static/css/additional.css b/docs/static/css/additional.css new file mode 100644 index 00000000000..15120762c52 --- /dev/null +++ b/docs/static/css/additional.css @@ -0,0 +1,36 @@ +body { + padding-top: 60px; +} + +#blurb { + background-color: #f5f5f5; + margin-bottom: 30px; + padding: 30px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +#blurb h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} + +#blurb p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} + +pre { + overflow: scroll; + background-color: #f5f5f5; + padding: 9px; + border: 1px solid rgba(0,0,0,.2); + -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.1); + -moz-box-shadow: 0 1px 2px rgba(0,0,0,.1); + box-shadow: 0 1px 2px rgba(0,0,0,.1); +} +pre .c{color:#998;font-style:italic;}pre .err{color:#a61717;background-color:#e3d2d2;}pre .k{font-weight:bold;}pre .o{font-weight:bold;}pre .cm{color:#998;font-style:italic;}pre .cp{color:#999;font-weight:bold;}pre .c1{color:#998;font-style:italic;}pre .cs{color:#999;font-weight:bold;font-style:italic;}pre .gd{color:#000;background-color:#fdd;}pre .gd .x{color:#000;background-color:#faa;}pre .ge{font-style:italic;}pre .gr{color:#a00;}pre .gh{color:#999;}pre .gi{color:#000;background-color:#dfd;}pre .gi .x{color:#000;background-color:#afa;}pre .go{color:#888;}pre .gp{color:#555;}pre .gs{font-weight:bold;}pre .gu{color:#aaa;}pre .gt{color:#a00;}pre .kc{font-weight:bold;}pre .kd{font-weight:bold;}pre .kp{font-weight:bold;}pre .kr{font-weight:bold;}pre .kt{color:#458;font-weight:bold;}pre .m{color:#099;}pre .s{color:#d14;}pre .na{color:#008080;}pre .nb{color:#0086B3;}pre .nc{color:#458;font-weight:bold;}pre .no{color:#008080;}pre .ni{color:#800080;}pre .ne{color:#900;font-weight:bold;}pre .nf{color:#900;font-weight:bold;}pre .nn{color:#555;}pre .nt{color:#000080;}pre .nv{color:#008080;}pre .ow{font-weight:bold;}pre .w{color:#bbb;}pre .mf{color:#099;}pre .mh{color:#099;}pre .mi{color:#099;}pre .mo{color:#099;}pre .sb{color:#d14;}pre .sc{color:#d14;}pre .sd{color:#d14;}pre .s2{color:#d14;}pre .se{color:#d14;}pre .sh{color:#d14;}pre .si{color:#d14;}pre .sx{color:#d14;}pre .sr{color:#009926;}pre .s1{color:#d14;}pre .ss{color:#990073;}pre .bp{color:#999;}pre .vc{color:#008080;}pre .vg{color:#008080;}pre .vi{color:#008080;}pre .il{color:#099;} \ No newline at end of file diff --git a/docs/css/bootstrap.min.css b/docs/static/css/bootstrap.min.css similarity index 100% rename from docs/css/bootstrap.min.css rename to docs/static/css/bootstrap.min.css diff --git a/docs/images/dropwizard-hat-small.png b/docs/static/images/dropwizard-hat-small.png similarity index 100% rename from docs/images/dropwizard-hat-small.png rename to docs/static/images/dropwizard-hat-small.png diff --git a/docs/images/dropwizard-hat-smaller.png b/docs/static/images/dropwizard-hat-smaller.png similarity index 100% rename from docs/images/dropwizard-hat-smaller.png rename to docs/static/images/dropwizard-hat-smaller.png diff --git a/docs/images/dropwizard-hat.png b/docs/static/images/dropwizard-hat.png similarity index 100% rename from docs/images/dropwizard-hat.png rename to docs/static/images/dropwizard-hat.png diff --git a/docs/templates/_toolbar.erb b/docs/templates/_toolbar.erb new file mode 100644 index 00000000000..99a2e74c28c --- /dev/null +++ b/docs/templates/_toolbar.erb @@ -0,0 +1,18 @@ +
          +
          +
          + Dropwizard + +
          +
          +
          \ No newline at end of file diff --git a/docs/templates/landing.html.erb b/docs/templates/landing.html.erb new file mode 100644 index 00000000000..c87a2bc8433 --- /dev/null +++ b/docs/templates/landing.html.erb @@ -0,0 +1,43 @@ + + + + + Dropwizard + + + + + + + + + +<%= partial :toolbar %> + +
          + +
          +
          +
          + +
          +
          + + <%= page.content %> + +

          Get + started »

          + +
          +
          + +
          +

          © Yammer 2011

          +
          +
          +
          + + + diff --git a/docs/templates/manual.html.erb b/docs/templates/manual.html.erb new file mode 100644 index 00000000000..88662096a16 --- /dev/null +++ b/docs/templates/manual.html.erb @@ -0,0 +1,39 @@ + + + + + <%= page.title %> | Dropwizard + + + + + + + + + +<%= partial :toolbar %> + +
          + + +
          +

          <%= page.title %>

          + + <%= page.content %> + +
          +

          © Yammer 2011

          +
          +
          +
          + + + From ee96661e06a7ad99cb9aa20e163a00ccfea9be42 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 6 Feb 2012 15:10:46 -0800 Subject: [PATCH 0208/2771] Fix copyright dates. --- docs/templates/landing.html.erb | 2 +- docs/templates/manual.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/templates/landing.html.erb b/docs/templates/landing.html.erb index c87a2bc8433..11959660b38 100644 --- a/docs/templates/landing.html.erb +++ b/docs/templates/landing.html.erb @@ -34,7 +34,7 @@
          -

          © Yammer 2011

          +

          © Yammer 2011-2012

          diff --git a/docs/templates/manual.html.erb b/docs/templates/manual.html.erb index 88662096a16..d6f7505a4df 100644 --- a/docs/templates/manual.html.erb +++ b/docs/templates/manual.html.erb @@ -30,7 +30,7 @@ <%= page.content %>
          -

          © Yammer 2011

          +

          © Yammer 2011-2012

          From 5554a697002de675f0003e916050ef2017861615 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 6 Feb 2012 17:11:53 -0800 Subject: [PATCH 0209/2771] Collapse DatabaseConfiguration. Stop modeling configuration as a map of names to connection configurations. Instead, just provide different instances of the connection configurations if you have multiple database connections. This is totally not backwards compatible. --- .../dropwizard/db/DatabaseConfiguration.java | 224 +++++++++--------- .../yammer/dropwizard/db/DatabaseFactory.java | 38 ++- .../dropwizard/db/tests/DatabaseTest.java | 11 +- 3 files changed, 132 insertions(+), 141 deletions(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java index e5cb04c9e42..117198e18fa 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java @@ -1,11 +1,10 @@ package com.yammer.dropwizard.db; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; import com.yammer.dropwizard.util.Duration; import com.yammer.dropwizard.validation.ValidationMethod; +import org.codehaus.jackson.annotate.JsonProperty; -import javax.validation.Valid; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; @@ -13,153 +12,152 @@ @SuppressWarnings("FieldMayBeFinal") public class DatabaseConfiguration { - public static class DatabaseConnectionConfiguration { - @NotNull - private String driverClass = null; - - @NotNull - private String user = null; + @NotNull + @JsonProperty + private String driverClass = null; - private String password = ""; + @NotNull + @JsonProperty + private String user = null; - @NotNull - private String url = null; + @JsonProperty + private String password = ""; - @NotNull - private Map properties = Maps.newHashMap(); + @NotNull + @JsonProperty + private String url = null; - @NotNull - private Duration maxWaitForConnection = Duration.seconds(1); - - @NotNull - private String validationQuery = "/* Health Check */ SELECT 1"; + @NotNull + @JsonProperty + private ImmutableMap properties = ImmutableMap.of(); - @Max(1024) - @Min(1) - private int minSize = 1; + @NotNull + @JsonProperty + private Duration maxWaitForConnection = Duration.seconds(1); - @Max(1024) - @Min(1) - private int maxSize = 8; + @NotNull + @JsonProperty + private String validationQuery = "/* Health Check */ SELECT 1"; - private boolean checkConnectionWhileIdle; + @Min(1) + @Max(1024) + @JsonProperty + private int minSize = 1; - @NotNull - private Duration checkConnectionHealthWhenIdleFor = Duration.seconds(10); + @Min(1) + @Max(1024) + @JsonProperty + private int maxSize = 8; - @NotNull - private Duration closeConnectionIfIdleFor = Duration.minutes(1); + @JsonProperty + private boolean checkConnectionWhileIdle; - public String getDriverClass() { - return driverClass; - } + @NotNull + @JsonProperty + private Duration checkConnectionHealthWhenIdleFor = Duration.seconds(10); - public void setDriverClass(String driverClass) { - this.driverClass = driverClass; - } + @NotNull + @JsonProperty + private Duration closeConnectionIfIdleFor = Duration.minutes(1); - public String getPassword() { - return password; - } + public String getDriverClass() { + return driverClass; + } - public void setPassword(String password) { - this.password = password; - } + public void setDriverClass(String driverClass) { + this.driverClass = driverClass; + } - public String getUser() { - return user; - } + public String getUser() { + return user; + } - public void setUser(String user) { - this.user = user; - } + public void setUser(String user) { + this.user = user; + } - public Map getProperties() { - return properties; - } + public String getPassword() { + return password; + } - public void setProperties(Map properties) { - this.properties = ImmutableMap.copyOf(properties); - } + public void setPassword(String password) { + this.password = password; + } - public String getUrl() { - return url; - } + public String getUrl() { + return url; + } - public void setUrl(String url) { - this.url = url; - } + public void setUrl(String url) { + this.url = url; + } - public Duration getMaxWaitForConnection() { - return maxWaitForConnection; - } + public ImmutableMap getProperties() { + return properties; + } - public void setMaxWaitForConnection(Duration maxWait) { - this.maxWaitForConnection = maxWait; - } + public void setProperties(Map properties) { + this.properties = ImmutableMap.copyOf(properties); + } - public String getValidationQuery() { - return validationQuery; - } + public Duration getMaxWaitForConnection() { + return maxWaitForConnection; + } - public void setValidationQuery(String validationQuery) { - this.validationQuery = validationQuery; - } + public void setMaxWaitForConnection(Duration maxWaitForConnection) { + this.maxWaitForConnection = maxWaitForConnection; + } - public int getMinSize() { - return minSize; - } + public String getValidationQuery() { + return validationQuery; + } - public void setMinSize(int minSize) { - this.minSize = minSize; - } + public void setValidationQuery(String validationQuery) { + this.validationQuery = validationQuery; + } - public int getMaxSize() { - return maxSize; - } + public int getMinSize() { + return minSize; + } - public void setMaxSize(int maxSize) { - this.maxSize = maxSize; - } + public void setMinSize(int minSize) { + this.minSize = minSize; + } - public boolean checkConnectionWhileIdle() { - return checkConnectionWhileIdle; - } + public int getMaxSize() { + return maxSize; + } - public void setCheckConnectionWhileIdle(boolean checkConnectionWhileIdle) { - this.checkConnectionWhileIdle = checkConnectionWhileIdle; - } + public void setMaxSize(int maxSize) { + this.maxSize = maxSize; + } - public Duration getCheckConnectionHealthWhenIdleFor() { - return checkConnectionHealthWhenIdleFor; - } + public boolean isCheckConnectionWhileIdle() { + return checkConnectionWhileIdle; + } - public void setCheckConnectionHealthWhenIdleFor(Duration timeout) { - this.checkConnectionHealthWhenIdleFor = timeout; - } + public void setCheckConnectionWhileIdle(boolean checkConnectionWhileIdle) { + this.checkConnectionWhileIdle = checkConnectionWhileIdle; + } - public Duration getCloseConnectionIfIdleFor() { - return closeConnectionIfIdleFor; - } + public Duration getCheckConnectionHealthWhenIdleFor() { + return checkConnectionHealthWhenIdleFor; + } - public void setCloseConnectionIfIdleFor(Duration timeout) { - this.closeConnectionIfIdleFor = timeout; - } + public void setCheckConnectionHealthWhenIdleFor(Duration checkConnectionHealthWhenIdleFor) { + this.checkConnectionHealthWhenIdleFor = checkConnectionHealthWhenIdleFor; + } - @ValidationMethod(message = ".minSize must be less than or equal to maxSize") - public boolean isPoolSizedCorrectly() { - return minSize <= maxSize; - } + public Duration getCloseConnectionIfIdleFor() { + return closeConnectionIfIdleFor; } - @Valid - private Map connections = Maps.newHashMap(); - - public DatabaseConnectionConfiguration getConnection(String name) { - return connections.get(name); + public void setCloseConnectionIfIdleFor(Duration closeConnectionIfIdleFor) { + this.closeConnectionIfIdleFor = closeConnectionIfIdleFor; } - - public void addConnection(String name, DatabaseConnectionConfiguration config) { - connections.put(name, config); + + @ValidationMethod(message = ".minSize must be less than or equal to maxSize") + public boolean isPoolSizedCorrectly() { + return minSize <= maxSize; } } diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java index 920c6105b51..84041ce00e6 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java @@ -10,29 +10,24 @@ import java.util.Map; import java.util.Properties; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.yammer.dropwizard.db.DatabaseConfiguration.DatabaseConnectionConfiguration; - public class DatabaseFactory { - private final DatabaseConfiguration config; + private final Environment environment; - public DatabaseFactory(DatabaseConfiguration config) { - this.config = config; + public DatabaseFactory(Environment environment) { + this.environment = environment; } - public Database build(String name, Environment environment) throws ClassNotFoundException { - final DatabaseConnectionConfiguration connectionConfig = config.getConnection(name); - Class.forName(connectionConfig.getDriverClass()); - checkNotNull(connectionConfig, "%s is not the name of a configured connection.", name); - final GenericObjectPool pool = buildPool(connectionConfig); - final DataSource dataSource = buildDataSource(connectionConfig, pool); + public Database build(DatabaseConfiguration configuration, String name) throws ClassNotFoundException { + Class.forName(configuration.getDriverClass()); + final GenericObjectPool pool = buildPool(configuration); + final DataSource dataSource = buildDataSource(configuration, pool); final Database database = new Database(dataSource, pool); environment.manage(database); environment.addHealthCheck(new DatabaseHealthCheck(database, name)); return database; } - private static DataSource buildDataSource(DatabaseConnectionConfiguration connectionConfig, GenericObjectPool pool) { + private static DataSource buildDataSource(DatabaseConfiguration connectionConfig, GenericObjectPool pool) { final Properties properties = new Properties(); for (Map.Entry property : connectionConfig.getProperties().entrySet()) { properties.setProperty(property.getKey(), property.getValue()); @@ -55,15 +50,16 @@ private static DataSource buildDataSource(DatabaseConnectionConfiguration connec return new PoolingDataSource(pool); } - private static GenericObjectPool buildPool(DatabaseConnectionConfiguration connectionConfig) { + private static GenericObjectPool buildPool(DatabaseConfiguration configuration) { final GenericObjectPool pool = new GenericObjectPool(null); - pool.setMaxWait(connectionConfig.getMaxWaitForConnection().toMilliseconds()); - pool.setMinIdle(connectionConfig.getMinSize()); - pool.setMaxActive(connectionConfig.getMaxSize()); - pool.setMaxIdle(connectionConfig.getMaxSize()); - pool.setTestWhileIdle(connectionConfig.checkConnectionWhileIdle()); - pool.setTimeBetweenEvictionRunsMillis(connectionConfig.getCheckConnectionHealthWhenIdleFor().toMilliseconds()); - pool.setMinEvictableIdleTimeMillis(connectionConfig.getCloseConnectionIfIdleFor().toMilliseconds()); + pool.setMaxWait(configuration.getMaxWaitForConnection().toMilliseconds()); + pool.setMinIdle(configuration.getMinSize()); + pool.setMaxActive(configuration.getMaxSize()); + pool.setMaxIdle(configuration.getMaxSize()); + pool.setTestWhileIdle(configuration.isCheckConnectionWhileIdle()); + pool.setTimeBetweenEvictionRunsMillis(configuration.getCheckConnectionHealthWhenIdleFor().toMilliseconds()); + pool.setMinEvictableIdleTimeMillis(configuration.getCloseConnectionIfIdleFor() + .toMilliseconds()); pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); return pool; } diff --git a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java index a0b039ef637..478eecfaf8e 100644 --- a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java +++ b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java @@ -16,29 +16,26 @@ import java.sql.Types; -import static com.yammer.dropwizard.db.DatabaseConfiguration.DatabaseConnectionConfiguration; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; public class DatabaseTest { - private final DatabaseConfiguration config = new DatabaseConfiguration(); - private final DatabaseConnectionConfiguration hsqlConfig = new DatabaseConnectionConfiguration(); + private final DatabaseConfiguration hsqlConfig = new DatabaseConfiguration(); { LoggingFactory.bootstrap(); hsqlConfig.setUrl("jdbc:hsqldb:mem:DbTest-"+System.currentTimeMillis()); hsqlConfig.setUser("sa"); hsqlConfig.setDriverClass("org.hsqldb.jdbcDriver"); - config.addConnection("hsql", hsqlConfig); } - private final DatabaseFactory factory = new DatabaseFactory(config); private final Environment environment = mock(Environment.class); + private final DatabaseFactory factory = new DatabaseFactory(environment); private Database database; @Before public void setUp() throws Exception { - this.database = factory.build("hsql", environment); + this.database = factory.build(hsqlConfig, "hsql"); final Handle handle = database.open(); try { handle.createCall("DROP TABLE people IF EXISTS").invoke(); @@ -87,7 +84,7 @@ public void createsAValidDBI() throws Exception { @Test public void managesTheDatabaseWithTheEnvironment() throws Exception { - final Database db = factory.build("hsql", environment); + final Database db = factory.build(hsqlConfig, "hsql"); verify(environment).manage(db); } From 78fb6c1433aff17a0aa9efe03cdcf529bd7873c6 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 6 Feb 2012 17:18:48 -0800 Subject: [PATCH 0210/2771] Add equals, hashCode, and toString to DatabaseConfiguration. --- .../dropwizard/db/DatabaseConfiguration.java | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java index 117198e18fa..9d4b8014af5 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseConfiguration.java @@ -1,5 +1,6 @@ package com.yammer.dropwizard.db; +import com.google.common.base.Objects; import com.google.common.collect.ImmutableMap; import com.yammer.dropwizard.util.Duration; import com.yammer.dropwizard.validation.ValidationMethod; @@ -10,7 +11,7 @@ import javax.validation.constraints.NotNull; import java.util.Map; -@SuppressWarnings("FieldMayBeFinal") +@SuppressWarnings({ "FieldMayBeFinal", "UnusedDeclaration" }) public class DatabaseConfiguration { @NotNull @JsonProperty @@ -160,4 +161,58 @@ public void setCloseConnectionIfIdleFor(Duration closeConnectionIfIdleFor) { public boolean isPoolSizedCorrectly() { return minSize <= maxSize; } + + @Override + public boolean equals(Object obj) { + if (this == obj) { return true; } + if ((obj == null) || (getClass() != obj.getClass())) { return false; } + final DatabaseConfiguration that = (DatabaseConfiguration) obj; + return (checkConnectionWhileIdle == that.checkConnectionWhileIdle) && + (maxSize == that.maxSize) && + (minSize == that.minSize) && + !((checkConnectionHealthWhenIdleFor != null) ? !checkConnectionHealthWhenIdleFor.equals(that.checkConnectionHealthWhenIdleFor) : (that.checkConnectionHealthWhenIdleFor != null)) && + !((closeConnectionIfIdleFor != null) ? !closeConnectionIfIdleFor.equals(that.closeConnectionIfIdleFor) : (that.closeConnectionIfIdleFor != null)) && + !((driverClass != null) ? !driverClass.equals(that.driverClass) : (that.driverClass != null)) && + !((maxWaitForConnection != null) ? !maxWaitForConnection.equals(that.maxWaitForConnection) : (that.maxWaitForConnection != null)) && + !((password != null) ? !password.equals(that.password) : (that.password != null)) && + !((properties != null) ? !properties.equals(that.properties) : (that.properties != null)) && + !((url != null) ? !url.equals(that.url) : (that.url != null)) && + !((user != null) ? !user.equals(that.user) : (that.user != null)) && + !((validationQuery != null) ? !validationQuery.equals(that.validationQuery) : (that.validationQuery != null)); + } + + @Override + public int hashCode() { + int result = (driverClass != null) ? driverClass.hashCode() : 0; + result = (31 * result) + ((user != null) ? user.hashCode() : 0); + result = (31 * result) + ((password != null) ? password.hashCode() : 0); + result = (31 * result) + ((url != null) ? url.hashCode() : 0); + result = (31 * result) + ((properties != null) ? properties.hashCode() : 0); + result = (31 * result) + ((maxWaitForConnection != null) ? maxWaitForConnection.hashCode() : 0); + result = (31 * result) + ((validationQuery != null) ? validationQuery.hashCode() : 0); + result = (31 * result) + minSize; + result = (31 * result) + maxSize; + result = (31 * result) + (checkConnectionWhileIdle ? 1 : 0); + result = (31 * result) + ((checkConnectionHealthWhenIdleFor != null) ? checkConnectionHealthWhenIdleFor.hashCode() : 0); + result = (31 * result) + ((closeConnectionIfIdleFor != null) ? closeConnectionIfIdleFor.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("driverClass", driverClass) + .add("user", user) + .add("password", password) + .add("url", url) + .add("properties", properties) + .add("maxWaitForConnection", maxWaitForConnection) + .add("validationQuery", validationQuery) + .add("minSize", minSize) + .add("maxSize", maxSize) + .add("checkConnectionWhileIdle", checkConnectionWhileIdle) + .add("checkConnectionHealthWhenIdleFor", checkConnectionHealthWhenIdleFor) + .add("closeConnectionIfIdleFor", closeConnectionIfIdleFor) + .toString(); + } } From 3f018e32747efb030f807fcac10cfc7e62a792c7 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 6 Feb 2012 17:27:27 -0800 Subject: [PATCH 0211/2771] Stop hardcoding the validation query for Database#ping(). Closes #25. --- .../com/yammer/dropwizard/db/Database.java | 21 ++++++++----------- .../yammer/dropwizard/db/DatabaseFactory.java | 2 +- .../dropwizard/db/tests/DatabaseTest.java | 14 +++++++++++++ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java index d92cf63d77e..e5ef1d8e398 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/Database.java @@ -8,27 +8,22 @@ import org.apache.log4j.Logger; import org.apache.tomcat.dbcp.pool.ObjectPool; import org.skife.jdbi.v2.DBI; +import org.skife.jdbi.v2.Handle; import org.skife.jdbi.v2.logging.Log4JLog; -import org.skife.jdbi.v2.sqlobject.SqlQuery; import javax.sql.DataSource; import java.sql.SQLException; public class Database extends DBI implements Managed { - public interface Ping { - @SqlQuery("SELECT 1") - public Integer ping(); - } - private static final Logger LOGGER = Logger.getLogger(Database.class); private final ObjectPool pool; - private final Ping ping; + private final String validationQuery; - public Database(DataSource dataSource, ObjectPool pool) { + public Database(DataSource dataSource, ObjectPool pool, String validationQuery) { super(dataSource); this.pool = pool; - this.ping = onDemand(Ping.class); + this.validationQuery = validationQuery; setSQLLog(new Log4JLog(LOGGER, Level.TRACE)); setTimingCollector(new InstrumentedTimingCollector(Metrics.defaultRegistry())); setStatementRewriter(new NamePrependingStatementRewriter()); @@ -47,9 +42,11 @@ public void stop() throws Exception { } public void ping() throws SQLException { - final Integer value = ping.ping(); - if (!Integer.valueOf(1).equals(value)) { - throw new SQLException("Expected 1 from 'SELECT 1', got " + value); + final Handle handle = open(); + try { + handle.execute(validationQuery); + } finally { + handle.close(); } } } diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java index 84041ce00e6..e051f24129f 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/DatabaseFactory.java @@ -21,7 +21,7 @@ public Database build(DatabaseConfiguration configuration, String name) throws C Class.forName(configuration.getDriverClass()); final GenericObjectPool pool = buildPool(configuration); final DataSource dataSource = buildDataSource(configuration, pool); - final Database database = new Database(dataSource, pool); + final Database database = new Database(dataSource, pool, configuration.getValidationQuery()); environment.manage(database); environment.addHealthCheck(new DatabaseHealthCheck(database, name)); return database; diff --git a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java index 478eecfaf8e..d92678a1cdd 100644 --- a/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java +++ b/dropwizard-db/src/test/java/com/yammer/dropwizard/db/tests/DatabaseTest.java @@ -14,10 +14,12 @@ import org.skife.jdbi.v2.Query; import org.skife.jdbi.v2.util.StringMapper; +import java.sql.SQLException; import java.sql.Types; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -28,6 +30,7 @@ public class DatabaseTest { hsqlConfig.setUrl("jdbc:hsqldb:mem:DbTest-"+System.currentTimeMillis()); hsqlConfig.setUser("sa"); hsqlConfig.setDriverClass("org.hsqldb.jdbcDriver"); + hsqlConfig.setValidationQuery("SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS"); } private final Environment environment = mock(Environment.class); private final DatabaseFactory factory = new DatabaseFactory(environment); @@ -110,4 +113,15 @@ public void sqlObjectsCanReturnImmutableLists() throws Exception { database.close(dao); } } + + @Test + @SuppressWarnings("CallToPrintStackTrace") + public void pingWorks() throws Exception { + try { + database.ping(); + } catch (SQLException e) { + e.printStackTrace(); + fail("shouldn't have thrown an exception but did"); + } + } } From db460ac38397841ca4a083cd4474f90ad48dd738 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 6 Feb 2012 17:28:26 -0800 Subject: [PATCH 0212/2771] Bump to 0.2.0-SNAPSHOT. THERE'S A-BREAKIN' CHANGES IN HYAH --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 20b2acd00fc..790aef1edf7 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.4-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 8d910e8d654..98f3594c28f 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.4-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 99340178133..ad2c6a4bd88 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.4-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index bcb44c95103..a667946c485 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.4-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index d4f0b08c038..3d62d1ef8e9 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.4-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index d5de97deb7c..7c75a6c846d 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.4-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index afa85a69a8a..14a5211f2e4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.1.4-SNAPSHOT + 0.2.0-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From 060ba4ec415c348cd585384075ac9cb371d6a067 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 6 Feb 2012 17:42:40 -0800 Subject: [PATCH 0213/2771] Updated CHANGELOG. --- CHANGELOG.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a7bd33058e..9df652d0510 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -v0.1.4: TBD +v0.2.0: TBD =================== * Switched to using `jackson-datatype-guava` for JSON serialization/deserialization of Guava types. @@ -6,6 +6,17 @@ v0.1.4: TBD * Upgraded to Jackson 1.9.4. * Upgraded to Jetty 7.6.0 final. * Upgraded to tomcat-dbcp 7.0.25. +* Improved fool-proofing for `Service` vs. `ScalaService`. +* Switched to using Jackson for configuration file parsing. SnakeYAML is used to parse YAML + configuration files to a JSON intermediary form, then Jackson is used to map that to your + `Configuration` subclass and its fields. Configuration files which don't end in `.yaml` or `.yml` + are treated as JSON. +* Rewrote `Json` to no longer be a singleton. +* Converted `JsonHelpers` in `dropwizard-testing` to use normalized JSON strings to compare JSON. +* Collapsed `DatabaseConfiguration`. It's no longer a map of connection names to configuration + objects. +* Changed `Database` to use the validation query in `DatabaseConfiguration` for its `#ping()` + method. v0.1.3: Jan 19 2012 From 7a1340cafa308eaea4861d93a929ec4ae2152424 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 6 Feb 2012 17:44:38 -0800 Subject: [PATCH 0214/2771] Fix the project.version for dropwizard-example. --- dropwizard-example/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index cadbb9e8d89..00fdd957f36 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.1.4-SNAPSHOT + 0.2.0-SNAPSHOT Dropwizard Example Application From 03d8327d389ffed1d3d8f3c4f7a07c2ca87ddbe7 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Mon, 6 Feb 2012 17:56:02 -0800 Subject: [PATCH 0215/2771] Upgrade maven-surefire-plugin. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 14a5211f2e4..3893debae22 100644 --- a/pom.xml +++ b/pom.xml @@ -126,7 +126,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.5 + 2.8.1 classes From e80b8efe73b90c1d8056cd8477ebe564815d0464 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 11:49:18 -0800 Subject: [PATCH 0216/2771] Fix Makefile for docs. --- docs/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 198757ab85a..b793a63723d 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,5 +1,5 @@ -default: +build: mook -upload: +upload: build rsync -avz target/ codahale.com:/home/codahale/dropwizard.codahale.com/ From ea423537cab3f19ed6977d8bcccebb8eaa64cf84 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:06:54 -0800 Subject: [PATCH 0217/2771] Formatting changes. --- .../main/java/com/yammer/dropwizard/config/Configuration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java index 919b81c8ee8..3e7a06e9ab5 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Configuration.java @@ -42,13 +42,13 @@ */ @SuppressWarnings("FieldMayBeFinal") public class Configuration { - @NotNull @Valid + @NotNull @JsonProperty private HttpConfiguration http = new HttpConfiguration(); - @NotNull @Valid + @NotNull @JsonProperty private LoggingConfiguration logging = new LoggingConfiguration(); From a66fcb1328eecd41eebdf6be8e93cb4810971ace Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:10:07 -0800 Subject: [PATCH 0218/2771] Fix minThread/maxThread defaults to Jetty's. --- .../dropwizard/config/HttpConfiguration.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 34f3f4be660..29a8835bcd8 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -3,6 +3,7 @@ import com.google.common.base.Optional; import com.yammer.dropwizard.util.Duration; import com.yammer.dropwizard.util.Size; +import com.yammer.dropwizard.validation.ValidationMethod; import org.codehaus.jackson.annotate.JsonProperty; import javax.validation.Valid; @@ -41,15 +42,15 @@ public enum ConnectorType { @JsonProperty private int adminPort = 8081; - @Min(10) - @Max(20000) + @Min(2) + @Max(1000000) @JsonProperty - private int maxThreads = 100; + private int maxThreads = 254; - @Min(10) - @Max(20000) + @Min(1) + @Max(1000000) @JsonProperty - private int minThreads = 10; + private int minThreads = 8; @NotNull @JsonProperty @@ -132,6 +133,11 @@ public enum ConnectorType { @JsonProperty private String bindHost = null; + @ValidationMethod + public boolean isThreadPoolSizedCorrectly() { + return minThreads <= maxThreads; + } + public RequestLogConfiguration getRequestLogConfiguration() { return requestLog; } From d3e163dbea08a905f9b0ee0bbc89da7e89d03d20 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:10:48 -0800 Subject: [PATCH 0219/2771] Fix maxIdleTime default to Jetty's. --- .../java/com/yammer/dropwizard/config/HttpConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 29a8835bcd8..91707e680dd 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -64,7 +64,7 @@ public enum ConnectorType { @NotNull @JsonProperty - private Duration maxIdleTime = Duration.seconds(1); + private Duration maxIdleTime = Duration.seconds(200); @Min(1) @Max(128) From 130958dde711e8870c5b72dc4f8b9b2d9d8f9c77 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:11:02 -0800 Subject: [PATCH 0220/2771] Fix acceptorThreadCount default to Jetty's. --- .../java/com/yammer/dropwizard/config/HttpConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 91707e680dd..6062485aa76 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -69,7 +69,7 @@ public enum ConnectorType { @Min(1) @Max(128) @JsonProperty - private int acceptorThreadCount = Runtime.getRuntime().availableProcessors(); + private int acceptorThreadCount = 1; @Min(-Thread.NORM_PRIORITY) @Max(Thread.NORM_PRIORITY) From 1dd50dfae2c7d4853f7d04351d8cbfc77cfc922f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:13:40 -0800 Subject: [PATCH 0221/2771] Fix buffer size defaults to Jetty's. --- .../java/com/yammer/dropwizard/config/HttpConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 6062485aa76..1a91dc17588 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -86,11 +86,11 @@ public enum ConnectorType { @NotNull @JsonProperty - private Size requestBufferSize = Size.kilobytes(32); + private Size requestBufferSize = Size.kilobytes(16); @NotNull @JsonProperty - private Size requestHeaderBufferSize = Size.kilobytes(3); + private Size requestHeaderBufferSize = Size.kilobytes(6); @NotNull @JsonProperty From 33c24f6476942d27779831f47f43b32921586332 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:16:41 -0800 Subject: [PATCH 0222/2771] Fix low resource threshold and maxIdleTime defaults to Jetty's. --- .../java/com/yammer/dropwizard/config/HttpConfiguration.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 1a91dc17588..9071471c1ef 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -106,13 +106,12 @@ public enum ConnectorType { @JsonProperty private Duration soLingerTime = null; - @Min(1) @JsonProperty - private int lowResourcesConnectionThreshold = 25000; + private int lowResourcesConnectionThreshold = 0; @NotNull @JsonProperty - private Duration lowResourcesMaxIdleTime = Duration.seconds(5); + private Duration lowResourcesMaxIdleTime = Duration.seconds(0); @NotNull @JsonProperty From b298771cd99410f078c47e4082ac3233fa02ecd3 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:40:47 -0800 Subject: [PATCH 0223/2771] Upgrade to JDBI 2.31.1. --- dropwizard-db/pom.xml | 2 +- .../dropwizard/db/args/OptionalArgumentFactory.java | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index ad2c6a4bd88..6979626de5d 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -21,7 +21,7 @@ org.jdbi jdbi - 2.30 + 2.31.1 com.yammer.metrics diff --git a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgumentFactory.java b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgumentFactory.java index 40191c50b0b..5f426db9d60 100644 --- a/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgumentFactory.java +++ b/dropwizard-db/src/main/java/com/yammer/dropwizard/db/args/OptionalArgumentFactory.java @@ -7,16 +7,12 @@ public class OptionalArgumentFactory implements ArgumentFactory> { @Override - public boolean accepts(Class> expectedType, - Object value, - StatementContext ctx) { + public boolean accepts(Class expectedType, Object value, StatementContext ctx) { return value instanceof Optional; } @Override - public Argument build(Class> expectedType, - Optional value, - StatementContext ctx) { + public Argument build(Class expectedType, Optional value, StatementContext ctx) { return new OptionalArgument(value); } } From b2453d58b73c1a53e9ca17355d3ed0e9b5d18bd0 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:40:59 -0800 Subject: [PATCH 0224/2771] Only pull snapshots from OSS Sonatype repo. --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index 3893debae22..48f2b8941fc 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,12 @@ sonatype-nexus-snapshots Sonatype Nexus Snapshots http://oss.sonatype.org/content/repositories/snapshots + + false + + + true + From 400bcac9311e63b02070fab5df0b3df0213f80a3 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:44:39 -0800 Subject: [PATCH 0225/2771] Upgrade to jackson-datatype-guava 1.9.0. --- dropwizard-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 98f3594c28f..55b9ea2abc7 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -72,7 +72,7 @@ com.fasterxml.jackson jackson-datatype-guava - 0.6.0 + 1.9.0 commons-cli From d5c6a4c6cb9269ff12a441739c74032e2ae30321 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 15:54:05 -0800 Subject: [PATCH 0226/2771] Upgrade maven-javadoc-plugin to 2.8.1. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 48f2b8941fc..9bb3c503e91 100644 --- a/pom.xml +++ b/pom.xml @@ -153,7 +153,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.8 + 2.8.1 attach-javadocs From f707e77f21eb840fd6aee242981e5f5215a10d95 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 17:46:24 -0800 Subject: [PATCH 0227/2771] Remove scala-tools.org. Scala artifacts are now available via Maven Central like they should have been years ago. --- dropwizard-scala_2.9.1/pom.xml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index a667946c485..61493a1ebb1 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -17,23 +17,12 @@ - - scala-tools-releases - http://scala-tools.org/repo-releases/ - repo.codahale.com http://repo.codahale.com/ - - - scala-tools-releases - http://scala-tools.org/repo-releases/ - - - org.scala-lang From 81d2a9c0742d1733faefc0c99c55efc1902bdc57 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 18:20:28 -0800 Subject: [PATCH 0228/2771] Upgrade to Metrics 2.0.0. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9bb3c503e91..7806fd6f505 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ UTF-8 UTF-8 - 2.0.0-RC0 + 2.0.0 1.11 From bcbd6a0b237620c9ff947257738aedc3a35caf78 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 18:20:39 -0800 Subject: [PATCH 0229/2771] Upgrade to JDBI 2.31.2. --- dropwizard-db/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 6979626de5d..6a7bc1a4c69 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -21,7 +21,7 @@ org.jdbi jdbi - 2.31.1 + 2.31.2 com.yammer.metrics From d7d046f90753ef76b8ff04611eec4520d0611192 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 19:30:36 -0800 Subject: [PATCH 0230/2771] Upgrade wagon-ssh-external and maven-javadoc. --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7806fd6f505..38f62397e58 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.8 + 2.8.1 org.codehaus.mojo @@ -230,7 +230,7 @@ org.apache.maven.wagon wagon-ssh-external - 1.0-beta-7 + 2.2 From eae510f6a685014673990a0e9a1401fef2fde7e2 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Tue, 7 Feb 2012 19:34:55 -0800 Subject: [PATCH 0231/2771] Updated changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9df652d0510..80e4c9e325e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ v0.2.0: TBD objects. * Changed `Database` to use the validation query in `DatabaseConfiguration` for its `#ping()` method. +* Upgraded to Metrics 2.0.0. v0.1.3: Jan 19 2012 From 12170e2971e5f1a0007724e24a34387de01e0dc1 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 8 Feb 2012 14:16:01 -0800 Subject: [PATCH 0232/2771] Update to Metrics 2.0.1. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 38f62397e58..c63df763ed5 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ UTF-8 UTF-8 - 2.0.0 + 2.0.1 1.11 From 3b0d03eb29c3558bbe5ef7a7bb769f1388422404 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 9 Feb 2012 15:18:56 -0800 Subject: [PATCH 0233/2771] Add support for ServletContextListeners. --- .../yammer/dropwizard/config/Environment.java | 16 ++++++++++++++++ .../dropwizard/config/ServerFactory.java | 19 +++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 4a03a8c0a73..322a735da2b 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -27,6 +27,7 @@ import javax.annotation.Nullable; import javax.servlet.Filter; import javax.servlet.Servlet; +import javax.servlet.ServletContextListener; import javax.ws.rs.HttpMethod; import javax.ws.rs.Path; import javax.ws.rs.ext.Provider; @@ -52,6 +53,7 @@ public class Environment extends AbstractLifeCycle { private final ResourceConfig config; private final ImmutableSet.Builder healthChecks; private final ImmutableMap.Builder servlets; + private final ImmutableSet.Builder servletContextListeners; private final ImmutableMap.Builder filters; private final ImmutableSet.Builder tasks; private final AggregateLifeCycle lifeCycle; @@ -77,6 +79,7 @@ public void validate() { }; this.healthChecks = ImmutableSet.builder(); this.servlets = ImmutableMap.builder(); + this.servletContextListeners = ImmutableSet.builder(); this.filters = ImmutableMap.builder(); this.tasks = ImmutableSet.builder(); this.lifeCycle = new AggregateLifeCycle(); @@ -323,6 +326,15 @@ public ScheduledExecutorService managedScheduledExecutorService(String nameForma return service; } + /** + * Adds a {@link ServletContextListener} to the servlet context. + * + * @param listener a {@link ServletContextListener} + */ + public void addServletContextListener(ServletContextListener listener) { + servletContextListeners.add(listener); + } + /* * Internal Accessors */ @@ -339,6 +351,10 @@ ImmutableMap getFilters() { return filters.build(); } + ImmutableSet getServletContextListeners() { + return servletContextListeners.build(); + } + ImmutableSet getTasks() { return tasks.build(); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index 91fe6a03a1d..faf69eaaca6 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -1,6 +1,7 @@ package com.yammer.dropwizard.config; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.yammer.dropwizard.jetty.BiDiGzipHandler; import com.yammer.dropwizard.jetty.QuietErrorHandler; @@ -25,8 +26,9 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ThreadPool; +import javax.servlet.ServletContextListener; import java.util.EnumSet; -import java.util.Map; +import java.util.EventListener; // TODO: 11/7/11 -- document ServerFactory // TODO: 11/7/11 -- document ServerFactory @@ -158,7 +160,7 @@ private AbstractConnector createConnector(int port) { private Handler createHandler(Environment env) { final HandlerCollection collection = new HandlerCollection(); - collection.addHandler(createExternalServlet(env.getServlets(), env.getFilters())); + collection.addHandler(createExternalServlet(env.getServlets(), env.getFilters(), env.getServletContextListeners())); collection.addHandler(createInternalServlet(env)); if (requestLogHandlerFactory.isEnabled()) { @@ -176,19 +178,24 @@ private static Handler createInternalServlet(Environment env) { return handler; } - private Handler createExternalServlet(Map servlets, - Map filters) { + private Handler createExternalServlet(ImmutableMap servlets, + ImmutableMap filters, + ImmutableSet listeners) { final ServletContextHandler handler = new ServletContextHandler(); handler.setBaseResource(Resource.newClassPathResource(".")); - for (Map.Entry entry : servlets.entrySet()) { + for (ImmutableMap.Entry entry : servlets.entrySet()) { handler.addServlet(entry.getValue(), entry.getKey()); } - for (Map.Entry entry : filters.entrySet()) { + for (ImmutableMap.Entry entry : filters.entrySet()) { handler.addFilter(entry.getValue(), entry.getKey(), EnumSet.of(DispatcherType.REQUEST)); } + final EventListener[] eventListeners = new EventListener[listeners.size()]; + listeners.toArray(eventListeners); + handler.setEventListeners(eventListeners); + handler.setConnectorNames(new String[]{"main"}); return wrapHandler(handler); From d40f0b59c4c767d8dc95ec729c70c6eceea1eaf1 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 9 Feb 2012 15:19:15 -0800 Subject: [PATCH 0234/2771] Clean Environment up a bit. --- .../yammer/dropwizard/config/Environment.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 322a735da2b..099e537a2e8 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -294,14 +294,14 @@ public ExecutorService managedExecutorService(String nameFormat, TimeUnit unit) { final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(nameFormat) .build(); - final ExecutorService service = new ThreadPoolExecutor(corePoolSize, - maximumPoolSize, - keepAliveTime, - unit, - new LinkedBlockingQueue(), - threadFactory); - manage(new ExecutorServiceManager(service, 5, TimeUnit.SECONDS)); - return service; + final ExecutorService executor = new ThreadPoolExecutor(corePoolSize, + maximumPoolSize, + keepAliveTime, + unit, + new LinkedBlockingQueue(), + threadFactory); + manage(new ExecutorServiceManager(executor, 5, TimeUnit.SECONDS)); + return executor; } /** @@ -320,10 +320,10 @@ public ScheduledExecutorService managedScheduledExecutorService(String nameForma int corePoolSize) { final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(nameFormat) .build(); - final ScheduledExecutorService service = new ScheduledThreadPoolExecutor(corePoolSize, - threadFactory); - manage(new ExecutorServiceManager(service, 5, TimeUnit.SECONDS)); - return service; + final ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(corePoolSize, + threadFactory); + manage(new ExecutorServiceManager(executor, 5, TimeUnit.SECONDS)); + return executor; } /** From 158332a09ff1ffbc742224e57e8275d429a0076a Mon Sep 17 00:00:00 2001 From: Cagatay Kavukcuoglu Date: Thu, 9 Feb 2012 21:31:19 -0500 Subject: [PATCH 0235/2771] More support for servlet listeners Both servlet context and servlet request listeners can now be added to a Dropwizard environment during service initialization. --- .../yammer/dropwizard/config/Environment.java | 38 +++++++++++-------- .../dropwizard/config/ServerFactory.java | 8 ++-- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 099e537a2e8..57ca117c547 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -27,10 +27,11 @@ import javax.annotation.Nullable; import javax.servlet.Filter; import javax.servlet.Servlet; -import javax.servlet.ServletContextListener; import javax.ws.rs.HttpMethod; import javax.ws.rs.Path; import javax.ws.rs.ext.Provider; + +import java.util.EventListener; import java.util.concurrent.*; import static com.google.common.base.Preconditions.checkNotNull; @@ -53,8 +54,8 @@ public class Environment extends AbstractLifeCycle { private final ResourceConfig config; private final ImmutableSet.Builder healthChecks; private final ImmutableMap.Builder servlets; - private final ImmutableSet.Builder servletContextListeners; private final ImmutableMap.Builder filters; + private final ImmutableSet.Builder servletListeners; private final ImmutableSet.Builder tasks; private final AggregateLifeCycle lifeCycle; @@ -79,8 +80,8 @@ public void validate() { }; this.healthChecks = ImmutableSet.builder(); this.servlets = ImmutableMap.builder(); - this.servletContextListeners = ImmutableSet.builder(); this.filters = ImmutableMap.builder(); + this.servletListeners = ImmutableSet.builder(); this.tasks = ImmutableSet.builder(); this.lifeCycle = new AggregateLifeCycle(); @@ -229,6 +230,20 @@ public FilterConfiguration addFilter(Class klass, return configuration; } + /** + * Add one or more servlet event listeners. + * + * @param listeners one or more listener instances that implement + * {@link javax.servlet.ServletContextListener}, + * {@link javax.servlet.ServletContextAttributeListener}, + * {@link javax.servlet.ServletRequestListener} or + * {@link javax.servlet.ServletRequestAttributeListener} + * + */ + public void addServletListeners(EventListener... listeners) { + this.servletListeners.add( listeners ); + } + /** * Adds a {@link Task} instance. * @@ -326,15 +341,6 @@ public ScheduledExecutorService managedScheduledExecutorService(String nameForma return executor; } - /** - * Adds a {@link ServletContextListener} to the servlet context. - * - * @param listener a {@link ServletContextListener} - */ - public void addServletContextListener(ServletContextListener listener) { - servletContextListeners.add(listener); - } - /* * Internal Accessors */ @@ -351,14 +357,14 @@ ImmutableMap getFilters() { return filters.build(); } - ImmutableSet getServletContextListeners() { - return servletContextListeners.build(); - } - ImmutableSet getTasks() { return tasks.build(); } + ImmutableSet getServletListeners() { + return servletListeners.build(); + } + private void logManagedObjects() { final ImmutableSet.Builder builder = ImmutableSet.builder(); for (Object bean : lifeCycle.getBeans()) { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index faf69eaaca6..a6aa3ed7ec0 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -26,7 +26,6 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ThreadPool; -import javax.servlet.ServletContextListener; import java.util.EnumSet; import java.util.EventListener; @@ -160,7 +159,7 @@ private AbstractConnector createConnector(int port) { private Handler createHandler(Environment env) { final HandlerCollection collection = new HandlerCollection(); - collection.addHandler(createExternalServlet(env.getServlets(), env.getFilters(), env.getServletContextListeners())); + collection.addHandler(createExternalServlet(env.getServlets(), env.getFilters(), env.getServletListeners())); collection.addHandler(createInternalServlet(env)); if (requestLogHandlerFactory.isEnabled()) { @@ -180,7 +179,7 @@ private static Handler createInternalServlet(Environment env) { private Handler createExternalServlet(ImmutableMap servlets, ImmutableMap filters, - ImmutableSet listeners) { + ImmutableSet listeners) { final ServletContextHandler handler = new ServletContextHandler(); handler.setBaseResource(Resource.newClassPathResource(".")); @@ -193,8 +192,7 @@ private Handler createExternalServlet(ImmutableMap servle } final EventListener[] eventListeners = new EventListener[listeners.size()]; - listeners.toArray(eventListeners); - handler.setEventListeners(eventListeners); + handler.setEventListeners(listeners.toArray(eventListeners)); handler.setConnectorNames(new String[]{"main"}); From 928372ba86a76acdb7f3a704cf8eb6065fd3909c Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 9 Feb 2012 19:20:34 -0800 Subject: [PATCH 0236/2771] Fix JarLocation. Closes #27. --- .../java/com/yammer/dropwizard/cli/Command.java | 14 +++++++------- .../yammer/dropwizard/cli/ConfiguredCommand.java | 5 ++--- .../com/yammer/dropwizard/cli/UsagePrinter.java | 12 ++++++------ .../com/yammer/dropwizard/util/JarLocation.java | 8 +++++++- .../dropwizard/util/tests/JarLocationTest.java | 2 +- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/Command.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/Command.java index 6d8fcc1af0a..567a6dee85b 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/Command.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/Command.java @@ -92,8 +92,8 @@ protected String getSyntax() { * * @return the usage string for the command */ - protected String getUsage() { - return format("%s %s %s", new JarLocation(), getName(), getSyntax()); + protected String getUsage(Class klass) { + return format("%s %s %s", new JarLocation(klass), getName(), getSyntax()); } /** @@ -107,17 +107,17 @@ public final void run(AbstractService service, String[] arguments) throws Exception { final CommandLine cmdLine = new GnuParser().parse(getOptionsWithHelp(), checkNotNull(arguments)); if (cmdLine.hasOption("help")) { - printHelp(); + printHelp(service.getClass()); } else { run(checkNotNull(service), cmdLine); } } - protected final void printHelp() { - UsagePrinter.printCommandHelp(this); + protected final void printHelp(Class klass) { + UsagePrinter.printCommandHelp(this, klass); } - protected final void printHelp(String message) { - UsagePrinter.printCommandHelp(this, message); + protected final void printHelp(String message, Class klass) { + UsagePrinter.printCommandHelp(this, klass, message); } } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java index 75b250038f3..b614f8d83e5 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/ConfiguredCommand.java @@ -7,7 +7,6 @@ import com.yammer.dropwizard.config.LoggingFactory; import com.yammer.dropwizard.validation.Validator; import org.apache.commons.cli.CommandLine; -import org.codehaus.jackson.map.Module; import java.io.File; import java.lang.reflect.ParameterizedType; @@ -71,10 +70,10 @@ protected final void run(AbstractService service, new LoggingFactory(configuration.getLoggingConfiguration()).configure(); run((AbstractService) service, configuration, params); } catch (ConfigurationException e) { - printHelp(e.getMessage()); + printHelp(e.getMessage(), service.getClass()); } } else { - printHelp(); + printHelp(service.getClass()); System.exit(-1); } } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/UsagePrinter.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/UsagePrinter.java index 28336e939f8..eed8ac493c9 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/UsagePrinter.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/cli/UsagePrinter.java @@ -11,20 +11,20 @@ private UsagePrinter() { } public static void printRootHelp(AbstractService service) { - System.out.printf("java -jar %s [arg1 arg2]\n\n", new JarLocation()); + System.out.printf("java -jar %s [arg1 arg2]\n\n", new JarLocation(service.getClass())); System.out.println("Commands"); System.out.println("========\n"); for (Command command : service.getCommands()) { - printCommandHelp(command); + printCommandHelp(command, service.getClass()); } } - public static void printCommandHelp(Command cmd) { - printCommandHelp(cmd, null); + public static void printCommandHelp(Command cmd, Class klass) { + printCommandHelp(cmd, klass, null); } - public static void printCommandHelp(Command cmd, String errorMessage) { + public static void printCommandHelp(Command cmd, Class klass, String errorMessage) { if (errorMessage != null) { System.err.println(errorMessage); System.out.println(); @@ -33,7 +33,7 @@ public static void printCommandHelp(Command cmd, String errorMessage) { System.out.println(formatTitle(cmd)); final HelpFormatter helpFormatter = new HelpFormatter(); helpFormatter.setLongOptPrefix(" --"); - helpFormatter.printHelp(String.format("java -jar %s", cmd.getUsage()), + helpFormatter.printHelp(String.format("java -jar %s", cmd.getUsage(klass)), cmd.getOptionsWithHelp()); System.out.println("\n"); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/JarLocation.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/JarLocation.java index 530f82640ab..76edf554daf 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/util/JarLocation.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/util/JarLocation.java @@ -8,9 +8,15 @@ * code is executing. */ public class JarLocation { + private final Class klass; + + public JarLocation(Class klass) { + this.klass = klass; + } + @Override public String toString() { - final URL location = JarLocation.class.getProtectionDomain().getCodeSource().getLocation(); + final URL location = klass.getProtectionDomain().getCodeSource().getLocation(); try { final String jar = new File(location.getFile()).getName(); if (jar.endsWith(".jar")) { diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/JarLocationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/JarLocationTest.java index 0f72df87521..d23a748321b 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/JarLocationTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/util/tests/JarLocationTest.java @@ -9,7 +9,7 @@ public class JarLocationTest { @Test public void isHumanReadable() throws Exception { - assertThat(new JarLocation().toString(), + assertThat(new JarLocation(JarLocationTest.class).toString(), is("project.jar")); } } From e3b893fe2adf450df114edcc949e43c4385ff9bf Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 9 Feb 2012 19:26:40 -0800 Subject: [PATCH 0237/2771] Upgrade to Metrics 2.0.2. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c63df763ed5..dce68a998b8 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ UTF-8 UTF-8 - 2.0.1 + 2.0.2 1.11 From 29d74103e8d7f9d7f6df40e689c5a17c65c6f6c4 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 9 Feb 2012 19:28:22 -0800 Subject: [PATCH 0238/2771] Update changelog. --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80e4c9e325e..37b1cd38f1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,11 @@ v0.2.0: TBD objects. * Changed `Database` to use the validation query in `DatabaseConfiguration` for its `#ping()` method. -* Upgraded to Metrics 2.0.0. +* Changed many `HttpConfiguration` defaults to match Jetty's defaults. +* Upgrade to JDBI 2.31.2. +* Fixed JAR locations in the CLI usage screens. +* Upgraded to Metrics 2.0.2. +* Added support for `ServletContextListener`s. v0.1.3: Jan 19 2012 From b87bc231efcab8994dcac812bfcb6acc602332c5 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 9 Feb 2012 22:51:01 -0800 Subject: [PATCH 0239/2771] Simplify adding event listeners. --- .../java/com/yammer/dropwizard/config/ServerFactory.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index a6aa3ed7ec0..9dee3bdc4e1 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -191,8 +191,9 @@ private Handler createExternalServlet(ImmutableMap servle handler.addFilter(entry.getValue(), entry.getKey(), EnumSet.of(DispatcherType.REQUEST)); } - final EventListener[] eventListeners = new EventListener[listeners.size()]; - handler.setEventListeners(listeners.toArray(eventListeners)); + for (EventListener listener : listeners) { + handler.addEventListener(listener); + } handler.setConnectorNames(new String[]{"main"}); From cc35092fc30c7722f192e7a532020d3f28204b08 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 9 Feb 2012 22:52:52 -0800 Subject: [PATCH 0240/2771] Added Log#setLevel(). --- .../src/main/java/com/yammer/dropwizard/logging/Log.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java index 530003ea63d..adb5b563834 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/logging/Log.java @@ -1,5 +1,6 @@ package com.yammer.dropwizard.logging; +import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.slf4j.helpers.MessageFormatter; @@ -76,6 +77,10 @@ private Log(Logger logger) { this.logger = logger; } + public void setLevel(Level level) { + logger.setLevel(level); + } + // TRACE public boolean isTraceEnabled() { From 938cb1ad63d9b19e808d6ffb48f49ad003f6d251 Mon Sep 17 00:00:00 2001 From: Cagatay Kavukcuoglu Date: Thu, 9 Feb 2012 23:41:35 -0500 Subject: [PATCH 0241/2771] Support servlet context parameters HttpConfiguration now has a contextParameters node that contains name/value pairs for all context parameters. --- .../com/yammer/dropwizard/config/HttpConfiguration.java | 9 +++++++++ .../java/com/yammer/dropwizard/config/ServerFactory.java | 5 +++++ .../dropwizard/config/tests/HttpConfigurationTest.java | 7 +++++++ .../src/test/resources/basic-configuration.yml | 6 +++++- dropwizard-core/src/test/resources/yaml/http.yml | 2 ++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java index 9071471c1ef..4aa0f8a72e4 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/HttpConfiguration.java @@ -1,6 +1,7 @@ package com.yammer.dropwizard.config; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; import com.yammer.dropwizard.util.Duration; import com.yammer.dropwizard.util.Size; import com.yammer.dropwizard.validation.ValidationMethod; @@ -26,6 +27,10 @@ public class HttpConfiguration { @JsonProperty private GzipConfiguration gzip = new GzipConfiguration(); + @NotNull + @JsonProperty + private ImmutableMap contextParameters = ImmutableMap.of(); + public enum ConnectorType { SOCKET, BLOCKING_CHANNEL, @@ -145,6 +150,10 @@ public GzipConfiguration getGzipConfiguration() { return gzip; } + public ImmutableMap getContextParameters() { + return contextParameters; + } + public ConnectorType getConnectorType() { if ("blocking".equalsIgnoreCase(connectorType)) { return ConnectorType.BLOCKING_CHANNEL; diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index 9dee3bdc4e1..ab1fbc8227a 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -28,6 +28,7 @@ import java.util.EnumSet; import java.util.EventListener; +import java.util.Map; // TODO: 11/7/11 -- document ServerFactory // TODO: 11/7/11 -- document ServerFactory @@ -195,6 +196,10 @@ private Handler createExternalServlet(ImmutableMap servle handler.addEventListener(listener); } + for (Map.Entry entry : config.getContextParameters().entrySet()) { + handler.setInitParameter( entry.getKey(), entry.getValue() ); + } + handler.setConnectorNames(new String[]{"main"}); return wrapHandler(handler); diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java index fb250c42cfd..9295388c3fa 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/HttpConfigurationTest.java @@ -1,6 +1,7 @@ package com.yammer.dropwizard.config.tests; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; import com.google.common.io.Resources; import com.yammer.dropwizard.config.ConfigurationFactory; import com.yammer.dropwizard.config.HttpConfiguration; @@ -36,6 +37,12 @@ public void loadsRequestLogConfig() throws Exception { is(true)); } + @Test + public void loadsContextParams() throws Exception { + assertThat(http.getContextParameters(), + is(ImmutableMap.of("param", "value"))); + } + @Test public void hasAServicePort() throws Exception { assertThat(http.getPort(), diff --git a/dropwizard-core/src/test/resources/basic-configuration.yml b/dropwizard-core/src/test/resources/basic-configuration.yml index b9defc5c0fc..77db3dba0ba 100644 --- a/dropwizard-core/src/test/resources/basic-configuration.yml +++ b/dropwizard-core/src/test/resources/basic-configuration.yml @@ -88,7 +88,11 @@ http: # The maximum number of old log files to retain. retainedFileCount: 5 - + + # Servlet context parameters + contextParameters: + param: value + # Logging settings. logging: diff --git a/dropwizard-core/src/test/resources/yaml/http.yml b/dropwizard-core/src/test/resources/yaml/http.yml index 16c01b64508..153dd4a34d3 100644 --- a/dropwizard-core/src/test/resources/yaml/http.yml +++ b/dropwizard-core/src/test/resources/yaml/http.yml @@ -27,3 +27,5 @@ useDateHeader: false useForwardedHeaders: false useDirectBuffers: false bindHost: "localhost" +contextParameters: + param: value From 2230c42b590d436ef5f871ab74d19eba794f4179 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 10 Feb 2012 10:46:19 -0800 Subject: [PATCH 0242/2771] Allow multiple filters per path. Fixes #29. --- .../com/yammer/dropwizard/config/Environment.java | 11 ++++------- .../yammer/dropwizard/config/FilterConfiguration.java | 6 +++--- .../com/yammer/dropwizard/config/ServerFactory.java | 5 +++-- .../config/tests/FilterConfigurationTest.java | 9 +++++---- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index 57ca117c547..a9cffae0d2e 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -1,9 +1,6 @@ package com.yammer.dropwizard.config; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Ordering; +import com.google.common.collect.*; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.core.reflection.AnnotatedMethod; @@ -54,7 +51,7 @@ public class Environment extends AbstractLifeCycle { private final ResourceConfig config; private final ImmutableSet.Builder healthChecks; private final ImmutableMap.Builder servlets; - private final ImmutableMap.Builder filters; + private final ImmutableMultimap.Builder filters; private final ImmutableSet.Builder servletListeners; private final ImmutableSet.Builder tasks; private final AggregateLifeCycle lifeCycle; @@ -80,7 +77,7 @@ public void validate() { }; this.healthChecks = ImmutableSet.builder(); this.servlets = ImmutableMap.builder(); - this.filters = ImmutableMap.builder(); + this.filters = ImmutableMultimap.builder(); this.servletListeners = ImmutableSet.builder(); this.tasks = ImmutableSet.builder(); this.lifeCycle = new AggregateLifeCycle(); @@ -353,7 +350,7 @@ ImmutableMap getServlets() { return servlets.build(); } - ImmutableMap getFilters() { + ImmutableMultimap getFilters() { return filters.build(); } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java index 6ab653f3de3..a277c7d2871 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java @@ -1,6 +1,6 @@ package com.yammer.dropwizard.config; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; import org.eclipse.jetty.servlet.FilterHolder; import java.util.Map; @@ -12,7 +12,7 @@ */ public class FilterConfiguration { private final FilterHolder holder; - private final ImmutableMap.Builder mappings; + private final ImmutableMultimap.Builder mappings; /** * Creates a new {@link FilterConfiguration}. @@ -21,7 +21,7 @@ public class FilterConfiguration { * @param mappings the mappings of URL patterns to {@link javax.servlet.Filter}s */ public FilterConfiguration(FilterHolder holder, - ImmutableMap.Builder mappings) { + ImmutableMultimap.Builder mappings) { this.holder = holder; this.mappings = mappings; } diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java index 9dee3bdc4e1..ecb659809b1 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServerFactory.java @@ -2,6 +2,7 @@ import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.yammer.dropwizard.jetty.BiDiGzipHandler; import com.yammer.dropwizard.jetty.QuietErrorHandler; @@ -178,7 +179,7 @@ private static Handler createInternalServlet(Environment env) { } private Handler createExternalServlet(ImmutableMap servlets, - ImmutableMap filters, + ImmutableMultimap filters, ImmutableSet listeners) { final ServletContextHandler handler = new ServletContextHandler(); handler.setBaseResource(Resource.newClassPathResource(".")); @@ -187,7 +188,7 @@ private Handler createExternalServlet(ImmutableMap servle handler.addServlet(entry.getValue(), entry.getKey()); } - for (ImmutableMap.Entry entry : filters.entrySet()) { + for (ImmutableMap.Entry entry : filters.entries()) { handler.addFilter(entry.getValue(), entry.getKey(), EnumSet.of(DispatcherType.REQUEST)); } diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/FilterConfigurationTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/FilterConfigurationTest.java index 0cdf43541bc..3753938a28f 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/FilterConfigurationTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/FilterConfigurationTest.java @@ -1,6 +1,7 @@ package com.yammer.dropwizard.config.tests; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; import com.yammer.dropwizard.config.FilterConfiguration; import org.eclipse.jetty.servlet.FilterHolder; import org.junit.Test; @@ -13,7 +14,7 @@ public class FilterConfigurationTest { private final FilterHolder holder = mock(FilterHolder.class); - private final ImmutableMap.Builder mappings = ImmutableMap.builder(); + private final ImmutableMultimap.Builder mappings = ImmutableMultimap.builder(); private final FilterConfiguration config = new FilterConfiguration(holder, mappings); @Test @@ -37,7 +38,7 @@ public void mapsAUrlPatternToAFilter() throws Exception { config.addUrlPattern("/one"); assertThat(mappings.build(), - is(ImmutableMap.of("/one", holder))); + is(ImmutableMultimap.of("/one", holder))); } @Test @@ -45,7 +46,7 @@ public void mapsUrlPatternsToAFilter() throws Exception { config.addUrlPatterns("/one", "/two"); assertThat(mappings.build(), - is(ImmutableMap.of("/one", holder, - "/two", holder))); + is(ImmutableMultimap.of("/one", holder, + "/two", holder))); } } From a5fea259a433eb80e77a74db5680a98897e25683 Mon Sep 17 00:00:00 2001 From: Cagatay Kavukcuoglu Date: Fri, 10 Feb 2012 14:53:34 -0500 Subject: [PATCH 0243/2771] Allow setting filter and servlet names --- .../config/FilterConfiguration.java | 19 +++++++++++++++++++ .../config/ServletConfiguration.java | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java index a277c7d2871..133d9149e70 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java @@ -5,7 +5,9 @@ import java.util.Map; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.isNullOrEmpty; /** * The configuration for a servlet {@link javax.servlet.Filter}. @@ -26,6 +28,23 @@ public FilterConfiguration(FilterHolder holder, this.mappings = mappings; } + /** + * Sets the filter's name. + * + * @param name the name of the filter + * @return {@code this} + */ + public FilterConfiguration setName(String name) { + checkArgument( !isNullOrEmpty( name ), "name must be non-empty" ); + /* + * We are warned against ordering setting the held class (which + * has already happened by the time this configuration is instantiated) + * before the name, but it seems harmless to do so. + */ + holder.setName( name ); + return this; + } + /** * Sets the given filter initialization parameter. * diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java index 74e2c30364c..43090b38a55 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java @@ -5,7 +5,9 @@ import java.util.Map; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.isNullOrEmpty; /** * The configuration for a {@link javax.servlet.Servlet}. @@ -26,6 +28,23 @@ public ServletConfiguration(ServletHolder holder, this.mappings = mappings; } + /** + * Sets the servlet's name. + * + * @param name the name of the servlet + * @return {@code this} + */ + public ServletConfiguration setName(String name) { + checkArgument( !isNullOrEmpty( name ), "name must be non-empty" ); + /* + * We are warned against ordering setting the held class (which + * has already happened by the time this configuration is instantiated) + * before the name, but it seems harmless to do so. + */ + holder.setName( name ); + return this; + } + /** * Sets the servlet's initialization order. * From 2b3bfb4832429e8694216ae64b0d22c8876a5258 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Fri, 10 Feb 2012 12:14:40 -0800 Subject: [PATCH 0244/2771] Some formatting changes. Also removed the warnings about setting the servlet and filter names. Setting the name after calling setHeldClass (which is called in the ServletHolder/FilterHolder constructors when passing a class instead of an instance) simply overwrites the default name, which is the canonical class name and the class hashCode. Given that overwriting the default name is the intended behavior, the warnings seemed a little dire. --- .../config/FilterConfiguration.java | 31 ++++++++--------- .../config/ServletConfiguration.java | 33 ++++++++----------- 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java index 133d9149e70..b9d9895f298 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/FilterConfiguration.java @@ -19,8 +19,8 @@ public class FilterConfiguration { /** * Creates a new {@link FilterConfiguration}. * - * @param holder the {@link FilterHolder} containing the {@link javax.servlet.Filter} - * @param mappings the mappings of URL patterns to {@link javax.servlet.Filter}s + * @param holder the {@link FilterHolder} containing the {@link javax.servlet.Filter} + * @param mappings the mappings of URL patterns to {@link javax.servlet.Filter}s */ public FilterConfiguration(FilterHolder holder, ImmutableMultimap.Builder mappings) { @@ -30,26 +30,21 @@ public FilterConfiguration(FilterHolder holder, /** * Sets the filter's name. - * - * @param name the name of the filter + * + * @param name the name of the filter * @return {@code this} */ public FilterConfiguration setName(String name) { - checkArgument( !isNullOrEmpty( name ), "name must be non-empty" ); - /* - * We are warned against ordering setting the held class (which - * has already happened by the time this configuration is instantiated) - * before the name, but it seems harmless to do so. - */ - holder.setName( name ); + checkArgument(!isNullOrEmpty(name), "name must be non-empty"); + holder.setName(name); return this; } - + /** * Sets the given filter initialization parameter. * - * @param name the name of the initialization parameter - * @param value the value of the parameter + * @param name the name of the initialization parameter + * @param value the value of the parameter * @return {@code this} */ public FilterConfiguration setInitParam(String name, String value) { @@ -60,7 +55,7 @@ public FilterConfiguration setInitParam(String name, String value) { /** * Sets the given filter initialization parameters. * - * @param params the initialization parameters + * @param params the initialization parameters * @return {@code this} */ public FilterConfiguration addInitParams(Map params) { @@ -73,7 +68,7 @@ public FilterConfiguration addInitParams(Map params) { /** * Adds the given URL pattern as a filter mapping. * - * @param urlPattern the URL pattern + * @param urlPattern the URL pattern * @return {@code this} */ public FilterConfiguration addUrlPattern(String urlPattern) { @@ -84,8 +79,8 @@ public FilterConfiguration addUrlPattern(String urlPattern) { /** * Adds the given URL patterns as a filter mappings. * - * @param urlPattern the URL pattern - * @param urlPatterns additional URL patterns + * @param urlPattern the URL pattern + * @param urlPatterns additional URL patterns * @return {@code this} */ public FilterConfiguration addUrlPatterns(String urlPattern, String... urlPatterns) { diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java index 43090b38a55..95fb366fabe 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/ServletConfiguration.java @@ -19,8 +19,8 @@ public class ServletConfiguration { /** * Creates a new {@link ServletConfiguration}. * - * @param holder the {@link ServletHolder} containing the {@link javax.servlet.Servlet} - * @param mappings the mappings of URL patterns to {@link javax.servlet.Servlet}s + * @param holder the {@link ServletHolder} containing the {@link javax.servlet.Servlet} + * @param mappings the mappings of URL patterns to {@link javax.servlet.Servlet}s */ public ServletConfiguration(ServletHolder holder, ImmutableMap.Builder mappings) { @@ -30,25 +30,20 @@ public ServletConfiguration(ServletHolder holder, /** * Sets the servlet's name. - * - * @param name the name of the servlet + * + * @param name the name of the servlet * @return {@code this} */ public ServletConfiguration setName(String name) { - checkArgument( !isNullOrEmpty( name ), "name must be non-empty" ); - /* - * We are warned against ordering setting the held class (which - * has already happened by the time this configuration is instantiated) - * before the name, but it seems harmless to do so. - */ - holder.setName( name ); + checkArgument(!isNullOrEmpty(name), "name must be non-empty"); + holder.setName(name); return this; } - + /** * Sets the servlet's initialization order. * - * @param order the initialization order + * @param order the initialization order * @return {@code this} */ public ServletConfiguration setInitOrder(int order) { @@ -59,8 +54,8 @@ public ServletConfiguration setInitOrder(int order) { /** * Sets the given servlet initialization parameter. * - * @param name the name of the initialization parameter - * @param value the value of the parameter + * @param name the name of the initialization parameter + * @param value the value of the parameter * @return {@code this} */ public ServletConfiguration setInitParam(String name, String value) { @@ -71,7 +66,7 @@ public ServletConfiguration setInitParam(String name, String value) { /** * Sets the given servlet initialization parameters. * - * @param params the initialization parameters + * @param params the initialization parameters * @return {@code this} */ public ServletConfiguration addInitParams(Map params) { @@ -84,7 +79,7 @@ public ServletConfiguration addInitParams(Map params) { /** * Adds the given URL pattern as a servlet mapping. * - * @param urlPattern the URL pattern + * @param urlPattern the URL pattern * @return {@code this} */ public ServletConfiguration addUrlPattern(String urlPattern) { @@ -95,8 +90,8 @@ public ServletConfiguration addUrlPattern(String urlPattern) { /** * Adds the given URL patterns as a servlet mappings. * - * @param urlPattern the URL pattern - * @param urlPatterns additional URL patterns + * @param urlPattern the URL pattern + * @param urlPatterns additional URL patterns * @return {@code this} */ public ServletConfiguration addUrlPatterns(String urlPattern, String... urlPatterns) { From 9753c277de80ce9dc9890a1743a0a564aaa13bb2 Mon Sep 17 00:00:00 2001 From: Cagatay Kavukcuoglu Date: Tue, 14 Feb 2012 11:37:51 -0500 Subject: [PATCH 0245/2771] Allow services to customize the Jersey servlet container implementation --- .../yammer/dropwizard/AbstractService.java | 24 +++++++++++++++++++ .../yammer/dropwizard/config/Environment.java | 9 +++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java index 619747731f1..820c1926c4a 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java @@ -3,11 +3,13 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.sun.jersey.spi.container.servlet.ServletContainer; import com.yammer.dropwizard.cli.Command; import com.yammer.dropwizard.cli.ConfiguredCommand; import com.yammer.dropwizard.cli.ServerCommand; import com.yammer.dropwizard.cli.UsagePrinter; import com.yammer.dropwizard.config.Configuration; +import com.yammer.dropwizard.config.DropwizardResourceConfig; import com.yammer.dropwizard.config.Environment; import com.yammer.dropwizard.config.LoggingFactory; import org.codehaus.jackson.map.Module; @@ -17,6 +19,8 @@ import java.util.List; import java.util.SortedMap; +import javax.annotation.CheckForNull; + /** * The base class for both Java and Scala services. Do not extend this directly. Use {@link Service} * instead. @@ -188,6 +192,26 @@ public ImmutableList getJacksonModules() { return ImmutableList.copyOf(modules); } + /** + * Returns the Jersey servlet container used to serve HTTP requests. This implementation + * creates a new {@link ServletContainer} instance with the given resource configuration. + * Subclasses must either use the same {@code config} instance or delegate to it. + *

          + * This method may be called before the service initialized with + * {@link #initialize(Configuration, Environment)}; service implementations must not + * assume the service has been initialized. + *

          + * An implementation that chooses to return {@code null} is responsible for creating + * a container with the given config by other means during initialization and startup. + * + * @param config the Jersey resource config to use for the container + * @return a Jersey servlet container, or {@code null} if the Jersey container + * will be created by other means + */ + public @CheckForNull ServletContainer getJerseyContainer(DropwizardResourceConfig config) { + return new ServletContainer(config); + } + private static boolean isHelp(String[] arguments) { return (arguments.length == 0) || ((arguments.length == 1) && diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index a9cffae0d2e..eb661997529 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -24,6 +24,7 @@ import javax.annotation.Nullable; import javax.servlet.Filter; import javax.servlet.Servlet; +import javax.servlet.http.HttpServlet; import javax.ws.rs.HttpMethod; import javax.ws.rs.Path; import javax.ws.rs.ext.Provider; @@ -48,7 +49,7 @@ public class Environment extends AbstractLifeCycle { private static final Log LOG = Log.forClass(Environment.class); private final AbstractService service; - private final ResourceConfig config; + private final DropwizardResourceConfig config; private final ImmutableSet.Builder healthChecks; private final ImmutableMap.Builder servlets; private final ImmutableMultimap.Builder filters; @@ -82,7 +83,11 @@ public void validate() { this.tasks = ImmutableSet.builder(); this.lifeCycle = new AggregateLifeCycle(); - addServlet(new ServletContainer(config), configuration.getHttpConfiguration().getRootPath()).setInitOrder(Integer.MAX_VALUE); + + HttpServlet jerseyContainer = service.getJerseyContainer(config); + if (jerseyContainer != null) { + addServlet(jerseyContainer, configuration.getHttpConfiguration().getRootPath()).setInitOrder(Integer.MAX_VALUE); + } addTask(new GarbageCollectionTask()); } From 794683d56232aadb51238380b7e8a13c97e3bad6 Mon Sep 17 00:00:00 2001 From: Cagatay Kavukcuoglu Date: Tue, 14 Feb 2012 12:00:02 -0500 Subject: [PATCH 0246/2771] minor formatting --- .../src/main/java/com/yammer/dropwizard/config/Environment.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java index eb661997529..99973bb38a4 100644 --- a/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java +++ b/dropwizard-core/src/main/java/com/yammer/dropwizard/config/Environment.java @@ -82,7 +82,6 @@ public void validate() { this.servletListeners = ImmutableSet.builder(); this.tasks = ImmutableSet.builder(); this.lifeCycle = new AggregateLifeCycle(); - HttpServlet jerseyContainer = service.getJerseyContainer(config); if (jerseyContainer != null) { From ae17995702edaafc08c0adb792e66f2ec0679309 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 10:00:06 -0800 Subject: [PATCH 0247/2771] Only enable validator tests in English locales. Sadly, there doesn't seem to be a way to force a locale for Hibernate Validator. Closes #32. --- .../config/tests/ConfigurationFactoryTest.java | 9 ++++++--- .../dropwizard/validation/tests/ValidatorTest.java | 10 +++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java index a669bb9eb15..f5e1675748b 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/config/tests/ConfigurationFactoryTest.java @@ -10,6 +10,7 @@ import javax.validation.constraints.Pattern; import java.io.File; import java.io.IOException; +import java.util.Locale; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; @@ -55,9 +56,11 @@ public void throwsAnExceptionOnInvalidFiles() throws Exception { try { factory.build(invalidFile); } catch (ConfigurationException e) { - assertThat(e.getMessage(), - endsWith("factory-test-invalid.yml has the following errors:\n" + - " * name must match \"[\\w]+[\\s]+[\\w]+\" (was Boop)")); + if ("en".equals(Locale.getDefault().getLanguage())) { + assertThat(e.getMessage(), + endsWith("factory-test-invalid.yml has the following errors:\n" + + " * name must match \"[\\w]+[\\s]+[\\w]+\" (was Boop)")); + } } } } diff --git a/dropwizard-core/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java b/dropwizard-core/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java index df0b0878277..ae068fa7eb7 100644 --- a/dropwizard-core/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java +++ b/dropwizard-core/src/test/java/com/yammer/dropwizard/validation/tests/ValidatorTest.java @@ -7,6 +7,8 @@ import javax.validation.constraints.Max; import javax.validation.constraints.NotNull; +import java.util.Locale; + import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -31,9 +33,11 @@ public void setTooBig(int tooBig) { @Test public void returnsASetOfErrorsForAnObject() throws Exception { - assertThat(validator.validate(new Example()), - is(ImmutableList.of("notNull may not be null (was null)", - "tooBig must be less than or equal to 30 (was 50)"))); + if ("en".equals(Locale.getDefault().getLanguage())) { + assertThat(validator.validate(new Example()), + is(ImmutableList.of("notNull may not be null (was null)", + "tooBig must be less than or equal to 30 (was 50)"))); + } } @Test From f2a7f0cb7150e325a1054af4edfb62f8b0800ee4 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 10:39:52 -0800 Subject: [PATCH 0248/2771] Switched docs to Sphinx. Includes a new, custom theme. Good lookin'. --- docs/Makefile | 159 ++- docs/README.md | 11 - docs/pages/getting-started.md | 642 ---------- docs/pages/index.md | 19 - docs/pages/manual.md | 992 --------------- .../_static}/dropwizard-hat.png | Bin docs/source/_themes/yammerdoc/genindex.html | 77 ++ docs/source/_themes/yammerdoc/layout.html | 121 ++ docs/source/_themes/yammerdoc/page.html | 13 + docs/source/_themes/yammerdoc/search.html | 56 + .../yammerdoc/static/bootstrap.min.css | 610 ++++++++++ .../_themes/yammerdoc/static/yammerdoc.css | 178 +++ docs/source/_themes/yammerdoc/theme.conf | 13 + docs/source/conf.py | 295 +++++ docs/source/dropwizard-logo.png | Bin 0 -> 961 bytes docs/source/getting-started.rst | 676 +++++++++++ docs/source/index.rst | 37 + docs/source/manual/client.rst | 7 + docs/source/manual/core.rst | 1063 +++++++++++++++++ docs/source/manual/db.rst | 7 + docs/source/manual/index.rst | 22 + docs/source/manual/production.rst | 7 + docs/source/manual/running.rst | 7 + docs/source/manual/scala.rst | 7 + docs/source/manual/templates.rst | 7 + docs/source/manual/testing.rst | 7 + docs/static/css/additional.css | 36 - docs/static/css/bootstrap.min.css | 356 ------ docs/static/images/dropwizard-hat-small.png | Bin 10925 -> 0 bytes docs/static/images/dropwizard-hat-smaller.png | Bin 6699 -> 0 bytes docs/templates/_toolbar.erb | 18 - docs/templates/landing.html.erb | 43 - docs/templates/manual.html.erb | 39 - 33 files changed, 3365 insertions(+), 2160 deletions(-) delete mode 100644 docs/README.md delete mode 100644 docs/pages/getting-started.md delete mode 100644 docs/pages/index.md delete mode 100644 docs/pages/manual.md rename docs/{static/images => source/_static}/dropwizard-hat.png (100%) create mode 100644 docs/source/_themes/yammerdoc/genindex.html create mode 100644 docs/source/_themes/yammerdoc/layout.html create mode 100644 docs/source/_themes/yammerdoc/page.html create mode 100644 docs/source/_themes/yammerdoc/search.html create mode 100644 docs/source/_themes/yammerdoc/static/bootstrap.min.css create mode 100644 docs/source/_themes/yammerdoc/static/yammerdoc.css create mode 100644 docs/source/_themes/yammerdoc/theme.conf create mode 100644 docs/source/conf.py create mode 100644 docs/source/dropwizard-logo.png create mode 100644 docs/source/getting-started.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/manual/client.rst create mode 100644 docs/source/manual/core.rst create mode 100644 docs/source/manual/db.rst create mode 100644 docs/source/manual/index.rst create mode 100644 docs/source/manual/production.rst create mode 100644 docs/source/manual/running.rst create mode 100644 docs/source/manual/scala.rst create mode 100644 docs/source/manual/templates.rst create mode 100644 docs/source/manual/testing.rst delete mode 100644 docs/static/css/additional.css delete mode 100644 docs/static/css/bootstrap.min.css delete mode 100644 docs/static/images/dropwizard-hat-small.png delete mode 100644 docs/static/images/dropwizard-hat-smaller.png delete mode 100644 docs/templates/_toolbar.erb delete mode 100644 docs/templates/landing.html.erb delete mode 100644 docs/templates/manual.html.erb diff --git a/docs/Makefile b/docs/Makefile index b793a63723d..8b3956f3c7e 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,5 +1,156 @@ -build: - mook +# Makefile for Sphinx documentation +# -upload: build - rsync -avz target/ codahale.com:/home/codahale/dropwizard.codahale.com/ +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = target + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Dropwizard.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Dropwizard.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Dropwizard" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Dropwizard" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +upload: clean dirhtml + rsync -avz --delete --exclude=maven $(BUILDDIR)/dirhtml/ codahale.com:/home/codahale/dropwizard.codahale.com/ diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index d6cf30e689c..00000000000 --- a/docs/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Building The Docs - -You'll need `mook`: - - gem install mook - -Then, run `mook`: - - mook - -The goodie will be in the `target` directory. \ No newline at end of file diff --git a/docs/pages/getting-started.md b/docs/pages/getting-started.md deleted file mode 100644 index d54ddcb4254..00000000000 --- a/docs/pages/getting-started.md +++ /dev/null @@ -1,642 +0,0 @@ -Title: Getting Started -Template: manual.html.erb -Order: 2 -* * * - -The goal of this document is to guide you through the process of -creating a simple Dropwizard project: Hello World. Along the way, we’ll -explain the various underlying libraries and their roles, important -concepts in Dropwizard, and suggest some organizational techniques to -help you as your project grows. (Or you can just skip to the -[fun part](#maven).) - -## Overview #overview - -Dropwizard straddles the line between being a library and a framework. -Its goal is to provide performant, reliable implementations of -everything a production-ready web service needs. Because this -functionality is extracted into a reusable library, your service remains -lean and focused, reducing both time-to-market and maintenance burdens. - -### Jetty for HTTP - -Because you can't be a web service without HTTP, Dropwizard uses the -[Jetty](http://www.eclipse.org/jetty/) HTTP library to embed an -incredibly tuned HTTP server directly into your project. Instead of -handing your service off to a complicated application server, Dropwizard -projects have a `main` method which spins up an HTTP server. Running -your service as a simple process eliminates a number of unsavory aspects -of Java in production (no PermGem issues, no application server -configuration and maintenance, no arcane deployment tools, no -`ClassLoader` troubles, no hidden application logs, no trying to tune a -single garbage collector to work with multiple application workloads) -and allows you to use all of Unix's existing process management tools -instead. - -### Jersey for REST - -For building RESTful web services, we've found nothing beats -[Jersey](http://jersey.java.net) (the -[JAX-RS](http://jcp.org/en/jsr/detail?id=311) reference implementation) -in terms of features or performance. It allows you to write clean, -testable classes which gracefully map HTTP requests to simple Java -objects. It supports streaming output, matrix URI parameters, -conditional `GET` requests, and much, much more. - -### Jackson for JSON - -In terms of data formats, JSON has become the web’s *lingua franca*, and -[Jackson](http://jackson.codehaus.org/) is the king of JSON on the JVM. -In addition to being lightning fast, it has a sophisticated object -mapper, allowing you to export your domain models directly. - -### Metrics for metrics - -Our very own [Metrics](https://github.com/codahale/metrics) library -rounds things out, providing you with unparalleled insight into your -code’s behavior in your production environment. - -### And Friends - -In addition to Jetty, Jersey, and Jackson, Dropwizard also includes a -number of libraries that we've come to rely on: - -- [Guava](http://code.google.com/p/guava-libraries/), which, in - addition to highly optimized immutable data structures, provides a - growing number of classes to speed up development in Java. -- [Log4j](http://logging.apache.org/log4j/1.2/) and - [slf4j](http://www.slf4j.org/) for performant logging. -- [Hibernate - Validator](http://www.hibernate.org/subprojects/validator.html), the - [JSR-303](http://jcp.org/en/jsr/detail?id=303) reference - implementation, provides an easy, declarative framework for - validating user input and generating helpful, internationalizable - error messages. -- [Apache - HttpClient](http://hc.apache.org/httpcomponents-client-ga/index.html) - and Jersey's client library allow for both low- and high-level - interaction with other web services. -- [JDBI](http://www.jdbi.org) is the most straight-forward way to use - a relational database with Java. -- [Freemarker](http://freemarker.sourceforge.net/) is a simple - template system for more user-facing services. - -Now that you've gotten the lay of the land, let's dig in! - -* * * * * - -## Setting Up Maven #maven - -We recommend you use [Maven](http://maven.apache.org) for new Dropwizard -services. If you're a big -[Ant](http://ant.apache.org/)/[Ivy](http://ant.apache.org/ivy/), -[Buildr](http://buildr.apache.org/), [Gradle](http://www.gradle.org/), -[SBT](https://github.com/harrah/xsbt/wiki), or -[Gant](http://gant.codehaus.org/) fan, that’s cool, but we use Maven and -we'll be using Maven as we go through this example service. If you have -any questions about how Maven works, [Maven: The Complete -Reference](http://www.sonatype.com/books/mvnref-book/reference/) should -have what you’re looking for. (We’re assuming you know how to create a -new Maven project.) - -Add the `dropwizard-core` library as a dependency: - -``` xml - - - com.yammer.dropwizard - dropwizard-core - 0.1.3 - - -``` - -Alright, that’s enough XML. We’ve got a Maven project set up now, and -it’s time to start writing real code. - -* * * * * - -## Creating A Configuration Class #configuration - -Each Dropwizard service has its own subclass of the `Configuration` -class which specify environment-specific parameters. These parameters -are specified in a [YAML](http://www.yaml.org/) configuration file which -is deserialized to an instance of your service’s configuration class and -validated. - -The service we’re building is a high-performance Hello World service, -and part of our requirements is that we need to be able to vary how it -says hello from environment to environment. We’ll need to specify at -least two things to begin with: a template for saying hello and a -default name to use in case the user doesn’t specify their name. - -Here's what our configuration class will look like: - -``` java -package com.example.helloworld; - -import com.yammer.dropwizard.config.Configuration; -import org.hibernate.validator.constraints.NotEmpty; - -public class HelloWorldConfiguration extends Configuration { - @NotEmpty - private String template; - - @NotEmpty - private String defaultName = "Stranger"; - - public String getTemplate() { - return template; - } - - public String getDefaultName() { - return defaultName; - } -} -``` - -There's a lot going on here, so let’s unpack a bit of it. - -When this class is deserialized from the YAML file, it will pull two -root-level fields from the YAML object: `template`, the template for our -Hello World saying, and `defaultName`, the default name to use. Both -`template` and `defaultName` are annotated with `@NotEmpty`, so if the -YAML configuration file has blank values for either or is missing -`template` entirely an informative exception will be thrown and your -service won’t start. - -Our YAML file, then, will look like this: - -``` yaml -template: Hello, %s! -defaultName: Stranger -``` - -Dropwizard has a *lot* more configuration parameters than that, but they -all have sane defaults so you can keep your configuration files small -and focused. - -So save that YAML file as `hello-world.yml`, because we’ll be getting up -and running pretty soon and we’ll need it. Next up, we’re creating our -service class! - -* * * * * - -## Creating A Service Class #service - -Combined with your project’s `Configuration` subclass, its `Service` -form the core of your Dropwizard service. The `Service` class pulls -together the various bundles and commands which provide basic -functionality. (More on that later.) For now, though, our -`HelloWorldService` looks like this: - -``` java -package com.example.helloworld; - -import com.yammer.dropwizard.Service; -import com.yammer.dropwizard.config.Environment; - -public class HelloWorldService extends Service { - public static void main(String[] args) throws Exception { - new HelloWorldService().run(args); - } - - private HelloWorldService() { - super("hello-world"); - } - - @Override - protected void initialize(HelloWorldConfiguration configuration, - Environment environment) { - // nothing to do yet - } - -} -``` - -As you can see, `HelloWorldService` is parameterized with the service’s -configuration type, `HelloWorldConfiguration`. `HelloWorldService`’s -constructor provides the service’s name: `hello-world`. Also, we’ve -added a `static` `main` method, which will be our service’s entry point. -Right now, we don’t have any functionality implemented, so our -`initialize` method is a little boring. Let’s fix that! - -* * * * * - -## Creating A Representation Class #representation - -Before we can get into the nuts-and-bolts of our Hello World service, we -need to stop and think about our API. Luckily, our service needs to -conform to an industry standard, [RFC -1149](http://www.ietf.org/rfc/rfc1149.txt "This is a joke."), which -specifies the following JSON representation of a Hello World saying: - -``` javascript -{ - "id": 1, - "content": "Hello, stranger!" -} -``` - -The `id` field is a unique identifier for the saying, and `content` is -the textual representation of the saying. (Thankfully, this is a fairly -straight-forward industry standard.) - -To model this representation, we'll create a representation class: - -``` javascript -package com.example.helloworld.core; - -public class Saying { - private final long id; - private final String content; - - public Saying(long id, String content) { - this.id = id; - this.content = content; - } - - public long getId() { - return id; - } - - public String getContent() { - return content; - } -} -``` - -This is a pretty simple POJO, but there are a few things worth noting -here. - -First, it’s immutable. This makes `Saying` instances *very* easy to -reason about multi-threaded environments as well as single-threaded -environments. Second, it uses the Java Bean standard for the `id` and -`content` properties. This allows Jackson to serialize it to the JSON we -need. The Jackson object mapping code will populate the `id` field of -the JSON object with the return value of `getId()`, likewise with -`content` and `getContent()`. - -Now that we’ve got our representation class, it makes sense to start in -on the resource it represents. - -* * * * * - -## Creating A Resource Class #resource - -Jersey resources are the meat-and-potatoes of a Dropwizard service. Each -resource class is associated with a URI template. For our service, we -need a resource which returns new `Saying` instances from the URI -`/hello-world`, so our resource class will look like this: - -``` java -package com.example.helloworld.resources; - -import com.example.helloworld.core.Saying; -import com.google.common.base.Optional; -import com.yammer.metrics.annotation.Timed; - -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 java.util.concurrent.atomic.AtomicLong; - -@Path("/hello-world") -@Produces(MediaType.APPLICATION_JSON) -public class HelloWorldResource { - private final String template; - private final String defaultName; - private final AtomicLong counter; - - public HelloWorldResource(String template, String defaultName) { - this.template = template; - this.defaultName = defaultName; - this.counter = new AtomicLong(); - } - - @GET - @Timed - public Saying sayHello(@QueryParam("name") Optional name) { - return new Saying(counter.incrementAndGet(), - String.format(template, name.or(defaultName))); - } -} -``` - -Finally, we’re in the thick of it! Let’s start from the top and work our -way down. - -`HelloWorldResource` has two annotations: `@Path` and `@Produces`. -`@Path("/hello-world")` tells Jersey that this resource is accessible at -the URI `/hello-world`, and `@Produces(MediaType.APPLICATION_JSON)` lets -Jersey’s content negotiation code know that this resource produces -representations which are `application/json`. - -`HelloWorldResource` takes two parameters for construction: the -`template` it uses to produce the saying and the `defaultName` used when -the user declines to tell us their name. An `AtomicLong` provides us -with a cheap, thread-safe way of generating unique(ish) IDs. - -**Remember**: Resource classes are used by multiple threads -concurrently. In general, we recommend that resources be -stateless/immutable, but it’s important to keep the context in mind. - -`sayHello(Optional)` is the meat of this class, and it’s a -fairly simple method. The `@QueryParam("name")` tells Jersey to map the -`name` parameter from the query string to the `name` parameter in the -method. If the client sends a request to `/hello-world?name=Dougie`, -`sayHello` will be called with `Optional.of("Dougie")`; if there is no -`name` parameter in the query string, `sayHello` will be called with -`Option.absent()`. (Support for Guava's `Optional` is a little extra -sauce that Dropwizard adds to Jersey's existing functionality.) - -Inside the `sayHello` method, we increment the counter, format the -template using `String.format(String, Object...)`, and return a new -`Saying` instance. - -Because `sayHello` is annotated with `@Timed`, Dropwizard automatically -records the duration and rate of its invocations as a Metrics Timer. - -Once `sayHello` has returned, Jersey takes the `Saying` instance and -looks for a provider class which can write `Saying` instances as -`application/json`. Dropwizard has one such provider built in which -allows for producing and consuming Java objects as JSON objects. The -provider writes out the JSON and the client receives a `200 OK` response -with a content type of `application/json`. - -Before that will actually work, though, we need to go back to our -`HelloWorldService` and add this new resource class. In its `initialize` -method we can read the template and default name from the -`HelloWorldConfiguration` instance, create a new `HelloWorldService` -instance, and then add it to the service’s environment: - -``` java -@Override -protected void initialize(HelloWorldConfiguration configuration, - Environment environment) { - final String template = configuration.getTemplate(); - final String defaultName = configuration.getDefaultName(); - environment.addResource(new HelloWorldResource(template, defaultName)); -} -``` - -When our service starts, we create a new instance of our resource class -with the parameters from the configuration file and hand it off to the -`Environment`, which acts like a registry of all the things your service -can do. - -Before we go too far, we should add a health check for our service. - -* * * * * - -## Adding A Health Check #healthcheck - -Health checks give you a way of adding small tests to your service to -allow you and your ops team to verify that your service is functioning -correctly in production. We **strongly** recommend that all of your -services have at least a minimal set of health checks. (We recommend -this so strongly, in fact, that Dropwizard will nag you should you -neglect to add a health check to your project.) - -Since formatting strings is not likely to fail while a service is -running (unlike, say, a database connection pool), we’ll have to get a -little creative here. We’ll add a health check to make sure we can -actually format the provided template: - -``` java -package com.example.helloworld.health; - -import com.yammer.metrics.core.HealthCheck; - -public class TemplateHealthCheck extends HealthCheck { - private final String template; - - public TemplateHealthCheck(String template) { - super("template"); - this.template = template; - } - - @Override - protected Result check() throws Exception { - final String saying = String.format(template, "TEST"); - if (!saying.contains("TEST")) { - return Result.unhealthy("template doesn't include a name"); - } - return Result.healthy(); - } -} -``` - -`TemplateHealthCheck` checks for two things: that the provided template -is actually a well-formed format string, and that the template actually -produces output with the given name. - -If the string is not a well-formed format string (for example, someone -accidentally put `Hello, %s%` in the configuration file), then -`String.format(String, Object...)` will throw an -`IllegalFormatException` and the health check will implicitly fail. If -the rendered saying doesn’t include the test string, the health check -will explicitly fail by returning an unhealthy `Result`. - -As with most things in Dropwizard, we create a new instance with the -appropriate parameters and add it to the `Environment`: - -``` java -@Override -protected void initialize(HelloWorldConfiguration configuration, - Environment environment) { - final String template = configuration.getTemplate(); - final String defaultName = configuration.getDefaultName(); - environment.addResource(new HelloWorldResource(template, defaultName)); - environment.addHealthCheck(new TemplateHealthCheck(template)); -} -``` - -Now we're almost ready to go! - -* * * * * - -## Building Fat JARs #building - -We recommend that you build your Dropwizard services as “fat†JAR -files—single `.jar` files which contain *all* of the `.class` files -required to run your service. This allows you to build a single -deployable artifact which you can copy from your staging environment to -your QA environment to your production environment without worrying -about differences in installed libraries. To start building our Hello -World service as a fat JAR, we need to configure a Maven plugin called -`maven-shade`. In your `pom.xml` file, add this: - -``` xml - - org.apache.maven.plugins - maven-shade-plugin - 1.4 - - true - - - - package - - shade - - - - - - com.example.helloworld.HelloWorldService - - - - - - - -``` - -This configures Maven to do a couple of things during its `package` -phase: - -- Produce a `pom.xml` file which doesn’t include dependencies for the - libraries whose contents are included in the fat JAR. -- Collate the various `META-INF/services` entries in the JARs instead - of overwriting them. (Jersey doesn’t work without those.) -- Set `com.example.helloworld.HelloWorldService` as the JAR’s - `MainClass`. - -Once you’ve got that configured, go into your project directory and run -`mvn package` (or run the `package` goal from your IDE). You should see -something like this: - -``` -[INFO] Including org.eclipse.jetty:jetty-util:jar:7.6.0.RC0 in the shaded jar. -[INFO] Including com.google.guava:guava:jar:10.0.1 in the shaded jar. -[INFO] Including com.google.code.findbugs:jsr305:jar:1.3.9 in the shaded jar. -[INFO] Including org.hibernate:hibernate-validator:jar:4.2.0.Final in the shaded jar. -[INFO] Including javax.validation:validation-api:jar:1.0.0.GA in the shaded jar. -[INFO] Including org.yaml:snakeyaml:jar:1.9 in the shaded jar. -[INFO] Replacing original artifact with shaded artifact. -[INFO] Replacing /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT.jar with /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT-shaded.jar -[INFO] ------------------------------------------------------------------------ -[INFO] BUILD SUCCESS -[INFO] ------------------------------------------------------------------------ -[INFO] Total time: 8.415s -[INFO] Finished at: Fri Dec 02 16:26:42 PST 2011 -[INFO] Final Memory: 11M/81M -[INFO] ------------------------------------------------------------------------ -``` - -**Congratulations!** You’ve built your first Dropwizard project! Now -it’s time to run it! - -* * * * * - -## Running Your Service #running - -Now that you’ve built a JAR file, it’s time to run it. - -In your project directory, run -`java -jar target/hello-world-0.0.1-SNAPSHOT.jar`. You should see -something like the following: - -``` -java -jar dropwizard-example-0.1.0-SNAPSHOT.jar [arg1 arg2] - -Commands -======== - -server: Starts an HTTP server running the service -------------------------------------------------- -usage: java -jar dropwizard-example-0.1.0-SNAPSHOT.jar server - -h, --help display usage information -``` - -Dropwizard takes the first command line argument and dispatches it to a -matching command. In this case, the only command available is `server`, -which runs your service as an HTTP server. The `server` command requires -a configuration file, so let’s go ahead and give it -[the one we previous saved](#configuration): -`java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml` - -You should see something like the following: - -``` -INFO [2011-12-03 00:38:32,927] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world -INFO [2011-12-03 00:38:32,931] org.eclipse.jetty.server.Server: jetty-7.x.y-SNAPSHOT -INFO [2011-12-03 00:38:32,936] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null} -INFO [2011-12-03 00:38:32,999] com.sun.jersey.server.impl.application.WebApplicationImpl: Initiating Jersey application, version 'Jersey: 1.10 11/02/2011 03:53 PM' -INFO [2011-12-03 00:38:33,041] com.yammer.dropwizard.config.Environment: - - GET /hello-world (com.example.helloworld.resources.HelloWorldResource) - -INFO [2011-12-03 00:38:33,215] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null} -INFO [2011-12-03 00:38:33,235] org.eclipse.jetty.server.AbstractConnector: Started BlockingChannelConnector@0.0.0.0:8080 STARTING -INFO [2011-12-03 00:38:33,238] org.eclipse.jetty.server.AbstractConnector: Started SocketConnector@0.0.0.0:8081 STARTING -``` - -Your Dropwizard service is now listening on ports `8080` for service -requests and `8081` for administration requests. If you press \^C, the -service will shut down gracefully, first closing the server socket, then -allowing a few seconds for in-flight requests to be processed, then -shutting down the process itself. - -But while it’s up, let’s give it a whirl! [Click here to say -hello!](http://localhost:8080/hello-world) [Click here to get even -friendlier!](http://localhost:8080/hello-world?name=Successful+Dropwizard+User) - -So, we’re generating sayings. Awesome. But that’s not all your service -can do. One of the main reasons for using Dropwizard is the -out-of-the-box operational tools it provides, all of which can be found -[on the admin port](http://localhost:8081/). - -If you click through to [metrics](http://localhost:8081/metrics), you -can see all of your service’s metrics represented as a JSON object. - -The [threads](http://localhost:8081/threads) resource allows you to -quickly get a thread dump of all the threads running in that process. - -The [healthcheck](http://localhost:8081/healthcheck) resource runs the -[`TemplateHealthCheck` instance we wrote](#healthcheck). You should see -something like this: - -``` -* deadlocks: OK -* template: OK -``` - -`template` here is the result of your `TemplateHealthCheck`, which -unsurprisingly passed. `deadlocks` is a built-in health check which -looks for deadlocked JVM threads and prints out a listing if any are -found. - -* * * * * - -## Next Steps #next - -Well, congratulations. You’ve got a Hello World service ready for -production (except for the lack of tests) that’s capable of doing -15,000-20,000 requests per second. Hopefully you've gotten a feel for -how Dropwizard combines Jetty, Jersey, Jackson, and other stable, mature -libraries to provide a phenomenal platform for developing RESTful web -services. - -There’s a lot more to Dropwizard than is covered here (commands, -bundles, servlets, advanced configuration, validation, HTTP clients, -database clients, templates, etc.), all of which is covered in -[by Dropwizard's manual.](manual.html) - -

          Learn more about Dropwizard »

          - -

          Learn more about Maven »

          - -

          Learn more about Jetty »

          - -

          Learn more about Jersey »

          - -

          Learn more about Jackson »

          - -

          Learn more about YAML »

          \ No newline at end of file diff --git a/docs/pages/index.md b/docs/pages/index.md deleted file mode 100644 index ecc2c505896..00000000000 --- a/docs/pages/index.md +++ /dev/null @@ -1,19 +0,0 @@ -Title: Home -Template: landing.html.erb -Order: 1 -* * * - -# Meet Dropwizard. - -**Dropwizard is a Java framework for developing ops-friendly, -high-performance, RESTful web services.** - -Developed by [Yammer](https://www.yammer.com) to power their JVM-based -backend services, Dropwizard pulls together stable, mature libraries -from the Java ecosystem into a simple, light-weight package that lets -you focus on getting things done. - -Dropwizard has out-of-the-box support for sophisticated application -metrics, logging, operational tools, and much more, allowing you and -your team to ship a production-quality HTTP+JSON web service in the -shortest time possible. \ No newline at end of file diff --git a/docs/pages/manual.md b/docs/pages/manual.md deleted file mode 100644 index 4dd10cf2cf7..00000000000 --- a/docs/pages/manual.md +++ /dev/null @@ -1,992 +0,0 @@ -Title: User's Manual -Template: manual.html.erb -Order: 3 -* * * - -This goal of this document is to provide you with all the information -required to build, organize, test, deploy, and maintain Dropwizard-based -services. - -## Organization - -In general, we recommend you separate your projects into three Maven -modules: `project-api`, `project-client`, and `project-server`. -`project-api` should contain your [representation -classes](#representations); `project-client` should use those classes -and an HTTP client from [`dropwizard-client`](#client) to implement a -full-fledged client for your service, and `project-server` should -provide the actual service implementation, including -[resources](#resources). - -Our services tend to look like this: - -* `com.example.myservice` - * `api`: [Representation](#representations) classes - * `cli`: Service [command](#commands) classes - * `client`: [Client](#client) implementation - * `core`: Domain implementation - * `health`: [Health check](#health-checks) classes - * `resources`: [Resource](#resources) classes - * `MyService`: The [service](#services) class - * `MyServiceConfiguration`: The [configuration](#configuration) class - -## Services #services - -The main entry point into a Dropwizard service is, unsurprisingly, the -`Service` class. Each `Service` has a **name**, which is mostly used to -render the command-line interface. In the constructor of your `Service` -you can add [bundles](#bundles) and [commands](#commands) to your -service. - -### Configuration #configuration - -Each `Service` subclass has a single type parameter: that of its -matching `Configuration` subclass. These are usually at the root of your -service's main package. For example, your User service would have two -classes: `UserServiceConfiguration`, extending `Configuration`, and -`UserService`, extending `Service`. - -When your service runs a [configured command](#configured-commands) like -the `server` command, Dropwizard parses the provided YAML configuration -file and builds an instance of your service's configuration class by -mapping YAML field names to object field names. - -In order to keep your configuration file and class manageable, we -recommend grouping related configuration parameters into independent -configuration classes. If your service requires a set of configuration -parameters in order to connect to a message queue, for example, we -recommend that you create a new `MessageQueueConfiguration` class: - -``` java -public class MessageQueueConfiguration { - @NotEmpty - private String host; - - @Min(1) - @Max(65535) - private int port = 5672; - - public String getHost() { - return host; - } - - public int getPort() { - return port; - } -} -``` - -Your main `Configuration` subclass can then include this as a member -field: - -``` java -public class ExampleServiceConfiguration extends Configuration { - @NotNull - private MessageQueueConfiguration messageQueue = new MessageQueueConfiguration(); - - public MessageQueueConfiguration getMessageQueueConfiguration() { - return messageQueue; - } -} -``` - -Then, in your service's YAML file, you can use a nested `messageQueue` -field: - -``` yaml -messageQueue: - host: mq.example.com - port: 5673 -``` - -The `@NotNull`, `@NotEmpty`, `@Min`, and `@Max` annotations are part of -Dropwizard's [validation](#validation) functionality. If your YAML -configuration file's `messageQueue.host` field was missing (or was a -blank string), Dropwizard would refuse to start and would output an -error message describing the issues. - -Once your service has parsed the YAML file and constructed its -`Configuration` instance, Dropwizard then calls your `Service` subclass -to initialize your service's `Environment`. - -### Environments - -A Dropwizard `Environment` consists of all the [resource -classes](#resources), servlets, filters, [health -checks](#health-checks), Jersey providers, [managed objects](#managed), -[tasks](#tasks), and Jersey properties which your service provides. - -Each `Service` subclass implements an `initialize` method. This is where -you should be creating new resource instances, etc., and adding them to -the given `Environment` class: - -``` java -@Override -protected void initialize(ExampleConfiguration config, - Environment environment) { - // encapsulate complicated setup logic in factories - final ThingyFactory thingyFactory = new ThingyFactory(config.getThingyConfiguration()); - - final Thingy thingy = thingyFactory.build(); - - environment.addResource(new ThingyResource(thingy)); - environment.addHealthCheck(new ThingyHealthCheck(thingy)); -} -``` - -It's important to keep the `initialize` method clean, so if creating an -instance of something is complicated, like the `Thingy` class above, -extract that logic into a factory. - -### Health Checks #health-checks - -A health check is a runtime test which you can use to verify your -service's behavior in its production environment. For example, you may -want to ensure that your database client is connected to the database: - -``` java -public class DatabaseHealthCheck extends HealthCheck { - private final Database database; - - public DatabaseHealthCheck(Database database) { - super("database"); - this.database = database; - } - - @Override - protected Result check() throws Exception { - if (database.isConnected()) { - return Result.healthy(); - } else { - return Result.unhealthy("Cannot connect to " + database.getUrl()); - } - } -} -``` - -You can then add this health check to your service's environment: - -``` java -environment.addHealthCheck(new DatabaseHealthCheck(database)); -``` - -By sending a `GET` request to `/healthcheck` on the admin port you can -run these tests and view the results: - -``` -$ curl http://dw.example.com:8081/healthcheck -* deadlocks: OK -* database: OK -``` - -If all health checks report success, a `200 OK` is returned. If any -fail, a `500 Internal Server Error` is returned with the error messages -and exception stack traces (if an exception was thrown). - -All Dropwizard services ship with the `deadlocks` health check installed -by default, which uses Java 1.6's built-in thread deadlock detection to -determine if any threads are deadlocked. - -### Managed Objects #managed - -Most services involve objects which need to be started and stopped: -thread pools, database connections, etc. Dropwizard provides the -`Managed` interface for this. You can either have the class in question -implement `Managed`'s `start()` and `stop()` methods, or write a wrapper -class which does so. Adding a `Managed` instance to your service's -`Environment` ties that object's lifecycle to that of the service's HTTP -server. Before the server starts, the `Managed`'s `start()` method is -called. After the server has stopped (and after its graceful shutdown -period) the `Managed`'s `stop()` method is called. - -For example, given a theoretical [Riak](http://riak.basho.com) client -which needs to be started and stopped: - -``` java -public class RiakClientManager implements Managed { - private final RiakClient client; - - public RiakClientManager(RiakClient client) { - this.client = client; - } - - @Override - public void start() throws Exception { - client.start(); - } - - @Override - public void stop() throws Exception { - client.stop(); - } -} -``` - -If `RiakClientManager#start()` throws an exception—e.g., an error -connecting to the server—your service will not start and a full -exception will be logged. If `RiakClientManager#stop()` throws an -exception, the exception will be logged but your service will still be -able to shut down. - -It should be noted that `Environment` has built-in constructors for -`ExecutorService` and `ScheduledExecutorService` instances which are -managed. See `Environment#managedExecutorService` and -`Environment#managedScheduledExecutorService` for details. - -### Bundles #bundles - -A Dropwizard bundle is a reusable group of functionality, used to define -blocks of a service's behavior. For example, `AssetBundle` provides a -simple way to serve static assets from your service's -`src/main/resources/assets` directory as files available from -`/assets/*` in your service. - -Some bundles require configuration parameters. The bundles implement -`ConfiguredBundle` and will require your service's `Configuration` -subclass to implement a specific interface. - -### Commands #commands - -Commands are basic actions which Dropwizard runs based on the arguments -provided on the command line. The built-in `server` command, for -example, spins up an HTTP server and runs your service. Each `Command` -subclass has a name and a set of command line options which Dropwizard -will use to parse the given command line arguments. - -#### Configured Commands #configured-commands - -Some commands require access to configuration parameters and should -extend the `ConfiguredCommand` class, using your service's -`Configuration` class as its type parameter. Dropwizard will treat the -first argument on the command line as the path to a YAML configuration -file, parse and validate it, and provide your command with an instance -of the configuration class. - -#### Managed Commands - -Managed commands further extend configured commands by creating a -lifecycle process for your service's [managed objects](#managed). All -`Managed` instances registered with your service's `Environment` will be -started before your command is run, and will be stopped afterward. - -### Tasks #tasks - -A `Task` is a run-time action your service provides access to on the -administrative port via HTTP. All Dropwizard services start with the -`gc` task, which explicitly triggers the JVM's garbage collection. (This -is useful, for example, for running full garbage collections during -off-peak times or while the given service is out of rotation.) - -Running a task can be done by sending a `POST` request to -`/tasks/{task-name}` on the admin port. For example: - -``` -$ curl -X POST http://dw.example.com:8081/tasks/gc -Running GC... -Done! -``` - -### Logging - -Dropwizard uses [Log4j](http://logging.apache.org/log4j) for its logging -backend. It provides an [slf4j](http://www.slf4j.org/) implementation, -and even routes all `java.util.logging` usage through log4j. - -#### The `Log` class - -Dropwizard comes with a `Log` convenience class, since most of the -logging APIs are horrendous. - -``` java -public class Example { - private static final Log LOG = Log.forClass(Example.class); - - public long fetchAge(long userId) { - LOG.debug("Fetching age for user {}", userId); - - try { - final User user = users.find(userId); - return user.getAge(); - } catch (IOException e) { - LOG.error(e, "Error connecting to user store for user {}", userId); - } catch (UserNotFoundException e) { - LOG.warn(e, "Unable to fetch age for user {}", userId); - } - } -} -``` - -`Log` provides the same statement formatting amenities as SLF4J, so you -can pass arbitrary objects in without having to concatenate strings. -Instances of `{}` in the log message are replaced with the string -representation of the objects. To log exceptions, just pass the -`Throwable` instance as the first parameter and it'll log the exception -type, message, and stack trace. - -The `Log` class also provides the following logging levels: - -* `FATAL`: Very severe error events that will presumably lead the application - to abort. -* `ERROR`: Error events that might still allow the application to continue - running. -* `WARN`: Potentially harmful situations. -* `INFO` :Informational messages that highlight the progress of the - application at coarse-grained level. -* `DEBUG`: Fine-grained informational events that are most useful to debug an - application. -* `TRACE`: Finer-grained informational events than the `DEBUG` level. - -#### Log Format - -Dropwizard's log format has a few specific goals: - -- Be human readable. -- Be machine parsable. -- Be easy for sleepy ops folks to figure out why things are - pear-shaped at 3:30AM using standard UNIXy tools like `tail` and - `grep`. - -The logging output looks like this: - -``` -TRACE [2010-04-06 06:42:35,271] com.example.dw.Thing: Contemplating doing a thing. -DEBUG [2010-04-06 06:42:35,274] com.example.dw.Thing: About to do a thing. -INFO [2010-04-06 06:42:35,274] com.example.dw.Thing: Doing a thing -WARN [2010-04-06 06:42:35,275] com.example.dw.Thing: Doing a thing -ERROR [2010-04-06 06:42:35,275] com.example.dw.Thing: This may get ugly. -FATAL [2010-04-06 06:42:35,275] com.example.dw.Thing: The thing has gone horribly wrong. -! java.lang.RuntimeException: oh noes! -! at com.example.dw.Thing.run(Thing.java:16) -! -``` - -A few items of note: - -- All timestamps are in UTC and ISO 8601 format. -- You can grep for messages of a specific level really easily: - `tail -f dw.log | grep '^WARN'` -- You can grep for messages from a specific class or package really - easily: `tail -f dw.log | grep 'com.example.dw.Thing'` -- You can even pull out full exception stack traces, plus the - accompanying log message: `tail -f dw.log | grep -B 1 '^\!'` - -You can specify a default logger level and even override the levels of -other loggers in your YAML configuration file: - -``` yaml -# Logging settings. -logging: - # The default level of all loggers. Can be OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, or ALL. - level: INFO - # Logger-specific levels. - loggers: - # Overrides the level of com.example.dw.Thing and sets it to DEBUG. - "com.example.dw.Thing": DEBUG -``` - -#### Console Logging - -By default, Dropwizard services log `INFO` and higher to `STDOUT`. You -can configure this by editing the `logging` section of your YAML -configuration file: - -``` yaml -logging: - # ... - # Settings for logging to stdout. - console: - # If true, write log statements to stdout. - enabled: true - # Do not display log statements below this threshold to stdout. - threshold: ALL -``` - -#### File Logging - -Dropwizard can also log to an automatically rotated set of log files. -This is the recommended configuration for your production environment: - -``` yaml -logging: - # ... - # Settings for logging to a file. - file: - # If true, write log statements to a file. - enabled: false - # Do not write log statements below this threshold to the file. - threshold: ALL - # The file to which statements will be logged. When the log file reaches the maximum size, the - # file will be renamed example.log.1, example.log will be truncated, and new statements written - # to it. - filenamePattern: ./logs/example.log - # The maximum size of any log file. Can also be "1GiB" etc - maxFileSize: 50MB - # The maximum number of log files to retain. - retainedFileCount: 5 -``` - -#### Syslog Logging - -Finally, Dropwizard can also log statements to syslog. (**Note:** -because Java doesn't use the native syslog bindings, your syslog server -**must** have an open network socket.) - -``` yaml -logging: - # ... - # Settings for logging to syslog. - syslog: - # If true, write log statements to syslog. - enabled: false - # The hostname of the syslog server to which statements will be sent. - # N.B.: If this is the local host, the local syslog instance will need to be configured to - # listen on an inet socket, not just a Unix socket. - host: localhost - # The syslog facility to which statements will be sent. - facility: local0 - -``` - -### Testing Services - -All of Dropwizard's APIs are designed with testability in mind, so even -your services can have unit tests: - -``` java -public class MyServiceTest { - private final Environment environment = mock(Environment.class); - private final MyService service = new MyService(); - private final MyConfiguration config = new MyConfiguration(); - - @Before - public void setup() throws Exception { - config.setMyParam("yay"); - } - - @Test - public void buildsAThingResource() throws Exception { - service.initialize(config, environment); - - verify(environment).addResource(any(ThingResource.class)); - } -} -``` - -We highly recommend [Mockito](http://code.google.com/p/mockito/) for all -your mocking needs. - -### Banners - -At Yammer, each of our services prints out a big ASCII art banner on -startup. Yours should, too. It's fun. Just add a `banner.txt` class to -`src/main/resources` and it'll print it out when your service starts: - -``` -INFO [2011-12-09 21:56:37,209] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world - dP - 88 - .d8888b. dP. .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b. - 88ooood8 `8bd8' 88' `88 88'`88'`88 88' `88 88 88ooood8 - 88. ... .d88b. 88. .88 88 88 88 88. .88 88 88. ... - `88888P' dP' `dP `88888P8 dP dP dP 88Y888P' dP `88888P' - 88 - dP - -INFO [2011-12-09 21:56:37,214] org.eclipse.jetty.server.Server: jetty-7.6.0.RC1 -... -``` - -We could probably make up an argument about why this is a serious devops -best practice with high ROI and an Agile Tool, but honestly we just -enjoy this. - -## Resources #resources - -Unsurprisingly, most of your day-to-day work with a Dropwizard service -will be in the resource classes, which model the resources exposed in -your RESTful API. Dropwizard uses [Jersey](http://jersey.java.net/) for -this, so most of this section is just re-hashing or collecting various -bits of Jersey documentation. - -Jersey is a framework for mapping various aspects of incoming HTTP -requests to POJOs and then mapping various aspects of POJOs to outgoing -HTTP responses. Here's a basic resource class: - - - -``` java -@Path("/{user}/notifications") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class NotificationsResource { - private final NotificationStore store; - - public NotificationsResource(NotificationStore store) { - this.store = store; - } - - @GET - public NotificationList fetch(@PathParam("user") LongParam userId, - @QueryParam("count") @DefaultValue("20") IntParam count) { - final List notifications = store.fetch(userId.get(), count.get()); - if (notifications != null) { - return new NotificationList(userId, notifications); - } - throw new WebApplicationException(Status.NOT_FOUND); - } - - @POST - public Response add(@PathParam("user") LongParam userId, - @Valid Notification notification) { - final long id = store.add(userId.get(), notification); - return Response.created(UriBuilder.fromResource(NotificationResource.class) - .build(userId.get(), id) - .build(); - } -} -``` - -This class provides a resource (a user's list of notifications) which -responds to `GET` and `POST` requests to `/{user}/notifications`, -providing and consuming `application/json` representations. There's -quite a lot of functionality on display here, and this section will -explain in detail what's in play and how to use these features in your -service. - -### Paths - -**Every resource class must have a `@Path` annotation.** The `@Path` -annotation isn't just a static string, it's a [URI -Template](http://tools.ietf.org/html/draft-gregorio-uritemplate-07). The -`{user}` part denotes a named variable, and when the template matches a -URI the value of that variable will be accessible via -`@PathParam`-annotated method parameters. - -For example, an incoming request for `/1001/notifications` would match -the URI template, and the value `1001` would be available as the path -parameter named `user`. - -If your service doesn't have a resource class whose `@Path` URI template -matches the URI of an incoming request, Jersey will automatically return -a `404 Not Found` to the client. - -### Methods - -Methods on a resource class which accept incoming requests are annotated -with the HTTP methods they handle: `@GET`, `@POST`, `@PUT`, `@DELETE`, -`@HEAD`, `@OPTIONS`, and even `@HttpMethod` for arbitrary new methods. - -If a request comes in which matches a resource class's path but has a -method which the class doesn't support, Jersey will automatically return -a `405 Method Not Allowed` to the client. - -The return value of the method (in this case, a `NotificationList` -instance) is then mapped to the [negotiated content type](#conneg). In -this case, our resource only supports JSON, and so the -`NotificationList` is serialized to JSON using Jackson. - -### Metrics - -Every resource method can be annotated with `@Timed`, `@Metered`, and -`@ExceptionMetered`. Dropwizard augments Jersey to automatically record -runtime information about your resource methods. - -### Parameters - -The annotated methods on a resource class can accept parameters which -are mapped to from aspects of the incoming request. The `*Param` -annotations determine which part of the request the data is mapped, and -the parameter *type* determines how the data is mapped. - -For example: - -- A `@PathParam("user")`-annotated `String` takes the raw value from - the `user` variable in the matched URI template and passes it into - the method as a `String`. -- A `@QueryParam("count")`-annotated `IntParam` parameter takes the - first `count` value from the request's query string and passes it as - a `String` to `IntParam`'s constructor. `IntParam` (and all other - `com.yammer.dropwizard.jersey.params.*` classes) parses the string - as an `Integer`, returning a `400 Bad Request` if the value is - malformed. -- A `@FormParam("name")`-annotated `Set` parameter takes all - the `name` values from a posted form and passes them to the method - as a set of strings. - -What's noteworthy here is that you can actually encapsulate the vast -majority of your validation logic using specialized parameter objects. -See `AbstractParam` for details. - -### Request Entities - -If you're handling request entities (e.g., an `application/json` object -on a `PUT` request), you can model this as a parameter without a -`*Param` annotation. In the [example code](#resource-example), the `add` -method provides a good example of this: - -``` java -@POST -public Response add(@PathParam("user") LongParam userId, - @Valid Notification notification) { - final long id = store.add(userId.get(), notification); - return Response.created(UriBuilder.fromResource(NotificationResource.class) - .build(userId.get(), id) - .build(); -} -``` - -Jersey maps the request entity to any single, unbound parameter. In this -case, because the resource is annotated with -`@Consumes(MediaType.APPLICATION_JSON)`, it uses the Dropwizard-provided -Jackson support which, in addition to parsing the JSON and mapping it to -an instance of `Notification`, also runs it through Dropwizard's -[validation](#validation). - -If the deserialized `Notification` isn't valid, Dropwizard returns a -`422 Unprocessable Entity` response to the client. - -### Media Types #conneg - -Jersey also provides full content negotiation, so if your resource class -consumes `application/json` but the client sends a `text/plain` entity, -Jersey will automatically reply with a `406 Not Acceptable`. Jersey's -even smart enough to use client-provided `q`-values in their `Accept` -headers to pick the best response content type based on what both the -client and server will support. - -### Responses - -If your clients are expecting custom headers or additional information -(or, if you simply desire an additional degree of control over your -responses), you can return explicitly-built `Response` objects: - -``` java -return Response.noContent().language(Locale.GERMAN).build(); -``` - -In general, though, we recommend you return actual domain objects if at -all possible. It makes [testing resources](#testing-resources) much -easier. - -### Error Handling - -If your resource class unintentionally throws an exception, Dropwizard -will log that exception (including stack traces) and return a terse, -safe `500` response. - -If your resource class needs to return an error to the client (e.g., the -requested record doesn't exist), you have two options: throw a -`WebApplicationException` or restructure your method to return a -`Response`. - -If at all possible, prefer throwing `WebApplicationException` instances -to returning `Response` objects. - -### URIs - -While Jersey doesn't quite have first-class support for hyperlink-driven -services, the provided `UriBuilder` functionality does quite well. - -Rather than duplicate resource URIs, it's possible (and recommended!) to -initialize a `UriBuilder` with the path from the resource class itself: - -``` java -UriBuilder.fromResource(UserResource.class).build(user.getId()); -``` - -### Testing #testing-resources - -As with just about everything in Dropwizard, we recommend you design -your resources to be testable. Dependencies which aren't -request-injected should be passed in via the constructor and assigned to -`final` fields. - -Testing, then, consists of creating an instance of your resource class -and passing it a mock. (Again: -[Mockito](http://code.google.com/p/mockito/).) - -``` java -public class NotificationsResourceTest { - private final NotificationStore store = mock(NotificationStore.class); - private final NotificationsResource resource = new NotificationsResource(store); - - @Test - public void getsReturnNotifications() { - final List notifications = mock(List.class); - when(store.fetch(1, 20)).thenReturn(notifications); - - final NotificationList list = resource.fetch(new LongParam("1"), new IntParam("20")); - - assertThat(list.getUserId(), - is(1L)); - - assertThat(list.getNotifications(), - is(notifications)); - } -} -``` - -### OAuth2 - -Dropwizard provides some super-minimalist support for [Oauth -2](http://tools.ietf.org/html/draft-ietf-oauth-v2-22): - -``` java -public Blah doAThing(@BearerToken String token) { - // etc -} -``` - -The Oauth 2 bearer token will be passed in via `token`. - -## Representations #representations - -Representation classes are classes which, when handled to various Jersey -`MessageBodyReader` and `MessageBodyWriter` providers, become the -entities in your service's API. Dropwizard heavily favors JSON, but it's -possible to map from any POJO to custom formats and back. - -### Basic JSON - -Jackson is awesome at converting regular POJOs to JSON and back. This -file: - -``` java -public class Notification { - @JsonProperty - private String text; - - public Notification(String text) { - this.text = text; - } - - public String getText() { - return text; - } - - public String setText(String text) { - this.text = text; - } -} -``` - -gets converted into this JSON: - -``` javascript -{ - "text": "hey it's the value of the text field" -} -``` - -If, at some point, you need to change the JSON field name or the Java -field without affecting the other, you can add an explicit field name to -the `@JsonProperty` annotation. - -If you prefer immutable objects rather than JavaBeans, that's also -doable: - -``` java -public class Notification { - @JsonProperty - private final String text; - - public Notification(@JsonProperty("text") String text) { - this.text = text; - } - - public String getText() { - return text; - } -} -``` - -### Advanced JSON - -Not all JSON representations map nicely to the objects your service -deals with, so it's sometimes necessary to use custom serializers and -deserializers. Just annotate your object like this: - -``` java -@JsonSerialize(using=FunkySerializer.class) -@JsonDeserialize(using=FunkyDeserializer.class) -public class Funky { - // ... -} -``` - -Then make a `FunkySerializer` class which implements -`JsonSerializer` and a `FunkyDeserializer` class which implements -`JsonDeserializer`. - -#### snake\_case - -A common issue with JSON is the disagreement between `camelCase` and -`snake_case` field names. Java and Javascript folks tend to like -`camelCase`; Ruby, Python, and Perl folks insist on `snake_case`. To -make Dropwizard automatically convert field names to `snake_case` (and -back), just annotate the class with `@JsonSnakeCase`: - -``` java -@JsonSnakeCase -public class Person { - @JsonProperty - private String firstName; - - public Person(String firstName) { - this.firstName = firstName; - } - - public String getFirstName() { - return firstName; - } -} -``` - -gets converted into this JSON: - -``` javascript -{ - "first_name": "Coda" -} -``` - -### Validation #validation - -Like [configuration classes](#configuration), you can add validation -annotations to fields of your representation classes and validate them. -If we're accepting client-provided `Person` objects, we probably want to -ensure that the `name` field of the object isn't `null` or blank. We can -do this as follows: - -``` java -public class Person { - @NotEmpty // ensure that name isn't null or blank - @JsonProperty - private final String name; - - public Person(@JsonProperty("name") String name) { - this.name = name; - } - - public String getName() { - return name; - } -} -``` - -Then, in our resource class, we can add the `@Valid` annotation to the -`Person` annotation: - -``` java -@PUT -public Response replace(@Valid Person person) { - // ... -} -``` - -If the `name` field is missing, Dropwizard will return a `text/plain` -`422 Unprocessable Entity` response detailing the validation errors: - -``` -* name may not be empty -``` - -#### Advanced - -More complex validations (for example, cross-field comparisons) are -often hard to do using declarative annotations. As an emergency -maneuver, add the `@ValidationMethod` to any `boolean`-returning method -which begins with `is`: - -``` java -@ValidationMethod(message="may not be Coda") -public boolean isNotCoda() { - return !("Coda".equals(name)); -} -``` - -Due to the rather daft JavaBeans conventions, **the method must begin -with `is`**. This is a limitation of Hibernate Validator, not -Dropwizard. - -### Streaming Output - -If your service happens to return lots of information, you may get a big -performance and efficiency bump by using streaming output. By returning -an object which implements Jersey's `StreamingOutput` interface, your -method can stream the response entity in a chunk-encoded output stream. -Otherwise, you'll need to fully construct your return value and *then* -hand it off to be sent to the client. - -### Testing - -The `dropwizard-testing` module contains a number of helper methods for -testing JSON parsing and generating. Given a JSON fixture file (e.g., -`src/test/resources/fixtures/person.json`), you can test that a `Person` -instance generates the same JSON as the fixture with the following: - -``` java -import static com.yammer.dropwizard.testing.JsonHelpers.asJson; -import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture; - -@Test -public void producesTheExpectedJson() throws Exception { - assertThat("rendering a person as JSON produces a valid API representation", - asJson(person), - is(jsonFixture("fixtures/person.json"))); -} -``` - -This does a whitespace- and comment-insensitive comparison of the -generated JSON and the JSON in the file. If they're different, both JSON -representations are helpfully displayed in the assertion error. - -Likewise, you can also test the parsing of the same JSON file to -guarantee round-trip compatibility: - -``` java -import static com.yammer.dropwizard.testing.JsonHelpers.fromJson; - -@Test -public void consumesTheExpectedJson() throws Exception { - assertThat("parsing a valid API representation produces a person", - fromJson(jsonFixture("fixtures/person.json"), Person.class), - is(person)); -} -``` - -### Custom Representations - -Sometimes, though, you've got some wacky output format you need to -produce or consume and no amount of arguing will make JSON acceptable. -That's unfortunate but OK. You can add support for arbitrary input and -output formats by creating classes which implement Jersey's -`MessageBodyReader` and `MessageBodyWriter` interfaces. (Make sure -they're annotated with `@Provider` and `@Produces("text/gibberish")` or -`@Consumes("text/gibberish")`.) Once you're done, just add instances of -them (or their classes if they depend on Jersey's `@Context` injection) -with your service's `Environment` on initialization. - -## Running Services - -TODO - -## In Production - -TODO - -## Dropwizard Client #client - -TODO - -## Dropwizard DB - -TODO - -## Dropwizard Templates - -TODO - -## Dropwizard & Scala - -TODO diff --git a/docs/static/images/dropwizard-hat.png b/docs/source/_static/dropwizard-hat.png similarity index 100% rename from docs/static/images/dropwizard-hat.png rename to docs/source/_static/dropwizard-hat.png diff --git a/docs/source/_themes/yammerdoc/genindex.html b/docs/source/_themes/yammerdoc/genindex.html new file mode 100644 index 00000000000..7bc002b6c1e --- /dev/null +++ b/docs/source/_themes/yammerdoc/genindex.html @@ -0,0 +1,77 @@ +{# + basic/genindex.html + ~~~~~~~~~~~~~~~~~~~ + + Template for an "all-in-one" index. + + :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{% macro indexentries(firstname, links) %} +
          + {%- if links -%} + + {%- if links[0][0] %}{% endif -%} + {{ firstname|e }} + {%- if links[0][0] %}{% endif -%} + + + {%- for ismain, link in links[1:] -%} + , {% if ismain %}{% endif -%} + [{{ loop.index }}] + {%- if ismain %}{% endif -%} + + {%- endfor %} + {%- else %} + {{ firstname|e }} + {%- endif %} +
          +{% endmacro %} + +{% extends "layout.html" %} +{% set title = _('Index') %} +{% block body %} + +

          {{ _('Index') }}

          + +
          + {% for key, dummy in genindexentries -%} + {{ key }} + {% if not loop.last %}| {% endif %} + {%- endfor %} +
          + +{%- for key, entries in genindexentries %} +

          {{ key }}

          + + {%- for column in entries|slice(2) if column %} + + {%- endfor %} +
          + {%- for entryname, (links, subitems) in column %} + {{ indexentries(entryname, links) }} + {%- if subitems %} +
          + {%- for subentryname, subentrylinks in subitems %} + {{ indexentries(subentryname, subentrylinks) }} + {%- endfor %} +
          + {%- endif -%} + {%- endfor %} +
          +{% endfor %} + +{% endblock %} + +{% block sidebarrel %} +{% if split_index %} +

          {{ _('Index') }}

          +

          {% for key, dummy in genindexentries -%} + {{ key }} + {% if not loop.last %}| {% endif %} + {%- endfor %}

          + +

          {{ _('Full index on one page') }}

          +{% endif %} + {{ super() }} +{% endblock %} diff --git a/docs/source/_themes/yammerdoc/layout.html b/docs/source/_themes/yammerdoc/layout.html new file mode 100644 index 00000000000..112156bfc46 --- /dev/null +++ b/docs/source/_themes/yammerdoc/layout.html @@ -0,0 +1,121 @@ + + +{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} +{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} +{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and +(sidebars != []) %} +{%- set url_root = pathto('', 1) %} +{# XXX necessary? #} +{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} +{%- if not embedded and docstitle %} +{%- set titlesuffix = " | "|safe + docstitle|e %} +{%- else %} +{%- set titlesuffix = "" %} +{%- endif %} +{% set css_files = ['_static/bootstrap.min.css'] + css_files %} + + + {{ title|striptags|e }}{{ titlesuffix }} + + {%- for cssfile in css_files %} + + {%- endfor %} + + {%- if favicon %} + + {%- endif %} + {%- block linktags %} + + {%- if parents %} + + {%- endif %} + {%- if next %} + + {%- endif %} + {%- if prev %} + + {%- endif %} + {%- endblock %} + + + + +
          +
          + {%- block sidebar %} + {%- if title != "Home" %} + + {%- endif %} + {%- endblock %} +
          + {% block body %} {% endblock %} +
          +
          +
          +
          + {%- if show_copyright %} + {%- if hasdoc('copyright') %} + {% trans path=pathto('copyright'), copyright=copyright|e %}© Copyright + {{ copyright }}.{% endtrans %} + {%- else %} + {% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} + {%- endif %} + {%- endif %} + {%- if last_updated %} + {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} + {%- endif %} + {%- if show_sphinx %} + {% trans sphinx_version=sphinx_version|e %}Created using Sphinx + {{ sphinx_version }}.{% endtrans %} + {%- endif %} +
          +
          + + + + + diff --git a/docs/source/_themes/yammerdoc/page.html b/docs/source/_themes/yammerdoc/page.html new file mode 100644 index 00000000000..f6e7a688cb6 --- /dev/null +++ b/docs/source/_themes/yammerdoc/page.html @@ -0,0 +1,13 @@ +{# + basic/page.html + ~~~~~~~~~~~~~~~ + + Master template for simple pages. + + :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{% extends "layout.html" %} +{% block body %} + {{ body }} +{% endblock %} diff --git a/docs/source/_themes/yammerdoc/search.html b/docs/source/_themes/yammerdoc/search.html new file mode 100644 index 00000000000..4cdc6935c0d --- /dev/null +++ b/docs/source/_themes/yammerdoc/search.html @@ -0,0 +1,56 @@ +{# + basic/search.html + ~~~~~~~~~~~~~~~~~ + + Template for the search page. + + :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{% extends "layout.html" %} +{% set title = _('Search') %} +{% set script_files = script_files + ['_static/searchtools.js'] %} +{% block extrahead %} + + {{ super() }} +{% endblock %} +{% block body %} +

          {{ _('Search') }}

          +
          + +

          + {% trans %}Please activate JavaScript to enable the search + functionality.{% endtrans %} +

          +
          +

          + {% trans %}From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list.{% endtrans %} +

          +
          + + + +
          + {% if search_performed %} +

          {{ _('Search Results') }}

          + {% if not search_results %} +

          {{ _('Your search did not match any results.') }}

          + {% endif %} + {% endif %} +
          + {% if search_results %} +
            + {% for href, caption, context in search_results %} +
          • {{ caption }} +
            {{ context|e }}
            +
          • + {% endfor %} +
          + {% endif %} +
          +{% endblock %} diff --git a/docs/source/_themes/yammerdoc/static/bootstrap.min.css b/docs/source/_themes/yammerdoc/static/bootstrap.min.css new file mode 100644 index 00000000000..98bf1671504 --- /dev/null +++ b/docs/source/_themes/yammerdoc/static/bootstrap.min.css @@ -0,0 +1,610 @@ +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} +audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} +audio:not([controls]){display:none;} +html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} +a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +a:hover,a:active{outline:0;} +sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} +sup{top:-0.5em;} +sub{bottom:-0.25em;} +img{max-width:100%;height:auto;border:0;-ms-interpolation-mode:bicubic;} +button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} +button,input{*overflow:visible;line-height:normal;} +button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} +button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} +input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;} +input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} +textarea{overflow:auto;vertical-align:top;} +body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;} +a{color:#0088cc;text-decoration:none;} +a:hover{color:#005580;text-decoration:underline;} +.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} +.row:after{clear:both;} +[class*="span"]{float:left;margin-left:20px;} +.span1{width:60px;} +.span2{width:140px;} +.span3{width:220px;} +.span4{width:300px;} +.span5{width:380px;} +.span6{width:460px;} +.span7{width:540px;} +.span8{width:620px;} +.span9{width:700px;} +.span10{width:780px;} +.span11{width:860px;} +.span12,.container{width:940px;} +.offset1{margin-left:100px;} +.offset2{margin-left:180px;} +.offset3{margin-left:260px;} +.offset4{margin-left:340px;} +.offset5{margin-left:420px;} +.offset6{margin-left:500px;} +.offset7{margin-left:580px;} +.offset8{margin-left:660px;} +.offset9{margin-left:740px;} +.offset10{margin-left:820px;} +.offset11{margin-left:900px;} +.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} +.row-fluid:after{clear:both;} +.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;} +.row-fluid>[class*="span"]:first-child{margin-left:0;} +.row-fluid .span1{width:6.382978723%;} +.row-fluid .span2{width:14.89361702%;} +.row-fluid .span3{width:23.404255317%;} +.row-fluid .span4{width:31.914893614%;} +.row-fluid .span5{width:40.425531911%;} +.row-fluid .span6{width:48.93617020799999%;} +.row-fluid .span7{width:57.446808505%;} +.row-fluid .span8{width:65.95744680199999%;} +.row-fluid .span9{width:74.468085099%;} +.row-fluid .span10{width:82.97872339599999%;} +.row-fluid .span11{width:91.489361693%;} +.row-fluid .span12{width:99.99999998999999%;} +.container{width:940px;margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";} +.container:after{clear:both;} +.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";} +.container-fluid:after{clear:both;} +p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;} +.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;} +h1,h2,h3,h4,h5,h6{margin:0;font-weight:bold;color:#333333;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;} +h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;} +h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;} +h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;} +h4,h5,h6{line-height:18px;} +h4{font-size:14px;}h4 small{font-size:12px;} +h5{font-size:12px;} +h6{font-size:11px;color:#999999;text-transform:uppercase;} +.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;} +.page-header h1{line-height:1;} +ul,ol{padding:0;margin:0 0 9px 25px;} +ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} +ul{list-style:disc;} +ol{list-style:decimal;} +li{line-height:18px;} +ul.unstyled{margin-left:0;list-style:none;} +dl{margin-bottom:18px;} +dt,dd{line-height:18px;} +dt{font-weight:bold;} +dd{margin-left:9px;} +hr{margin:18px 0;border:0;border-top:1px solid #e5e5e5;border-bottom:1px solid #ffffff;} +strong{font-weight:bold;} +em{font-style:italic;} +.muted{color:#999999;} +abbr{font-size:90%;text-transform:uppercase;border-bottom:1px dotted #ddd;cursor:help;} +blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;} +blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} +blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} +q:before,q:after,blockquote:before,blockquote:after{content:"";} +address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;} +small{font-size:100%;} +cite{font-style:normal;} +code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +code{padding:3px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} +pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;}pre.prettyprint{margin-bottom:18px;} +pre code{padding:0;background-color:transparent;} +form{margin:0 0 18px;} +fieldset{padding:0;margin:0;border:0;} +legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;} +label,input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;} +label{display:block;margin-bottom:5px;color:#333333;} +input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.uneditable-textarea{width:auto;height:auto;} +label input,label textarea,label select{display:block;} +input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:0;cursor:pointer;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +input[type="file"]{padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;} +select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;} +select{width:220px;background-color:#ffffff;} +select[multiple],select[size]{height:auto;} +input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +textarea{height:auto;} +input[type="hidden"]{display:none;} +.radio,.checkbox{padding-left:18px;} +.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;} +.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} +.radio.inline,.checkbox.inline{display:inline-block;margin-bottom:0;vertical-align:middle;} +.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} +.controls>.radio.inline:first-child,.controls>.checkbox.inline:first-child{padding-top:0;} +input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;} +input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;} +input[type="file"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.input-mini{width:60px;} +.input-small{width:90px;} +.input-medium{width:150px;} +.input-large{width:210px;} +.input-xlarge{width:270px;} +.input-xxlarge{width:530px;} +input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;} +input.span1,textarea.span1,.uneditable-input.span1{width:50px;} +input.span2,textarea.span2,.uneditable-input.span2{width:130px;} +input.span3,textarea.span3,.uneditable-input.span3{width:210px;} +input.span4,textarea.span4,.uneditable-input.span4{width:290px;} +input.span5,textarea.span5,.uneditable-input.span5{width:370px;} +input.span6,textarea.span6,.uneditable-input.span6{width:450px;} +input.span7,textarea.span7,.uneditable-input.span7{width:530px;} +input.span8,textarea.span8,.uneditable-input.span8{width:610px;} +input.span9,textarea.span9,.uneditable-input.span9{width:690px;} +input.span10,textarea.span10,.uneditable-input.span10{width:770px;} +input.span11,textarea.span11,.uneditable-input.span11{width:850px;} +input.span12,textarea.span12,.uneditable-input.span12{width:930px;} +input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;} +.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} +.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;} +.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} +.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} +.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;} +.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} +.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} +.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;} +.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} +input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} +.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #ddd;} +.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} +:-moz-placeholder{color:#999999;} +::-webkit-input-placeholder{color:#999999;} +.help-block{margin-top:5px;margin-bottom:0;color:#999999;} +.help-inline{display:inline-block;*display:inline;*zoom:1;margin-bottom:9px;vertical-align:middle;padding-left:5px;} +.input-prepend,.input-append{margin-bottom:5px;*zoom:1;}.input-prepend:before,.input-append:before,.input-prepend:after,.input-append:after{display:table;content:"";} +.input-prepend:after,.input-append:after{clear:both;} +.input-prepend input,.input-append input,.input-prepend .uneditable-input,.input-append .uneditable-input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;} +.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;} +.input-prepend .add-on,.input-append .add-on{float:left;display:block;width:auto;min-width:16px;height:18px;margin-right:-1px;padding:4px 5px;font-weight:normal;line-height:18px;color:#999999;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#f5f5f5;border:1px solid #ccc;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;} +.input-prepend .add-on{*margin-top:1px;} +.input-append input,.input-append .uneditable-input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-append .uneditable-input{border-right-color:#ccc;} +.input-append .add-on{margin-right:0;margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.input-append input:first-child{*margin-left:-160px;}.input-append input:first-child+.add-on{*margin-left:-21px;} +.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;} +.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input{display:inline-block;margin-bottom:0;} +.form-search label,.form-inline label,.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{display:inline-block;} +.form-search .input-append .add-on,.form-inline .input-prepend .add-on,.form-search .input-append .add-on,.form-inline .input-prepend .add-on{vertical-align:middle;} +.control-group{margin-bottom:9px;} +.form-horizontal legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;} +.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";} +.form-horizontal .control-group:after{clear:both;} +.form-horizontal .control-group>label{float:left;width:140px;padding-top:5px;text-align:right;} +.form-horizontal .controls{margin-left:160px;} +.form-horizontal .form-actions{padding-left:160px;} +table{max-width:100%;border-collapse:collapse;border-spacing:0;} +.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;border-top:1px solid #ddd;} +.table th{font-weight:bold;vertical-align:bottom;} +.table td{vertical-align:top;} +.table thead:first-child tr th,.table thead:first-child tr td{border-top:0;} +.table tbody+tbody{border-top:2px solid #ddd;} +.table-condensed th,.table-condensed td{padding:4px 5px;} +.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th+th,.table-bordered td+td,.table-bordered th+td,.table-bordered td+th{border-left:1px solid #ddd;} +.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} +.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;} +.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;} +.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;} +.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;} +.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} +table .span1{float:none;width:44px;margin-left:0;} +table .span2{float:none;width:124px;margin-left:0;} +table .span3{float:none;width:204px;margin-left:0;} +table .span4{float:none;width:284px;margin-left:0;} +table .span5{float:none;width:364px;margin-left:0;} +table .span6{float:none;width:444px;margin-left:0;} +table .span7{float:none;width:524px;margin-left:0;} +table .span8{float:none;width:604px;margin-left:0;} +table .span9{float:none;width:684px;margin-left:0;} +table .span10{float:none;width:764px;margin-left:0;} +table .span11{float:none;width:844px;margin-left:0;} +table .span12{float:none;width:924px;margin-left:0;} +[class^="icon-"]{display:inline-block;width:14px;height:14px;vertical-align:text-top;background-image:url(img/glyphicons-halflings.png);background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child{*margin-left:0;} +.icon-white{background-image:url(img/glyphicons-halflings-white.png);} +.icon-glass{background-position:0 0;} +.icon-music{background-position:-24px 0;} +.icon-search{background-position:-48px 0;} +.icon-envelope{background-position:-72px 0;} +.icon-heart{background-position:-96px 0;} +.icon-star{background-position:-120px 0;} +.icon-star-empty{background-position:-144px 0;} +.icon-user{background-position:-168px 0;} +.icon-film{background-position:-192px 0;} +.icon-th-large{background-position:-216px 0;} +.icon-th{background-position:-240px 0;} +.icon-th-list{background-position:-264px 0;} +.icon-ok{background-position:-288px 0;} +.icon-remove{background-position:-312px 0;} +.icon-zoom-in{background-position:-336px 0;} +.icon-zoom-out{background-position:-360px 0;} +.icon-off{background-position:-384px 0;} +.icon-signal{background-position:-408px 0;} +.icon-cog{background-position:-432px 0;} +.icon-trash{background-position:-456px 0;} +.icon-home{background-position:0 -24px;} +.icon-file{background-position:-24px -24px;} +.icon-time{background-position:-48px -24px;} +.icon-road{background-position:-72px -24px;} +.icon-download-alt{background-position:-96px -24px;} +.icon-download{background-position:-120px -24px;} +.icon-upload{background-position:-144px -24px;} +.icon-inbox{background-position:-168px -24px;} +.icon-play-circle{background-position:-192px -24px;} +.icon-repeat{background-position:-216px -24px;} +.icon-refresh{background-position:-240px -24px;} +.icon-list-alt{background-position:-264px -24px;} +.icon-lock{background-position:-287px -24px;} +.icon-flag{background-position:-312px -24px;} +.icon-headphones{background-position:-336px -24px;} +.icon-volume-off{background-position:-360px -24px;} +.icon-volume-down{background-position:-384px -24px;} +.icon-volume-up{background-position:-408px -24px;} +.icon-qrcode{background-position:-432px -24px;} +.icon-barcode{background-position:-456px -24px;} +.icon-tag{background-position:0 -48px;} +.icon-tags{background-position:-25px -48px;} +.icon-book{background-position:-48px -48px;} +.icon-bookmark{background-position:-72px -48px;} +.icon-print{background-position:-96px -48px;} +.icon-camera{background-position:-120px -48px;} +.icon-font{background-position:-144px -48px;} +.icon-bold{background-position:-167px -48px;} +.icon-italic{background-position:-192px -48px;} +.icon-text-height{background-position:-216px -48px;} +.icon-text-width{background-position:-240px -48px;} +.icon-align-left{background-position:-264px -48px;} +.icon-align-center{background-position:-288px -48px;} +.icon-align-right{background-position:-312px -48px;} +.icon-align-justify{background-position:-336px -48px;} +.icon-list{background-position:-360px -48px;} +.icon-indent-left{background-position:-384px -48px;} +.icon-indent-right{background-position:-408px -48px;} +.icon-facetime-video{background-position:-432px -48px;} +.icon-picture{background-position:-456px -48px;} +.icon-pencil{background-position:0 -72px;} +.icon-map-marker{background-position:-24px -72px;} +.icon-adjust{background-position:-48px -72px;} +.icon-tint{background-position:-72px -72px;} +.icon-edit{background-position:-96px -72px;} +.icon-share{background-position:-120px -72px;} +.icon-check{background-position:-144px -72px;} +.icon-move{background-position:-168px -72px;} +.icon-step-backward{background-position:-192px -72px;} +.icon-fast-backward{background-position:-216px -72px;} +.icon-backward{background-position:-240px -72px;} +.icon-play{background-position:-264px -72px;} +.icon-pause{background-position:-288px -72px;} +.icon-stop{background-position:-312px -72px;} +.icon-forward{background-position:-336px -72px;} +.icon-fast-forward{background-position:-360px -72px;} +.icon-step-forward{background-position:-384px -72px;} +.icon-eject{background-position:-408px -72px;} +.icon-chevron-left{background-position:-432px -72px;} +.icon-chevron-right{background-position:-456px -72px;} +.icon-plus-sign{background-position:0 -96px;} +.icon-minus-sign{background-position:-24px -96px;} +.icon-remove-sign{background-position:-48px -96px;} +.icon-ok-sign{background-position:-72px -96px;} +.icon-question-sign{background-position:-96px -96px;} +.icon-info-sign{background-position:-120px -96px;} +.icon-screenshot{background-position:-144px -96px;} +.icon-remove-circle{background-position:-168px -96px;} +.icon-ok-circle{background-position:-192px -96px;} +.icon-ban-circle{background-position:-216px -96px;} +.icon-arrow-left{background-position:-240px -96px;} +.icon-arrow-right{background-position:-264px -96px;} +.icon-arrow-up{background-position:-289px -96px;} +.icon-arrow-down{background-position:-312px -96px;} +.icon-share-alt{background-position:-336px -96px;} +.icon-resize-full{background-position:-360px -96px;} +.icon-resize-small{background-position:-384px -96px;} +.icon-plus{background-position:-408px -96px;} +.icon-minus{background-position:-433px -96px;} +.icon-asterisk{background-position:-456px -96px;} +.icon-exclamation-sign{background-position:0 -120px;} +.icon-gift{background-position:-24px -120px;} +.icon-leaf{background-position:-48px -120px;} +.icon-fire{background-position:-72px -120px;} +.icon-eye-open{background-position:-96px -120px;} +.icon-eye-close{background-position:-120px -120px;} +.icon-warning-sign{background-position:-144px -120px;} +.icon-plane{background-position:-168px -120px;} +.icon-calendar{background-position:-192px -120px;} +.icon-random{background-position:-216px -120px;} +.icon-comment{background-position:-240px -120px;} +.icon-magnet{background-position:-264px -120px;} +.icon-chevron-up{background-position:-288px -120px;} +.icon-chevron-down{background-position:-313px -119px;} +.icon-retweet{background-position:-336px -120px;} +.icon-shopping-cart{background-position:-360px -120px;} +.icon-folder-close{background-position:-384px -120px;} +.icon-folder-open{background-position:-408px -120px;} +.icon-resize-vertical{background-position:-432px -119px;} +.icon-resize-horizontal{background-position:-456px -118px;} +.dropdown{position:relative;} +.dropdown-toggle{*margin-bottom:-3px;} +.dropdown-toggle:active,.open .dropdown-toggle{outline:0;} +.caret{display:inline-block;width:0;height:0;text-indent:-99999px;*text-indent:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"\2193";} +.dropdown .caret{margin-top:8px;margin-left:2px;} +.dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;max-width:220px;_width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.bottom-up{top:auto;bottom:100%;margin-bottom:2px;} +.dropdown-menu .divider{height:1px;margin:5px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;} +.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#555555;white-space:nowrap;} +.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0088cc;} +.dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);} +.dropdown.open .dropdown-menu{display:block;} +.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} +.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;} +.collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;} +.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;} +.btn{display:inline-block;padding:4px 10px 4px;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:first-child{*margin-left:0;} +.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} +.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;} +.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.btn-large .icon{margin-top:1px;} +.btn-small{padding:5px 9px;font-size:11px;line-height:16px;} +.btn-small .icon{margin-top:-1px;} +.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} +.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active{color:rgba(255, 255, 255, 0.75);} +.btn-primary{background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-ms-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(top, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0044cc;} +.btn-primary:active,.btn-primary.active{background-color:#003399 \9;} +.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;} +.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} +.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;} +.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} +.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} +.btn-success:active,.btn-success.active{background-color:#408140 \9;} +.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;} +.btn-info:active,.btn-info.active{background-color:#24748c \9;} +button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} +button.btn.large,input[type="submit"].btn.large{*padding-top:7px;*padding-bottom:7px;} +button.btn.small,input[type="submit"].btn.small{*padding-top:3px;*padding-bottom:3px;} +.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";} +.btn-group:after{clear:both;} +.btn-group:first-child{*margin-left:0;} +.btn-group+.btn-group{margin-left:5px;} +.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;} +.btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} +.btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} +.btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;} +.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} +.btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:5px;*padding-bottom:5px;} +.btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);} +.btn .caret{margin-top:7px;margin-left:0;} +.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);} +.btn-primary .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret{border-top-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);} +.btn-small .caret{margin-top:4px;} +.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.alert,.alert-heading{color:#c09853;} +.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;} +.alert-success{background-color:#dff0d8;border-color:#d6e9c6;} +.alert-success,.alert-success .alert-heading{color:#468847;} +.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;} +.alert-danger,.alert-error,.alert-danger .alert-heading,.alert-error .alert-heading{color:#b94a48;} +.alert-info{background-color:#d9edf7;border-color:#bce8f1;} +.alert-info,.alert-info .alert-heading{color:#3a87ad;} +.alert-block{padding-top:14px;padding-bottom:14px;} +.alert-block>p,.alert-block>ul{margin-bottom:0;} +.alert-block p+p{margin-top:5px;} +.nav{margin-left:0;margin-bottom:18px;list-style:none;} +.nav>li>a{display:block;} +.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;} +.nav-list{padding-left:14px;padding-right:14px;margin-bottom:0;} +.nav-list>li>a,.nav-list .nav-header{display:block;padding:3px 15px;margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} +.nav-list .nav-header{font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-transform:uppercase;} +.nav-list>li+.nav-header{margin-top:9px;} +.nav-list .active>a,.nav-list .active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} +.nav-list [class^="icon-"]{margin-right:2px;} +.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";} +.nav-tabs:after,.nav-pills:after{clear:both;} +.nav-tabs>li,.nav-pills>li{float:left;} +.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} +.nav-tabs{border-bottom:1px solid #ddd;} +.nav-tabs>li{margin-bottom:-1px;} +.nav-tabs>li>a{padding-top:9px;padding-bottom:9px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;} +.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} +.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.nav-pills .active>a,.nav-pills .active>a:hover{color:#ffffff;background-color:#0088cc;} +.nav-stacked>li{float:none;} +.nav-stacked>li>a{margin-right:0;} +.nav-tabs.nav-stacked{border-bottom:0;} +.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} +.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} +.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;} +.nav-pills.nav-stacked>li>a{margin-bottom:3px;} +.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} +.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;} +.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;margin-top:6px;} +.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;} +.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;} +.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;} +.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;} +.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;opacity:1;filter:alpha(opacity=100);} +.tabs-stacked .open>a:hover{border-color:#999999;} +.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";} +.tabbable:after{clear:both;} +.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;} +.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} +.tab-content>.active,.pill-content>.active{display:block;} +.tabs-below .nav-tabs{border-top:1px solid #ddd;} +.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;} +.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;} +.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;} +.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;} +.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} +.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} +.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} +.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} +.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} +.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} +.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} +.navbar{overflow:visible;margin-bottom:18px;} +.navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);} +.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;} +.btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;} +.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} +.btn-navbar .icon-bar+.icon-bar{margin-top:3px;} +.nav-collapse.collapse{height:auto;} +.navbar .brand:hover{text-decoration:none;} +.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;} +.navbar .navbar-text{margin-bottom:0;line-height:40px;color:#999999;}.navbar .navbar-text a:hover{color:#ffffff;background-color:transparent;} +.navbar .btn,.navbar .btn-group{margin-top:5px;} +.navbar .btn-group .btn{margin-top:0;} +.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";} +.navbar-form:after{clear:both;} +.navbar-form input,.navbar-form select{display:inline-block;margin-top:5px;margin-bottom:0;} +.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} +.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} +.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;color:rgba(255, 255, 255, 0.75);background:#666;background:rgba(255, 255, 255, 0.3);border:1px solid #111;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query :-moz-placeholder{color:#eeeeee;} +.navbar-search .search-query::-webkit-input-placeholder{color:#eeeeee;} +.navbar-search .search-query:hover{color:#ffffff;background-color:#999999;background-color:rgba(255, 255, 255, 0.5);} +.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} +.navbar-fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030;} +.navbar-fixed-top .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} +.navbar .nav.pull-right{float:right;} +.navbar .nav>li{display:block;float:left;} +.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} +.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;} +.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;background-color:rgba(0, 0, 0, 0.5);} +.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;} +.navbar .nav.pull-right{margin-left:10px;margin-right:0;} +.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} +.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} +.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;} +.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);} +.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;} +.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;} +.navbar .nav.pull-right .dropdown-menu{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before{left:auto;right:12px;} +.navbar .nav.pull-right .dropdown-menu:after{left:auto;right:13px;} +.breadcrumb{padding:7px 14px;margin:0 0 18px;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline;text-shadow:0 1px 0 #ffffff;} +.breadcrumb .divider{padding:0 5px;color:#999999;} +.breadcrumb .active a{color:#333333;} +.pagination{height:36px;margin:18px 0;} +.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} +.pagination li{display:inline;} +.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;} +.pagination a:hover,.pagination .active a{background-color:#f5f5f5;} +.pagination .active a{color:#999999;cursor:default;} +.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;} +.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.pagination-centered{text-align:center;} +.pagination-right{text-align:right;} +.pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";} +.pager:after{clear:both;} +.pager li{display:inline;} +.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.pager a:hover{text-decoration:none;background-color:#f5f5f5;} +.pager .next a{float:right;} +.pager .previous a{float:left;} +.modal-open .dropdown-menu{z-index:2050;} +.modal-open .dropdown.open{*z-index:2050;} +.modal-open .popover{z-index:2060;} +.modal-open .tooltip{z-index:2070;} +.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} +.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} +.modal{position:fixed;top:50%;left:50%;z-index:1050;max-height:500px;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} +.modal.fade.in{top:50%;} +.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} +.modal-body{padding:15px;} +.modal-footer{padding:14px 15px 15px;margin-bottom:0;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";} +.modal-footer:after{clear:both;} +.modal-footer .btn{float:right;margin-left:5px;margin-bottom:0;} +.tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} +.tooltip.top{margin-top:-2px;} +.tooltip.right{margin-left:2px;} +.tooltip.bottom{margin-top:2px;} +.tooltip.left{margin-left:-2px;} +.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} +.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} +.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} +.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.tooltip-arrow{position:absolute;width:0;height:0;} +.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;} +.popover.right{margin-left:5px;} +.popover.bottom{margin-top:5px;} +.popover.left{margin-left:-5px;} +.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} +.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} +.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} +.popover .arrow{position:absolute;width:0;height:0;} +.popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);} +.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;} +.popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;} +.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";} +.thumbnails:after{clear:both;} +.thumbnails>li{float:left;margin:0 0 18px 20px;} +.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);} +a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} +.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} +.thumbnail .caption{padding:9px;} +.label{padding:1px 3px 2px;font-size:9.75px;font-weight:bold;color:#ffffff;text-transform:uppercase;background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.label-important{background-color:#b94a48;} +.label-warning{background-color:#f89406;} +.label-success{background-color:#468847;} +.label-info{background-color:#3a87ad;} +@-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} +.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} +.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} +.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);} +.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);} +.progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);} +.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.accordion{margin-bottom:18px;} +.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.accordion-heading{border-bottom:0;} +.accordion-heading .accordion-toggle{display:block;padding:8px 15px;} +.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} +.carousel{position:relative;margin-bottom:18px;line-height:1;} +.carousel-inner{overflow:hidden;width:100%;position:relative;} +.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;} +.carousel .item>img{display:block;line-height:1;} +.carousel .active,.carousel .next,.carousel .prev{display:block;} +.carousel .active{left:0;} +.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;} +.carousel .next{left:100%;} +.carousel .prev{left:-100%;} +.carousel .next.left,.carousel .prev.right{left:0;} +.carousel .active.left{left:-100%;} +.carousel .active.right{left:100%;} +.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} +.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} +.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);} +.carousel-caption h4,.carousel-caption p{color:#ffffff;} +.hero-unit{padding:60px;margin-bottom:30px;background-color:#f5f5f5;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;} +.hero-unit p{font-size:18px;font-weight:200;line-height:27px;} +.pull-right{float:right;} +.pull-left{float:left;} +.hide{display:none;} +.show{display:block;} +.invisible{visibility:hidden;} diff --git a/docs/source/_themes/yammerdoc/static/yammerdoc.css b/docs/source/_themes/yammerdoc/static/yammerdoc.css new file mode 100644 index 00000000000..64e6fb2889a --- /dev/null +++ b/docs/source/_themes/yammerdoc/static/yammerdoc.css @@ -0,0 +1,178 @@ +#call-to-action { + text-align: right; +} + +a.headerlink { + display: none; +} + +#title { + color: #ffffff; +} + +.hero-unit h1 { + padding-bottom: 20px ! important; +} + +#top-bar small { + color: #f8f8ff; + text-shadow: 0px -1px 0px #5f0c17; +} + +#landing { + text-align: center; +} + +#landing > a { + font-size: 16px; + padding: 10px 20px 10px; +} + +.admonition { + padding: 14px 35px 14px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.admonition .admonition-title { + font-size: 14pt; + font-weight: bold; +} + +.admonition.note .admonition-title, +.admonition-todo .admonition-title { + color: #c09853; +} + +.admonition.tip, +.admonition.hint { + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.admonition.tip .admonition-title, +.admonition.hint .admonition-title { + color: #468847; +} + +.admonition.error, +.admonition.warning, +.admonition.caution, +.admonition.danger, +.admonition.attention { + background-color: #f2dede; + border-color: #eed3d7; +} + +.admonition.error .admonition-title, +.admonition.warning .admonition-title, +.admonition.caution .admonition-title, +.admonition.danger .admonition-title, +.admonition.attention .admonition-title { + color: #b94a48; +} + +.admonition.important { + background-color: #d9edf7; + border-color: #bce8f1; +} + +.admonition.important .admonition-title { + color: #3a87ad; +} + +.admonition > p, .admonition > ul { + margin-bottom: 0; +} + +.admonition p + p { + margin-top: 5px; +} + +a.internal.reference > em { + font-style: normal ! important; + text-decoration: none ! important; +} + +tt { + padding: 1px 3px; + font-family: 'Panic Sans', Menlo, Monaco, Consolas, Andale Mono, Courier New, monospace; + font-size: 12px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + background-color: #fee9cc; + color: rgba(0, 0, 0, 0.75); +} + +.section > p, .section ul li, .admonition p, .section dt, .section dl { + font-size: 13pt; + line-height: 18pt; +} + +.section tt { + font-size: 11pt; + line-height: 11pt; +} + +.section > * { + margin-bottom: 20px; +} + +pre { + font-family: 'Panic Sans', Menlo, Monaco, Consolas, Andale Mono, Courier New, monospace !important; + font-size: 12pt !important; + line-height: 22px !important; + display: block !important; + width: auto !important; + height: auto !important; + overflow: auto !important; + white-space: pre !important; + word-wrap: normal !important; +} + +#body h1, h1 tt { + font-size: 28pt; +} + +h1 tt { + background-color: transparent; + font-size: 26pt !important; +} + +#body h2 { + font-size: 24pt; +} + +h2 tt { + background-color: transparent; + font-size: 22pt !important; +} + +#body h3 { + font-size: 20pt; +} + +h3 tt { + background-color: transparent; + font-size: 18pt !important; +} + +#body h4 { + font-size: 16pt; +} + +h4 tt { + background-color: transparent; + font-size: 14pt !important; +} + +#sidebar tt { + color: #08c; + background-color: transparent; +} diff --git a/docs/source/_themes/yammerdoc/theme.conf b/docs/source/_themes/yammerdoc/theme.conf new file mode 100644 index 00000000000..a708c56aded --- /dev/null +++ b/docs/source/_themes/yammerdoc/theme.conf @@ -0,0 +1,13 @@ +[theme] +inherit = none +stylesheet = yammerdoc.css +pygments_style = trac + +[options] +tagline = Your tagline here. +gradient_start = #9b4853 +gradient_end = #5f0c17 +gradient_text = #ffffff +gradient_bg = #7D2A35 +landing_logo = logo.png +landing_logo_width = 150px diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000000..b03dba5b6c5 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,295 @@ +# -*- coding: utf-8 -*- +# +# Dropwizard documentation build configuration file, created by +# sphinx-quickstart on Mon Feb 13 11:29:49 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.todo'] + +# Add any paths that contain templates here, relative to this directory. +#templates_path = ['ytemplates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Dropwizard' +copyright = u'2011-2012, Coda Hale, Yammer Inc.' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.2' +# The full version, including alpha/beta/rc tags. +release = '0.2.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +#pygments_style = 'trac' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'yammerdoc' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + 'tagline': u'Production-ready, out of the box.', + 'gradient_start': u'#545d63', + 'gradient_end': u'#182127', + 'gradient_text': u'#ffffff', + 'gradient_bg': u'#363F45', + 'landing_logo': u'dropwizard-hat.png', + 'landing_logo_width': u'150px' +} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = ["./_themes"] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = u'Dropwizard' + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = u'dropwizard-logo.png' + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Dropwizarddoc' + +todo_include_todos = True + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Dropwizard.tex', u'Dropwizard Documentation', + u'Coda Hale', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'dropwizard', u'Dropwizard Documentation', + [u'Coda Hale'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'Dropwizard', u'Dropwizard Documentation', + u'Coda Hale', 'Dropwizard', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# -- Options for Epub output --------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'Dropwizard' +epub_author = u'Coda Hale' +epub_publisher = u'Coda Hale' +epub_copyright = u'2012, Coda Hale' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +#epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True diff --git a/docs/source/dropwizard-logo.png b/docs/source/dropwizard-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..157f688b685741a0c7dfb2b0965026f8d6af635d GIT binary patch literal 961 zcmV;y13vtTP)X1^@s6?pbuq0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU#V@X6oRCwBKR84GDRTTd2x%a*MrqfO- zonp&~mLhGUSR<%yNE2GqMiRopg)uCEkhpYD!WLGn*qG=>7RH#En7DMIap4Ntzyb*r z2%-E)P0TOfeCOvo=R7gB^fg|2yoV{5E|7EI%Pha_h3GL+ z$lWWs!noWh+V?!`Z?nZ9m1s$MBNvGtJupYwN9;ooqbDW1yqC+Hn zh_^3lrZvjVgYMJ`)}R~0=CHB+P_PrWuW;%I9SL-U;F!<_?`+j6v0pd`$qr1PUT{*P z8>%4msD()v$?c(jWh^%OlDRz56bkB8+vhzkLKICi4P+h2u{iLPMn`-3-y0n@hx$5^ z!4oYi;ot(9A+6KwbgppR27>3b+u*I)?kJu={n?KguRcPa5!cO5ykF|+GaKV2xPIsS z`;n&MPo}S+Hn;|pix3&C`~uq#b+)QKGN(<_AI^-%xo=M5>hf-AnHG^5JJ^0-XJi&+ z3x*Y?dBwx=+qJi_(NgTxhBy1AAlyu6ZX@rqwQcybO=+m#?#J9)KqD<+2>uIR1=Fr>c{e@U$GB)!J%fPkr_huu(ox77P zo*dzM|7eR`tQtdzenB+nJy%w!TPO@oDXu@L;ml886wbKLxh?W@E}!>2)GkE^lI!)x z7wbu!L2d;8O(SUT2y406MlPZT4~Ls+f@7av!l}>yKyyPDt4T!$wir{|ynly{cNXM4 z3$x2FAr4t5uy@xJOpHA#M)O78;b9P3xjE~8fO$pTYGPs(w{AVEB}w!_qElS_ZU#p5 zBZ*r~N;XwzG5Hb#@Rk{5N-q4Lxu4~gtG_V$;i((fSB`4ly0xcetT#(gF{e#2ZfRV*(*#(KRDCphJJfYHy-vJ#x;xha=Wt(0(d3OKPe zikL7Wd}u82aij5c{?6@(vwvM%8N0Xg&*19gda2nmB2Kh_ZFHzLK3-j)etYci-EWNi jsrv?g7gGKDOn?CZ2_y9yYu>)U00000NkvXXu0mjfC^pb3 literal 0 HcmV?d00001 diff --git a/docs/source/getting-started.rst b/docs/source/getting-started.rst new file mode 100644 index 00000000000..d8e5d5b0757 --- /dev/null +++ b/docs/source/getting-started.rst @@ -0,0 +1,676 @@ +.. _getting-started: + +############### +Getting Started +############### + +.. highlight:: text + +.. rubric:: *Getting Started* will guide you through the process of creating a simple Dropwizard + project: Hello World. Along the way, we'll explain the various underlying libraries and + their roles, important concepts in Dropwizard, and suggest some organizational + techniques to help you as your project grows. (Or you can just skip to + the :ref:`fun part `.) + +.. _gs-overview: + +Overview +======== + +Dropwizard straddles the line between being a library and a framework. Its goal is to provide +performant, reliable implementations of everything a production-ready web service needs. Because +this functionality is extracted into a reusable library, your service remains lean and focused, +reducing both time-to-market and maintenance burdens. + +.. _gs-jetty: + +Jetty for HTTP +-------------- + +Because you can't be a web service without HTTP, Dropwizard uses the Jetty_ HTTP library to embed +an incredibly tuned HTTP server directly into your project. Instead of handing your service off to a +complicated application server, Dropwizard projects have a ``main`` method which spins up an HTTP +server. Running your service as a simple process eliminates a number of unsavory aspects of Java in +production (no PermGem issues, no application server configuration and maintenance, no arcane +deployment tools, no ``ClassLoader`` troubles, no hidden application logs, no trying to tune a +single garbage collector to work with multiple application workloads) and allows you to use all of +the existing Unix process management tools instead. + +.. _Jetty: http://www.eclipse.org/jetty/ + +.. _gs-jersey: + +Jersey for REST +--------------- + +For building RESTful web services, we've found nothing beats Jersey_ (the `JAX-RS`_ reference +implementation) in terms of features or performance. It allows you to write clean, testable classes +which gracefully map HTTP requests to simple Java objects. It supports streaming output, matrix URI +parameters, conditional ``GET`` requests, and much, much more. + +.. _Jersey: http://jersey.java.net +.. _JAX-RS: http://jcp.org/en/jsr/detail?id=311 + +.. _gs-jackson: + +Jackson for JSON +---------------- + +In terms of data formats, JSON has become the web’s *lingua franca*, and Jackson_ is the king of +JSON on the JVM. In addition to being lightning fast, it has a sophisticated object mapper, allowing +you to export your domain models directly. + +.. _Jackson: http://jackson.codehaus.org/ + +.. _gs-metrics: + +Metrics for metrics +------------------- + +Our very own Metrics_ library rounds things out, providing you with unparalleled insight into your +code's behavior in your production environment. + +.. _Metrics: http://metrics.codahale.com + +.. _gs-and-friends: + +And Friends +----------- + +In addition to Jetty_, Jersey_, and Jackson_, Dropwizard also includes a number of libraries that +we've come to rely on: + +* Guava_, which, in addition to highly optimized immutable data structures, provides a growing + number of classes to speed up development in Java. +* Log4j_ and slf4j_ for performant logging. +* `Hibernate Validator`_, the `JSR-303`_ reference implementation, provides an easy, declarative + framework for validating user input and generating helpful, internationalizable error messages. +* The `Apache HttpClient`_ and Jersey_ client libraries allow for both low- and high-level + interaction with other web services. +* JDBI_ is the most straight-forward way to use a relational database with Java. +* Freemarker_ is a simple template system for more user-facing services. + +.. _Guava: http://code.google.com/p/guava-libraries/ +.. _Log4j: http://logging.apache.org/log4j/1.2/ +.. _slf4j: http://www.slf4j.org/ +.. _Hibernate Validator: http://www.hibernate.org/subprojects/validator.html +.. _JSR-303: http://jcp.org/en/jsr/detail?id=303 +.. _Apache HttpClient: http://hc.apache.org/httpcomponents-client-ga/index.html +.. _JDBI: http://www.jdbi.org +.. _Freemarker: http://freemarker.sourceforge.net/ + +Now that you've gotten the lay of the land, let's dig in! + +.. _gs-maven-setup: + +Setting Up Maven +================ + +We recommend you use Maven_ for new Dropwizard services. If you're a big Ant_ / Ivy_, Buildr_, +Gradle_, SBT_, Leiningen_, or Gant_ fan, that’s cool, but we use Maven and we'll be using Maven as +we go through this example service. If you have any questions about how Maven works, +`Maven: The Complete Reference `_ should have what you’re looking for. (We’re assuming +you know how to create a new Maven project.) + +.. _Maven: http://maven.apache.org +.. _Ant: http://ant.apache.org/ +.. _Ivy: http://ant.apache.org/ivy/ +.. _Buildr: http://buildr.apache.org/ +.. _Gradle: http://www.gradle.org/ +.. _SBT: https://github.com/harrah/xsbt/wiki +.. _Gant: http://gant.codehaus.org/ +.. _Leiningen: https://github.com/technomancy/leiningen +.. _maven-book: http://www.sonatype.com/books/mvnref-book/reference/ + +Add the ``dropwizard-core`` library as a dependency: + +.. _gs-pom-dependencies: + +.. code-block:: xml + + + + com.yammer.dropwizard + dropwizard-core + 0.2.0 + + + +Alright, that's enough XML. We’ve got a Maven project set up now, and it's time to start writing +real code. + +.. _gs-configuration: + +Creating A Configuration Class +============================== + +Each Dropwizard service has its own subclass of the ``Configuration`` class which specify +environment-specific parameters. These parameters are specified in a YAML_ configuration file which +is deserialized to an instance of your service's configuration class and validated. + +.. _YAML: http://www.yaml.org/ + +The service we're building is a high-performance Hello World service, and part of our requirements +is that we need to be able to vary how it says hello from environment to environment. We'll need to +specify at least two things to begin with: a template for saying hello and a default name to use in +case the user doesn't specify their name. + +Here's what our configuration class will look like: + +.. _gs-configuration-class: + +.. code-block:: java + :emphasize-lines: 10,14 + + package com.example.helloworld; + + import com.yammer.dropwizard.config.Configuration; + import org.codehaus.jackson.annotate.JsonProperty; + import org.hibernate.validator.constraints.NotEmpty; + + public class HelloWorldConfiguration extends Configuration { + @NotEmpty + @JsonProperty + private String template; + + @NotEmpty + @JsonProperty + private String defaultName = "Stranger"; + + public String getTemplate() { + return template; + } + + public String getDefaultName() { + return defaultName; + } + } + +There's a lot going on here, so let’s unpack a bit of it. + +When this class is deserialized from the YAML file, it will pull two root-level fields from the YAML +object: ``template``, the template for our Hello World saying, and ``defaultName``, the default name +to use. Both ``template`` and ``defaultName`` are annotated with ``@NotEmpty``, so if the YAML +configuration file has blank values for either or is missing ``template`` entirely an informative +exception will be thrown and your service won't start. + +.. note:: + + The mapping from YAML to your service's ``Configuration`` instance is done by Jackson_. This + means your ``Configuration`` class can use all of Jackon's + `object-mapping annotations `_. The validation of ``@NotEmpty`` is handled + by Hibernate Validator, which has a `wide range of built-in constraints `_ + for you to use. + +.. _jackson-annotations: http://wiki.fasterxml.com/JacksonAnnotations +.. _validator-annotations: http://docs.jboss.org/hibernate/validator/4.2/reference/en-US/html_single/#validator-defineconstraints-builtin + +Our YAML file, then, will look like this: + +.. _gs-yaml-file: + +.. code-block:: yaml + + template: Hello, %s! + defaultName: Stranger + +Dropwizard has *many* more configuration parameters than that, but they all have sane defaults so +you can keep your configuration files small and focused. + +So save that YAML file as ``hello-world.yml``, because we'll be getting up and running pretty soon +and we'll need it. Next up, we're creating our service class! + +.. _gs-service: + +Creating A Service Class +======================== + +Combined with your project's ``Configuration`` subclass, its ``Service`` form the core of your +Dropwizard service. The ``Service`` class pulls together the various bundles and commands which +provide basic functionality. (More on that later.) For now, though, our ``HelloWorldService`` looks +like this: + +.. code-block:: java + :emphasize-lines: 7,8,9,12 + + package com.example.helloworld; + + import com.yammer.dropwizard.Service; + import com.yammer.dropwizard.config.Environment; + + public class HelloWorldService extends Service { + public static void main(String[] args) throws Exception { + new HelloWorldService().run(args); + } + + private HelloWorldService() { + super("hello-world"); + } + + @Override + protected void initialize(HelloWorldConfiguration configuration, + Environment environment) { + // nothing to do yet + } + + } + +As you can see, ``HelloWorldService`` is parameterized with the service's configuration type, +``HelloWorldConfiguration``. The constructor of ``HelloWorldService`` provides the service's name: +``hello-world``. Also, we've added a ``static`` ``main`` method, which will be our service's entry +point. Right now, we don't have any functionality implemented, so our ``initialize`` method is a +little boring. Let’s fix that! + +.. _gs-representation: + +Creating A Representation Class +=============================== + +Before we can get into the nuts-and-bolts of our Hello World service, we need to stop and think +about our API. Luckily, our service needs to conform to an industry standard, `RFC 1149`__, which +specifies the following JSON representation of a Hello World saying: + +.. __: http://www.ietf.org/rfc/rfc1149.txt + +.. code-block:: javascript + + { + "id": 1, + "content": "Hello, stranger!" + } + + +The ``id`` field is a unique identifier for the saying, and ``content`` is the textual +representation of the saying. (Thankfully, this is a fairly straight-forward industry standard.) + +To model this representation, we'll create a representation class: + +.. code-block:: java + + package com.example.helloworld.core; + + public class Saying { + private final long id; + private final String content; + + public Saying(long id, String content) { + this.id = id; + this.content = content; + } + + public long getId() { + return id; + } + + public String getContent() { + return content; + } + } + +This is a pretty simple POJO, but there are a few things worth noting here. + +First, it's immutable. This makes ``Saying`` instances *very* easy to reason about in multi-threaded +environments as well as single-threaded environments. Second, it uses the Java Bean standard for the +``id`` and ``content`` properties. This allows Jackson_ to serialize it to the JSON we need. The +Jackson object mapping code will populate the ``id`` field of the JSON object with the return value +of ``#getId()``, likewise with ``content`` and ``#getContent()``. + +.. note:: + + The JSON serialization here is done by Jackson, which supports far more than simple JavaBean + objects like this one. In addition to the sophisticated set of + `annotations `_, you can even write your own custom serializers and + deserializers. + +Now that we've got our representation class, it makes sense to start in on the +resource it represents. + +.. _gs-resource: + +Creating A Resource Class +========================= + +Jersey resources are the meat-and-potatoes of a Dropwizard service. Each resource class is +associated with a URI template. For our service, we need a resource which returns new ``Saying`` +instances from the URI ``/hello-world``, so our resource class will look like this: + +.. code-block:: java + :emphasize-lines: 14,15,21,27,28,29 + + package com.example.helloworld.resources; + + import com.example.helloworld.core.Saying; + import com.google.common.base.Optional; + import com.yammer.metrics.annotation.Timed; + + 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 java.util.concurrent.atomic.AtomicLong; + + @Path("/hello-world") + @Produces(MediaType.APPLICATION_JSON) + public class HelloWorldResource { + private final String template; + private final String defaultName; + private final AtomicLong counter; + + public HelloWorldResource(String template, String defaultName) { + this.template = template; + this.defaultName = defaultName; + this.counter = new AtomicLong(); + } + + @GET + @Timed + public Saying sayHello(@QueryParam("name") Optional name) { + return new Saying(counter.incrementAndGet(), + String.format(template, name.or(defaultName))); + } + } + +Finally, we're in the thick of it! Let's start from the top and work our way down. + +``HelloWorldResource`` has two annotations: ``@Path`` and ``@Produces``. ``@Path("/hello-world")`` +tells Jersey that this resource is accessible at the URI ``/hello-world``, and +``@Produces(MediaType.APPLICATION_JSON)`` lets Jersey's content negotiation code know that this +resource produces representations which are ``application/json``. + +``HelloWorldResource`` takes two parameters for construction: the ``template`` it uses to produce +the saying and the ``defaultName`` used when the user declines to tell us their name. An +``AtomicLong`` provides us with a cheap, thread-safe way of generating unique(ish) IDs. + +.. warning:: + + Resource classes are used by multiple threads concurrently. In general, we recommend that + resources be stateless/immutable, but it's important to keep the context in mind. + +``#sayHello(Optional)`` is the meat of this class, and it's a fairly simple method. The +``@QueryParam("name")`` annotation tells Jersey to map the ``name`` parameter from the query string +to the ``name`` parameter in the method. If the client sends a request to +``/hello-world?name=Dougie``, ``sayHello`` will be called with ``Optional.of("Dougie")``; if there +is no ``name`` parameter in the query string, ``sayHello`` will be called with ``Option.absent()``. +(Support for Guava's ``Optional`` is a little extra sauce that Dropwizard adds to Jersey's existing +functionality.) + +Inside the ``sayHello`` method, we increment the counter, format the template using +``String.format(String, Object...)``, and return a new ``Saying`` instance. + +Because ``sayHello`` is annotated with ``@Timed``, Dropwizard automatically records the duration and +rate of its invocations as a Metrics Timer. + +Once ``sayHello`` has returned, Jersey takes the ``Saying`` instance and looks for a provider class +which can write ``Saying`` instances as ``application/json``. Dropwizard has one such provider built +in which allows for producing and consuming Java objects as JSON objects. The provider writes out +the JSON and the client receives a ``200 OK`` response with a content type of ``application/json``. + +.. _gs-resource-register: + +Registering A Resource +---------------------- + +Before that will actually work, though, we need to go back to ``HelloWorldService`` and add this new +resource class. In its ``initialize`` method we can read the template and default name from the +``HelloWorldConfiguration`` instance, create a new ``HelloWorldService`` instance, and then add it +to the service's environment: + +.. code-block:: java + + @Override + protected void initialize(HelloWorldConfiguration configuration, + Environment environment) { + final String template = configuration.getTemplate(); + final String defaultName = configuration.getDefaultName(); + environment.addResource(new HelloWorldResource(template, defaultName)); + } + +When our service starts, we create a new instance of our resource class with the +parameters from the configuration file and hand it off to the ``Environment``, +which acts like a registry of all the things your service can do. + +Before we go too far, we should add a health check for our service. + +.. _gs-healthcheck: + +Creating A Health Check +======================= + +Health checks give you a way of adding small tests to your service to allow you and your ops team to +verify that your service is functioning correctly in production. We **strongly** recommend that all +of your services have at least a minimal set of health checks. + +.. note:: + + We recommend this so strongly, in fact, that Dropwizard will nag you should you neglect to add a + health check to your project. + +Since formatting strings is not likely to fail while a service is running (unlike, say, a database +connection pool), we'll have to get a little creative here. We'll add a health check to make sure we +can actually format the provided template: + +.. code-block:: java + + package com.example.helloworld.health; + + import com.yammer.metrics.core.HealthCheck; + + public class TemplateHealthCheck extends HealthCheck { + private final String template; + + public TemplateHealthCheck(String template) { + super("template"); + this.template = template; + } + + @Override + protected Result check() throws Exception { + final String saying = String.format(template, "TEST"); + if (!saying.contains("TEST")) { + return Result.unhealthy("template doesn't include a name"); + } + return Result.healthy(); + } + } + + +``TemplateHealthCheck`` checks for two things: that the provided template is actually a well-formed +format string, and that the template actually produces output with the given name. + +If the string is not a well-formed format string (for example, someone accidentally put +``Hello, %s%`` in the configuration file), then ``String.format(String, Object...)`` will throw an +``IllegalFormatException`` and the health check will implicitly fail. If the rendered saying doesn't +include the test string, the health check will explicitly fail by returning an unhealthy ``Result``. + +.. _gs-healthcheck-add: + +Adding A Heath Check +-------------------- + +As with most things in Dropwizard, we create a new instance with the appropriate parameters and add +it to the ``Environment``: + +.. code-block:: java + + @Override + protected void initialize(HelloWorldConfiguration configuration, + Environment environment) { + final String template = configuration.getTemplate(); + final String defaultName = configuration.getDefaultName(); + environment.addResource(new HelloWorldResource(template, defaultName)); + environment.addHealthCheck(new TemplateHealthCheck(template)); + } + + +Now we're almost ready to go! + +.. _gs-building: + +Building Fat JARs +================= + +We recommend that you build your Dropwizard services as "fat" JAR files-single ``.jar`` files which +contain *all* of the ``.class`` files required to run your service. This allows you to build a +single deployable artifact which you can promote from your staging environment to your QA +environment to your production environment without worrying about differences in installed +libraries. To start building our Hello World service as a fat JAR, we need to configure a Maven +plugin called ``maven-shade``. In the ```` section of your ``pom.xml`` file, add +this: + +.. code-block:: xml + :emphasize-lines: 6,10,16,17,18,19 + + + org.apache.maven.plugins + maven-shade-plugin + 1.4 + + true + + + + package + + shade + + + + + + com.example.helloworld.HelloWorldService + + + + + + + +This configures Maven to do a couple of things during its ``package`` phase: + +* Produce a ``pom.xml`` file which doesn't include dependencies for the libraries whose contents are + included in the fat JAR. +* Collate the various ``META-INF/services`` entries in the JARs instead of overwriting them. (Jersey + doesn't work without those.) +* Set ``com.example.helloworld.HelloWorldService`` as the JAR's ``MainClass``. This will allow you + to run the JAR using ``java -jar``. + +Once you've got that configured, go into your project directory and run ``mvn package`` (or run the +``package`` goal from your IDE). You should see something like this: + +.. code-block:: text + + [INFO] Including org.eclipse.jetty:jetty-util:jar:7.6.0.RC0 in the shaded jar. + [INFO] Including com.google.guava:guava:jar:10.0.1 in the shaded jar. + [INFO] Including com.google.code.findbugs:jsr305:jar:1.3.9 in the shaded jar. + [INFO] Including org.hibernate:hibernate-validator:jar:4.2.0.Final in the shaded jar. + [INFO] Including javax.validation:validation-api:jar:1.0.0.GA in the shaded jar. + [INFO] Including org.yaml:snakeyaml:jar:1.9 in the shaded jar. + [INFO] Replacing original artifact with shaded artifact. + [INFO] Replacing /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT.jar with /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT-shaded.jar + [INFO] ------------------------------------------------------------------------ + [INFO] BUILD SUCCESS + [INFO] ------------------------------------------------------------------------ + [INFO] Total time: 8.415s + [INFO] Finished at: Fri Dec 02 16:26:42 PST 2011 + [INFO] Final Memory: 11M/81M + [INFO] ------------------------------------------------------------------------ + +**Congratulations!** You've built your first Dropwizard project! Now it's time to +run it! + +.. _gs-running: + +Running Your Service +==================== + +Now that you’ve built a JAR file, it's time to run it. + +In your project directory, run this: + +.. code-block:: text + + java -jar target/hello-world-0.0.1-SNAPSHOT.jar + +You should see something like the following: + +.. code-block:: text + + java -jar dropwizard-example-0.1.0-SNAPSHOT.jar [arg1 arg2] + + Commands + ======== + + server: Starts an HTTP server running the service + ------------------------------------------------- + usage: java -jar dropwizard-example-0.1.0-SNAPSHOT.jar server + -h, --help display usage information + +Dropwizard takes the first command line argument and dispatches it to a matching command. In this +case, the only command available is ``server``, which runs your service as an HTTP server. The +``server`` command requires a configuration file, so let’s go ahead and give it +:ref:`the YAML file we previously saved `:: + + java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml + +You should see something like the following: + +.. code-block:: text + + INFO [2011-12-03 00:38:32,927] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world + INFO [2011-12-03 00:38:32,931] org.eclipse.jetty.server.Server: jetty-7.x.y-SNAPSHOT + INFO [2011-12-03 00:38:32,936] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null} + INFO [2011-12-03 00:38:32,999] com.sun.jersey.server.impl.application.WebApplicationImpl: Initiating Jersey application, version 'Jersey: 1.10 11/02/2011 03:53 PM' + INFO [2011-12-03 00:38:33,041] com.yammer.dropwizard.config.Environment: + + GET /hello-world (com.example.helloworld.resources.HelloWorldResource) + + INFO [2011-12-03 00:38:33,215] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null} + INFO [2011-12-03 00:38:33,235] org.eclipse.jetty.server.AbstractConnector: Started BlockingChannelConnector@0.0.0.0:8080 STARTING + INFO [2011-12-03 00:38:33,238] org.eclipse.jetty.server.AbstractConnector: Started SocketConnector@0.0.0.0:8081 STARTING + +Your Dropwizard service is now listening on ports ``8080`` for service requests and ``8081`` for +administration requests. If you press ``^C``, the service will shut down gracefully, first closing +the server socket, then allowing a few seconds for in-flight requests to be processed, then shutting +down the process itself. (You can disable this to allow for faster restarts during development, by +setting ``http.shutdownGracePeriod`` to ``0s`` in your configuration file.) + +But while it's up, let's give it a whirl! +`Click here to say hello! `_ +`Click here to get even friendlier! `_ + +So, we're generating sayings. Awesome. But that's not all your service can do. One of the main +reasons for using Dropwizard is the out-of-the-box operational tools it provides, all of which can +be found `on the admin port `_. + +If you click through to the `metrics resource `_, you can see all of +your service's metrics represented as a JSON object. + +The `threads resource `_ allows you to quickly get a thread dump of +all the threads running in that process. + +The `healthcheck resource `_ runs the +:ref:`health check class we wrote `. You should see something like this:: + + * deadlocks: OK + * template: OK + + +``template`` here is the result of your ``TemplateHealthCheck``, which unsurprisingly passed. +``deadlocks`` is a built-in health check which looks for deadlocked JVM threads and prints out a +listing if any are found. + +.. _gs-next: + +Next Steps +========== + +Well, congratulations. You've got a Hello World service ready for production (except for the lack of +tests) that's capable of doing 15,000-20,000 requests per second. Hopefully you've gotten a feel for +how Dropwizard combines Jetty, Jersey, Jackson, and other stable, mature libraries to provide a +phenomenal platform for developing RESTful web services. + +There's a lot more to Dropwizard than is covered here (commands, bundles, servlets, advanced +configuration, validation, HTTP clients, database clients, templates, etc.), all of which is covered +by the :ref:`User Manual `. diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000000..182451f4acf --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,37 @@ +.. title:: Home + +.. raw:: html + +
          + +################################################################################################### +Dropwizard is a Java framework for developing ops-friendly, high-performance, RESTful web services. +################################################################################################### + +Developed by Yammer__ to power their JVM-based backend services, Dropwizard pulls together +**stable**, **mature** libraries from the Java ecosystem into a **simple**, **light-weight** package +that lets you focus on *getting things done*. + +.. __: https://www.yammer.com + +Dropwizard has *out-of-the-box* support for sophisticated **configuration**, +**application metrics**, **logging**, **operational tools**, and much more, allowing you and your +team to ship a *production-quality* HTTP+JSON web service in the shortest time possible. + +.. raw:: html + + +

          + Getting Started » + User Manual » +

          +
          diff --git a/docs/source/manual/client.rst b/docs/source/manual/client.rst new file mode 100644 index 00000000000..a318df76843 --- /dev/null +++ b/docs/source/manual/client.rst @@ -0,0 +1,7 @@ +.. _man-client: + +################# +Dropwizard Client +################# + +.. todo:: write Client diff --git a/docs/source/manual/core.rst b/docs/source/manual/core.rst new file mode 100644 index 00000000000..81a0f0012ca --- /dev/null +++ b/docs/source/manual/core.rst @@ -0,0 +1,1063 @@ +.. _man-core: + +############### +Dropwizard Core +############### + +.. highlight:: text + +The ``dropwizard-core`` module provides you with everything you'll need for most of your services. + +It includes: + +* Jetty, a high-performance HTTP server. +* Jersey, a full-featured RESTful web framework. +* Jackson, the best JSON library for the JVM. +* Metrics, `Yammer's`__ own library for application metrics. +* Guava, Google's excellent utility library. +* Log4j, Java's most widely-used logging framework. +* Hibernate Validator, the reference implementation of the Java Bean Validation standard. + +.. __: https://www.yammer.com + +Dropwizard consists mostly of glue code to automatically connect and configure these components. + +.. _man-core-organization: + +Organizing Your Project +======================= + +In general, we recommend you separate your projects into three Maven modules: ``project-api``, +``project-client``, and ``project-service``. + +``project-api`` should contain your :ref:`man-core-representations`; ``project-client`` should use +those classes and an :ref:`HTTP client ` to implement a full-fledged client for your +service, and ``project-service`` should provide the actual service implementation, including +:ref:`man-core-resources`. + +Our services tend to look like this: + +* ``com.example.myservice``: + + * ``api``: :ref:`man-core-representations`. + * ``cli``: :ref:`man-core-commands` + * ``client``: :ref:`Client ` implementation for your service + * ``core``: Domain implementation + * ``health``: :ref:`man-core-healthchecks` + * ``resources``: :ref:`man-core-resources` + * ``MyService``: The :ref:`service ` class + * ``MyServiceConfiguration``: :ref:`configuration ` class + +.. _man-core-service: + +Service +======= + +The main entry point into a Dropwizard service is, unsurprisingly, the ``Service`` class. Each +``Service`` has a **name**, which is mostly used to render the command-line interface. In the +constructor of your ``Service`` you can add :ref:`man-core-bundles` and :ref:`man-core-commands` to +your service. + + +.. _man-core-configuration: + +Configuration +============= + +Each ``Service`` subclass has a single type parameter: that of its matching ``Configuration`` +subclass. These are usually at the root of your service's main package. For example, your User +service would have two classes: ``UserServiceConfiguration``, extending ``Configuration``, and +``UserService``, extending ``Service``. + +When your service runs a :ref:`man-core-commands-configured` like the ``server`` command, Dropwizard +parses the provided YAML configuration file and builds an instance of your service's configuration +class by mapping YAML field names to object field names. + +.. note:: + + If your configuration file doesn't end in ``.yml`` or ``.yaml``, Dropwizard tries to parse it + as a JSON file. + +In order to keep your configuration file and class manageable, we recommend grouping related +configuration parameters into independent configuration classes. If your service requires a set of +configuration parameters in order to connect to a message queue, for example, we recommend that you +create a new ``MessageQueueConfiguration`` class: + +.. code-block:: java + + public class MessageQueueConfiguration { + @NotEmpty + @JsonProperty + private String host; + + @Min(1) + @Max(65535) + @JsonProperty + private int port = 5672; + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + } + +Your main ``Configuration`` subclass can then include this as a member field: + +.. code-block:: java + + public class ExampleServiceConfiguration extends Configuration { + @NotNull + @JsonProperty + private MessageQueueConfiguration messageQueue = new MessageQueueConfiguration(); + + public MessageQueueConfiguration getMessageQueueConfiguration() { + return messageQueue; + } + } + +Then, in your service's YAML file, you can use a nested ``messageQueue`` field: + +.. code-block:: java + + messageQueue: + host: mq.example.com + port: 5673 + +The ``@NotNull``, ``@NotEmpty``, ``@Min``, and ``@Max`` annotations are part of Dropwizard's +:ref:`man-core-representations-validation` functionality. If your YAML configuration file's +``messageQueue.host`` field was missing (or was a blank string), Dropwizard would refuse to start +and would output an error message describing the issues. + +Once your service has parsed the YAML file and constructed its ``Configuration`` instance, +Dropwizard then calls your ``Service`` subclass to initialize your service's ``Environment``. + +.. _man-core-environments: + +Environments +============ + +A Dropwizard ``Environment`` consists of all the :ref:`man-core-resources`, servlets, filters, +:ref:`man-core-healthchecks`, Jersey providers, :ref:`man-core-managed`, :ref:`man-core-tasks`, and +Jersey properties which your service provides. + +Each ``Service`` subclass implements an ``initialize`` method. This is where you should be creating +new resource instances, etc., and adding them to the given ``Environment`` class: + +.. code-block:: java + + @Override + protected void initialize(ExampleConfiguration config, + Environment environment) { + // encapsulate complicated setup logic in factories + final ThingyFactory thingyFactory = new ThingyFactory(config.getThingyConfiguration()); + + final Thingy thingy = thingyFactory.build(); + + environment.addResource(new ThingyResource(thingy)); + environment.addHealthCheck(new ThingyHealthCheck(thingy)); + } + +It's important to keep the ``initialize`` method clean, so if creating an instance of something is +complicated, like the ``Thingy`` class above, extract that logic into a factory. + +.. _man-core-healthchecks: + +Health Checks +============= + +A health check is a runtime test which you can use to verify your service's behavior in its +production environment. For example, you may want to ensure that your database client is connected +to the database: + +.. code-block:: java + + public class DatabaseHealthCheck extends HealthCheck { + private final Database database; + + public DatabaseHealthCheck(Database database) { + super("database"); + this.database = database; + } + + @Override + protected Result check() throws Exception { + if (database.isConnected()) { + return Result.healthy(); + } else { + return Result.unhealthy("Cannot connect to " + database.getUrl()); + } + } + } + +You can then add this health check to your service's environment: + +.. code-block:: java + + environment.addHealthCheck(new DatabaseHealthCheck(database)); + +By sending a ``GET`` request to ``/healthcheck`` on the admin port you can run these tests and view +the results:: + + $ curl http://dw.example.com:8081/healthcheck + * deadlocks: OK + * database: OK + +If all health checks report success, a ``200 OK`` is returned. If any fail, a +``500 Internal Server Error`` is returned with the error messages and exception stack traces (if an +exception was thrown). + +All Dropwizard services ship with the ``deadlocks`` health check installed by default, which uses +Java 1.6's built-in thread deadlock detection to determine if any threads are deadlocked. + +.. _man-core-managed: + +Managed Objects +=============== + +Most services involve objects which need to be started and stopped: thread pools, database +connections, etc. Dropwizard provides the ``Managed`` interface for this. You can either have the +class in question implement the ``#start()`` and ``#stop()`` methods, or write a wrapper class which +does so. Adding a ``Managed`` instance to your service's ``Environment`` ties that object's +lifecycle to that of the service's HTTP server. Before the server starts, the ``#start()`` method is +called. After the server has stopped (and after its graceful shutdown period) the ``#stop()`` method +is called. + +For example, given a theoretical Riak__ client which needs to be started and stopped: + +.. __: http://riak.basho.com + +.. code-block:: java + + public class RiakClientManager implements Managed { + private final RiakClient client; + + public RiakClientManager(RiakClient client) { + this.client = client; + } + + @Override + public void start() throws Exception { + client.start(); + } + + @Override + public void stop() throws Exception { + client.stop(); + } + } + + +If ``RiakClientManager#start()`` throws an exception—e.g., an error connecting to the server—your +service will not start and a full exception will be logged. If ``RiakClientManager#stop()`` throws +an exception, the exception will be logged but your service will still be able to shut down. + +It should be noted that ``Environment`` has built-in factory methods for ``ExecutorService`` and +``ScheduledExecutorService`` instances which are managed. See ``Environment#managedExecutorService`` +and ``Environment#managedScheduledExecutorService`` for details. + +.. _man-core-bundles: + +Bundles +======= + +A Dropwizard bundle is a reusable group of functionality, used to define blocks of a service's +behavior. For example, ``AssetBundle`` provides a simple way to serve static assets from your +service's ``src/main/resources/assets`` directory as files available from ``/assets/*`` in your +service. + +Some bundles require configuration parameters. These bundles implement ``ConfiguredBundle`` and will +require your service's ``Configuration`` subclass to implement a specific interface. + +.. _man-core-commands: + +Commands +======== + +Commands are basic actions which Dropwizard runs based on the arguments provided on the command +line. The built-in ``server`` command, for example, spins up an HTTP server and runs your service. +Each ``Command`` subclass has a name and a set of command line options which Dropwizard will use to +parse the given command line arguments. + +.. _man-core-commands-configured: + +Configured Commands +------------------- + +Some commands require access to configuration parameters and should extend the ``ConfiguredCommand`` +class, using your service's ``Configuration`` class as its type parameter. Dropwizard will treat the +first argument on the command line as the path to a YAML configuration file, parse and validate it, +and provide your command with an instance of the configuration class. + +.. _man-core-commands-managed: + +Managed Commands +---------------- + +Managed commands further extend configured commands by creating a lifecycle process for your +service's :ref:`man-core-managed`. All ``Managed`` instances registered with your service's +``Environment`` will be started before your command is run, and will be stopped afterward. + +.. _man-core-tasks: + +Tasks +===== + +A ``Task`` is a run-time action your service provides access to on the administrative port via HTTP. +All Dropwizard services start with the ``gc`` task, which explicitly triggers the JVM's garbage +collection. (This is useful, for example, for running full garbage collections during off-peak times +or while the given service is out of rotation.) + +Running a task can be done by sending a ``POST`` request to ``/tasks/{task-name}`` on the admin +port. For example:: + + $ curl -X POST http://dw.example.com:8081/tasks/gc + Running GC... + Done! + +.. _man-core-logging: + +Logging +======= + +Dropwizard uses Log4j_ for its logging backend. It provides an slf4j_ implementation, and even +routes all ``java.util.logging`` usage through log4j. + +.. _Log4j: http://logging.apache.org/log4j/1.2/ +.. _slf4j: http://www.slf4j.org/ + +.. _man-core-logging-class: + +The ``Log`` class +----------------- + +Dropwizard comes with a ``Log`` convenience class, since most of the logging APIs are horrendous. + +.. code-block:: java + + public class Example { + private static final Log LOG = Log.forClass(Example.class); + + public long fetchAge(long userId) { + LOG.debug("Fetching age for user {}", userId); + + try { + final User user = users.find(userId); + return user.getAge(); + } catch (IOException e) { + LOG.error(e, "Error connecting to user store for user {}", userId); + } catch (UserNotFoundException e) { + LOG.warn(e, "Unable to fetch age for user {}", userId); + } + } + } + +``Log`` provides the same statement formatting amenities as SLF4J, so you can pass arbitrary objects +in without having to concatenate strings. Instances of ``{}`` in the log message are replaced with +the string representation of the objects. To log exceptions, just pass the ``Throwable`` instance as +the first parameter and it'll log the exception type, message, and stack trace. + +The ``Log`` class provides the following logging levels: + +``FATAL`` + Very severe error events that will presumably lead the application to abort. +``ERROR`` + Error events that might still allow the application to continue running. +``WARN`` + Potentially harmful situations. +``INFO`` + Informational messages that highlight the progress of the application at coarse-grained level. +``DEBUG`` + Fine-grained informational events that are most useful to debug an application. +``TRACE`` + Finer-grained informational events than the ``DEBUG`` level. + +.. _man-core-logging-format: + +Log Format +---------- + +Dropwizard's log format has a few specific goals: + +* Be human readable. +* Be machine parsable. +* Be easy for sleepy ops folks to figure out why things are pear-shaped at 3:30AM using standard + UNIXy tools like ``tail`` and ``grep``. + +The logging output looks like this:: + + TRACE [2010-04-06 06:42:35,271] com.example.dw.Thing: Contemplating doing a thing. + DEBUG [2010-04-06 06:42:35,274] com.example.dw.Thing: About to do a thing. + INFO [2010-04-06 06:42:35,274] com.example.dw.Thing: Doing a thing + WARN [2010-04-06 06:42:35,275] com.example.dw.Thing: Doing a thing + ERROR [2010-04-06 06:42:35,275] com.example.dw.Thing: This may get ugly. + FATAL [2010-04-06 06:42:35,275] com.example.dw.Thing: The thing has gone horribly wrong. + ! java.lang.RuntimeException: oh noes! + ! at com.example.dw.Thing.run(Thing.java:16) + ! + +A few items of note: + +* All timestamps are in UTC and ISO 8601 format. +* You can grep for messages of a specific level really easily:: + + tail -f dw.log | grep '^WARN' + +* You can grep for messages from a specific class or package really easily:: + + tail -f dw.log | grep 'com.example.dw.Thing' + +* You can even pull out full exception stack traces, plus the accompanying log message:: + + tail -f dw.log | grep -B 1 '^\!' + +You can specify a default logger level and even override the levels of +other loggers in your YAML configuration file: + +.. code-block:: yaml + + # Logging settings. + logging: + # The default level of all loggers. Can be OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, or ALL. + level: INFO + # Logger-specific levels. + loggers: + # Overrides the level of com.example.dw.Thing and sets it to DEBUG. + "com.example.dw.Thing": DEBUG + +.. _man-core-logging-console: + +Console Logging +--------------- + +By default, Dropwizard services log ``INFO`` and higher to ``STDOUT``. You can configure this by +editing the ``logging`` section of your YAML configuration file: + +.. code-block:: yaml + + logging: + # ... + # Settings for logging to stdout. + console: + # If true, write log statements to stdout. + enabled: true + # Do not display log statements below this threshold to stdout. + threshold: ALL + +.. _man-core-logging-file: + +File Logging +------------ + +Dropwizard can also log to an automatically rotated set of log files. This is the recommended +configuration for your production environment: + +.. code-block:: yaml + + logging: + # ... + # Settings for logging to a file. + file: + # If true, write log statements to a file. + enabled: false + # Do not write log statements below this threshold to the file. + threshold: ALL + # The file to which statements will be logged. When the log file reaches the maximum size, the + # file will be renamed example.log.1, example.log will be truncated, and new statements written + # to it. + filenamePattern: ./logs/example.log + # The maximum size of any log file. Can also be "1GiB" etc + maxFileSize: 50MB + # The maximum number of log files to retain. + retainedFileCount: 5 + +.. _man-core-logging-syslog: + +Syslog Logging +-------------- + +Finally, Dropwizard can also log statements to syslog. + +.. note:: + + Because Java doesn't use the native syslog bindings, your syslog server **must** have an open + network socket. + +.. code-block:: yaml + + logging: + # ... + # Settings for logging to syslog. + syslog: + # If true, write log statements to syslog. + enabled: false + # The hostname of the syslog server to which statements will be sent. + # N.B.: If this is the local host, the local syslog instance will need to be configured to + # listen on an inet socket, not just a Unix socket. + host: localhost + # The syslog facility to which statements will be sent. + facility: local0 + +.. _man-core-testing-services: + +Testing Services +================ + +All of Dropwizard's APIs are designed with testability in mind, so even your services can have unit +tests: + +.. code-block:: java + + public class MyServiceTest { + private final Environment environment = mock(Environment.class); + private final MyService service = new MyService(); + private final MyConfiguration config = new MyConfiguration(); + + @Before + public void setup() throws Exception { + config.setMyParam("yay"); + } + + @Test + public void buildsAThingResource() throws Exception { + service.initialize(config, environment); + + verify(environment).addResource(any(ThingResource.class)); + } + } + +We highly recommend Mockito_ for all your mocking needs. + +.. _Mockito: http://code.google.com/p/mockito/ + + +.. _man-core-banners: + +Banners +======= + +At Yammer, each of our services prints out a big ASCII art banner on startup. Yours should, too. +It's fun. Just add a ``banner.txt`` class to ``src/main/resources`` and it'll print it out when your +service starts:: + + INFO [2011-12-09 21:56:37,209] com.yammer.dropwizard.cli.ServerCommand: Starting hello-world + dP + 88 + .d8888b. dP. .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b. + 88ooood8 `8bd8' 88' `88 88'`88'`88 88' `88 88 88ooood8 + 88. ... .d88b. 88. .88 88 88 88 88. .88 88 88. ... + `88888P' dP' `dP `88888P8 dP dP dP 88Y888P' dP `88888P' + 88 + dP + + INFO [2011-12-09 21:56:37,214] org.eclipse.jetty.server.Server: jetty-7.6.0 + ... + +We could probably make up an argument about why this is a serious devops best practice with high ROI +and an Agile Tool, but honestly we just enjoy this. + +.. _man-core-resources: + +Resources +========= + +Unsurprisingly, most of your day-to-day work with a Dropwizard service will be in the resource +classes, which model the resources exposed in your RESTful API. Dropwizard uses Jersey__ for this, +so most of this section is just re-hashing or collecting various bits of Jersey documentation. + +.. __: http://jersey.java.net/ + +Jersey is a framework for mapping various aspects of incoming HTTP requests to POJOs and then +mapping various aspects of POJOs to outgoing HTTP responses. Here's a basic resource class: + +.. _man-core-resources-example: + +.. code-block:: java + + @Path("/{user}/notifications") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public class NotificationsResource { + private final NotificationStore store; + + public NotificationsResource(NotificationStore store) { + this.store = store; + } + + @GET + public NotificationList fetch(@PathParam("user") LongParam userId, + @QueryParam("count") @DefaultValue("20") IntParam count) { + final List notifications = store.fetch(userId.get(), count.get()); + if (notifications != null) { + return new NotificationList(userId, notifications); + } + throw new WebApplicationException(Status.NOT_FOUND); + } + + @POST + public Response add(@PathParam("user") LongParam userId, + @Valid Notification notification) { + final long id = store.add(userId.get(), notification); + return Response.created(UriBuilder.fromResource(NotificationResource.class) + .build(userId.get(), id) + .build(); + } + } + +This class provides a resource (a user's list of notifications) which responds to ``GET`` and +``POST`` requests to ``/{user}/notifications``, providing and consuming ``application/json`` +representations. There's quite a lot of functionality on display here, and this section will +explain in detail what's in play and how to use these features in your service. + +.. _man-core-resources-paths: + +Paths +----- + +.. important:: + + Every resource class must have a ``@Path`` annotation. + +The ``@Path`` annotation isn't just a static string, it's a `URI Template`__. The ``{user}`` part +denotes a named variable, and when the template matches a URI the value of that variable will be +accessible via ``@PathParam``-annotated method parameters. + +.. __: http://tools.ietf.org/html/draft-gregorio-uritemplate-07 + +For example, an incoming request for ``/1001/notifications`` would match the URI template, and the +value ``"1001"`` would be available as the path parameter named ``user``. + +If your service doesn't have a resource class whose ``@Path`` URI template matches the URI of an +incoming request, Jersey will automatically return a ``404 Not Found`` to the client. + +.. _man-core-resources-methods: + +Methods +------- + +Methods on a resource class which accept incoming requests are annotated with the HTTP methods they +handle: ``@GET``, ``@POST``, ``@PUT``, ``@DELETE``, ``@HEAD``, ``@OPTIONS``, and even +``@HttpMethod`` for arbitrary new methods. + +If a request comes in which matches a resource class's path but has a method which the class doesn't +support, Jersey will automatically return a ``405 Method Not Allowed`` to the client. + +The return value of the method (in this case, a ``NotificationList`` instance) is then mapped to the +:ref:`negotiated media type ` this case, our resource only supports +JSON, and so the ``NotificationList`` is serialized to JSON using Jackson. + +.. _man-core-resources-metrics: + +Metrics +------- + +Every resource method can be annotated with ``@Timed``, ``@Metered``, and ``@ExceptionMetered``. +Dropwizard augments Jersey to automatically record runtime information about your resource methods. + + +.. _man-core-resources-parameters: + +Parameters +---------- + +The annotated methods on a resource class can accept parameters which are mapped to from aspects of +the incoming request. The ``*Param`` annotations determine which part of the request the data is +mapped, and the parameter *type* determines how the data is mapped. + +For example: + +* A ``@PathParam("user")``-annotated ``String`` takes the raw value from the ``user`` variable in + the matched URI template and passes it into the method as a ``String``. +* A ``@QueryParam("count")``-annotated ``IntParam`` parameter takes the first ``count`` value from + the request's query string and passes it as a ``String`` to ``IntParam``'s constructor. + ``IntParam`` (and all other ``com.yammer.dropwizard.jersey.params.*`` classes) parses the string + as an ``Integer``, returning a ``400 Bad Request`` if the value is malformed. +* A ``@FormParam("name")``-annotated ``Set`` parameter takes all the ``name`` values from a + posted form and passes them to the method as a set of strings. + +What's noteworthy here is that you can actually encapsulate the vast majority of your validation +logic using specialized parameter objects. See ``AbstractParam`` for details. + +.. _man-core-resources-request-entities: + +Request Entities +---------------- + +If you're handling request entities (e.g., an ``application/json`` object on a ``PUT`` request), you +can model this as a parameter without a ``*Param`` annotation. In the +:ref:`example code `, the ``add`` method provides a good example of +this: + +.. code-block:: java + :emphasize-lines: 3 + + @POST + public Response add(@PathParam("user") LongParam userId, + @Valid Notification notification) { + final long id = store.add(userId.get(), notification); + return Response.created(UriBuilder.fromResource(NotificationResource.class) + .build(userId.get(), id) + .build(); + } + +Jersey maps the request entity to any single, unbound parameter. In this case, because the resource +is annotated with ``@Consumes(MediaType.APPLICATION_JSON)``, it uses the Dropwizard-provided Jackson +support which, in addition to parsing the JSON and mapping it to an instance of ``Notification``, +also runs that instance through Dropwizard's :ref:`man-core-representations-validation`. + +If the deserialized ``Notification`` isn't valid, Dropwizard returns a ``422 Unprocessable Entity`` +response to the client. + +.. note:: + + If your request entity parameter isn't annotated with ``@Valid``, it won't be validated. + +.. _man-core-resources-media-types: + +Media Types +----------- + +Jersey also provides full content negotiation, so if your resource class consumes +``application/json`` but the client sends a ``text/plain`` entity, Jersey will automatically reply +with a ``406 Not Acceptable``. Jersey's even smart enough to use client-provided ``q``-values in +their ``Accept`` headers to pick the best response content type based on what both the client and +server will support. + +.. _man-core-resources-responses: + +Responses +--------- + +If your clients are expecting custom headers or additional information (or, if you simply desire an +additional degree of control over your responses), you can return explicitly-built ``Response`` +objects: + +.. code-block:: java + + return Response.noContent().language(Locale.GERMAN).build(); + + +In general, though, we recommend you return actual domain objects if at all possible. It makes +:ref:`testing resources ` much easier. + +.. _man-core-resource-error-handling: + +Error Handling +-------------- + +If your resource class unintentionally throws an exception, Dropwizard will log that exception +(including stack traces) and return a terse, safe ``text/plain`` ``500 Internal Server Error`` +response. + +If your resource class needs to return an error to the client (e.g., the requested record doesn't +exist), you have two options: throw a ``WebApplicationException`` or restructure your method to +return a ``Response``. + +If at all possible, prefer throwing ``WebApplicationException`` instances to returning +``Response`` objects. + +.. _man-core-resources-uris: + +URIs +---- + +While Jersey doesn't quite have first-class support for hyperlink-driven services, the provided +``UriBuilder`` functionality does quite well. + +Rather than duplicate resource URIs, it's possible (and recommended!) to initialize a +``UriBuilder`` with the path from the resource class itself: + +.. code-block:: java + + UriBuilder.fromResource(UserResource.class).build(user.getId()); + +.. _man-core-resources-testing: + +Testing +------- + +As with just about everything in Dropwizard, we recommend you design your resources to be testable. +Dependencies which aren't request-injected should be passed in via the constructor and assigned to +``final`` fields. + +Testing, then, consists of creating an instance of your resource class and passing it a mock. +(Again: Mockito_.) + +.. code-block:: java + + public class NotificationsResourceTest { + private final NotificationStore store = mock(NotificationStore.class); + private final NotificationsResource resource = new NotificationsResource(store); + + @Test + public void getsReturnNotifications() { + final List notifications = mock(List.class); + when(store.fetch(1, 20)).thenReturn(notifications); + + final NotificationList list = resource.fetch(new LongParam("1"), new IntParam("20")); + + assertThat(list.getUserId(), + is(1L)); + + assertThat(list.getNotifications(), + is(notifications)); + } + } + +.. _man-core-resources-oauth2: + +OAuth2 +------ + +Dropwizard provides some super-minimalist support for `Oauth 2`__: + +.. __: http://tools.ietf.org/html/draft-ietf-oauth-v2-22 + +.. code-block:: java + + public Blah doAThing(@BearerToken String token) { + // etc + } + +The Oauth 2 bearer token will be passed in via ``token``. + +.. _man-core-representations: + +Representations +=============== + +Representation classes are classes which, when handled to various Jersey ``MessageBodyReader`` and +``MessageBodyWriter`` providers, become the entities in your service's API. Dropwizard heavily +favors JSON, but it's possible to map from any POJO to custom formats and back. + +.. _man-core-representations-basic: + +Basic JSON +---------- + +Jackson is awesome at converting regular POJOs to JSON and back. This file: + +.. code-block:: java + + public class Notification { + @JsonProperty + private String text; + + public Notification(String text) { + this.text = text; + } + + public String getText() { + return text; + } + + public String setText(String text) { + this.text = text; + } + } + +gets converted into this JSON: + +.. code-block:: javascript + + { + "text": "hey it's the value of the text field" + } + +If, at some point, you need to change the JSON field name or the Java field without affecting the +other, you can add an explicit field name to the ``@JsonProperty`` annotation. + +If you prefer immutable objects rather than JavaBeans, that's also doable: + +.. code-block:: java + + public class Notification { + @JsonProperty + private final String text; + + public Notification(@JsonProperty("text") String text) { + this.text = text; + } + + public String getText() { + return text; + } + } + +.. _man-core-representations-advanced: + +Advanced JSON +------------- + +Not all JSON representations map nicely to the objects your service deals with, so it's sometimes +necessary to use custom serializers and deserializers. Just annotate your object like this: + +.. code-block:: java + + @JsonSerialize(using=FunkySerializer.class) + @JsonDeserialize(using=FunkyDeserializer.class) + public class Funky { + // ... + } + +Then make a ``FunkySerializer`` class which implements ``JsonSerializer`` and a +``FunkyDeserializer`` class which implements ``JsonDeserializer``. + +.. _man-core-representations-advanced-snake-case: + +``snake_case`` +************** + +A common issue with JSON is the disagreement between ``camelCase`` and ``snake_case`` field names. +Java and Javascript folks tend to like ``camelCase``; Ruby, Python, and Perl folks insist on +``snake_case``. To make Dropwizard automatically convert field names to ``snake_case`` (and back), +just annotate the class with ``@JsonSnakeCase``: + +.. code-block:: java + + @JsonSnakeCase + public class Person { + @JsonProperty + private String firstName; + + public Person(String firstName) { + this.firstName = firstName; + } + + public String getFirstName() { + return firstName; + } + } + +This gets converted into this JSON: + +.. code-block:: javascript + + { + "first_name": "Coda" + } + +.. _man-core-representations-validation: + +Validation +---------- + +Like :ref:`man-core-configuration`, you can add validation annotations to fields of your +representation classes and validate them. If we're accepting client-provided ``Person`` objects, we +probably want to ensure that the ``name`` field of the object isn't ``null`` or blank. We can do +this as follows: + +.. code-block:: java + + public class Person { + @NotEmpty // ensure that name isn't null or blank + @JsonProperty + private final String name; + + public Person(@JsonProperty("name") String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + +Then, in our resource class, we can add the ``@Valid`` annotation to the ``Person`` annotation: + +.. code-block:: java + + @PUT + public Response replace(@Valid Person person) { + // ... + } + +If the ``name`` field is missing, Dropwizard will return a ``text/plain`` +``422 Unprocessable Entity`` response detailing the validation errors:: + + * name may not be empty + +.. _man-core-resources-validation-advanced: + +Advanced +******** + +More complex validations (for example, cross-field comparisons) are often hard to do using +declarative annotations. As an emergency maneuver, add the ``@ValidationMethod`` to any +``boolean``-returning method which begins with ``is``: + +.. code-block:: java + + @ValidationMethod(message="may not be Coda") + public boolean isNotCoda() { + return !("Coda".equals(name)); + } + +.. note:: + + Due to the rather daft JavaBeans conventions, the method must begin with ``is`` (e.g., + ``#isValidPortRange()``. This is a limitation of Hibernate Validator, not Dropwizard. + +.. _man-core-representations-streaming: + +Streaming Output +---------------- + +If your service happens to return lots of information, you may get a big performance and efficiency +bump by using streaming output. By returning an object which implements Jersey's ``StreamingOutput`` +interface, your method can stream the response entity in a chunk-encoded output stream. Otherwise, +you'll need to fully construct your return value and *then* hand it off to be sent to the client. + +.. _man-core-representations-testing: + +Testing +------- + +The ``dropwizard-testing`` module contains a number of helper methods for testing JSON parsing and +generating. Given a JSON fixture file (e.g., ``src/test/resources/fixtures/person.json``), you can +test that a ``Person`` instance generates the same JSON as the fixture with the following: + +.. code-block:: java + + import static com.yammer.dropwizard.testing.JsonHelpers.asJson; + import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture; + + @Test + public void producesTheExpectedJson() throws Exception { + assertThat("rendering a person as JSON produces a valid API representation", + asJson(person), + is(jsonFixture("fixtures/person.json"))); + } + +This does a whitespace- and comment-insensitive comparison of the generated JSON and the JSON in the +file. If they're different, both JSON representations are helpfully displayed in the assertion +error. + +Likewise, you can also test the parsing of the same JSON file to guarantee round-trip compatibility: + +.. code-block:: java + + import static com.yammer.dropwizard.testing.JsonHelpers.fromJson; + + @Test + public void consumesTheExpectedJson() throws Exception { + assertThat("parsing a valid API representation produces a person", + fromJson(jsonFixture("fixtures/person.json"), Person.class), + is(person)); + } + + +.. _man-core-representations-custom: + +Custom Representations +---------------------- + +Sometimes, though, you've got some wacky output format you need to produce or consume and no amount +of arguing will make JSON acceptable. That's unfortunate but OK. You can add support for arbitrary +input and output formats by creating classes which implement Jersey's ``MessageBodyReader`` and +``MessageBodyWriter`` interfaces. (Make sure they're annotated with ``@Provider`` and +``@Produces("text/gibberish")`` or ``@Consumes("text/gibberish")``.) Once you're done, just add +instances of them (or their classes if they depend on Jersey's ``@Context`` injection) to your +service's ``Environment`` on initialization. diff --git a/docs/source/manual/db.rst b/docs/source/manual/db.rst new file mode 100644 index 00000000000..d06454e3d87 --- /dev/null +++ b/docs/source/manual/db.rst @@ -0,0 +1,7 @@ +.. _man-db: + +############# +Dropwizard DB +############# + +.. todo:: write DB diff --git a/docs/source/manual/index.rst b/docs/source/manual/index.rst new file mode 100644 index 00000000000..18fea3c42ca --- /dev/null +++ b/docs/source/manual/index.rst @@ -0,0 +1,22 @@ +.. _manual-index: + +########### +User Manual +########### + +.. rubric:: This goal of this document is to provide you with all the information required to build, + organize, test, deploy, and maintain Dropwizard-based services. If you're new to + Dropwizard, you should read the :ref:`getting-started` guide first. + +.. toctree:: + :maxdepth: 1 + + core + client + db + scala + templates + testing + running + production + diff --git a/docs/source/manual/production.rst b/docs/source/manual/production.rst new file mode 100644 index 00000000000..0fdf509aa14 --- /dev/null +++ b/docs/source/manual/production.rst @@ -0,0 +1,7 @@ +.. _manual-production: + +######################## +Dropwizard In Production +######################## + +.. todo:: write Production diff --git a/docs/source/manual/running.rst b/docs/source/manual/running.rst new file mode 100644 index 00000000000..52676872e56 --- /dev/null +++ b/docs/source/manual/running.rst @@ -0,0 +1,7 @@ +.. _manual-running: + +########################### +Running Dropwizard Services +########################### + +.. todo:: write Running diff --git a/docs/source/manual/scala.rst b/docs/source/manual/scala.rst new file mode 100644 index 00000000000..4c71b81ab0a --- /dev/null +++ b/docs/source/manual/scala.rst @@ -0,0 +1,7 @@ +.. _manual-scala: + +################## +Dropwizard & Scala +################## + +.. todo:: write Scala diff --git a/docs/source/manual/templates.rst b/docs/source/manual/templates.rst new file mode 100644 index 00000000000..4613e130dd7 --- /dev/null +++ b/docs/source/manual/templates.rst @@ -0,0 +1,7 @@ +.. _manual-templates: + +#################### +Dropwizard Templates +#################### + +.. todo:: write Templates diff --git a/docs/source/manual/testing.rst b/docs/source/manual/testing.rst new file mode 100644 index 00000000000..984508c906b --- /dev/null +++ b/docs/source/manual/testing.rst @@ -0,0 +1,7 @@ +.. _manual-testing: + +################## +Testing Dropwizard +################## + +.. todo:: write Testing diff --git a/docs/static/css/additional.css b/docs/static/css/additional.css deleted file mode 100644 index 15120762c52..00000000000 --- a/docs/static/css/additional.css +++ /dev/null @@ -1,36 +0,0 @@ -body { - padding-top: 60px; -} - -#blurb { - background-color: #f5f5f5; - margin-bottom: 30px; - padding: 30px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} - -#blurb h1 { - margin-bottom: 0; - font-size: 60px; - line-height: 1; - letter-spacing: -1px; -} - -#blurb p { - font-size: 18px; - font-weight: 200; - line-height: 27px; -} - -pre { - overflow: scroll; - background-color: #f5f5f5; - padding: 9px; - border: 1px solid rgba(0,0,0,.2); - -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.1); - -moz-box-shadow: 0 1px 2px rgba(0,0,0,.1); - box-shadow: 0 1px 2px rgba(0,0,0,.1); -} -pre .c{color:#998;font-style:italic;}pre .err{color:#a61717;background-color:#e3d2d2;}pre .k{font-weight:bold;}pre .o{font-weight:bold;}pre .cm{color:#998;font-style:italic;}pre .cp{color:#999;font-weight:bold;}pre .c1{color:#998;font-style:italic;}pre .cs{color:#999;font-weight:bold;font-style:italic;}pre .gd{color:#000;background-color:#fdd;}pre .gd .x{color:#000;background-color:#faa;}pre .ge{font-style:italic;}pre .gr{color:#a00;}pre .gh{color:#999;}pre .gi{color:#000;background-color:#dfd;}pre .gi .x{color:#000;background-color:#afa;}pre .go{color:#888;}pre .gp{color:#555;}pre .gs{font-weight:bold;}pre .gu{color:#aaa;}pre .gt{color:#a00;}pre .kc{font-weight:bold;}pre .kd{font-weight:bold;}pre .kp{font-weight:bold;}pre .kr{font-weight:bold;}pre .kt{color:#458;font-weight:bold;}pre .m{color:#099;}pre .s{color:#d14;}pre .na{color:#008080;}pre .nb{color:#0086B3;}pre .nc{color:#458;font-weight:bold;}pre .no{color:#008080;}pre .ni{color:#800080;}pre .ne{color:#900;font-weight:bold;}pre .nf{color:#900;font-weight:bold;}pre .nn{color:#555;}pre .nt{color:#000080;}pre .nv{color:#008080;}pre .ow{font-weight:bold;}pre .w{color:#bbb;}pre .mf{color:#099;}pre .mh{color:#099;}pre .mi{color:#099;}pre .mo{color:#099;}pre .sb{color:#d14;}pre .sc{color:#d14;}pre .sd{color:#d14;}pre .s2{color:#d14;}pre .se{color:#d14;}pre .sh{color:#d14;}pre .si{color:#d14;}pre .sx{color:#d14;}pre .sr{color:#009926;}pre .s1{color:#d14;}pre .ss{color:#990073;}pre .bp{color:#999;}pre .vc{color:#008080;}pre .vg{color:#008080;}pre .vi{color:#008080;}pre .il{color:#099;} \ No newline at end of file diff --git a/docs/static/css/bootstrap.min.css b/docs/static/css/bootstrap.min.css deleted file mode 100644 index e2f7c4ae358..00000000000 --- a/docs/static/css/bootstrap.min.css +++ /dev/null @@ -1,356 +0,0 @@ -html,body{margin:0;padding:0;} -h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,cite,code,del,dfn,em,img,q,s,samp,small,strike,strong,sub,sup,tt,var,dd,dl,dt,li,ol,ul,fieldset,form,label,legend,button,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;font-weight:normal;font-style:normal;font-size:100%;line-height:1;font-family:inherit;} -table{border-collapse:collapse;border-spacing:0;} -ol,ul{list-style:none;} -q:before,q:after,blockquote:before,blockquote:after{content:"";} -html{overflow-y:scroll;font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} -a:focus{outline:thin dotted;} -a:hover,a:active{outline:0;} -article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} -audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} -audio:not([controls]){display:none;} -sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;} -sup{top:-0.5em;} -sub{bottom:-0.25em;} -img{border:0;-ms-interpolation-mode:bicubic;} -button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;} -button,input{line-height:normal;*overflow:visible;} -button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;} -button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} -input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;} -input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;} -textarea{overflow:auto;vertical-align:top;} -body{background-color:#ffffff;margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;color:#404040;} -.container{width:940px;margin-left:auto;margin-right:auto;zoom:1;}.container:before,.container:after{display:table;content:"";zoom:1;} -.container:after{clear:both;} -.container-fluid{position:relative;min-width:940px;padding-left:20px;padding-right:20px;zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";zoom:1;} -.container-fluid:after{clear:both;} -.container-fluid>.sidebar{position:absolute;top:0;left:20px;width:220px;} -.container-fluid>.content{margin-left:240px;} -a{color:#0069d6;text-decoration:none;line-height:inherit;font-weight:inherit;}a:hover{color:#00438a;text-decoration:underline;} -.pull-right{float:right;} -.pull-left{float:left;} -.hide{display:none;} -.show{display:block;} -.row{zoom:1;margin-left:-20px;}.row:before,.row:after{display:table;content:"";zoom:1;} -.row:after{clear:both;} -.row>[class*="span"]{display:inline;float:left;margin-left:20px;} -.span1{width:40px;} -.span2{width:100px;} -.span3{width:160px;} -.span4{width:220px;} -.span5{width:280px;} -.span6{width:340px;} -.span7{width:400px;} -.span8{width:460px;} -.span9{width:520px;} -.span10{width:580px;} -.span11{width:640px;} -.span12{width:700px;} -.span13{width:760px;} -.span14{width:820px;} -.span15{width:880px;} -.span16{width:940px;} -.span17{width:1000px;} -.span18{width:1060px;} -.span19{width:1120px;} -.span20{width:1180px;} -.span21{width:1240px;} -.span22{width:1300px;} -.span23{width:1360px;} -.span24{width:1420px;} -.row>.offset1{margin-left:80px;} -.row>.offset2{margin-left:140px;} -.row>.offset3{margin-left:200px;} -.row>.offset4{margin-left:260px;} -.row>.offset5{margin-left:320px;} -.row>.offset6{margin-left:380px;} -.row>.offset7{margin-left:440px;} -.row>.offset8{margin-left:500px;} -.row>.offset9{margin-left:560px;} -.row>.offset10{margin-left:620px;} -.row>.offset11{margin-left:680px;} -.row>.offset12{margin-left:740px;} -.span-one-third{width:300px;} -.span-two-thirds{width:620px;} -.row>.offset-one-third{margin-left:340px;} -.row>.offset-two-thirds{margin-left:660px;} -p{font-size:13px;font-weight:normal;line-height:18px;margin-bottom:9px;}p small{font-size:11px;color:#bfbfbf;} -h1,h2,h3,h4,h5,h6{font-weight:bold;color:#404040;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{color:#bfbfbf;} -h1{margin-bottom:18px;font-size:30px;line-height:36px;}h1 small{font-size:18px;} -h2{font-size:24px;line-height:36px;}h2 small{font-size:14px;} -h3,h4,h5,h6{line-height:36px;} -h3{font-size:18px;}h3 small{font-size:14px;} -h4{font-size:16px;}h4 small{font-size:12px;} -h5{font-size:14px;} -h6{font-size:13px;color:#bfbfbf;text-transform:uppercase;} -ul,ol{margin:0 0 18px 25px;} -ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} -ul{list-style:disc;} -ol{list-style:decimal;} -li{line-height:18px;color:#808080;} -ul.unstyled{list-style:none;margin-left:0;} -dl{margin-bottom:18px;}dl dt,dl dd{line-height:18px;} -dl dt{font-weight:bold;} -dl dd{margin-left:9px;} -hr{margin:20px 0 19px;border:0;border-bottom:1px solid #eee;} -strong{font-style:inherit;font-weight:bold;} -em{font-style:italic;font-weight:inherit;line-height:inherit;} -.muted{color:#bfbfbf;} -blockquote{margin-bottom:18px;border-left:5px solid #eee;padding-left:15px;}blockquote p{font-size:14px;font-weight:300;line-height:18px;margin-bottom:0;} -blockquote small{display:block;font-size:12px;font-weight:300;line-height:18px;color:#bfbfbf;}blockquote small:before{content:'\2014 \00A0';} -address{display:block;line-height:18px;margin-bottom:18px;} -code,pre{padding:0 3px 2px;font-family:Monaco, Andale Mono, Courier New, monospace;font-size:12px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} -code{background-color:#fee9cc;color:rgba(0, 0, 0, 0.75);padding:1px 3px;} -pre{background-color:#f5f5f5;display:block;padding:8.5px;margin:0 0 18px;line-height:18px;font-size:12px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} -form{margin-bottom:18px;} -fieldset{margin-bottom:18px;padding-top:18px;}fieldset legend{display:block;padding-left:150px;font-size:19.5px;line-height:1;color:#404040;*padding:0 0 5px 145px;*line-height:1.5;} -form .clearfix{margin-bottom:18px;zoom:1;}form .clearfix:before,form .clearfix:after{display:table;content:"";zoom:1;} -form .clearfix:after{clear:both;} -label,input,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:normal;} -label{padding-top:6px;font-size:13px;line-height:18px;float:left;width:130px;text-align:right;color:#404040;} -form .input{margin-left:150px;} -input[type=checkbox],input[type=radio]{cursor:pointer;} -input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;font-size:13px;line-height:18px;color:#808080;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} -select{padding:initial;} -input[type=checkbox],input[type=radio]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:none;} -input[type=file]{background-color:#ffffff;padding:initial;border:initial;line-height:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} -input[type=button],input[type=reset],input[type=submit]{width:auto;height:auto;} -select,input[type=file]{height:27px;*height:auto;line-height:27px;*margin-top:4px;} -select[multiple]{height:inherit;background-color:#ffffff;} -textarea{height:auto;} -.uneditable-input{background-color:#ffffff;display:block;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} -:-moz-placeholder{color:#bfbfbf;} -::-webkit-input-placeholder{color:#bfbfbf;} -input,textarea{-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);} -input:focus,textarea:focus{outline:0;border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);} -input[type=file]:focus,input[type=checkbox]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:1px dotted #666;} -form .clearfix.error>label,form .clearfix.error .help-block,form .clearfix.error .help-inline{color:#b94a48;} -form .clearfix.error input,form .clearfix.error textarea{color:#b94a48;border-color:#ee5f5b;}form .clearfix.error input:focus,form .clearfix.error textarea:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} -form .clearfix.error .input-prepend .add-on,form .clearfix.error .input-append .add-on{color:#b94a48;background-color:#fce6e6;border-color:#b94a48;} -form .clearfix.warning>label,form .clearfix.warning .help-block,form .clearfix.warning .help-inline{color:#c09853;} -form .clearfix.warning input,form .clearfix.warning textarea{color:#c09853;border-color:#ccae64;}form .clearfix.warning input:focus,form .clearfix.warning textarea:focus{border-color:#be9a3f;-webkit-box-shadow:0 0 6px #e5d6b1;-moz-box-shadow:0 0 6px #e5d6b1;box-shadow:0 0 6px #e5d6b1;} -form .clearfix.warning .input-prepend .add-on,form .clearfix.warning .input-append .add-on{color:#c09853;background-color:#d2b877;border-color:#c09853;} -form .clearfix.success>label,form .clearfix.success .help-block,form .clearfix.success .help-inline{color:#468847;} -form .clearfix.success input,form .clearfix.success textarea{color:#468847;border-color:#57a957;}form .clearfix.success input:focus,form .clearfix.success textarea:focus{border-color:#458845;-webkit-box-shadow:0 0 6px #9acc9a;-moz-box-shadow:0 0 6px #9acc9a;box-shadow:0 0 6px #9acc9a;} -form .clearfix.success .input-prepend .add-on,form .clearfix.success .input-append .add-on{color:#468847;background-color:#bcddbc;border-color:#468847;} -.input-mini,input.mini,textarea.mini,select.mini{width:60px;} -.input-small,input.small,textarea.small,select.small{width:90px;} -.input-medium,input.medium,textarea.medium,select.medium{width:150px;} -.input-large,input.large,textarea.large,select.large{width:210px;} -.input-xlarge,input.xlarge,textarea.xlarge,select.xlarge{width:270px;} -.input-xxlarge,input.xxlarge,textarea.xxlarge,select.xxlarge{width:530px;} -textarea.xxlarge{overflow-y:auto;} -input.span1,textarea.span1{display:inline-block;float:none;width:30px;margin-left:0;} -input.span2,textarea.span2{display:inline-block;float:none;width:90px;margin-left:0;} -input.span3,textarea.span3{display:inline-block;float:none;width:150px;margin-left:0;} -input.span4,textarea.span4{display:inline-block;float:none;width:210px;margin-left:0;} -input.span5,textarea.span5{display:inline-block;float:none;width:270px;margin-left:0;} -input.span6,textarea.span6{display:inline-block;float:none;width:330px;margin-left:0;} -input.span7,textarea.span7{display:inline-block;float:none;width:390px;margin-left:0;} -input.span8,textarea.span8{display:inline-block;float:none;width:450px;margin-left:0;} -input.span9,textarea.span9{display:inline-block;float:none;width:510px;margin-left:0;} -input.span10,textarea.span10{display:inline-block;float:none;width:570px;margin-left:0;} -input.span11,textarea.span11{display:inline-block;float:none;width:630px;margin-left:0;} -input.span12,textarea.span12{display:inline-block;float:none;width:690px;margin-left:0;} -input.span13,textarea.span13{display:inline-block;float:none;width:750px;margin-left:0;} -input.span14,textarea.span14{display:inline-block;float:none;width:810px;margin-left:0;} -input.span15,textarea.span15{display:inline-block;float:none;width:870px;margin-left:0;} -input.span16,textarea.span16{display:inline-block;float:none;width:930px;margin-left:0;} -input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;} -.actions{background:#f5f5f5;margin-top:18px;margin-bottom:18px;padding:17px 20px 18px 150px;border-top:1px solid #ddd;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;}.actions .secondary-action{float:right;}.actions .secondary-action a{line-height:30px;}.actions .secondary-action a:hover{text-decoration:underline;} -.help-inline,.help-block{font-size:13px;line-height:18px;color:#bfbfbf;} -.help-inline{padding-left:5px;*position:relative;*top:-5px;} -.help-block{display:block;max-width:600px;} -.inline-inputs{color:#808080;}.inline-inputs span{padding:0 2px 0 1px;} -.input-prepend input,.input-append input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} -.input-prepend .add-on,.input-append .add-on{position:relative;background:#f5f5f5;border:1px solid #ccc;z-index:2;float:left;display:block;width:auto;min-width:16px;height:18px;padding:4px 4px 4px 5px;margin-right:-1px;font-weight:normal;line-height:18px;color:#bfbfbf;text-align:center;text-shadow:0 1px 0 #ffffff;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} -.input-prepend .active,.input-append .active{background:#a9dba9;border-color:#46a546;} -.input-prepend .add-on{*margin-top:1px;} -.input-append input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} -.input-append .add-on{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;margin-right:0;margin-left:-1px;} -.inputs-list{margin:0 0 5px;width:100%;}.inputs-list li{display:block;padding:0;width:100%;} -.inputs-list label{display:block;float:none;width:auto;padding:0;margin-left:20px;line-height:18px;text-align:left;white-space:normal;}.inputs-list label strong{color:#808080;} -.inputs-list label small{font-size:11px;font-weight:normal;} -.inputs-list .inputs-list{margin-left:25px;margin-bottom:10px;padding-top:0;} -.inputs-list:first-child{padding-top:6px;} -.inputs-list li+li{padding-top:2px;} -.inputs-list input[type=radio],.inputs-list input[type=checkbox]{margin-bottom:0;margin-left:-20px;float:left;} -.form-stacked{padding-left:20px;}.form-stacked fieldset{padding-top:9px;} -.form-stacked legend{padding-left:0;} -.form-stacked label{display:block;float:none;width:auto;font-weight:bold;text-align:left;line-height:20px;padding-top:0;} -.form-stacked .clearfix{margin-bottom:9px;}.form-stacked .clearfix div.input{margin-left:0;} -.form-stacked .inputs-list{margin-bottom:0;}.form-stacked .inputs-list li{padding-top:0;}.form-stacked .inputs-list li label{font-weight:normal;padding-top:0;} -.form-stacked div.clearfix.error{padding-top:10px;padding-bottom:10px;padding-left:10px;margin-top:0;margin-left:-10px;} -.form-stacked .actions{margin-left:-20px;padding-left:20px;} -table{width:100%;margin-bottom:18px;padding:0;font-size:13px;border-collapse:collapse;}table th,table td{padding:10px 10px 9px;line-height:18px;text-align:left;} -table th{padding-top:9px;font-weight:bold;vertical-align:middle;} -table td{vertical-align:top;border-top:1px solid #ddd;} -table tbody th{border-top:1px solid #ddd;vertical-align:top;} -.condensed-table th,.condensed-table td{padding:5px 5px 4px;} -.bordered-table{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.bordered-table th+th,.bordered-table td+td,.bordered-table th+td{border-left:1px solid #ddd;} -.bordered-table thead tr:first-child th:first-child,.bordered-table tbody tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;} -.bordered-table thead tr:first-child th:last-child,.bordered-table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;} -.bordered-table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;} -.bordered-table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;} -table .span1{width:20px;} -table .span2{width:60px;} -table .span3{width:100px;} -table .span4{width:140px;} -table .span5{width:180px;} -table .span6{width:220px;} -table .span7{width:260px;} -table .span8{width:300px;} -table .span9{width:340px;} -table .span10{width:380px;} -table .span11{width:420px;} -table .span12{width:460px;} -table .span13{width:500px;} -table .span14{width:540px;} -table .span15{width:580px;} -table .span16{width:620px;} -.zebra-striped tbody tr:nth-child(odd) td,.zebra-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} -.zebra-striped tbody tr:hover td,.zebra-striped tbody tr:hover th{background-color:#f5f5f5;} -table .header{cursor:pointer;}table .header:after{content:"";float:right;margin-top:7px;border-width:0 4px 4px;border-style:solid;border-color:#000 transparent;visibility:hidden;} -table .headerSortUp,table .headerSortDown{background-color:rgba(141, 192, 219, 0.25);text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);} -table .header:hover:after{visibility:visible;} -table .headerSortDown:after,table .headerSortDown:hover:after{visibility:visible;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;} -table .headerSortUp:after{border-bottom:none;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000;visibility:visible;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;} -table .blue{color:#049cdb;border-bottom-color:#049cdb;} -table .headerSortUp.blue,table .headerSortDown.blue{background-color:#ade6fe;} -table .green{color:#46a546;border-bottom-color:#46a546;} -table .headerSortUp.green,table .headerSortDown.green{background-color:#cdeacd;} -table .red{color:#9d261d;border-bottom-color:#9d261d;} -table .headerSortUp.red,table .headerSortDown.red{background-color:#f4c8c5;} -table .yellow{color:#ffc40d;border-bottom-color:#ffc40d;} -table .headerSortUp.yellow,table .headerSortDown.yellow{background-color:#fff6d9;} -table .orange{color:#f89406;border-bottom-color:#f89406;} -table .headerSortUp.orange,table .headerSortDown.orange{background-color:#fee9cc;} -table .purple{color:#7a43b6;border-bottom-color:#7a43b6;} -table .headerSortUp.purple,table .headerSortDown.purple{background-color:#e2d5f0;} -.topbar{height:40px;position:fixed;top:0;left:0;right:0;z-index:10000;overflow:visible;}.topbar a{color:#bfbfbf;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} -.topbar h3 a:hover,.topbar .brand:hover,.topbar ul .active>a{background-color:#333;background-color:rgba(255, 255, 255, 0.05);color:#ffffff;text-decoration:none;} -.topbar h3{position:relative;} -.topbar h3 a,.topbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;color:#ffffff;font-size:20px;font-weight:200;line-height:1;} -.topbar p{margin:0;line-height:40px;}.topbar p a:hover{background-color:transparent;color:#ffffff;} -.topbar form{float:left;margin:5px 0 0 0;position:relative;filter:alpha(opacity=100);-khtml-opacity:1;-moz-opacity:1;opacity:1;} -.topbar form.pull-right{float:right;} -.topbar input{background-color:#444;background-color:rgba(255, 255, 255, 0.3);font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:normal;font-weight:13px;line-height:1;padding:4px 9px;color:#ffffff;color:rgba(255, 255, 255, 0.75);border:1px solid #111;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.topbar input:-moz-placeholder{color:#e6e6e6;} -.topbar input::-webkit-input-placeholder{color:#e6e6e6;} -.topbar input:hover{background-color:#bfbfbf;background-color:rgba(255, 255, 255, 0.5);color:#ffffff;} -.topbar input:focus,.topbar input.focused{outline:0;background-color:#ffffff;color:#404040;text-shadow:0 1px 0 #ffffff;border:0;padding:5px 10px;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);} -.topbar-inner,.topbar .fill{background-color:#222;background-color:#222222;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#333333), to(#222222));background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #333333), color-stop(100%, #222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);} -.topbar div>ul,.nav{display:block;float:left;margin:0 10px 0 0;position:relative;left:0;}.topbar div>ul>li,.nav>li{display:block;float:left;} -.topbar div>ul a,.nav a{display:block;float:none;padding:10px 10px 11px;line-height:19px;text-decoration:none;}.topbar div>ul a:hover,.nav a:hover{color:#ffffff;text-decoration:none;} -.topbar div>ul .active>a,.nav .active>a{background-color:#222;background-color:rgba(0, 0, 0, 0.5);} -.topbar div>ul.secondary-nav,.nav.secondary-nav{float:right;margin-left:10px;margin-right:0;}.topbar div>ul.secondary-nav .menu-dropdown,.nav.secondary-nav .menu-dropdown,.topbar div>ul.secondary-nav .dropdown-menu,.nav.secondary-nav .dropdown-menu{right:0;border:0;} -.topbar div>ul a.menu:hover,.nav a.menu:hover,.topbar div>ul li.open .menu,.nav li.open .menu,.topbar div>ul .dropdown-toggle:hover,.nav .dropdown-toggle:hover,.topbar div>ul .dropdown.open .dropdown-toggle,.nav .dropdown.open .dropdown-toggle{background:#444;background:rgba(255, 255, 255, 0.05);} -.topbar div>ul .menu-dropdown,.nav .menu-dropdown,.topbar div>ul .dropdown-menu,.nav .dropdown-menu{background-color:#333;}.topbar div>ul .menu-dropdown a.menu,.nav .menu-dropdown a.menu,.topbar div>ul .dropdown-menu a.menu,.nav .dropdown-menu a.menu,.topbar div>ul .menu-dropdown .dropdown-toggle,.nav .menu-dropdown .dropdown-toggle,.topbar div>ul .dropdown-menu .dropdown-toggle,.nav .dropdown-menu .dropdown-toggle{color:#ffffff;}.topbar div>ul .menu-dropdown a.menu.open,.nav .menu-dropdown a.menu.open,.topbar div>ul .dropdown-menu a.menu.open,.nav .dropdown-menu a.menu.open,.topbar div>ul .menu-dropdown .dropdown-toggle.open,.nav .menu-dropdown .dropdown-toggle.open,.topbar div>ul .dropdown-menu .dropdown-toggle.open,.nav .dropdown-menu .dropdown-toggle.open{background:#444;background:rgba(255, 255, 255, 0.05);} -.topbar div>ul .menu-dropdown li a,.nav .menu-dropdown li a,.topbar div>ul .dropdown-menu li a,.nav .dropdown-menu li a{color:#999;text-shadow:0 1px 0 rgba(0, 0, 0, 0.5);}.topbar div>ul .menu-dropdown li a:hover,.nav .menu-dropdown li a:hover,.topbar div>ul .dropdown-menu li a:hover,.nav .dropdown-menu li a:hover{background-color:#191919;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#292929), to(#191919));background-image:-moz-linear-gradient(top, #292929, #191919);background-image:-ms-linear-gradient(top, #292929, #191919);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #292929), color-stop(100%, #191919));background-image:-webkit-linear-gradient(top, #292929, #191919);background-image:-o-linear-gradient(top, #292929, #191919);background-image:linear-gradient(top, #292929, #191919);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#292929', endColorstr='#191919', GradientType=0);color:#ffffff;} -.topbar div>ul .menu-dropdown .active a,.nav .menu-dropdown .active a,.topbar div>ul .dropdown-menu .active a,.nav .dropdown-menu .active a{color:#ffffff;} -.topbar div>ul .menu-dropdown .divider,.nav .menu-dropdown .divider,.topbar div>ul .dropdown-menu .divider,.nav .dropdown-menu .divider{background-color:#222;border-color:#444;} -.topbar ul .menu-dropdown li a,.topbar ul .dropdown-menu li a{padding:4px 15px;} -li.menu,.dropdown{position:relative;} -a.menu:after,.dropdown-toggle:after{width:0;height:0;display:inline-block;content:"↓";text-indent:-99999px;vertical-align:top;margin-top:8px;margin-left:4px;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #ffffff;filter:alpha(opacity=50);-khtml-opacity:0.5;-moz-opacity:0.5;opacity:0.5;} -.menu-dropdown,.dropdown-menu{background-color:#ffffff;float:left;display:none;position:absolute;top:40px;z-index:900;min-width:160px;max-width:220px;_width:160px;margin-left:0;margin-right:0;padding:6px 0;zoom:1;border-color:#999;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:0 1px 1px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.menu-dropdown li,.dropdown-menu li{float:none;display:block;background-color:none;} -.menu-dropdown .divider,.dropdown-menu .divider{height:1px;margin:5px 0;overflow:hidden;background-color:#eee;border-bottom:1px solid #ffffff;} -.topbar .dropdown-menu a,.dropdown-menu a{display:block;padding:4px 15px;clear:both;font-weight:normal;line-height:18px;color:#808080;text-shadow:0 1px 0 #ffffff;}.topbar .dropdown-menu a:hover,.dropdown-menu a:hover,.topbar .dropdown-menu a.hover,.dropdown-menu a.hover{background-color:#dddddd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#eeeeee), to(#dddddd));background-image:-moz-linear-gradient(top, #eeeeee, #dddddd);background-image:-ms-linear-gradient(top, #eeeeee, #dddddd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #eeeeee), color-stop(100%, #dddddd));background-image:-webkit-linear-gradient(top, #eeeeee, #dddddd);background-image:-o-linear-gradient(top, #eeeeee, #dddddd);background-image:linear-gradient(top, #eeeeee, #dddddd);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#dddddd', GradientType=0);color:#404040;text-decoration:none;-webkit-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);} -.open .menu,.dropdown.open .menu,.open .dropdown-toggle,.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);} -.open .menu-dropdown,.dropdown.open .menu-dropdown,.open .dropdown-menu,.dropdown.open .dropdown-menu{display:block;} -.tabs,.pills{margin:0 0 18px;padding:0;list-style:none;zoom:1;}.tabs:before,.pills:before,.tabs:after,.pills:after{display:table;content:"";zoom:1;} -.tabs:after,.pills:after{clear:both;} -.tabs>li,.pills>li{float:left;}.tabs>li>a,.pills>li>a{display:block;} -.tabs{border-color:#ddd;border-style:solid;border-width:0 0 1px;}.tabs>li{position:relative;margin-bottom:-1px;}.tabs>li>a{padding:0 15px;margin-right:2px;line-height:34px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.tabs>li>a:hover{text-decoration:none;background-color:#eee;border-color:#eee #eee #ddd;} -.tabs .active>a,.tabs .active>a:hover{color:#808080;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} -.tabs .menu-dropdown,.tabs .dropdown-menu{top:35px;border-width:1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;} -.tabs a.menu:after,.tabs .dropdown-toggle:after{border-top-color:#999;margin-top:15px;margin-left:5px;} -.tabs li.open.menu .menu,.tabs .open.dropdown .dropdown-toggle{border-color:#999;} -.tabs li.open a.menu:after,.tabs .dropdown.open .dropdown-toggle:after{border-top-color:#555;} -.pills a{margin:5px 3px 5px 0;padding:0 15px;line-height:30px;text-shadow:0 1px 1px #ffffff;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}.pills a:hover{color:#ffffff;text-decoration:none;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#00438a;} -.pills .active a{color:#ffffff;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#0069d6;} -.pills-vertical>li{float:none;} -.tab-content>.tab-pane,.pill-content>.pill-pane,.tab-content>div,.pill-content>div{display:none;} -.tab-content>.active,.pill-content>.active{display:block;} -.breadcrumb{padding:7px 14px;margin:0 0 18px;background-color:#f5f5f5;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ffffff), to(#f5f5f5));background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline;text-shadow:0 1px 0 #ffffff;} -.breadcrumb .divider{padding:0 5px;color:#bfbfbf;} -.breadcrumb .active a{color:#404040;} -.hero-unit{background-color:#f5f5f5;margin-bottom:30px;padding:60px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;} -.hero-unit p{font-size:18px;font-weight:200;line-height:27px;} -footer{margin-top:17px;padding-top:17px;border-top:1px solid #eee;} -.page-header{margin-bottom:17px;border-bottom:1px solid #ddd;-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}.page-header h1{margin-bottom:8px;} -.btn.danger,.alert-message.danger,.btn.danger:hover,.alert-message.danger:hover,.btn.error,.alert-message.error,.btn.error:hover,.alert-message.error:hover,.btn.success,.alert-message.success,.btn.success:hover,.alert-message.success:hover,.btn.info,.alert-message.info,.btn.info:hover,.alert-message.info:hover{color:#ffffff;} -.btn .close,.alert-message .close{font-family:Arial,sans-serif;line-height:18px;} -.btn.danger,.alert-message.danger,.btn.error,.alert-message.error{background-color:#c43c35;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#c43c35 #c43c35 #882a25;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} -.btn.success,.alert-message.success{background-color:#57a957;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#57a957 #57a957 #3d773d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} -.btn.info,.alert-message.info{background-color:#339bb9;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#339bb9 #339bb9 #22697d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} -.btn{cursor:pointer;display:inline-block;background-color:#e6e6e6;background-repeat:no-repeat;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);padding:5px 14px 6px;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);color:#333;font-size:13px;line-height:normal;border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-webkit-transition:0.1s linear all;-moz-transition:0.1s linear all;-ms-transition:0.1s linear all;-o-transition:0.1s linear all;transition:0.1s linear all;}.btn:hover{background-position:0 -15px;color:#333;text-decoration:none;} -.btn:focus{outline:1px dotted #666;} -.btn.primary{color:#ffffff;background-color:#0064cd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd));background-image:-moz-linear-gradient(top, #049cdb, #0064cd);background-image:-ms-linear-gradient(top, #049cdb, #0064cd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd));background-image:-webkit-linear-gradient(top, #049cdb, #0064cd);background-image:-o-linear-gradient(top, #049cdb, #0064cd);background-image:linear-gradient(top, #049cdb, #0064cd);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#0064cd #0064cd #003f81;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} -.btn.active,.btn:active{-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);} -.btn.disabled{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} -.btn[disabled]{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} -.btn.large{font-size:15px;line-height:normal;padding:9px 14px 9px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} -.btn.small{padding:7px 9px 7px;font-size:11px;} -:root .alert-message,:root .btn{border-radius:0 \0;} -button.btn::-moz-focus-inner,input[type=submit].btn::-moz-focus-inner{padding:0;border:0;} -.close{float:right;color:#000000;font-size:20px;font-weight:bold;line-height:13.5px;text-shadow:0 1px 0 #ffffff;filter:alpha(opacity=25);-khtml-opacity:0.25;-moz-opacity:0.25;opacity:0.25;}.close:hover{color:#000000;text-decoration:none;filter:alpha(opacity=40);-khtml-opacity:0.4;-moz-opacity:0.4;opacity:0.4;} -.alert-message{position:relative;padding:7px 15px;margin-bottom:18px;color:#404040;background-color:#eedc94;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94));background-image:-moz-linear-gradient(top, #fceec1, #eedc94);background-image:-ms-linear-gradient(top, #fceec1, #eedc94);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94));background-image:-webkit-linear-gradient(top, #fceec1, #eedc94);background-image:-o-linear-gradient(top, #fceec1, #eedc94);background-image:linear-gradient(top, #fceec1, #eedc94);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#eedc94 #eedc94 #e4c652;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);border-width:1px;border-style:solid;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);}.alert-message .close{margin-top:1px;*margin-top:0;} -.alert-message a{font-weight:bold;color:#404040;} -.alert-message.danger p a,.alert-message.error p a,.alert-message.success p a,.alert-message.info p a{color:#ffffff;} -.alert-message h5{line-height:18px;} -.alert-message p{margin-bottom:0;} -.alert-message div{margin-top:5px;margin-bottom:2px;line-height:28px;} -.alert-message .btn{-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);} -.alert-message.block-message{background-image:none;background-color:#fdf5d9;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);padding:14px;border-color:#fceec1;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}.alert-message.block-message ul,.alert-message.block-message p{margin-right:30px;} -.alert-message.block-message ul{margin-bottom:0;} -.alert-message.block-message li{color:#404040;} -.alert-message.block-message .alert-actions{margin-top:5px;} -.alert-message.block-message.error,.alert-message.block-message.success,.alert-message.block-message.info{color:#404040;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} -.alert-message.block-message.error{background-color:#fddfde;border-color:#fbc7c6;} -.alert-message.block-message.success{background-color:#d1eed1;border-color:#bfe7bf;} -.alert-message.block-message.info{background-color:#ddf4fb;border-color:#c6edf9;} -.alert-message.block-message.danger p a,.alert-message.block-message.error p a,.alert-message.block-message.success p a,.alert-message.block-message.info p a{color:#404040;} -.pagination{height:36px;margin:18px 0;}.pagination ul{float:left;margin:0;border:1px solid #ddd;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} -.pagination li{display:inline;} -.pagination a{float:left;padding:0 14px;line-height:34px;border-right:1px solid;border-right-color:#ddd;border-right-color:rgba(0, 0, 0, 0.15);*border-right-color:#ddd;text-decoration:none;} -.pagination a:hover,.pagination .active a{background-color:#c7eefe;} -.pagination .disabled a,.pagination .disabled a:hover{background-color:transparent;color:#bfbfbf;} -.pagination .next a{border:0;} -.well{background-color:#f5f5f5;margin-bottom:20px;padding:19px;min-height:20px;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} -.modal-backdrop{background-color:#000000;position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000;}.modal-backdrop.fade{opacity:0;} -.modal-backdrop,.modal-backdrop.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;} -.modal{position:fixed;top:50%;left:50%;z-index:11000;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal .close{margin-top:7px;} -.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} -.modal.fade.in{top:50%;} -.modal-header{border-bottom:1px solid #eee;padding:5px 15px;} -.modal-body{padding:15px;} -.modal-body form{margin-bottom:0;} -.modal-footer{background-color:#f5f5f5;padding:14px 15px 15px;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;zoom:1;margin-bottom:0;}.modal-footer:before,.modal-footer:after{display:table;content:"";zoom:1;} -.modal-footer:after{clear:both;} -.modal-footer .btn{float:right;margin-left:5px;} -.modal .popover,.modal .twipsy{z-index:12000;} -.twipsy{display:block;position:absolute;visibility:visible;padding:5px;font-size:11px;z-index:1000;filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;}.twipsy.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;} -.twipsy.above .twipsy-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} -.twipsy.left .twipsy-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} -.twipsy.below .twipsy-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} -.twipsy.right .twipsy-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} -.twipsy-inner{padding:3px 8px;background-color:#000000;color:white;text-align:center;max-width:200px;text-decoration:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} -.twipsy-arrow{position:absolute;width:0;height:0;} -.popover{position:absolute;top:0;left:0;z-index:1000;padding:5px;display:none;}.popover.above .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} -.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} -.popover.below .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} -.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} -.popover .arrow{position:absolute;width:0;height:0;} -.popover .inner{background:#000000;background:rgba(0, 0, 0, 0.8);padding:3px;overflow:hidden;width:280px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);} -.popover .title{background-color:#f5f5f5;padding:9px 15px;line-height:1;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;border-bottom:1px solid #eee;} -.popover .content{background-color:#ffffff;padding:14px;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover .content p,.popover .content ul,.popover .content ol{margin-bottom:0;} -.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;} -.label{padding:1px 3px 2px;font-size:9.75px;font-weight:bold;color:#ffffff;text-transform:uppercase;white-space:nowrap;background-color:#bfbfbf;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}.label.important{background-color:#c43c35;} -.label.warning{background-color:#f89406;} -.label.success{background-color:#46a546;} -.label.notice{background-color:#62cffc;} -.media-grid{margin-left:-20px;margin-bottom:0;zoom:1;}.media-grid:before,.media-grid:after{display:table;content:"";zoom:1;} -.media-grid:after{clear:both;} -.media-grid li{display:inline;} -.media-grid a{float:left;padding:4px;margin:0 0 18px 20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);}.media-grid a img{display:block;} -.media-grid a:hover{border-color:#0069d6;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} diff --git a/docs/static/images/dropwizard-hat-small.png b/docs/static/images/dropwizard-hat-small.png deleted file mode 100644 index a62158fd628ef4c9bbdd5c23a0a4dfbd73b394e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10925 zcmeHtcTm&W*FH!!^j-uEp$Y*)6+-V_dJ7#AdJUl$Dbjn9B8bvNy7b;fX$nY{CL&0Y zUPM6Phq}Ap-T8g@o!Oc9{ckgq+}zJO&vVXw?zty(XA-S>PmusX3qV6dBT!b7)4m>6 zuiyT-*w>$80)dLx0}V>v5T)a4gYvdSBG9Dau2u-3va_WvLK|TT_jMmYh+Ttu?R5=N zhU#iiYgcD(%O5`6KF)5}=xZ8DA2&;DM+6FJg|M}E5eMzIc7lNRaB+}-YR&}#x`1j-WVNAwB^xkPiY8=7HSh;fHYX3PT}+Pyt@x zZ!eGp04Rop+d#GD6n+bLJrf7np-^s69v*LRZ*FgXZdar&53h)b2oHphhmViz+Jno( z*9B$i!{y?^^n>CThaAGg8fou_vUha>{@}Ep!^NJdsX6nc>zv z2q%Oy!Ug5Q!^_Rf^Jo8SCA95r?NA#oYJjlPL0O`H zF6=iE{s;<{_C(paB0V%+J?wwTb#4ElB2Wx&4gIy2pVMEmN;{!`&3;Xt?0;wpb+UA^ z6$kln!4Wo=o=zwb&u<8xAIkp@5##wQ;SYXmB*GHqiu_Xm9fbQ|1N?>Sck55CKZAde zq3lskh(A&N9{9J4_?uiMG?Df$D6yZZI@$ki;{PER`;V-89@hs@7lCy4_{U-YvaH`T z7329^Zm~aaG*tGNZnCb|g>Q{gcCm5&S=WE{v6qG;<$X|=aOCfG|Nq-%?NPpeZ`HnT z6+a8&Z`d`hUE$Yt`Kx083pon;cjUSVCj(dHb<_B-Sb1kl`~S(Vhy308Q^sGL_oowo zy&J!tU3Ze}CdTte7yGqMzxA8{v*D*&|7YyK5&s+HA1VB=T>r}Tj}-Vv&i_`|zjFN} z1^$uqzt#1>CKup8_aKDJ_2tL=`j+#?_JR%#jh<9lPFmMzcFWX0iQd3d;>7F3*yf=^ zK_3hZcb-Y%Qk7wdXNecG&H{0FVLil@Q43*Yme-3>(FcMR= zqmTuJI-5nv0#DiJAy}2KhHIdPS@qFH#RA(J_d?)qpm@Rdo3`r5#SZO3Lv7O+?H(P6 zk3DwU-{^0j5@q_{{VHv-=Neayv(e3FGpOYrfwJRwG)9Xuw~6u~DM%c@r02&1-zKq5 zSHG#c?6f%ZodMTF0+rMLjiw5ApPa@~+z|Xo%c4G+Wx;r3BjRA*1y=-TW$W#Z!AND{ zTB1zs{(+?p&6L+s+r!ECkGt}5g)fpGR(`cAD%(CeVESavyadCaQbTsL`opjmbfsN)IS7g9mO5>?G-U>pvn?ZXmZfGuM2A^MOB*{eV=^W?6V@}4H1Sz~` z$InfSR=2SiwZWeY_3mimLM&l9tC3V+ck&mQu3U|lDL>L1_M`hS7?G=RE0VKfZ}KYa z=A8tD*QeLoU>b%#_L6h`8Kjl*%Ujv!TKdZ9?~j~PkwM6(5djm1)m&zYNCZBn)}OB2$Mq(Eo4Dl| z&e>oF1v)7_S%YY8N0?X)mO|pAG`GP!Pp3OZ0VyX&L)|@>?26p$9tb0u`r5SQO#K5= z;aMV#P98}Cp(kHQ)EXb17~@mOThBiTmr@X|Tu5ZG5=e-0Fb}4|3i7V6byjtWV}6MW zo3wfhQ-PGHMAs$+J@urh4c2ku$z!aI4d}==_;NxPseae6f((W_xL_8-OPPNYpxN}e z0SxhpwO=enH8>wD4xx)1huMRX`;>>1tlfHPQmS91=})(!s1GUEU((9oTvPB1q*z~j z=IDrUQKDXQCMoeEd7nm6Qo!r0niPnO?JBP=gGo+-gJk-IQ_RnSqzHl4a6P+nA+cc5 z;_~IH&;Q2DFOcbTf8`uwaCWB7nX49jcBT#&a}J#+t9ZS9g}-P;%&*VE#D2^;G^-LY zr%;v9NiVm-y2P-b2s)Xe;MLl)ke4$GfdE1am#FsrzHyr+GGucnxMm^7nq6h2cNjEG zHNr?byX&|MWEex37OlW9x%xc961C(4Rl_D#+1j|tQ@TNROt;|{=s4+~B^jj)+jI82 zc;iJY#;XyxFfI5<9k@v?EVS(*3q+`dsLfN%CfuI3tID3fF*C{tS2Y}q3XU-+@=7vN zbC%{iuV%Zk6G9di6)7>4b=USqn5Iv@rfLSdL0{f+O-9au=QX0o`n~R=MK->hU<GV3kouo^8rooBwB1UE{7>|Up6?R(peu>God znM)h|8}EJfyQBbyIZ|PFw5=cYyu4UeP#88w%{^ns+SJKW(r|oeO`y=kzREcNWY^tz^{Y~+(cD8 z;3Zf`Pl;qHGfULc7x|3g&scSeZk@8s6;IVXdtDBVE;uV{00hK#^||Vm-P%^|-G-FB zE>7>mKe4XtLw71{@6*AZI!c2_RZ-$~kWLkWZoSjNpFKpZ8+%f3dJ@gg!th_M*7r+Y zuRfi@~b74E0%p;u{H^9e&b+6wTEkcxI5hm~NxLE$q z@|N68bP!M>a&XP6>}10iv5FPyUbIx=^w9aGM>A(+R&sf{bW^g1gMp|a1M zh6*Iy(kvJsFouETyEGOrtZO)Wqj2jMzC4Lg=S+~Q|J*v9dyvj~Xu7C<-Z(yWVdK%8 zz23Q+G9M`T%9NJoy@z7Qa*_y3;)fZZi8nSYjx&v=aW1Vd*jLdS28 zWnpZ{NU#)W5dLIq0c~=;RyQ#9PSwS3;mx~u~V|3Z|rcXQem6mo=pnj3Sfq< zvk$NQMLH8CA@?x`&etjfi?JbD9&qIDcN?;m?=Wj{-KJT>E)1T?>KYArnQ}Mw79eFi zxid1O5f`Q)2Rgegsa!J8&ZxJ)gwO=&~ipvb!sX#J&CNa#5?SBqH?B|<-Penmm3h>+OBd!6g2b|LkhgHf8~mR zi;uEcV$$aEgzh}55sLtM*I}EzUhDz0#I9r;9rqM~l$pEuF0YEO)IAp~g(kVwws@q6 ze(dnKR^emcQf2k2JJscnQ7au{pJ%Y*{oKUdOXB;#Ga~zq6aI-P4YGgVRuUp z^&=k{oyF1=;EWa9HVWc_B@kyS4Asgzghe!^>;s1>+O;Cc&j6pHQ?Wot*ybneLy@wK zpxq#&8x&IRBY^#ZOl!`R>OyG}V~Ta7@+}qEdFI<7K_AY0fe|(q0uO?q^JczQ^Glp= zo<&;d^-$3nVK4!`XTm)}L6VXgAk)+65{<(J;(S!zW5c-o)MyJ129oleN_(!FiHPis zGXZ006ti2T7|lmoKGGCXkT+D=9*?t#dAn4NC|NDSF;BdU>v6;w8qJ_!d&k#-=xcg4rc1=_8WHH($p=flQzbb0KG<_&v*`iW==ZD!lKoJR|0l z*7`7W(+%cx5-qXy*W(f)AW(`8p5cP#p8n!Y+O>CI=fXe;vQ^zxPkc;>TtKx?!Jai8 zZHLx;y{slEa+dt&(J;3U68Skkc8E zzguY3Ml4mPI=)!bQ6TN;&E>@}qm&Tx@CKo)pkcAss;2QIo3~ifE7F6@#N!Li@{!^NhBrM+ zU$ck_42JgeiCI?Oc2zU?zo5mzunCE>e=P1&CX!sIO<-~IDA4UoOhJtnr>kDl_j=0# z%jXjqjT3Z4K92SR^Y?I4RTZcYrJm41>B19YrUM=};hBL_`KaHC~z!303>-Ji=}hj9v0(V@r-2dp?#wO7dt%X>Yi$MORnIPGG-{TIrx?SHC#* z`6pxgrIq*L4kY@bk6WIhySCl*h}0PXzK%ZY+8Pk1QHIR!P)(OW!pewQm$>*=p8|+3 zz3}25ZzvCCzBH<0Fh&0$@&XS~*ls9m#bKIUKUgD&V{1mbY>o65)E~B8*QMfpOOMu{HU{XW4BA;jiyi1joKMK#RlN>q_-=>DX6rLj*zK$o(c?rIGOOg1Nqu#d8G~Op6Q@lXZa>ZOGRM&(`CqN=xYVPm8Yarqmy1b;I`7rk^1Xn zgf1|G$@!Uc>S+~sw{gOtlKg!r?6Wo(ANMJzK#SZ`!uuQbakdA7JvD%FtSRmx4oppj zYyd9?1eNNb#98zwL3s+skiL(d(g!s~p? z6((AYDefxy2wXzN*gF$DPc`Nx$^keaBY&&5H zir$(fj^nAx(1$A6VO66}$j$Sllm)+jT6LwCqPYM!7(A2I@H4nZweG8LFPJZmGk3qz zuH&nkprJo_09e4}y0oV~5XqID(0wLYB~!F4+U9xvi*c8}XTTUfydv8w?mJc;SS|&N^zb!8pz#qxZ>OjIL<6W{}kS3wzLsQZsA$5$9x)HAyYUDCpvS6#Wq7TxpG&!?MG z=O68a47>~#u%opd86HjSVzp03>{EJB!5(mOzBjpJxM4*$oJ4@_(o-4}P8;yO*FR*# zo$*F__+9*-+>kKM%1sn`!El}uYm^TGR}FR$az62W$;dT>t(*Lnmk{d*F>zw(D4%>g zS72w@c0JsP&7kN&w2j7;;4I7>&(_e2)keYyD9K=-B8s{W_C8U8Zm7 zcVZ9IBDY~tN<0c>bPRzHYVuk>^DkG%;!yQ^-!@X!su7azJKBW7Svwk}-YgfFzl6F6 z)4##w`~(dH^W%`$d@R;5Bl@IB#qp)ofA0cEsCUSfyhzg-vpI{4&p(aK$}c~4I4C}z z(GJ_NBUX%G|H3VnAcU%W-$Q=pIMykgThN@}FtuDGoB%^g&Ztp_cA2fy4B&>k^L=a0acSv2XyxL0wYXOaWtI_3 zW^m&?rIA;~5PC_qe0rZsSUw9Ai@Di=gc)Z}ipxOl`fVhdAovJjl!Jr#IEN?uij|sf(t1w1&H; z82GI1gCP!Gu2J zTXu_2r(xhU(MlbMdwSk?HEtfLOryV@KXAMTDjMsy;92{zJMxmY-dhr%#5<^jynN@0pXgP(i%!{br_E%ZHK|5{Y&s1tGjoY9Piu*D0$5Br1uxFU zGq!Gdp~x-g8U#o6hkMy1E?I>AZHS?(df@jinQ^vV)Gk{cZ=Dh#SU5Hh9Wuu(>YJiz zoC810nfrHWOl>wF(D%r+qxtyaf6qt^Rg{W%oy{+YWW4}>Xw`|GKr&Yz%I-**5qyf8 zwId0mQvBH2@m1&B^!?Ki4GZx%x;WFXK=0_7-+WLtN$jg6|1gx^vGHi|0!1tq@OT}jBLK66^o{iGJtMN!@ zx_$3FH+!BejRvN;z3QBiykf3k$=SLjkjMx&XUE0HlK|gwS;_g6FIK#}twEt$X`!pZ z-I;4*HrPsPp|PL+Nf%>8;sp27F^8-<+GEfU4SNKW7j2OQHv>)MUSKbdVlBDmJlh6m z^|QZMBXMw?mPKqJ`;64kxtcYcP-2)9YpRob9#1;`Spsa9{MILmCAH4YaO;SUk1JYE z&Ogk3F;9T?my=i{_vu>AcN0u(A`F+mey6LIfA;#$I`1>F$#1#E3(@86F!bH;G!{%$ zAw;=2`k>%VPejQfl}yu_4X*#%4Ln)x`!q71_>yf}e@3&#$%p6Fmt@w8`_>|>-+Zl2E8u!2^p-3)JzVC) zOvG->p3U=x=x~ux#i#hkqft%il*wr0kZQT<6FpF6uQqRbP-sg?9m2Mtm-sxPDi8P3 zt=QA027*}8P8F%ZWClsHMEDWG=w+!{)s=ja_6A_1_g*d(XGG!ZZON8>7&~37qkuc?HMfmAtg}J}1=;(3fr# z>68YvJKzRcX8q~o_`F9cRj4G3k_oq}JoX%~a?+kbLhSp^9uo7_HT2vGak6Fs4Av(r z$mRlx{qewKKZ0dCtwJ$b*#gWdPBJuvab{7#{Jw!gfpnH%VTRMFin&?@U^eb~{}DU; zGpbjKC}v$OHyZkA%1k$n*_SFU>t%6L2e*A6d?PD7w1kE}tNj`;GL5?-NWS6E`7-cw zhWdLq0s4I7CumcUG)`KnVE?!y!%f3{ww99}GCT4&{D)B&8l7GwX7>Z5d}_FF`)7D6 zYdGtLiZ)fFiFix{1#Q)yuH*}l#MM(}ShF$T{Bp#aPC7i3F~xWacvw#SWO#dM1U?e< z@Yq$QFX}8pVd+`GO^KRj9Bd&lT9sySwFC2V@U0gyao`O`WcvyG-SU(#4=tU_@iinp z=@>5eYhT>Ia;K&RCqMM%rX$f^boe3xlqCaovjJ4{viFSF9`8bJACLYOSn;+rl*^6PdSHs$7-~(l1k`=D>OXTCYeO1 zQt3lh>J+mSfL!x5z)I`r8&%GsMyh3--7`^!?faz+5l<@g%Q(xRd@&U&aH)5({P{ zT>)0~)W*>bV0&@xo9mfi6!icGGZs(7*^IEys{1;J&kKiB@Jy3C<2-W6bCkbWwxttI z*-q&rQaTBi_JTPDaHFZ<=!|MZ>@wBuW)`fMroxIr{Jpx^*Pxh`6K(Pt?FwBFinD{# zCH@!fhY%_@DXCi}FEI0HWogHF!(UD@${z-F<+awL4W*BS2s%=A%?jczwS=3J zVpdPZE9R`8hr}H<1MAr>l`-`vPcF>0R?caS#=W}@5pd9p<(NC$HO6*VF33L7(#bQ0 z6l!|7=eu_gVq=mxCL}ibV9~;ss6x!*d!`RQy&mZuAfv+Vmll>yzbi9h5N+sK7fq&< zMrsVyamnEgHKI2tJhCga6;LP*Oyb0C+|R2mLz_1LfT3z<>?O-nZn%i&;WwK%lWu?v z@z=gl2*i3%--L^epXda^a30kCd@LVT)~jZ~6OeNMj?$=eJ)#J6QyWYo0Rx{<&s6&vg|F zxwV<1ad(E)gJn-hoMr3im*?kHB}XNo_2y$vh;aj*5l5MF-A{!Nv+mCsHpDf9q- zK_VfIIrH8(o6VDhha&TCaFbF9MA#1`G8mKsERtDpg9niDeju1V1zROR4w$EIsLiN> zhPm%V$P(8#pd1YE+UJ1ZVcGFzi;^|Z{}dR#=n>cDo4fcOBrb7Vp1Ln*(8^t$!ooH#0af ezg%HbqcLX=G%wSdxBU16sj~b%xk?#}(EkV4Q`p)7 diff --git a/docs/static/images/dropwizard-hat-smaller.png b/docs/static/images/dropwizard-hat-smaller.png deleted file mode 100644 index 553a2be2783ac78be390b7d7809028d8c0cc87f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6699 zcmeHMcTiK?w+F-Mg zfxjTYo63KMz`#EeZt|nZ7$lWQ{w{z$#_z`fKX84uZgG7N-Xx>qsJ@u*sJ;gNQV~DN zRo8}$BT!*msrur6n)pBDuzzHAq%dAU2Mifc`Q@-bEbD8gFz`>gVc%~w)M#5bBO;^l zQB*j=i?~(SKlD`KxtH#_i4f?u}>c#`ZHtCt)-(@V73uy-i>G&3|p! zQtQ9Q{)PB=kY7^xw_LyF`XvQ^$@zD6{g&&O6!<0Q-_`a1CKu;F=O7G$arg;joN_v_ zYvKR^cM{y#z#*u&*45{n<4eKyCEa4}Ko6y}Pk=z~bHJ?jQ!Jd^#L>Ivci}hjzM@?V z))BYh_7N49U3z&q&y9*aIIU8(RJro}dFAfPN>|T=P7=9?lJ6KqCIUT0Qq#0QUhf$^ z7CJp&t&-JWC81JIp30z1X$`qdx(&JdWcn08Siza@M_j!Qu6qQE=%bUD{c^8oy5G`78MjrcLP_lzBM4qVTFz zeop<{`*s_dlGyyQmr_81TLY~;X z7+reimyb1+aZ_itNuGH%nS-C4F>mE#ZBI52=0@B(c;c1Dltlbew; zJn6~R9Y;hXVFq?)>B6;1ov+~+5=9AnftQrMj_Z^xiz14aZ1(oXqMU@i&$`d4x#3#&$7f zEo1pSJQ?aY&%;D&|+sf}&7@`~cq5|->(KMt+H_?RZ09wlV3#3;E?RMw1= z8|C3skuiOj3`Y2MZk3fN_nD8nd-fZOD?7-vu9DBeWDL!YCJA&+lE+P&)u;m|Jd$z7 zM$(N0L?R*Su%mFqXEC`L*4oup*Y}}oA)MtzUcs`Y76_XhTKL1h)q==sn&Km-{+Ggm z836FZN1XK$Lc?)&?@ce~L^rUPS7qcN^?Rc+r333C{wm~CQ@HHsdaU$vP?(a_Ur#e1 zh;3+A3*dJkUXGmclsS{}AEayM!TWp;qbzinrL2A)Lg(LJu3=-lPdD-M4#T8k8paCZ zbHr1k_~tEkl``ioba>w`Kav%AM!TAV1Ql21^+8^>=C$xcPBlyAn{+_RJL<#FRP{#Q zFFBC|R-EHA^wMETrnQ~QF8Yk8eUKkC?#_cCSQLYl7KM&BcoeimP5t$809L-Z^30C| zDocv1v>)1af4{mY=CN|IyT!$h?S9K zj~1|(i9SFKQkXBCT(ou9nNSVmr>aeM+R_vc!jG)z4Rjj{h8*6PlpGE0tOfPhooS^5 z1#KHwT4yK^?o4n`iT20nGpS;TZSrbde_Qd%=h5Aq9my9;_J`K93 z&~uN(HX@@k4(vW5$Wb6e8}ij_riSLK!$gvDQt2wUbvigjXqeLKSm0X$i%h!2XtnBu z+=Tt|c;^%kqfMAQyJ7*Z(gkvCQNgr%UjKW}`|QiY#6?`rvBa>mar}7+JXJqiuHz6z zkF3oUA3w_UAWgA9kKVRWcKg;-&b_%;diiw(sy@C@mkeDWHr-(sI@{M1P*3q*Y4_xB zBUIhC*iv^Ib3fC|Q8`lkjCCO*PSe2N_wEi(yl&q4taq%= zue9$qr~@3OuZpoYcbzHf{gg8EF7moqQg6w%1m-9~1(&C7(5&E3jv9&Pw_S_h2s71_ zcDp6t8^1QW;ozfw1-!;L6g;dIX|R^gefWt&*8*Q$xYaQsc!;rrzOZ8G=h0;Gf6Urn21zS7jFwhcyy2xd8r?M3+W zhZ6J(Vsb(s%^d3Zv)MTbGo=%E`=H{KaFlY^GYP{%eKUWnKWO!=5q&Kd?^G0?vNLn} z6dy2fyI(95hZh?%!1_3v745Bl>&U95!3EFsB8^B3Lcg?U6AbKe|+gLS>YE_V}g#8^H3+N*dFw!3|0iH2p)OIn znB;sh)ULI9|1(gM6?0;42G8S^=jspNmsX(d+h0D5>vF3Q1TGCYTk=k^-%$cS^swX;c6 zx1APCF}h7gHO2H^jMOzTnm#svv7|#Q;;dn{Nyf$?c)(a=e7LYdV()=nSwXifsysrK zdC!~4!Ba_#eBfX@@;b@Z&tX2v5Kmz-^f&VMu+4sPch8QL8+($Ql+>de@w=C}E5|Cu zLOXTu^Ejs8)OM3=s9KCRPu86qwU#+_*=?-3sfse;x7;zNS+cQDJnVy}si~=LVRWww zXTe;-e%sV4zH%LAJBXK@#PDmuG)WHev6fhZT|Jj)kQ>^!yuKzd)nQ;W$^Q9}E|kJ+HnheU({j@+@!I3K zF|6Oxdr5DHlaWe=H6ad73U4rNXw}p9*Y+%UkhDc+BFEk0meuO+Mmo0DD5)wPIPARW zNeGnjWp?t$8Tj~2BC6bVhpVSN;@=;5;T#P~lWXpHrK9b*0;Li+7Iuc{G~uRZx?b+Dl -
          -
          - Dropwizard - -
          -
          - \ No newline at end of file diff --git a/docs/templates/landing.html.erb b/docs/templates/landing.html.erb deleted file mode 100644 index 11959660b38..00000000000 --- a/docs/templates/landing.html.erb +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Dropwizard - - - - - - - - - -<%= partial :toolbar %> - -
          - -
          -
          -
          - -
          -
          - - <%= page.content %> - -

          Get - started »

          - -
          -
          - -
          -

          © Yammer 2011-2012

          -
          -
          -
          - - - diff --git a/docs/templates/manual.html.erb b/docs/templates/manual.html.erb deleted file mode 100644 index d6f7505a4df..00000000000 --- a/docs/templates/manual.html.erb +++ /dev/null @@ -1,39 +0,0 @@ - - - - - <%= page.title %> | Dropwizard - - - - - - - - - -<%= partial :toolbar %> - -
          - - -
          -

          <%= page.title %>

          - - <%= page.content %> - -
          -

          © Yammer 2011-2012

          -
          -
          -
          - - - From 0eec02ddb8a6e7cc8def2c8f16d84890218a6ef4 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 11:18:13 -0800 Subject: [PATCH 0249/2771] Upgrade to Findbugs 2.4.0. Also, fix some false alarms. No idea where it gets some of this stuff. --- findbugs-exclude.xml | 24 ++++++++++++++++++++++++ pom.xml | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/findbugs-exclude.xml b/findbugs-exclude.xml index a11c68a9bf0..32586a32800 100644 --- a/findbugs-exclude.xml +++ b/findbugs-exclude.xml @@ -26,6 +26,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index dce68a998b8..fa0942fcd6f 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,7 @@ org.codehaus.mojo findbugs-maven-plugin - 2.3.3 + 2.4.0 Max Default @@ -211,7 +211,7 @@ org.codehaus.mojo findbugs-maven-plugin - 2.3.2 + 2.4.0 org.apache.maven.plugins From e266401d0bd67718bca46f9a18c1050b887cd782 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 12:08:53 -0800 Subject: [PATCH 0250/2771] Moved changelog to release notes. --- CHANGELOG.md | 72 -------------------------------- docs/source/relnotes.rst | 89 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 72 deletions(-) delete mode 100644 CHANGELOG.md create mode 100644 docs/source/relnotes.rst diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 37b1cd38f1b..00000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,72 +0,0 @@ -v0.2.0: TBD -=================== - -* Switched to using `jackson-datatype-guava` for JSON serialization/deserialization of Guava types. -* Use `InstrumentedQueuedThreadPool` from `metrics-jetty`. -* Upgraded to Jackson 1.9.4. -* Upgraded to Jetty 7.6.0 final. -* Upgraded to tomcat-dbcp 7.0.25. -* Improved fool-proofing for `Service` vs. `ScalaService`. -* Switched to using Jackson for configuration file parsing. SnakeYAML is used to parse YAML - configuration files to a JSON intermediary form, then Jackson is used to map that to your - `Configuration` subclass and its fields. Configuration files which don't end in `.yaml` or `.yml` - are treated as JSON. -* Rewrote `Json` to no longer be a singleton. -* Converted `JsonHelpers` in `dropwizard-testing` to use normalized JSON strings to compare JSON. -* Collapsed `DatabaseConfiguration`. It's no longer a map of connection names to configuration - objects. -* Changed `Database` to use the validation query in `DatabaseConfiguration` for its `#ping()` - method. -* Changed many `HttpConfiguration` defaults to match Jetty's defaults. -* Upgrade to JDBI 2.31.2. -* Fixed JAR locations in the CLI usage screens. -* Upgraded to Metrics 2.0.2. -* Added support for `ServletContextListener`s. - - -v0.1.3: Jan 19 2012 -=================== - -* Upgraded to Guava 11.0.1. -* Fixed logging in `ServerCommand`. For the last time. -* Switched to using the instrumented connectors from `metrics-jetty`. This allows for much - lower-level metrics about your service, including whether or not your thread pools are overloaded. -* Added FindBugs to the build process. -* Added `ResourceTest` to `dropwizard-testing`, which uses the Jersey Test Framework to provide - full testing of resources. -* Upgraded to Jetty 7.6.0.RC4. -* Decoupled URIs and resource paths in `AssetServlet` and `AssetsBundle`. -* Added `rootPath` to `Configuration`. It allows you to serve Jersey assets off a specific path - (e.g., `/resources/*` vs `/*`). -* `AssetServlet` now looks for `index.htm` when handling requests for the root URI. -* Upgraded to Metrics 2.0.0-RC0. - - -v0.1.2: Jan 07 2012 -=================== - -* All Jersey resource methods annotated with `@Timed`, `@Metered`, or `@ExceptionMetered` are now - instrumented via `metrics-jersey`. -* Now licensed under Apache License 2.0. -* Upgraded to Jetty 7.6.0.RC3. -* Upgraded to Metrics 2.0.0-BETA19. -* Fixed logging in `ServerCommand`. -* Made `ServerCommand#run()` non-`final`. - - -v0.1.1: Dec 28 2011 -=================== - -* Fixed `ManagedCommand` to provide access to the `Environment`, among other things. -* Made `JerseyClient`'s thread pool managed. -* Improved ease of use for `Duration` and `Size` configuration parameters. -* Upgraded to Mockito 1.9.0. -* Upgraded to Jetty 7.6.0.RC2. -* Removed single-arg constructors for `ConfiguredCommand`. -* Added `Log`, a simple front-end for logging. - - -v0.1.0: Dec 21 2011 -=================== - -* Initial release diff --git a/docs/source/relnotes.rst b/docs/source/relnotes.rst new file mode 100644 index 00000000000..7427a55d68c --- /dev/null +++ b/docs/source/relnotes.rst @@ -0,0 +1,89 @@ +.. _release-notes: + +############# +Release Notes +############# + +.. _rel-0.2.0: + +v0.2.0: TBD +=================== + +* Switched to using ``jackson-datatype-guava`` for JSON serialization/deserialization of Guava + types. +* Use ``InstrumentedQueuedThreadPool`` from ``metrics-jetty``. +* Upgraded to Jackson 1.9.4. +* Upgraded to Jetty 7.6.0 final. +* Upgraded to tomcat-dbcp 7.0.25. +* Improved fool-proofing for ``Service`` vs. ``ScalaService``. +* Switched to using Jackson for configuration file parsing. SnakeYAML is used to parse YAML + configuration files to a JSON intermediary form, then Jackson is used to map that to your + ``Configuration`` subclass and its fields. Configuration files which don't end in ``.yaml`` or + ``.yml`` are treated as JSON. +* Rewrote ``Json`` to no longer be a singleton. +* Converted ``JsonHelpers`` in ``dropwizard-testing`` to use normalized JSON strings to compare + JSON. +* Collapsed ``DatabaseConfiguration``. It's no longer a map of connection names to configuration + objects. +* Changed ``Database`` to use the validation query in ``DatabaseConfiguration`` for its ``#ping()`` + method. +* Changed many ``HttpConfiguration`` defaults to match Jetty's defaults. +* Upgraded to JDBI 2.31.2. +* Fixed JAR locations in the CLI usage screens. +* Upgraded to Metrics 2.0.2. +* Added support for ``ServletContextListener`` instances. +* Added ``Log#setLevel(Level)``. + +.. _rel-0.1.3: + +v0.1.3: Jan 19 2012 +=================== + +* Upgraded to Guava 11.0.1. +* Fixed logging in ``ServerCommand``. For the last time. +* Switched to using the instrumented connectors from ``metrics-jetty``. This allows for much + lower-level metrics about your service, including whether or not your thread pools are overloaded. +* Added FindBugs to the build process. +* Added ``ResourceTest`` to ``dropwizard-testing``, which uses the Jersey Test Framework to provide + full testing of resources. +* Upgraded to Jetty 7.6.0.RC4. +* Decoupled URIs and resource paths in ``AssetServlet`` and ``AssetsBundle``. +* Added ``rootPath`` to ``Configuration``. It allows you to serve Jersey assets off a specific path + (e.g., ``/resources/*`` vs ``/*``). +* ``AssetServlet`` now looks for ``index.htm`` when handling requests for the root URI. +* Upgraded to Metrics 2.0.0-RC0. + +.. _rel-0.1.2: + +v0.1.2: Jan 07 2012 +=================== + +* All Jersey resource methods annotated with ``@Timed``, ``@Metered``, or ``@ExceptionMetered`` are + now instrumented via ``metrics-jersey``. +* Now licensed under Apache License 2.0. +* Upgraded to Jetty 7.6.0.RC3. +* Upgraded to Metrics 2.0.0-BETA19. +* Fixed logging in ``ServerCommand``. +* Made ``ServerCommand#run()`` non-``final``. + + +.. _rel-0.1.1: + +v0.1.1: Dec 28 2011 +=================== + +* Fixed ``ManagedCommand`` to provide access to the ``Environment``, among other things. +* Made ``JerseyClient``'s thread pool managed. +* Improved ease of use for ``Duration`` and ``Size`` configuration parameters. +* Upgraded to Mockito 1.9.0. +* Upgraded to Jetty 7.6.0.RC2. +* Removed single-arg constructors for ``ConfiguredCommand``. +* Added ``Log``, a simple front-end for logging. + +.. _rel-0.1.0: + + +v0.1.0: Dec 21 2011 +=================== + +* Initial release From f94d2ee7496a92dca356b715a9d570b9eca88faa Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 12:09:08 -0800 Subject: [PATCH 0251/2771] Auto-generate landing links. --- .../_themes/yammerdoc/static/yammerdoc.css | 43 +++++++++++++++---- docs/source/index.rst | 11 +---- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/docs/source/_themes/yammerdoc/static/yammerdoc.css b/docs/source/_themes/yammerdoc/static/yammerdoc.css index 64e6fb2889a..b7721fe2e12 100644 --- a/docs/source/_themes/yammerdoc/static/yammerdoc.css +++ b/docs/source/_themes/yammerdoc/static/yammerdoc.css @@ -19,15 +19,6 @@ a.headerlink { text-shadow: 0px -1px 0px #5f0c17; } -#landing { - text-align: center; -} - -#landing > a { - font-size: 16px; - padding: 10px 20px 10px; -} - .admonition { padding: 14px 35px 14px 14px; margin-bottom: 18px; @@ -176,3 +167,37 @@ h4 tt { color: #08c; background-color: transparent; } + +.hero-unit .toctree-wrapper { + text-align: center; +} + +.hero-unit li { + display: inline; + list-style-type: none; + padding-right: 20px; +} + +.hero-unit li a:after { + content: " »"; +} + +.hero-unit li a{display:inline-block;padding:10px 10px 10px;font-size:16pt;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:first-child{*margin-left:0;} +.hero-unit li a:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} +.hero-unit li a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.hero-unit li a:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;} + +.hero-unit li a{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} +.hero-unit li a:active{background-color:#408140 \9;} + +.hero-unit li a, .hero-unit li a:hover {text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} +.hero-unit li a:active {color: rgba(255, 255, 255, 0.75);} + +.hero-unit li a:hover, +.hero-unit li a:active { + background-color: #51a351; +} + +.hero-unit li a:active { + background-color: #408140 \9; +} diff --git a/docs/source/index.rst b/docs/source/index.rst index 182451f4acf..b6e4f588fa8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -18,20 +18,13 @@ Dropwizard has *out-of-the-box* support for sophisticated **configuration**, **application metrics**, **logging**, **operational tools**, and much more, allowing you and your team to ship a *production-quality* HTTP+JSON web service in the shortest time possible. -.. raw:: html - - -

          - Getting Started » - User Manual » -

          From a2487f7584900a1208b942eb693b5490fd52cf63 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 12:35:43 -0800 Subject: [PATCH 0252/2771] Include Twitter Bootstrap 2.0. This includes the .less files and uses them to build the CSS for the docs. Right now it's totally non-modular, but we can fix that. --- docs/Makefile | 9 +- docs/source/_themes/yammerdoc/layout.html | 1 - .../_themes/yammerdoc/less/accordion.less | 28 + .../source/_themes/yammerdoc/less/alerts.less | 70 ++ .../_themes/yammerdoc/less/bootstrap.less | 62 ++ .../_themes/yammerdoc/less/breadcrumbs.less | 22 + .../_themes/yammerdoc/less/button-groups.less | 147 +++++ .../_themes/yammerdoc/less/buttons.less | 165 +++++ .../_themes/yammerdoc/less/carousel.less | 121 ++++ docs/source/_themes/yammerdoc/less/close.less | 18 + docs/source/_themes/yammerdoc/less/code.less | 44 ++ .../yammerdoc/less/component-animations.less | 18 + .../_themes/yammerdoc/less/dropdowns.less | 131 ++++ docs/source/_themes/yammerdoc/less/forms.less | 515 +++++++++++++++ docs/source/_themes/yammerdoc/less/grid.less | 8 + .../_themes/yammerdoc/less/hero-unit.less | 20 + .../source/_themes/yammerdoc/less/labels.less | 16 + .../_themes/yammerdoc/less/layouts.less | 17 + .../source/_themes/yammerdoc/less/mixins.less | 537 +++++++++++++++ .../source/_themes/yammerdoc/less/modals.less | 72 +++ .../source/_themes/yammerdoc/less/navbar.less | 292 +++++++++ docs/source/_themes/yammerdoc/less/navs.less | 343 ++++++++++ docs/source/_themes/yammerdoc/less/pager.less | 30 + .../_themes/yammerdoc/less/pagination.less | 55 ++ .../_themes/yammerdoc/less/patterns.less | 13 + .../_themes/yammerdoc/less/popovers.less | 49 ++ docs/source/_themes/yammerdoc/less/print.less | 18 + .../_themes/yammerdoc/less/progress-bars.less | 95 +++ docs/source/_themes/yammerdoc/less/reset.less | 126 ++++ .../_themes/yammerdoc/less/responsive.less | 323 ++++++++++ .../_themes/yammerdoc/less/scaffolding.less | 29 + .../_themes/yammerdoc/less/sprites.less | 156 +++++ .../source/_themes/yammerdoc/less/tables.less | 139 ++++ .../_themes/yammerdoc/less/thumbnails.less | 35 + .../_themes/yammerdoc/less/tooltip.less | 35 + docs/source/_themes/yammerdoc/less/type.less | 217 +++++++ .../_themes/yammerdoc/less/utilities.less | 23 + .../_themes/yammerdoc/less/variables.less | 99 +++ docs/source/_themes/yammerdoc/less/wells.less | 17 + .../_themes/yammerdoc/less/yammerdoc.less | 219 +++++++ .../yammerdoc/static/bootstrap.min.css | 610 ------------------ .../_themes/yammerdoc/static/yammerdoc.css | 581 +++++++++++------ 42 files changed, 4712 insertions(+), 813 deletions(-) create mode 100644 docs/source/_themes/yammerdoc/less/accordion.less create mode 100644 docs/source/_themes/yammerdoc/less/alerts.less create mode 100644 docs/source/_themes/yammerdoc/less/bootstrap.less create mode 100644 docs/source/_themes/yammerdoc/less/breadcrumbs.less create mode 100644 docs/source/_themes/yammerdoc/less/button-groups.less create mode 100644 docs/source/_themes/yammerdoc/less/buttons.less create mode 100644 docs/source/_themes/yammerdoc/less/carousel.less create mode 100644 docs/source/_themes/yammerdoc/less/close.less create mode 100644 docs/source/_themes/yammerdoc/less/code.less create mode 100644 docs/source/_themes/yammerdoc/less/component-animations.less create mode 100644 docs/source/_themes/yammerdoc/less/dropdowns.less create mode 100644 docs/source/_themes/yammerdoc/less/forms.less create mode 100644 docs/source/_themes/yammerdoc/less/grid.less create mode 100644 docs/source/_themes/yammerdoc/less/hero-unit.less create mode 100644 docs/source/_themes/yammerdoc/less/labels.less create mode 100644 docs/source/_themes/yammerdoc/less/layouts.less create mode 100644 docs/source/_themes/yammerdoc/less/mixins.less create mode 100644 docs/source/_themes/yammerdoc/less/modals.less create mode 100644 docs/source/_themes/yammerdoc/less/navbar.less create mode 100644 docs/source/_themes/yammerdoc/less/navs.less create mode 100644 docs/source/_themes/yammerdoc/less/pager.less create mode 100644 docs/source/_themes/yammerdoc/less/pagination.less create mode 100644 docs/source/_themes/yammerdoc/less/patterns.less create mode 100644 docs/source/_themes/yammerdoc/less/popovers.less create mode 100644 docs/source/_themes/yammerdoc/less/print.less create mode 100644 docs/source/_themes/yammerdoc/less/progress-bars.less create mode 100644 docs/source/_themes/yammerdoc/less/reset.less create mode 100644 docs/source/_themes/yammerdoc/less/responsive.less create mode 100644 docs/source/_themes/yammerdoc/less/scaffolding.less create mode 100644 docs/source/_themes/yammerdoc/less/sprites.less create mode 100644 docs/source/_themes/yammerdoc/less/tables.less create mode 100644 docs/source/_themes/yammerdoc/less/thumbnails.less create mode 100644 docs/source/_themes/yammerdoc/less/tooltip.less create mode 100644 docs/source/_themes/yammerdoc/less/type.less create mode 100644 docs/source/_themes/yammerdoc/less/utilities.less create mode 100644 docs/source/_themes/yammerdoc/less/variables.less create mode 100644 docs/source/_themes/yammerdoc/less/wells.less create mode 100644 docs/source/_themes/yammerdoc/less/yammerdoc.less delete mode 100644 docs/source/_themes/yammerdoc/static/bootstrap.min.css diff --git a/docs/Makefile b/docs/Makefile index 8b3956f3c7e..3d5b957efc8 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -41,12 +41,12 @@ help: clean: -rm -rf $(BUILDDIR)/* -html: +html: less $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." -dirhtml: +dirhtml: less $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." @@ -152,5 +152,8 @@ doctest: @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." +less: + lessc --compress source/_themes/yammerdoc/less/yammerdoc.less > source/_themes/yammerdoc/static/yammerdoc.css + upload: clean dirhtml - rsync -avz --delete --exclude=maven $(BUILDDIR)/dirhtml/ codahale.com:/home/codahale/dropwizard.codahale.com/ + rsync -avz --delete --exclude=maven $(BUILDDIR)/dirhtml/ codahale.com:/home/codahale/dropwizard.codahale.com/sphinx-ex/ diff --git a/docs/source/_themes/yammerdoc/layout.html b/docs/source/_themes/yammerdoc/layout.html index 112156bfc46..75c602e1c4f 100644 --- a/docs/source/_themes/yammerdoc/layout.html +++ b/docs/source/_themes/yammerdoc/layout.html @@ -12,7 +12,6 @@ {%- else %} {%- set titlesuffix = "" %} {%- endif %} -{% set css_files = ['_static/bootstrap.min.css'] + css_files %} {{ title|striptags|e }}{{ titlesuffix }} diff --git a/docs/source/_themes/yammerdoc/less/accordion.less b/docs/source/_themes/yammerdoc/less/accordion.less new file mode 100644 index 00000000000..11a36b544e8 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/accordion.less @@ -0,0 +1,28 @@ +// ACCORDION +// --------- + + +// Parent container +.accordion { + margin-bottom: @baseLineHeight; +} + +// Group == heading + body +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + .border-radius(4px); +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +// Inner needs the styles because you can't animate properly with any styles on the element +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} diff --git a/docs/source/_themes/yammerdoc/less/alerts.less b/docs/source/_themes/yammerdoc/less/alerts.less new file mode 100644 index 00000000000..562826fd30c --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/alerts.less @@ -0,0 +1,70 @@ +// ALERT STYLES +// ------------ + +// Base alert styles +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: @baseLineHeight; + text-shadow: 0 1px 0 rgba(255,255,255,.5); + background-color: @warningBackground; + border: 1px solid @warningBorder; + .border-radius(4px); +} +.alert, +.alert-heading { + color: @warningText; +} + +// Adjust close link position +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} + +// Alternate styles +// ---------------- + +.alert-success { + background-color: @successBackground; + border-color: @successBorder; +} +.alert-success, +.alert-success .alert-heading { + color: @successText; +} +.alert-danger, +.alert-error { + background-color: @errorBackground; + border-color: @errorBorder; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: @errorText; +} +.alert-info { + background-color: @infoBackground; + border-color: @infoBorder; +} +.alert-info, +.alert-info .alert-heading { + color: @infoText; +} + + +// Block alerts +// ------------------------ +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} diff --git a/docs/source/_themes/yammerdoc/less/bootstrap.less b/docs/source/_themes/yammerdoc/less/bootstrap.less new file mode 100644 index 00000000000..ea84f489987 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/bootstrap.less @@ -0,0 +1,62 @@ +/*! + * Bootstrap v2.0.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +// CSS Reset +@import "reset.less"; + +// Core variables and mixins +@import "variables.less"; // Modify this for custom colors, font-sizes, etc +@import "mixins.less"; + +// Grid system and page structure +@import "scaffolding.less"; +@import "grid.less"; +@import "layouts.less"; + +// Base CSS +@import "type.less"; +@import "code.less"; +@import "forms.less"; +@import "tables.less"; + +// Components: common +@import "sprites.less"; +@import "dropdowns.less"; +@import "wells.less"; +@import "component-animations.less"; +@import "close.less"; + +// Components: Buttons & Alerts +@import "buttons.less"; +@import "button-groups.less"; +@import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less + +// Components: Nav +@import "navs.less"; +@import "navbar.less"; +@import "breadcrumbs.less"; +@import "pagination.less"; +@import "pager.less"; + +// Components: Popovers +@import "modals.less"; +@import "tooltip.less"; +@import "popovers.less"; + +// Components: Misc +@import "thumbnails.less"; +@import "labels.less"; +@import "progress-bars.less"; +@import "accordion.less"; +@import "carousel.less"; +@import "hero-unit.less"; + +// Utility classes +@import "utilities.less"; // Has to be last to override when necessary diff --git a/docs/source/_themes/yammerdoc/less/breadcrumbs.less b/docs/source/_themes/yammerdoc/less/breadcrumbs.less new file mode 100644 index 00000000000..19b8081e1b6 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/breadcrumbs.less @@ -0,0 +1,22 @@ +// BREADCRUMBS +// ----------- + +.breadcrumb { + padding: 7px 14px; + margin: 0 0 @baseLineHeight; + #gradient > .vertical(@white, #f5f5f5); + border: 1px solid #ddd; + .border-radius(3px); + .box-shadow(inset 0 1px 0 @white); + li { + display: inline; + text-shadow: 0 1px 0 @white; + } + .divider { + padding: 0 5px; + color: @grayLight; + } + .active a { + color: @grayDark; + } +} diff --git a/docs/source/_themes/yammerdoc/less/button-groups.less b/docs/source/_themes/yammerdoc/less/button-groups.less new file mode 100644 index 00000000000..4b0523df295 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/button-groups.less @@ -0,0 +1,147 @@ +// BUTTON GROUPS +// ------------- + + +// Make the div behave like a button +.btn-group { + position: relative; + .clearfix(); // clears the floated buttons + .ie7-restore-left-whitespace(); +} + +// Space out series of button groups +.btn-group + .btn-group { + margin-left: 5px; +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + margin-top: @baseLineHeight / 2; + margin-bottom: @baseLineHeight / 2; + .btn-group { + display: inline-block; + .ie7-inline-block(); + } +} + +// Float them, remove border radius, then re-add to first and last elements +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + .border-radius(0); +} +// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, +.btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +// Reset corners for large buttons +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, +.btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} + +// On hover/focus/active, bring the proper btn to front +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} + +// On active and open, don't show outline +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + + + +// Split button dropdowns +// ---------------------- + +// Give the line between buttons some depth +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + @shadow: inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + .box-shadow(@shadow); + *padding-top: 5px; + *padding-bottom: 5px; +} + +.btn-group.open { + // IE7's z-index only goes to the nearest positioned ancestor, which would + // make the menu appear below buttons that appeared later on the page + *z-index: @zindexDropdown; + + // Reposition menu on open and round all corners + .dropdown-menu { + display: block; + margin-top: 1px; + .border-radius(5px); + } + + .dropdown-toggle { + background-image: none; + @shadow: inset 0 1px 6px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05); + .box-shadow(@shadow); + } +} + +// Reposition the caret +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, +.open.btn-group .caret { + .opacity(100); +} + + +// Account for other colors +.btn-primary, +.btn-danger, +.btn-info, +.btn-success { + .caret { + border-top-color: @white; + .opacity(75); + } +} + +// Small button dropdowns +.btn-small .caret { + margin-top: 4px; +} + diff --git a/docs/source/_themes/yammerdoc/less/buttons.less b/docs/source/_themes/yammerdoc/less/buttons.less new file mode 100644 index 00000000000..07a2b5879e0 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/buttons.less @@ -0,0 +1,165 @@ +// BUTTON STYLES +// ------------- + + +// Base styles +// -------------------------------------------------- + +// Core +.btn { + display: inline-block; + padding: 4px 10px 4px; + font-size: @baseFontSize; + line-height: @baseLineHeight; + color: @grayDark; + text-align: center; + text-shadow: 0 1px 1px rgba(255,255,255,.75); + #gradient > .vertical-three-colors(@white, @white, 25%, darken(@white, 10%)); // Don't use .gradientbar() here since it does a three-color gradient + border: 1px solid #ccc; + border-bottom-color: #bbb; + .border-radius(4px); + @shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + .box-shadow(@shadow); + cursor: pointer; + + // Give IE7 some love + .ie7-restore-left-whitespace(); +} + +// Hover state +.btn:hover { + color: @grayDark; + text-decoration: none; + background-color: darken(@white, 10%); + background-position: 0 -15px; + + // transition is only when going to hover, otherwise the background + // behind the gradient (there for IE<=9 fallback) gets mismatched + .transition(background-position .1s linear); +} + +// Focus state for keyboard and accessibility +.btn:focus { + .tab-focus(); +} + +// Active state +.btn.active, +.btn:active { + background-image: none; + @shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05); + .box-shadow(@shadow); + background-color: darken(@white, 10%); + background-color: darken(@white, 15%) e("\9"); + color: rgba(0,0,0,.5); + outline: 0; +} + +// Disabled state +.btn.disabled, +.btn[disabled] { + cursor: default; + background-image: none; + background-color: darken(@white, 10%); + .opacity(65); + .box-shadow(none); +} + + +// Button Sizes +// -------------------------------------------------- + +// Large +.btn-large { + padding: 9px 14px; + font-size: @baseFontSize + 2px; + line-height: normal; + .border-radius(5px); +} +.btn-large .icon { + margin-top: 1px; +} + +// Small +.btn-small { + padding: 5px 9px; + font-size: @baseFontSize - 2px; + line-height: @baseLineHeight - 2px; +} +.btn-small .icon { + margin-top: -1px; +} + + +// Alternate buttons +// -------------------------------------------------- + +// Set text color +// ------------------------- +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover { + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + color: @white +} +// Provide *some* extra contrast for those who can get it +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active { + color: rgba(255,255,255,.75); +} + +// Set the backgrounds +// ------------------------- +.btn-primary { + .buttonBackground(@primaryButtonBackground, spin(@primaryButtonBackground, 20)); +} +// Warning appears are orange +.btn-warning { + .buttonBackground(lighten(@orange, 15%), @orange); +} +// Danger and error appear as red +.btn-danger { + .buttonBackground(#ee5f5b, #bd362f); +} +// Success appears as green +.btn-success { + .buttonBackground(#62c462, #51a351); +} +// Info appears as a neutral blue +.btn-info { + .buttonBackground(#5bc0de, #2f96b4); +} + + +// Cross-browser Jank +// -------------------------------------------------- + +button.btn, +input[type="submit"].btn { + &::-moz-focus-inner { + padding: 0; + border: 0; + } + + // IE7 has some default padding on button controls + *padding-top: 2px; + *padding-bottom: 2px; + &.large { + *padding-top: 7px; + *padding-bottom: 7px; + } + &.small { + *padding-top: 3px; + *padding-bottom: 3px; + } +} diff --git a/docs/source/_themes/yammerdoc/less/carousel.less b/docs/source/_themes/yammerdoc/less/carousel.less new file mode 100644 index 00000000000..8fbd303154a --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/carousel.less @@ -0,0 +1,121 @@ +// CAROUSEL +// -------- + +.carousel { + position: relative; + margin-bottom: @baseLineHeight; + line-height: 1; +} + +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} + +.carousel { + + .item { + display: none; + position: relative; + .transition(.6s ease-in-out left); + } + + // Account for jankitude on images + .item > img { + display: block; + line-height: 1; + } + + .active, + .next, + .prev { display: block; } + + .active { + left: 0; + } + + .next, + .prev { + position: absolute; + top: 0; + width: 100%; + } + + .next { + left: 100%; + } + .prev { + left: -100%; + } + .next.left, + .prev.right { + left: 0; + } + + .active.left { + left: -100%; + } + .active.right { + left: 100%; + } + +} + +// Left/right controls for nav +// --------------------------- + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: @white; + text-align: center; + background: @grayDarker; + border: 3px solid @white; + .border-radius(23px); + .opacity(50); + + // we can't have this transition here + // because webkit cancels the carousel + // animation if you trip this while + // in the middle of another animation + // ;_; + // .transition(opacity .2s linear); + + // Reposition the right one + &.right { + left: auto; + right: 15px; + } + + // Hover state + &:hover { + color: @white; + text-decoration: none; + .opacity(90); + } +} + +// Caption for text below images +// ----------------------------- + +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: @grayDark; + background: rgba(0,0,0,.75); +} +.carousel-caption h4, +.carousel-caption p { + color: @white; +} diff --git a/docs/source/_themes/yammerdoc/less/close.less b/docs/source/_themes/yammerdoc/less/close.less new file mode 100644 index 00000000000..a0e5edba1b6 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/close.less @@ -0,0 +1,18 @@ +// CLOSE ICONS +// ----------- + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: @baseLineHeight; + color: @black; + text-shadow: 0 1px 0 rgba(255,255,255,1); + .opacity(20); + &:hover { + color: @black; + text-decoration: none; + .opacity(40); + cursor: pointer; + } +} diff --git a/docs/source/_themes/yammerdoc/less/code.less b/docs/source/_themes/yammerdoc/less/code.less new file mode 100644 index 00000000000..0cc3db857ae --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/code.less @@ -0,0 +1,44 @@ +// Code.less +// Code typography styles for the and
           elements
          +// --------------------------------------------------------
          +
          +// Inline and block code styles
          +code,
          +pre {
          +  padding: 0 3px 2px;
          +  #font > #family > .monospace;
          +  font-size: @baseFontSize - 1;
          +  color: @grayDark;
          +  .border-radius(3px);
          +}
          +code {
          +  padding: 3px 4px;
          +  color: #d14;
          +  background-color: #f7f7f9;
          +  border: 1px solid #e1e1e8;
          +}
          +pre {
          +  display: block;
          +  padding: (@baseLineHeight - 1) / 2;
          +  margin: 0 0 @baseLineHeight / 2;
          +  font-size: 12px;
          +  line-height: @baseLineHeight;
          +  background-color: #f5f5f5;
          +  border: 1px solid #ccc; // fallback for IE7-8
          +  border: 1px solid rgba(0,0,0,.15);
          +  .border-radius(4px);
          +  white-space: pre;
          +  white-space: pre-wrap;
          +  word-break: break-all;
          +
          +  // Make prettyprint styles more spaced out for readability
          +  &.prettyprint {
          +    margin-bottom: @baseLineHeight;
          +  }
          +
          +  // Account for some code outputs that place code tags in pre tags
          +  code {
          +    padding: 0;
          +    background-color: transparent;
          +  }
          +}
          diff --git a/docs/source/_themes/yammerdoc/less/component-animations.less b/docs/source/_themes/yammerdoc/less/component-animations.less
          new file mode 100644
          index 00000000000..4f2a4fd1185
          --- /dev/null
          +++ b/docs/source/_themes/yammerdoc/less/component-animations.less
          @@ -0,0 +1,18 @@
          +// COMPONENT ANIMATIONS
          +// --------------------
          +
          +.fade {
          +  .transition(opacity .15s linear);
          +  opacity: 0;
          +  &.in {
          +    opacity: 1;
          +  }
          +}
          +
          +.collapse {
          +  .transition(height .35s ease);
          +  position:relative;
          +  overflow:hidden;
          +  height: 0;
          +  &.in { height: auto; }
          +}
          diff --git a/docs/source/_themes/yammerdoc/less/dropdowns.less b/docs/source/_themes/yammerdoc/less/dropdowns.less
          new file mode 100644
          index 00000000000..83f535ae861
          --- /dev/null
          +++ b/docs/source/_themes/yammerdoc/less/dropdowns.less
          @@ -0,0 +1,131 @@
          +// DROPDOWN MENUS
          +// --------------
          +
          +// Use the .menu class on any 
        • element within the topbar or ul.tabs and you'll get some superfancy dropdowns +.dropdown { + position: relative; +} +.dropdown-toggle { + // The caret makes the toggle a bit too tall in IE7 + *margin-bottom: -3px; +} +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} +// Dropdown arrow/caret +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + // IE7 won't do the border trick if there's a text indent, but it doesn't + // do the content that text-indent is hiding, either, so we're ok. + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid @black; + .opacity(30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, +.open.dropdown .caret { + .opacity(100); +} +// The dropdown menu (ul) +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: @zindexDropdown; + float: left; + display: none; // none by default, but block on "open" of the menu + min-width: 160px; + max-width: 220px; + _width: 160px; + padding: 4px 0; + margin: 0; // override default ul + list-style: none; + background-color: @white; + border-color: #ccc; + border-color: rgba(0,0,0,.2); + border-style: solid; + border-width: 1px; + .border-radius(0 0 5px 5px); + .box-shadow(0 5px 10px rgba(0,0,0,.2)); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; + + // Allow for dropdowns to go bottom up (aka, dropup-menu) + &.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; + } + + // Dividers (basically an hr) within the dropdown + .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid @white; + + // IE7 needs a set width since we gave a height. Restricting just + // to IE7 to keep the 1px left/right space in other browsers. + // It is unclear where IE is getting the extra space that we need + // to negative-margin away, but so it goes. + *width: 100%; + *margin: -5px 0 5px; + } + + // Links within the dropdown menu + a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: @gray; + white-space: nowrap; + } +} + +// Hover state +.dropdown-menu li > a:hover, +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: @white; + text-decoration: none; + background-color: @linkColor; +} + +// Open state for the dropdown +.dropdown.open { + // IE7's z-index only goes to the nearest positioned ancestor, which would + // make the menu appear below buttons that appeared later on the page + *z-index: @zindexDropdown; + + .dropdown-toggle { + color: @white; + background: #ccc; + background: rgba(0,0,0,.3); + } + .dropdown-menu { + display: block; + } +} + +// Typeahead +.typeahead { + margin-top: 2px; // give it some space to breathe + .border-radius(4px); +} diff --git a/docs/source/_themes/yammerdoc/less/forms.less b/docs/source/_themes/yammerdoc/less/forms.less new file mode 100644 index 00000000000..d70d532e8c4 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/forms.less @@ -0,0 +1,515 @@ +// Forms.less +// Base styles for various input types, form layouts, and states +// ------------------------------------------------------------- + + +// GENERAL STYLES +// -------------- + +// Make all forms have space below them +form { + margin: 0 0 @baseLineHeight; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +// Groups of fields with labels on top (legends) +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: @baseLineHeight * 1.5; + font-size: @baseFontSize * 1.5; + line-height: @baseLineHeight * 2; + color: @grayDark; + border: 0; + border-bottom: 1px solid #eee; +} + +// Set font for forms +label, +input, +button, +select, +textarea { + #font > .sans-serif(@baseFontSize,normal,@baseLineHeight); +} + +// Identify controls by their labels +label { + display: block; + margin-bottom: 5px; + color: @grayDark; +} + +// Inputs, Textareas, Selects +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: @baseLineHeight; + padding: 4px; + margin-bottom: 9px; + font-size: @baseFontSize; + line-height: @baseLineHeight; + color: @gray; + border: 1px solid #ccc; + .border-radius(3px); +} +.uneditable-textarea { + width: auto; + height: auto; +} + +// Inputs within a label +label input, +label textarea, +label select { + display: block; +} + +// Mini reset for unique input types +input[type="image"], +input[type="checkbox"], +input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; /* IE7 */ + line-height: normal; + border: 0; + cursor: pointer; + border-radius: 0 e("\0/"); // Nuke border-radius for IE9 only +} + +// Reset the file input to browser defaults +input[type="file"] { + padding: initial; + line-height: initial; + border: initial; + background-color: @white; + background-color: initial; + .box-shadow(none); +} + +// Help out input buttons +input[type="button"], +input[type="reset"], +input[type="submit"] { + width: auto; + height: auto; +} + +// Set the height of select and file controls to match text inputs +select, +input[type="file"] { + height: 28px; /* In IE7, the height of the select element cannot be changed by height, only font-size */ + *margin-top: 4px; /* For IE7, add top margin to align select with labels */ + line-height: 28px; +} + +// Chrome on Linux and Mobile Safari need background-color +select { + width: 220px; // default input width + 10px of padding that doesn't get applied + background-color: @white; +} + +// Make multiple select elements height not fixed +select[multiple], +select[size] { + height: auto; +} + +// Remove shadow from image inputs +input[type="image"] { + .box-shadow(none); +} + +// Make textarea height behave +textarea { + height: auto; +} + +// Hidden inputs +input[type="hidden"] { + display: none; +} + + + +// CHECKBOXES & RADIOS +// ------------------- + +// Indent the labels to position radios/checkboxes as hanging +.radio, +.checkbox { + padding-left: 18px; +} +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} + +// Move the options list down to align with labels +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; // has to be padding because margin collaspes +} + +// Radios and checkboxes on same line +.radio.inline, +.checkbox.inline { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; // space out consecutive inline controls +} +// But don't forget to remove their padding on first-child +.controls > .radio.inline:first-child, +.controls > .checkbox.inline:first-child { + padding-top: 0; +} + + + +// FOCUS STATE +// ----------- + +input, +textarea { + .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); + @transition: border linear .2s, box-shadow linear .2s; + .transition(@transition); +} +input:focus, +textarea:focus { + border-color: rgba(82,168,236,.8); + @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6); + .box-shadow(@shadow); + outline: 0; + outline: thin dotted \9; /* IE6-8 */ +} +input[type="file"]:focus, +input[type="checkbox"]:focus, +select:focus { + .box-shadow(none); // override for file inputs + .tab-focus(); +} + + + +// INPUT SIZES +// ----------- + +// General classes for quick sizes +.input-mini { width: 60px; } +.input-small { width: 90px; } +.input-medium { width: 150px; } +.input-large { width: 210px; } +.input-xlarge { width: 270px; } +.input-xxlarge { width: 530px; } + +// Grid style input sizes +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} + + + +// GRID SIZING FOR INPUTS +// ---------------------- + +#inputGridSystem > .generate(@gridColumns, @gridColumnWidth, @gridGutterWidth); + + + + +// DISABLED STATE +// -------------- + +// Disabled and read-only inputs +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} + + + + +// FORM FIELD FEEDBACK STATES +// -------------------------- + +// Mixin for form field states +.formFieldState(@textColor: #555, @borderColor: #ccc, @backgroundColor: #f5f5f5) { + // Set the text color + > label, + .help-block, + .help-inline { + color: @textColor; + } + // Style inputs accordingly + input, + select, + textarea { + color: @textColor; + border-color: @borderColor; + &:focus { + border-color: darken(@borderColor, 10%); + .box-shadow(0 0 6px lighten(@borderColor, 20%)); + } + } + // Give a small background color for input-prepend/-append + .input-prepend .add-on, + .input-append .add-on { + color: @textColor; + background-color: @backgroundColor; + border-color: @textColor; + } +} +// Warning +.control-group.warning { + .formFieldState(@warningText, @warningText, @warningBackground); +} +// Error +.control-group.error { + .formFieldState(@errorText, @errorText, @errorBackground); +} +// Success +.control-group.success { + .formFieldState(@successText, @successText, @successBackground); +} + +// HTML5 invalid states +// Shares styles with the .control-group.error above +input:focus:required:invalid, +textarea:focus:required:invalid, +select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; + &:focus { + border-color: darken(#ee5f5b, 10%); + .box-shadow(0 0 6px lighten(#ee5f5b, 20%)); + } +} + + + +// FORM ACTIONS +// ------------ + +.form-actions { + padding: (@baseLineHeight - 1) 20px @baseLineHeight; + margin-top: @baseLineHeight; + margin-bottom: @baseLineHeight; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} + +// For text that needs to appear as an input but should not be an input +.uneditable-input { + display: block; + background-color: @white; + border-color: #eee; + .box-shadow(inset 0 1px 2px rgba(0,0,0,.025)); + cursor: not-allowed; +} + +// Placeholder text gets special styles; can't be bundled together though for some reason +.placeholder(@grayLight); + + + +// HELP TEXT +// --------- + +.help-block { + margin-top: 5px; + margin-bottom: 0; + color: @grayLight; +} + +.help-inline { + display: inline-block; + .ie7-inline-block(); + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} + + + +// INPUT GROUPS +// ------------ + +// Allow us to put symbols and text within the input field for a cleaner look +.input-prepend, +.input-append { + margin-bottom: 5px; + .clearfix(); // Clear the float to prevent wrapping + input, + .uneditable-input { + .border-radius(0 3px 3px 0); + &:focus { + position: relative; + z-index: 2; + } + } + .uneditable-input { + border-left-color: #ccc; + } + .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: @baseLineHeight; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: @baseLineHeight; + color: @grayLight; + text-align: center; + text-shadow: 0 1px 0 @white; + background-color: #f5f5f5; + border: 1px solid #ccc; + .border-radius(3px 0 0 3px); + } + .active { + background-color: lighten(@green, 30); + border-color: @green; + } +} +.input-prepend { + .add-on { + *margin-top: 1px; /* IE6-7 */ + } +} +.input-append { + input, + .uneditable-input { + float: left; + .border-radius(3px 0 0 3px); + } + .uneditable-input { + border-right-color: #ccc; + } + .add-on { + margin-right: 0; + margin-left: -1px; + .border-radius(0 3px 3px 0); + } + input:first-child { + // In IE7, having a hasLayout container (from clearfix's zoom:1) can make the first input + // inherit the sum of its ancestors' margins. + *margin-left: -160px; + + &+.add-on { + *margin-left: -21px; + } + } +} + + + +// SEARCH FORM +// ----------- + +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; // remove the default margin on all inputs + .border-radius(14px); +} + + + +// HORIZONTAL & VERTICAL FORMS +// --------------------------- + +// Common properties +// ----------------- + +.form-search, +.form-inline, +.form-horizontal { + input, + textarea, + select, + .help-inline, + .uneditable-input { + display: inline-block; + margin-bottom: 0; + } +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +// Make the prepend and append add-on vertical-align: middle; +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} + +// Margin to space out fieldsets +.control-group { + margin-bottom: @baseLineHeight / 2; +} + +// Horizontal-specific styles +// -------------------------- + +.form-horizontal { + // Legend collapses margin, so we're relegated to padding + legend + .control-group { + margin-top: @baseLineHeight; + -webkit-margin-top-collapse: separate; + } + // Increase spacing between groups + .control-group { + margin-bottom: @baseLineHeight; + .clearfix(); + } + // Float the labels left + .control-group > label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; + } + // Move over all input controls and content + .controls { + margin-left: 160px; + } + // Move over buttons in .form-actions to align with .controls + .form-actions { + padding-left: 160px; + } +} diff --git a/docs/source/_themes/yammerdoc/less/grid.less b/docs/source/_themes/yammerdoc/less/grid.less new file mode 100644 index 00000000000..4acb0a44ce6 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/grid.less @@ -0,0 +1,8 @@ +// GRID SYSTEM +// ----------- + +// Fixed (940px) +#gridSystem > .generate(@gridColumns, @gridColumnWidth, @gridGutterWidth); + +// Fluid (940px) +#fluidGridSystem > .generate(@gridColumns, @fluidGridColumnWidth, @fluidGridGutterWidth); diff --git a/docs/source/_themes/yammerdoc/less/hero-unit.less b/docs/source/_themes/yammerdoc/less/hero-unit.less new file mode 100644 index 00000000000..cba1cc46cff --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/hero-unit.less @@ -0,0 +1,20 @@ +// HERO UNIT +// --------- + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + .border-radius(6px); + h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + } + p { + font-size: 18px; + font-weight: 200; + line-height: @baseLineHeight * 1.5; + } +} diff --git a/docs/source/_themes/yammerdoc/less/labels.less b/docs/source/_themes/yammerdoc/less/labels.less new file mode 100644 index 00000000000..c0f42775020 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/labels.less @@ -0,0 +1,16 @@ +// LABELS +// ------ + +.label { + padding: 1px 3px 2px; + font-size: @baseFontSize * .75; + font-weight: bold; + color: @white; + text-transform: uppercase; + background-color: @grayLight; + .border-radius(3px); +} +.label-important { background-color: @errorText; } +.label-warning { background-color: @orange; } +.label-success { background-color: @successText; } +.label-info { background-color: @infoText; } diff --git a/docs/source/_themes/yammerdoc/less/layouts.less b/docs/source/_themes/yammerdoc/less/layouts.less new file mode 100644 index 00000000000..c8d358b24a1 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/layouts.less @@ -0,0 +1,17 @@ +// +// Layouts +// Fixed-width and fluid (with sidebar) layouts +// -------------------------------------------- + + +// Container (centered, fixed-width layouts) +.container { + .container-fixed(); +} + +// Fluid layouts (left aligned, with sidebar, min- & max-width content) +.container-fluid { + padding-left: @gridGutterWidth; + padding-right: @gridGutterWidth; + .clearfix(); +} \ No newline at end of file diff --git a/docs/source/_themes/yammerdoc/less/mixins.less b/docs/source/_themes/yammerdoc/less/mixins.less new file mode 100644 index 00000000000..545ccb9bad3 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/mixins.less @@ -0,0 +1,537 @@ +// Mixins.less +// Snippets of reusable CSS to develop faster and keep code readable +// ----------------------------------------------------------------- + + +// UTILITY MIXINS +// -------------------------------------------------- + +// Clearfix +// -------- +// For clearing floats like a boss h5bp.com/q +.clearfix() { + *zoom: 1; + &:before, + &:after { + display: table; + content: ""; + } + &:after { + clear: both; + } +} + +// Webkit-style focus +// ------------------ +.tab-focus() { + // Default + outline: thin dotted; + // Webkit + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +// Center-align a block level element +// ---------------------------------- +.center-block() { + display: block; + margin-left: auto; + margin-right: auto; +} + +// IE7 inline-block +// ---------------- +.ie7-inline-block() { + *display: inline; /* IE7 inline-block hack */ + *zoom: 1; +} + +// IE7 likes to collapse whitespace on either side of the inline-block elements. +// Ems because we're attempting to match the width of a space character. Left +// version is for form buttons, which typically come after other elements, and +// right version is for icons, which come before. Applying both is ok, but it will +// mean that space between those elements will be .6em (~2 space characters) in IE7, +// instead of the 1 space in other browsers. +.ie7-restore-left-whitespace() { + *margin-left: .3em; + + &:first-child { + *margin-left: 0; + } +} + +.ie7-restore-right-whitespace() { + *margin-right: .3em; + + &:last-child { + *margin-left: 0; + } +} + +// Sizing shortcuts +// ------------------------- +.size(@height: 5px, @width: 5px) { + width: @width; + height: @height; +} +.square(@size: 5px) { + .size(@size, @size); +} + +// Placeholder text +// ------------------------- +.placeholder(@color: @placeholderText) { + :-moz-placeholder { + color: @color; + } + ::-webkit-input-placeholder { + color: @color; + } +} + + + +// FONTS +// -------------------------------------------------- + +#font { + #family { + .serif() { + font-family: Georgia, "Times New Roman", Times, serif; + } + .sans-serif() { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + } + .monospace() { + font-family: Menlo, Monaco, "Courier New", monospace; + } + } + .shorthand(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + font-size: @size; + font-weight: @weight; + line-height: @lineHeight; + } + .serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .serif; + #font > .shorthand(@size, @weight, @lineHeight); + } + .sans-serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .sans-serif; + #font > .shorthand(@size, @weight, @lineHeight); + } + .monospace(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .monospace; + #font > .shorthand(@size, @weight, @lineHeight); + } +} + + + +// GRID SYSTEM +// -------------------------------------------------- + +// Site container +// ------------------------- +.container-fixed() { + width: @gridRowWidth; + margin-left: auto; + margin-right: auto; + .clearfix(); +} + +// Le grid system +// ------------------------- +#gridSystem { + // Setup the mixins to be used + .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, @columns) { + width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1)); + } + .offset(@gridColumnWidth, @gridGutterWidth, @columns) { + margin-left: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1)) + (@gridGutterWidth * 2); + } + .gridColumn(@gridGutterWidth) { + float: left; + margin-left: @gridGutterWidth; + } + // Take these values and mixins, and make 'em do their thang + .generate(@gridColumns, @gridColumnWidth, @gridGutterWidth) { + // Row surrounds the columns + .row { + margin-left: @gridGutterWidth * -1; + .clearfix(); + } + // Find all .span# classes within .row and give them the necessary properties for grid columns (supported by all browsers back to IE7, thanks @dhg) + [class*="span"] { + #gridSystem > .gridColumn(@gridGutterWidth); + } + // Default columns + .span1 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 1); } + .span2 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 2); } + .span3 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 3); } + .span4 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 4); } + .span5 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 5); } + .span6 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 6); } + .span7 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 7); } + .span8 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 8); } + .span9 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 9); } + .span10 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 10); } + .span11 { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 11); } + .span12, + .container { #gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 12); } + // Offset column options + .offset1 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 1); } + .offset2 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 2); } + .offset3 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 3); } + .offset4 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 4); } + .offset5 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 5); } + .offset6 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 6); } + .offset7 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 7); } + .offset8 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 8); } + .offset9 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 9); } + .offset10 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 10); } + .offset11 { #gridSystem > .offset(@gridColumnWidth, @gridGutterWidth, 11); } + } +} + +// Fluid grid system +// ------------------------- +#fluidGridSystem { + // Setup the mixins to be used + .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, @columns) { + width: 1% * (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)); + } + .gridColumn(@fluidGridGutterWidth) { + float: left; + margin-left: @fluidGridGutterWidth; + } + // Take these values and mixins, and make 'em do their thang + .generate(@gridColumns, @fluidGridColumnWidth, @fluidGridGutterWidth) { + // Row surrounds the columns + .row-fluid { + width: 100%; + .clearfix(); + + // Find all .span# classes within .row and give them the necessary properties for grid columns (supported by all browsers back to IE7, thanks @dhg) + > [class*="span"] { + #fluidGridSystem > .gridColumn(@fluidGridGutterWidth); + } + > [class*="span"]:first-child { + margin-left: 0; + } + // Default columns + .span1 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 1); } + .span2 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 2); } + .span3 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 3); } + .span4 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 4); } + .span5 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 5); } + .span6 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 6); } + .span7 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 7); } + .span8 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 8); } + .span9 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 9); } + .span10 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 10); } + .span11 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 11); } + .span12 { #fluidGridSystem > .columns(@fluidGridGutterWidth, @fluidGridColumnWidth, 12); } + } + } +} + + + +// Input grid system +// ------------------------- +#inputGridSystem { + .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, @columns) { + width: ((@gridColumnWidth) * @columns) + (@gridGutterWidth * (@columns - 1)) - 10; + } + .generate(@gridColumns, @gridColumnWidth, @gridGutterWidth) { + input, + textarea, + .uneditable-input { + &.span1 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 1); } + &.span2 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 2); } + &.span3 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 3); } + &.span4 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 4); } + &.span5 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 5); } + &.span6 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 6); } + &.span7 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 7); } + &.span8 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 8); } + &.span9 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 9); } + &.span10 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 10); } + &.span11 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 11); } + &.span12 { #inputGridSystem > .inputColumns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, 12); } + } + } +} + + + +// CSS3 PROPERTIES +// -------------------------------------------------- + +// Border Radius +.border-radius(@radius: 5px) { + -webkit-border-radius: @radius; + -moz-border-radius: @radius; + border-radius: @radius; +} + +// Drop shadows +.box-shadow(@shadow: 0 1px 3px rgba(0,0,0,.25)) { + -webkit-box-shadow: @shadow; + -moz-box-shadow: @shadow; + box-shadow: @shadow; +} + +// Transitions +.transition(@transition) { + -webkit-transition: @transition; + -moz-transition: @transition; + -ms-transition: @transition; + -o-transition: @transition; + transition: @transition; +} + +// Transformations +.rotate(@degrees) { + -webkit-transform: rotate(@degrees); + -moz-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); + -o-transform: rotate(@degrees); + transform: rotate(@degrees); +} +.scale(@ratio) { + -webkit-transform: scale(@ratio); + -moz-transform: scale(@ratio); + -ms-transform: scale(@ratio); + -o-transform: scale(@ratio); + transform: scale(@ratio); +} +.translate(@x: 0, @y: 0) { + -webkit-transform: translate(@x, @y); + -moz-transform: translate(@x, @y); + -ms-transform: translate(@x, @y); + -o-transform: translate(@x, @y); + transform: translate(@x, @y); +} +.skew(@x: 0, @y: 0) { + -webkit-transform: translate(@x, @y); + -moz-transform: translate(@x, @y); + -ms-transform: translate(@x, @y); + -o-transform: translate(@x, @y); + transform: translate(@x, @y); +} +.skew(@x: 0, @y: 0) { + -webkit-transform: skew(@x, @y); + -moz-transform: skew(@x, @y); + -ms-transform: skew(@x, @y); + -o-transform: skew(@x, @y); + transform: skew(@x, @y); +} + +// Background clipping +// Heads up: FF 3.6 and under need "padding" instead of "padding-box" +.background-clip(@clip) { + -webkit-background-clip: @clip; + -moz-background-clip: @clip; + background-clip: @clip; +} + +// Background sizing +.background-size(@size){ + -webkit-background-size: @size; + -moz-background-size: @size; + -o-background-size: @size; + background-size: @size; +} + + +// Box sizing +.box-sizing(@boxmodel) { + -webkit-box-sizing: @boxmodel; + -moz-box-sizing: @boxmodel; + box-sizing: @boxmodel; +} + +// User select +// For selecting text on the page +.user-select(@select) { + -webkit-user-select: @select; + -moz-user-select: @select; + -o-user-select: @select; + user-select: @select; +} + +// Resize anything +.resizable(@direction: both) { + resize: @direction; // Options: horizontal, vertical, both + overflow: auto; // Safari fix +} + +// CSS3 Content Columns +.content-columns(@columnCount, @columnGap: @gridColumnGutter) { + -webkit-column-count: @columnCount; + -moz-column-count: @columnCount; + column-count: @columnCount; + -webkit-column-gap: @columnGap; + -moz-column-gap: @columnGap; + column-gap: @columnGap; +} + +// Opacity +.opacity(@opacity: 100) { + opacity: @opacity / 100; + filter: e(%("alpha(opacity=%d)", @opacity)); +} + + + +// BACKGROUNDS +// -------------------------------------------------- + +// Add an alphatransparency value to any background or border color (via Elyse Holladay) +#translucent { + .background(@color: @white, @alpha: 1) { + background-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha); + } + .border(@color: @white, @alpha: 1) { + border-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha); + .background-clip(padding-box); + } +} + +// Gradient Bar Colors for buttons and alerts +.gradientBar(@primaryColor, @secondaryColor) { + #gradient > .vertical(@primaryColor, @secondaryColor); + border-color: @secondaryColor @secondaryColor darken(@secondaryColor, 15%); + border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fadein(rgba(0,0,0,.1), 15%); +} + +// Gradients +#gradient { + .horizontal(@startColor: #555, @endColor: #333) { + background-color: @endColor; + background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+ + background-image: -ms-linear-gradient(left, @startColor, @endColor); // IE10 + background-image: -webkit-gradient(linear, 0 0, 100% 0, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(left, @startColor, @endColor); // Le standard + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",@startColor,@endColor)); // IE9 and down + } + .vertical(@startColor: #555, @endColor: #333) { + background-color: mix(@startColor, @endColor, 60%); + background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+ + background-image: -ms-linear-gradient(top, @startColor, @endColor); // IE10 + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(top, @startColor, @endColor); // The standard + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",@startColor,@endColor)); // IE9 and down + } + .directional(@startColor: #555, @endColor: #333, @deg: 45deg) { + background-color: @endColor; + background-repeat: repeat-x; + background-image: -moz-linear-gradient(@deg, @startColor, @endColor); // FF 3.6+ + background-image: -ms-linear-gradient(@deg, @startColor, @endColor); // IE10 + background-image: -webkit-linear-gradient(@deg, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(@deg, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(@deg, @startColor, @endColor); // The standard + } + .vertical-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) { + background-color: mix(@midColor, @endColor, 80%); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor)); + background-image: -webkit-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: -moz-linear-gradient(top, @startColor, @midColor @colorStop, @endColor); + background-image: -ms-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: -o-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",@startColor,@endColor)); // IE9 and down, gets no color-stop at all for proper fallback + } + .radial(@innerColor: #555, @outerColor: #333) { + background-color: @outerColor; + background-image: -webkit-gradient(radial, center center, 0, center center, 460, from(@innerColor), to(@outerColor)); + background-image: -webkit-radial-gradient(circle, @innerColor, @outerColor); + background-image: -moz-radial-gradient(circle, @innerColor, @outerColor); + background-image: -ms-radial-gradient(circle, @innerColor, @outerColor); + background-repeat: no-repeat; + // Opera cannot do radial gradients yet + } + .striped(@color, @angle: -45deg) { + background-color: @color; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + } +} +// Reset filters for IE +.reset-filter() { + filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); +} + + +// Mixin for generating button backgrounds +// --------------------------------------- +.buttonBackground(@startColor, @endColor) { + // gradientBar will set the background to a pleasing blend of these, to support IE<=9 + .gradientBar(@startColor, @endColor); + .reset-filter(); + + // in these cases the gradient won't cover the background, so we override + &:hover, &:active, &.active, &.disabled, &[disabled] { + background-color: @endColor; + } + + // IE 7 + 8 can't handle box-shadow to show active, so we darken a bit ourselves + &:active, + &.active { + background-color: darken(@endColor, 10%) e("\9"); + } +} + + +// COMPONENT MIXINS +// -------------------------------------------------- + +// POPOVER ARROWS +// ------------------------- +// For tipsies and popovers +#popoverArrow { + .top(@arrowWidth: 5px) { + bottom: 0; + left: 50%; + margin-left: -@arrowWidth; + border-left: @arrowWidth solid transparent; + border-right: @arrowWidth solid transparent; + border-top: @arrowWidth solid @black; + } + .left(@arrowWidth: 5px) { + top: 50%; + right: 0; + margin-top: -@arrowWidth; + border-top: @arrowWidth solid transparent; + border-bottom: @arrowWidth solid transparent; + border-left: @arrowWidth solid @black; + } + .bottom(@arrowWidth: 5px) { + top: 0; + left: 50%; + margin-left: -@arrowWidth; + border-left: @arrowWidth solid transparent; + border-right: @arrowWidth solid transparent; + border-bottom: @arrowWidth solid @black; + } + .right(@arrowWidth: 5px) { + top: 50%; + left: 0; + margin-top: -@arrowWidth; + border-top: @arrowWidth solid transparent; + border-bottom: @arrowWidth solid transparent; + border-right: @arrowWidth solid @black; + } +} diff --git a/docs/source/_themes/yammerdoc/less/modals.less b/docs/source/_themes/yammerdoc/less/modals.less new file mode 100644 index 00000000000..aa14675edee --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/modals.less @@ -0,0 +1,72 @@ +// MODALS +// ------ + +.modal-open { + .dropdown-menu { z-index: @zindexDropdown + @zindexModal; } + .dropdown.open { *z-index: @zindexDropdown + @zindexModal; } + .popover { z-index: @zindexPopover + @zindexModal; } + .tooltip { z-index: @zindexTooltip + @zindexModal; } +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: @zindexModalBackdrop; + background-color: @black; + // Fade for backdrop + &.fade { opacity: 0; } +} + +.modal-backdrop, +.modal-backdrop.fade.in { + .opacity(80); +} + +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: @zindexModal; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: @white; + border: 1px solid #999; + border: 1px solid rgba(0,0,0,.3); + *border: 1px solid #999; /* IE6-7 */ + .border-radius(6px); + .box-shadow(0 3px 7px rgba(0,0,0,0.3)); + .background-clip(padding-box); + &.fade { + .transition(e('opacity .3s linear, top .3s ease-out')); + top: -25%; + } + &.fade.in { top: 50%; } +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; + // Close icon + .close { margin-top: 2px; } +} +.modal-body { + padding: 15px; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + .border-radius(0 0 6px 6px); + .box-shadow(inset 0 1px 0 @white); + .clearfix(); + .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs + } +} diff --git a/docs/source/_themes/yammerdoc/less/navbar.less b/docs/source/_themes/yammerdoc/less/navbar.less new file mode 100644 index 00000000000..93c0400b6ef --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/navbar.less @@ -0,0 +1,292 @@ +// NAVBAR (FIXED AND STATIC) +// ------------------------- + + +// COMMON STYLES +// ------------- + +.navbar { + overflow: visible; + margin-bottom: @baseLineHeight; +} + +// Gradient is applied to it's own element because overflow visible is not honored by IE when filter is present +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + #gradient > .vertical(@navbarBackgroundHighlight, @navbarBackground); + .border-radius(4px); + @shadow: 0 1px 3px rgba(0,0,0,.25), inset 0 -1px 0 rgba(0,0,0,.1); + .box-shadow(@shadow); +} + +// Navbar button for toggling navbar items in responsive layouts +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + .buttonBackground(@navbarBackgroundHighlight, @navbarBackground); + @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075); + .box-shadow(@shadow); +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + .border-radius(1px); + .box-shadow(0 1px 0 rgba(0,0,0,.25)); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +// Override the default collapsed state +.nav-collapse.collapse { + height: auto; +} + + +// Brand, links, text, and buttons +.navbar { + // Hover and active states + .brand:hover { + text-decoration: none; + } + // Website or project name + .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; // negative indent to left-align the text down the page + font-size: 20px; + font-weight: 200; + line-height: 1; + color: @white; + } + // Plain text in topbar + .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: @navbarText; + a:hover { + color: @white; + background-color: transparent; + } + } + // Buttons in navbar + .btn, + .btn-group { + margin-top: 5px; // make buttons vertically centered in navbar + } + .btn-group .btn { + margin-top: 0; + } +} + +// Navbar forms +.navbar-form { + margin-bottom: 0; // remove default bottom margin + .clearfix(); + input, + select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; + } + .radio, + .checkbox { + margin-top: 5px; + } + input[type="image"], + input[type="checkbox"], + input[type="radio"] { + margin-top: 3px; + } +} + +// Navbar search +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; + .search-query { + padding: 4px 9px; + #font > .sans-serif(13px, normal, 1); + color: @white; + color: rgba(255,255,255,.75); + background: #666; + background: rgba(255,255,255,.3); + border: 1px solid #111; + @shadow: inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0px rgba(255,255,255,.15); + .box-shadow(@shadow); + .transition(none); + + // Placeholder text gets special styles; can't be bundled together though for some reason + .placeholder(@grayLighter); + + // Hover states + &:hover { + color: @white; + background-color: @grayLight; + background-color: rgba(255,255,255,.5); + } + // Focus states (we use .focused since IE8 and down doesn't support :focus) + &:focus, + &.focused { + padding: 5px 10px; + color: @grayDark; + text-shadow: 0 1px 0 @white; + background-color: @white; + border: 0; + .box-shadow(0 0 3px rgba(0,0,0,.15)); + outline: 0; + } + } +} + + +// FIXED NAVBAR +// ------------ + +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: @zindexFixedNavbar; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + .border-radius(0); +} + + +// NAVIGATION +// ---------- + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; // redeclare due to specificity +} +.navbar .nav > li { + display: block; + float: left; +} + +// Links +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: @navbarLinkColor; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); +} +// Hover +.navbar .nav > li > a:hover { + background-color: transparent; + color: @navbarLinkColorHover; + text-decoration: none; +} + +// Active nav items +.navbar .nav .active > a, +.navbar .nav .active > a:hover { + color: @navbarLinkColorHover; + text-decoration: none; + background-color: @navbarBackground; + background-color: rgba(0,0,0,.5); +} + +// Dividers (basically a vertical hr) +.navbar .divider-vertical { + height: @navbarHeight; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: @navbarBackground; + border-right: 1px solid @navbarBackgroundHighlight; +} + +// Secondary (floated right) nav in topbar +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} + + + +// Dropdown menus +// -------------- + +// Menu position and menu carets +.navbar .dropdown-menu { + margin-top: 1px; + .border-radius(4px); + &:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0,0,0,.2); + position: absolute; + top: -7px; + left: 9px; + } + &:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid @white; + position: absolute; + top: -6px; + left: 10px; + } +} + +// Dropdown toggle caret +.navbar .nav .dropdown-toggle .caret, +.navbar .nav .open.dropdown .caret { + border-top-color: @white; +} +.navbar .nav .active .caret { + .opacity(100); +} + +// Remove background color from open dropdown +.navbar .nav .open > .dropdown-toggle, +.navbar .nav .active > .dropdown-toggle, +.navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} + +// Dropdown link on hover +.navbar .nav .active > .dropdown-toggle:hover { + color: @white; +} + +// Right aligned menus need alt position +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; + &:before { + left: auto; + right: 12px; + } + &:after { + left: auto; + right: 13px; + } +} \ No newline at end of file diff --git a/docs/source/_themes/yammerdoc/less/navs.less b/docs/source/_themes/yammerdoc/less/navs.less new file mode 100644 index 00000000000..dfb2996f098 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/navs.less @@ -0,0 +1,343 @@ +// NAVIGATIONS +// ----------- + + + +// BASE CLASS +// ---------- + +.nav { + margin-left: 0; + margin-bottom: @baseLineHeight; + list-style: none; +} + +// Make links block level +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: @grayLighter; +} + + + +// NAV LIST +// -------- + +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, +.nav-list .nav-header { + display: block; + padding: 3px 15px; + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255,255,255,.5); +} +.nav-list .nav-header { + font-size: 11px; + font-weight: bold; + line-height: @baseLineHeight; + color: @grayLight; + text-transform: uppercase; +} +.nav-list > li + .nav-header { + margin-top: 9px; +} +.nav-list .active > a { + color: @white; + text-shadow: 0 -1px 0 rgba(0,0,0,.2); + background-color: @linkColor; +} +.nav-list .icon { + margin-right: 2px; +} + + + +// TABS AND PILLS +// ------------- + +// Common styles +.nav-tabs, +.nav-pills { + .clearfix(); +} +.nav-tabs > li, +.nav-pills > li { + float: left; +} +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; // keeps the overall height an even number +} + +// TABS +// ---- + +// Give the tabs something to sit on +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +// Make the list-items overlay the bottom border +.nav-tabs > li { + margin-bottom: -1px; +} + +// Actual tabs (as links) +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + .border-radius(4px 4px 0 0); + &:hover { + border-color: @grayLighter @grayLighter #ddd; + } +} +// Active state, and it's :hover to override normal :hover +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover { + color: @gray; + background-color: @white; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} + +// PILLS +// ----- + +// Links rendered as pills +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + .border-radius(5px); +} + +// Active state +.nav-pills .active > a, +.nav-pills .active > a:hover { + color: @white; + background-color: @linkColor; +} + + + +// STACKED NAV +// ----------- + +// Stacked tabs and pills +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; // no need for the gap between nav items +} + +// Tabs +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + .border-radius(0); +} +.nav-tabs.nav-stacked > li:first-child > a { + .border-radius(4px 4px 0 0); +} +.nav-tabs.nav-stacked > li:last-child > a { + .border-radius(0 0 4px 4px); +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} + +// Pills +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; // decrease margin to match sizing of stacked tabs +} + + + +// DROPDOWNS +// --------- + +// Position the menu +.nav-tabs .dropdown-menu, +.nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + .border-radius(4px); +} + +// Default dropdown links +// ------------------------- +// Make carets use linkColor to start +.nav-tabs .dropdown-toggle .caret, +.nav-pills .dropdown-toggle .caret { + border-top-color: @linkColor; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, +.nav-pills .dropdown-toggle:hover .caret { + border-top-color: @linkColorHover; +} + +// Active dropdown links +// ------------------------- +.nav-tabs .active .dropdown-toggle .caret, +.nav-pills .active .dropdown-toggle .caret { + border-top-color: @grayDark; +} + +// Active:hover dropdown links +// ------------------------- +.nav > .dropdown.active > a:hover { + color: @black; + cursor: pointer; +} + +// Open dropdowns +// ------------------------- +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > .open.active > a:hover { + color: @white; + background-color: @grayLight; + border-color: @grayLight; +} +.nav .open .caret, +.nav .open.active .caret, +.nav .open a:hover .caret { + border-top-color: @white; + .opacity(100); +} + +// Dropdowns in stacked tabs +.tabs-stacked .open > a:hover { + border-color: @grayLight; +} + + + +// TABBABLE +// -------- + + +// COMMON STYLES +// ------------- + +// Clear any floats +.tabbable { + .clearfix(); +} + +// Remove border on bottom, left, right +.tabs-below .nav-tabs, +.tabs-right .nav-tabs, +.tabs-left .nav-tabs { + border-bottom: 0; +} + +// Show/hide tabbable areas +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} +.tab-content > .active, +.pill-content > .active { + display: block; +} + + +// BOTTOM +// ------ + +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + .border-radius(0 0 4px 4px); + &:hover { + border-bottom-color: transparent; + border-top-color: #ddd; + } +} +.tabs-below .nav-tabs .active > a, +.tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} + +// LEFT & RIGHT +// ------------ + +// Common styles +.tabs-left .nav-tabs > li, +.tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, +.tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +// Tabs on the left +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + .border-radius(4px 0 0 4px); +} +.tabs-left .nav-tabs > li > a:hover { + border-color: @grayLighter #ddd @grayLighter @grayLighter; +} +.tabs-left .nav-tabs .active > a, +.tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: @white; +} + +// Tabs on the right +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + .border-radius(0 4px 4px 0); +} +.tabs-right .nav-tabs > li > a:hover { + border-color: @grayLighter @grayLighter @grayLighter #ddd; +} +.tabs-right .nav-tabs .active > a, +.tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: @white; +} diff --git a/docs/source/_themes/yammerdoc/less/pager.less b/docs/source/_themes/yammerdoc/less/pager.less new file mode 100644 index 00000000000..104e41cab01 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/pager.less @@ -0,0 +1,30 @@ +// PAGER +// ----- + +.pager { + margin-left: 0; + margin-bottom: @baseLineHeight; + list-style: none; + text-align: center; + .clearfix(); +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + .border-radius(15px); +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} diff --git a/docs/source/_themes/yammerdoc/less/pagination.less b/docs/source/_themes/yammerdoc/less/pagination.less new file mode 100644 index 00000000000..de578075944 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/pagination.less @@ -0,0 +1,55 @@ +// PAGINATION +// ---------- + +.pagination { + height: @baseLineHeight * 2; + margin: @baseLineHeight 0; + } +.pagination ul { + display: inline-block; + .ie7-inline-block(); + margin-left: 0; + margin-bottom: 0; + .border-radius(3px); + .box-shadow(0 1px 2px rgba(0,0,0,.05)); +} +.pagination li { + display: inline; + } +.pagination a { + float: left; + padding: 0 14px; + line-height: (@baseLineHeight * 2) - 2; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, +.pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: @grayLight; + cursor: default; +} +.pagination .disabled a, +.pagination .disabled a:hover { + color: @grayLight; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + .border-radius(3px 0 0 3px); +} +.pagination li:last-child a { + .border-radius(0 3px 3px 0); +} + +// Centered +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} diff --git a/docs/source/_themes/yammerdoc/less/patterns.less b/docs/source/_themes/yammerdoc/less/patterns.less new file mode 100644 index 00000000000..d94b921e422 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/patterns.less @@ -0,0 +1,13 @@ +// Patterns.less +// Repeatable UI elements outside the base styles provided from the scaffolding +// ---------------------------------------------------------------------------- + + +// PAGE HEADERS +// ------------ + +footer { + padding-top: @baseLineHeight - 1; + margin-top: @baseLineHeight - 1; + border-top: 1px solid #eee; +} diff --git a/docs/source/_themes/yammerdoc/less/popovers.less b/docs/source/_themes/yammerdoc/less/popovers.less new file mode 100644 index 00000000000..558d99ec999 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/popovers.less @@ -0,0 +1,49 @@ +// POPOVERS +// -------- + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: @zindexPopover; + display: none; + padding: 5px; + &.top { margin-top: -5px; } + &.right { margin-left: 5px; } + &.bottom { margin-top: 5px; } + &.left { margin-left: -5px; } + &.top .arrow { #popoverArrow > .top(); } + &.right .arrow { #popoverArrow > .right(); } + &.bottom .arrow { #popoverArrow > .bottom(); } + &.left .arrow { #popoverArrow > .left(); } + .arrow { + position: absolute; + width: 0; + height: 0; + } +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: @black; // has to be full background declaration for IE fallback + background: rgba(0,0,0,.8); + .border-radius(6px); + .box-shadow(0 3px 7px rgba(0,0,0,0.3)); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom:1px solid #eee; + .border-radius(3px 3px 0 0); +} +.popover-content { + padding: 14px; + background-color: @white; + .border-radius(0 0 3px 3px); + .background-clip(padding-box); + p, ul, ol { + margin-bottom: 0; + } +} diff --git a/docs/source/_themes/yammerdoc/less/print.less b/docs/source/_themes/yammerdoc/less/print.less new file mode 100644 index 00000000000..4fd45e28220 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/print.less @@ -0,0 +1,18 @@ +/*! + * Bootstrap @VERSION for Print + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + * Date: @DATE + */ + + +// HIDE UNECESSARY COMPONENTS +// -------------------------- + +.navbar-fixed { + display: none; +} \ No newline at end of file diff --git a/docs/source/_themes/yammerdoc/less/progress-bars.less b/docs/source/_themes/yammerdoc/less/progress-bars.less new file mode 100644 index 00000000000..c3144e1bd74 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/progress-bars.less @@ -0,0 +1,95 @@ +// PROGRESS BARS +// ------------- + + +// ANIMATIONS +// ---------- + +// Webkit +@-webkit-keyframes progress-bar-stripes { + from { background-position: 0 0; } + to { background-position: 40px 0; } +} + +// Firefox +@-moz-keyframes progress-bar-stripes { + from { background-position: 0 0; } + to { background-position: 40px 0; } +} + +// Spec +@keyframes progress-bar-stripes { + from { background-position: 0 0; } + to { background-position: 40px 0; } +} + + + +// THE BARS +// -------- + +// Outer container +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + #gradient > .vertical(#f5f5f5, #f9f9f9); + .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); + .border-radius(4px); +} + +// Bar of progress +.progress .bar { + width: 0%; + height: 18px; + color: @white; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + #gradient > .vertical(#149bdf, #0480be); + .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15)); + .box-sizing(border-box); + .transition(width .6s ease); +} + +// Striped bars +.progress-striped .bar { + #gradient > .striped(#62c462); + .background-size(40px 40px); +} + +// Call animation for the active one +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + + + +// COLORS +// ------ + +// Danger (red) +.progress-danger .bar { + #gradient > .vertical(#ee5f5b, #c43c35); +} +.progress-danger.progress-striped .bar { + #gradient > .striped(#ee5f5b); +} + +// Success (green) +.progress-success .bar { + #gradient > .vertical(#62c462, #57a957); +} +.progress-success.progress-striped .bar { + #gradient > .striped(#62c462); +} + +// Info (teal) +.progress-info .bar { + #gradient > .vertical(#5bc0de, #339bb9); +} +.progress-info.progress-striped .bar { + #gradient > .striped(#5bc0de); +} diff --git a/docs/source/_themes/yammerdoc/less/reset.less b/docs/source/_themes/yammerdoc/less/reset.less new file mode 100644 index 00000000000..28d8eb60ca4 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/reset.less @@ -0,0 +1,126 @@ +// Reset.less +// Adapted from Normalize.css http://github.com/necolas/normalize.css +// ------------------------------------------------------------------------ + +// Display in IE6-9 and FF3 +// ------------------------- + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +// Display block in IE6-9 and FF3 +// ------------------------- + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +// Prevents modern browsers from displaying 'audio' without controls +// ------------------------- + +audio:not([controls]) { + display: none; +} + +// Base settings +// ------------------------- + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +// Focus states +a:focus { + .tab-focus(); +} +// Hover & Active +a:hover, +a:active { + outline: 0; +} + +// Prevents sub and sup affecting line-height in all browsers +// ------------------------- + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} + +// Img border in a's and image quality +// ------------------------- + +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} + +// Forms +// ------------------------- + +// Font size in all browsers, margin changes, misc consistency +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, +input { + *overflow: visible; // Inner spacing ie IE6/7 + line-height: normal; // FF3/4 have !important on line-height in UA stylesheet +} +button::-moz-focus-inner, +input::-moz-focus-inner { // Inner padding and border oddities in FF3/4 + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; // Cursors on all buttons applied consistently + -webkit-appearance: button; // Style clicable inputs in iOS +} +input[type="search"] { // Appearance in Safari/Chrome + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5 +} +textarea { + overflow: auto; // Remove vertical scrollbar in IE6-9 + vertical-align: top; // Readability and alignment cross-browser +} diff --git a/docs/source/_themes/yammerdoc/less/responsive.less b/docs/source/_themes/yammerdoc/less/responsive.less new file mode 100644 index 00000000000..7d494a35765 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/responsive.less @@ -0,0 +1,323 @@ +/*! + * Bootstrap Responsive v2.0.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +// Responsive.less +// For phone and tablet devices +// ------------------------------------------------------------- + + +// REPEAT VARIABLES & MIXINS +// ------------------------- +// Required since we compile the responsive stuff separately + +@import "variables.less"; // Modify this for custom colors, font-sizes, etc +@import "mixins.less"; + + +// RESPONSIVE CLASSES +// ------------------ + +// Hide from screenreaders and browsers +// Credit: HTML5 Boilerplate +.hidden { + display: none; + visibility: hidden; +} + + + +// UP TO LANDSCAPE PHONE +// --------------------- + +@media (max-width: 480px) { + + // Smooth out the collapsing/expanding nav + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); // activate the GPU + } + + // Block level the page header small tag for readability + .page-header h1 small { + display: block; + line-height: @baseLineHeight; + } + + // Make span* classes full width + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + height: 28px; /* Make inputs at least the height of their button counterpart */ + /* Makes inputs behave like true block-level elements */ + -webkit-box-sizing: border-box; /* Older Webkit */ + -moz-box-sizing: border-box; /* Older FF */ + -ms-box-sizing: border-box; /* IE8 */ + box-sizing: border-box; /* CSS3 spec*/ + } + // But don't let it screw up prepend/append inputs + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + width: auto; + } + + // Update checkboxes for iOS + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + + // Remove the horizontal form styles + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + // Move over all input controls and content + .form-horizontal .controls { + margin-left: 0; + } + // Move the options list down to align with labels + .form-horizontal .control-list { + padding-top: 0; // has to be padding because margin collaspes + } + // Move over buttons in .form-actions to align with .controls + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + + // Modals + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + &.fade.in { top: auto; } + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + + // Carousel + .carousel-caption { + position: static; + } + +} + + + +// LANDSCAPE PHONE TO SMALL DESKTOP & PORTRAIT TABLET +// -------------------------------------------------- + +@media (max-width: 768px) { + // GRID & CONTAINERS + // ----------------- + // Remove width from containers + .container { + width: auto; + padding: 0 20px; + } + // Fluid rows + .row-fluid { + width: 100%; + } + // Undo negative margin on rows + .row { + margin-left: 0; + } + // Make all columns even + .row > [class*="span"], + .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} + + + +// PORTRAIT TABLET TO DEFAULT DESKTOP +// ---------------------------------- + +@media (min-width: 768px) and (max-width: 980px) { + + // Fixed grid + #gridSystem > .generate(12, 42px, 20px); + + // Fluid grid + #fluidGridSystem > .generate(12, 5.801104972%, 2.762430939%); + + // Input grid + #inputGridSystem > .generate(12, 42px, 20px); + +} + + + +// TABLETS AND BELOW +// ----------------- +@media (max-width: 980px) { + + // UNFIX THE TOPBAR + // ---------------- + // Remove any padding from the body + body { + padding-top: 0; + } + // Unfix the navbar + .navbar-fixed-top { + position: static; + margin-bottom: @baseLineHeight; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + // Account for brand name + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + // Nav collapse clears brand + .navbar .nav-collapse { + clear: left; + } + // Block-level the nav + .navbar .nav { + float: none; + margin: 0 0 (@baseLineHeight / 2); + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + // Nav and dropdown links in navbar + .navbar .nav > li > a, + .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: @navbarLinkColor; + .border-radius(3px); + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, + .navbar .dropdown-menu a:hover { + background-color: @navbarBackground; + } + // Dropdowns in the navbar + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + .border-radius(0); + .box-shadow(none); + } + .navbar .dropdown-menu:before, + .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + // Forms in navbar + .navbar-form, + .navbar-search { + float: none; + padding: (@baseLineHeight / 2) 15px; + margin: (@baseLineHeight / 2) 0; + border-top: 1px solid @navbarBackground; + border-bottom: 1px solid @navbarBackground; + @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); + .box-shadow(@shadow); + } + // Pull right (secondary) nav content + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + // Static navbar + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + // Navbar button + .btn-navbar { + display: block; + } + + // Hide everything in the navbar save .brand and toggle button */ + .nav-collapse { + overflow: hidden; + height: 0; + } +} + + + +// DEFAULT DESKTOP +// --------------- + +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} + + + +// LARGE DESKTOP & UP +// ------------------ + +@media (min-width: 1200px) { + + // Fixed grid + #gridSystem > .generate(12, 70px, 30px); + + // Fluid grid + #fluidGridSystem > .generate(12, 5.982905983%, 2.564102564%); + + // Input grid + #inputGridSystem > .generate(12, 70px, 30px); + + // Thumbnails + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } + +} diff --git a/docs/source/_themes/yammerdoc/less/scaffolding.less b/docs/source/_themes/yammerdoc/less/scaffolding.less new file mode 100644 index 00000000000..47ce53818b6 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/scaffolding.less @@ -0,0 +1,29 @@ +// Scaffolding +// Basic and global styles for generating a grid system, structural layout, and page templates +// ------------------------------------------------------------------------------------------- + + +// STRUCTURAL LAYOUT +// ----------------- + +body { + margin: 0; + font-family: @baseFontFamily; + font-size: @baseFontSize; + line-height: @baseLineHeight; + color: @textColor; + background-color: @white; +} + + +// LINKS +// ----- + +a { + color: @linkColor; + text-decoration: none; +} +a:hover { + color: @linkColorHover; + text-decoration: underline; +} diff --git a/docs/source/_themes/yammerdoc/less/sprites.less b/docs/source/_themes/yammerdoc/less/sprites.less new file mode 100644 index 00000000000..a56216c71c6 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/sprites.less @@ -0,0 +1,156 @@ +// SPRITES +// Glyphs and icons for buttons, nav, and more +// ------------------------------------------- + + +// ICONS +// ----- + +// All icons receive the styles of the tag with a base class +// of .i and are then given a unique class to add width, height, +// and background-position. Your resulting HTML will look like +// . + +// For the white version of the icons, just add the .icon-white class: +// + +[class^="icon-"] { + display: inline-block; + width: 14px; + height: 14px; + vertical-align: text-top; + background-image: url(../img/glyphicons-halflings.png); + background-position: 14px 14px; + background-repeat: no-repeat; + + .ie7-restore-right-whitespace(); +} +.icon-white { + background-image: url(../img/glyphicons-halflings-white.png); +} + +.icon-glass { background-position: 0 0; } +.icon-music { background-position: -24px 0; } +.icon-search { background-position: -48px 0; } +.icon-envelope { background-position: -72px 0; } +.icon-heart { background-position: -96px 0; } +.icon-star { background-position: -120px 0; } +.icon-star-empty { background-position: -144px 0; } +.icon-user { background-position: -168px 0; } +.icon-film { background-position: -192px 0; } +.icon-th-large { background-position: -216px 0; } +.icon-th { background-position: -240px 0; } +.icon-th-list { background-position: -264px 0; } +.icon-ok { background-position: -288px 0; } +.icon-remove { background-position: -312px 0; } +.icon-zoom-in { background-position: -336px 0; } +.icon-zoom-out { background-position: -360px 0; } +.icon-off { background-position: -384px 0; } +.icon-signal { background-position: -408px 0; } +.icon-cog { background-position: -432px 0; } +.icon-trash { background-position: -456px 0; } + +.icon-home { background-position: 0 -24px; } +.icon-file { background-position: -24px -24px; } +.icon-time { background-position: -48px -24px; } +.icon-road { background-position: -72px -24px; } +.icon-download-alt { background-position: -96px -24px; } +.icon-download { background-position: -120px -24px; } +.icon-upload { background-position: -144px -24px; } +.icon-inbox { background-position: -168px -24px; } +.icon-play-circle { background-position: -192px -24px; } +.icon-repeat { background-position: -216px -24px; } +.icon-refresh { background-position: -240px -24px; } +.icon-list-alt { background-position: -264px -24px; } +.icon-lock { background-position: -287px -24px; } // 1px off +.icon-flag { background-position: -312px -24px; } +.icon-headphones { background-position: -336px -24px; } +.icon-volume-off { background-position: -360px -24px; } +.icon-volume-down { background-position: -384px -24px; } +.icon-volume-up { background-position: -408px -24px; } +.icon-qrcode { background-position: -432px -24px; } +.icon-barcode { background-position: -456px -24px; } + +.icon-tag { background-position: 0 -48px; } +.icon-tags { background-position: -25px -48px; } // 1px off +.icon-book { background-position: -48px -48px; } +.icon-bookmark { background-position: -72px -48px; } +.icon-print { background-position: -96px -48px; } +.icon-camera { background-position: -120px -48px; } +.icon-font { background-position: -144px -48px; } +.icon-bold { background-position: -167px -48px; } // 1px off +.icon-italic { background-position: -192px -48px; } +.icon-text-height { background-position: -216px -48px; } +.icon-text-width { background-position: -240px -48px; } +.icon-align-left { background-position: -264px -48px; } +.icon-align-center { background-position: -288px -48px; } +.icon-align-right { background-position: -312px -48px; } +.icon-align-justify { background-position: -336px -48px; } +.icon-list { background-position: -360px -48px; } +.icon-indent-left { background-position: -384px -48px; } +.icon-indent-right { background-position: -408px -48px; } +.icon-facetime-video { background-position: -432px -48px; } +.icon-picture { background-position: -456px -48px; } + +.icon-pencil { background-position: 0 -72px; } +.icon-map-marker { background-position: -24px -72px; } +.icon-adjust { background-position: -48px -72px; } +.icon-tint { background-position: -72px -72px; } +.icon-edit { background-position: -96px -72px; } +.icon-share { background-position: -120px -72px; } +.icon-check { background-position: -144px -72px; } +.icon-move { background-position: -168px -72px; } +.icon-step-backward { background-position: -192px -72px; } +.icon-fast-backward { background-position: -216px -72px; } +.icon-backward { background-position: -240px -72px; } +.icon-play { background-position: -264px -72px; } +.icon-pause { background-position: -288px -72px; } +.icon-stop { background-position: -312px -72px; } +.icon-forward { background-position: -336px -72px; } +.icon-fast-forward { background-position: -360px -72px; } +.icon-step-forward { background-position: -384px -72px; } +.icon-eject { background-position: -408px -72px; } +.icon-chevron-left { background-position: -432px -72px; } +.icon-chevron-right { background-position: -456px -72px; } + +.icon-plus-sign { background-position: 0 -96px; } +.icon-minus-sign { background-position: -24px -96px; } +.icon-remove-sign { background-position: -48px -96px; } +.icon-ok-sign { background-position: -72px -96px; } +.icon-question-sign { background-position: -96px -96px; } +.icon-info-sign { background-position: -120px -96px; } +.icon-screenshot { background-position: -144px -96px; } +.icon-remove-circle { background-position: -168px -96px; } +.icon-ok-circle { background-position: -192px -96px; } +.icon-ban-circle { background-position: -216px -96px; } +.icon-arrow-left { background-position: -240px -96px; } +.icon-arrow-right { background-position: -264px -96px; } +.icon-arrow-up { background-position: -289px -96px; } // 1px off +.icon-arrow-down { background-position: -312px -96px; } +.icon-share-alt { background-position: -336px -96px; } +.icon-resize-full { background-position: -360px -96px; } +.icon-resize-small { background-position: -384px -96px; } +.icon-plus { background-position: -408px -96px; } +.icon-minus { background-position: -433px -96px; } +.icon-asterisk { background-position: -456px -96px; } + +.icon-exclamation-sign { background-position: 0 -120px; } +.icon-gift { background-position: -24px -120px; } +.icon-leaf { background-position: -48px -120px; } +.icon-fire { background-position: -72px -120px; } +.icon-eye-open { background-position: -96px -120px; } +.icon-eye-close { background-position: -120px -120px; } +.icon-warning-sign { background-position: -144px -120px; } +.icon-plane { background-position: -168px -120px; } +.icon-calendar { background-position: -192px -120px; } +.icon-random { background-position: -216px -120px; } +.icon-comment { background-position: -240px -120px; } +.icon-magnet { background-position: -264px -120px; } +.icon-chevron-up { background-position: -288px -120px; } +.icon-chevron-down { background-position: -313px -119px; } // 1px off +.icon-retweet { background-position: -336px -120px; } +.icon-shopping-cart { background-position: -360px -120px; } +.icon-folder-close { background-position: -384px -120px; } +.icon-folder-open { background-position: -408px -120px; } +.icon-resize-vertical { background-position: -432px -119px; } +.icon-resize-horizontal { background-position: -456px -118px; } diff --git a/docs/source/_themes/yammerdoc/less/tables.less b/docs/source/_themes/yammerdoc/less/tables.less new file mode 100644 index 00000000000..c069ed58862 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/tables.less @@ -0,0 +1,139 @@ +// +// Tables.less +// Tables for, you guessed it, tabular data +// ---------------------------------------- + + +// BASE TABLES +// ----------------- + +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} + +// BASELINE STYLES +// --------------- + +.table { + width: 100%; + margin-bottom: @baseLineHeight; + // Cells + th, + td { + padding: 8px; + line-height: @baseLineHeight; + text-align: left; + border-top: 1px solid #ddd; + } + th { + font-weight: bold; + vertical-align: bottom; + } + td { + vertical-align: top; + } + // Remove top border from thead by default + thead:first-child tr th, + thead:first-child tr td { + border-top: 0; + } + // Account for multiple tbody instances + tbody + tbody { + border-top: 2px solid #ddd; + } +} + + + +// CONDENSED TABLE W/ HALF PADDING +// ------------------------------- + +.table-condensed { + th, + td { + padding: 4px 5px; + } +} + + +// BORDERED VERSION +// ---------------- + +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; // Done so we can round those corners! + *border-collapse: collapsed; // IE7 can't round corners anyway + .border-radius(4px); + th + th, + td + td, + th + td, + td + th { + border-left: 1px solid #ddd; + } + // Prevent a double border + thead:first-child tr:first-child th, + tbody:first-child tr:first-child th, + tbody:first-child tr:first-child td { + border-top: 0; + } + // For first th or td in the first row in the first thead or tbody + thead:first-child tr:first-child th:first-child, + tbody:first-child tr:first-child td:first-child { + .border-radius(4px 0 0 0); + } + thead:first-child tr:first-child th:last-child, + tbody:first-child tr:first-child td:last-child { + .border-radius(0 4px 0 0); + } + // For first th or td in the first row in the first thead or tbody + thead:last-child tr:last-child th:first-child, + tbody:last-child tr:last-child td:first-child { + .border-radius(0 0 0 4px); + } + thead:last-child tr:last-child th:last-child, + tbody:last-child tr:last-child td:last-child { + .border-radius(0 0 4px 0); + } +} + + +// ZEBRA-STRIPING +// -------------- + +// Default zebra-stripe styles (alternating gray and transparent backgrounds) +.table-striped { + tbody { + tr:nth-child(odd) td, + tr:nth-child(odd) th { + background-color: #f9f9f9; + } + } +} + + + +// TABLE CELL SIZING +// ----------------- + +// Change the columns +.tableColumns(@columnSpan: 1) { + float: none; + width: ((@gridColumnWidth) * @columnSpan) + (@gridGutterWidth * (@columnSpan - 1)) - 16; + margin-left: 0; +} +table { + .span1 { .tableColumns(1); } + .span2 { .tableColumns(2); } + .span3 { .tableColumns(3); } + .span4 { .tableColumns(4); } + .span5 { .tableColumns(5); } + .span6 { .tableColumns(6); } + .span7 { .tableColumns(7); } + .span8 { .tableColumns(8); } + .span9 { .tableColumns(9); } + .span10 { .tableColumns(10); } + .span11 { .tableColumns(11); } + .span12 { .tableColumns(12); } +} diff --git a/docs/source/_themes/yammerdoc/less/thumbnails.less b/docs/source/_themes/yammerdoc/less/thumbnails.less new file mode 100644 index 00000000000..541fbd6a746 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/thumbnails.less @@ -0,0 +1,35 @@ +// THUMBNAILS +// ---------- + +.thumbnails { + margin-left: -20px; + list-style: none; + .clearfix(); +} +.thumbnails > li { + float: left; + margin: 0 0 @baseLineHeight 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + .border-radius(4px); + .box-shadow(0 1px 1px rgba(0,0,0,.075)); +} +// Add a hover state for linked versions only +a.thumbnail:hover { + border-color: @linkColor; + .box-shadow(0 1px 4px rgba(0,105,214,.25)); +} +// Images and captions +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} diff --git a/docs/source/_themes/yammerdoc/less/tooltip.less b/docs/source/_themes/yammerdoc/less/tooltip.less new file mode 100644 index 00000000000..5111a193f03 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/tooltip.less @@ -0,0 +1,35 @@ +// TOOLTIP +// ------= + +.tooltip { + position: absolute; + z-index: @zindexTooltip; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + .opacity(0); + &.in { .opacity(80); } + &.top { margin-top: -2px; } + &.right { margin-left: 2px; } + &.bottom { margin-top: 2px; } + &.left { margin-left: -2px; } + &.top .tooltip-arrow { #popoverArrow > .top(); } + &.left .tooltip-arrow { #popoverArrow > .left(); } + &.bottom .tooltip-arrow { #popoverArrow > .bottom(); } + &.right .tooltip-arrow { #popoverArrow > .right(); } +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: @white; + text-align: center; + text-decoration: none; + background-color: @black; + .border-radius(4px); +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} diff --git a/docs/source/_themes/yammerdoc/less/type.less b/docs/source/_themes/yammerdoc/less/type.less new file mode 100644 index 00000000000..7841bb0906a --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/type.less @@ -0,0 +1,217 @@ +// Typography.less +// Headings, body text, lists, code, and more for a versatile and durable typography system +// ---------------------------------------------------------------------------------------- + + +// BODY TEXT +// --------- + +p { + margin: 0 0 @baseLineHeight / 2; + font-family: @baseFontFamily; + font-size: @baseFontSize; + line-height: @baseLineHeight; + small { + font-size: @baseFontSize - 2; + color: @grayLight; + } +} +.lead { + margin-bottom: @baseLineHeight; + font-size: 20px; + font-weight: 200; + line-height: @baseLineHeight * 1.5; +} + +// HEADINGS +// -------- + +h1, h2, h3, h4, h5, h6 { + margin: 0; + font-weight: bold; + color: @grayDark; + text-rendering: optimizelegibility; // Fix the character spacing for headings + small { + font-weight: normal; + color: @grayLight; + } +} +h1 { + font-size: 30px; + line-height: @baseLineHeight * 2; + small { + font-size: 18px; + } +} +h2 { + font-size: 24px; + line-height: @baseLineHeight * 2; + small { + font-size: 18px; + } +} +h3 { + line-height: @baseLineHeight * 1.5; + font-size: 18px; + small { + font-size: 14px; + } +} +h4, h5, h6 { + line-height: @baseLineHeight; +} +h4 { + font-size: 14px; + small { + font-size: 12px; + } +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: @grayLight; + text-transform: uppercase; +} + +// Page header +.page-header { + padding-bottom: @baseLineHeight - 1; + margin: @baseLineHeight 0; + border-bottom: 1px solid @grayLighter; +} +.page-header h1 { + line-height: 1; +} + + + +// LISTS +// ----- + +// Unordered and Ordered lists +ul, ol { + padding: 0; + margin: 0 0 @baseLineHeight / 2 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: @baseLineHeight; +} +ul.unstyled { + margin-left: 0; + list-style: none; +} + +// Description Lists +dl { + margin-bottom: @baseLineHeight; +} +dt, +dd { + line-height: @baseLineHeight; +} +dt { + font-weight: bold; +} +dd { + margin-left: @baseLineHeight / 2; +} + +// MISC +// ---- + +// Horizontal rules +hr { + margin: @baseLineHeight 0; + border: 0; + border-top: 1px solid #e5e5e5; + border-bottom: 1px solid @white; +} + +// Emphasis +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: @grayLight; +} + +// Abbreviations and acronyms +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} + +// Blockquotes +blockquote { + padding: 0 0 0 15px; + margin: 0 0 @baseLineHeight; + border-left: 5px solid @grayLighter; + p { + margin-bottom: 0; + #font > .shorthand(16px,300,@baseLineHeight * 1.25); + } + small { + display: block; + line-height: @baseLineHeight; + color: @grayLight; + &:before { + content: '\2014 \00A0'; + } + } + + // Float right with text-align: right + &.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid @grayLighter; + p, + small { + text-align: right; + } + } +} + +// Quotes +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +// Addresses +address { + display: block; + margin-bottom: @baseLineHeight; + line-height: @baseLineHeight; + font-style: normal; +} + +// Misc +small { + font-size: 100%; +} +cite { + font-style: normal; +} diff --git a/docs/source/_themes/yammerdoc/less/utilities.less b/docs/source/_themes/yammerdoc/less/utilities.less new file mode 100644 index 00000000000..d60d2203119 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/utilities.less @@ -0,0 +1,23 @@ +// UTILITY CLASSES +// --------------- + +// Quick floats +.pull-right { + float: right; +} +.pull-left { + float: left; +} + +// Toggling content +.hide { + display: none; +} +.show { + display: block; +} + +// Visibility +.invisible { + visibility: hidden; +} diff --git a/docs/source/_themes/yammerdoc/less/variables.less b/docs/source/_themes/yammerdoc/less/variables.less new file mode 100644 index 00000000000..f01c232e4a8 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/variables.less @@ -0,0 +1,99 @@ +// Variables.less +// Variables to customize the look and feel of Bootstrap +// ----------------------------------------------------- + + + +// GLOBAL VALUES +// -------------------------------------------------- + +// Links +@linkColor: #08c; +@linkColorHover: darken(@linkColor, 15%); + +// Grays +@black: #000; +@grayDarker: #222; +@grayDark: #333; +@gray: #555; +@grayLight: #999; +@grayLighter: #eee; +@white: #fff; + +// Accent colors +@blue: #049cdb; +@blueDark: #0064cd; +@green: #46a546; +@red: #9d261d; +@yellow: #ffc40d; +@orange: #f89406; +@pink: #c3325f; +@purple: #7a43b6; + +// Typography +@baseFontSize: 13px; +@baseFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif; +@baseLineHeight: 18px; +@textColor: @grayDark; + +// Buttons +@primaryButtonBackground: @linkColor; + + + +// COMPONENT VARIABLES +// -------------------------------------------------- + +// Z-index master list +// Used for a bird's eye view of components dependent on the z-axis +// Try to avoid customizing these :) +@zindexDropdown: 1000; +@zindexPopover: 1010; +@zindexTooltip: 1020; +@zindexFixedNavbar: 1030; +@zindexModalBackdrop: 1040; +@zindexModal: 1050; + +// Input placeholder text color +@placeholderText: @grayLight; + +// Navbar +@navbarHeight: 40px; +@navbarBackground: @grayDarker; +@navbarBackgroundHighlight: @grayDark; + +@navbarText: @grayLight; +@navbarLinkColor: @grayLight; +@navbarLinkColorHover: @white; + +// Form states and alerts +@warningText: #c09853; +@warningBackground: #fcf8e3; +@warningBorder: darken(spin(@warningBackground, -10), 3%); + +@errorText: #b94a48; +@errorBackground: #f2dede; +@errorBorder: darken(spin(@errorBackground, -10), 3%); + +@successText: #468847; +@successBackground: #dff0d8; +@successBorder: darken(spin(@successBackground, -10), 5%); + +@infoText: #3a87ad; +@infoBackground: #d9edf7; +@infoBorder: darken(spin(@infoBackground, -10), 7%); + + + +// GRID +// -------------------------------------------------- + +// Default 940px grid +@gridColumns: 12; +@gridColumnWidth: 60px; +@gridGutterWidth: 20px; +@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1)); + +// Fluid grid +@fluidGridColumnWidth: 6.382978723%; +@fluidGridGutterWidth: 2.127659574%; diff --git a/docs/source/_themes/yammerdoc/less/wells.less b/docs/source/_themes/yammerdoc/less/wells.less new file mode 100644 index 00000000000..244b8ca102b --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/wells.less @@ -0,0 +1,17 @@ +// WELLS +// ----- + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0,0,0,.05); + .border-radius(4px); + .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); + blockquote { + border-color: #ddd; + border-color: rgba(0,0,0,.15); + } +} diff --git a/docs/source/_themes/yammerdoc/less/yammerdoc.less b/docs/source/_themes/yammerdoc/less/yammerdoc.less new file mode 100644 index 00000000000..53c3285b487 --- /dev/null +++ b/docs/source/_themes/yammerdoc/less/yammerdoc.less @@ -0,0 +1,219 @@ +@import "reset.less"; +@import "variables.less"; // Modify this for custom colors, font-sizes, etc +@import "mixins.less"; +@import "scaffolding.less"; +@import "grid.less"; +@import "layouts.less"; +@import "type.less"; +@import "code.less"; +@import "forms.less"; +@import "tables.less"; +@import "buttons.less"; +@import "navs.less"; +@import "navbar.less"; +@import "hero-unit.less"; +@import "utilities.less"; // Has to be last to override when necessary + +#call-to-action { + text-align: right; +} + +a.headerlink { + display: none; +} + +#title { + color: #ffffff; +} + +.hero-unit h1 { + padding-bottom: 20px ! important; +} + +#top-bar small { + color: #f8f8ff; + text-shadow: 0px -1px 0px #5f0c17; +} + +.admonition { + padding: 14px 35px 14px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.admonition .admonition-title { + font-size: 14pt; + font-weight: bold; +} + +.admonition.note .admonition-title, +.admonition-todo .admonition-title { + color: #c09853; +} + +.admonition.tip, +.admonition.hint { + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.admonition.tip .admonition-title, +.admonition.hint .admonition-title { + color: #468847; +} + +.admonition.error, +.admonition.warning, +.admonition.caution, +.admonition.danger, +.admonition.attention { + background-color: #f2dede; + border-color: #eed3d7; +} + +.admonition.error .admonition-title, +.admonition.warning .admonition-title, +.admonition.caution .admonition-title, +.admonition.danger .admonition-title, +.admonition.attention .admonition-title { + color: #b94a48; +} + +.admonition.important { + background-color: #d9edf7; + border-color: #bce8f1; +} + +.admonition.important .admonition-title { + color: #3a87ad; +} + +.admonition > p, .admonition > ul { + margin-bottom: 0; +} + +.admonition p + p { + margin-top: 5px; +} + +a.internal.reference > em { + font-style: normal ! important; + text-decoration: none ! important; +} + +tt { + padding: 1px 3px; + font-family: 'Panic Sans', Menlo, Monaco, Consolas, Andale Mono, Courier New, monospace; + font-size: 12px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + background-color: #fee9cc; + color: rgba(0, 0, 0, 0.75); +} + +.section > p, .section ul li, .admonition p, .section dt, .section dl { + font-size: 13pt; + line-height: 18pt; +} + +.section tt { + font-size: 11pt; + line-height: 11pt; +} + +.section > * { + margin-bottom: 20px; +} + +pre { + font-family: 'Panic Sans', Menlo, Monaco, Consolas, Andale Mono, Courier New, monospace !important; + font-size: 12pt !important; + line-height: 22px !important; + display: block !important; + width: auto !important; + height: auto !important; + overflow: auto !important; + white-space: pre !important; + word-wrap: normal !important; +} + +#body h1, h1 tt { + font-size: 28pt; +} + +h1 tt { + background-color: transparent; + font-size: 26pt !important; +} + +#body h2 { + font-size: 24pt; +} + +h2 tt { + background-color: transparent; + font-size: 22pt !important; +} + +#body h3 { + font-size: 20pt; +} + +h3 tt { + background-color: transparent; + font-size: 18pt !important; +} + +#body h4 { + font-size: 16pt; +} + +h4 tt { + background-color: transparent; + font-size: 14pt !important; +} + +#sidebar tt { + color: #08c; + background-color: transparent; +} + +.hero-unit .toctree-wrapper { + text-align: center; +} + +.hero-unit li { + display: inline; + list-style-type: none; + padding-right: 20px; +} + +.hero-unit li a:after { + content: " »"; +} + +.hero-unit li a{display:inline-block;padding:10px 10px 10px;font-size:16pt;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:first-child{*margin-left:0;} +.hero-unit li a:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} +.hero-unit li a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.hero-unit li a:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;} + +.hero-unit li a{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} +.hero-unit li a:active{background-color:#408140 \9;} + +.hero-unit li a, .hero-unit li a:hover {text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} +.hero-unit li a:active {color: rgba(255, 255, 255, 0.75);} + +.hero-unit li a:hover, +.hero-unit li a:active { + background-color: #51a351; +} + +.hero-unit li a:active { + background-color: #408140 \9; +} diff --git a/docs/source/_themes/yammerdoc/static/bootstrap.min.css b/docs/source/_themes/yammerdoc/static/bootstrap.min.css deleted file mode 100644 index 98bf1671504..00000000000 --- a/docs/source/_themes/yammerdoc/static/bootstrap.min.css +++ /dev/null @@ -1,610 +0,0 @@ -article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} -audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} -audio:not([controls]){display:none;} -html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} -a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} -a:hover,a:active{outline:0;} -sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} -sup{top:-0.5em;} -sub{bottom:-0.25em;} -img{max-width:100%;height:auto;border:0;-ms-interpolation-mode:bicubic;} -button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} -button,input{*overflow:visible;line-height:normal;} -button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} -button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} -input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;} -input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} -textarea{overflow:auto;vertical-align:top;} -body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;} -a{color:#0088cc;text-decoration:none;} -a:hover{color:#005580;text-decoration:underline;} -.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} -.row:after{clear:both;} -[class*="span"]{float:left;margin-left:20px;} -.span1{width:60px;} -.span2{width:140px;} -.span3{width:220px;} -.span4{width:300px;} -.span5{width:380px;} -.span6{width:460px;} -.span7{width:540px;} -.span8{width:620px;} -.span9{width:700px;} -.span10{width:780px;} -.span11{width:860px;} -.span12,.container{width:940px;} -.offset1{margin-left:100px;} -.offset2{margin-left:180px;} -.offset3{margin-left:260px;} -.offset4{margin-left:340px;} -.offset5{margin-left:420px;} -.offset6{margin-left:500px;} -.offset7{margin-left:580px;} -.offset8{margin-left:660px;} -.offset9{margin-left:740px;} -.offset10{margin-left:820px;} -.offset11{margin-left:900px;} -.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} -.row-fluid:after{clear:both;} -.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;} -.row-fluid>[class*="span"]:first-child{margin-left:0;} -.row-fluid .span1{width:6.382978723%;} -.row-fluid .span2{width:14.89361702%;} -.row-fluid .span3{width:23.404255317%;} -.row-fluid .span4{width:31.914893614%;} -.row-fluid .span5{width:40.425531911%;} -.row-fluid .span6{width:48.93617020799999%;} -.row-fluid .span7{width:57.446808505%;} -.row-fluid .span8{width:65.95744680199999%;} -.row-fluid .span9{width:74.468085099%;} -.row-fluid .span10{width:82.97872339599999%;} -.row-fluid .span11{width:91.489361693%;} -.row-fluid .span12{width:99.99999998999999%;} -.container{width:940px;margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";} -.container:after{clear:both;} -.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";} -.container-fluid:after{clear:both;} -p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;} -.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;} -h1,h2,h3,h4,h5,h6{margin:0;font-weight:bold;color:#333333;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;} -h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;} -h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;} -h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;} -h4,h5,h6{line-height:18px;} -h4{font-size:14px;}h4 small{font-size:12px;} -h5{font-size:12px;} -h6{font-size:11px;color:#999999;text-transform:uppercase;} -.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;} -.page-header h1{line-height:1;} -ul,ol{padding:0;margin:0 0 9px 25px;} -ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} -ul{list-style:disc;} -ol{list-style:decimal;} -li{line-height:18px;} -ul.unstyled{margin-left:0;list-style:none;} -dl{margin-bottom:18px;} -dt,dd{line-height:18px;} -dt{font-weight:bold;} -dd{margin-left:9px;} -hr{margin:18px 0;border:0;border-top:1px solid #e5e5e5;border-bottom:1px solid #ffffff;} -strong{font-weight:bold;} -em{font-style:italic;} -.muted{color:#999999;} -abbr{font-size:90%;text-transform:uppercase;border-bottom:1px dotted #ddd;cursor:help;} -blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;} -blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} -blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} -q:before,q:after,blockquote:before,blockquote:after{content:"";} -address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;} -small{font-size:100%;} -cite{font-style:normal;} -code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} -code{padding:3px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} -pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;}pre.prettyprint{margin-bottom:18px;} -pre code{padding:0;background-color:transparent;} -form{margin:0 0 18px;} -fieldset{padding:0;margin:0;border:0;} -legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;} -label,input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;} -label{display:block;margin-bottom:5px;color:#333333;} -input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} -.uneditable-textarea{width:auto;height:auto;} -label input,label textarea,label select{display:block;} -input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:0;cursor:pointer;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} -input[type="file"]{padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} -input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;} -select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;} -select{width:220px;background-color:#ffffff;} -select[multiple],select[size]{height:auto;} -input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} -textarea{height:auto;} -input[type="hidden"]{display:none;} -.radio,.checkbox{padding-left:18px;} -.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;} -.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} -.radio.inline,.checkbox.inline{display:inline-block;margin-bottom:0;vertical-align:middle;} -.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} -.controls>.radio.inline:first-child,.controls>.checkbox.inline:first-child{padding-top:0;} -input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;} -input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;} -input[type="file"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} -.input-mini{width:60px;} -.input-small{width:90px;} -.input-medium{width:150px;} -.input-large{width:210px;} -.input-xlarge{width:270px;} -.input-xxlarge{width:530px;} -input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;} -input.span1,textarea.span1,.uneditable-input.span1{width:50px;} -input.span2,textarea.span2,.uneditable-input.span2{width:130px;} -input.span3,textarea.span3,.uneditable-input.span3{width:210px;} -input.span4,textarea.span4,.uneditable-input.span4{width:290px;} -input.span5,textarea.span5,.uneditable-input.span5{width:370px;} -input.span6,textarea.span6,.uneditable-input.span6{width:450px;} -input.span7,textarea.span7,.uneditable-input.span7{width:530px;} -input.span8,textarea.span8,.uneditable-input.span8{width:610px;} -input.span9,textarea.span9,.uneditable-input.span9{width:690px;} -input.span10,textarea.span10,.uneditable-input.span10{width:770px;} -input.span11,textarea.span11,.uneditable-input.span11{width:850px;} -input.span12,textarea.span12,.uneditable-input.span12{width:930px;} -input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;} -.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} -.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;} -.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} -.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} -.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;} -.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} -.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} -.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;} -.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} -input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} -.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #ddd;} -.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} -:-moz-placeholder{color:#999999;} -::-webkit-input-placeholder{color:#999999;} -.help-block{margin-top:5px;margin-bottom:0;color:#999999;} -.help-inline{display:inline-block;*display:inline;*zoom:1;margin-bottom:9px;vertical-align:middle;padding-left:5px;} -.input-prepend,.input-append{margin-bottom:5px;*zoom:1;}.input-prepend:before,.input-append:before,.input-prepend:after,.input-append:after{display:table;content:"";} -.input-prepend:after,.input-append:after{clear:both;} -.input-prepend input,.input-append input,.input-prepend .uneditable-input,.input-append .uneditable-input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;} -.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;} -.input-prepend .add-on,.input-append .add-on{float:left;display:block;width:auto;min-width:16px;height:18px;margin-right:-1px;padding:4px 5px;font-weight:normal;line-height:18px;color:#999999;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#f5f5f5;border:1px solid #ccc;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} -.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;} -.input-prepend .add-on{*margin-top:1px;} -.input-append input,.input-append .uneditable-input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} -.input-append .uneditable-input{border-right-color:#ccc;} -.input-append .add-on{margin-right:0;margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} -.input-append input:first-child{*margin-left:-160px;}.input-append input:first-child+.add-on{*margin-left:-21px;} -.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;} -.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input{display:inline-block;margin-bottom:0;} -.form-search label,.form-inline label,.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{display:inline-block;} -.form-search .input-append .add-on,.form-inline .input-prepend .add-on,.form-search .input-append .add-on,.form-inline .input-prepend .add-on{vertical-align:middle;} -.control-group{margin-bottom:9px;} -.form-horizontal legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;} -.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";} -.form-horizontal .control-group:after{clear:both;} -.form-horizontal .control-group>label{float:left;width:140px;padding-top:5px;text-align:right;} -.form-horizontal .controls{margin-left:160px;} -.form-horizontal .form-actions{padding-left:160px;} -table{max-width:100%;border-collapse:collapse;border-spacing:0;} -.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;border-top:1px solid #ddd;} -.table th{font-weight:bold;vertical-align:bottom;} -.table td{vertical-align:top;} -.table thead:first-child tr th,.table thead:first-child tr td{border-top:0;} -.table tbody+tbody{border-top:2px solid #ddd;} -.table-condensed th,.table-condensed td{padding:4px 5px;} -.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th+th,.table-bordered td+td,.table-bordered th+td,.table-bordered td+th{border-left:1px solid #ddd;} -.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} -.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;} -.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;} -.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;} -.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;} -.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} -table .span1{float:none;width:44px;margin-left:0;} -table .span2{float:none;width:124px;margin-left:0;} -table .span3{float:none;width:204px;margin-left:0;} -table .span4{float:none;width:284px;margin-left:0;} -table .span5{float:none;width:364px;margin-left:0;} -table .span6{float:none;width:444px;margin-left:0;} -table .span7{float:none;width:524px;margin-left:0;} -table .span8{float:none;width:604px;margin-left:0;} -table .span9{float:none;width:684px;margin-left:0;} -table .span10{float:none;width:764px;margin-left:0;} -table .span11{float:none;width:844px;margin-left:0;} -table .span12{float:none;width:924px;margin-left:0;} -[class^="icon-"]{display:inline-block;width:14px;height:14px;vertical-align:text-top;background-image:url(img/glyphicons-halflings.png);background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child{*margin-left:0;} -.icon-white{background-image:url(img/glyphicons-halflings-white.png);} -.icon-glass{background-position:0 0;} -.icon-music{background-position:-24px 0;} -.icon-search{background-position:-48px 0;} -.icon-envelope{background-position:-72px 0;} -.icon-heart{background-position:-96px 0;} -.icon-star{background-position:-120px 0;} -.icon-star-empty{background-position:-144px 0;} -.icon-user{background-position:-168px 0;} -.icon-film{background-position:-192px 0;} -.icon-th-large{background-position:-216px 0;} -.icon-th{background-position:-240px 0;} -.icon-th-list{background-position:-264px 0;} -.icon-ok{background-position:-288px 0;} -.icon-remove{background-position:-312px 0;} -.icon-zoom-in{background-position:-336px 0;} -.icon-zoom-out{background-position:-360px 0;} -.icon-off{background-position:-384px 0;} -.icon-signal{background-position:-408px 0;} -.icon-cog{background-position:-432px 0;} -.icon-trash{background-position:-456px 0;} -.icon-home{background-position:0 -24px;} -.icon-file{background-position:-24px -24px;} -.icon-time{background-position:-48px -24px;} -.icon-road{background-position:-72px -24px;} -.icon-download-alt{background-position:-96px -24px;} -.icon-download{background-position:-120px -24px;} -.icon-upload{background-position:-144px -24px;} -.icon-inbox{background-position:-168px -24px;} -.icon-play-circle{background-position:-192px -24px;} -.icon-repeat{background-position:-216px -24px;} -.icon-refresh{background-position:-240px -24px;} -.icon-list-alt{background-position:-264px -24px;} -.icon-lock{background-position:-287px -24px;} -.icon-flag{background-position:-312px -24px;} -.icon-headphones{background-position:-336px -24px;} -.icon-volume-off{background-position:-360px -24px;} -.icon-volume-down{background-position:-384px -24px;} -.icon-volume-up{background-position:-408px -24px;} -.icon-qrcode{background-position:-432px -24px;} -.icon-barcode{background-position:-456px -24px;} -.icon-tag{background-position:0 -48px;} -.icon-tags{background-position:-25px -48px;} -.icon-book{background-position:-48px -48px;} -.icon-bookmark{background-position:-72px -48px;} -.icon-print{background-position:-96px -48px;} -.icon-camera{background-position:-120px -48px;} -.icon-font{background-position:-144px -48px;} -.icon-bold{background-position:-167px -48px;} -.icon-italic{background-position:-192px -48px;} -.icon-text-height{background-position:-216px -48px;} -.icon-text-width{background-position:-240px -48px;} -.icon-align-left{background-position:-264px -48px;} -.icon-align-center{background-position:-288px -48px;} -.icon-align-right{background-position:-312px -48px;} -.icon-align-justify{background-position:-336px -48px;} -.icon-list{background-position:-360px -48px;} -.icon-indent-left{background-position:-384px -48px;} -.icon-indent-right{background-position:-408px -48px;} -.icon-facetime-video{background-position:-432px -48px;} -.icon-picture{background-position:-456px -48px;} -.icon-pencil{background-position:0 -72px;} -.icon-map-marker{background-position:-24px -72px;} -.icon-adjust{background-position:-48px -72px;} -.icon-tint{background-position:-72px -72px;} -.icon-edit{background-position:-96px -72px;} -.icon-share{background-position:-120px -72px;} -.icon-check{background-position:-144px -72px;} -.icon-move{background-position:-168px -72px;} -.icon-step-backward{background-position:-192px -72px;} -.icon-fast-backward{background-position:-216px -72px;} -.icon-backward{background-position:-240px -72px;} -.icon-play{background-position:-264px -72px;} -.icon-pause{background-position:-288px -72px;} -.icon-stop{background-position:-312px -72px;} -.icon-forward{background-position:-336px -72px;} -.icon-fast-forward{background-position:-360px -72px;} -.icon-step-forward{background-position:-384px -72px;} -.icon-eject{background-position:-408px -72px;} -.icon-chevron-left{background-position:-432px -72px;} -.icon-chevron-right{background-position:-456px -72px;} -.icon-plus-sign{background-position:0 -96px;} -.icon-minus-sign{background-position:-24px -96px;} -.icon-remove-sign{background-position:-48px -96px;} -.icon-ok-sign{background-position:-72px -96px;} -.icon-question-sign{background-position:-96px -96px;} -.icon-info-sign{background-position:-120px -96px;} -.icon-screenshot{background-position:-144px -96px;} -.icon-remove-circle{background-position:-168px -96px;} -.icon-ok-circle{background-position:-192px -96px;} -.icon-ban-circle{background-position:-216px -96px;} -.icon-arrow-left{background-position:-240px -96px;} -.icon-arrow-right{background-position:-264px -96px;} -.icon-arrow-up{background-position:-289px -96px;} -.icon-arrow-down{background-position:-312px -96px;} -.icon-share-alt{background-position:-336px -96px;} -.icon-resize-full{background-position:-360px -96px;} -.icon-resize-small{background-position:-384px -96px;} -.icon-plus{background-position:-408px -96px;} -.icon-minus{background-position:-433px -96px;} -.icon-asterisk{background-position:-456px -96px;} -.icon-exclamation-sign{background-position:0 -120px;} -.icon-gift{background-position:-24px -120px;} -.icon-leaf{background-position:-48px -120px;} -.icon-fire{background-position:-72px -120px;} -.icon-eye-open{background-position:-96px -120px;} -.icon-eye-close{background-position:-120px -120px;} -.icon-warning-sign{background-position:-144px -120px;} -.icon-plane{background-position:-168px -120px;} -.icon-calendar{background-position:-192px -120px;} -.icon-random{background-position:-216px -120px;} -.icon-comment{background-position:-240px -120px;} -.icon-magnet{background-position:-264px -120px;} -.icon-chevron-up{background-position:-288px -120px;} -.icon-chevron-down{background-position:-313px -119px;} -.icon-retweet{background-position:-336px -120px;} -.icon-shopping-cart{background-position:-360px -120px;} -.icon-folder-close{background-position:-384px -120px;} -.icon-folder-open{background-position:-408px -120px;} -.icon-resize-vertical{background-position:-432px -119px;} -.icon-resize-horizontal{background-position:-456px -118px;} -.dropdown{position:relative;} -.dropdown-toggle{*margin-bottom:-3px;} -.dropdown-toggle:active,.open .dropdown-toggle{outline:0;} -.caret{display:inline-block;width:0;height:0;text-indent:-99999px;*text-indent:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"\2193";} -.dropdown .caret{margin-top:8px;margin-left:2px;} -.dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);} -.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;max-width:220px;_width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.bottom-up{top:auto;bottom:100%;margin-bottom:2px;} -.dropdown-menu .divider{height:1px;margin:5px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;} -.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#555555;white-space:nowrap;} -.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0088cc;} -.dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);} -.dropdown.open .dropdown-menu{display:block;} -.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} -.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} -.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;} -.collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;} -.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;} -.btn{display:inline-block;padding:4px 10px 4px;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:first-child{*margin-left:0;} -.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} -.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} -.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;} -.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} -.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} -.btn-large .icon{margin-top:1px;} -.btn-small{padding:5px 9px;font-size:11px;line-height:16px;} -.btn-small .icon{margin-top:-1px;} -.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} -.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active{color:rgba(255, 255, 255, 0.75);} -.btn-primary{background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-ms-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(top, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0044cc;} -.btn-primary:active,.btn-primary.active{background-color:#003399 \9;} -.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;} -.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} -.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;} -.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} -.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} -.btn-success:active,.btn-success.active{background-color:#408140 \9;} -.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;} -.btn-info:active,.btn-info.active{background-color:#24748c \9;} -button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} -button.btn.large,input[type="submit"].btn.large{*padding-top:7px;*padding-bottom:7px;} -button.btn.small,input[type="submit"].btn.small{*padding-top:3px;*padding-bottom:3px;} -.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";} -.btn-group:after{clear:both;} -.btn-group:first-child{*margin-left:0;} -.btn-group+.btn-group{margin-left:5px;} -.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;} -.btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} -.btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} -.btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} -.btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} -.btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} -.btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;} -.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} -.btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:5px;*padding-bottom:5px;} -.btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} -.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);} -.btn .caret{margin-top:7px;margin-left:0;} -.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);} -.btn-primary .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret{border-top-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);} -.btn-small .caret{margin-top:4px;} -.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} -.alert,.alert-heading{color:#c09853;} -.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;} -.alert-success{background-color:#dff0d8;border-color:#d6e9c6;} -.alert-success,.alert-success .alert-heading{color:#468847;} -.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;} -.alert-danger,.alert-error,.alert-danger .alert-heading,.alert-error .alert-heading{color:#b94a48;} -.alert-info{background-color:#d9edf7;border-color:#bce8f1;} -.alert-info,.alert-info .alert-heading{color:#3a87ad;} -.alert-block{padding-top:14px;padding-bottom:14px;} -.alert-block>p,.alert-block>ul{margin-bottom:0;} -.alert-block p+p{margin-top:5px;} -.nav{margin-left:0;margin-bottom:18px;list-style:none;} -.nav>li>a{display:block;} -.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;} -.nav-list{padding-left:14px;padding-right:14px;margin-bottom:0;} -.nav-list>li>a,.nav-list .nav-header{display:block;padding:3px 15px;margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} -.nav-list .nav-header{font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-transform:uppercase;} -.nav-list>li+.nav-header{margin-top:9px;} -.nav-list .active>a,.nav-list .active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} -.nav-list [class^="icon-"]{margin-right:2px;} -.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";} -.nav-tabs:after,.nav-pills:after{clear:both;} -.nav-tabs>li,.nav-pills>li{float:left;} -.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} -.nav-tabs{border-bottom:1px solid #ddd;} -.nav-tabs>li{margin-bottom:-1px;} -.nav-tabs>li>a{padding-top:9px;padding-bottom:9px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;} -.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} -.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} -.nav-pills .active>a,.nav-pills .active>a:hover{color:#ffffff;background-color:#0088cc;} -.nav-stacked>li{float:none;} -.nav-stacked>li>a{margin-right:0;} -.nav-tabs.nav-stacked{border-bottom:0;} -.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} -.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} -.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} -.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;} -.nav-pills.nav-stacked>li>a{margin-bottom:3px;} -.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} -.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;} -.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} -.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;margin-top:6px;} -.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;} -.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;} -.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;} -.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;} -.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;opacity:1;filter:alpha(opacity=100);} -.tabs-stacked .open>a:hover{border-color:#999999;} -.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";} -.tabbable:after{clear:both;} -.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;} -.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} -.tab-content>.active,.pill-content>.active{display:block;} -.tabs-below .nav-tabs{border-top:1px solid #ddd;} -.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;} -.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;} -.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;} -.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;} -.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} -.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} -.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} -.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} -.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} -.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} -.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} -.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} -.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} -.navbar{overflow:visible;margin-bottom:18px;} -.navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);} -.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;} -.btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;} -.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} -.btn-navbar .icon-bar+.icon-bar{margin-top:3px;} -.nav-collapse.collapse{height:auto;} -.navbar .brand:hover{text-decoration:none;} -.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;} -.navbar .navbar-text{margin-bottom:0;line-height:40px;color:#999999;}.navbar .navbar-text a:hover{color:#ffffff;background-color:transparent;} -.navbar .btn,.navbar .btn-group{margin-top:5px;} -.navbar .btn-group .btn{margin-top:0;} -.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";} -.navbar-form:after{clear:both;} -.navbar-form input,.navbar-form select{display:inline-block;margin-top:5px;margin-bottom:0;} -.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} -.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} -.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;color:rgba(255, 255, 255, 0.75);background:#666;background:rgba(255, 255, 255, 0.3);border:1px solid #111;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query :-moz-placeholder{color:#eeeeee;} -.navbar-search .search-query::-webkit-input-placeholder{color:#eeeeee;} -.navbar-search .search-query:hover{color:#ffffff;background-color:#999999;background-color:rgba(255, 255, 255, 0.5);} -.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} -.navbar-fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030;} -.navbar-fixed-top .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} -.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} -.navbar .nav.pull-right{float:right;} -.navbar .nav>li{display:block;float:left;} -.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} -.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;} -.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;background-color:rgba(0, 0, 0, 0.5);} -.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;} -.navbar .nav.pull-right{margin-left:10px;margin-right:0;} -.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} -.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} -.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;} -.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);} -.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;} -.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;} -.navbar .nav.pull-right .dropdown-menu{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before{left:auto;right:12px;} -.navbar .nav.pull-right .dropdown-menu:after{left:auto;right:13px;} -.breadcrumb{padding:7px 14px;margin:0 0 18px;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline;text-shadow:0 1px 0 #ffffff;} -.breadcrumb .divider{padding:0 5px;color:#999999;} -.breadcrumb .active a{color:#333333;} -.pagination{height:36px;margin:18px 0;} -.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} -.pagination li{display:inline;} -.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;} -.pagination a:hover,.pagination .active a{background-color:#f5f5f5;} -.pagination .active a{color:#999999;cursor:default;} -.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;} -.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} -.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} -.pagination-centered{text-align:center;} -.pagination-right{text-align:right;} -.pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";} -.pager:after{clear:both;} -.pager li{display:inline;} -.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} -.pager a:hover{text-decoration:none;background-color:#f5f5f5;} -.pager .next a{float:right;} -.pager .previous a{float:left;} -.modal-open .dropdown-menu{z-index:2050;} -.modal-open .dropdown.open{*z-index:2050;} -.modal-open .popover{z-index:2060;} -.modal-open .tooltip{z-index:2070;} -.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} -.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} -.modal{position:fixed;top:50%;left:50%;z-index:1050;max-height:500px;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} -.modal.fade.in{top:50%;} -.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} -.modal-body{padding:15px;} -.modal-footer{padding:14px 15px 15px;margin-bottom:0;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";} -.modal-footer:after{clear:both;} -.modal-footer .btn{float:right;margin-left:5px;margin-bottom:0;} -.tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} -.tooltip.top{margin-top:-2px;} -.tooltip.right{margin-left:2px;} -.tooltip.bottom{margin-top:2px;} -.tooltip.left{margin-left:-2px;} -.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} -.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} -.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} -.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} -.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} -.tooltip-arrow{position:absolute;width:0;height:0;} -.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;} -.popover.right{margin-left:5px;} -.popover.bottom{margin-top:5px;} -.popover.left{margin-left:-5px;} -.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} -.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} -.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} -.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} -.popover .arrow{position:absolute;width:0;height:0;} -.popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);} -.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;} -.popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;} -.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";} -.thumbnails:after{clear:both;} -.thumbnails>li{float:left;margin:0 0 18px 20px;} -.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);} -a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} -.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} -.thumbnail .caption{padding:9px;} -.label{padding:1px 3px 2px;font-size:9.75px;font-weight:bold;color:#ffffff;text-transform:uppercase;background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} -.label-important{background-color:#b94a48;} -.label-warning{background-color:#f89406;} -.label-success{background-color:#468847;} -.label-info{background-color:#3a87ad;} -@-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} -.progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} -.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} -.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} -.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);} -.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} -.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);} -.progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} -.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);} -.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} -.accordion{margin-bottom:18px;} -.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} -.accordion-heading{border-bottom:0;} -.accordion-heading .accordion-toggle{display:block;padding:8px 15px;} -.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} -.carousel{position:relative;margin-bottom:18px;line-height:1;} -.carousel-inner{overflow:hidden;width:100%;position:relative;} -.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;} -.carousel .item>img{display:block;line-height:1;} -.carousel .active,.carousel .next,.carousel .prev{display:block;} -.carousel .active{left:0;} -.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;} -.carousel .next{left:100%;} -.carousel .prev{left:-100%;} -.carousel .next.left,.carousel .prev.right{left:0;} -.carousel .active.left{left:-100%;} -.carousel .active.right{left:100%;} -.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} -.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} -.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);} -.carousel-caption h4,.carousel-caption p{color:#ffffff;} -.hero-unit{padding:60px;margin-bottom:30px;background-color:#f5f5f5;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;} -.hero-unit p{font-size:18px;font-weight:200;line-height:27px;} -.pull-right{float:right;} -.pull-left{float:left;} -.hide{display:none;} -.show{display:block;} -.invisible{visibility:hidden;} diff --git a/docs/source/_themes/yammerdoc/static/yammerdoc.css b/docs/source/_themes/yammerdoc/static/yammerdoc.css index b7721fe2e12..28b8b62462a 100644 --- a/docs/source/_themes/yammerdoc/static/yammerdoc.css +++ b/docs/source/_themes/yammerdoc/static/yammerdoc.css @@ -1,203 +1,386 @@ -#call-to-action { - text-align: right; -} - -a.headerlink { - display: none; -} - -#title { - color: #ffffff; -} - -.hero-unit h1 { - padding-bottom: 20px ! important; -} - -#top-bar small { - color: #f8f8ff; - text-shadow: 0px -1px 0px #5f0c17; -} - -.admonition { - padding: 14px 35px 14px 14px; - margin-bottom: 18px; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - background-color: #fcf8e3; - border: 1px solid #fbeed5; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.admonition .admonition-title { - font-size: 14pt; - font-weight: bold; -} - -.admonition.note .admonition-title, -.admonition-todo .admonition-title { - color: #c09853; -} - -.admonition.tip, -.admonition.hint { - background-color: #dff0d8; - border-color: #d6e9c6; -} - -.admonition.tip .admonition-title, -.admonition.hint .admonition-title { - color: #468847; -} - -.admonition.error, -.admonition.warning, -.admonition.caution, -.admonition.danger, -.admonition.attention { - background-color: #f2dede; - border-color: #eed3d7; -} - -.admonition.error .admonition-title, -.admonition.warning .admonition-title, -.admonition.caution .admonition-title, -.admonition.danger .admonition-title, -.admonition.attention .admonition-title { - color: #b94a48; -} - -.admonition.important { - background-color: #d9edf7; - border-color: #bce8f1; -} - -.admonition.important .admonition-title { - color: #3a87ad; -} - -.admonition > p, .admonition > ul { - margin-bottom: 0; -} - -.admonition p + p { - margin-top: 5px; -} - -a.internal.reference > em { - font-style: normal ! important; - text-decoration: none ! important; -} - -tt { - padding: 1px 3px; - font-family: 'Panic Sans', Menlo, Monaco, Consolas, Andale Mono, Courier New, monospace; - font-size: 12px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - background-color: #fee9cc; - color: rgba(0, 0, 0, 0.75); -} - -.section > p, .section ul li, .admonition p, .section dt, .section dl { - font-size: 13pt; - line-height: 18pt; -} - -.section tt { - font-size: 11pt; - line-height: 11pt; -} - -.section > * { - margin-bottom: 20px; -} - -pre { - font-family: 'Panic Sans', Menlo, Monaco, Consolas, Andale Mono, Courier New, monospace !important; - font-size: 12pt !important; - line-height: 22px !important; - display: block !important; - width: auto !important; - height: auto !important; - overflow: auto !important; - white-space: pre !important; - word-wrap: normal !important; -} - -#body h1, h1 tt { - font-size: 28pt; -} - -h1 tt { - background-color: transparent; - font-size: 26pt !important; -} - -#body h2 { - font-size: 24pt; -} - -h2 tt { - background-color: transparent; - font-size: 22pt !important; -} - -#body h3 { - font-size: 20pt; -} - -h3 tt { - background-color: transparent; - font-size: 18pt !important; -} - -#body h4 { - font-size: 16pt; -} - -h4 tt { - background-color: transparent; - font-size: 14pt !important; -} - -#sidebar tt { - color: #08c; - background-color: transparent; -} - -.hero-unit .toctree-wrapper { - text-align: center; -} - -.hero-unit li { - display: inline; - list-style-type: none; - padding-right: 20px; -} - -.hero-unit li a:after { - content: " »"; -} - -.hero-unit li a{display:inline-block;padding:10px 10px 10px;font-size:16pt;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:first-child{*margin-left:0;} +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} +audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} +audio:not([controls]){display:none;} +html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} +a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +a:hover,a:active{outline:0;} +sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} +sup{top:-0.5em;} +sub{bottom:-0.25em;} +img{max-width:100%;height:auto;border:0;-ms-interpolation-mode:bicubic;} +button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} +button,input{*overflow:visible;line-height:normal;} +button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} +button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} +input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;} +input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} +textarea{overflow:auto;vertical-align:top;} +body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;} +a{color:#0088cc;text-decoration:none;} +a:hover{color:#005580;text-decoration:underline;} +.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} +.row:after{clear:both;} +[class*="span"]{float:left;margin-left:20px;} +.span1{width:60px;} +.span2{width:140px;} +.span3{width:220px;} +.span4{width:300px;} +.span5{width:380px;} +.span6{width:460px;} +.span7{width:540px;} +.span8{width:620px;} +.span9{width:700px;} +.span10{width:780px;} +.span11{width:860px;} +.span12,.container{width:940px;} +.offset1{margin-left:100px;} +.offset2{margin-left:180px;} +.offset3{margin-left:260px;} +.offset4{margin-left:340px;} +.offset5{margin-left:420px;} +.offset6{margin-left:500px;} +.offset7{margin-left:580px;} +.offset8{margin-left:660px;} +.offset9{margin-left:740px;} +.offset10{margin-left:820px;} +.offset11{margin-left:900px;} +.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} +.row-fluid:after{clear:both;} +.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;} +.row-fluid>[class*="span"]:first-child{margin-left:0;} +.row-fluid .span1{width:6.382978723%;} +.row-fluid .span2{width:14.89361702%;} +.row-fluid .span3{width:23.404255317%;} +.row-fluid .span4{width:31.914893614%;} +.row-fluid .span5{width:40.425531911%;} +.row-fluid .span6{width:48.93617020799999%;} +.row-fluid .span7{width:57.446808505%;} +.row-fluid .span8{width:65.95744680199999%;} +.row-fluid .span9{width:74.468085099%;} +.row-fluid .span10{width:82.97872339599999%;} +.row-fluid .span11{width:91.489361693%;} +.row-fluid .span12{width:99.99999998999999%;} +.container{width:940px;margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";} +.container:after{clear:both;} +.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";} +.container-fluid:after{clear:both;} +p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;} +.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;} +h1,h2,h3,h4,h5,h6{margin:0;font-weight:bold;color:#333333;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;} +h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;} +h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;} +h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;} +h4,h5,h6{line-height:18px;} +h4{font-size:14px;}h4 small{font-size:12px;} +h5{font-size:12px;} +h6{font-size:11px;color:#999999;text-transform:uppercase;} +.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;} +.page-header h1{line-height:1;} +ul,ol{padding:0;margin:0 0 9px 25px;} +ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} +ul{list-style:disc;} +ol{list-style:decimal;} +li{line-height:18px;} +ul.unstyled{margin-left:0;list-style:none;} +dl{margin-bottom:18px;} +dt,dd{line-height:18px;} +dt{font-weight:bold;} +dd{margin-left:9px;} +hr{margin:18px 0;border:0;border-top:1px solid #e5e5e5;border-bottom:1px solid #ffffff;} +strong{font-weight:bold;} +em{font-style:italic;} +.muted{color:#999999;} +abbr{font-size:90%;text-transform:uppercase;border-bottom:1px dotted #ddd;cursor:help;} +blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;} +blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} +blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} +q:before,q:after,blockquote:before,blockquote:after{content:"";} +address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;} +small{font-size:100%;} +cite{font-style:normal;} +code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +code{padding:3px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} +pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;}pre.prettyprint{margin-bottom:18px;} +pre code{padding:0;background-color:transparent;} +form{margin:0 0 18px;} +fieldset{padding:0;margin:0;border:0;} +legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;} +label,input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;} +label{display:block;margin-bottom:5px;color:#333333;} +input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.uneditable-textarea{width:auto;height:auto;} +label input,label textarea,label select{display:block;} +input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:0;cursor:pointer;border-radius:0 \0/;} +input[type="file"]{padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;} +select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;} +select{width:220px;background-color:#ffffff;} +select[multiple],select[size]{height:auto;} +input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +textarea{height:auto;} +input[type="hidden"]{display:none;} +.radio,.checkbox{padding-left:18px;} +.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;} +.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} +.radio.inline,.checkbox.inline{display:inline-block;margin-bottom:0;vertical-align:middle;} +.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} +.controls>.radio.inline:first-child,.controls>.checkbox.inline:first-child{padding-top:0;} +input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;} +input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;} +input[type="file"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.input-mini{width:60px;} +.input-small{width:90px;} +.input-medium{width:150px;} +.input-large{width:210px;} +.input-xlarge{width:270px;} +.input-xxlarge{width:530px;} +input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;} +input.span1,textarea.span1,.uneditable-input.span1{width:50px;} +input.span2,textarea.span2,.uneditable-input.span2{width:130px;} +input.span3,textarea.span3,.uneditable-input.span3{width:210px;} +input.span4,textarea.span4,.uneditable-input.span4{width:290px;} +input.span5,textarea.span5,.uneditable-input.span5{width:370px;} +input.span6,textarea.span6,.uneditable-input.span6{width:450px;} +input.span7,textarea.span7,.uneditable-input.span7{width:530px;} +input.span8,textarea.span8,.uneditable-input.span8{width:610px;} +input.span9,textarea.span9,.uneditable-input.span9{width:690px;} +input.span10,textarea.span10,.uneditable-input.span10{width:770px;} +input.span11,textarea.span11,.uneditable-input.span11{width:850px;} +input.span12,textarea.span12,.uneditable-input.span12{width:930px;} +input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;} +.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} +.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;} +.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} +.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} +.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;} +.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} +.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} +.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;} +.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} +input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} +.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #ddd;} +.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} +:-moz-placeholder{color:#999999;} +::-webkit-input-placeholder{color:#999999;} +.help-block{margin-top:5px;margin-bottom:0;color:#999999;} +.help-inline{display:inline-block;*display:inline;*zoom:1;margin-bottom:9px;vertical-align:middle;padding-left:5px;} +.input-prepend,.input-append{margin-bottom:5px;*zoom:1;}.input-prepend:before,.input-append:before,.input-prepend:after,.input-append:after{display:table;content:"";} +.input-prepend:after,.input-append:after{clear:both;} +.input-prepend input,.input-append input,.input-prepend .uneditable-input,.input-append .uneditable-input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;} +.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;} +.input-prepend .add-on,.input-append .add-on{float:left;display:block;width:auto;min-width:16px;height:18px;margin-right:-1px;padding:4px 5px;font-weight:normal;line-height:18px;color:#999999;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#f5f5f5;border:1px solid #ccc;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;} +.input-prepend .add-on{*margin-top:1px;} +.input-append input,.input-append .uneditable-input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-append .uneditable-input{border-right-color:#ccc;} +.input-append .add-on{margin-right:0;margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.input-append input:first-child{*margin-left:-160px;}.input-append input:first-child+.add-on{*margin-left:-21px;} +.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;} +.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input{display:inline-block;margin-bottom:0;} +.form-search label,.form-inline label,.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{display:inline-block;} +.form-search .input-append .add-on,.form-inline .input-prepend .add-on,.form-search .input-append .add-on,.form-inline .input-prepend .add-on{vertical-align:middle;} +.control-group{margin-bottom:9px;} +.form-horizontal legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;} +.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";} +.form-horizontal .control-group:after{clear:both;} +.form-horizontal .control-group>label{float:left;width:140px;padding-top:5px;text-align:right;} +.form-horizontal .controls{margin-left:160px;} +.form-horizontal .form-actions{padding-left:160px;} +table{max-width:100%;border-collapse:collapse;border-spacing:0;} +.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;border-top:1px solid #ddd;} +.table th{font-weight:bold;vertical-align:bottom;} +.table td{vertical-align:top;} +.table thead:first-child tr th,.table thead:first-child tr td{border-top:0;} +.table tbody+tbody{border-top:2px solid #ddd;} +.table-condensed th,.table-condensed td{padding:4px 5px;} +.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th+th,.table-bordered td+td,.table-bordered th+td,.table-bordered td+th{border-left:1px solid #ddd;} +.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} +.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;} +.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;} +.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;} +.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;} +.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} +table .span1{float:none;width:44px;margin-left:0;} +table .span2{float:none;width:124px;margin-left:0;} +table .span3{float:none;width:204px;margin-left:0;} +table .span4{float:none;width:284px;margin-left:0;} +table .span5{float:none;width:364px;margin-left:0;} +table .span6{float:none;width:444px;margin-left:0;} +table .span7{float:none;width:524px;margin-left:0;} +table .span8{float:none;width:604px;margin-left:0;} +table .span9{float:none;width:684px;margin-left:0;} +table .span10{float:none;width:764px;margin-left:0;} +table .span11{float:none;width:844px;margin-left:0;} +table .span12{float:none;width:924px;margin-left:0;} +.btn{display:inline-block;padding:4px 10px 4px;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:first-child{*margin-left:0;} +.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} +.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;} +.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.btn-large .icon{margin-top:1px;} +.btn-small{padding:5px 9px;font-size:11px;line-height:16px;} +.btn-small .icon{margin-top:-1px;} +.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} +.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active{color:rgba(255, 255, 255, 0.75);} +.btn-primary{background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-ms-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(top, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0044cc;} +.btn-primary:active,.btn-primary.active{background-color:#003399 \9;} +.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;} +.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} +.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;} +.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} +.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} +.btn-success:active,.btn-success.active{background-color:#408140 \9;} +.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;} +.btn-info:active,.btn-info.active{background-color:#24748c \9;} +button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} +button.btn.large,input[type="submit"].btn.large{*padding-top:7px;*padding-bottom:7px;} +button.btn.small,input[type="submit"].btn.small{*padding-top:3px;*padding-bottom:3px;} +.nav{margin-left:0;margin-bottom:18px;list-style:none;} +.nav>li>a{display:block;} +.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;} +.nav-list{padding-left:14px;padding-right:14px;margin-bottom:0;} +.nav-list>li>a,.nav-list .nav-header{display:block;padding:3px 15px;margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} +.nav-list .nav-header{font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-transform:uppercase;} +.nav-list>li+.nav-header{margin-top:9px;} +.nav-list .active>a{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} +.nav-list .icon{margin-right:2px;} +.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";} +.nav-tabs:after,.nav-pills:after{clear:both;} +.nav-tabs>li,.nav-pills>li{float:left;} +.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} +.nav-tabs{border-bottom:1px solid #ddd;} +.nav-tabs>li{margin-bottom:-1px;} +.nav-tabs>li>a{padding-top:9px;padding-bottom:9px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;} +.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} +.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.nav-pills .active>a,.nav-pills .active>a:hover{color:#ffffff;background-color:#0088cc;} +.nav-stacked>li{float:none;} +.nav-stacked>li>a{margin-right:0;} +.nav-tabs.nav-stacked{border-bottom:0;} +.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} +.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} +.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;} +.nav-pills.nav-stacked>li>a{margin-bottom:3px;} +.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} +.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;} +.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;margin-top:6px;} +.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;} +.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;} +.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;} +.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;} +.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;opacity:1;filter:alpha(opacity=100);} +.tabs-stacked .open>a:hover{border-color:#999999;} +.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";} +.tabbable:after{clear:both;} +.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;} +.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} +.tab-content>.active,.pill-content>.active{display:block;} +.tabs-below .nav-tabs{border-top:1px solid #ddd;} +.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;} +.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;} +.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;} +.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;} +.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} +.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} +.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} +.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} +.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} +.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} +.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} +.navbar{overflow:visible;margin-bottom:18px;} +.navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);} +.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;} +.btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;} +.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} +.btn-navbar .icon-bar+.icon-bar{margin-top:3px;} +.nav-collapse.collapse{height:auto;} +.navbar .brand:hover{text-decoration:none;} +.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;} +.navbar .navbar-text{margin-bottom:0;line-height:40px;color:#999999;}.navbar .navbar-text a:hover{color:#ffffff;background-color:transparent;} +.navbar .btn,.navbar .btn-group{margin-top:5px;} +.navbar .btn-group .btn{margin-top:0;} +.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";} +.navbar-form:after{clear:both;} +.navbar-form input,.navbar-form select{display:inline-block;margin-top:5px;margin-bottom:0;} +.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} +.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} +.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;color:rgba(255, 255, 255, 0.75);background:#666;background:rgba(255, 255, 255, 0.3);border:1px solid #111;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query :-moz-placeholder{color:#eeeeee;} +.navbar-search .search-query::-webkit-input-placeholder{color:#eeeeee;} +.navbar-search .search-query:hover{color:#ffffff;background-color:#999999;background-color:rgba(255, 255, 255, 0.5);} +.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} +.navbar-fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030;} +.navbar-fixed-top .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} +.navbar .nav.pull-right{float:right;} +.navbar .nav>li{display:block;float:left;} +.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} +.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;} +.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;background-color:rgba(0, 0, 0, 0.5);} +.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;} +.navbar .nav.pull-right{margin-left:10px;margin-right:0;} +.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} +.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} +.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;} +.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);} +.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;} +.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;} +.navbar .nav.pull-right .dropdown-menu{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before{left:auto;right:12px;} +.navbar .nav.pull-right .dropdown-menu:after{left:auto;right:13px;} +.hero-unit{padding:60px;margin-bottom:30px;background-color:#f5f5f5;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;} +.hero-unit p{font-size:18px;font-weight:200;line-height:27px;} +.pull-right{float:right;} +.pull-left{float:left;} +.hide{display:none;} +.show{display:block;} +.invisible{visibility:hidden;} +#call-to-action{text-align:right;} +a.headerlink{display:none;} +#title{color:#ffffff;} +.hero-unit h1{padding-bottom:20px ! important;} +#top-bar small{color:#f8f8ff;text-shadow:0px -1px 0px #5f0c17;} +.admonition{padding:14px 35px 14px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.admonition .admonition-title{font-size:14pt;font-weight:bold;} +.admonition.note .admonition-title,.admonition-todo .admonition-title{color:#c09853;} +.admonition.tip,.admonition.hint{background-color:#dff0d8;border-color:#d6e9c6;} +.admonition.tip .admonition-title,.admonition.hint .admonition-title{color:#468847;} +.admonition.error,.admonition.warning,.admonition.caution,.admonition.danger,.admonition.attention{background-color:#f2dede;border-color:#eed3d7;} +.admonition.error .admonition-title,.admonition.warning .admonition-title,.admonition.caution .admonition-title,.admonition.danger .admonition-title,.admonition.attention .admonition-title{color:#b94a48;} +.admonition.important{background-color:#d9edf7;border-color:#bce8f1;} +.admonition.important .admonition-title{color:#3a87ad;} +.admonition>p,.admonition>ul{margin-bottom:0;} +.admonition p+p{margin-top:5px;} +a.internal.reference>em{font-style:normal ! important;text-decoration:none ! important;} +tt{padding:1px 3px;font-family:'Panic Sans',Menlo,Monaco,Consolas,Andale Mono,Courier New,monospace;font-size:12px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#fee9cc;color:rgba(0, 0, 0, 0.75);} +.section>p,.section ul li,.admonition p,.section dt,.section dl{font-size:13pt;line-height:18pt;} +.section tt{font-size:11pt;line-height:11pt;} +.section>*{margin-bottom:20px;} +pre{font-family:'Panic Sans',Menlo,Monaco,Consolas,Andale Mono,Courier New,monospace !important;font-size:12pt !important;line-height:22px !important;display:block !important;width:auto !important;height:auto !important;overflow:auto !important;white-space:pre !important;word-wrap:normal !important;} +#body h1,h1 tt{font-size:28pt;} +h1 tt{background-color:transparent;font-size:26pt !important;} +#body h2{font-size:24pt;} +h2 tt{background-color:transparent;font-size:22pt !important;} +#body h3{font-size:20pt;} +h3 tt{background-color:transparent;font-size:18pt !important;} +#body h4{font-size:16pt;} +h4 tt{background-color:transparent;font-size:14pt !important;} +#sidebar tt{color:#08c;background-color:transparent;} +.hero-unit .toctree-wrapper{text-align:center;} +.hero-unit li{display:inline;list-style-type:none;padding-right:20px;} +.hero-unit li a:after{content:" »";} +.hero-unit li a{display:inline-block;padding:10px 10px 10px;font-size:16pt;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;} +.btn:first-child{*margin-left:0;} .hero-unit li a:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} .hero-unit li a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} .hero-unit li a:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;} - -.hero-unit li a{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} +.hero-unit li a{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);} +.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} +.hero-unit li a:active{background-color:#408140 \9;} +.hero-unit li a,.hero-unit li a:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} +.hero-unit li a:active{color:rgba(255, 255, 255, 0.75);} +.hero-unit li a:hover,.hero-unit li a:active{background-color:#51a351;} .hero-unit li a:active{background-color:#408140 \9;} - -.hero-unit li a, .hero-unit li a:hover {text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} -.hero-unit li a:active {color: rgba(255, 255, 255, 0.75);} - -.hero-unit li a:hover, -.hero-unit li a:active { - background-color: #51a351; -} - -.hero-unit li a:active { - background-color: #408140 \9; -} From 18fd93b679ea265a7b2b316b7c8e5c7f587bcfb6 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 13:01:26 -0800 Subject: [PATCH 0253/2771] Use some LESS. --- docs/source/_themes/yammerdoc/less/code.less | 6 +- .../source/_themes/yammerdoc/less/mixins.less | 2 +- .../_themes/yammerdoc/less/yammerdoc.less | 64 +++++----- .../_themes/yammerdoc/static/yammerdoc.css | 111 ++---------------- 4 files changed, 51 insertions(+), 132 deletions(-) diff --git a/docs/source/_themes/yammerdoc/less/code.less b/docs/source/_themes/yammerdoc/less/code.less index 0cc3db857ae..c640537ae87 100644 --- a/docs/source/_themes/yammerdoc/less/code.less +++ b/docs/source/_themes/yammerdoc/less/code.less @@ -3,7 +3,7 @@ // -------------------------------------------------------- // Inline and block code styles -code, +.code-and-pre, pre { padding: 0 3px 2px; #font > #family > .monospace; @@ -11,8 +11,8 @@ pre { color: @grayDark; .border-radius(3px); } -code { - padding: 3px 4px; +.code, code { + .code-and-pre(); color: #d14; background-color: #f7f7f9; border: 1px solid #e1e1e8; diff --git a/docs/source/_themes/yammerdoc/less/mixins.less b/docs/source/_themes/yammerdoc/less/mixins.less index 545ccb9bad3..30e868e72fb 100644 --- a/docs/source/_themes/yammerdoc/less/mixins.less +++ b/docs/source/_themes/yammerdoc/less/mixins.less @@ -103,7 +103,7 @@ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } .monospace() { - font-family: Menlo, Monaco, "Courier New", monospace; + font-family: "Panic Sans", Menlo, Monaco, Consolas, "Courier New", monospace; } } .shorthand(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { diff --git a/docs/source/_themes/yammerdoc/less/yammerdoc.less b/docs/source/_themes/yammerdoc/less/yammerdoc.less index 53c3285b487..17313e86cac 100644 --- a/docs/source/_themes/yammerdoc/less/yammerdoc.less +++ b/docs/source/_themes/yammerdoc/less/yammerdoc.less @@ -6,7 +6,6 @@ @import "layouts.less"; @import "type.less"; @import "code.less"; -@import "forms.less"; @import "tables.less"; @import "buttons.less"; @import "navs.less"; @@ -107,14 +106,7 @@ a.internal.reference > em { } tt { - padding: 1px 3px; - font-family: 'Panic Sans', Menlo, Monaco, Consolas, Andale Mono, Courier New, monospace; - font-size: 12px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - background-color: #fee9cc; - color: rgba(0, 0, 0, 0.75); + .code(); } .section > p, .section ul li, .admonition p, .section dt, .section dl { @@ -194,26 +186,40 @@ h4 tt { padding-right: 20px; } -.hero-unit li a:after { - content: " »"; +.hero-unit li a { + .btn(); + .btn-success(); + padding:10px 10px 10px; + font-size:16pt; + &:hover { + color: @grayDark; + text-decoration: none; + background-color: darken(@white, 10%); + background-position: 0 -15px; + + // transition is only when going to hover, otherwise the background + // behind the gradient (there for IE<=9 fallback) gets mismatched + .transition(background-position .1s linear); + .btn-success(); + } + + &:focus { + .tab-focus(); + .btn-success(); + } + + &:active { + background-image: none; + @shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05); + .box-shadow(@shadow); + background-color: darken(@white, 10%); + background-color: darken(@white, 15%) e("\9"); + color: rgba(0,0,0,.5); + outline: 0; + .btn-success(); + } } -.hero-unit li a{display:inline-block;padding:10px 10px 10px;font-size:16pt;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:first-child{*margin-left:0;} -.hero-unit li a:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} -.hero-unit li a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} -.hero-unit li a:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;} - -.hero-unit li a{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} -.hero-unit li a:active{background-color:#408140 \9;} - -.hero-unit li a, .hero-unit li a:hover {text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} -.hero-unit li a:active {color: rgba(255, 255, 255, 0.75);} - -.hero-unit li a:hover, -.hero-unit li a:active { - background-color: #51a351; -} - -.hero-unit li a:active { - background-color: #408140 \9; +.hero-unit li a:after { + content: " »"; } diff --git a/docs/source/_themes/yammerdoc/static/yammerdoc.css b/docs/source/_themes/yammerdoc/static/yammerdoc.css index 28b8b62462a..e1e4e007a82 100644 --- a/docs/source/_themes/yammerdoc/static/yammerdoc.css +++ b/docs/source/_themes/yammerdoc/static/yammerdoc.css @@ -98,94 +98,10 @@ q:before,q:after,blockquote:before,blockquote:after{content:"";} address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;} small{font-size:100%;} cite{font-style:normal;} -code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} -code{padding:3px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} +.code-and-pre,pre{padding:0 3px 2px;font-family:"Panic Sans",Menlo,Monaco,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.code,code{padding:0 3px 2px;font-family:"Panic Sans",Menlo,Monaco,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;}pre.prettyprint{margin-bottom:18px;} pre code{padding:0;background-color:transparent;} -form{margin:0 0 18px;} -fieldset{padding:0;margin:0;border:0;} -legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;} -label,input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;} -label{display:block;margin-bottom:5px;color:#333333;} -input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} -.uneditable-textarea{width:auto;height:auto;} -label input,label textarea,label select{display:block;} -input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:0;cursor:pointer;border-radius:0 \0/;} -input[type="file"]{padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} -input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;} -select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;} -select{width:220px;background-color:#ffffff;} -select[multiple],select[size]{height:auto;} -input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} -textarea{height:auto;} -input[type="hidden"]{display:none;} -.radio,.checkbox{padding-left:18px;} -.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;} -.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} -.radio.inline,.checkbox.inline{display:inline-block;margin-bottom:0;vertical-align:middle;} -.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} -.controls>.radio.inline:first-child,.controls>.checkbox.inline:first-child{padding-top:0;} -input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;} -input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;} -input[type="file"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} -.input-mini{width:60px;} -.input-small{width:90px;} -.input-medium{width:150px;} -.input-large{width:210px;} -.input-xlarge{width:270px;} -.input-xxlarge{width:530px;} -input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;} -input.span1,textarea.span1,.uneditable-input.span1{width:50px;} -input.span2,textarea.span2,.uneditable-input.span2{width:130px;} -input.span3,textarea.span3,.uneditable-input.span3{width:210px;} -input.span4,textarea.span4,.uneditable-input.span4{width:290px;} -input.span5,textarea.span5,.uneditable-input.span5{width:370px;} -input.span6,textarea.span6,.uneditable-input.span6{width:450px;} -input.span7,textarea.span7,.uneditable-input.span7{width:530px;} -input.span8,textarea.span8,.uneditable-input.span8{width:610px;} -input.span9,textarea.span9,.uneditable-input.span9{width:690px;} -input.span10,textarea.span10,.uneditable-input.span10{width:770px;} -input.span11,textarea.span11,.uneditable-input.span11{width:850px;} -input.span12,textarea.span12,.uneditable-input.span12{width:930px;} -input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;} -.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} -.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;} -.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} -.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} -.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;} -.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} -.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} -.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;} -.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} -input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} -.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #ddd;} -.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} -:-moz-placeholder{color:#999999;} -::-webkit-input-placeholder{color:#999999;} -.help-block{margin-top:5px;margin-bottom:0;color:#999999;} -.help-inline{display:inline-block;*display:inline;*zoom:1;margin-bottom:9px;vertical-align:middle;padding-left:5px;} -.input-prepend,.input-append{margin-bottom:5px;*zoom:1;}.input-prepend:before,.input-append:before,.input-prepend:after,.input-append:after{display:table;content:"";} -.input-prepend:after,.input-append:after{clear:both;} -.input-prepend input,.input-append input,.input-prepend .uneditable-input,.input-append .uneditable-input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;} -.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;} -.input-prepend .add-on,.input-append .add-on{float:left;display:block;width:auto;min-width:16px;height:18px;margin-right:-1px;padding:4px 5px;font-weight:normal;line-height:18px;color:#999999;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#f5f5f5;border:1px solid #ccc;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} -.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;} -.input-prepend .add-on{*margin-top:1px;} -.input-append input,.input-append .uneditable-input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} -.input-append .uneditable-input{border-right-color:#ccc;} -.input-append .add-on{margin-right:0;margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} -.input-append input:first-child{*margin-left:-160px;}.input-append input:first-child+.add-on{*margin-left:-21px;} -.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;} -.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input{display:inline-block;margin-bottom:0;} -.form-search label,.form-inline label,.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{display:inline-block;} -.form-search .input-append .add-on,.form-inline .input-prepend .add-on,.form-search .input-append .add-on,.form-inline .input-prepend .add-on{vertical-align:middle;} -.control-group{margin-bottom:9px;} -.form-horizontal legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;} -.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";} -.form-horizontal .control-group:after{clear:both;} -.form-horizontal .control-group>label{float:left;width:140px;padding-top:5px;text-align:right;} -.form-horizontal .controls{margin-left:160px;} -.form-horizontal .form-actions{padding-left:160px;} table{max-width:100%;border-collapse:collapse;border-spacing:0;} .table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;border-top:1px solid #ddd;} .table th{font-weight:bold;vertical-align:bottom;} @@ -355,7 +271,7 @@ a.headerlink{display:none;} .admonition>p,.admonition>ul{margin-bottom:0;} .admonition p+p{margin-top:5px;} a.internal.reference>em{font-style:normal ! important;text-decoration:none ! important;} -tt{padding:1px 3px;font-family:'Panic Sans',Menlo,Monaco,Consolas,Andale Mono,Courier New,monospace;font-size:12px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#fee9cc;color:rgba(0, 0, 0, 0.75);} +tt{padding:0 3px 2px;font-family:"Panic Sans",Menlo,Monaco,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} .section>p,.section ul li,.admonition p,.section dt,.section dl{font-size:13pt;line-height:18pt;} .section tt{font-size:11pt;line-height:11pt;} .section>*{margin-bottom:20px;} @@ -371,16 +287,13 @@ h4 tt{background-color:transparent;font-size:14pt !important;} #sidebar tt{color:#08c;background-color:transparent;} .hero-unit .toctree-wrapper{text-align:center;} .hero-unit li{display:inline;list-style-type:none;padding-right:20px;} +.hero-unit li a{display:inline-block;padding:4px 10px 4px;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);padding:10px 10px 10px;font-size:16pt;}.hero-unit li a:first-child{*margin-left:0;} +.hero-unit li a:hover,.hero-unit li a:active,.hero-unit li a.active,.hero-unit li a.disabled,.hero-unit li a[disabled]{background-color:#51a351;} +.hero-unit li a:active,.hero-unit li a.active{background-color:#408140 \9;} +.hero-unit li a:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.hero-unit li a:hover:hover,.hero-unit li a:hover:active,.hero-unit li a:hover.active,.hero-unit li a:hover.disabled,.hero-unit li a:hover[disabled]{background-color:#51a351;} +.hero-unit li a:hover:active,.hero-unit li a:hover.active{background-color:#408140 \9;} +.hero-unit li a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.hero-unit li a:focus:hover,.hero-unit li a:focus:active,.hero-unit li a:focus.active,.hero-unit li a:focus.disabled,.hero-unit li a:focus[disabled]{background-color:#51a351;} +.hero-unit li a:focus:active,.hero-unit li a:focus.active{background-color:#408140 \9;} +.hero-unit li a:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.hero-unit li a:active:hover,.hero-unit li a:active:active,.hero-unit li a:active.active,.hero-unit li a:active.disabled,.hero-unit li a:active[disabled]{background-color:#51a351;} +.hero-unit li a:active:active,.hero-unit li a:active.active{background-color:#408140 \9;} .hero-unit li a:after{content:" »";} -.hero-unit li a{display:inline-block;padding:10px 10px 10px;font-size:16pt;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;} -.btn:first-child{*margin-left:0;} -.hero-unit li a:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} -.hero-unit li a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} -.hero-unit li a:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;} -.hero-unit li a{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);} -.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} -.hero-unit li a:active{background-color:#408140 \9;} -.hero-unit li a,.hero-unit li a:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} -.hero-unit li a:active{color:rgba(255, 255, 255, 0.75);} -.hero-unit li a:hover,.hero-unit li a:active{background-color:#51a351;} -.hero-unit li a:active{background-color:#408140 \9;} From a00ce40d5c00496b8458ccd434943c43c549dd9e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 13:05:23 -0800 Subject: [PATCH 0254/2771] Update the relnotes. --- docs/source/relnotes.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/relnotes.rst b/docs/source/relnotes.rst index 7427a55d68c..78fbad0016c 100644 --- a/docs/source/relnotes.rst +++ b/docs/source/relnotes.rst @@ -31,8 +31,11 @@ v0.2.0: TBD * Upgraded to JDBI 2.31.2. * Fixed JAR locations in the CLI usage screens. * Upgraded to Metrics 2.0.2. -* Added support for ``ServletContextListener`` instances. +* Added support for all servlet listener types. * Added ``Log#setLevel(Level)``. +* Added ``Service#getJerseyContainer``, which allows services to fully customize the Jersey + container instance. +* Added the ``http.contextParameters`` configuration parameter. .. _rel-0.1.3: From 9b77d2de8fc9343ee404b3cc7badef85699f837a Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 15:28:32 -0800 Subject: [PATCH 0255/2771] Added dropwizard-client docs. --- docs/source/manual/client.rst | 158 +++++++++++++++++++++++++++++++++- docs/source/manual/core.rst | 3 +- 2 files changed, 159 insertions(+), 2 deletions(-) diff --git a/docs/source/manual/client.rst b/docs/source/manual/client.rst index a318df76843..ac0900a9ac6 100644 --- a/docs/source/manual/client.rst +++ b/docs/source/manual/client.rst @@ -4,4 +4,160 @@ Dropwizard Client ################# -.. todo:: write Client +.. rubric:: The ``dropwizard-client`` module provides you with two different performant, + instrumented HTTP clients so you can integrate your service with other web + services: :ref:`man-client-apache` and :ref:`man-client-jersey`. + +.. _man-client-apache: + +Apache HttpClient +================= + +The underlying library for ``dropwizard-client`` is Apache's HttpClient_, a full-featured, +well-tested HTTP client library. + +.. _HttpClient: http://hc.apache.org/httpcomponents-client-ga/ + +To create a :ref:`manged `, instrumented ``HttpClient`` instance, your +:ref:`configuration class ` needs an ``HttpClientConfiguration`` instance: + +.. code-block:: java + + public class ExampleConfiguration extends Configuration { + @Valid + @NotNull + @JsonProperty + private HttpClientConfiguration httpClient = new HttpClientConfiguration(); + + public HttpClientConfiguration getHttpClientConfiguration() { + return httpClient; + } + } + +Then, in your service's ``initialize`` method, create a new ``HttpClientFactory``: + +.. code-block:: java + + @Override + protected void initialize(ExampleConfiguration config, + Environment environment) { + final HttpClientFactory factory = new HttpClientFactory(config.getHttpClientConfiguration()); + final HttpClient httpClient = factory.build(); + environment.addResource(new ExternalServiceResource(httpClient)); + } + +Your service's configuration file will then look like this: + +.. code-block:: yaml + + httpClient: + timeout: 1s # timeout after 1s while connecting, reading, or writing + timeToLive: 10m # keep connections open for 10 minutes + cookiesEnabled: false # don't track cookies + +.. _man-client-apache-metrics: + +Metrics +------- + +Dropwizard's ``HttpClientFactory`` actually gives you an instrumented subclass which tracks the +following pieces of data: + +``org.apache.http.conn.ClientConnectionManager.connections`` + The number of open connections currently in the connection pool. + +``org.apache.http.impl.conn.tsccm.ConnPoolByRoute.new-connections`` + The rate at which new connections are being created. + +``org.apache.http.client.HttpClient.get-requests`` + The rate at which ``GET`` requests are being sent. + +``org.apache.http.client.HttpClient.post-requests`` + The rate at which ``POST`` requests are being sent. + +``org.apache.http.client.HttpClient.head-requests`` + The rate at which ``HEAD`` requests are being sent. + +``org.apache.http.client.HttpClient.put-requests`` + The rate at which ``PUT`` requests are being sent. + +``org.apache.http.client.HttpClient.delete-requests`` + The rate at which ``DELETE`` requests are being sent. + +``org.apache.http.client.HttpClient.options-requests`` + The rate at which ``OPTIONS`` requests are being sent. + +``org.apache.http.client.HttpClient.trace-requests`` + The rate at which ``TRACE`` requests are being sent. + +``org.apache.http.client.HttpClient.connect-requests`` + The rate at which ``CONNECT`` requests are being sent. + +``org.apache.http.client.HttpClient.move-requests`` + The rate at which ``MOVE`` requests are being sent. + +``org.apache.http.client.HttpClient.patch-requests`` + The rate at which ``PATCH`` requests are being sent. + +``org.apache.http.client.HttpClient.other-requests`` + The rate at which requests with none of the above methods are being sent. + +.. _man-client-jersey: + +JerseyClient +============ + +If HttpClient_ is too low-level for you, Dropwizard also supports Jersey's `Client API`_. +``JerseyClient`` allows you to use all of the server-side media type support that your service uses +to, for example, deserialize ``application/json`` request entities as POJOs. + +.. _Client API: http://jersey.java.net/nonav/documentation/latest/user-guide.html#client-api + +To create a :ref:`manged `, instrumented ``JerseyClient`` instance, your +:ref:`configuration class ` needs an ``JerseyClientConfiguration`` instance: + +.. code-block:: java + + public class ExampleConfiguration extends Configuration { + @Valid + @NotNull + @JsonProperty + private JerseyClientConfiguration httpClient = new JerseyClientConfiguration(); + + public JerseyClientConfiguration getJerseyClientConfiguration() { + return httpClient; + } + } + +Then, in your service's ``initialize`` method, create a new ``JerseyClientFactory``: + +.. code-block:: java + + @Override + protected void initialize(ExampleConfiguration config, + Environment environment) { + final JerseyClientFactory factory = new JerseyClientFactory(config.getJerseyClientConfiguration()); + final JerseyClient jerseyClient = factory.build(environment); + environment.addResource(new ExternalServiceResource(jerseyClient)); + } + +Your service's configuration file will then look like this: + +.. code-block:: yaml + + httpClient: + timeout: 1s # timeout after 1s while connecting, reading, or writing + timeToLive: 10m # keep connections open for 10 minutes + cookiesEnabled: false # don't track cookies + gzipEnabled: true # allow for gzipped request and response entities + minThreads: 1 + maxThreads: 128 # thread pool for JerseyClient's async requests + +.. tip:: + + As of Jersey 1.11, most of the classes ``JerseyClient`` returns are declared ``final`` and as + such aren't mockable using Mockito_. In place of Mockito, we recommend using `PowerMock`_'s + Mockito-compatible API. + +.. _Mockito: http://code.google.com/p/mockito/ +.. _PowerMock: http://code.google.com/p/powermock/ diff --git a/docs/source/manual/core.rst b/docs/source/manual/core.rst index 81a0f0012ca..ed9e5cb4c5f 100644 --- a/docs/source/manual/core.rst +++ b/docs/source/manual/core.rst @@ -6,7 +6,8 @@ Dropwizard Core .. highlight:: text -The ``dropwizard-core`` module provides you with everything you'll need for most of your services. +.. rubric:: The ``dropwizard-core`` module provides you with everything you'll need for most of your + services. It includes: From 7d3f67bc93336247be51bb2c88c964b3143369f7 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 16:18:22 -0800 Subject: [PATCH 0256/2771] Tighten up docs for dropwizard-client. --- docs/source/manual/client.rst | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/source/manual/client.rst b/docs/source/manual/client.rst index ac0900a9ac6..6f61181dde3 100644 --- a/docs/source/manual/client.rst +++ b/docs/source/manual/client.rst @@ -4,6 +4,8 @@ Dropwizard Client ################# +.. highlight:: text + .. rubric:: The ``dropwizard-client`` module provides you with two different performant, instrumented HTTP clients so you can integrate your service with other web services: :ref:`man-client-apache` and :ref:`man-client-jersey`. @@ -51,9 +53,14 @@ Your service's configuration file will then look like this: .. code-block:: yaml httpClient: - timeout: 1s # timeout after 1s while connecting, reading, or writing - timeToLive: 10m # keep connections open for 10 minutes - cookiesEnabled: false # don't track cookies + # timeout after 1s while connecting, reading, or writing + timeout: 1s + + # keep connections open for 10 minutes + timeToLive: 10m + + # don't track cookies + cookiesEnabled: false .. _man-client-apache-metrics: From cedff7876b53a8f572613f3584dd3b3c21f100f9 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 16:18:29 -0800 Subject: [PATCH 0257/2771] Add docs for dropwizard-db. --- docs/source/manual/db.rst | 142 +++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/docs/source/manual/db.rst b/docs/source/manual/db.rst index d06454e3d87..e935aaef9c3 100644 --- a/docs/source/manual/db.rst +++ b/docs/source/manual/db.rst @@ -4,4 +4,144 @@ Dropwizard DB ############# -.. todo:: write DB +.. highlight:: text + +.. rubric:: The ``dropwizard-db`` module provides you with managed access to JDBI_, a flexible and + modular library for interacting with relational databases via SQL. + +.. _JDBI: http://jdbi.org/ + +Access to JDBI is provided via a ``DBI`` subclass: ``Database``. + +Configuration +============= + +To create a :ref:`manged `, instrumented ``Database`` instance, your +:ref:`configuration class ` needs an ``DatabaseConfiguration`` instance: + +.. code-block:: java + + public class ExampleConfiguration extends Configuration { + @Valid + @NotNull + @JsonProperty + private DatabaseConfiguration database = new DatabaseConfiguration(); + + public DatabaseConfiguration getDatabaseConfiguration() { + return database; + } + } + +Then, in your service's ``initialize`` method, create a new ``DatabaseFactory``: + +.. code-block:: java + + @Override + protected void initialize(ExampleConfiguration config, + Environment environment) { + final DatabaseFactory factory = new DatabaseFactory(environment); + final Database db = factory.build(config.getDatabaseConfiguration(), "postgresql"); + final UserDAO dao = db.onDemand(UserDAO.class); + environment.addResource(new UserResource(dao)); + } + +This will create a new :ref:`managed ` connection pool to the database, a +:ref:`health check ` for connectivity to the database, and a new ``Database`` +instance for you to use. + +Your service's configuration file will then look like this: + +.. code-block:: yaml + + database: + # the name of your JDBC driver + driverClass: org.postgresql.Driver + + # the username + user: pg-user + + # the password + password: iAMs00perSecrEET + + # the JDBC URL + url: jdbc:postgresql://db.example.com/db-prod + + # any properties specific to your JDBC driver: + properties: + charSet: UTF-8 + + # the maximum amount of time to wait on an empty pool before throwing an exception + maxWaitForConnection: 1s + + # the SQL query to run when validating a connection's liveness + validationQuery: "/* MyService Health Check */ SELECT 1" + + # the minimum number of connections to keep open + minSize: 8 + + # the maximum number of connections to keep open + maxSize: 32 + + # whether or not idle connections should be validated + checkConnectionWhileIdle: false + + # how long a connection must be held before it can be validated + checkConnectionHealthWhenIdleFor: 10s + + # the maximum lifetime of an idle connection + closeConnectionIfIdleFor: 1 minute + +Usage +===== + +We highly recommend you use JDBI's `SQL Objects API`_, which allows you to write DAO classes as +interfaces: + +.. _SQL Objects API: http://jdbi.org/sql_object_overview/ + +.. code-block:: java + + public interface MyDAO { + @SqlUpdate("create table something (id int primary key, name varchar(100))") + void createSomethingTable(); + + @SqlUpdate("insert into something (id, name) values (:id, :name)") + void insert(@Bind("id") int id, @Bind("name") String name); + + @SqlQuery("select name from something where id = :id") + String findNameById(@Bind("id") int id); + } + + final MyDAO dao = database.onDemand(MyDAO.class); + +This ensures your DAO classes are trivially mockable, as well as encouraging you to extract mapping +code (e.g., ``ResultSet`` -> domain objects) into testable, reusable classes. + +Exception Handling +================== + +By adding the ``DBIExceptionsBundle`` to your :ref:`service `, your Dropwizard +application will automatically unwrap any thrown ``SQLException`` or ``DBIException`` instances. +This is critical for debugging, since + +Prepended Comments +================== + +If you're using JDBI's `SQL Objects API`_ (and you should be), ``dropwizard-db`` will automatically +prepend the SQL object's class and method name to the SQL query as an SQL comment: + + + +.. code-block:: sql + + /* com.example.service.dao.UserDAO.findByName */ + SELECT id, name, email + FROM users + WHERE name = 'Coda'; + +This will allow you to quickly determine the origin of any slow or misbehaving queries. + +Guava Support +============= + +``Database`` supports ``Optional`` arguments and ``ImmutableList`` query results. From 7e22fc5c16bacaada207ebd3a1f2a3341add702b Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 16:34:15 -0800 Subject: [PATCH 0258/2771] Added docs for dw-scala. --- docs/source/manual/scala.rst | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/source/manual/scala.rst b/docs/source/manual/scala.rst index 4c71b81ab0a..35fd1dcd144 100644 --- a/docs/source/manual/scala.rst +++ b/docs/source/manual/scala.rst @@ -4,4 +4,37 @@ Dropwizard & Scala ################## -.. todo:: write Scala +.. highlight:: text + +.. rubric:: The ``dropwizard-scala`` module provides you with glue code required to write your + Dropwizard services in Scala_. + + +.. _Scala: http://www.scala-lang.org + +Dropwizard :ref:`services ` should extend ``ScalaService`` instead of ``Service``: + +.. code-block:: scala + + object ExampleService extends ScalaService[ExampleConfiguration]("example") { + def initialize(configuration: ExampleConfiguration, environment: Environment) { + environment.addResource(new ExampleResource) + } + } + +.. _man-scala-features: + +Features +======== + +``dropwizard-scala`` provides the following: + +* ``QueryParam``-annotated parameters of type ``Seq[String]``, ``List[String]``, ``Vector[String]``, + ``IndexedSeq[String]``, ``Set[String]``, and ``Option[String]``. +* ``AST.JValue`` request and response entities. +* ``JsonNode`` request and response entities. +* Case class (i.e., ``Product`` instances) JSON request and response entities. +* ``Array[A]`` request and response entities. (Due to the JVM's type erasure and mismatches between + Scala and Java type signatures, this is the only "generic" class supported since ``Array`` type + parameters are reified.) +* ``BearerToken``-annotated parameters of type ``Option[String]``. From ce3a80247c2a231a6b6f8f77bb87d660c6f2761e Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 16:52:46 -0800 Subject: [PATCH 0259/2771] Replace em-dashes with double dashes. SmartyPants'll get 'em. --- docs/source/manual/core.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/manual/core.rst b/docs/source/manual/core.rst index ed9e5cb4c5f..85d789c9312 100644 --- a/docs/source/manual/core.rst +++ b/docs/source/manual/core.rst @@ -251,7 +251,7 @@ For example, given a theoretical Riak__ client which needs to be started and sto } -If ``RiakClientManager#start()`` throws an exception—e.g., an error connecting to the server—your +If ``RiakClientManager#start()`` throws an exception--e.g., an error connecting to the server--your service will not start and a full exception will be logged. If ``RiakClientManager#stop()`` throws an exception, the exception will be logged but your service will still be able to shut down. From 843d4bb2b6c246acdbeb376f1e08886963f132bb Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 16:53:07 -0800 Subject: [PATCH 0260/2771] Add dw-templates docs. --- docs/source/manual/templates.rst | 61 +++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/docs/source/manual/templates.rst b/docs/source/manual/templates.rst index 4613e130dd7..7860dac4cd5 100644 --- a/docs/source/manual/templates.rst +++ b/docs/source/manual/templates.rst @@ -4,4 +4,63 @@ Dropwizard Templates #################### -.. todo:: write Templates +.. highlight:: text + +.. rubric:: The ``dropwizard-templates`` module provides you with simple, fast templates using the + Freemarker_. + +.. _Freemarker: http://freemarker.sourceforge.net/ + +To enable Freemarker templates for your :ref:`service `, add the +``TemplateBundle``: + +.. code-block:: java + + public MyService() { + super("my-service"); + addBundle(new TemplateBundle()); + } + +Then, in your :ref:`resource method `, return a ``Viewable`` instance: + +.. code-block:: java + + @Path("/people/{id}") + @Produces(MediaType.TEXT_HTML) + public class PersonResource { + + private final PersonDAO dao; + + public PersonResource(PersonDAO dao) { + this.dao = dao; + } + + @GET + public Viewable getPerson(@PathParam("id") String id) { + final Person person = dao.find(id); + return new Viewable("index.ftl", person); + } + } + +``index.ftl`` is the path of the template relative to the class name. If this class was +``com.example.service.PersonResource``, Jersey would then look for the file +``src/main/resources/com/example/service/PersonResource/index.ftl``, which might look something like +this: + +.. code-block:: text + :emphasize-lines: 1, 5 + + <#-- @ftlvariable name="" type="com.example.core.Person" --> + + + +

          Hello, ${name?html}!

          + + + +The ``@fltvariable`` lets Freemarker (and any Freemarker IDE plugins you may be using) that the +default object is a ``com.example.core.Person`` instance. If you attempt to call a property which +doesn't exist on ``Person``--``getConnectionPool()``, for example--it will flag that line in your +IDE. + +For more information on how to use Freemarker, see the `Freemarker documentation `_. From 1759b9e71c4df20373a24abdf5270ace510d3bf3 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 18:03:58 -0800 Subject: [PATCH 0261/2771] Round out testing. Also, drop production/running until I have time. --- docs/source/manual/index.rst | 2 - docs/source/manual/production.rst | 7 -- docs/source/manual/running.rst | 7 -- docs/source/manual/testing.rst | 177 +++++++++++++++++++++++++++++- 4 files changed, 176 insertions(+), 17 deletions(-) delete mode 100644 docs/source/manual/production.rst delete mode 100644 docs/source/manual/running.rst diff --git a/docs/source/manual/index.rst b/docs/source/manual/index.rst index 18fea3c42ca..d118377bad9 100644 --- a/docs/source/manual/index.rst +++ b/docs/source/manual/index.rst @@ -17,6 +17,4 @@ User Manual scala templates testing - running - production diff --git a/docs/source/manual/production.rst b/docs/source/manual/production.rst deleted file mode 100644 index 0fdf509aa14..00000000000 --- a/docs/source/manual/production.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _manual-production: - -######################## -Dropwizard In Production -######################## - -.. todo:: write Production diff --git a/docs/source/manual/running.rst b/docs/source/manual/running.rst deleted file mode 100644 index 52676872e56..00000000000 --- a/docs/source/manual/running.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _manual-running: - -########################### -Running Dropwizard Services -########################### - -.. todo:: write Running diff --git a/docs/source/manual/testing.rst b/docs/source/manual/testing.rst index 984508c906b..f1f251961af 100644 --- a/docs/source/manual/testing.rst +++ b/docs/source/manual/testing.rst @@ -4,4 +4,179 @@ Testing Dropwizard ################## -.. todo:: write Testing +.. highlight:: text + +.. rubric:: The ``dropwizard-testing`` module provides you with some handy classes for testing + your :ref:`representation classes ` + and :ref:`resource classes `. + +.. _man-testing-representations: + +Testing Representations +======================= + +While Jackson's JSON support is powerful and fairly easy-to-use, you shouldn't just rely on +eyeballing your representation classes to ensure you're actually producing the API you think you +are. By using the helper methods in `JsonHelpers` you can add unit tests for serializing and +deserializing your representation classes to and from JSON. + +Let's assume we have a ``Person`` class which your API uses as both a request entity (e.g., when +writing via a ``PUT`` request) and a response entity (e.g., when reading via a ``GET`` request): + +.. code-block:: java + + public class Person { + @JsonProperty + private String name; + + @JsonProperty + private String email; + + private Person() { + // Jackson deserialization + } + + public Person(String name, String email) { + this.name = name; + this.email = email; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + // hashCode + // equals + // toString etc. + } + +.. _man-testing-representations-fixtures: + +Fixtures +-------- + +First, write out the exact JSON representation of a ``Person`` in the +``src/test/resources/fixtures`` directory of your Dropwizard project as ``person.json``: + +.. code-block:: javascript + + { + "name": "Luther Blissett", + "email": "lb@example.com" + } + +.. _man-testing-representations-serialization: + +Testing Serialization +--------------------- + +Next, write a test for serializing a ``Person`` instance to JSON: + +.. code-block:: java + + import com.yammer.dropwizard.testing.JsonHelpers.*; + import org.hamcrest.Matchers.*; + + @Test + public void serializesToJSON() throws Exception { + final Person = new Person("Luther Blissett", "lb@example.com"); + assertThat("a Person can be serialized to JSON", + asJSON(person), + is(equalTo(jsonFixture("fixtures/person.json")))); + } + +This test uses `Hamcrest matchers`_ and JUnit_ to test that when a ``Person`` instance is serialized +via Jackson it matches the JSON in the fixture file. (The comparison is done via a normalized JSON +string representation, so whitespace doesn't affect the results.) + +.. _Hamcrest matchers: http://code.google.com/p/hamcrest/ +.. _JUnit: http://www.junit.org/ + +.. _man-testing-representations-deserialization: + +Testing Deserialization +----------------------- + +Next, write a test for deserializing a ``Person`` instance from JSON: + +.. code-block:: java + + import com.yammer.dropwizard.testing.JsonHelpers.*; + import org.hamcrest.Matchers.*; + + @Test + public void serializesToJSON() throws Exception { + final Person = new Person("Luther Blissett", "lb@example.com"); + assertThat("a Person can be serialized to JSON", + fromJSON(Person.class, jsonFixture("fixtures/person.json")), + is(person)); + } + + +This test uses `Hamcrest matchers`_ and JUnit_ to test that when a ``Person`` instance is +deserialized via Jackson from the specified JSON fixture it matches the given object. + +.. _man-testing-resources: + +Testing Resources +================= + +While many resource classes can be tested just by calling the methods on the class in a test, some +resources lend themselves to a more full-stack approach. For these, use ``ResourceTest``, which +loads a given resource instance in an in-memory Jersey server: + +.. _man-testing-resources-example: + +.. code-block:: java + + public class PersonResourceTest extends ResourceTest { + private final Person person = new Person("blah", "blah@example.com"); + private final PeopleStore store = mock(PeopleStore.class); + + @Override + protected void setUpResources() { + when(store.fetchPerson(anyString())).thenReturn(person); + addResource(new PersonResource(store)); + } + + @Test + public void simpleResourceTest() throws Exception { + assertThat("GET requests fetch the Person by ID", + client().resource("/person/blah").get(Person.class), + is(person)); + + verify(store).fetchPerson("blah"); + } + } + +In your ``#setUpResources()`` method, instantiate the various resource instances you want to test +and add them to the test context via ``#addResource(Object)``. In your actual test methods, use +``#client()`` which returns a Jersey ``Client`` instance which will talk to your resource instances. + +This doesn't require opening a port, but ``ResourceTest`` tests will perform all the serialization, +deserialization, and validation that happens inside of the HTTP process. + +This also doesn't require a full integration test. In the above +:ref:`example `, a mocked ``PersonDAO`` is passed to the +``PersonResource`` instance to isolate it from the database. Not only does this make the test much +faster, but it allows your resource unit tests to test error conditions and edge cases much more +easily. + +.. hint:: + + You can trust ``PersonDAO`` works because you've got working unit tests for it, right? + +Should you, at some point, grow tired of the near-infinite amount of debug logging produced by +``ResourceTest`` you can use the ``java.util.logging`` API to silence the ``com.sun.jersey`` logger. From bf4492772ae5925f2110902a6b7559cdd6dc1154 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 19:16:35 -0800 Subject: [PATCH 0262/2771] Finalize relnotes. --- docs/source/relnotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/relnotes.rst b/docs/source/relnotes.rst index 78fbad0016c..8c18203424d 100644 --- a/docs/source/relnotes.rst +++ b/docs/source/relnotes.rst @@ -6,7 +6,7 @@ Release Notes .. _rel-0.2.0: -v0.2.0: TBD +v0.2.0: Feb 15 2012 =================== * Switched to using ``jackson-datatype-guava`` for JSON serialization/deserialization of Guava From 7ba8672076bdaa2a40b9f5554f797894c4663a78 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 19:17:55 -0800 Subject: [PATCH 0263/2771] [maven-release-plugin] prepare release v0.2.0 --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 790aef1edf7..d9c07886a31 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 55b9ea2abc7..4b5225bd87b 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 6a7bc1a4c69..a49c11626ac 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 00fdd957f36..86742382bb0 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.2.0-SNAPSHOT + 0.2.0 Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 61493a1ebb1..5b739397c5b 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 3d62d1ef8e9..cff5d05a66c 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 7c75a6c846d..8c00d2511e2 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index fa0942fcd6f..5a7e9748fbf 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 pom Dropwizard Project http://dropwizard.codahale.com/ From e429a93d8662a166c3d3acc7871d86afcdd27902 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 19:17:59 -0800 Subject: [PATCH 0264/2771] [maven-release-plugin] prepare for next development iteration --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index d9c07886a31..7896a5ea1c0 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 4b5225bd87b..ce6fdb3fde8 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index a49c11626ac..7393b83c64b 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 86742382bb0..067b43246ef 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.2.0 + 0.2.1-SNAPSHOT Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 5b739397c5b..85d3527ea02 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index cff5d05a66c..8107282ce6d 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 8c00d2511e2..5d28a920b1b 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 5a7e9748fbf..f1d829618af 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From 8892e4c1e95391de80c4113cacd13ebce1bffb1f Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 19:24:40 -0800 Subject: [PATCH 0265/2771] [maven-release-plugin] rollback the release of v0.2.0 --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 7896a5ea1c0..790aef1edf7 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index ce6fdb3fde8..55b9ea2abc7 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 7393b83c64b..6a7bc1a4c69 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 067b43246ef..00fdd957f36 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 85d3527ea02..61493a1ebb1 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 8107282ce6d..3d62d1ef8e9 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 5d28a920b1b..7c75a6c846d 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index f1d829618af..fa0942fcd6f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From cc67da2c453b57166bb0add0a88c524921aab417 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 19:56:12 -0800 Subject: [PATCH 0266/2771] Don't include maven-project-info-reports-plugin. It crashes. --- pom.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index fa0942fcd6f..df305462bfa 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,9 @@ 4.0.0 + + 3.0.0 + com.yammer.dropwizard dropwizard-parent @@ -198,11 +201,6 @@ 3.0 - - org.apache.maven.plugins - maven-project-info-reports-plugin - 2.4 - org.apache.maven.plugins maven-javadoc-plugin From 8e93a4f2df338b709fd05f651efd60ac17bcd345 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 19:57:02 -0800 Subject: [PATCH 0267/2771] [maven-release-plugin] prepare release v0.2.0 --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 790aef1edf7..d9c07886a31 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 55b9ea2abc7..4b5225bd87b 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 6a7bc1a4c69..a49c11626ac 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 00fdd957f36..86742382bb0 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.2.0-SNAPSHOT + 0.2.0 Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 61493a1ebb1..5b739397c5b 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 3d62d1ef8e9..cff5d05a66c 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 7c75a6c846d..8c00d2511e2 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index df305462bfa..6c2ff7cfad2 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 pom Dropwizard Project http://dropwizard.codahale.com/ From 89029a5f4b3c914c26a6fac2994f6fc6b381b84c Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 19:58:37 -0800 Subject: [PATCH 0268/2771] Revert "[maven-release-plugin] prepare release v0.2.0" This reverts commit 8e93a4f2df338b709fd05f651efd60ac17bcd345. --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index d9c07886a31..790aef1edf7 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 4b5225bd87b..55b9ea2abc7 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index a49c11626ac..6a7bc1a4c69 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 86742382bb0..00fdd957f36 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.2.0 + 0.2.0-SNAPSHOT Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 5b739397c5b..61493a1ebb1 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index cff5d05a66c..3d62d1ef8e9 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 8c00d2511e2..7c75a6c846d 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 6c2ff7cfad2..df305462bfa 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.0-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From d7d1509dcc8c19615d0713c45cf7e8d73557b9f6 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 19:58:53 -0800 Subject: [PATCH 0269/2771] [maven-release-plugin] prepare for next development iteration --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 790aef1edf7..7896a5ea1c0 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 55b9ea2abc7..ce6fdb3fde8 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 6a7bc1a4c69..7393b83c64b 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 00fdd957f36..067b43246ef 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.2.0-SNAPSHOT + 0.2.1-SNAPSHOT Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 61493a1ebb1..85d3527ea02 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 3d62d1ef8e9..8107282ce6d 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 7c75a6c846d..5d28a920b1b 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index df305462bfa..2ce6cf13e21 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.1-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From ad4845985468d8c1389c686aa2ccc4c6df53ca89 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 20:00:58 -0800 Subject: [PATCH 0270/2771] Reset version to 0.2.0-SNAPSHOT. --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 7896a5ea1c0..790aef1edf7 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index ce6fdb3fde8..55b9ea2abc7 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 7393b83c64b..6a7bc1a4c69 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 85d3527ea02..61493a1ebb1 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 8107282ce6d..3d62d1ef8e9 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 5d28a920b1b..7c75a6c846d 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 2ce6cf13e21..df305462bfa 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From 0f7eb670683a755d4c7decff559f723e39d3d072 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 20:03:31 -0800 Subject: [PATCH 0271/2771] Fix dw-example version. --- dropwizard-example/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 067b43246ef..00fdd957f36 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.2.1-SNAPSHOT + 0.2.0-SNAPSHOT Dropwizard Example Application From 6b0ebd256d0d4d7aae3840a4c04211c573e36f39 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 20:04:19 -0800 Subject: [PATCH 0272/2771] [maven-release-plugin] prepare release v0.2.0 --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index 790aef1edf7..d9c07886a31 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 55b9ea2abc7..4b5225bd87b 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index 6a7bc1a4c69..a49c11626ac 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 00fdd957f36..86742382bb0 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.2.0-SNAPSHOT + 0.2.0 Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 61493a1ebb1..5b739397c5b 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index 3d62d1ef8e9..cff5d05a66c 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 7c75a6c846d..8c00d2511e2 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index df305462bfa..6c2ff7cfad2 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0-SNAPSHOT + 0.2.0 pom Dropwizard Project http://dropwizard.codahale.com/ From ce142ffea196bd827c30abeadfb6ef7505eb44e0 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 20:04:23 -0800 Subject: [PATCH 0273/2771] [maven-release-plugin] prepare for next development iteration --- dropwizard-client/pom.xml | 2 +- dropwizard-core/pom.xml | 2 +- dropwizard-db/pom.xml | 2 +- dropwizard-example/pom.xml | 2 +- dropwizard-scala_2.9.1/pom.xml | 2 +- dropwizard-templates/pom.xml | 2 +- dropwizard-testing/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwizard-client/pom.xml b/dropwizard-client/pom.xml index d9c07886a31..7896a5ea1c0 100644 --- a/dropwizard-client/pom.xml +++ b/dropwizard-client/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-core/pom.xml b/dropwizard-core/pom.xml index 4b5225bd87b..ce6fdb3fde8 100644 --- a/dropwizard-core/pom.xml +++ b/dropwizard-core/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-db/pom.xml b/dropwizard-db/pom.xml index a49c11626ac..7393b83c64b 100644 --- a/dropwizard-db/pom.xml +++ b/dropwizard-db/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-example/pom.xml b/dropwizard-example/pom.xml index 86742382bb0..067b43246ef 100644 --- a/dropwizard-example/pom.xml +++ b/dropwizard-example/pom.xml @@ -4,7 +4,7 @@ com.yammer.dropwizard dropwizard-example - 0.2.0 + 0.2.1-SNAPSHOT Dropwizard Example Application diff --git a/dropwizard-scala_2.9.1/pom.xml b/dropwizard-scala_2.9.1/pom.xml index 5b739397c5b..85d3527ea02 100644 --- a/dropwizard-scala_2.9.1/pom.xml +++ b/dropwizard-scala_2.9.1/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-templates/pom.xml b/dropwizard-templates/pom.xml index cff5d05a66c..8107282ce6d 100644 --- a/dropwizard-templates/pom.xml +++ b/dropwizard-templates/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/dropwizard-testing/pom.xml b/dropwizard-testing/pom.xml index 8c00d2511e2..5d28a920b1b 100644 --- a/dropwizard-testing/pom.xml +++ b/dropwizard-testing/pom.xml @@ -5,7 +5,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT com.yammer.dropwizard diff --git a/pom.xml b/pom.xml index 6c2ff7cfad2..2ce6cf13e21 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.yammer.dropwizard dropwizard-parent - 0.2.0 + 0.2.1-SNAPSHOT pom Dropwizard Project http://dropwizard.codahale.com/ From 3afa2c3a3db8ab9995c16de54743938698723d64 Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Wed, 15 Feb 2012 20:09:36 -0800 Subject: [PATCH 0274/2771] Push docs to root. --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index 3d5b957efc8..e614a87f279 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -156,4 +156,4 @@ less: lessc --compress source/_themes/yammerdoc/less/yammerdoc.less > source/_themes/yammerdoc/static/yammerdoc.css upload: clean dirhtml - rsync -avz --delete --exclude=maven $(BUILDDIR)/dirhtml/ codahale.com:/home/codahale/dropwizard.codahale.com/sphinx-ex/ + rsync -avz --delete --exclude=maven $(BUILDDIR)/dirhtml/ codahale.com:/home/codahale/dropwizard.codahale.com/ From 3f97584bf67c8ac49027569eb2ebfe1b45ac1aef Mon Sep 17 00:00:00 2001 From: Coda Hale Date: Thu, 16 Feb 2012 08:38:08 -0800 Subject: [PATCH 0275/2771] Add a Fork Me ribbon. --- docs/source/_themes/yammerdoc/layout.html | 4 ++++ docs/source/_themes/yammerdoc/theme.conf | 1 + docs/source/conf.py | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/source/_themes/yammerdoc/layout.html b/docs/source/_themes/yammerdoc/layout.html index 75c602e1c4f..0e99c136a2c 100644 --- a/docs/source/_themes/yammerdoc/layout.html +++ b/docs/source/_themes/yammerdoc/layout.html @@ -68,6 +68,10 @@ + + Fork me on GitHub