public class TorrentConfiguration { @JsonProperty @NotNull private File watchDir; @JsonProperty private Duration updateDelay = Duration.minutes(15); @JsonProperty private Duration backfillDelay = Duration.days(7); @JsonProperty private Set<String> primaryQualities = EpisodeNameParser.EPISODE_QUALITIES; @JsonProperty private Duration primaryQualityTimeout = Duration.days(1); @JsonProperty private Set<String> secondaryQualities = Collections.emptySet(); @JsonProperty private Map<String, ParserConfiguration> feeders = Collections.emptyMap(); @JsonProperty private Map<String, ParserConfiguration> searchers = Collections.emptyMap(); public File getWatchDir() { return watchDir; } public Duration getUpdateDelay() { return updateDelay; } public Duration getBackfillDelay() { return backfillDelay; } public Set<String> getPrimaryQualities() { return primaryQualities; } public Duration getPrimaryQualityTimeout() { return primaryQualityTimeout; } public Set<String> getSecondaryQualities() { return secondaryQualities; } public Map<String, ParserConfiguration> getFeeders() { return feeders; } public Map<String, ParserConfiguration> getSearchers() { return searchers; } }
@Override public ThreadPoolExecutor getThreadPool( HystrixThreadPoolKey threadPoolKey, HystrixProperty<Integer> corePoolSize, HystrixProperty<Integer> maximumPoolSize, HystrixProperty<Integer> keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { final String nameFormat = Joiner.on('-').join(ImmutableList.of("hystrix"), threadPoolKey.name(), "%d"); final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(nameFormat).build(); final String key = threadPoolKey.name(); final ThreadPoolExecutor existing = executors.putIfAbsent( key, new ThreadPoolExecutor( corePoolSize.get(), maximumPoolSize.get(), keepAliveTime.get(), unit, workQueue, threadFactory)); final ThreadPoolExecutor threadPoolExecutor = executors.get(key); if (existing == null) { environment .lifecycle() .manage(new ExecutorServiceManager(threadPoolExecutor, Duration.seconds(5), nameFormat)); } return threadPoolExecutor; }
/** * A factory for configuring the metrics sub-system for the environment. * * <p>Configures an optional list of {@link com.codahale.metrics.ScheduledReporter reporters} with a * default {@link #frequency}. * * <p><b>Configuration Parameters:</b> * * <table> * <tr> * <td>Name</td> * <td>Default</td> * <td>Description</td> * </tr> * <tr> * <td>frequency</td> * <td>1 minute</td> * <td>The frequency to report metrics. Overridable per-reporter.</td> * </tr> * <tr> * <td>reporters</td> * <td>No reporters.</td> * <td>A list of {@link ReporterFactory reporters} to report metrics.</td> * </tr> * </table> */ public class MetricsFactory { private static final Logger LOGGER = LoggerFactory.getLogger(MetricsFactory.class); @Valid @NotNull private Duration frequency = Duration.minutes(1); @Valid @NotNull private ImmutableList<ReporterFactory> reporters = ImmutableList.of(); @JsonProperty public ImmutableList<ReporterFactory> getReporters() { return reporters; } @JsonProperty public void setReporters(ImmutableList<ReporterFactory> reporters) { this.reporters = reporters; } @JsonProperty public Duration getFrequency() { return frequency; } @JsonProperty public void setFrequency(Duration frequency) { this.frequency = frequency; } /** * Configures the given lifecycle with the {@link com.codahale.metrics.ScheduledReporter * reporters} configured for the given registry. * * <p>The reporters are tied in to the given lifecycle, such that their {@link #getFrequency() * frequency} for reporting metrics begins when the lifecycle {@link * io.dropwizard.lifecycle.Managed#start() starts}, and stops when the lifecycle {@link * io.dropwizard.lifecycle.Managed#stop() stops}. * * @param environment the lifecycle to manage the reporters. * @param registry the metric registry to report metrics from. */ public void configure(LifecycleEnvironment environment, MetricRegistry registry) { for (ReporterFactory reporter : reporters) { try { final ScheduledReporterManager manager = new ScheduledReporterManager( reporter.build(registry), reporter.getFrequency().orElseGet(this::getFrequency)); environment.manage(manager); } catch (Exception e) { LOGGER.warn("Failed to create reporter, metrics may not be properly reported.", e); } } } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("frequency", frequency) .add("reporters", reporters) .toString(); } }
@JsonIgnore public boolean setupStream(AmazonKinesis kinesis, String streamName) { boolean setup = false; Preconditions.checkState(!Strings.isNullOrEmpty(streamName), "streamName was not specified"); try { DescribeStreamResult result; if (getRetryPeriod() != null) { Integer retryAttempts = getMaxAttempts(); while (retryAttempts == null || retryAttempts > 0) { try { result = kinesis.describeStream(streamName); if ("active".equalsIgnoreCase(result.getStreamDescription().getStreamStatus())) { LOG.info("stream {} is active", streamName); setup = true; break; } } catch (NullPointerException | ResourceNotFoundException e) { createStream(kinesis, streamName); } Thread.sleep(retryPeriod.toMilliseconds()); if (retryAttempts != null) { retryAttempts--; } } } } catch (InterruptedException e) { LOG.error( "Needed to create stream {} but was interrupted, nothing is guaranteed now", streamName); } return setup; }
@Override public void start() { future = executor.scheduleWithFixedDelay( new Runnable() { @Override public void run() { final Timer.Context context = timer.time(); try { execute(); } finally { context.stop(); } } }, initialDelay.toSeconds(), frequency.toSeconds(), TimeUnit.SECONDS); }
@Before public void setup() throws Exception { JerseyClientConfiguration clientConfiguration = new JerseyClientConfiguration(); clientConfiguration.setConnectionTimeout(Duration.milliseconds(SLEEP_TIME_IN_MILLIS / 2)); clientConfiguration.setTimeout(Duration.milliseconds(DEFAULT_CONNECT_TIMEOUT_IN_MILLIS)); environment = new Environment( "test-dropwizard-apache-connector", Jackson.newObjectMapper(), Validators.newValidator(), new MetricRegistry(), getClass().getClassLoader()); client = (JerseyClient) new JerseyClientBuilder(environment).using(clientConfiguration).build("test"); for (LifeCycle lifeCycle : environment.lifecycle().getManagedObjects()) { lifeCycle.start(); } }
protected Server buildServer(LifecycleEnvironment lifecycle, ThreadPool threadPool) { final Server server = new Server(threadPool); server.addLifeCycleListener(buildSetUIDListener()); lifecycle.attach(server); final ErrorHandler errorHandler = new ErrorHandler(); errorHandler.setServer(server); errorHandler.setShowStacks(false); server.addBean(errorHandler); server.setStopAtShutdown(true); server.setStopTimeout(shutdownGracePeriod.toMilliseconds()); return server; }
@Test public void testMinimalConfiguration() throws Exception { DataSourceFactory ds = getDataSourceFactory("yaml/minimal_db_pool.yml"); assertThat(ds.getDriverClass()).isEqualTo("org.postgresql.Driver"); assertThat(ds.getUser()).isEqualTo("pg-user"); assertThat(ds.getUrl()).isEqualTo("jdbc:postgresql://db.example.com/db-prod"); assertThat(ds.getPassword()).isEqualTo("iAMs00perSecrEET"); assertThat(ds.getProperties()).isEmpty(); assertThat(ds.getMaxWaitForConnection()).isEqualTo(Duration.seconds(30)); assertThat(ds.getValidationQuery()).isEqualTo("/* Health Check */ SELECT 1"); assertThat(ds.getMinSize()).isEqualTo(10); assertThat(ds.getInitialSize()).isEqualTo(10); assertThat(ds.getMaxSize()).isEqualTo(100); assertThat(ds.getCheckConnectionWhileIdle()).isTrue(); assertThat(ds.getEvictionInterval()).isEqualTo(Duration.seconds(5)); assertThat(ds.getMinIdleTime()).isEqualTo(Duration.minutes(1)); assertThat(ds.getValidationInterval()).isEqualTo(Duration.seconds(30)); assertThat(ds.isAutoCommentsEnabled()).isTrue(); assertThat(ds.getReadOnlyByDefault()).isNull(); assertThat(ds.isRemoveAbandoned()).isFalse(); assertThat(ds.getRemoveAbandonedTimeout()).isEqualTo(Duration.seconds(60L)); assertThat(ds.getAbandonWhenPercentageFull()).isEqualTo(0); assertThat(ds.isAlternateUsernamesAllowed()).isFalse(); assertThat(ds.getCommitOnReturn()).isFalse(); assertThat(ds.getRollbackOnReturn()).isFalse(); assertThat(ds.getAutoCommitByDefault()).isNull(); assertThat(ds.getDefaultCatalog()).isNull(); assertThat(ds.getDefaultTransactionIsolation()) .isEqualTo(DataSourceFactory.TransactionIsolation.DEFAULT); assertThat(ds.getUseFairQueue()).isTrue(); assertThat(ds.getInitializationQuery()).isNull(); assertThat(ds.getLogAbandonedConnections()).isEqualTo(false); assertThat(ds.getLogValidationErrors()).isEqualTo(false); assertThat(ds.getMaxConnectionAge()).isEqualTo(Optional.empty()); assertThat(ds.getCheckConnectionOnBorrow()).isEqualTo(false); assertThat(ds.getCheckConnectionOnConnect()).isEqualTo(true); assertThat(ds.getCheckConnectionOnReturn()).isEqualTo(false); assertThat(ds.getValidationQueryTimeout()).isEqualTo(Optional.empty()); }
protected ThreadPool createThreadPool(MetricRegistry metricRegistry) { final BlockingQueue<Runnable> queue = new BlockingArrayQueue<>(minThreads, maxThreads, maxQueuedRequests); final InstrumentedQueuedThreadPool threadPool = new InstrumentedQueuedThreadPool( metricRegistry, maxThreads, minThreads, (int) idleThreadTimeout.toMilliseconds(), queue); threadPool.setName("dw"); return threadPool; }
/** * Return a new Curator connection to the ensemble. It is the caller's responsibility to start and * close the connection. */ public CuratorFramework newCurator() { // Make all of the curator threads daemon threads so they don't block the JVM from terminating. // Also label them // with the ensemble they're connecting to, in case someone is trying to sort through a thread // dump. ThreadFactory threadFactory = new ThreadFactoryBuilder() .setNameFormat("CuratorFramework[" + _connectString.or(DEFAULT_CONNECT_STRING) + "]-%d") .setDaemon(true) .build(); org.apache.curator.RetryPolicy retry = _setterRetryPolicy.or( (_configRetryPolicy != null) ? _configRetryPolicy : DEFAULT_RETRY_POLICY); return CuratorFrameworkFactory.builder() .ensembleProvider(new ResolvingEnsembleProvider(_connectString.or(DEFAULT_CONNECT_STRING))) .retryPolicy(retry) .sessionTimeoutMs(Ints.checkedCast(_sessionTimeout.toMilliseconds())) .connectionTimeoutMs(Ints.checkedCast(_connectionTimeout.toMilliseconds())) .namespace(_namespace.orNull()) .threadFactory(threadFactory) .build(); }
@Test public void testFullConfiguration() throws Exception { DataSourceFactory ds = getDataSourceFactory("yaml/full_db_pool.yml"); assertThat(ds.getDriverClass()).isEqualTo("org.postgresql.Driver"); assertThat(ds.getUser()).isEqualTo("pg-user"); assertThat(ds.getUrl()).isEqualTo("jdbc:postgresql://db.example.com/db-prod"); assertThat(ds.getPassword()).isEqualTo("iAMs00perSecrEET"); assertThat(ds.getProperties()).containsEntry("charSet", "UTF-8"); assertThat(ds.getMaxWaitForConnection()).isEqualTo(Duration.seconds(1)); assertThat(ds.getValidationQuery()).isEqualTo("/* MyService Health Check */ SELECT 1"); assertThat(ds.getMinSize()).isEqualTo(8); assertThat(ds.getInitialSize()).isEqualTo(15); assertThat(ds.getMaxSize()).isEqualTo(32); assertThat(ds.getCheckConnectionWhileIdle()).isFalse(); assertThat(ds.getEvictionInterval()).isEqualTo(Duration.seconds(10)); assertThat(ds.getMinIdleTime()).isEqualTo(Duration.minutes(1)); assertThat(ds.getValidationInterval()).isEqualTo(Duration.minutes(1)); assertThat(ds.isAutoCommentsEnabled()).isFalse(); assertThat(ds.getReadOnlyByDefault()).isFalse(); assertThat(ds.isRemoveAbandoned()).isTrue(); assertThat(ds.getRemoveAbandonedTimeout()).isEqualTo(Duration.seconds(15L)); assertThat(ds.getAbandonWhenPercentageFull()).isEqualTo(75); assertThat(ds.isAlternateUsernamesAllowed()).isTrue(); assertThat(ds.getCommitOnReturn()).isTrue(); assertThat(ds.getRollbackOnReturn()).isTrue(); assertThat(ds.getAutoCommitByDefault()).isFalse(); assertThat(ds.getDefaultCatalog()).isEqualTo("test_catalog"); assertThat(ds.getDefaultTransactionIsolation()) .isEqualTo(DataSourceFactory.TransactionIsolation.READ_COMMITTED); assertThat(ds.getUseFairQueue()).isFalse(); assertThat(ds.getInitializationQuery()) .isEqualTo("insert into connections_log(ts) values (now())"); assertThat(ds.getLogAbandonedConnections()).isEqualTo(true); assertThat(ds.getLogValidationErrors()).isEqualTo(true); assertThat(ds.getMaxConnectionAge()).isEqualTo(Optional.of(Duration.hours(1))); assertThat(ds.getCheckConnectionOnBorrow()).isEqualTo(true); assertThat(ds.getCheckConnectionOnConnect()).isEqualTo(false); assertThat(ds.getCheckConnectionOnReturn()).isEqualTo(true); assertThat(ds.getValidationQueryTimeout()).isEqualTo(Optional.of(Duration.seconds(3))); assertThat(ds.getValidatorClassName()) .isEqualTo(Optional.of("io.dropwizard.db.CustomConnectionValidator")); }
public class StreamCreateConfiguration { private static final Logger LOG = LoggerFactory.getLogger(StreamCreateConfiguration.class); @Min(1) private int shardCount = 1; @Valid @NotNull private Duration retryPeriod = Duration.seconds(5); @Min(1) private Integer maxAttempts; @JsonProperty public int getShardCount() { return shardCount; } @JsonProperty public void setShardCount(int shardCount) { this.shardCount = shardCount; } @JsonIgnore public StreamCreateConfiguration shardCount(int shardCount) { this.setShardCount(shardCount); return this; } @JsonProperty public Duration getRetryPeriod() { return retryPeriod; } @JsonProperty public void setRetryPeriod(Duration retryPeriod) { this.retryPeriod = retryPeriod; } @JsonProperty public StreamCreateConfiguration retryPeriod(Duration retryPeriod) { this.setRetryPeriod(retryPeriod); return this; } @JsonProperty public Integer getMaxAttempts() { return maxAttempts; } @JsonProperty public void setMaxAttempts(Integer maxAttempts) { this.maxAttempts = maxAttempts; } @JsonIgnore public StreamCreateConfiguration maxAttempts(Integer maxAttempts) { this.setMaxAttempts(maxAttempts); return this; } @JsonIgnore public boolean setupStream(AmazonKinesis kinesis, String streamName) { boolean setup = false; Preconditions.checkState(!Strings.isNullOrEmpty(streamName), "streamName was not specified"); try { DescribeStreamResult result; if (getRetryPeriod() != null) { Integer retryAttempts = getMaxAttempts(); while (retryAttempts == null || retryAttempts > 0) { try { result = kinesis.describeStream(streamName); if ("active".equalsIgnoreCase(result.getStreamDescription().getStreamStatus())) { LOG.info("stream {} is active", streamName); setup = true; break; } } catch (NullPointerException | ResourceNotFoundException e) { createStream(kinesis, streamName); } Thread.sleep(retryPeriod.toMilliseconds()); if (retryAttempts != null) { retryAttempts--; } } } } catch (InterruptedException e) { LOG.error( "Needed to create stream {} but was interrupted, nothing is guaranteed now", streamName); } return setup; } private void createStream(AmazonKinesis kinesis, String streamName) { LOG.info( String.format( "stream %s was not found, creating with %d shards", streamName, getShardCount())); try { final CreateStreamResult stream = kinesis.createStream(streamName, getShardCount()); } catch (ResourceInUseException ue) { LOG.info(String.format("failed to create stream %s because it already existed", streamName)); } catch (Exception e) { LOG.error(String.format("failed to create stream %s", e), e); } } }
public MockDistributedLockManager(Duration timeout) throws URISyntaxException, StorageException { super(mockLockManager(), timeout, Duration.milliseconds(10)); }
/** Jackson friendly object for holding configuration information about a ZooKeeper ensemble. */ public class ZooKeeperConfiguration { private static final String DEFAULT_CONNECT_STRING = "localhost:2181"; private static final RetryPolicy DEFAULT_RETRY_POLICY = new BoundedExponentialBackoffRetry(100, 1000, 5); @NotNull @JsonProperty("connectString") @UnwrapValidatedValue(false) private Optional<String> _connectString = Optional.absent(); @JsonProperty("namespace") private Optional<String> _namespace = Optional.absent(); @JsonProperty("retryPolicy") private RetryPolicy _configRetryPolicy = null; @JsonProperty("sessionTimeout") private Duration _sessionTimeout = Duration.seconds(60); @JsonProperty("connectionTimeout") private Duration _connectionTimeout = Duration.seconds(15); /** * Used to hold a retry policy provided by a setter. This needs to be separate from {@code * _retryPolicy} because we want callers to be able to specify any Curator {@link * org.apache.curator.RetryPolicy} implementation instead of the inner {@link RetryPolicy} and its * subclasses that are used entirely to hold Jackson annotations. */ private Optional<org.apache.curator.RetryPolicy> _setterRetryPolicy = Optional.absent(); /** * Return a new Curator connection to the ensemble. It is the caller's responsibility to start and * close the connection. */ public CuratorFramework newCurator() { // Make all of the curator threads daemon threads so they don't block the JVM from terminating. // Also label them // with the ensemble they're connecting to, in case someone is trying to sort through a thread // dump. ThreadFactory threadFactory = new ThreadFactoryBuilder() .setNameFormat("CuratorFramework[" + _connectString.or(DEFAULT_CONNECT_STRING) + "]-%d") .setDaemon(true) .build(); org.apache.curator.RetryPolicy retry = _setterRetryPolicy.or( (_configRetryPolicy != null) ? _configRetryPolicy : DEFAULT_RETRY_POLICY); return CuratorFrameworkFactory.builder() .ensembleProvider(new ResolvingEnsembleProvider(_connectString.or(DEFAULT_CONNECT_STRING))) .retryPolicy(retry) .sessionTimeoutMs(Ints.checkedCast(_sessionTimeout.toMilliseconds())) .connectionTimeoutMs(Ints.checkedCast(_connectionTimeout.toMilliseconds())) .namespace(_namespace.orNull()) .threadFactory(threadFactory) .build(); } /** * Return a managed Curator connection. This created connection will be wrapped in a {@link * ManagedCuratorFramework} and offered to the provided {@link Environment} parameter. * * @deprecated Use {@link #newManagedCurator(LifecycleEnvironment)} instead. */ @Deprecated public CuratorFramework newManagedCurator(Environment env) { return newManagedCurator(env.lifecycle()); } /** * Return a managed Curator connection. This created connection will be wrapped in a {@link * ManagedCuratorFramework} and offered to the provided {@link LifecycleEnvironment} parameter. */ public CuratorFramework newManagedCurator(LifecycleEnvironment env) { CuratorFramework curator = newCurator(); env.manage(new ManagedCuratorFramework(curator)); return curator; } @JsonIgnore public Optional<String> getConnectString() { return _connectString; } @JsonIgnore public Optional<String> getNamespace() { return _namespace; } @JsonIgnore public Optional<org.apache.curator.RetryPolicy> getRetryPolicy() { if (_setterRetryPolicy.isPresent()) { return _setterRetryPolicy; } return Optional.<org.apache.curator.RetryPolicy>fromNullable(_configRetryPolicy); } @JsonIgnore public void setConnectString(String connectString) { _connectString = Optional.of(connectString); } @JsonIgnore public void setNamespace(String namespace) { _namespace = Optional.of(namespace); } @JsonIgnore public void setRetryPolicy(org.apache.curator.RetryPolicy retryPolicy) { _setterRetryPolicy = Optional.of(retryPolicy); } @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @JsonSubTypes.Type( value = BoundedExponentialBackoffRetry.class, name = "boundedExponentialBackoff"), @JsonSubTypes.Type(value = ExponentialBackoffRetry.class, name = "exponentialBackoff"), @JsonSubTypes.Type(value = RetryNTimes.class, name = "nTimes"), @JsonSubTypes.Type(value = RetryUntilElapsed.class, name = "untilElapsed") }) static interface RetryPolicy extends org.apache.curator.RetryPolicy {} private static final class BoundedExponentialBackoffRetry extends org.apache.curator.retry.BoundedExponentialBackoffRetry implements RetryPolicy { @JsonCreator public BoundedExponentialBackoffRetry( @JsonProperty("baseSleepTimeMs") int baseSleepTimeMs, @JsonProperty("maxSleepTimeMs") int maxSleepTimeMs, @JsonProperty("maxRetries") int maxRetries) { super(baseSleepTimeMs, maxSleepTimeMs, maxRetries); } } private static final class ExponentialBackoffRetry extends org.apache.curator.retry.ExponentialBackoffRetry implements RetryPolicy { @JsonCreator public ExponentialBackoffRetry( @JsonProperty("baseSleepTimeMs") int baseSleepTimeMs, @JsonProperty("maxRetries") int maxRetries) { super(baseSleepTimeMs, maxRetries); } } private static final class RetryNTimes extends org.apache.curator.retry.RetryNTimes implements RetryPolicy { @JsonCreator public RetryNTimes( @JsonProperty("n") int n, @JsonProperty("sleepMsBetweenRetries") int sleepMsBetweenRetries) { super(n, sleepMsBetweenRetries); } } private static final class RetryUntilElapsed extends org.apache.curator.retry.RetryUntilElapsed implements RetryPolicy { public RetryUntilElapsed( @JsonProperty("maxElapsedTimeMs") int maxElapsedTimeMs, @JsonProperty("sleepMsBetweenRetries") int sleepMsBetweenRetries) { super(maxElapsedTimeMs, sleepMsBetweenRetries); } } }
/** * A base class for {@link ServerFactory} implementations. * * <p><b>Configuration Parameters:</b> * * <table> * <tr> * <td>Name</td> * <td>Default</td> * <td>Description</td> * </tr> * <tr> * <td>{@code requestLog}</td> * <td></td> * <td>The {@link RequestLogFactory request log} configuration.</td> * </tr> * <tr> * <td>{@code gzip}</td> * <td></td> * <td>The {@link GzipHandlerFactory GZIP} configuration.</td> * </tr> * <tr> * <td>{@code serverPush}</td> * <td></td> * <td>The {@link ServerPushFilterFactory} configuration.</td> * </tr> * <tr> * <td>{@code maxThreads}</td> * <td>1024</td> * <td>The maximum number of threads to use for requests.</td> * </tr> * <tr> * <td>{@code minThreads}</td> * <td>8</td> * <td>The minimum number of threads to use for requests.</td> * </tr> * <tr> * <td>{@code maxQueuedRequests}</td> * <td>1024</td> * <td>The maximum number of requests to queue before blocking the acceptors.</td> * </tr> * <tr> * <td>{@code idleThreadTimeout}</td> * <td>1 minute</td> * <td>The amount of time a worker thread can be idle before being stopped.</td> * </tr> * <tr> * <td>{@code nofileSoftLimit}</td> * <td>(none)</td> * <td> * The number of open file descriptors before a soft error is issued. <b>Requires Jetty's * {@code libsetuid.so} on {@code java.library.path}.</b> * </td> * </tr> * <tr> * <td>{@code nofileHardLimit}</td> * <td>(none)</td> * <td> * The number of open file descriptors before a hard error is issued. <b>Requires Jetty's * {@code libsetuid.so} on {@code java.library.path}.</b> * </td> * </tr> * <tr> * <td>{@code gid}</td> * <td>(none)</td> * <td> * The group ID to switch to once the connectors have started. <b>Requires Jetty's * {@code libsetuid.so} on {@code java.library.path}.</b> * </td> * </tr> * <tr> * <td>{@code uid}</td> * <td>(none)</td> * <td> * The user ID to switch to once the connectors have started. <b>Requires Jetty's * {@code libsetuid.so} on {@code java.library.path}.</b> * </td> * </tr> * <tr> * <td>{@code user}</td> * <td>(none)</td> * <td> * The username to switch to once the connectors have started. <b>Requires Jetty's * {@code libsetuid.so} on {@code java.library.path}.</b> * </td> * </tr> * <tr> * <td>{@code group}</td> * <td>(none)</td> * <td> * The group to switch to once the connectors have started. <b>Requires Jetty's * {@code libsetuid.so} on {@code java.library.path}.</b> * </td> * </tr> * <tr> * <td>{@code umask}</td> * <td>(none)</td> * <td> * The umask to switch to once the connectors have started. <b>Requires Jetty's * {@code libsetuid.so} on {@code java.library.path}.</b> * </td> * </tr> * <tr> * <td>{@code startsAsRoot}</td> * <td>(none)</td> * <td> * Whether or not the Dropwizard application is started as a root user. <b>Requires * Jetty's {@code libsetuid.so} on {@code java.library.path}.</b> * </td> * </tr> * <tr> * <td>{@code registerDefaultExceptionMappers}</td> * <td>true</td> * <td> * Whether or not the default Jersey ExceptionMappers should be registered. * Set this to false if you want to register your own. * </td> * </tr> * <tr> * <td>{@code shutdownGracePeriod}</td> * <td>30 seconds</td> * <td> * The maximum time to wait for Jetty, and all Managed instances, to cleanly shutdown * before forcibly terminating them. * </td> * </tr> * <tr> * <td>{@code allowedMethods}</td> * <td>GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH</td> * <td> * The set of allowed HTTP methods. Others will be rejected with a * 405 Method Not Allowed response. * </td> * </tr> * <tr> * <td>{@code rootPath}</td> * <td>/*</td> * <td> * The URL pattern relative to {@code applicationContextPath} from which the JAX-RS resources will be served. * </td> * </tr> * </table> * * @see DefaultServerFactory * @see SimpleServerFactory */ public abstract class AbstractServerFactory implements ServerFactory { private static final Logger LOGGER = LoggerFactory.getLogger(ServerFactory.class); private static final Pattern WINDOWS_NEWLINE = Pattern.compile("\\r\\n?"); @Valid @NotNull private RequestLogFactory requestLog = new LogbackAccessRequestLogFactory(); @Valid @NotNull private GzipHandlerFactory gzip = new GzipHandlerFactory(); @Valid @NotNull private ServerPushFilterFactory serverPush = new ServerPushFilterFactory(); @Min(2) private int maxThreads = 1024; @Min(1) private int minThreads = 8; private int maxQueuedRequests = 1024; @MinDuration(1) private Duration idleThreadTimeout = Duration.minutes(1); @Min(1) private Integer nofileSoftLimit; @Min(1) private Integer nofileHardLimit; private Integer gid; private Integer uid; private String user; private String group; private String umask; private Boolean startsAsRoot; private Boolean registerDefaultExceptionMappers = Boolean.TRUE; private Duration shutdownGracePeriod = Duration.seconds(30); @NotNull private Set<String> allowedMethods = AllowedMethodsFilter.DEFAULT_ALLOWED_METHODS; private Optional<String> jerseyRootPath = Optional.absent(); @JsonIgnore @ValidationMethod(message = "must have a smaller minThreads than maxThreads") public boolean isThreadPoolSizedCorrectly() { return minThreads <= maxThreads; } @JsonProperty("requestLog") public RequestLogFactory getRequestLogFactory() { return requestLog; } @JsonProperty("requestLog") public void setRequestLogFactory(RequestLogFactory requestLog) { this.requestLog = requestLog; } @JsonProperty("gzip") public GzipHandlerFactory getGzipFilterFactory() { return gzip; } @JsonProperty("gzip") public void setGzipFilterFactory(GzipHandlerFactory gzip) { this.gzip = gzip; } @JsonProperty("serverPush") public ServerPushFilterFactory getServerPush() { return serverPush; } @JsonProperty("serverPush") public void setServerPush(ServerPushFilterFactory serverPush) { this.serverPush = serverPush; } @JsonProperty public int getMaxThreads() { return maxThreads; } @JsonProperty public void setMaxThreads(int count) { this.maxThreads = count; } @JsonProperty public int getMinThreads() { return minThreads; } @JsonProperty public void setMinThreads(int count) { this.minThreads = count; } @JsonProperty public int getMaxQueuedRequests() { return maxQueuedRequests; } @JsonProperty public void setMaxQueuedRequests(int maxQueuedRequests) { this.maxQueuedRequests = maxQueuedRequests; } @JsonProperty public Duration getIdleThreadTimeout() { return idleThreadTimeout; } @JsonProperty public void setIdleThreadTimeout(Duration idleThreadTimeout) { this.idleThreadTimeout = idleThreadTimeout; } @JsonProperty public Integer getNofileSoftLimit() { return nofileSoftLimit; } @JsonProperty public void setNofileSoftLimit(Integer nofileSoftLimit) { this.nofileSoftLimit = nofileSoftLimit; } @JsonProperty public Integer getNofileHardLimit() { return nofileHardLimit; } @JsonProperty public void setNofileHardLimit(Integer nofileHardLimit) { this.nofileHardLimit = nofileHardLimit; } @JsonProperty public Integer getGid() { return gid; } @JsonProperty public void setGid(Integer gid) { this.gid = gid; } @JsonProperty public Integer getUid() { return uid; } @JsonProperty public void setUid(Integer uid) { this.uid = uid; } @JsonProperty public String getUser() { return user; } @JsonProperty public void setUser(String user) { this.user = user; } @JsonProperty public String getGroup() { return group; } @JsonProperty public void setGroup(String group) { this.group = group; } @JsonProperty public String getUmask() { return umask; } @JsonProperty public void setUmask(String umask) { this.umask = umask; } @JsonProperty public Boolean getStartsAsRoot() { return startsAsRoot; } @JsonProperty public void setStartsAsRoot(Boolean startsAsRoot) { this.startsAsRoot = startsAsRoot; } public Boolean getRegisterDefaultExceptionMappers() { return registerDefaultExceptionMappers; } public void setRegisterDefaultExceptionMappers(Boolean registerDefaultExceptionMappers) { this.registerDefaultExceptionMappers = registerDefaultExceptionMappers; } @JsonProperty public Duration getShutdownGracePeriod() { return shutdownGracePeriod; } @JsonProperty public void setShutdownGracePeriod(Duration shutdownGracePeriod) { this.shutdownGracePeriod = shutdownGracePeriod; } @JsonProperty public Set<String> getAllowedMethods() { return allowedMethods; } @JsonProperty public void setAllowedMethods(Set<String> allowedMethods) { this.allowedMethods = allowedMethods; } @JsonProperty("rootPath") public Optional<String> getJerseyRootPath() { return jerseyRootPath; } @JsonProperty("rootPath") public void setJerseyRootPath(String jerseyRootPath) { this.jerseyRootPath = Optional.fromNullable(jerseyRootPath); } protected Handler createAdminServlet( Server server, MutableServletContextHandler handler, MetricRegistry metrics, HealthCheckRegistry healthChecks) { configureSessionsAndSecurity(handler, server); handler.setServer(server); handler.getServletContext().setAttribute(MetricsServlet.METRICS_REGISTRY, metrics); handler .getServletContext() .setAttribute(HealthCheckServlet.HEALTH_CHECK_REGISTRY, healthChecks); handler.addServlet(new NonblockingServletHolder(new AdminServlet()), "/*"); handler .addFilter(AllowedMethodsFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)) .setInitParameter( AllowedMethodsFilter.ALLOWED_METHODS_PARAM, Joiner.on(',').join(allowedMethods)); return handler; } private void configureSessionsAndSecurity(MutableServletContextHandler handler, Server server) { handler.setServer(server); if (handler.isSecurityEnabled()) { handler.getSecurityHandler().setServer(server); } if (handler.isSessionsEnabled()) { handler.getSessionHandler().setServer(server); } } protected Handler createAppServlet( Server server, JerseyEnvironment jersey, ObjectMapper objectMapper, Validator validator, MutableServletContextHandler handler, @Nullable Servlet jerseyContainer, MetricRegistry metricRegistry) { configureSessionsAndSecurity(handler, server); handler .addFilter(AllowedMethodsFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)) .setInitParameter( AllowedMethodsFilter.ALLOWED_METHODS_PARAM, Joiner.on(',').join(allowedMethods)); handler.addFilter(ThreadNameFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); serverPush.addFilter(handler); if (jerseyContainer != null) { if (jerseyRootPath.isPresent()) { jersey.setUrlPattern(jerseyRootPath.get()); } jersey.register(new JacksonMessageBodyProvider(objectMapper)); jersey.register(new HibernateValidationFeature(validator)); if (registerDefaultExceptionMappers == null || registerDefaultExceptionMappers) { jersey.register(new LoggingExceptionMapper<Throwable>() {}); jersey.register(new JerseyViolationExceptionMapper()); jersey.register(new JsonProcessingExceptionMapper()); jersey.register(new EarlyEofExceptionMapper()); } handler.addServlet(new NonblockingServletHolder(jerseyContainer), jersey.getUrlPattern()); } final InstrumentedHandler instrumented = new InstrumentedHandler(metricRegistry); instrumented.setServer(server); instrumented.setHandler(handler); return instrumented; } protected ThreadPool createThreadPool(MetricRegistry metricRegistry) { final BlockingQueue<Runnable> queue = new BlockingArrayQueue<>(minThreads, maxThreads, maxQueuedRequests); final InstrumentedQueuedThreadPool threadPool = new InstrumentedQueuedThreadPool( metricRegistry, maxThreads, minThreads, (int) idleThreadTimeout.toMilliseconds(), queue); threadPool.setName("dw"); return threadPool; } protected Server buildServer(LifecycleEnvironment lifecycle, ThreadPool threadPool) { final Server server = new Server(threadPool); server.addLifeCycleListener(buildSetUIDListener()); lifecycle.attach(server); final ErrorHandler errorHandler = new ErrorHandler(); errorHandler.setServer(server); errorHandler.setShowStacks(false); server.addBean(errorHandler); server.setStopAtShutdown(true); server.setStopTimeout(shutdownGracePeriod.toMilliseconds()); return server; } protected SetUIDListener buildSetUIDListener() { final SetUIDListener listener = new SetUIDListener(); if (startsAsRoot != null) { listener.setStartServerAsPrivileged(startsAsRoot); } if (gid != null) { listener.setGid(gid); } if (uid != null) { listener.setUid(uid); } if (user != null) { listener.setUsername(user); } if (group != null) { listener.setGroupname(group); } if (nofileHardLimit != null || nofileSoftLimit != null) { final RLimit rlimit = new RLimit(); if (nofileHardLimit != null) { rlimit.setHard(nofileHardLimit); } if (nofileSoftLimit != null) { rlimit.setSoft(nofileSoftLimit); } listener.setRLimitNoFiles(rlimit); } if (umask != null) { listener.setUmaskOctal(umask); } return listener; } protected Handler addRequestLog(Server server, Handler handler, String name) { if (requestLog.isEnabled()) { final RequestLogHandler requestLogHandler = new RequestLogHandler(); requestLogHandler.setRequestLog(requestLog.build(name)); // server should own the request log's lifecycle since it's already started, // the handler might not become managed in case of an error which would leave // the request log stranded server.addBean(requestLogHandler.getRequestLog(), true); requestLogHandler.setHandler(handler); return requestLogHandler; } return handler; } protected Handler addStatsHandler(Handler handler) { // Graceful shutdown is implemented via the statistics handler, // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=420142 final StatisticsHandler statisticsHandler = new StatisticsHandler(); statisticsHandler.setHandler(handler); return statisticsHandler; } protected Handler buildGzipHandler(Handler handler) { return gzip.isEnabled() ? gzip.build(handler) : handler; } protected void printBanner(String name) { try { final String banner = WINDOWS_NEWLINE .matcher( Resources.toString(Resources.getResource("banner.txt"), StandardCharsets.UTF_8)) .replaceAll("\n") .replace("\n", String.format("%n")); LOGGER.info(String.format("Starting {}%n{}"), name, banner); } catch (IllegalArgumentException | IOException ignored) { // don't display the banner if there isn't one LOGGER.info("Starting {}", name); } } }