diff --git a/pom.xml b/pom.xml
index 8bea60031..aa5902685 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,22 +11,69 @@
TextSecureServer
0.13
+
+ 0.7.0
+ 2.3.3
+
+
+
+ io.dropwizard
+ dropwizard-core
+ ${dropwizard.version}
+
+
+ io.dropwizard
+ dropwizard-jdbi
+ ${dropwizard.version}
+
+
+ io.dropwizard
+ dropwizard-auth
+ ${dropwizard.version}
+
+
+ io.dropwizard
+ dropwizard-client
+ ${dropwizard.version}
+
+
+ io.dropwizard
+ dropwizard-migrations
+ ${dropwizard.version}
+
+
+ io.dropwizard
+ dropwizard-testing
+ ${dropwizard.version}
+
+
+ io.dropwizard
+ dropwizard-metrics-graphite
+ ${dropwizard.version}
+
+
+
+ com.sun.jersey
+ jersey-json
+ 1.18.1
+
+
+ com.codahale.metrics
+ metrics-graphite
+ 3.0.2
+
+
+ org.eclipse.jetty.websocket
+ websocket-server
+ 9.0.7.v20131107
+
+
bouncycastle
bcprov-jdk16
140
-
- com.yammer.dropwizard
- dropwizard-core
- 0.6.2
-
-
- com.yammer.metrics
- metrics-graphite
- 2.2.0
-
com.google.android.gcm
gcm-server
@@ -66,31 +113,6 @@
jar
compile
-
- com.yammer.dropwizard
- dropwizard-jdbi
- 0.6.2
-
-
- com.yammer.dropwizard
- dropwizard-auth
- 0.6.2
-
-
- com.yammer.dropwizard
- dropwizard-client
- 0.6.2
-
-
- com.yammer.dropwizard
- dropwizard-migrations
- 0.6.2
-
-
- com.yammer.dropwizard
- dropwizard-testing
- 0.6.2
-
com.twilio.sdk
twilio-java-sdk
@@ -103,25 +125,19 @@
9.1-901.jdbc4
-
- com.sun.jersey
- jersey-json
- 1.17.1
-
-
- org.eclipse.jetty
- jetty-websocket
- 8.1.14.v20131031
-
-
-
- org.coursera
- metrics-datadog
- 0.1.5
-
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.api.version}
+
+
+
+
diff --git a/src/main/java/org/whispersystems/textsecuregcm/WhisperServerConfiguration.java b/src/main/java/org/whispersystems/textsecuregcm/WhisperServerConfiguration.java
index 61c09af19..eb43240e8 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/WhisperServerConfiguration.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/WhisperServerConfiguration.java
@@ -17,8 +17,6 @@
package org.whispersystems.textsecuregcm;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.yammer.dropwizard.config.Configuration;
-import com.yammer.dropwizard.db.DatabaseConfiguration;
import org.whispersystems.textsecuregcm.configuration.ApnConfiguration;
import org.whispersystems.textsecuregcm.configuration.FederationConfiguration;
import org.whispersystems.textsecuregcm.configuration.GcmConfiguration;
@@ -35,6 +33,9 @@ import org.whispersystems.textsecuregcm.configuration.WebsocketConfiguration;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
+import io.dropwizard.Configuration;
+import io.dropwizard.db.DataSourceFactory;
+
public class WhisperServerConfiguration extends Configuration {
@NotNull
@@ -74,7 +75,7 @@ public class WhisperServerConfiguration extends Configuration {
@Valid
@NotNull
@JsonProperty
- private DatabaseConfiguration database = new DatabaseConfiguration();
+ private DataSourceFactory database = new DataSourceFactory();
@Valid
@NotNull
@@ -87,7 +88,7 @@ public class WhisperServerConfiguration extends Configuration {
@Valid
@JsonProperty
- private MetricsConfiguration metrics = new MetricsConfiguration();
+ private MetricsConfiguration viz = new MetricsConfiguration();
@Valid
@JsonProperty
@@ -125,7 +126,7 @@ public class WhisperServerConfiguration extends Configuration {
return redis;
}
- public DatabaseConfiguration getDatabaseConfiguration() {
+ public DataSourceFactory getDataSourceFactory() {
return database;
}
@@ -142,6 +143,6 @@ public class WhisperServerConfiguration extends Configuration {
}
public MetricsConfiguration getMetricsConfiguration() {
- return metrics;
+ return viz;
}
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
index 03485fcff..bea26462d 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
@@ -16,18 +16,12 @@
*/
package org.whispersystems.textsecuregcm;
+import com.codahale.metrics.SharedMetricRegistries;
+import com.codahale.metrics.graphite.GraphiteReporter;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.Service;
-import com.yammer.dropwizard.config.Bootstrap;
-import com.yammer.dropwizard.config.Environment;
-import com.yammer.dropwizard.config.HttpConfiguration;
-import com.yammer.dropwizard.db.DatabaseConfiguration;
-import com.yammer.dropwizard.jdbi.DBIFactory;
-import com.yammer.dropwizard.migrations.MigrationsBundle;
-import com.yammer.metrics.Metrics;
-import com.yammer.metrics.reporting.GraphiteReporter;
import net.spy.memcached.MemcachedClient;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.skife.jdbi.v2.DBI;
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
import org.whispersystems.textsecuregcm.auth.FederatedPeerAuthenticator;
@@ -71,16 +65,28 @@ import org.whispersystems.textsecuregcm.storage.PendingDevicesManager;
import org.whispersystems.textsecuregcm.storage.PubSubManager;
import org.whispersystems.textsecuregcm.storage.StoredMessageManager;
import org.whispersystems.textsecuregcm.storage.StoredMessages;
-import org.whispersystems.textsecuregcm.util.CORSHeaderFilter;
+import org.whispersystems.textsecuregcm.util.Constants;
import org.whispersystems.textsecuregcm.util.UrlSigner;
import org.whispersystems.textsecuregcm.workers.DirectoryCommand;
+import javax.servlet.DispatcherType;
+import javax.servlet.FilterRegistration;
+import javax.servlet.ServletRegistration;
import java.security.Security;
+import java.util.EnumSet;
import java.util.concurrent.TimeUnit;
+import static com.codahale.metrics.MetricRegistry.name;
+import io.dropwizard.Application;
+import io.dropwizard.db.DataSourceFactory;
+import io.dropwizard.jdbi.DBIFactory;
+import io.dropwizard.metrics.graphite.GraphiteReporterFactory;
+import io.dropwizard.migrations.MigrationsBundle;
+import io.dropwizard.setup.Bootstrap;
+import io.dropwizard.setup.Environment;
import redis.clients.jedis.JedisPool;
-public class WhisperServerService extends Service {
+public class WhisperServerService extends Application {
static {
Security.addProvider(new BouncyCastleProvider());
@@ -88,24 +94,28 @@ public class WhisperServerService extends Service {
@Override
public void initialize(Bootstrap bootstrap) {
- bootstrap.setName("whisper-server");
bootstrap.addCommand(new DirectoryCommand());
bootstrap.addBundle(new MigrationsBundle() {
@Override
- public DatabaseConfiguration getDatabaseConfiguration(WhisperServerConfiguration configuration) {
- return configuration.getDatabaseConfiguration();
+ public DataSourceFactory getDataSourceFactory(WhisperServerConfiguration configuration) {
+ return configuration.getDataSourceFactory();
}
});
}
+ @Override
+ public String getName() {
+ return "whisper-server";
+ }
+
@Override
public void run(WhisperServerConfiguration config, Environment environment)
throws Exception
{
- config.getHttpConfiguration().setConnectorType(HttpConfiguration.ConnectorType.NONBLOCKING);
-
+ SharedMetricRegistries.add(Constants.METRICS_NAME, environment.metrics());
+
DBIFactory dbiFactory = new DBIFactory();
- DBI jdbi = dbiFactory.build(environment, config.getDatabaseConfiguration(), "postgresql");
+ DBI jdbi = dbiFactory.build(environment, config.getDataSourceFactory(), "postgresql");
Accounts accounts = jdbi.onDemand(Accounts.class);
PendingAccounts pendingAccounts = jdbi.onDemand(PendingAccounts.class);
@@ -140,44 +150,59 @@ public class WhisperServerService extends Service {
KeysController keysController = new KeysController(rateLimiters, keys, accountsManager, federatedClientManager);
MessageController messageController = new MessageController(rateLimiters, pushSender, accountsManager, federatedClientManager);
- environment.addProvider(new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(config.getFederationConfiguration()),
- FederatedPeer.class,
- deviceAuthenticator,
- Device.class, "WhisperServer"));
+ environment.jersey().register(new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(config.getFederationConfiguration()),
+ FederatedPeer.class,
+ deviceAuthenticator,
+ Device.class, "WhisperServer"));
- environment.addResource(new AccountController(pendingAccountsManager, accountsManager, rateLimiters, smsSender));
- environment.addResource(new DeviceController(pendingDevicesManager, accountsManager, rateLimiters));
- environment.addResource(new DirectoryController(rateLimiters, directory));
- environment.addResource(new FederationController(accountsManager, attachmentController, keysController, messageController));
- environment.addResource(attachmentController);
- environment.addResource(keysController);
- environment.addResource(messageController);
+ environment.jersey().register(new AccountController(pendingAccountsManager, accountsManager, rateLimiters, smsSender));
+ environment.jersey().register(new DeviceController(pendingDevicesManager, accountsManager, rateLimiters));
+ environment.jersey().register(new DirectoryController(rateLimiters, directory));
+ environment.jersey().register(new FederationController(accountsManager, attachmentController, keysController, messageController));
+ environment.jersey().register(attachmentController);
+ environment.jersey().register(keysController);
+ environment.jersey().register(messageController);
if (config.getWebsocketConfiguration().isEnabled()) {
- environment.addServlet(new WebsocketControllerFactory(deviceAuthenticator, storedMessageManager, pubSubManager),
- "/v1/websocket/");
- environment.addFilter(new CORSHeaderFilter(), "/*");
+ WebsocketControllerFactory servlet = new WebsocketControllerFactory(deviceAuthenticator,
+ storedMessageManager,
+ pubSubManager);
+
+ ServletRegistration.Dynamic websocket = environment.servlets().addServlet("WebSocket", servlet);
+ websocket.addMapping("/v1/websocket/*");
+ websocket.setAsyncSupported(true);
+
+ FilterRegistration.Dynamic filter = environment.servlets().addFilter("CORS", CrossOriginFilter.class);
+ filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
+ filter.setInitParameter("allowedOrigins", "*");
+ filter.setInitParameter("allowedHeaders", "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin");
+ filter.setInitParameter("allowedMethods", "GET,PUT,POST,DELETE,OPTIONS");
+ filter.setInitParameter("preflightMaxAge", "5184000");
+ filter.setInitParameter("allowCredentials", "true");
}
- environment.addHealthCheck(new RedisHealthCheck(redisClient));
- environment.addHealthCheck(new MemcacheHealthCheck(memcachedClient));
+ environment.healthChecks().register("redis", new RedisHealthCheck(redisClient));
+ environment.healthChecks().register("memcache", new MemcacheHealthCheck(memcachedClient));
- environment.addProvider(new IOExceptionMapper());
- environment.addProvider(new RateLimitExceededExceptionMapper());
+ environment.jersey().register(new IOExceptionMapper());
+ environment.jersey().register(new RateLimitExceededExceptionMapper());
- Metrics.newGauge(CpuUsageGauge.class, "cpu", new CpuUsageGauge());
- Metrics.newGauge(FreeMemoryGauge.class, "free_memory", new FreeMemoryGauge());
- Metrics.newGauge(NetworkSentGauge.class, "bytes_sent", new NetworkSentGauge());
- Metrics.newGauge(NetworkReceivedGauge.class, "bytes_received", new NetworkReceivedGauge());
+ environment.metrics().register(name(CpuUsageGauge.class, "cpu"), new CpuUsageGauge());
+ environment.metrics().register(name(FreeMemoryGauge.class, "free_memory"), new FreeMemoryGauge());
+ environment.metrics().register(name(NetworkSentGauge.class, "bytes_sent"), new NetworkSentGauge());
+ environment.metrics().register(name(NetworkReceivedGauge.class, "bytes_received"), new NetworkReceivedGauge());
if (config.getGraphiteConfiguration().isEnabled()) {
- GraphiteReporter.enable(15, TimeUnit.SECONDS,
- config.getGraphiteConfiguration().getHost(),
- config.getGraphiteConfiguration().getPort());
+ GraphiteReporterFactory graphiteReporterFactory = new GraphiteReporterFactory();
+ graphiteReporterFactory.setHost(config.getGraphiteConfiguration().getHost());
+ graphiteReporterFactory.setPort(config.getGraphiteConfiguration().getPort());
+
+ GraphiteReporter graphiteReporter = (GraphiteReporter) graphiteReporterFactory.build(environment.metrics());
+ graphiteReporter.start(15, TimeUnit.SECONDS);
}
if (config.getMetricsConfiguration().isEnabled()) {
- new JsonMetricsReporter("textsecure", Metrics.defaultRegistry(),
+ new JsonMetricsReporter(environment.metrics(),
config.getMetricsConfiguration().getToken(),
config.getMetricsConfiguration().getHost())
.start(60, TimeUnit.SECONDS);
diff --git a/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticator.java b/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticator.java
index 0ece5a49b..0e9786701 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticator.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticator.java
@@ -16,29 +16,27 @@
*/
package org.whispersystems.textsecuregcm.auth;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.SharedMetricRegistries;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.AuthenticationException;
-import com.yammer.dropwizard.auth.Authenticator;
-import com.yammer.dropwizard.auth.basic.BasicCredentials;
-import com.yammer.metrics.Metrics;
-import com.yammer.metrics.core.Meter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.storage.Account;
-import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
+import org.whispersystems.textsecuregcm.storage.Device;
+import org.whispersystems.textsecuregcm.util.Constants;
-import java.util.concurrent.TimeUnit;
+import static com.codahale.metrics.MetricRegistry.name;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.basic.BasicCredentials;
public class AccountAuthenticator implements Authenticator {
- private final Meter authenticationFailedMeter = Metrics.newMeter(AccountAuthenticator.class,
- "authentication", "failed",
- TimeUnit.MINUTES);
-
- private final Meter authenticationSucceededMeter = Metrics.newMeter(AccountAuthenticator.class,
- "authentication", "succeeded",
- TimeUnit.MINUTES);
+ private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
+ private final Meter authenticationFailedMeter = metricRegistry.meter(name(getClass(), "authentication", "failed" ));
+ private final Meter authenticationSucceededMeter = metricRegistry.meter(name(getClass(), "authentication", "succeeded"));
private final Logger logger = LoggerFactory.getLogger(AccountAuthenticator.class);
diff --git a/src/main/java/org/whispersystems/textsecuregcm/auth/AuthorizationHeader.java b/src/main/java/org/whispersystems/textsecuregcm/auth/AuthorizationHeader.java
index 6e5d3a8d7..c2411ec00 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/auth/AuthorizationHeader.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/auth/AuthorizationHeader.java
@@ -25,13 +25,13 @@ import java.io.IOException;
public class AuthorizationHeader {
private final String number;
- private final long accountId;
+ private final long accountId;
private final String password;
private AuthorizationHeader(String number, long accountId, String password) {
- this.number = number;
+ this.number = number;
this.accountId = accountId;
- this.password = password;
+ this.password = password;
}
public static AuthorizationHeader fromUserAndPassword(String user, String password) throws InvalidAuthorizationHeaderException {
diff --git a/src/main/java/org/whispersystems/textsecuregcm/auth/FederatedPeerAuthenticator.java b/src/main/java/org/whispersystems/textsecuregcm/auth/FederatedPeerAuthenticator.java
index b4736c791..effa85b4c 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/auth/FederatedPeerAuthenticator.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/auth/FederatedPeerAuthenticator.java
@@ -16,30 +16,35 @@
*/
package org.whispersystems.textsecuregcm.auth;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.SharedMetricRegistries;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.AuthenticationException;
-import com.yammer.dropwizard.auth.Authenticator;
-import com.yammer.dropwizard.auth.basic.BasicCredentials;
-import com.yammer.metrics.Metrics;
-import com.yammer.metrics.core.Meter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.FederationConfiguration;
import org.whispersystems.textsecuregcm.federation.FederatedPeer;
+import org.whispersystems.textsecuregcm.util.Constants;
import java.util.List;
-import java.util.concurrent.TimeUnit;
+
+import static com.codahale.metrics.MetricRegistry.name;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.basic.BasicCredentials;
public class FederatedPeerAuthenticator implements Authenticator {
- private final Meter authenticationFailedMeter = Metrics.newMeter(FederatedPeerAuthenticator.class,
- "authentication", "failed",
- TimeUnit.MINUTES);
+ private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
- private final Meter authenticationSucceededMeter = Metrics.newMeter(FederatedPeerAuthenticator.class,
- "authentication", "succeeded",
- TimeUnit.MINUTES);
+ private final Meter authenticationFailedMeter = metricRegistry.meter(name(getClass(),
+ "authentication",
+ "failed"));
+
+ private final Meter authenticationSucceededMeter = metricRegistry.meter(name(getClass(),
+ "authentication",
+ "succeeded"));
private final Logger logger = LoggerFactory.getLogger(FederatedPeerAuthenticator.class);
diff --git a/src/main/java/org/whispersystems/textsecuregcm/auth/MultiBasicAuthProvider.java b/src/main/java/org/whispersystems/textsecuregcm/auth/MultiBasicAuthProvider.java
index 05034aa90..713968ba2 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/auth/MultiBasicAuthProvider.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/auth/MultiBasicAuthProvider.java
@@ -21,17 +21,14 @@ import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
-import com.yammer.dropwizard.auth.Auth;
-import com.yammer.dropwizard.auth.Authenticator;
-import com.yammer.dropwizard.auth.basic.BasicAuthProvider;
-import com.yammer.dropwizard.auth.basic.BasicCredentials;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import io.dropwizard.auth.Auth;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.basic.BasicAuthProvider;
+import io.dropwizard.auth.basic.BasicCredentials;
public class MultiBasicAuthProvider implements InjectableProvider {
- private final Logger logger = LoggerFactory.getLogger(MultiBasicAuthProvider.class);
-
private final BasicAuthProvider provider1;
private final BasicAuthProvider provider2;
@@ -44,8 +41,8 @@ public class MultiBasicAuthProvider implements InjectableProvider clazz2,
String realm)
{
- this.provider1 = new BasicAuthProvider(authenticator1, realm);
- this.provider2 = new BasicAuthProvider(authenticator2, realm);
+ this.provider1 = new BasicAuthProvider<>(authenticator1, realm);
+ this.provider2 = new BasicAuthProvider<>(authenticator2, realm);
this.clazz1 = clazz1;
this.clazz2 = clazz2;
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/configuration/DataDogConfiguration.java b/src/main/java/org/whispersystems/textsecuregcm/configuration/DataDogConfiguration.java
deleted file mode 100644
index 9fe5f9837..000000000
--- a/src/main/java/org/whispersystems/textsecuregcm/configuration/DataDogConfiguration.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.whispersystems.textsecuregcm.configuration;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-public class DataDogConfiguration {
-
- @JsonProperty
- private String apiKey;
-
- @JsonProperty
- private boolean enabled = false;
-
- public String getApiKey() {
- return apiKey;
- }
-
- public boolean isEnabled() {
- return enabled && apiKey != null;
- }
-}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java
index 9e7d6501e..1aab611fd 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java
@@ -16,10 +16,9 @@
*/
package org.whispersystems.textsecuregcm.controllers;
+import com.codahale.metrics.annotation.Timed;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.Auth;
-import com.yammer.metrics.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
@@ -55,6 +54,8 @@ import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import io.dropwizard.auth.Auth;
+
@Path("/v1/accounts")
public class AccountController {
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/AttachmentController.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/AttachmentController.java
index 5ca054464..628a050ef 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/AttachmentController.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/AttachmentController.java
@@ -17,9 +17,8 @@
package org.whispersystems.textsecuregcm.controllers;
import com.amazonaws.HttpMethod;
+import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.Auth;
-import com.yammer.metrics.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptor;
@@ -44,6 +43,8 @@ import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import io.dropwizard.auth.Auth;
+
@Path("/v1/attachments")
public class AttachmentController {
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java
index 9dddc82b4..4ccda6d4a 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java
@@ -16,10 +16,9 @@
*/
package org.whispersystems.textsecuregcm.controllers;
+import com.codahale.metrics.annotation.Timed;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.Auth;
-import com.yammer.metrics.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
@@ -29,8 +28,8 @@ import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.entities.DeviceResponse;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.storage.Account;
-import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
+import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.PendingDevicesManager;
import org.whispersystems.textsecuregcm.util.VerificationCode;
@@ -48,6 +47,8 @@ import javax.ws.rs.core.Response;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import io.dropwizard.auth.Auth;
+
@Path("/v1/devices")
public class DeviceController {
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/DirectoryController.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/DirectoryController.java
index e7ceaf99e..785803b81 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/DirectoryController.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/DirectoryController.java
@@ -16,11 +16,11 @@
*/
package org.whispersystems.textsecuregcm.controllers;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.SharedMetricRegistries;
+import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.Auth;
-import com.yammer.metrics.Metrics;
-import com.yammer.metrics.annotation.Timed;
-import com.yammer.metrics.core.Histogram;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.ClientContact;
@@ -30,6 +30,7 @@ import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.DirectoryManager;
import org.whispersystems.textsecuregcm.util.Base64;
+import org.whispersystems.textsecuregcm.util.Constants;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
@@ -45,11 +46,15 @@ import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
+import static com.codahale.metrics.MetricRegistry.name;
+import io.dropwizard.auth.Auth;
+
@Path("/v1/directory")
public class DirectoryController {
- private final Logger logger = LoggerFactory.getLogger(DirectoryController.class);
- private final Histogram contactsHistogram = Metrics.newHistogram(DirectoryController.class, "contacts");
+ private final Logger logger = LoggerFactory.getLogger(DirectoryController.class);
+ private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
+ private final Histogram contactsHistogram = metricRegistry.histogram(name(getClass(), "contacts"));
private final RateLimiters rateLimiters;
private final DirectoryManager directory;
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/FederationController.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/FederationController.java
index e9714720f..3f86bd5bc 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/FederationController.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/FederationController.java
@@ -16,9 +16,8 @@
*/
package org.whispersystems.textsecuregcm.controllers;
+import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.Auth;
-import com.yammer.metrics.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.AccountCount;
@@ -45,6 +44,8 @@ import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
+import io.dropwizard.auth.Auth;
+
@Path("/v1/federation")
public class FederationController {
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java
index a13f3cf81..2fd3a3b47 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java
@@ -16,9 +16,8 @@
*/
package org.whispersystems.textsecuregcm.controllers;
+import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.Auth;
-import com.yammer.metrics.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.PreKey;
@@ -47,6 +46,8 @@ import javax.ws.rs.core.Response;
import java.util.LinkedList;
import java.util.List;
+import io.dropwizard.auth.Auth;
+
@Path("/v1/keys")
public class KeysController {
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java
index 551437693..9bdd6aafa 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java
@@ -16,10 +16,9 @@
*/
package org.whispersystems.textsecuregcm.controllers;
+import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Optional;
import com.google.protobuf.ByteString;
-import com.yammer.dropwizard.auth.Auth;
-import com.yammer.metrics.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.IncomingMessage;
@@ -56,6 +55,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Set;
+import io.dropwizard.auth.Auth;
+
@Path("/v1/messages")
public class MessageController {
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/MismatchedDevicesException.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/MismatchedDevicesException.java
index 3748b638c..44b924746 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/MismatchedDevicesException.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/MismatchedDevicesException.java
@@ -1,7 +1,6 @@
package org.whispersystems.textsecuregcm.controllers;
import java.util.List;
-import java.util.Set;
public class MismatchedDevicesException extends Exception {
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/NoSuchUserException.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/NoSuchUserException.java
index 646ef5930..ac03eed75 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/NoSuchUserException.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/NoSuchUserException.java
@@ -16,8 +16,6 @@
*/
package org.whispersystems.textsecuregcm.controllers;
-import org.whispersystems.textsecuregcm.federation.NoSuchPeerException;
-
import java.util.LinkedList;
import java.util.List;
@@ -27,7 +25,7 @@ public class NoSuchUserException extends Exception {
public NoSuchUserException(String user) {
super(user);
- missing = new LinkedList();
+ missing = new LinkedList<>();
missing.add(user);
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/WebsocketController.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/WebsocketController.java
index ea6022f39..cbc403bc7 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/WebsocketController.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/WebsocketController.java
@@ -1,9 +1,14 @@
package org.whispersystems.textsecuregcm.controllers;
import com.fasterxml.jackson.databind.ObjectMapper;
-import org.eclipse.jetty.websocket.WebSocket;
+import com.google.common.base.Optional;
+import org.eclipse.jetty.websocket.api.CloseStatus;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.UpgradeRequest;
+import org.eclipse.jetty.websocket.api.WebSocketListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
import org.whispersystems.textsecuregcm.entities.AcknowledgeWebsocketMessage;
import org.whispersystems.textsecuregcm.entities.IncomingWebsocketMessage;
import org.whispersystems.textsecuregcm.storage.Account;
@@ -22,111 +27,94 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-public class WebsocketController implements WebSocket.OnTextMessage, PubSubListener {
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.auth.basic.BasicCredentials;
+
+public class WebsocketController implements WebSocketListener, PubSubListener {
private static final Logger logger = LoggerFactory.getLogger(WebsocketController.class);
private static final ObjectMapper mapper = new ObjectMapper();
private static final Map pendingMessages = new HashMap<>();
+ private final AccountAuthenticator accountAuthenticator;
private final StoredMessageManager storedMessageManager;
private final PubSubManager pubSubManager;
- private final Account account;
- private final Device device;
+ private Account account;
+ private Device device;
+ private Session session;
- private Connection connection;
- private long pendingMessageSequence;
+ private long pendingMessageSequence;
- public WebsocketController(StoredMessageManager storedMessageManager,
- PubSubManager pubSubManager,
- Account account)
+ public WebsocketController(AccountAuthenticator accountAuthenticator,
+ StoredMessageManager storedMessageManager,
+ PubSubManager pubSubManager)
{
+ this.accountAuthenticator = accountAuthenticator;
this.storedMessageManager = storedMessageManager;
this.pubSubManager = pubSubManager;
- this.account = account;
- this.device = account.getAuthenticatedDevice().get();
- }
-
-
- @Override
- public void onOpen(Connection connection) {
- this.connection = connection;
- pubSubManager.subscribe(new WebsocketAddress(this.account.getId(), this.device.getId()), this);
- handleQueryDatabase();
}
@Override
- public void onClose(int i, String s) {
- handleClose();
+ public void onWebSocketConnect(Session session) {
+ try {
+ UpgradeRequest request = session.getUpgradeRequest();
+ Map parameters = request.getParameterMap();
+ String[] usernames = parameters.get("login" );
+ String[] passwords = parameters.get("password");
+
+ if (usernames == null || usernames.length == 0 ||
+ passwords == null || passwords.length == 0)
+ {
+ session.close(new CloseStatus(401, "Unauthorized"));
+ return;
+ }
+
+ BasicCredentials credentials = new BasicCredentials(usernames[0], passwords[0]);
+ Optional account = accountAuthenticator.authenticate(credentials);
+
+ if (!account.isPresent()) {
+ session.close(new CloseStatus(401, "Unauthorized"));
+ return;
+ }
+
+ this.account = account.get();
+ this.device = account.get().getAuthenticatedDevice().get();
+ this.session = session;
+
+ this.session.setIdleTimeout(10 * 60 * 1000);
+ this.pubSubManager.subscribe(new WebsocketAddress(this.account.getId(),
+ this.device.getId()), this);
+
+ handleQueryDatabase();
+ } catch (AuthenticationException e) {
+ try { session.close(500, "Server Error");} catch (IOException e1) {}
+ } catch (IOException ioe) {
+ logger.info("Abrupt session close.");
+ }
}
@Override
- public void onMessage(String body) {
+ public void onWebSocketText(String body) {
try {
IncomingWebsocketMessage incomingMessage = mapper.readValue(body, IncomingWebsocketMessage.class);
switch (incomingMessage.getType()) {
- case IncomingWebsocketMessage.TYPE_ACKNOWLEDGE_MESSAGE: handleMessageAck(body); break;
- case IncomingWebsocketMessage.TYPE_PING_MESSAGE: handlePing(); break;
- default: handleClose(); break;
+ case IncomingWebsocketMessage.TYPE_ACKNOWLEDGE_MESSAGE:
+ handleMessageAck(body);
+ break;
+ default:
+ close(new CloseStatus(410, "Unknown Type"));
}
} catch (IOException e) {
logger.debug("Parse", e);
- handleClose();
+ close(new CloseStatus(410, "Badly Formatted"));
}
}
@Override
- public void onPubSubMessage(PubSubMessage outgoingMessage) {
- switch (outgoingMessage.getType()) {
- case PubSubMessage.TYPE_DELIVER: handleDeliverOutgoingMessage(outgoingMessage.getContents()); break;
- case PubSubMessage.TYPE_QUERY_DB: handleQueryDatabase(); break;
- default:
- logger.warn("Unknown pubsub message: " + outgoingMessage.getType());
- }
- }
-
- private void handleDeliverOutgoingMessage(String message) {
- try {
- long messageSequence;
-
- synchronized (pendingMessages) {
- messageSequence = pendingMessageSequence++;
- pendingMessages.put(messageSequence, message);
- }
-
- connection.sendMessage(mapper.writeValueAsString(new WebsocketMessage(messageSequence, message)));
- } catch (IOException e) {
- logger.debug("Response failed", e);
- handleClose();
- }
- }
-
- private void handleMessageAck(String message) {
- try {
- AcknowledgeWebsocketMessage ack = mapper.readValue(message, AcknowledgeWebsocketMessage.class);
-
- synchronized (pendingMessages) {
- pendingMessages.remove(ack.getId());
- }
- } catch (IOException e) {
- logger.warn("Mapping", e);
- }
- }
-
- private void handlePing() {
- try {
- IncomingWebsocketMessage pongMessage = new IncomingWebsocketMessage(IncomingWebsocketMessage.TYPE_PONG_MESSAGE);
- connection.sendMessage(mapper.writeValueAsString(pongMessage));
- } catch (IOException e) {
- logger.warn("Pong failed", e);
- handleClose();
- }
- }
-
- private void handleClose() {
+ public void onWebSocketClose(int i, String s) {
pubSubManager.unsubscribe(new WebsocketAddress(account.getId(), device.getId()), this);
- connection.close();
List remainingMessages = new LinkedList<>();
@@ -144,6 +132,50 @@ public class WebsocketController implements WebSocket.OnTextMessage, PubSubListe
storedMessageManager.storeMessages(account, device, remainingMessages);
}
+
+ @Override
+ public void onPubSubMessage(PubSubMessage outgoingMessage) {
+ switch (outgoingMessage.getType()) {
+ case PubSubMessage.TYPE_DELIVER:
+ handleDeliverOutgoingMessage(outgoingMessage.getContents());
+ break;
+ case PubSubMessage.TYPE_QUERY_DB:
+ handleQueryDatabase();
+ break;
+ default:
+ logger.warn("Unknown pubsub message: " + outgoingMessage.getType());
+ }
+ }
+
+ private void handleDeliverOutgoingMessage(String message) {
+ try {
+ long messageSequence;
+
+ synchronized (pendingMessages) {
+ messageSequence = pendingMessageSequence++;
+ pendingMessages.put(messageSequence, message);
+ }
+
+ WebsocketMessage websocketMessage = new WebsocketMessage(messageSequence, message);
+ session.getRemote().sendStringByFuture(mapper.writeValueAsString(websocketMessage));
+ } catch (IOException e) {
+ logger.debug("Response failed", e);
+ close(null);
+ }
+ }
+
+ private void handleMessageAck(String message) {
+ try {
+ AcknowledgeWebsocketMessage ack = mapper.readValue(message, AcknowledgeWebsocketMessage.class);
+
+ synchronized (pendingMessages) {
+ pendingMessages.remove(ack.getId());
+ }
+ } catch (IOException e) {
+ logger.warn("Mapping", e);
+ }
+ }
+
private void handleQueryDatabase() {
List messages = storedMessageManager.getOutgoingMessages(account, device);
@@ -152,4 +184,25 @@ public class WebsocketController implements WebSocket.OnTextMessage, PubSubListe
}
}
+ @Override
+ public void onWebSocketBinary(byte[] bytes, int i, int i2) {
+ logger.info("Received binary message!");
+ }
+
+ @Override
+ public void onWebSocketError(Throwable throwable) {
+ logger.info("onWebSocketError", throwable);
+ }
+
+
+ private void close(CloseStatus closeStatus) {
+ try {
+ if (this.session != null) {
+ if (closeStatus != null) this.session.close(closeStatus);
+ else this.session.close();
+ }
+ } catch (IOException e) {
+ logger.info("close()", e);
+ }
+ }
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/controllers/WebsocketControllerFactory.java b/src/main/java/org/whispersystems/textsecuregcm/controllers/WebsocketControllerFactory.java
index 825ebb2c9..c9e9201be 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/controllers/WebsocketControllerFactory.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/controllers/WebsocketControllerFactory.java
@@ -1,23 +1,18 @@
package org.whispersystems.textsecuregcm.controllers;
-import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.AuthenticationException;
-import com.yammer.dropwizard.auth.basic.BasicCredentials;
-import org.eclipse.jetty.websocket.WebSocket;
-import org.eclipse.jetty.websocket.WebSocketServlet;
+import org.eclipse.jetty.websocket.api.UpgradeRequest;
+import org.eclipse.jetty.websocket.api.UpgradeResponse;
+import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
+import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
+import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
-import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.PubSubManager;
import org.whispersystems.textsecuregcm.storage.StoredMessageManager;
-import javax.servlet.http.HttpServletRequest;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-public class WebsocketControllerFactory extends WebSocketServlet {
+public class WebsocketControllerFactory extends WebSocketServlet implements WebSocketCreator {
private final Logger logger = LoggerFactory.getLogger(WebsocketControllerFactory.class);
@@ -25,14 +20,6 @@ public class WebsocketControllerFactory extends WebSocketServlet {
private final PubSubManager pubSubManager;
private final AccountAuthenticator accountAuthenticator;
- private final LinkedHashMap> cache =
- new LinkedHashMap>() {
- @Override
- protected boolean removeEldestEntry(Map.Entry> eldest) {
- return size() > 10;
- }
- };
-
public WebsocketControllerFactory(AccountAuthenticator accountAuthenticator,
StoredMessageManager storedMessageManager,
PubSubManager pubSubManager)
@@ -43,56 +30,12 @@ public class WebsocketControllerFactory extends WebSocketServlet {
}
@Override
- public WebSocket doWebSocketConnect(HttpServletRequest request, String s) {
- try {
- String username = request.getParameter("user");
- String password = request.getParameter("password");
-
- if (username == null || password == null) {
- return null;
- }
-
- BasicCredentials credentials = new BasicCredentials(username, password);
-
- Optional account = cache.remove(credentials);
-
- if (account == null) {
- account = accountAuthenticator.authenticate(new BasicCredentials(username, password));
- }
-
- if (!account.isPresent()) {
- return null;
- }
-
- return new WebsocketController(storedMessageManager, pubSubManager, account.get());
- } catch (AuthenticationException e) {
- throw new AssertionError(e);
- }
+ public void configure(WebSocketServletFactory factory) {
+ factory.setCreator(this);
}
@Override
- public boolean checkOrigin(HttpServletRequest request, String origin) {
- try {
- String username = request.getParameter("user");
- String password = request.getParameter("password");
-
- if (username == null || password == null) {
- return false;
- }
-
- BasicCredentials credentials = new BasicCredentials(username, password);
- Optional account = accountAuthenticator.authenticate(credentials);
-
- if (!account.isPresent()) {
- return false;
- }
-
- cache.put(credentials, account);
-
- return true;
- } catch (AuthenticationException e) {
- logger.warn("Auth Failure", e);
- return false;
- }
+ public Object createWebSocket(UpgradeRequest upgradeRequest, UpgradeResponse upgradeResponse) {
+ return new WebsocketController(accountAuthenticator, storedMessageManager, pubSubManager);
}
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/limits/RateLimiter.java b/src/main/java/org/whispersystems/textsecuregcm/limits/RateLimiter.java
index 3309e5534..9d452b17d 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/limits/RateLimiter.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/limits/RateLimiter.java
@@ -16,13 +16,14 @@
*/
package org.whispersystems.textsecuregcm.limits;
-import com.yammer.metrics.Metrics;
-import com.yammer.metrics.core.Meter;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.SharedMetricRegistries;
import net.spy.memcached.MemcachedClient;
-
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
+import org.whispersystems.textsecuregcm.util.Constants;
-import java.util.concurrent.TimeUnit;
+import static com.codahale.metrics.MetricRegistry.name;
public class RateLimiter {
@@ -35,7 +36,9 @@ public class RateLimiter {
public RateLimiter(MemcachedClient memcachedClient, String name,
int bucketSize, double leakRatePerMinute)
{
- this.meter = Metrics.newMeter(RateLimiter.class, name, "exceeded", TimeUnit.MINUTES);
+ MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
+
+ this.meter = metricRegistry.meter(name(getClass(), name, "exceeded"));
this.memcachedClient = memcachedClient;
this.name = name;
this.bucketSize = bucketSize;
diff --git a/src/main/java/org/whispersystems/textsecuregcm/metrics/CpuUsageGauge.java b/src/main/java/org/whispersystems/textsecuregcm/metrics/CpuUsageGauge.java
index f5ca9a7a0..77a640163 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/metrics/CpuUsageGauge.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/metrics/CpuUsageGauge.java
@@ -1,13 +1,13 @@
package org.whispersystems.textsecuregcm.metrics;
+import com.codahale.metrics.Gauge;
import com.sun.management.OperatingSystemMXBean;
-import com.yammer.metrics.core.Gauge;
import java.lang.management.ManagementFactory;
-public class CpuUsageGauge extends Gauge {
+public class CpuUsageGauge implements Gauge {
@Override
- public Integer value() {
+ public Integer getValue() {
OperatingSystemMXBean mbean = (com.sun.management.OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean();
diff --git a/src/main/java/org/whispersystems/textsecuregcm/metrics/FreeMemoryGauge.java b/src/main/java/org/whispersystems/textsecuregcm/metrics/FreeMemoryGauge.java
index c2b959ff5..ef2232892 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/metrics/FreeMemoryGauge.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/metrics/FreeMemoryGauge.java
@@ -1,17 +1,14 @@
package org.whispersystems.textsecuregcm.metrics;
+import com.codahale.metrics.Gauge;
import com.sun.management.OperatingSystemMXBean;
-import com.yammer.metrics.core.Gauge;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.lang.management.ManagementFactory;
-public class FreeMemoryGauge extends Gauge {
+public class FreeMemoryGauge implements Gauge {
@Override
- public Long value() {
+ public Long getValue() {
OperatingSystemMXBean mbean = (com.sun.management.OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean();
diff --git a/src/main/java/org/whispersystems/textsecuregcm/metrics/JsonMetricsReporter.java b/src/main/java/org/whispersystems/textsecuregcm/metrics/JsonMetricsReporter.java
index 32189ed17..eb8e70d3f 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/metrics/JsonMetricsReporter.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/metrics/JsonMetricsReporter.java
@@ -1,23 +1,17 @@
package org.whispersystems.textsecuregcm.metrics;
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.ScheduledReporter;
+import com.codahale.metrics.Snapshot;
+import com.codahale.metrics.Timer;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.yammer.metrics.core.Clock;
-import com.yammer.metrics.core.Counter;
-import com.yammer.metrics.core.Gauge;
-import com.yammer.metrics.core.Histogram;
-import com.yammer.metrics.core.Metered;
-import com.yammer.metrics.core.Metric;
-import com.yammer.metrics.core.MetricName;
-import com.yammer.metrics.core.MetricProcessor;
-import com.yammer.metrics.core.MetricsRegistry;
-import com.yammer.metrics.core.Sampling;
-import com.yammer.metrics.core.Summarizable;
-import com.yammer.metrics.core.Timer;
-import com.yammer.metrics.core.VirtualMachineMetrics;
-import com.yammer.metrics.reporting.AbstractPollingReporter;
-import com.yammer.metrics.stats.Snapshot;
import java.io.IOException;
import java.io.OutputStream;
@@ -33,292 +27,133 @@ import java.util.regex.Pattern;
/**
* Adapted from MetricsServlet.
*/
-public class JsonMetricsReporter extends AbstractPollingReporter implements MetricProcessor {
- private final Clock clock = Clock.defaultClock();
- private final VirtualMachineMetrics vm = VirtualMachineMetrics.getInstance();
- private final String service;
- private final MetricsRegistry registry;
+public class JsonMetricsReporter extends ScheduledReporter {
private final JsonFactory factory = new JsonFactory();
private final String table;
private final String sunnylabsHost;
private final String host;
- private final boolean includeVMMetrics;
-
- public JsonMetricsReporter(String service, MetricsRegistry registry, String token, String sunnylabsHost) throws UnknownHostException {
- this(service, registry, token, sunnylabsHost, true);
- }
-
- public JsonMetricsReporter(String service, MetricsRegistry registry, String token, String sunnylabsHost, boolean includeVMMetrics) throws UnknownHostException {
- super(registry, "jsonmetrics-reporter");
- this.service = service;
- this.registry = registry;
- this.table = token;
+ public JsonMetricsReporter(MetricRegistry registry, String token, String sunnylabsHost)
+ throws UnknownHostException
+ {
+ super(registry, "jsonmetrics-reporter", MetricFilter.ALL, TimeUnit.SECONDS, TimeUnit.MILLISECONDS);
+ this.table = token;
this.sunnylabsHost = sunnylabsHost;
- this.host = InetAddress.getLocalHost().getHostName();
- this.includeVMMetrics = includeVMMetrics;
+ this.host = InetAddress.getLocalHost().getHostName();
}
@Override
- public void run() {
+ public void report(SortedMap stringGaugeSortedMap,
+ SortedMap stringCounterSortedMap,
+ SortedMap stringHistogramSortedMap,
+ SortedMap stringMeterSortedMap,
+ SortedMap stringTimerSortedMap)
+ {
try {
- URL http = new URL("https", sunnylabsHost, 443, "/report/metrics?t=" + table + "&h=" + host);
- System.out.println("Reporting started to: " + http);
- HttpURLConnection urlc = (HttpURLConnection) http.openConnection();
- urlc.setDoOutput(true);
- urlc.addRequestProperty("Content-Type", "application/json");
- OutputStream outputStream = urlc.getOutputStream();
- writeJson(outputStream);
+ URL url = new URL("https", sunnylabsHost, 443, "/report/metrics?t=" + table + "&h=" + host);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+
+ connection.setDoOutput(true);
+ connection.addRequestProperty("Content-Type", "application/json");
+
+ OutputStream outputStream = connection.getOutputStream();
+ JsonGenerator json = factory.createGenerator(outputStream, JsonEncoding.UTF8);
+
+ json.writeStartObject();
+
+ for (Map.Entry gauge : stringGaugeSortedMap.entrySet()) {
+ reportGauge(json, gauge.getKey(), gauge.getValue());
+ }
+
+ for (Map.Entry counter : stringCounterSortedMap.entrySet()) {
+ reportCounter(json, counter.getKey(), counter.getValue());
+ }
+
+ for (Map.Entry histogram : stringHistogramSortedMap.entrySet()) {
+ reportHistogram(json, histogram.getKey(), histogram.getValue());
+ }
+
+ for (Map.Entry meter : stringMeterSortedMap.entrySet()) {
+ reportMeter(json, meter.getKey(), meter.getValue());
+ }
+
+ for (Map.Entry timer : stringTimerSortedMap.entrySet()) {
+ reportTimer(json, timer.getKey(), timer.getValue());
+ }
+
+ json.writeEndObject();
+ json.close();
+
outputStream.close();
- System.out.println("Reporting complete: " + urlc.getResponseCode());
} catch (IOException e) {
e.printStackTrace();
}
}
- static final class Context {
- final boolean showFullSamples;
- final JsonGenerator json;
-
- Context(JsonGenerator json, boolean showFullSamples) {
- this.json = json;
- this.showFullSamples = showFullSamples;
- }
- }
-
- public void writeJson(OutputStream out) throws IOException {
- final JsonGenerator json = factory.createGenerator(out, JsonEncoding.UTF8);
- json.writeStartObject();
- if (includeVMMetrics) {
- writeVmMetrics(json);
- }
- writeRegularMetrics(json, false);
- json.writeEndObject();
- json.close();
- }
-
- private void writeVmMetrics(JsonGenerator json) throws IOException {
- json.writeFieldName(service);
- json.writeStartObject();
- json.writeFieldName("jvm");
- json.writeStartObject();
- {
- json.writeFieldName("vm");
- json.writeStartObject();
- {
- json.writeStringField("name", vm.name());
- json.writeStringField("version", vm.version());
- }
- json.writeEndObject();
-
- json.writeFieldName("memory");
- json.writeStartObject();
- {
- json.writeNumberField("totalInit", vm.totalInit());
- json.writeNumberField("totalUsed", vm.totalUsed());
- json.writeNumberField("totalMax", vm.totalMax());
- json.writeNumberField("totalCommitted", vm.totalCommitted());
-
- json.writeNumberField("heapInit", vm.heapInit());
- json.writeNumberField("heapUsed", vm.heapUsed());
- json.writeNumberField("heapMax", vm.heapMax());
- json.writeNumberField("heapCommitted", vm.heapCommitted());
-
- json.writeNumberField("heap_usage", vm.heapUsage());
- json.writeNumberField("non_heap_usage", vm.nonHeapUsage());
- json.writeFieldName("memory_pool_usages");
- json.writeStartObject();
- {
- for (Map.Entry pool : vm.memoryPoolUsage().entrySet()) {
- json.writeNumberField(pool.getKey(), pool.getValue());
- }
- }
- json.writeEndObject();
- }
- json.writeEndObject();
-
- final Map bufferPoolStats = vm.getBufferPoolStats();
- if (!bufferPoolStats.isEmpty()) {
- json.writeFieldName("buffers");
- json.writeStartObject();
- {
- json.writeFieldName("direct");
- json.writeStartObject();
- {
- json.writeNumberField("count", bufferPoolStats.get("direct").getCount());
- json.writeNumberField("memoryUsed", bufferPoolStats.get("direct").getMemoryUsed());
- json.writeNumberField("totalCapacity", bufferPoolStats.get("direct").getTotalCapacity());
- }
- json.writeEndObject();
-
- json.writeFieldName("mapped");
- json.writeStartObject();
- {
- json.writeNumberField("count", bufferPoolStats.get("mapped").getCount());
- json.writeNumberField("memoryUsed", bufferPoolStats.get("mapped").getMemoryUsed());
- json.writeNumberField("totalCapacity", bufferPoolStats.get("mapped").getTotalCapacity());
- }
- json.writeEndObject();
- }
- json.writeEndObject();
- }
-
-
- json.writeNumberField("daemon_thread_count", vm.daemonThreadCount());
- json.writeNumberField("thread_count", vm.threadCount());
- json.writeNumberField("current_time", clock.time());
- json.writeNumberField("uptime", vm.uptime());
- json.writeNumberField("fd_usage", vm.fileDescriptorUsage());
-
- json.writeFieldName("thread-states");
- json.writeStartObject();
- {
- for (Map.Entry entry : vm.threadStatePercentages()
- .entrySet()) {
- json.writeNumberField(entry.getKey().toString().toLowerCase(),
- entry.getValue());
- }
- }
- json.writeEndObject();
-
- json.writeFieldName("garbage-collectors");
- json.writeStartObject();
- {
- for (Map.Entry entry : vm.garbageCollectors()
- .entrySet()) {
- json.writeFieldName(entry.getKey());
- json.writeStartObject();
- {
- final VirtualMachineMetrics.GarbageCollectorStats gc = entry.getValue();
- json.writeNumberField("runs", gc.getRuns());
- json.writeNumberField("time", gc.getTime(TimeUnit.MILLISECONDS));
- }
- json.writeEndObject();
- }
- }
- json.writeEndObject();
- }
- json.writeEndObject();
- json.writeEndObject();
- }
-
- public void writeRegularMetrics(JsonGenerator json, boolean showFullSamples) throws IOException {
- for (Map.Entry> entry : registry.groupedMetrics().entrySet()) {
- for (Map.Entry subEntry : entry.getValue().entrySet()) {
- json.writeFieldName(sanitize(subEntry.getKey()));
- try {
- subEntry.getValue()
- .processWith(this,
- subEntry.getKey(),
- new Context(json, showFullSamples));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- @Override
- public void processHistogram(MetricName name, Histogram histogram, Context context) throws Exception {
- final JsonGenerator json = context.json;
- json.writeStartObject();
- {
- json.writeNumberField("count", histogram.count());
- writeSummarizable(histogram, json);
- writeSampling(histogram, json);
- if (context.showFullSamples) {
- json.writeObjectField("values", histogram.getSnapshot().getValues());
- }
- histogram.clear();
- }
- json.writeEndObject();
- }
-
- @Override
- public void processCounter(MetricName name, Counter counter, Context context) throws Exception {
- final JsonGenerator json = context.json;
- json.writeNumber(counter.count());
- }
-
- @Override
- public void processGauge(MetricName name, Gauge> gauge, Context context) throws Exception {
- final JsonGenerator json = context.json;
+ public void reportGauge(JsonGenerator json, String name, Gauge gauge) throws IOException {
+ json.writeFieldName(sanitize(name));
json.writeObject(evaluateGauge(gauge));
}
- @Override
- public void processMeter(MetricName name, Metered meter, Context context) throws Exception {
- final JsonGenerator json = context.json;
+ public void reportCounter(JsonGenerator json, String name, Counter counter) throws IOException {
+ json.writeFieldName(sanitize(name));
+ json.writeNumber(counter.getCount());
+ }
+
+ public void reportHistogram(JsonGenerator json, String name, Histogram histogram) throws IOException {
+ Snapshot snapshot = histogram.getSnapshot();
+ json.writeFieldName(sanitize(name));
json.writeStartObject();
- {
- writeMeteredFields(meter, json);
- }
+ json.writeNumberField("count", histogram.getCount());
+ writeSnapshot(json, snapshot);
json.writeEndObject();
}
- @Override
- public void processTimer(MetricName name, Timer timer, Context context) throws Exception {
- final JsonGenerator json = context.json;
+ public void reportMeter(JsonGenerator json, String name, Meter meter) throws IOException {
+ json.writeFieldName(sanitize(name));
json.writeStartObject();
- {
- json.writeFieldName("duration");
- json.writeStartObject();
- {
- json.writeStringField("unit", timer.durationUnit().toString().toLowerCase());
- writeSummarizable(timer, json);
- writeSampling(timer, json);
- if (context.showFullSamples) {
- json.writeObjectField("values", timer.getSnapshot().getValues());
- }
- }
- json.writeEndObject();
+ json.writeNumberField("count", meter.getCount());
+ json.writeNumberField("mean", meter.getMeanRate());
+ json.writeNumberField("m1", meter.getOneMinuteRate());
+ json.writeNumberField("m5", meter.getFiveMinuteRate());
+ json.writeNumberField("m15", meter.getFifteenMinuteRate());
+ json.writeEndObject();
+ }
- json.writeFieldName("rate");
- json.writeStartObject();
- {
- writeMeteredFields(timer, json);
- }
- json.writeEndObject();
- }
+ public void reportTimer(JsonGenerator json, String name, Timer timer) throws IOException {
+ json.writeFieldName(sanitize(name));
+ json.writeStartObject();
+ json.writeNumberField("count", timer.getCount());
+ writeSnapshot(json, timer.getSnapshot());
json.writeEndObject();
}
private static Object evaluateGauge(Gauge> gauge) {
try {
- return gauge.value();
+ return gauge.getValue();
} catch (RuntimeException e) {
return "error reading gauge: " + e.getMessage();
}
}
- private static void writeSummarizable(Summarizable metric, JsonGenerator json) throws IOException {
- json.writeNumberField("min", metric.min());
- json.writeNumberField("max", metric.max());
- json.writeNumberField("mean", metric.mean());
- }
-
- private static void writeSampling(Sampling metric, JsonGenerator json) throws IOException {
- final Snapshot snapshot = metric.getSnapshot();
+ private static void writeSnapshot(JsonGenerator json, Snapshot snapshot) throws IOException {
+ json.writeNumberField("max", snapshot.getMax());
+ json.writeNumberField("mean", snapshot.getMean());
+ json.writeNumberField("min", snapshot.getMin());
+ json.writeNumberField("stddev", snapshot.getStdDev());
json.writeNumberField("median", snapshot.getMedian());
json.writeNumberField("p75", snapshot.get75thPercentile());
json.writeNumberField("p95", snapshot.get95thPercentile());
+ json.writeNumberField("p98", snapshot.get98thPercentile());
json.writeNumberField("p99", snapshot.get99thPercentile());
json.writeNumberField("p999", snapshot.get999thPercentile());
}
- private static void writeMeteredFields(Metered metered, JsonGenerator json) throws IOException {
- json.writeNumberField("count", metered.count());
- json.writeNumberField("mean", metered.meanRate());
- json.writeNumberField("m1", metered.oneMinuteRate());
- json.writeNumberField("m5", metered.fiveMinuteRate());
- json.writeNumberField("m15", metered.fifteenMinuteRate());
- }
-
private static final Pattern SIMPLE_NAMES = Pattern.compile("[^a-zA-Z0-9_.\\-~]");
- private String sanitize(MetricName metricName) {
- return SIMPLE_NAMES.matcher(metricName.getGroup() + "." + metricName.getName()).replaceAll("_");
+ private String sanitize(String metricName) {
+ return SIMPLE_NAMES.matcher(metricName).replaceAll("_");
}
}
\ No newline at end of file
diff --git a/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkGauge.java b/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkGauge.java
index 08e03816f..245d33dde 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkGauge.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkGauge.java
@@ -1,16 +1,15 @@
package org.whispersystems.textsecuregcm.metrics;
-import com.yammer.metrics.core.Gauge;
+import com.codahale.metrics.Gauge;
import org.whispersystems.textsecuregcm.util.Pair;
import java.io.BufferedReader;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
-public abstract class NetworkGauge extends Gauge {
+public abstract class NetworkGauge implements Gauge {
protected Pair getSentReceived() throws IOException {
File proc = new File("/proc/net/dev");
diff --git a/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkReceivedGauge.java b/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkReceivedGauge.java
index 5d6437a19..647a69c99 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkReceivedGauge.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkReceivedGauge.java
@@ -14,7 +14,7 @@ public class NetworkReceivedGauge extends NetworkGauge {
private long lastReceived;
@Override
- public Long value() {
+ public Long getValue() {
try {
long timestamp = System.currentTimeMillis();
Pair sentAndReceived = getSentReceived();
diff --git a/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkSentGauge.java b/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkSentGauge.java
index e8b1b4ef1..0e922a7b7 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkSentGauge.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/metrics/NetworkSentGauge.java
@@ -14,7 +14,7 @@ public class NetworkSentGauge extends NetworkGauge {
private long lastSent;
@Override
- public Long value() {
+ public Long getValue() {
try {
long timestamp = System.currentTimeMillis();
Pair sentAndReceived = getSentReceived();
diff --git a/src/main/java/org/whispersystems/textsecuregcm/providers/MemcacheHealthCheck.java b/src/main/java/org/whispersystems/textsecuregcm/providers/MemcacheHealthCheck.java
index 41c407273..f6915a7e7 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/providers/MemcacheHealthCheck.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/providers/MemcacheHealthCheck.java
@@ -16,8 +16,7 @@
*/
package org.whispersystems.textsecuregcm.providers;
-import com.yammer.metrics.core.HealthCheck;
-import com.yammer.metrics.core.HealthCheck.Result;
+import com.codahale.metrics.health.HealthCheck;
import net.spy.memcached.MemcachedClient;
import java.security.SecureRandom;
@@ -27,7 +26,6 @@ public class MemcacheHealthCheck extends HealthCheck {
private final MemcachedClient client;
public MemcacheHealthCheck(MemcachedClient client) {
- super("memcached");
this.client = client;
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/providers/RedisHealthCheck.java b/src/main/java/org/whispersystems/textsecuregcm/providers/RedisHealthCheck.java
index c0a661eac..219eb86b6 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/providers/RedisHealthCheck.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/providers/RedisHealthCheck.java
@@ -16,7 +16,7 @@
*/
package org.whispersystems.textsecuregcm.providers;
-import com.yammer.metrics.core.HealthCheck;
+import com.codahale.metrics.health.HealthCheck;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@@ -26,7 +26,6 @@ public class RedisHealthCheck extends HealthCheck {
private final JedisPool clientPool;
public RedisHealthCheck(JedisPool clientPool) {
- super("redis");
this.clientPool = clientPool;
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java b/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java
index b5aa2edfc..ff5b05640 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java
@@ -16,17 +16,19 @@
*/
package org.whispersystems.textsecuregcm.push;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.SharedMetricRegistries;
import com.google.common.base.Optional;
import com.notnoop.apns.APNS;
import com.notnoop.apns.ApnsService;
import com.notnoop.exceptions.NetworkIOException;
-import com.yammer.metrics.Metrics;
-import com.yammer.metrics.core.Meter;
import org.bouncycastle.openssl.PEMReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.CryptoEncodingException;
import org.whispersystems.textsecuregcm.entities.EncryptedOutgoingMessage;
+import org.whispersystems.textsecuregcm.util.Constants;
import org.whispersystems.textsecuregcm.util.Util;
import java.io.ByteArrayInputStream;
@@ -40,13 +42,15 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
-import java.util.concurrent.TimeUnit;
+
+import static com.codahale.metrics.MetricRegistry.name;
public class APNSender {
- private final Meter success = Metrics.newMeter(APNSender.class, "sent", "success", TimeUnit.MINUTES);
- private final Meter failure = Metrics.newMeter(APNSender.class, "sent", "failure", TimeUnit.MINUTES);
- private final Logger logger = LoggerFactory.getLogger(APNSender.class);
+ private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
+ private final Meter success = metricRegistry.meter(name(getClass(), "sent", "success"));
+ private final Meter failure = metricRegistry.meter(name(getClass(), "sent", "failure"));
+ private final Logger logger = LoggerFactory.getLogger(APNSender.class);
private static final String MESSAGE_BODY = "m";
diff --git a/src/main/java/org/whispersystems/textsecuregcm/push/GCMSender.java b/src/main/java/org/whispersystems/textsecuregcm/push/GCMSender.java
index 449eb2276..7065a8fb6 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/push/GCMSender.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/push/GCMSender.java
@@ -16,22 +16,25 @@
*/
package org.whispersystems.textsecuregcm.push;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.SharedMetricRegistries;
import com.google.android.gcm.server.Constants;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;
-import com.yammer.metrics.Metrics;
-import com.yammer.metrics.core.Meter;
import org.whispersystems.textsecuregcm.entities.CryptoEncodingException;
import org.whispersystems.textsecuregcm.entities.EncryptedOutgoingMessage;
import java.io.IOException;
-import java.util.concurrent.TimeUnit;
+
+import static com.codahale.metrics.MetricRegistry.name;
public class GCMSender {
- private final Meter success = Metrics.newMeter(GCMSender.class, "sent", "success", TimeUnit.MINUTES);
- private final Meter failure = Metrics.newMeter(GCMSender.class, "sent", "failure", TimeUnit.MINUTES);
+ private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(org.whispersystems.textsecuregcm.util.Constants.METRICS_NAME);
+ private final Meter success = metricRegistry.meter(name(getClass(), "sent", "success"));
+ private final Meter failure = metricRegistry.meter(name(getClass(), "sent", "failure"));
private final Sender sender;
diff --git a/src/main/java/org/whispersystems/textsecuregcm/sms/NexmoSmsSender.java b/src/main/java/org/whispersystems/textsecuregcm/sms/NexmoSmsSender.java
index fab421abd..58e34a060 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/sms/NexmoSmsSender.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/sms/NexmoSmsSender.java
@@ -16,11 +16,13 @@
*/
package org.whispersystems.textsecuregcm.sms;
-import com.yammer.metrics.Metrics;
-import com.yammer.metrics.core.Meter;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.SharedMetricRegistries;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.NexmoConfiguration;
+import org.whispersystems.textsecuregcm.util.Constants;
import java.io.BufferedReader;
import java.io.IOException;
@@ -28,13 +30,15 @@ import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
-import java.util.concurrent.TimeUnit;
+
+import static com.codahale.metrics.MetricRegistry.name;
public class NexmoSmsSender {
- private final Meter smsMeter = Metrics.newMeter(NexmoSmsSender.class, "sms", "delivered", TimeUnit.MINUTES);
- private final Meter voxMeter = Metrics.newMeter(NexmoSmsSender.class, "vox", "delivered", TimeUnit.MINUTES);
- private final Logger logger = LoggerFactory.getLogger(NexmoSmsSender.class);
+ private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
+ private final Meter smsMeter = metricRegistry.meter(name(getClass(), "sms", "delivered"));
+ private final Meter voxMeter = metricRegistry.meter(name(getClass(), "vox", "delivered"));
+ private final Logger logger = LoggerFactory.getLogger(NexmoSmsSender.class);
private static final String NEXMO_SMS_URL =
"https://rest.nexmo.com/sms/json?api_key=%s&api_secret=%s&from=%s&to=%s&text=%s";
diff --git a/src/main/java/org/whispersystems/textsecuregcm/sms/TwilioSmsSender.java b/src/main/java/org/whispersystems/textsecuregcm/sms/TwilioSmsSender.java
index f538c89fc..07c281be9 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/sms/TwilioSmsSender.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/sms/TwilioSmsSender.java
@@ -16,22 +16,25 @@
*/
package org.whispersystems.textsecuregcm.sms;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.SharedMetricRegistries;
import com.twilio.sdk.TwilioRestClient;
import com.twilio.sdk.TwilioRestException;
import com.twilio.sdk.resource.factory.CallFactory;
import com.twilio.sdk.resource.factory.MessageFactory;
-import com.yammer.metrics.Metrics;
-import com.yammer.metrics.core.Meter;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.whispersystems.textsecuregcm.configuration.TwilioConfiguration;
+import org.whispersystems.textsecuregcm.util.Constants;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
+
+import static com.codahale.metrics.MetricRegistry.name;
public class TwilioSmsSender {
@@ -40,8 +43,9 @@ public class TwilioSmsSender {
" " + SmsSender.VOX_VERIFICATION_TEXT + "%s\n" +
"";
- private final Meter smsMeter = Metrics.newMeter(TwilioSmsSender.class, "sms", "delivered", TimeUnit.MINUTES);
- private final Meter voxMeter = Metrics.newMeter(TwilioSmsSender.class, "vox", "delivered", TimeUnit.MINUTES);
+ private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
+ private final Meter smsMeter = metricRegistry.meter(name(getClass(), "sms", "delivered"));
+ private final Meter voxMeter = metricRegistry.meter(name(getClass(), "vox", "delivered"));
private final String accountId;
private final String accountToken;
diff --git a/src/main/java/org/whispersystems/textsecuregcm/storage/PubSubManager.java b/src/main/java/org/whispersystems/textsecuregcm/storage/PubSubManager.java
index b9e10b7e8..471d892ce 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/storage/PubSubManager.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/storage/PubSubManager.java
@@ -134,6 +134,7 @@ public class PubSubManager {
public void onSubscribe(String channel, int count) {
try {
WebsocketAddress address = new WebsocketAddress(channel);
+
if (address.getAccountId() == 0 && address.getDeviceId() == 0) {
synchronized (PubSubManager.this) {
subscribed = true;
diff --git a/src/main/java/org/whispersystems/textsecuregcm/util/Constants.java b/src/main/java/org/whispersystems/textsecuregcm/util/Constants.java
new file mode 100644
index 000000000..86021e884
--- /dev/null
+++ b/src/main/java/org/whispersystems/textsecuregcm/util/Constants.java
@@ -0,0 +1,7 @@
+package org.whispersystems.textsecuregcm.util;
+
+public class Constants {
+
+ public static final String METRICS_NAME = "textsecure";
+
+}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/workers/DirectoryCommand.java b/src/main/java/org/whispersystems/textsecuregcm/workers/DirectoryCommand.java
index d06d76318..fcc8dd0fe 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/workers/DirectoryCommand.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/workers/DirectoryCommand.java
@@ -16,13 +16,6 @@
*/
package org.whispersystems.textsecuregcm.workers;
-import com.yammer.dropwizard.cli.ConfiguredCommand;
-import com.yammer.dropwizard.config.Bootstrap;
-import com.yammer.dropwizard.db.DatabaseConfiguration;
-import com.yammer.dropwizard.jdbi.ImmutableListContainerFactory;
-import com.yammer.dropwizard.jdbi.ImmutableSetContainerFactory;
-import com.yammer.dropwizard.jdbi.OptionalContainerFactory;
-import com.yammer.dropwizard.jdbi.args.OptionalArgumentFactory;
import net.sourceforge.argparse4j.inf.Namespace;
import net.spy.memcached.MemcachedClient;
import org.skife.jdbi.v2.DBI;
@@ -36,6 +29,13 @@ import org.whispersystems.textsecuregcm.storage.Accounts;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.DirectoryManager;
+import io.dropwizard.cli.ConfiguredCommand;
+import io.dropwizard.db.DataSourceFactory;
+import io.dropwizard.jdbi.ImmutableListContainerFactory;
+import io.dropwizard.jdbi.ImmutableSetContainerFactory;
+import io.dropwizard.jdbi.OptionalContainerFactory;
+import io.dropwizard.jdbi.args.OptionalArgumentFactory;
+import io.dropwizard.setup.Bootstrap;
import redis.clients.jedis.JedisPool;
public class DirectoryCommand extends ConfiguredCommand {
@@ -53,8 +53,8 @@ public class DirectoryCommand extends ConfiguredCommand>() {
@Override
public List answer(InvocationOnMock invocationOnMock) throws Throwable {
- List query = (List) invocationOnMock.getArguments()[0];
+ List query = (List) invocationOnMock.getArguments()[0];
List response = new LinkedList<>(query);
response.remove(0);
return response;
}
});
-
- addResource(new DirectoryController(rateLimiters, directoryManager));
}
@Test
@@ -58,14 +65,13 @@ public class DirectoryControllerTest extends ResourceTest {
expectedResponse.remove(0);
ClientResponse response =
- client().resource("/v1/directory/tokens/")
- .entity(new ClientContactTokens(tokens))
- .type(MediaType.APPLICATION_JSON_TYPE)
- .header("Authorization",
- AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER,
- AuthHelper.VALID_PASSWORD))
- .put(ClientResponse.class);
-
+ resources.client().resource("/v1/directory/tokens/")
+ .entity(new ClientContactTokens(tokens))
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .header("Authorization",
+ AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER,
+ AuthHelper.VALID_PASSWORD))
+ .put(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(200);
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/FederatedControllerTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/FederatedControllerTest.java
index c00d396a1..d04674a06 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/FederatedControllerTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/FederatedControllerTest.java
@@ -4,7 +4,8 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse;
-import com.yammer.dropwizard.testing.ResourceTest;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.whispersystems.textsecuregcm.controllers.FederationController;
import org.whispersystems.textsecuregcm.controllers.MessageController;
@@ -23,17 +24,16 @@ import javax.ws.rs.core.MediaType;
import java.util.LinkedList;
import java.util.List;
-import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture;
+import io.dropwizard.testing.junit.ResourceTestRule;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
+import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.jsonFixture;
-public class FederatedControllerTest extends ResourceTest {
+public class FederatedControllerTest {
private static final String SINGLE_DEVICE_RECIPIENT = "+14151111111";
private static final String MULTI_DEVICE_RECIPIENT = "+14152222222";
@@ -46,10 +46,20 @@ public class FederatedControllerTest extends ResourceTest {
private final ObjectMapper mapper = new ObjectMapper();
- @Override
- protected void setUpResources() throws Exception {
- addProvider(AuthHelper.getAuthenticator());
+ private final MessageController messageController = new MessageController(rateLimiters, pushSender, accountsManager, federatedClientManager);
+ @Rule
+ public final ResourceTestRule resources = ResourceTestRule.builder()
+ .addProvider(AuthHelper.getAuthenticator())
+ .addResource(new FederationController(accountsManager,
+ null, null,
+ messageController))
+ .build();
+
+
+
+ @Before
+ public void setup() throws Exception {
List singleDeviceList = new LinkedList() {{
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 111));
}};
@@ -66,15 +76,12 @@ public class FederatedControllerTest extends ResourceTest {
when(accountsManager.get(eq(MULTI_DEVICE_RECIPIENT))).thenReturn(Optional.of(multiDeviceAccount));
when(rateLimiters.getMessagesLimiter()).thenReturn(rateLimiter);
-
- MessageController messageController = new MessageController(rateLimiters, pushSender, accountsManager, federatedClientManager);
- addResource(new FederationController(accountsManager, null, null, messageController));
}
@Test
public void testSingleDeviceCurrent() throws Exception {
ClientResponse response =
- client().resource(String.format("/v1/federation/messages/+14152223333/1/%s", SINGLE_DEVICE_RECIPIENT))
+ resources.client().resource(String.format("/v1/federation/messages/+14152223333/1/%s", SINGLE_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader("cyanogen", "foofoo"))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/KeyControllerTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/KeyControllerTest.java
index c40d5def0..e6edabd97 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/KeyControllerTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/KeyControllerTest.java
@@ -2,7 +2,8 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse;
-import com.yammer.dropwizard.testing.ResourceTest;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
@@ -24,16 +25,17 @@ import javax.ws.rs.core.MediaType;
import java.util.LinkedList;
import java.util.List;
+import io.dropwizard.testing.junit.ResourceTestRule;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
-public class KeyControllerTest extends ResourceTest {
+public class KeyControllerTest {
- private final String EXISTS_NUMBER = "+14152222222";
- private final String NOT_EXISTS_NUMBER = "+14152222220";
+ private static final String EXISTS_NUMBER = "+14152222222";
+ private static String NOT_EXISTS_NUMBER = "+14152222220";
- private final int SAMPLE_REGISTRATION_ID = 999;
- private final int SAMPLE_REGISTRATION_ID2 = 1002;
+ private static int SAMPLE_REGISTRATION_ID = 999;
+ private static int SAMPLE_REGISTRATION_ID2 = 1002;
private final PreKey SAMPLE_KEY = new PreKey(1, EXISTS_NUMBER, Device.MASTER_ID, 1234, "test1", "test2", false);
private final PreKey SAMPLE_KEY2 = new PreKey(2, EXISTS_NUMBER, 2, 5667, "test3", "test4,", false );
@@ -42,14 +44,17 @@ public class KeyControllerTest extends ResourceTest {
private final AccountsManager accounts = mock(AccountsManager.class);
private final Account existsAccount = mock(Account.class );
+ private RateLimiters rateLimiters = mock(RateLimiters.class);
+ private RateLimiter rateLimiter = mock(RateLimiter.class );
- @Override
- protected void setUpResources() {
- addProvider(AuthHelper.getAuthenticator());
-
- RateLimiters rateLimiters = mock(RateLimiters.class);
- RateLimiter rateLimiter = mock(RateLimiter.class );
+ @Rule
+ public final ResourceTestRule resources = ResourceTestRule.builder()
+ .addProvider(AuthHelper.getAuthenticator())
+ .addResource(new KeysController(rateLimiters, keys, accounts, null))
+ .build();
+ @Before
+ public void setup() {
Device sampleDevice = mock(Device.class );
Device sampleDevice2 = mock(Device.class);
Device sampleDevice3 = mock(Device.class);
@@ -94,15 +99,12 @@ public class KeyControllerTest extends ResourceTest {
});
when(keys.getCount(eq(AuthHelper.VALID_NUMBER), eq(1L))).thenReturn(5);
-
when(AuthHelper.VALID_ACCOUNT.getIdentityKey()).thenReturn(null);
-
- addResource(new KeysController(rateLimiters, keys, accounts, null));
}
@Test
public void validKeyStatusTest() throws Exception {
- PreKeyStatus result = client().resource("/v1/keys")
+ PreKeyStatus result = resources.client().resource("/v1/keys")
.header("Authorization",
AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyStatus.class);
@@ -114,7 +116,7 @@ public class KeyControllerTest extends ResourceTest {
@Test
public void validLegacyRequestTest() throws Exception {
- PreKey result = client().resource(String.format("/v1/keys/%s", EXISTS_NUMBER))
+ PreKey result = resources.client().resource(String.format("/v1/keys/%s", EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKey.class);
@@ -131,7 +133,7 @@ public class KeyControllerTest extends ResourceTest {
@Test
public void validMultiRequestTest() throws Exception {
- UnstructuredPreKeyList results = client().resource(String.format("/v1/keys/%s/*", EXISTS_NUMBER))
+ UnstructuredPreKeyList results = resources.client().resource(String.format("/v1/keys/%s/*", EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(UnstructuredPreKeyList.class);
@@ -163,27 +165,27 @@ public class KeyControllerTest extends ResourceTest {
@Test
public void invalidRequestTest() throws Exception {
- ClientResponse response = client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
+ ClientResponse response = resources.client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(ClientResponse.class);
- assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(404);
+ assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404);
}
@Test
public void unauthorizedRequestTest() throws Exception {
ClientResponse response =
- client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
+ resources.client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD))
.get(ClientResponse.class);
- assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(401);
+ assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
response =
- client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
+ resources.client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.get(ClientResponse.class);
- assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(401);
+ assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
}
@Test
@@ -200,7 +202,7 @@ public class KeyControllerTest extends ResourceTest {
preKeyList.setLastResortKey(lastResortKey);
ClientResponse response =
- client().resource("/v1/keys")
+ resources.client().resource("/v1/keys")
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class, preKeyList);
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java
index e16cf632c..97f434a50 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java
@@ -3,10 +3,11 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse;
-import com.yammer.dropwizard.testing.ResourceTest;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.whispersystems.textsecuregcm.controllers.MessageController;
-import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.entities.IncomingMessageList;
import org.whispersystems.textsecuregcm.entities.MessageProtos;
import org.whispersystems.textsecuregcm.entities.MismatchedDevices;
@@ -24,35 +25,39 @@ import javax.ws.rs.core.MediaType;
import java.util.LinkedList;
import java.util.List;
-import static com.yammer.dropwizard.testing.JsonHelpers.asJson;
-import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
+import io.dropwizard.testing.junit.ResourceTestRule;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
+import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.asJson;
+import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.jsonFixture;
-public class MessageControllerTest extends ResourceTest {
+public class MessageControllerTest {
private static final String SINGLE_DEVICE_RECIPIENT = "+14151111111";
private static final String MULTI_DEVICE_RECIPIENT = "+14152222222";
- private PushSender pushSender = mock(PushSender.class );
- private FederatedClientManager federatedClientManager = mock(FederatedClientManager.class);
- private AccountsManager accountsManager = mock(AccountsManager.class );
- private RateLimiters rateLimiters = mock(RateLimiters.class );
- private RateLimiter rateLimiter = mock(RateLimiter.class );
+ private final PushSender pushSender = mock(PushSender.class );
+ private final FederatedClientManager federatedClientManager = mock(FederatedClientManager.class);
+ private final AccountsManager accountsManager = mock(AccountsManager.class );
+ private final RateLimiters rateLimiters = mock(RateLimiters.class );
+ private final RateLimiter rateLimiter = mock(RateLimiter.class );
- private final ObjectMapper mapper = new ObjectMapper();
+ private final ObjectMapper mapper = new ObjectMapper();
- @Override
- protected void setUpResources() throws Exception {
- addProvider(AuthHelper.getAuthenticator());
+ @Rule
+ public final ResourceTestRule resources = ResourceTestRule.builder()
+ .addProvider(AuthHelper.getAuthenticator())
+ .addResource(new MessageController(rateLimiters, pushSender, accountsManager,
+ federatedClientManager))
+ .build();
+
+ @Before
+ public void setup() throws Exception {
List singleDeviceList = new LinkedList() {{
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 111));
}};
@@ -69,15 +74,12 @@ public class MessageControllerTest extends ResourceTest {
when(accountsManager.get(eq(MULTI_DEVICE_RECIPIENT))).thenReturn(Optional.of(multiDeviceAccount));
when(rateLimiters.getMessagesLimiter()).thenReturn(rateLimiter);
-
- addResource(new MessageController(rateLimiters, pushSender, accountsManager,
- federatedClientManager));
}
@Test
- public void testSingleDeviceLegacy() throws Exception {
+ public synchronized void testSingleDeviceLegacy() throws Exception {
ClientResponse response =
- client().resource("/v1/messages/")
+ resources.client().resource("/v1/messages/")
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/legacy_message_single_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
@@ -85,13 +87,13 @@ public class MessageControllerTest extends ResourceTest {
assertThat("Good Response", response.getStatus(), is(equalTo(200)));
- verify(pushSender).sendMessage(any(Account.class), any(Device.class), any(MessageProtos.OutgoingMessageSignal.class));
+ verify(pushSender, times(1)).sendMessage(any(Account.class), any(Device.class), any(MessageProtos.OutgoingMessageSignal.class));
}
@Test
- public void testSingleDeviceCurrent() throws Exception {
+ public synchronized void testSingleDeviceCurrent() throws Exception {
ClientResponse response =
- client().resource(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT))
+ resources.client().resource(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
@@ -99,13 +101,13 @@ public class MessageControllerTest extends ResourceTest {
assertThat("Good Response", response.getStatus(), is(equalTo(204)));
- verify(pushSender).sendMessage(any(Account.class), any(Device.class), any(MessageProtos.OutgoingMessageSignal.class));
+ verify(pushSender, times(1)).sendMessage(any(Account.class), any(Device.class), any(MessageProtos.OutgoingMessageSignal.class));
}
@Test
- public void testMultiDeviceMissing() throws Exception {
+ public synchronized void testMultiDeviceMissing() throws Exception {
ClientResponse response =
- client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
+ resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
@@ -121,9 +123,9 @@ public class MessageControllerTest extends ResourceTest {
}
@Test
- public void testMultiDeviceExtra() throws Exception {
+ public synchronized void testMultiDeviceExtra() throws Exception {
ClientResponse response =
- client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
+ resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_extra_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
@@ -139,9 +141,9 @@ public class MessageControllerTest extends ResourceTest {
}
@Test
- public void testMultiDevice() throws Exception {
+ public synchronized void testMultiDevice() throws Exception {
ClientResponse response =
- client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
+ resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_multi_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
@@ -153,9 +155,9 @@ public class MessageControllerTest extends ResourceTest {
}
@Test
- public void testRegistrationIdMismatch() throws Exception {
+ public synchronized void testRegistrationIdMismatch() throws Exception {
ClientResponse response =
- client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
+ resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_registration_id.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/WebsocketControllerTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/WebsocketControllerTest.java
index 331a548bf..fe81dc6b8 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/WebsocketControllerTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/WebsocketControllerTest.java
@@ -2,8 +2,10 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
-import com.yammer.dropwizard.auth.basic.BasicCredentials;
-import org.eclipse.jetty.websocket.WebSocket;
+import org.eclipse.jetty.websocket.api.CloseStatus;
+import org.eclipse.jetty.websocket.api.RemoteEndpoint;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.junit.Test;
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
import org.whispersystems.textsecuregcm.controllers.WebsocketController;
@@ -15,12 +17,11 @@ import org.whispersystems.textsecuregcm.storage.PubSubManager;
import org.whispersystems.textsecuregcm.storage.StoredMessageManager;
import org.whispersystems.textsecuregcm.websocket.WebsocketAddress;
-import javax.servlet.http.HttpServletRequest;
-
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
-import static org.fest.assertions.api.Assertions.assertThat;
+import io.dropwizard.auth.basic.BasicCredentials;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
@@ -34,13 +35,13 @@ public class WebsocketControllerTest {
private static final String VALID_PASSWORD = "secure";
private static final String INVALID_PASSWORD = "insecure";
- private final StoredMessageManager storedMessageManager = mock(StoredMessageManager.class);
- private final AccountAuthenticator accountAuthenticator = mock(AccountAuthenticator.class);
- private final PubSubManager pubSubManager = mock(PubSubManager.class );
- private final Account account = mock(Account.class );
- private final Device device = mock(Device.class );
- private final HttpServletRequest request = mock(HttpServletRequest.class );
- private final WebSocket.Connection connection = mock(WebSocket.Connection.class);
+ private static final StoredMessageManager storedMessageManager = mock(StoredMessageManager.class);
+ private static final AccountAuthenticator accountAuthenticator = mock(AccountAuthenticator.class);
+ private static final PubSubManager pubSubManager = mock(PubSubManager.class );
+ private static final Account account = mock(Account.class );
+ private static final Device device = mock(Device.class );
+ private static final UpgradeRequest upgradeRequest = mock(UpgradeRequest.class );
+ private static final Session session = mock(Session.class );
@Test
public void testCredentials() throws Exception {
@@ -50,23 +51,35 @@ public class WebsocketControllerTest {
when(accountAuthenticator.authenticate(eq(new BasicCredentials(INVALID_USER, INVALID_PASSWORD))))
.thenReturn(Optional.absent());
- WebsocketControllerFactory factory = new WebsocketControllerFactory(accountAuthenticator,
- storedMessageManager,
- pubSubManager);
+ when(session.getUpgradeRequest()).thenReturn(upgradeRequest);
- when(request.getParameter(eq("user"))).thenReturn(VALID_USER);
- when(request.getParameter(eq("password"))).thenReturn(VALID_PASSWORD);
+ WebsocketController controller = new WebsocketController(accountAuthenticator, storedMessageManager, pubSubManager);
- assertThat(factory.checkOrigin(request, "foobar")).isEqualTo(true);
+ when(upgradeRequest.getParameterMap()).thenReturn(new HashMap() {{
+ put("login", new String[] {VALID_USER});
+ put("password", new String[] {VALID_PASSWORD});
+ }});
- when(request.getParameter(eq("user"))).thenReturn(INVALID_USER);
- when(request.getParameter(eq("password"))).thenReturn(INVALID_PASSWORD);
+ controller.onWebSocketConnect(session);
- assertThat(factory.checkOrigin(request, "foobar")).isEqualTo(false);
+ verify(session, never()).close();
+ verify(session, never()).close(any(CloseStatus.class));
+ verify(session, never()).close(anyInt(), anyString());
+
+ when(upgradeRequest.getParameterMap()).thenReturn(new HashMap() {{
+ put("login", new String[] {INVALID_USER});
+ put("password", new String[] {INVALID_PASSWORD});
+ }});
+
+ controller.onWebSocketConnect(session);
+
+ verify(session).close(any(CloseStatus.class));
}
@Test
public void testOpen() throws Exception {
+ RemoteEndpoint remote = mock(RemoteEndpoint.class);
+
List outgoingMessages = new LinkedList() {{
add("first");
add("second");
@@ -76,29 +89,29 @@ public class WebsocketControllerTest {
when(device.getId()).thenReturn(2L);
when(account.getId()).thenReturn(31337L);
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device));
+ when(session.getRemote()).thenReturn(remote);
+ when(session.getUpgradeRequest()).thenReturn(upgradeRequest);
- when(request.getParameter(eq("user"))).thenReturn(VALID_USER);
- when(request.getParameter(eq("password"))).thenReturn(VALID_PASSWORD);
+ when(upgradeRequest.getParameterMap()).thenReturn(new HashMap() {{
+ put("login", new String[] {VALID_USER});
+ put("password", new String[] {VALID_PASSWORD});
+ }});
when(accountAuthenticator.authenticate(eq(new BasicCredentials(VALID_USER, VALID_PASSWORD))))
.thenReturn(Optional.of(account));
when(storedMessageManager.getOutgoingMessages(eq(account), eq(device))).thenReturn(outgoingMessages);
- WebsocketControllerFactory factory = new WebsocketControllerFactory(accountAuthenticator,
- storedMessageManager,
- pubSubManager);
+ WebsocketControllerFactory factory = new WebsocketControllerFactory(accountAuthenticator, storedMessageManager, pubSubManager);
+ WebsocketController controller = (WebsocketController) factory.createWebSocket(null, null);
- assertThat(factory.checkOrigin(request, "foobar")).isEqualTo(true);
+ controller.onWebSocketConnect(session);
- WebsocketController socket = (WebsocketController)factory.doWebSocketConnect(request, "foo");
- socket.onOpen(connection);
+ verify(pubSubManager).subscribe(eq(new WebsocketAddress(31337L, 2L)), eq((controller)));
+ verify(remote, times(3)).sendStringByFuture(anyString());
- verify(pubSubManager).subscribe(eq(new WebsocketAddress(31337L, 2L)), eq((socket)));
- verify(connection, times(3)).sendMessage(anyString());
-
- socket.onMessage(mapper.writeValueAsString(new AcknowledgeWebsocketMessage(1)));
- socket.onClose(1000, "Closed");
+ controller.onWebSocketText(mapper.writeValueAsString(new AcknowledgeWebsocketMessage(1)));
+ controller.onWebSocketClose(1000, "Closed");
List pending = new LinkedList() {{
add("first");
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/entities/ClientContactTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/entities/ClientContactTest.java
index 67144edb5..d1bf807d4 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/entities/ClientContactTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/entities/ClientContactTest.java
@@ -1,13 +1,16 @@
package org.whispersystems.textsecuregcm.tests.entities;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.whispersystems.textsecuregcm.entities.ClientContact;
import org.whispersystems.textsecuregcm.util.Util;
-import static com.yammer.dropwizard.testing.JsonHelpers.*;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.asJson;
+import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.fromJson;
+import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.jsonFixture;
public class ClientContactTest {
@@ -41,4 +44,5 @@ public class ClientContactTest {
is(contact));
}
+
}
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/entities/PreKeyTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/entities/PreKeyTest.java
index 0c8a256ec..f4bd4bdd0 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/entities/PreKeyTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/entities/PreKeyTest.java
@@ -5,10 +5,10 @@ import org.whispersystems.textsecuregcm.entities.ClientContact;
import org.whispersystems.textsecuregcm.entities.PreKey;
import org.whispersystems.textsecuregcm.util.Util;
-import static com.yammer.dropwizard.testing.JsonHelpers.*;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.*;
public class PreKeyTest {
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/util/JsonHelpers.java b/src/test/java/org/whispersystems/textsecuregcm/tests/util/JsonHelpers.java
new file mode 100644
index 000000000..fd3bded24
--- /dev/null
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/util/JsonHelpers.java
@@ -0,0 +1,27 @@
+package org.whispersystems.textsecuregcm.tests.util;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.IOException;
+
+import static io.dropwizard.testing.FixtureHelpers.fixture;
+
+public class JsonHelpers {
+
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+
+ public static String asJson(Object object) throws JsonProcessingException {
+ return objectMapper.writeValueAsString(object);
+ }
+
+ public static T fromJson(String value, Class clazz) throws IOException {
+ return objectMapper.readValue(value, clazz);
+ }
+
+ public static String jsonFixture(String filename) throws IOException {
+ return objectMapper.writeValueAsString(objectMapper.readValue(fixture(filename), JsonNode.class));
+ }
+}
diff --git a/src/test/resources/fixtures/contact.relay.json b/src/test/resources/fixtures/contact.relay.json
index 5661661c3..de8c7991f 100644
--- a/src/test/resources/fixtures/contact.relay.json
+++ b/src/test/resources/fixtures/contact.relay.json
@@ -1,4 +1,4 @@
{
- "token" : "BQVVHxMt5zAFXA",
- "relay" : "whisper"
+ "relay" : "whisper",
+ "token" : "BQVVHxMt5zAFXA"
}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/contact.relay.sms.json b/src/test/resources/fixtures/contact.relay.sms.json
index 4ec2d626e..4afe626c4 100644
--- a/src/test/resources/fixtures/contact.relay.sms.json
+++ b/src/test/resources/fixtures/contact.relay.sms.json
@@ -1,5 +1,5 @@
{
- "token" : "BQVVHxMt5zAFXA",
"relay" : "whisper",
- "supportsSms" : true
+ "supportsSms" : true,
+ "token" : "BQVVHxMt5zAFXA"
}
\ No newline at end of file