Get rid of GSON dependency.

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2015-01-03 18:28:51 -08:00
parent 4711fa2a9a
commit fa4e492d1c
5 changed files with 74 additions and 87 deletions

View File

@ -91,11 +91,6 @@
<artifactId>gcm-server</artifactId> <artifactId>gcm-server</artifactId>
<version>1.0.2</version> <version>1.0.2</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.2</version>
</dependency>
<dependency> <dependency>
<groupId>net.spy</groupId> <groupId>net.spy</groupId>
<artifactId>spymemcached</artifactId> <artifactId>spymemcached</artifactId>

View File

@ -18,12 +18,8 @@ package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.whispersystems.textsecuregcm.federation.FederatedPeer; import org.whispersystems.textsecuregcm.federation.FederatedPeer;
import java.util.LinkedList;
import java.util.List; import java.util.List;
public class FederationConfiguration { public class FederationConfiguration {
@ -34,31 +30,7 @@ public class FederationConfiguration {
@JsonProperty @JsonProperty
private String name; private String name;
@JsonProperty
private String herokuPeers;
public List<FederatedPeer> getPeers() { public List<FederatedPeer> getPeers() {
if (peers != null) {
return peers;
}
if (herokuPeers != null) {
List<FederatedPeer> peers = new LinkedList<>();
JsonElement root = new JsonParser().parse(herokuPeers);
JsonArray peerElements = root.getAsJsonArray();
for (JsonElement peer : peerElements) {
String name = peer.getAsJsonObject().get("name").getAsString();
String url = peer.getAsJsonObject().get("url").getAsString();
String authenticationToken = peer.getAsJsonObject().get("authenticationToken").getAsString();
String certificate = peer.getAsJsonObject().get("certificate").getAsString();
peers.add(new FederatedPeer(name, url, authenticationToken, certificate));
}
return peers;
}
return peers; return peers;
} }

View File

@ -18,15 +18,10 @@ package org.whispersystems.textsecuregcm.entities;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.gson.Gson;
import org.whispersystems.textsecuregcm.util.Base64;
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter; import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.Arrays; import java.util.Arrays;
@JsonInclude(JsonInclude.Include.NON_DEFAULT) @JsonInclude(JsonInclude.Include.NON_DEFAULT)
@ -73,9 +68,9 @@ public class ClientContact {
this.inactive = inactive; this.inactive = inactive;
} }
public String toString() { // public String toString() {
return new Gson().toJson(this); // return new Gson().toJson(this);
} // }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {

View File

@ -16,14 +16,19 @@
*/ */
package org.whispersystems.textsecuregcm.storage; package org.whispersystems.textsecuregcm.storage;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.gson.Gson; import org.slf4j.Logger;
import com.google.gson.annotations.SerializedName; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.ClientContact; import org.whispersystems.textsecuregcm.entities.ClientContact;
import org.whispersystems.textsecuregcm.util.IterablePair; import org.whispersystems.textsecuregcm.util.IterablePair;
import org.whispersystems.textsecuregcm.util.Pair; import org.whispersystems.textsecuregcm.util.Pair;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
import java.io.IOException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -34,12 +39,17 @@ import redis.clients.jedis.Response;
public class DirectoryManager { public class DirectoryManager {
private final Logger logger = LoggerFactory.getLogger(DirectoryManager.class);
private static final byte[] DIRECTORY_KEY = {'d', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y'}; private static final byte[] DIRECTORY_KEY = {'d', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y'};
private final ObjectMapper objectMapper;
private final JedisPool redisPool; private final JedisPool redisPool;
public DirectoryManager(JedisPool redisPool) { public DirectoryManager(JedisPool redisPool) {
this.redisPool = redisPool; this.redisPool = redisPool;
this.objectMapper = new ObjectMapper();
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
} }
public void remove(String number) { public void remove(String number) {
@ -63,45 +73,48 @@ public class DirectoryManager {
public void add(ClientContact contact) { public void add(ClientContact contact) {
TokenValue tokenValue = new TokenValue(contact.getRelay(), contact.isSupportsSms()); TokenValue tokenValue = new TokenValue(contact.getRelay(), contact.isSupportsSms());
Jedis jedis = redisPool.getResource();
jedis.hset(DIRECTORY_KEY, contact.getToken(), new Gson().toJson(tokenValue).getBytes()); try (Jedis jedis = redisPool.getResource()) {
redisPool.returnResource(jedis); jedis.hset(DIRECTORY_KEY, contact.getToken(), objectMapper.writeValueAsBytes(tokenValue));
} catch (JsonProcessingException e) {
logger.warn("JSON Serialization", e);
}
} }
public void add(BatchOperationHandle handle, ClientContact contact) { public void add(BatchOperationHandle handle, ClientContact contact) {
try {
Pipeline pipeline = handle.pipeline; Pipeline pipeline = handle.pipeline;
TokenValue tokenValue = new TokenValue(contact.getRelay(), contact.isSupportsSms()); TokenValue tokenValue = new TokenValue(contact.getRelay(), contact.isSupportsSms());
pipeline.hset(DIRECTORY_KEY, contact.getToken(), new Gson().toJson(tokenValue).getBytes()); pipeline.hset(DIRECTORY_KEY, contact.getToken(), objectMapper.writeValueAsBytes(tokenValue));
} catch (JsonProcessingException e) {
logger.warn("JSON Serialization", e);
}
} }
public PendingClientContact get(BatchOperationHandle handle, byte[] token) { public PendingClientContact get(BatchOperationHandle handle, byte[] token) {
Pipeline pipeline = handle.pipeline; Pipeline pipeline = handle.pipeline;
return new PendingClientContact(token, pipeline.hget(DIRECTORY_KEY, token)); return new PendingClientContact(objectMapper, token, pipeline.hget(DIRECTORY_KEY, token));
} }
public Optional<ClientContact> get(byte[] token) { public Optional<ClientContact> get(byte[] token) {
Jedis jedis = redisPool.getResource(); try (Jedis jedis = redisPool.getResource()) {
try {
byte[] result = jedis.hget(DIRECTORY_KEY, token); byte[] result = jedis.hget(DIRECTORY_KEY, token);
if (result == null) { if (result == null) {
return Optional.absent(); return Optional.absent();
} }
TokenValue tokenValue = new Gson().fromJson(new String(result), TokenValue.class); TokenValue tokenValue = objectMapper.readValue(result, TokenValue.class);
return Optional.of(new ClientContact(token, tokenValue.relay, tokenValue.supportsSms)); return Optional.of(new ClientContact(token, tokenValue.relay, tokenValue.supportsSms));
} finally { } catch (IOException e) {
redisPool.returnResource(jedis); logger.warn("JSON Error", e);
return Optional.absent();
} }
} }
public List<ClientContact> get(List<byte[]> tokens) { public List<ClientContact> get(List<byte[]> tokens) {
Jedis jedis = redisPool.getResource(); try (Jedis jedis = redisPool.getResource()) {
try {
Pipeline pipeline = jedis.pipelined(); Pipeline pipeline = jedis.pipelined();
List<Response<byte[]>> futures = new LinkedList<>(); List<Response<byte[]>> futures = new LinkedList<>();
List<ClientContact> results = new LinkedList<>(); List<ClientContact> results = new LinkedList<>();
@ -117,17 +130,19 @@ public class DirectoryManager {
IterablePair<byte[], Response<byte[]>> lists = new IterablePair<>(tokens, futures); IterablePair<byte[], Response<byte[]>> lists = new IterablePair<>(tokens, futures);
for (Pair<byte[], Response<byte[]>> pair : lists) { for (Pair<byte[], Response<byte[]>> pair : lists) {
try {
if (pair.second().get() != null) { if (pair.second().get() != null) {
TokenValue tokenValue = new Gson().fromJson(new String(pair.second().get()), TokenValue.class); TokenValue tokenValue = objectMapper.readValue(pair.second().get(), TokenValue.class);
ClientContact clientContact = new ClientContact(pair.first(), tokenValue.relay, tokenValue.supportsSms); ClientContact clientContact = new ClientContact(pair.first(), tokenValue.relay, tokenValue.supportsSms);
results.add(clientContact); results.add(clientContact);
} }
} catch (IOException e) {
logger.warn("Deserialization Problem: ", e);
}
} }
return results; return results;
} finally {
redisPool.returnResource(jedis);
} }
} }
@ -156,10 +171,10 @@ public class DirectoryManager {
} }
private static class TokenValue { private static class TokenValue {
@SerializedName("r") @JsonProperty(value = "r")
private String relay; private String relay;
@SerializedName("s") @JsonProperty(value = "s")
private boolean supportsSms; private boolean supportsSms;
public TokenValue(String relay, boolean supportsSms) { public TokenValue(String relay, boolean supportsSms) {
@ -169,22 +184,24 @@ public class DirectoryManager {
} }
public static class PendingClientContact { public static class PendingClientContact {
private final ObjectMapper objectMapper;
private final byte[] token; private final byte[] token;
private final Response<byte[]> response; private final Response<byte[]> response;
PendingClientContact(byte[] token, Response<byte[]> response) { PendingClientContact(ObjectMapper objectMapper, byte[] token, Response<byte[]> response) {
this.objectMapper = objectMapper;
this.token = token; this.token = token;
this.response = response; this.response = response;
} }
public Optional<ClientContact> get() { public Optional<ClientContact> get() throws IOException {
byte[] result = response.get(); byte[] result = response.get();
if (result == null) { if (result == null) {
return Optional.absent(); return Optional.absent();
} }
TokenValue tokenValue = new Gson().fromJson(new String(result), TokenValue.class); TokenValue tokenValue = objectMapper.readValue(result, TokenValue.class);
return Optional.of(new ClientContact(token, tokenValue.relay, tokenValue.supportsSms)); return Optional.of(new ClientContact(token, tokenValue.relay, tokenValue.supportsSms));
} }

View File

@ -29,6 +29,7 @@ import org.whispersystems.textsecuregcm.storage.DirectoryManager.BatchOperationH
import org.whispersystems.textsecuregcm.util.Base64; import org.whispersystems.textsecuregcm.util.Base64;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -53,9 +54,12 @@ public class DirectoryUpdater {
} }
public void updateFromLocalDatabase() { public void updateFromLocalDatabase() {
int contactsAdded = 0;
int contactsRemoved = 0;
BatchOperationHandle batchOperation = directory.startBatchOperation(); BatchOperationHandle batchOperation = directory.startBatchOperation();
try { try {
logger.info("Updating from local DB.");
Iterator<Account> accounts = accountsManager.getAll(); Iterator<Account> accounts = accountsManager.getAll();
if (accounts == null) if (accounts == null)
@ -69,17 +73,17 @@ public class DirectoryUpdater {
ClientContact clientContact = new ClientContact(token, null, account.getSupportsSms()); ClientContact clientContact = new ClientContact(token, null, account.getSupportsSms());
directory.add(batchOperation, clientContact); directory.add(batchOperation, clientContact);
contactsAdded++;
logger.debug("Adding local token: " + Base64.encodeBytesWithoutPadding(token));
} else { } else {
directory.remove(batchOperation, account.getNumber()); directory.remove(batchOperation, account.getNumber());
contactsRemoved++;
} }
} }
} finally { } finally {
directory.stopBatchOperation(batchOperation); directory.stopBatchOperation(batchOperation);
} }
logger.info("Local directory is updated."); logger.info(String.format("Local directory is updated (%d added, %d removed).", contactsAdded, contactsRemoved));
} }
public void updateFromPeers() { public void updateFromPeers() {
@ -121,6 +125,7 @@ public class DirectoryUpdater {
Iterator<PendingClientContact> localContactIterator = localContacts.iterator(); Iterator<PendingClientContact> localContactIterator = localContacts.iterator();
while (remoteContactIterator.hasNext() && localContactIterator.hasNext()) { while (remoteContactIterator.hasNext() && localContactIterator.hasNext()) {
try {
ClientContact remoteContact = remoteContactIterator.next(); ClientContact remoteContact = remoteContactIterator.next();
Optional<ClientContact> localContact = localContactIterator.next().get(); Optional<ClientContact> localContact = localContactIterator.next().get();
@ -135,6 +140,9 @@ public class DirectoryUpdater {
directory.remove(handle, remoteContact.getToken()); directory.remove(handle, remoteContact.getToken());
} }
} }
} catch (IOException e) {
logger.warn("JSON Serialization Failed: ", e);
}
} }
directory.stopBatchOperation(handle); directory.stopBatchOperation(handle);