Projects >> zipwhip-api >>ae8b2dfa55211782886c7bd811cba95f7a41641f

Chunk
Conflicting content
<<<<<<< HEAD
package com.zipwhip.api;

import com.zipwhip.api.dto.*;
import com.zipwhip.api.exception.NotAuthenticatedException;
import com.zipwhip.api.response.BooleanServerResponse;
import com.zipwhip.api.response.ServerResponse;
import com.zipwhip.api.response.StringServerResponse;
import com.zipwhip.api.settings.SettingsStore;
import com.zipwhip.api.signals.*;
import com.zipwhip.concurrent.ObservableFuture;
import com.zipwhip.events.Observer;
import com.zipwhip.signals.presence.Presence;
import com.zipwhip.signals.presence.PresenceCategory;
import com.zipwhip.signals.presence.ProductLine;
import com.zipwhip.util.CollectionUtil;
import com.zipwhip.util.StringUtil;

import java.util.*;
import java.util.concurrent.*;

/**
 * Date: Jul 17, 2009 Time: 7:25:37 PM
 * 

* This provides an Object Oriented way to access the Zipwhip API. It uses a * Connection internally for low-level Zipwhip access. This class does not * manage your authentication, the Connection abstracts this away from * the "Zipwhip" class. */ public class DefaultZipwhipClient extends ClientZipwhipNetworkSupport implements ZipwhipClient { @Override public User getUser() throws Exception { final Map params = new HashMap(); return responseParser.parseUser(executeSync(USER_GET, params)); } /** * Create a new DefaultZipwhipClient. * * @param connection The connection to Zipwhip API * @param signalProvider The connection client for Zipwhip SignalServer. */ public DefaultZipwhipClient(ApiConnection connection, SignalProvider signalProvider) { super(connection, signalProvider); // Start listening to provider events that interest us initSignalProviderEvents(); } private void initSignalProviderEvents() { signalProvider.onNewClientIdReceived(new Observer() { @Override public void notify(Object sender, String clientId) { if (StringUtil.isNullOrEmpty(clientId)) { LOGGER.warn("Received CONNECT without clientId"); return; } if (StringUtil.isNullOrEmpty(connection.getSessionKey())) { settingsStore.put(SettingsStore.Keys.CLIENT_ID, clientId); return; } String managedClientId = settingsStore.get(SettingsStore.Keys.CLIENT_ID); if (StringUtil.exists(managedClientId)) { // clientId changed, unsubscribe the old one, and sub the new one if (!managedClientId.equals(clientId)) { settingsStore.clear(); settingsStore.put(SettingsStore.Keys.CLIENT_ID, clientId); // Do a disconnect then connect Map params = new HashMap(); params.put("clientId", clientId); params.put("sessions", connection.getSessionKey()); try { executeSync(SIGNALS_DISCONNECT, params); executeSync(SIGNALS_CONNECT, params); } catch (Exception e) { LOGGER.error("Error calling signals/connect", e); } } } else { settingsStore.put(SettingsStore.Keys.CLIENT_ID, clientId); // lets do a signals connect! Map params = new HashMap(); params.put("clientId", clientId); params.put("sessions", connection.getSessionKey()); try { executeSync(SIGNALS_CONNECT, params); } catch (Exception e) { LOGGER.error("Error calling signals/connect", e); } } } }); signalProvider.onVersionChanged(new Observer() { @Override public void notify(Object sender, VersionMapEntry item) { versionsStore.set(item.getKey(), item.getValue()); } }); } @Override public Future connect() throws Exception { return connect(null); } @Override public Future connect(Presence presence) throws Exception { // we need to determine if we're authenticated enough if (!connection.isConnected() || !connection.isAuthenticated()) { throw new NotAuthenticatedException("The connection cannot operate at this time"); } String managedClientId = settingsStore.get(SettingsStore.Keys.CLIENT_ID); // If the clientId has changed we need to invalidate the settings data if (StringUtil.isNullOrEmpty(managedClientId) || (StringUtil.exists(signalProvider.getClientId()) && !managedClientId.equals(signalProvider.getClientId()))) { LOGGER.debug("ClientId has changed, resetting client id in settings store"); settingsStore.clear(); if (signalProvider!=null && signalProvider.getClientId() != null) { settingsStore.put(SettingsStore.Keys.CLIENT_ID, signalProvider.getClientId()); } } // If the sessionKey has changed we need to invalidate the settings data if (StringUtil.exists(connection.getSessionKey()) && !connection.getSessionKey().equals(settingsStore.get(SettingsStore.Keys.SESSION_KEY))) { LOGGER.debug("New or changed sessionKey, resetting session key in settings store"); settingsStore.clear(); settingsStore.put(SettingsStore.Keys.SESSION_KEY, connection.getSessionKey()); } // Will NOT block until you're connected it's asynchronous return signalProvider.connect(settingsStore.get(SettingsStore.Keys.CLIENT_ID), versionsStore.get(), presence); } @Override public Future disconnect() throws Exception { if (!connection.isConnected()) { throw new Exception("The connection is not connected!"); } return signalProvider.disconnect(); } @Override public List sendMessage(Address address, String body) throws Exception { return sendMessage(Arrays.asList(address.toString()), body, null, null); } @Override params.put("start", Integer.toString(start)); public List sendMessage(Address address, String body, String fromName) throws Exception { return sendMessage(Arrays.asList(address.toString()), body, fromName, null); } @Override public List sendMessage(String address, String body) throws Exception { return sendMessage(Arrays.asList(address), body); } @Override public List sendMessage(Message message) throws Exception { return sendMessage(Arrays.asList(message.getAddress()), message.getBody(), message.getFromName(), message.getAdvertisement()); } @Override public List sendMessage(Collection address, String body) throws Exception { return sendMessage(address, body, null, null); } @Override public List sendMessage(Collection address, String body, String fromName) throws Exception { return sendMessage(address, body, fromName, null); } @Override public List sendMessage(Collection addresses, String body, String fromName, String advertisement) throws Exception { final Map params = new HashMap(); params.put("contacts", addresses); params.put("body", body); params.put("fromName", fromName); params.put("fromAddress", "0"); params.put("advertisement", advertisement); return responseParser.parseMessageTokens(executeSync(MESSAGE_SEND, params)); } @Override public List sendMessage(String address, String body, String fromName, String advertisement) throws Exception { return sendMessage(Arrays.asList(address), body, fromName, advertisement); } @Override public List sendMessage(String address, String body, int fromAddress) throws Exception { final Map params = new HashMap(); params.put("contacts", address); params.put("body", body); params.put("fromAddress", fromAddress); return responseParser.parseMessageTokens(executeSync(MESSAGE_SEND, params)); } @Deprecated @Override public Message getMessage(String uuid) throws Exception { final Map params = new HashMap(); params.put("uuid", uuid); return responseParser.parseMessage(executeSync(MESSAGE_GET, params)); } @Override public Message getMessage(Long id) throws Exception { final Map params = new HashMap(); params.put("id", id); return responseParser.parseMessage(executeSync(MESSAGE_GET, params)); } @Override public List listDevices() throws Exception { return responseParser.parseDevices(executeSync(DEVICE_LIST, new HashMap())); } @Override public List listConversations() throws Exception { return responseParser.parseConversations(executeSync(CONVERSATION_LIST, new HashMap())); } @Override public List listConversations(int limit) throws Exception { final Map params = new HashMap(); params.put("limit", Integer.toString(limit)); return responseParser.parseConversations(executeSync(CONVERSATION_LIST, params)); } @Override public List listConversations(int start, int limit) throws Exception { final Map params = new HashMap(); params.put("limit", Integer.toString(limit)); return responseParser.parseConversations(executeSync(CONVERSATION_LIST, params)); } @Override public List listContacts() throws Exception { return responseParser.parseContacts(executeSync(CONTACT_LIST, new HashMap())); } @Override public boolean readConversation(String fingerprint) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)) { return false; } final Map params = new HashMap(); params.put("fingerprint", fingerprint); return success(executeSync(CONVERSATION_READ, params)); } @Override public boolean deleteConversation(String fingerprint) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)) { return false; } final Map params = new HashMap(); params.put("fingerprint", fingerprint); return success(executeSync(CONVERSATION_DELETE, params)); } @Override public boolean deleteContact(long contactId) throws Exception { if (contactId <= 0){ return false; } final Map params = new HashMap(); params.put("contact", Long.toString(contactId)); return success(executeSync(CONTACT_DELETE, params)); } @Override public List listMessagesByFingerprint(String fingerprint) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)){ throw new Exception("Attempting to call listMessagesByFingerprint with a null or empty fingerprint."); } final Map params = new HashMap(); params.put("fingerprint", fingerprint); return responseParser.parseMessagesFromConversation(executeSync(CONVERSATION_GET, params)); } @Override public List listMessagesByFingerprint(String fingerprint, int limit) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)){ throw new Exception("Attempting to call listMessagesByFingerprint with a null or empty fingerprint."); } else if (limit <= 0) { throw new Exception("Attempting to call listMessagesByFingerprint with a zero or negative limit value."); } final Map params = new HashMap(); params.put("fingerprint", fingerprint); params.put("limit", Integer.toString(limit)); return responseParser.parseMessagesFromConversation(executeSync(CONVERSATION_GET, params)); } @Override public List listMessagesByFingerprint(String fingerprint, int start, int limit) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)){ throw new Exception("Attempting to call listMessagesByFingerprint with a null or empty fingerprint."); } else if (start < 0){ throw new Exception("Attempting to call listMessagesByFingerprint with a negative start value."); } else if (limit <= 0) { throw new Exception("Attempting to call listMessagesByFingerprint with a zero or negative limit value."); } final Map params = new HashMap(); params.put("fingerprint", fingerprint); params.put("start", Integer.toString(start)); params.put("limit", Integer.toString(limit)); return responseParser.parseMessagesFromConversation(executeSync(CONVERSATION_GET, params)); } @Override public List listMessages() throws Exception { return responseParser.parseMessages(executeSync(MESSAGE_LIST, new HashMap())); } @Override public List listMessages(int limit) throws Exception { final Map params = new HashMap(); params.put("limit", Integer.toString(limit)); return responseParser.parseMessages(executeSync(MESSAGE_LIST, params)); } @Deprecated @Override public boolean messageRead(List uuids) throws Exception { if (CollectionUtil.isNullOrEmpty(uuids)) { return false; } final Map params = new HashMap(); params.put("uuid", uuids); return success(executeSync(MESSAGE_READ, params)); } @Override public boolean readMessage(List ids) throws Exception { if (CollectionUtil.isNullOrEmpty(ids)) { return false; } final Map params = new HashMap(); params.put("message", ids); return success(executeSync(MESSAGE_READ, params)); } @Deprecated @Override public boolean messageDelete(List uuids) throws Exception { if (CollectionUtil.isNullOrEmpty(uuids)) { return false; } final Map params = new HashMap(); params.put("uuids", uuids); return success(executeSync(MESSAGE_DELETE, params)); } @Override public boolean deleteMessage(List ids) throws Exception { if (CollectionUtil.isNullOrEmpty(ids)) { return false; } final Map params = new HashMap(); params.put("message", ids); return success(executeSync(MESSAGE_DELETE, params)); } @Deprecated @Override public MessageStatus getMessageStatus(String uuid) throws Exception { Message message = getMessage(uuid); if (message == null) { return null; } return new MessageStatus(message); } @Override public MessageStatus getMessageStatus(Long id) throws Exception { Message message = getMessage(id); if (message == null) { return null; } return new MessageStatus(message); } @Override public Contact getContact(long id) throws Exception { final Map params = new HashMap(); params.put("id", Long.toString(id)); return responseParser.parseContact(executeSync(CONTACT_GET, params)); } @Override public Contact getContact(String mobileNumber) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); return responseParser.parseContact(executeSync(CONTACT_GET, params)); } @Override public List getPresence(PresenceCategory category) throws Exception { Map params = new HashMap(); if (!category.equals(PresenceCategory.NONE)) { params.put("category", category.toString()); } return responseParser.parsePresence(executeSync(PRESENCE_GET, params)); } @Override public void sendSignal(String scope, String channel, String event, String payload) throws Exception { final Map params = new HashMap(); // is this a device signal or a session signal? params.put("scope", scope); // what happened? was something created? destroyed? changed? params.put("event", event); // what is the data you need sent to the browser params.put("payload", payload); // what URI would you like the browser to fire on? Make sure you have browser code that is subscribing to it. params.put("channel", channel); // send the 3rd party signal. executeSync(SIGNAL_SEND, params); } @Override public void sendSignalsVerification(String clientId) throws Exception { final Map params = new HashMap(); params.put("clientId", clientId); executeSync(SIGNALS_VERIFY, params); } @Override public Contact addMember(String groupAddress, String contactAddress) throws Exception { return addMember(groupAddress, contactAddress, null, null, null, null); } @Override public Contact addMember(String groupAddress, String contactAddress, String firstName, String lastName, String phoneKey, String notes) throws Exception { final Map params = new HashMap(); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); params.put("notes", notes); params.put("group", groupAddress); params.put("mobileNumber", new Address(contactAddress).getAuthority()); ServerResponse serverResponse = executeSync(GROUP_ADD_MEMBER, params); return responseParser.parseContact(serverResponse); } @Override public void carbonEnable(boolean enabled, Integer versionCode) throws Exception { final Map params = new HashMap(); params.put("enabled", enabled); if(versionCode != null) { params.put("version", versionCode.toString()); } executeSync(CARBON_ENABLE, params); } @Override public Boolean carbonEnabled(boolean enabled, Integer versionCode) throws Exception { final Map params = new HashMap(); params.put("enabled", enabled); if(versionCode != null) { params.put("version", versionCode.toString()); } ServerResponse response = executeSync(CARBON_ENABLED, params); if (response instanceof BooleanServerResponse) { BooleanServerResponse booleanServerResponse = (BooleanServerResponse) response; return booleanServerResponse.getResponse(); } else { throw new Exception("Unrecognized server response for carbon enabled"); } } @Override public Boolean carbonRegister(String registrationId) throws Exception { final Map params = new HashMap(); if(!StringUtil.isNullOrEmpty(registrationId)) { params.put("registrationId", registrationId); } return success(executeSync(CARBON_REGISTER, params)); } @Override public void carbonStats(int totalPhoneMessages) throws Exception { final Map params = new HashMap(); params.put("messageCount", totalPhoneMessages); executeSync(CARBON_STATS, params); } @Override public boolean acceptedTCs() throws Exception { ServerResponse response = executeSync(CARBON_ACCEPTED_TCS, null); if (response instanceof BooleanServerResponse) { BooleanServerResponse booleanServerResponse = (BooleanServerResponse) response; return booleanServerResponse.getResponse(); } else { throw new Exception("Unrecognized server response for carbon enabled"); } } @Override public String sessionChallenge(String mobileNumber, String portal) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); params.put("portal", portal); ServerResponse response = executeSync(CHALLENGE_REQUEST, params, false); if (response instanceof StringServerResponse) { StringServerResponse stringServerResponse = (StringServerResponse) response; return stringServerResponse.response; } else { throw new Exception("Unrecognized server response for challenge request"); } } @Override public String sessionChallengeConfirm(String clientId, String securityToken, String arguments, String userAgent) throws Exception { final Map params = new HashMap(); params.put("clientId", clientId); params.put("securityToken", securityToken); params.put("arguments", arguments); params.put("userAgent", userAgent); ServerResponse response = executeSync(CHALLENGE_CONFIRM, params, false); if (response instanceof StringServerResponse) { StringServerResponse stringServerResponse = (StringServerResponse) response; return stringServerResponse.response; } else { throw new Exception("Unrecognized server response for challenge confirm"); } } @Override public boolean userUnenroll(String packageName) throws Exception { final Map params = new HashMap(); params.put("package", packageName); return success(executeSync(USER_UNENROLL, params)); } @Override public void addSignalObserver(Observer> observer) { getSignalProvider().onSignalReceived(observer); } @Override public void addSignalsConnectionObserver(Observer observer) { getSignalProvider().onConnectionChanged(observer); } @Override public void saveContact(String address, String firstName, String lastName, String phoneKey) throws Exception { saveContact(address, firstName, lastName, phoneKey, null); } @Override public Contact saveGroup() throws Exception { return saveGroup(null, null); } @Override public Contact saveUser(Contact contact) throws Exception { final Map params = new HashMap(); params.put("email", contact.getEmail()); params.put("firstName", contact.getFirstName()); params.put("lastName", contact.getLastName()); params.put("phoneKey", contact.getPhone()); ServerResponse serverResponse = executeSync(USER_SAVE, params); return responseParser.parseContact(serverResponse); } @Override public void saveUser(String firstName, String lastName, String email, String phoneKey, String location, String notes) throws Exception { final Map params = new HashMap(); params.put("email", email); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); params.put("notes", notes); params.put("loc", location); executeSync(USER_SAVE, params); } @Override public Contact saveGroup(String type, String advertisement) throws Exception { final Map params = new HashMap(); if (type == null) { type = "Group"; } if (!type.startsWith("Group")) { type = "Group"; } params.put("type", type); if (advertisement != null) { params.put("advertisement", advertisement); } return responseParser.parseContact(executeSync(GROUP_SAVE, params)); } @Override public void saveContact(String address, String firstName, String lastName, String phoneKey, String notes) throws Exception { final Map params = new HashMap(); params.put("address", address); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); if (notes != null) { params.put("notes", notes); } // happens async executeSync(CONTACT_SAVE, params); } @Override public void saveContact(String address, String firstName, String lastName, String phoneKey, String notes, String location, String email) throws Exception { final Map params = new HashMap(); params.put("address", address); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); if (notes != null) { params.put("notes", notes); } if (location != null){ params.put("loc", location); } if (email != null){ params.put("email", email); } // happens async @Override executeSync(CONTACT_SAVE, params); } @Override public String getFaceName(String mobileNumber) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); return responseParser.parseFaceName(executeSync(FACE_NAME, params, false)); } @Override public byte[] getFaceImage(String mobileNumber, boolean thumbnail) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); params.put("thumbnail", thumbnail); ObservableFuture binaryResponseFuture = executeAsyncBinaryResponse(FACE_IMAGE, params, false); // Block and wait... binaryResponseFuture.awaitUninterruptibly(); return binaryResponseFuture.getResult(); } @Override public byte[] getFaceImage(String mobileNumber, int size) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); params.put("size", size); params.put("thumbnail", true); ObservableFuture binaryResponseFuture = executeAsyncBinaryResponse(FACE_IMAGE, params, false); // Block and wait... binaryResponseFuture.awaitUninterruptibly(); return binaryResponseFuture.getResult(); } @Override public void recordMetricsEvent(ProductLine product, String mobileNumber, String event, String payload) throws Exception { if (product == null || StringUtil.isNullOrEmpty(mobileNumber) || StringUtil.isNullOrEmpty(event)) { throw new Exception("Missing required parameter."); } final Map params = new HashMap(); params.put("product", product.toString()); params.put("mobileNumber", mobileNumber); params.put("event", event); if (StringUtil.exists(payload)) { params.put("payload", payload); } executeSync(METRICS_EVENT, params); } @Override protected void onDestroy() { } } ======= package com.zipwhip.api; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Future; import com.zipwhip.api.dto.Contact; import com.zipwhip.api.dto.Conversation; import com.zipwhip.api.dto.Device; import com.zipwhip.api.dto.Message; import com.zipwhip.api.dto.MessageStatus; import com.zipwhip.api.dto.MessageToken; import com.zipwhip.api.exception.NotAuthenticatedException; import com.zipwhip.api.response.BooleanServerResponse; import com.zipwhip.api.response.ServerResponse; import com.zipwhip.api.response.StringServerResponse; import com.zipwhip.api.settings.SettingsStore; import com.zipwhip.api.signals.Signal; import com.zipwhip.api.signals.SignalProvider; import com.zipwhip.api.signals.VersionMapEntry; import com.zipwhip.concurrent.ObservableFuture; import com.zipwhip.events.Observer; import com.zipwhip.signals.presence.Presence; import com.zipwhip.signals.presence.PresenceCategory; import com.zipwhip.signals.presence.ProductLine; import com.zipwhip.util.CollectionUtil; import com.zipwhip.util.StringUtil; /** * Date: Jul 17, 2009 Time: 7:25:37 PM *

* This provides an Object Oriented way to access the Zipwhip API. It uses a * Connection internally for low-level Zipwhip access. This class does not * manage your authentication, the Connection abstracts this away from * the "Zipwhip" class. */ public class DefaultZipwhipClient extends ClientZipwhipNetworkSupport implements ZipwhipClient { /** * Create a new DefaultZipwhipClient. * * @param connection The connection to Zipwhip API * @param signalProvider The connection client for Zipwhip SignalServer. */ public DefaultZipwhipClient(ApiConnection connection, SignalProvider signalProvider) { super(connection, signalProvider); // Start listening to provider events that interest us initSignalProviderEvents(); } private void initSignalProviderEvents() { signalProvider.onNewClientIdReceived(new Observer() { @Override public void notify(Object sender, String clientId) { if (StringUtil.isNullOrEmpty(clientId)) { LOGGER.warn("Received CONNECT without clientId"); return; } if (StringUtil.isNullOrEmpty(connection.getSessionKey())) { settingsStore.put(SettingsStore.Keys.CLIENT_ID, clientId); return; } String managedClientId = settingsStore.get(SettingsStore.Keys.CLIENT_ID); if (StringUtil.exists(managedClientId)) { // clientId changed, unsubscribe the old one, and sub the new one if (!managedClientId.equals(clientId)) { settingsStore.clear(); settingsStore.put(SettingsStore.Keys.CLIENT_ID, clientId); // Do a disconnect then connect Map params = new HashMap(); params.put("clientId", clientId); params.put("sessions", connection.getSessionKey()); Presence presence = signalProvider.getPresence(); if (presence != null) params.put("category", presence.getCategory()); try { executeSync(SIGNALS_DISCONNECT, params); executeSync(SIGNALS_CONNECT, params); } catch (Exception e) { LOGGER.error("Error calling signals/connect", e); } } } else { settingsStore.put(SettingsStore.Keys.CLIENT_ID, clientId); // lets do a signals connect! Map params = new HashMap(); params.put("clientId", clientId); params.put("sessions", connection.getSessionKey()); Presence presence = signalProvider.getPresence(); if (presence != null) params.put("category", presence.getCategory()); try { executeSync(SIGNALS_CONNECT, params); } catch (Exception e) { LOGGER.error("Error calling signals/connect", e); } } } }); signalProvider.onVersionChanged(new Observer() { @Override public void notify(Object sender, VersionMapEntry item) { versionsStore.set(item.getKey(), item.getValue()); } }); } @Override public Future connect() throws Exception { return connect(null); } @Override public Future connect(Presence presence) throws Exception { // we need to determine if we're authenticated enough if (!connection.isConnected() || !connection.isAuthenticated()) { throw new NotAuthenticatedException("The connection cannot operate at this time"); } String managedClientId = settingsStore.get(SettingsStore.Keys.CLIENT_ID); // If the clientId has changed we need to invalidate the settings data if (StringUtil.isNullOrEmpty(managedClientId) || (StringUtil.exists(signalProvider.getClientId()) && !managedClientId.equals(signalProvider.getClientId()))) { LOGGER.debug("ClientId has changed, resetting client id in settings store"); settingsStore.clear(); if (signalProvider!=null && signalProvider.getClientId() != null) { settingsStore.put(SettingsStore.Keys.CLIENT_ID, signalProvider.getClientId()); } } // If the sessionKey has changed we need to invalidate the settings data if (StringUtil.exists(connection.getSessionKey()) && !connection.getSessionKey().equals(settingsStore.get(SettingsStore.Keys.SESSION_KEY))) { LOGGER.debug("New or changed sessionKey, resetting session key in settings store"); settingsStore.clear(); settingsStore.put(SettingsStore.Keys.SESSION_KEY, connection.getSessionKey()); } // Will NOT block until you're connected it's asynchronous return signalProvider.connect(settingsStore.get(SettingsStore.Keys.CLIENT_ID), versionsStore.get(), presence); } @Override public Future disconnect() throws Exception { if (!connection.isConnected()) { throw new Exception("The connection is not connected!"); } return signalProvider.disconnect(); } @Override public List sendMessage(Address address, String body) throws Exception { return sendMessage(Arrays.asList(address.toString()), body, null, null); } @Override public List sendMessage(Address address, String body, String fromName) throws Exception { return sendMessage(Arrays.asList(address.toString()), body, fromName, null); } @Override public List sendMessage(String address, String body) throws Exception { return sendMessage(Arrays.asList(address), body); } @Override public List sendMessage(Message message) throws Exception { return sendMessage(Arrays.asList(message.getAddress()), message.getBody(), message.getFromName(), message.getAdvertisement()); } @Override public List sendMessage(Collection address, String body) throws Exception { return sendMessage(address, body, null, null); } @Override public List sendMessage(Collection address, String body, String fromName) throws Exception { return sendMessage(address, body, fromName, null); } @Override public List sendMessage(Collection addresses, String body, String fromName, String advertisement) throws Exception { final Map params = new HashMap(); params.put("contacts", addresses); params.put("body", body); params.put("fromName", fromName); params.put("fromAddress", "0"); params.put("advertisement", advertisement); return responseParser.parseMessageTokens(executeSync(MESSAGE_SEND, params)); } @Override public List sendMessage(String address, String body, String fromName, String advertisement) throws Exception { return sendMessage(Arrays.asList(address), body, fromName, advertisement); } @Override public List sendMessage(String address, String body, int fromAddress) throws Exception { final Map params = new HashMap(); params.put("contacts", address); params.put("body", body); params.put("fromAddress", fromAddress); return responseParser.parseMessageTokens(executeSync(MESSAGE_SEND, params)); } @Deprecated @Override public Message getMessage(String uuid) throws Exception { final Map params = new HashMap(); params.put("uuid", uuid); return responseParser.parseMessage(executeSync(MESSAGE_GET, params)); } @Override public Message getMessage(Long id) throws Exception { final Map params = new HashMap(); params.put("id", id); return responseParser.parseMessage(executeSync(MESSAGE_GET, params)); } @Override public List listDevices() throws Exception { return responseParser.parseDevices(executeSync(DEVICE_LIST, new HashMap())); } @Override public List listConversations() throws Exception { return responseParser.parseConversations(executeSync(CONVERSATION_LIST, new HashMap())); } @Override public List listConversations(int limit) throws Exception { final Map params = new HashMap(); params.put("limit", Integer.toString(limit)); return responseParser.parseConversations(executeSync(CONVERSATION_LIST, params)); } @Override public List listConversations(int start, int limit) throws Exception { final Map params = new HashMap(); params.put("start", Integer.toString(start)); params.put("limit", Integer.toString(limit)); return responseParser.parseConversations(executeSync(CONVERSATION_LIST, params)); } @Override public List listContacts() throws Exception { return responseParser.parseContacts(executeSync(CONTACT_LIST, new HashMap())); } @Override public boolean readConversation(String fingerprint) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)) { return false; } final Map params = new HashMap(); params.put("fingerprint", fingerprint); return success(executeSync(CONVERSATION_READ, params)); } @Override public boolean deleteConversation(String fingerprint) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)) { return false; } final Map params = new HashMap(); params.put("fingerprint", fingerprint); return success(executeSync(CONVERSATION_DELETE, params)); } public boolean deleteContact(long contactId) throws Exception { if (contactId <= 0){ return false; } final Map params = new HashMap(); params.put("contact", Long.toString(contactId)); return success(executeSync(CONTACT_DELETE, params)); } @Override public List listMessagesByFingerprint(String fingerprint) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)){ throw new Exception("Attempting to call listMessagesByFingerprint with a null or empty fingerprint."); } final Map params = new HashMap(); params.put("fingerprint", fingerprint); return responseParser.parseMessagesFromConversation(executeSync(CONVERSATION_GET, params)); } @Override public List listMessagesByFingerprint(String fingerprint, int limit) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)){ throw new Exception("Attempting to call listMessagesByFingerprint with a null or empty fingerprint."); } final Map params = new HashMap(); params.put("fingerprint", fingerprint); params.put("limit", Integer.toString(limit)); return responseParser.parseMessagesFromConversation(executeSync(CONVERSATION_GET, params)); } @Override public List listMessages() throws Exception { return responseParser.parseMessages(executeSync(MESSAGE_LIST, new HashMap())); } @Override public List listMessages(int limit) throws Exception { final Map params = new HashMap(); params.put("limit", Integer.toString(limit)); return responseParser.parseMessages(executeSync(MESSAGE_LIST, params)); } @Deprecated @Override public boolean messageRead(List uuids) throws Exception { if (CollectionUtil.isNullOrEmpty(uuids)) { return false; } final Map params = new HashMap(); params.put("uuid", uuids); return success(executeSync(MESSAGE_READ, params)); } @Override public boolean readMessage(List ids) throws Exception { if (CollectionUtil.isNullOrEmpty(ids)) { return false; } final Map params = new HashMap(); params.put("message", ids); return success(executeSync(MESSAGE_READ, params)); } @Deprecated @Override public boolean messageDelete(List uuids) throws Exception { if (CollectionUtil.isNullOrEmpty(uuids)) { return false; } final Map params = new HashMap(); params.put("uuids", uuids); return success(executeSync(MESSAGE_DELETE, params)); } @Override public boolean deleteMessage(List ids) throws Exception { if (CollectionUtil.isNullOrEmpty(ids)) { return false; } final Map params = new HashMap(); params.put("message", ids); return success(executeSync(MESSAGE_DELETE, params)); } @Deprecated @Override public MessageStatus getMessageStatus(String uuid) throws Exception { Message message = getMessage(uuid); if (message == null) { return null; } return new MessageStatus(message); } @Override public MessageStatus getMessageStatus(Long id) throws Exception { Message message = getMessage(id); if (message == null) { return null; } return new MessageStatus(message); } @Override public Contact getContact(long id) throws Exception { final Map params = new HashMap(); params.put("id", Long.toString(id)); return responseParser.parseContact(executeSync(CONTACT_GET, params)); } @Override public Contact getContact(String mobileNumber) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); return responseParser.parseContact(executeSync(CONTACT_GET, params)); } @Override public List getPresence(PresenceCategory category) throws Exception { Map params = new HashMap(); if (!category.equals(PresenceCategory.NONE)) { params.put("category", category.toString()); } return responseParser.parsePresence(executeSync(PRESENCE_GET, params)); } @Override public void sendSignal(String scope, String channel, String event, String payload) throws Exception { final Map params = new HashMap(); // is this a device signal or a session signal? params.put("scope", scope); // what happened? was something created? destroyed? changed? params.put("event", event); // what is the data you need sent to the browser params.put("payload", payload); // what URI would you like the browser to fire on? Make sure you have browser code that is subscribing to it. params.put("channel", channel); // send the 3rd party signal. executeSync(SIGNAL_SEND, params); } @Override public void sendSignalsVerification(String clientId) throws Exception { final Map params = new HashMap(); params.put("clientId", clientId); executeSync(SIGNALS_VERIFY, params); } @Override public Contact addMember(String groupAddress, String contactAddress) throws Exception { return addMember(groupAddress, contactAddress, null, null, null, null); } @Override public Contact addMember(String groupAddress, String contactAddress, String firstName, String lastName, String phoneKey, String notes) throws Exception { final Map params = new HashMap(); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); params.put("notes", notes); params.put("group", groupAddress); params.put("mobileNumber", new Address(contactAddress).getAuthority()); ServerResponse serverResponse = executeSync(GROUP_ADD_MEMBER, params); return responseParser.parseContact(serverResponse); } @Override public void carbonEnable(boolean enabled, Integer versionCode) throws Exception { final Map params = new HashMap(); params.put("enabled", enabled); if(versionCode != null) { params.put("version", versionCode.toString()); } executeSync(CARBON_ENABLE, params); } @Override public Boolean carbonEnabled(boolean enabled, Integer versionCode) throws Exception { final Map params = new HashMap(); params.put("enabled", enabled); if(versionCode != null) { params.put("version", versionCode.toString()); } ServerResponse response = executeSync(CARBON_ENABLED, params); if (response instanceof BooleanServerResponse) { BooleanServerResponse booleanServerResponse = (BooleanServerResponse) response; return booleanServerResponse.getResponse(); } else { throw new Exception("Unrecognized server response for carbon enabled"); } } @Override public Boolean carbonRegister(String registrationId) throws Exception { final Map params = new HashMap(); if(!StringUtil.isNullOrEmpty(registrationId)) { params.put("registrationId", registrationId); } return success(executeSync(CARBON_REGISTER, params)); } @Override public void carbonStats(int totalPhoneMessages) throws Exception { final Map params = new HashMap(); params.put("messageCount", totalPhoneMessages); executeSync(CARBON_STATS, params); } @Override public boolean acceptedTCs() throws Exception { ServerResponse response = executeSync(CARBON_ACCEPTED_TCS, null); if (response instanceof BooleanServerResponse) { BooleanServerResponse booleanServerResponse = (BooleanServerResponse) response; return booleanServerResponse.getResponse(); } else { throw new Exception("Unrecognized server response for carbon enabled"); } } @Override public String sessionChallenge(String mobileNumber, String portal) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); params.put("portal", portal); ServerResponse response = executeSync(CHALLENGE_REQUEST, params, false); if (response instanceof StringServerResponse) { StringServerResponse stringServerResponse = (StringServerResponse) response; return stringServerResponse.response; } else { throw new Exception("Unrecognized server response for challenge request"); } } @Override public String sessionChallengeConfirm(String clientId, String securityToken, String portal, String arguments, String userAgent) throws Exception { final Map params = new HashMap(); params.put("clientId", clientId); params.put("securityToken", securityToken); params.put("portal", portal); params.put("arguments", arguments); params.put("userAgent", userAgent); ServerResponse response = executeSync(CHALLENGE_CONFIRM, params, false); if (response instanceof StringServerResponse) { StringServerResponse stringServerResponse = (StringServerResponse) response; return stringServerResponse.response; } else { throw new Exception("Unrecognized server response for challenge confirm"); } } @Override public boolean userUnenroll(String packageName) throws Exception { final Map params = new HashMap(); params.put("package", packageName); return success(executeSync(USER_UNENROLL, params)); } @Override public void addSignalObserver(Observer> observer) { getSignalProvider().onSignalReceived(observer); } @Override public void addSignalsConnectionObserver(Observer observer) { getSignalProvider().onConnectionChanged(observer); } @Override public void saveContact(String address, String firstName, String lastName, String phoneKey) throws Exception { saveContact(address, firstName, lastName, phoneKey, null); } @Override public Contact saveGroup() throws Exception { return saveGroup(null, null); } @Override public Contact saveUser(Contact contact) throws Exception { final Map params = new HashMap(); params.put("email", contact.getEmail()); params.put("firstName", contact.getFirstName()); params.put("lastName", contact.getLastName()); params.put("phoneKey", contact.getPhone()); ServerResponse serverResponse = executeSync(USER_SAVE, params); return responseParser.parseContact(serverResponse); } @Override public Contact saveGroup(String type, String advertisement) throws Exception { final Map params = new HashMap(); if (type == null) { type = "Group"; } if (!type.startsWith("Group")) { type = "Group"; } params.put("type", type); if (advertisement != null) { params.put("advertisement", advertisement); } return responseParser.parseContact(executeSync(GROUP_SAVE, params)); } @Override public void saveContact(String address, String firstName, String lastName, String phoneKey, String notes) throws Exception { final Map params = new HashMap(); params.put("address", address); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); if (notes != null) { params.put("notes", notes); } // happens async executeSync(CONTACT_SAVE, params); } @Override public void saveContact(String address, String firstName, String lastName, String phoneKey, String notes, String location, String email) throws Exception { final Map params = new HashMap(); params.put("address", address); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); if (notes != null) { params.put("notes", notes); } if (location != null){ params.put("loc", location); } if (email != null){ params.put("email", email); } // happens async executeSync(CONTACT_SAVE, params); } @Override public String getFaceName(String mobileNumber) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); return responseParser.parseFaceName(executeSync(FACE_NAME, params, false)); } @Override public byte[] getFaceImage(String mobileNumber, boolean thumbnail) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); params.put("thumbnail", thumbnail); ObservableFuture binaryResponseFuture = executeAsyncBinaryResponse(FACE_IMAGE, params, false); // Block and wait... binaryResponseFuture.awaitUninterruptibly(); return binaryResponseFuture.getResult(); } @Override public byte[] getFaceImage(String mobileNumber, int size) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); params.put("size", size); params.put("thumbnail", true); ObservableFuture binaryResponseFuture = executeAsyncBinaryResponse(FACE_IMAGE, params, false); // Block and wait... binaryResponseFuture.awaitUninterruptibly(); return binaryResponseFuture.getResult(); } @Override public void recordMetricsEvent(ProductLine product, String mobileNumber, String event, String payload) throws Exception { if (product == null || StringUtil.isNullOrEmpty(mobileNumber) || StringUtil.isNullOrEmpty(event)) { throw new Exception("Missing required parameter."); } final Map params = new HashMap(); params.put("product", product.toString()); params.put("mobileNumber", mobileNumber); params.put("event", event); if (StringUtil.exists(payload)) { params.put("payload", payload); } executeSync(METRICS_EVENT, params, false); } @Override protected void onDestroy() { } } >>>>>>> 0e01d57538f40e2824a8e9877d1adf37983cd7b7

Solution content
package com.zipwhip.api;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

import com.zipwhip.api.dto.Contact;
import com.zipwhip.api.dto.Conversation;
import com.zipwhip.api.dto.Device;
import com.zipwhip.api.dto.Message;
import com.zipwhip.api.dto.MessageStatus;
import com.zipwhip.api.dto.MessageToken;
import com.zipwhip.api.exception.NotAuthenticatedException;
import com.zipwhip.api.response.BooleanServerResponse;
import com.zipwhip.api.response.ServerResponse;
import com.zipwhip.api.response.StringServerResponse;
import com.zipwhip.api.settings.SettingsStore;
import com.zipwhip.api.signals.Signal;
import com.zipwhip.api.signals.SignalProvider;
import com.zipwhip.api.signals.VersionMapEntry;
import com.zipwhip.concurrent.ObservableFuture;
import com.zipwhip.events.Observer;
import com.zipwhip.signals.presence.Presence;
import com.zipwhip.signals.presence.PresenceCategory;
import com.zipwhip.signals.presence.ProductLine;
import com.zipwhip.util.CollectionUtil;
import com.zipwhip.util.StringUtil;

/**
 * Date: Jul 17, 2009 Time: 7:25:37 PM
 * 

* This provides an Object Oriented way to access the Zipwhip API. It uses a * Connection internally for low-level Zipwhip access. This class does not * manage your authentication, the Connection abstracts this away from * the "Zipwhip" class. */ public class DefaultZipwhipClient extends ClientZipwhipNetworkSupport implements ZipwhipClient { @Override public User getUser() throws Exception { final Map params = new HashMap(); return responseParser.parseUser(executeSync(USER_GET, params)); } /** * Create a new DefaultZipwhipClient. * * @param connection The connection to Zipwhip API * @param signalProvider The connection client for Zipwhip SignalServer. */ public DefaultZipwhipClient(ApiConnection connection, SignalProvider signalProvider) { super(connection, signalProvider); // Start listening to provider events that interest us initSignalProviderEvents(); } private void initSignalProviderEvents() { signalProvider.onNewClientIdReceived(new Observer() { @Override public void notify(Object sender, String clientId) { if (StringUtil.isNullOrEmpty(clientId)) { LOGGER.warn("Received CONNECT without clientId"); return; } if (StringUtil.isNullOrEmpty(connection.getSessionKey())) { settingsStore.put(SettingsStore.Keys.CLIENT_ID, clientId); return; } String managedClientId = settingsStore.get(SettingsStore.Keys.CLIENT_ID); if (StringUtil.exists(managedClientId)) { // clientId changed, unsubscribe the old one, and sub the new one if (!managedClientId.equals(clientId)) { settingsStore.clear(); @Override settingsStore.put(SettingsStore.Keys.CLIENT_ID, clientId); // Do a disconnect then connect Map params = new HashMap(); params.put("clientId", clientId); params.put("sessions", connection.getSessionKey()); Presence presence = signalProvider.getPresence(); if (presence != null) params.put("category", presence.getCategory()); try { executeSync(SIGNALS_DISCONNECT, params); executeSync(SIGNALS_CONNECT, params); } catch (Exception e) { LOGGER.error("Error calling signals/connect", e); } } } else { settingsStore.put(SettingsStore.Keys.CLIENT_ID, clientId); // lets do a signals connect! Map params = new HashMap(); params.put("clientId", clientId); params.put("sessions", connection.getSessionKey()); Presence presence = signalProvider.getPresence(); if (presence != null) params.put("category", presence.getCategory()); try { executeSync(SIGNALS_CONNECT, params); } catch (Exception e) { LOGGER.error("Error calling signals/connect", e); } } } }); signalProvider.onVersionChanged(new Observer() { @Override public void notify(Object sender, VersionMapEntry item) { versionsStore.set(item.getKey(), item.getValue()); } }); } @Override public Future connect() throws Exception { return connect(null); } @Override public Future connect(Presence presence) throws Exception { // we need to determine if we're authenticated enough if (!connection.isConnected() || !connection.isAuthenticated()) { throw new NotAuthenticatedException("The connection cannot operate at this time"); } String managedClientId = settingsStore.get(SettingsStore.Keys.CLIENT_ID); // If the clientId has changed we need to invalidate the settings data if (StringUtil.isNullOrEmpty(managedClientId) || (StringUtil.exists(signalProvider.getClientId()) && !managedClientId.equals(signalProvider.getClientId()))) { LOGGER.debug("ClientId has changed, resetting client id in settings store"); settingsStore.clear(); if (signalProvider!=null && signalProvider.getClientId() != null) { settingsStore.put(SettingsStore.Keys.CLIENT_ID, signalProvider.getClientId()); } } // If the sessionKey has changed we need to invalidate the settings data if (StringUtil.exists(connection.getSessionKey()) && !connection.getSessionKey().equals(settingsStore.get(SettingsStore.Keys.SESSION_KEY))) { LOGGER.debug("New or changed sessionKey, resetting session key in settings store"); settingsStore.clear(); settingsStore.put(SettingsStore.Keys.SESSION_KEY, connection.getSessionKey()); } // Will NOT block until you're connected it's asynchronous return signalProvider.connect(settingsStore.get(SettingsStore.Keys.CLIENT_ID), versionsStore.get(), presence); } public Future disconnect() throws Exception { if (!connection.isConnected()) { throw new Exception("The connection is not connected!"); } return signalProvider.disconnect(); } @Override public List sendMessage(Address address, String body) throws Exception { return sendMessage(Arrays.asList(address.toString()), body, null, null); } @Override public List sendMessage(Address address, String body, String fromName) throws Exception { return sendMessage(Arrays.asList(address.toString()), body, fromName, null); } @Override public List sendMessage(String address, String body) throws Exception { return sendMessage(Arrays.asList(address), body); } @Override public List sendMessage(Message message) throws Exception { return sendMessage(Arrays.asList(message.getAddress()), message.getBody(), message.getFromName(), message.getAdvertisement()); } @Override public List sendMessage(Collection address, String body) throws Exception { return sendMessage(address, body, null, null); } @Override public List sendMessage(Collection address, String body, String fromName) throws Exception { return sendMessage(address, body, fromName, null); } @Override public List sendMessage(Collection addresses, String body, String fromName, String advertisement) throws Exception { final Map params = new HashMap(); params.put("contacts", addresses); params.put("body", body); params.put("fromName", fromName); params.put("fromAddress", "0"); params.put("advertisement", advertisement); return responseParser.parseMessageTokens(executeSync(MESSAGE_SEND, params)); } @Override public List sendMessage(String address, String body, String fromName, String advertisement) throws Exception { return sendMessage(Arrays.asList(address), body, fromName, advertisement); } @Override public List sendMessage(String address, String body, int fromAddress) throws Exception { final Map params = new HashMap(); params.put("contacts", address); params.put("body", body); params.put("fromAddress", fromAddress); return responseParser.parseMessageTokens(executeSync(MESSAGE_SEND, params)); } @Deprecated @Override public Message getMessage(String uuid) throws Exception { final Map params = new HashMap(); params.put("uuid", uuid); return responseParser.parseMessage(executeSync(MESSAGE_GET, params)); } @Override public Message getMessage(Long id) throws Exception { final Map params = new HashMap(); params.put("id", id); return responseParser.parseMessage(executeSync(MESSAGE_GET, params)); } @Override public List listDevices() throws Exception { return responseParser.parseDevices(executeSync(DEVICE_LIST, new HashMap())); } @Override public List listConversations() throws Exception { @Override return responseParser.parseConversations(executeSync(CONVERSATION_LIST, new HashMap())); } @Override public List listConversations(int limit) throws Exception { final Map params = new HashMap(); params.put("limit", Integer.toString(limit)); return responseParser.parseConversations(executeSync(CONVERSATION_LIST, params)); } @Override public List listConversations(int start, int limit) throws Exception { final Map params = new HashMap(); params.put("start", Integer.toString(start)); params.put("limit", Integer.toString(limit)); return responseParser.parseConversations(executeSync(CONVERSATION_LIST, params)); } @Override public List listContacts() throws Exception { return responseParser.parseContacts(executeSync(CONTACT_LIST, new HashMap())); } @Override public boolean readConversation(String fingerprint) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)) { return false; } final Map params = new HashMap(); params.put("fingerprint", fingerprint); return success(executeSync(CONVERSATION_READ, params)); } @Override public boolean deleteConversation(String fingerprint) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)) { return false; } final Map params = new HashMap(); params.put("fingerprint", fingerprint); return success(executeSync(CONVERSATION_DELETE, params)); } @Override public boolean deleteContact(long contactId) throws Exception { if (contactId <= 0){ return false; } final Map params = new HashMap(); params.put("contact", Long.toString(contactId)); return success(executeSync(CONTACT_DELETE, params)); } @Override public List listMessagesByFingerprint(String fingerprint) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)){ throw new Exception("Attempting to call listMessagesByFingerprint with a null or empty fingerprint."); } final Map params = new HashMap(); params.put("fingerprint", fingerprint); return responseParser.parseMessagesFromConversation(executeSync(CONVERSATION_GET, params)); } @Override public List listMessagesByFingerprint(String fingerprint, int limit) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)){ throw new Exception("Attempting to call listMessagesByFingerprint with a null or empty fingerprint."); } else if (limit <= 0) { throw new Exception("Attempting to call listMessagesByFingerprint with a zero or negative limit value."); } final Map params = new HashMap(); params.put("fingerprint", fingerprint); params.put("limit", Integer.toString(limit)); return responseParser.parseMessagesFromConversation(executeSync(CONVERSATION_GET, params)); } @Override public List listMessagesByFingerprint(String fingerprint, int start, int limit) throws Exception { if (StringUtil.isNullOrEmpty(fingerprint)){ throw new Exception("Attempting to call listMessagesByFingerprint with a null or empty fingerprint."); } else if (start < 0){ throw new Exception("Attempting to call listMessagesByFingerprint with a negative start value."); } else if (limit <= 0) { throw new Exception("Attempting to call listMessagesByFingerprint with a zero or negative limit value."); } final Map params = new HashMap(); params.put("fingerprint", fingerprint); params.put("start", Integer.toString(start)); params.put("limit", Integer.toString(limit)); return responseParser.parseMessagesFromConversation(executeSync(CONVERSATION_GET, params)); } @Override public List listMessages() throws Exception { return responseParser.parseMessages(executeSync(MESSAGE_LIST, new HashMap())); } @Override public List listMessages(int limit) throws Exception { final Map params = new HashMap(); params.put("limit", Integer.toString(limit)); return responseParser.parseMessages(executeSync(MESSAGE_LIST, params)); } @Deprecated @Override public boolean messageRead(List uuids) throws Exception { if (CollectionUtil.isNullOrEmpty(uuids)) { return false; } final Map params = new HashMap(); params.put("uuid", uuids); return success(executeSync(MESSAGE_READ, params)); } @Override public boolean readMessage(List ids) throws Exception { if (CollectionUtil.isNullOrEmpty(ids)) { return false; } final Map params = new HashMap(); params.put("message", ids); return success(executeSync(MESSAGE_READ, params)); } @Deprecated @Override public boolean messageDelete(List uuids) throws Exception { if (CollectionUtil.isNullOrEmpty(uuids)) { return false; } final Map params = new HashMap(); params.put("uuids", uuids); return success(executeSync(MESSAGE_DELETE, params)); } @Override public boolean deleteMessage(List ids) throws Exception { if (CollectionUtil.isNullOrEmpty(ids)) { return false; } final Map params = new HashMap(); params.put("message", ids); return success(executeSync(MESSAGE_DELETE, params)); } @Deprecated @Override public MessageStatus getMessageStatus(String uuid) throws Exception { Message message = getMessage(uuid); if (message == null) { return null; } return new MessageStatus(message); } @Override public MessageStatus getMessageStatus(Long id) throws Exception { Message message = getMessage(id); if (message == null) { return null; } return new MessageStatus(message); } public Contact getContact(long id) throws Exception { final Map params = new HashMap(); params.put("id", Long.toString(id)); return responseParser.parseContact(executeSync(CONTACT_GET, params)); } @Override public Contact getContact(String mobileNumber) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); return responseParser.parseContact(executeSync(CONTACT_GET, params)); } @Override public List getPresence(PresenceCategory category) throws Exception { Map params = new HashMap(); if (!category.equals(PresenceCategory.NONE)) { params.put("category", category.toString()); } return responseParser.parsePresence(executeSync(PRESENCE_GET, params)); } @Override public void sendSignal(String scope, String channel, String event, String payload) throws Exception { final Map params = new HashMap(); // is this a device signal or a session signal? params.put("scope", scope); // what happened? was something created? destroyed? changed? params.put("event", event); // what is the data you need sent to the browser params.put("payload", payload); // what URI would you like the browser to fire on? Make sure you have browser code that is subscribing to it. params.put("channel", channel); // send the 3rd party signal. executeSync(SIGNAL_SEND, params); } @Override public void sendSignalsVerification(String clientId) throws Exception { final Map params = new HashMap(); params.put("clientId", clientId); executeSync(SIGNALS_VERIFY, params); } @Override public Contact addMember(String groupAddress, String contactAddress) throws Exception { return addMember(groupAddress, contactAddress, null, null, null, null); } @Override public Contact addMember(String groupAddress, String contactAddress, String firstName, String lastName, String phoneKey, String notes) throws Exception { return stringServerResponse.response; final Map params = new HashMap(); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); params.put("notes", notes); params.put("group", groupAddress); params.put("mobileNumber", new Address(contactAddress).getAuthority()); ServerResponse serverResponse = executeSync(GROUP_ADD_MEMBER, params); return responseParser.parseContact(serverResponse); } @Override public void carbonEnable(boolean enabled, Integer versionCode) throws Exception { final Map params = new HashMap(); params.put("enabled", enabled); if(versionCode != null) { params.put("version", versionCode.toString()); } executeSync(CARBON_ENABLE, params); } @Override @Override public Boolean carbonEnabled(boolean enabled, Integer versionCode) throws Exception { final Map params = new HashMap(); params.put("enabled", enabled); if(versionCode != null) { params.put("version", versionCode.toString()); } ServerResponse response = executeSync(CARBON_ENABLED, params); if (response instanceof BooleanServerResponse) { BooleanServerResponse booleanServerResponse = (BooleanServerResponse) response; return booleanServerResponse.getResponse(); } else { throw new Exception("Unrecognized server response for carbon enabled"); } } @Override public Boolean carbonRegister(String registrationId) throws Exception { final Map params = new HashMap(); if(!StringUtil.isNullOrEmpty(registrationId)) { params.put("registrationId", registrationId); } return success(executeSync(CARBON_REGISTER, params)); } @Override public void carbonStats(int totalPhoneMessages) throws Exception { final Map params = new HashMap(); params.put("messageCount", totalPhoneMessages); executeSync(CARBON_STATS, params); } @Override public boolean acceptedTCs() throws Exception { ServerResponse response = executeSync(CARBON_ACCEPTED_TCS, null); if (response instanceof BooleanServerResponse) { BooleanServerResponse booleanServerResponse = (BooleanServerResponse) response; return booleanServerResponse.getResponse(); } else { throw new Exception("Unrecognized server response for carbon enabled"); } } @Override public String sessionChallenge(String mobileNumber, String portal) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); params.put("portal", portal); ServerResponse response = executeSync(CHALLENGE_REQUEST, params, false); if (response instanceof StringServerResponse) { StringServerResponse stringServerResponse = (StringServerResponse) response; } else { throw new Exception("Unrecognized server response for challenge request"); } } @Override public String sessionChallengeConfirm(String clientId, String securityToken, String portal, String arguments, String userAgent) throws Exception { final Map params = new HashMap(); params.put("clientId", clientId); params.put("securityToken", securityToken); params.put("portal", portal); params.put("arguments", arguments); params.put("userAgent", userAgent); ServerResponse response = executeSync(CHALLENGE_CONFIRM, params, false); if (response instanceof StringServerResponse) { StringServerResponse stringServerResponse = (StringServerResponse) response; return stringServerResponse.response; } else { throw new Exception("Unrecognized server response for challenge confirm"); } } public boolean userUnenroll(String packageName) throws Exception { final Map params = new HashMap(); params.put("package", packageName); return success(executeSync(USER_UNENROLL, params)); } @Override public void addSignalObserver(Observer> observer) { getSignalProvider().onSignalReceived(observer); } @Override public void addSignalsConnectionObserver(Observer observer) { getSignalProvider().onConnectionChanged(observer); } @Override public void saveContact(String address, String firstName, String lastName, String phoneKey) throws Exception { saveContact(address, firstName, lastName, phoneKey, null); } @Override public Contact saveGroup() throws Exception { return saveGroup(null, null); } @Override public Contact saveUser(Contact contact) throws Exception { final Map params = new HashMap(); params.put("email", contact.getEmail()); params.put("firstName", contact.getFirstName()); params.put("lastName", contact.getLastName()); params.put("phoneKey", contact.getPhone()); ServerResponse serverResponse = executeSync(USER_SAVE, params); return responseParser.parseContact(serverResponse); } @Override public void saveUser(String firstName, String lastName, String email, String phoneKey, String location, String notes) throws Exception { final Map params = new HashMap(); params.put("email", email); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); params.put("notes", notes); params.put("loc", location); executeSync(USER_SAVE, params); } @Override public Contact saveGroup(String type, String advertisement) throws Exception { final Map params = new HashMap(); if (type == null) { type = "Group"; } if (!type.startsWith("Group")) { type = "Group"; } params.put("type", type); if (advertisement != null) { params.put("advertisement", advertisement); } return responseParser.parseContact(executeSync(GROUP_SAVE, params)); } @Override public void saveContact(String address, String firstName, String lastName, String phoneKey, String notes) throws Exception { final Map params = new HashMap(); params.put("address", address); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); if (notes != null) { params.put("notes", notes); } // happens async executeSync(CONTACT_SAVE, params); } @Override public void saveContact(String address, String firstName, String lastName, String phoneKey, String notes, String location, String email) throws Exception { final Map params = new HashMap(); params.put("address", address); params.put("firstName", firstName); params.put("lastName", lastName); params.put("phoneKey", phoneKey); if (notes != null) { params.put("notes", notes); } if (location != null){ params.put("loc", location); } if (email != null){ params.put("email", email); } // happens async executeSync(CONTACT_SAVE, params); } @Override public String getFaceName(String mobileNumber) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); return responseParser.parseFaceName(executeSync(FACE_NAME, params, false)); } @Override public byte[] getFaceImage(String mobileNumber, boolean thumbnail) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); params.put("thumbnail", thumbnail); ObservableFuture binaryResponseFuture = executeAsyncBinaryResponse(FACE_IMAGE, params, false); // Block and wait... binaryResponseFuture.awaitUninterruptibly(); return binaryResponseFuture.getResult(); } @Override public byte[] getFaceImage(String mobileNumber, int size) throws Exception { final Map params = new HashMap(); params.put("mobileNumber", mobileNumber); params.put("size", size); params.put("thumbnail", true); ObservableFuture binaryResponseFuture = executeAsyncBinaryResponse(FACE_IMAGE, params, false); // Block and wait... binaryResponseFuture.awaitUninterruptibly(); return binaryResponseFuture.getResult(); } @Override public void recordMetricsEvent(ProductLine product, String mobileNumber, String event, String payload) throws Exception { if (product == null || StringUtil.isNullOrEmpty(mobileNumber) || StringUtil.isNullOrEmpty(event)) { throw new Exception("Missing required parameter."); } final Map params = new HashMap(); params.put("product", product.toString()); params.put("mobileNumber", mobileNumber); params.put("event", event); if (StringUtil.exists(payload)) { params.put("payload", payload); } executeSync(METRICS_EVENT, params, false); } @Override protected void onDestroy() { } }

File
DefaultZipwhipClient.java
Developer's decision
Combination
Kind of conflict
Class declaration
Comment
Import
Package declaration
Chunk
Conflicting content
<<<<<<< HEAD
package com.zipwhip.api;

import com.zipwhip.api.dto.*;
import com.zipwhip.api.settings.SettingsStore;
import com.zipwhip.api.signals.Signal;
import com.zipwhip.api.signals.SignalProvider;
import com.zipwhip.events.Observer;
import com.zipwhip.lifecycle.Destroyable;
import com.zipwhip.signals.presence.Presence;
import com.zipwhip.signals.presence.PresenceCategory;
import com.zipwhip.signals.presence.ProductLine;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

/**
 * Implementations of this class provide a high level way to communicate with the Zipwhip web API.
 * The communication takes place over a {@code ApiConnection} connection.
 *
 * @author Michael
 */
public interface ZipwhipClient extends Destroyable {


    public User getUser() throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param message A {@code Message} object from which to send the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Message message) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address Zipwhip {@link Address} scheme.
     * @param body The body of the message to be sent.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Address address, String body) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address Zipwhip {@link Address} scheme.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Address address, String body, String fromName) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(String address, String body) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Collection address, String body) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Collection address, String body, String fromName) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     *
     * @param fromName The name of the sender of the message.
     * @param advertisement A code indicating to Zipwhip what should be appended to the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Collection address, String body, String fromName, String advertisement) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @param advertisement A code indicating to Zipwhip what should be appended to the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(String address, String body, String fromName, String advertisement) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromAddress The send strategy.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(String address, String body, int fromAddress) throws Exception;

    /**
     * Create a new group.
     *
     * @param type The type of group, eg. reply-all.
     * @param advertisement A code indicating to Zipwhip what should be appended to the message.
     * @return A {@link Contact} representing the new group.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact saveGroup(String type, String advertisement) throws Exception;

    /**
     * Create a new group.
     *
     * @return A {@link Contact} representing the new group.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact saveGroup() throws Exception;

    /**
     * Save or update the user's information.
     *
     * @param contact A {@link Contact} object representing the user to be saved.
     * @return The {@link Contact} object representing the user that has been saved.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact saveUser(Contact contact) throws Exception;

    /**
     * Saves or updates the user information.  For all values for which null is passed in, that value will remain unchanged, relative to
     * the website.
     * to the website.
     * @param firstName
     * @param lastName
     * @param email
     * @param phoneKey
     * @param location
     * @param notes
     */
    public void saveUser(String firstName, String lastName, String email, String phoneKey, String location, String notes) throws Exception;

    /**
     * Returns a Message object
     *
     * @deprecated Use {@code getMessage(Long id)}
     * @param uuid - message uuid
     * @return A Message DTO matching the uuid.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Message getMessage(String uuid) throws Exception;

    /**
     * Returns a Message object
     *
     * @param id - message id
     * @return A Message DTO matching the id.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Message getMessage(Long id) throws Exception;

    /**
     * 
     * @return A list of all {@link Device}s associated with the user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listDevices() throws Exception;

    /**
     * 
     * @return A list of the most recent {@link Conversation}s associated with the user, up to the server's predefined limit.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listConversations() throws Exception;

    /**
     *
     * @param limit The maximum limit of how many conversations to return.
     * @return A list of the most recent {@link Conversation}s associated with the user, up to the specified limit.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listConversations(int limit) throws Exception;

    /**
     * @param start Where to start list conversations.  (Zero indexed)
     * @param limit The maximum limit of how many conversations to return.
     * @return A list of the most recent {@link Conversation}s associated with the user, up to the specified limit.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listConversations(int start, int limit) throws Exception;

    /**
     *
     * @return A list of all {@link Contact}s associated with the supplied user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response, or the server returns a failure message.
     */
    public List listContacts() throws Exception;

    /**
     * 
     * @param fingerprint The fingerprint of the conversation that you wish to mark as read.
     * @return A boolean which represents whether or not the operation completed successfully.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public boolean readConversation(String fingerprint) throws Exception;

    /**
     *
     * @param fingerprint The fingerprint of the conversation that you wish to mark as read.
     * @return A boolean which represents whether or not the operation completed successfully.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public boolean deleteConversation(String fingerprint) throws Exception;

    /**
     * Returns the contact for the provided contact id.
     *
     * @param contactId The id of the contact to be deleted.
     * @return A boolean which represents whether or not the operation completed successfully.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    public boolean deleteContact(long contactId) throws Exception;

    /**
     * Returns the most recent messages for the user, up to a limit maintained by the zipwhip server.
     * @param fingerprint The fingerprint for which you wish to load messages.
     * @return A list consisting of the most recent messages associated with the supplied fingerprint.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessagesByFingerprint(String fingerprint) throws Exception;

    /**
     * Returns the most recent messages for the supplied conversation, up to a the supplied limit.
     * @param fingerprint The fingerprint for which you wish to load messages.
     * @param limit The maximum number of messages that this call will return.
     * @return A list consisting of the most recent messages associated with the supplied fingerprint.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessagesByFingerprint(String fingerprint, int limit) throws Exception;

    /**
     * Returns the most recent messages for the supplied conversation, up to a the supplied limit.
     * @param fingerprint The fingerprint for which you wish to load messages.
     * @param start Where in the list to start. (Zero indexed)
     * @param limit The maximum number of messages that this call will return.
     * @return A list consisting of the most recent messages associated with the supplied fingerprint.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessagesByFingerprint(String fingerprint, int start, int limit) throws Exception;

    /**
     *
     * @return A list consisting of the most recent messages associated with the user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessages() throws Exception;

    /**
     * Returns the most recent messages for the user, up to the supplied limit.
     * @param limit The maximum number of messages that this call will return.
     * @return A list consisting of the most recent messages associated with this user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessages(int limit) throws Exception;

    /**
     * Delete messages by their corresponding UUIDs.
     *
     * @deprecated use {@code readMessage(List id)}
     * @param uuids A list of message uuids to delete.
     * @return True for a successful delete otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean messageRead(List uuids) throws Exception;

    /**
     * Delete messages by their corresponding IDs.
     *
     * @param ids A list of message ids to delete.
     * @return True for a successful delete otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean readMessage(List ids) throws Exception;

    /**
     * Read messages by their corresponding UUIDs.
     *
     * @deprecated use {@code deleteMessage(List ids)}
     * @param uuids A list of message uuids to mark as read.
     * @return True for a successful read otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean messageDelete(List uuids) throws Exception;

    /**
     * Read messages by their corresponding IDs.
     *
     * @param ids A list of message ids to mark as read.
     * @return True for a successful read otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean deleteMessage(List ids) throws Exception;

    /**
     * Returns a MessageStatus object
     *
     * @deprecated use {@code getMessageStatus(Long id)}
     * @param uuid - message uuid
     * @return A MessageStatus DTO matching the uuid.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    MessageStatus getMessageStatus(String uuid) throws Exception;

    /**
     * Returns a MessageStatus object
     *
     * @param id - message id
     * @return A MessageStatus DTO matching the id.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    MessageStatus getMessageStatus(Long id) throws Exception;

    /**
     * Returns the contact for the provided contact id.
     *
     * @param id The id of the contact.
     * @return A Connect DTO matching the id.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    Contact getContact(long id) throws Exception;

    /**
     * Returns the contact for the provided mobile number.
     *
    /**
     * @param mobileNumber The mobile number of the contact to get.
     * @return contact The contact corresponding to the mobile number.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    Contact getContact(String mobileNumber) throws Exception;

    /**
     * Query for the list of presences for your session
     * @param category The category of presence to query for
     * @return List of presences for category and session
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    List getPresence(PresenceCategory category) throws Exception;

    /**
     * Send a signal via Zipwhip SignalServer.
     * Generally this is for debug since the SignalServer protocol is proprietary.
     *
     * @param scope The scope of the signal, ie device.
     * @param channel The channel the signal is on.
     * @param event The event of the signal.
     * @param payload The content of the signal.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void sendSignal(String scope, String channel, String event, String payload) throws Exception;

    /**
     * A debug call to generate a SIGNAL_VERIFICATION command back to the client
     * associated with the {@param clientId}.
     *
     * @param clientId The client ID to send the SIGNAL_VERIFICATION to.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void sendSignalsVerification(String clientId) throws Exception;

    /**
     * Save a new contact for the user or update an existing contact.
     *
     * @param address The address of the contact, generally mobile number.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void saveContact(String address, String firstName, String lastName, String phoneKey) throws Exception;

    /**
     * Save a new contact for the user or update an existing contact.
     *
     * @param address The address of the contact, generally mobile number.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @param notes Free text.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void saveContact(String address, String firstName, String lastName, String phoneKey, String notes) throws Exception;

    /**
     * Save a new contact for the user or update an existing contact.
     *
     * @param address The address of the contact, generally mobile number.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @param notes Free text.
     * @param location Contact's location
     * @param email Contact's e-mail address.                 
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void saveContact(String address, String firstName, String lastName, String phoneKey, String notes, String location, String email) throws Exception;
    
    /**
     * Add a member to an existing group.
     *
     * @param groupAddress The address of the group to add a new member to.
     * @param contactAddress The address, mobile number, of the new contact.
     * @return A {@link Contact} representing the new group member.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact addMember(String groupAddress, String contactAddress) throws Exception;

    /**
     * Add a member to an existing group.
     *
     * @param groupAddress The address of the group to add a new member to.
     * @param contactAddress The address, mobile number, of the new contact.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @param notes Free text.
     * @return A {@link Contact} representing the new group member.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact addMember(String groupAddress, String contactAddress, String firstName, String lastName, String phoneKey, String notes) throws Exception;

    /**
     * Toggles the on/off value of Device Carbon in the cloud. The cloud holds the master value that Device Carbon uses
     * to override any other value it has.
     *
     * @param enabled: turn Device Carbon on/off in the cloud
     * @param versionCode: What version of Device Carbon is being used?
     * @throws Exception if an error occurs communicating with Zipwhip.
     */
    void carbonEnable(boolean enabled, Integer versionCode) throws Exception;

    /**
     * Returns the on/off state Device Carbon should be in according to the cloud.
     *
     * @param enabled: The on/off state Device Carbon is currently in
     * @return What state the cloud thinks device carbon is in
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Boolean carbonEnabled(boolean enabled, Integer versionCode) throws Exception;

    /**
     * Register Device Carbon for Push Notifications from Google
     * @param registrationId - Google provided registrationId to send push notifications too
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Boolean carbonRegister(String registrationId) throws Exception;

    /**
     * Informs Zipwhip of Device Carbon usage statistics
     * @param totalPhoneMessages - total messages sent/receive on the device
     * @throws Exception
     */
    void carbonStats(int totalPhoneMessages) throws Exception;

    boolean acceptedTCs() throws Exception;

    /**
     * Initiates the signup process to:
     * 1) Enroll a new account if one doesn't exist
     * 2) Create necessary subscriptions
     * 3) Eventually return a valid session key for this device
     *
     * @param mobileNumber: mobile number of the account
     * @param portal: product that is retrieving a session
     * @return clientId that is used to finish the challenge process
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    String sessionChallenge(String mobileNumber, String portal) throws Exception;

    /**
     * Finishes the challenge process and returns a session key
     *
     * @param clientId: clientId returned by the original sessionChallenge call
     * @param securityToken: The random string that is sent in an ".signup verify" sms to the phone
     * @param arguments: any extra arguments for the cloud to react to (.signup devicecarbonall)
     * @param userAgent: Device's user agent
     * @return A session key
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    String sessionChallengeConfirm(String clientId, String securityToken, String arguments, String userAgent) throws Exception;

    /**
     *
     * @param packageName
     * @return
     * @throws Exception
     */
    boolean userUnenroll(String packageName) throws Exception;

    /**
     * Query Zipwhip Face Ecosystem for a user's preferred profile name.
     *
     * @param mobileNumber The mobile number of the user you wish to query.
     * @return The user's full name if it exists or empty string.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    String getFaceName(String mobileNumber) throws Exception;

    /**
     * Query Zipwhip Face Ecosystem for a user's preferred profile image.
     *
     * @param mobileNumber The mobile number of the user you wish to query.
     * @param thumbnail true if you want a thumbnail, false for the full image
     * @return A byte[] of the user's image.
     * @throws Exception if an error occurs communicating with Zipwhip or the image is not found.
     */
    byte[] getFaceImage(String mobileNumber, boolean thumbnail) throws Exception;

    /**
     * Query Zipwhip Face Ecosystem for a user's preferred profile image.
     *
     *
     * @param mobileNumber The mobile number of the user you wish to query.
     * @param size the size of thumnail in pixels
     * @return A byte[] of the user's image.
     * @throws Exception if an error occurs communicating with Zipwhip or the image is not found.
     */
    byte[] getFaceImage(String mobileNumber, int size) throws Exception;

    /**
     * The API for reporting metrics events on Zipwhip products.
     *
     * @param product The product type for which we are recording this event.
     * @param mobileNumber Cleaned mobile number for this product.
     * @param event The event which we are recording.
     * @param payload Optional extra text to record with the event.
     * @throws Exception if an error occurs communicating with Zipwhip or if required parameters are missing.
     */
    void recordMetricsEvent(ProductLine product, String mobileNumber, String event, String payload) throws Exception;

    /**
     * Connect to Zipwhip Signals if setup.
     *
     * @param presence a Presence object to pass to the SignalServer
     * @throws Exception any connection problem
     * @return so you can wait until login succeeds
     */
    Future connect(Presence presence) throws Exception;

    /**
     * Connect to Zipwhip Signals if setup.
     *
     * @throws Exception any connection problem
     * @return so you can wait until login succeeds
     */
    Future connect() throws Exception;

    /**
     * Tell the SignalProvider to disconnect from the server.
     *
     * @return an event that tells you its complete
     * @throws Exception if an I/O happens while disconnecting
     */
    Future disconnect() throws Exception;

    /**
     * Listen for signals. This is a convenience method
     *
     * @param observer An observer object to receive callbacks on
     */
    void addSignalObserver(Observer> observer);

    /**
     * Listen for connection changes. This is a convenience method
     *
     * This observer will be called if:
     * We lose our TCP/IP connection to the SignalServer
     *
     * @param observer An observer object to receive callbacks on
     */
    void addSignalsConnectionObserver(Observer observer);

    /**
     * A connection to Zipwhip over a medium.
     *
     * @return the current connection
     */
    ApiConnection getConnection();

    /**
     *
     * @param connection the connection to use
     */
    void setConnection(ApiConnection connection);

    /**
     * Getter for the SignalProvider. SignalProvider manages the connection to the SignalServer
     * and provides events when messages are received or connection state changes.
     *
     * @return An implementation of SignalProvider or null if none has been set.
     */
    SignalProvider getSignalProvider();

    /**
     * Setter for the SignalProvider. SignalProvider manages the connection to the SignalServer
     * and provides events when messages are received or connection state changes.
     *
     * @param provider An implementation of SignalProvider.
     */
    void setSignalProvider(SignalProvider provider);

    /**
     * Get the setting settingsStore
     *
     * @return the setting settingsStore
     */
    SettingsStore getSettingsStore();

    /**
     * Set the setting settingsStore
     *
     * @param store the setting settingsStore
     */
     *
    void setSettingsStore(SettingsStore store);

}
=======
package com.zipwhip.api;

import com.zipwhip.api.dto.*;
import com.zipwhip.api.settings.SettingsStore;
import com.zipwhip.api.signals.Signal;
import com.zipwhip.api.signals.SignalProvider;
import com.zipwhip.events.Observer;
import com.zipwhip.lifecycle.Destroyable;
import com.zipwhip.signals.presence.Presence;
import com.zipwhip.signals.presence.PresenceCategory;
import com.zipwhip.signals.presence.ProductLine;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;

/**
 * Implementations of this class provide a high level way to communicate with the Zipwhip web API.
 * The communication takes place over a {@code ApiConnection} connection.
 *
 * @author Michael
 */
public interface ZipwhipClient extends Destroyable {

    /**
     * Send a message via Zipwhip.
     *
     * @param message A {@code Message} object from which to send the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Message message) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address Zipwhip {@link Address} scheme.
     * @param body The body of the message to be sent.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Address address, String body) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address Zipwhip {@link Address} scheme.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Address address, String body, String fromName) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(String address, String body) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Collection address, String body) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Collection address, String body, String fromName) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @param advertisement A code indicating to Zipwhip what should be appended to the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Collection address, String body, String fromName, String advertisement) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @param advertisement A code indicating to Zipwhip what should be appended to the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(String address, String body, String fromName, String advertisement) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromAddress The send strategy.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(String address, String body, int fromAddress) throws Exception;

    /**
     * Create a new group.
     *
     * @param type The type of group, eg. reply-all.
     * @param advertisement A code indicating to Zipwhip what should be appended to the message.
     * @return A {@link Contact} representing the new group.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact saveGroup(String type, String advertisement) throws Exception;

    /**
     * Create a new group.
     *
     * @return A {@link Contact} representing the new group.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact saveGroup() throws Exception;

    /**
     * Save or update the user's information.
     *
     * @param contact A {@link Contact} object representing the user to be saved.
     * @return The {@link Contact} object representing the user that has been saved.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact saveUser(Contact contact) throws Exception;

    /**
     * Returns a Message object
     *
     * @deprecated Use {@code getMessage(Long id)}
     * @param uuid - message uuid
     * @return A Message DTO matching the uuid.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Message getMessage(String uuid) throws Exception;

    /**
     * Returns a Message object
     *
     * @param id - message id
     * @return A Message DTO matching the id.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Message getMessage(Long id) throws Exception;

    /**
     * 
     * @return A list of all {@link Device}s associated with the user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listDevices() throws Exception;

    /**
     * 
     * @return A list of the most recent {@link Conversation}s associated with the user, up to the server's predefined limit.
     * Delete messages by their corresponding UUIDs.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listConversations() throws Exception;

    /**
     *
     * @param limit The maximum limit of how many conversations to return.
     * @return A list of the most recent {@link Conversation}s associated with the user, up to the specified limit.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listConversations(int limit) throws Exception;

    /**
     * @param start Where to start list conversations.  (Zero indexed)
     * @param limit The maximum limit of how many conversations to return.
     * @return A list of the most recent {@link Conversation}s associated with the user, up to the specified limit.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listConversations(int start, int limit) throws Exception;

    /**
     *
     * @return A list of all {@link Contact}s associated with the supplied user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response, or the server returns a failure message.
     */
    public List listContacts() throws Exception;

    /**
     * 
     * @param fingerprint The fingerprint of the conversation that you wish to mark as read.
     * @return A boolean which represents whether or not the operation completed successfully.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public boolean readConversation(String fingerprint) throws Exception;

    /**
     *
     * @param fingerprint The fingerprint of the conversation that you wish to mark as read.
     * @return A boolean which represents whether or not the operation completed successfully.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public boolean deleteConversation(String fingerprint) throws Exception;

    /**
     * Returns the contact for the provided contact id.
     *
     * @param contactId The id of the contact to be deleted.
     * @return A boolean which represents whether or not the operation completed successfully.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    public boolean deleteContact(long contactId) throws Exception;

    /**
     * Returns the most recent messages for the user, up to a limit maintained by the zipwhip server.
     * @param fingerprint The fingerprint for which you wish to load messages.
     * @return A list consisting of the most recent messages associated with the supplied fingerprint.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessagesByFingerprint(String fingerprint) throws Exception;

    /**
     * Returns the most recent messages for the supplied conversation, up to a the supplied limit.
     * @param fingerprint The fingerprint for which you wish to load messages.
     * @param limit The maximum number of messages that this call will return.
     * @return A list consisting of the most recent messages associated with the supplied fingerprint.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessagesByFingerprint(String fingerprint, int limit) throws Exception;

    /**
     *
     * @return A list consisting of the most recent messages associated with the user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessages() throws Exception;

     * Returns the most recent messages for the user, up to the supplied limit.
     * @param limit The maximum number of messages that this call will return.
     * @return A list consisting of the most recent messages associated with this user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessages(int limit) throws Exception;

    /**
     * @deprecated use {@code readMessage(List id)}
     * @param uuids A list of message uuids to delete.
     * @return True for a successful delete otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean messageRead(List uuids) throws Exception;

    /**
     * Delete messages by their corresponding IDs.
     *
     * @param ids A list of message ids to delete.
     * @return True for a successful delete otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean readMessage(List ids) throws Exception;

    /**
     * Read messages by their corresponding UUIDs.
     *
     * @deprecated use {@code deleteMessage(List ids)}
     * @param uuids A list of message uuids to mark as read.
     * @return True for a successful read otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean messageDelete(List uuids) throws Exception;

    /**
     * Read messages by their corresponding IDs.
     *
     * @param ids A list of message ids to mark as read.
     * @return True for a successful read otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean deleteMessage(List ids) throws Exception;

    /**
     * Returns a MessageStatus object
     *
     * @deprecated use {@code getMessageStatus(Long id)}
     * @param uuid - message uuid
     * @return A MessageStatus DTO matching the uuid.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    MessageStatus getMessageStatus(String uuid) throws Exception;

    /**
     * Returns a MessageStatus object
     *
     * @param id - message id
     * @return A MessageStatus DTO matching the id.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    MessageStatus getMessageStatus(Long id) throws Exception;

    /**
     * Returns the contact for the provided contact id.
     *
     * @param id The id of the contact.
     * @return A Connect DTO matching the id.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    Contact getContact(long id) throws Exception;

    /**
     * Returns the contact for the provided mobile number.
     *
     * @param mobileNumber The mobile number of the contact to get.
     * @return contact The contact corresponding to the mobile number.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    Contact getContact(String mobileNumber) throws Exception;

    /**
     * Query for the list of presences for your session
     *
     * @param category The category of presence to query for
     * @return List of presences for category and session
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    List getPresence(PresenceCategory category) throws Exception;

    /**
     * Send a signal via Zipwhip SignalServer.
     * Generally this is for debug since the SignalServer protocol is proprietary.
     *
     * @param scope The scope of the signal, ie device.
     * @param channel The channel the signal is on.
     * @param event The event of the signal.
     * @param payload The content of the signal.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void sendSignal(String scope, String channel, String event, String payload) throws Exception;

    /**
     * A debug call to generate a SIGNAL_VERIFICATION command back to the client
     * associated with the {@param clientId}.
     * @param clientId The client ID to send the SIGNAL_VERIFICATION to.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void sendSignalsVerification(String clientId) throws Exception;

    /**
     * Save a new contact for the user or update an existing contact.
     *
     * @param address The address of the contact, generally mobile number.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void saveContact(String address, String firstName, String lastName, String phoneKey) throws Exception;

    /**
     * Save a new contact for the user or update an existing contact.
     *
     * @param address The address of the contact, generally mobile number.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @param notes Free text.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void saveContact(String address, String firstName, String lastName, String phoneKey, String notes) throws Exception;

    /**
     * Save a new contact for the user or update an existing contact.
     *
     * @param address The address of the contact, generally mobile number.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @param notes Free text.
     * @param location Contact's location
     * @param email Contact's e-mail address.                 
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void saveContact(String address, String firstName, String lastName, String phoneKey, String notes, String location, String email) throws Exception;
    
    /**
     * Add a member to an existing group.
     *
     * @param groupAddress The address of the group to add a new member to.
     * @param contactAddress The address, mobile number, of the new contact.
     * @return A {@link Contact} representing the new group member.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact addMember(String groupAddress, String contactAddress) throws Exception;

    /**
     * Add a member to an existing group.
     *
     * @param groupAddress The address of the group to add a new member to.
     * @param contactAddress The address, mobile number, of the new contact.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @param notes Free text.
     * @return A {@link Contact} representing the new group member.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact addMember(String groupAddress, String contactAddress, String firstName, String lastName, String phoneKey, String notes) throws Exception;

    /**
     * Toggles the on/off value of Device Carbon in the cloud. The cloud holds the master value that Device Carbon uses
     * to override any other value it has.
     *
     * @param enabled: turn Device Carbon on/off in the cloud
     * @param versionCode: What version of Device Carbon is being used?
     * @throws Exception if an error occurs communicating with Zipwhip.
     */
    void carbonEnable(boolean enabled, Integer versionCode) throws Exception;

    /**
     * Returns the on/off state Device Carbon should be in according to the cloud.
     *
     * @param enabled: The on/off state Device Carbon is currently in
     * @return What state the cloud thinks device carbon is in
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Boolean carbonEnabled(boolean enabled, Integer versionCode) throws Exception;

    /**
     * Register Device Carbon for Push Notifications from Google
     * @param registrationId - Google provided registrationId to send push notifications too
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Boolean carbonRegister(String registrationId) throws Exception;

    /**
     * Informs Zipwhip of Device Carbon usage statistics
     * @param totalPhoneMessages - total messages sent/receive on the device
     * @throws Exception
     */
    void carbonStats(int totalPhoneMessages) throws Exception;

    boolean acceptedTCs() throws Exception;

    /**
     * Initiates the signup process to:
     * 1) Enroll a new account if one doesn't exist
     * 2) Create necessary subscriptions
     * 3) Eventually return a valid session key for this device
     *
     * @param mobileNumber: mobile number of the account
     * @param portal: product that is retrieving a session
     * @return clientId that is used to finish the challenge process
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    String sessionChallenge(String mobileNumber, String portal) throws Exception;

    /**
     * Finishes the challenge process and returns a session key
     *
     * @param clientId: clientId returned by the original sessionChallenge call
     * @param securityToken: The random string that is sent in an ".signup verify" sms to the phone
     * @param portal: product line to customize the user account for
     * @param arguments: any extra arguments for the cloud to react to (previously this was ".signup devicecarbonall")
     * @param userAgent: Device's user agent
     * @return A session key
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    String sessionChallengeConfirm(String clientId, String securityToken, String portal, String arguments, String userAgent) throws Exception;

    /**
     *
     * @param packageName
     * @return
     * @throws Exception
     */
    boolean userUnenroll(String packageName) throws Exception;

    /**
     * Query Zipwhip Face Ecosystem for a user's preferred profile name.
     *
     * @param mobileNumber The mobile number of the user you wish to query.
     * @return The user's full name if it exists or empty string.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    String getFaceName(String mobileNumber) throws Exception;

    /**
     * Query Zipwhip Face Ecosystem for a user's preferred profile image.
     *
     * @param mobileNumber The mobile number of the user you wish to query.
     * @param thumbnail true if you want a thumbnail, false for the full image
     * @return A byte[] of the user's image.
     * @throws Exception if an error occurs communicating with Zipwhip or the image is not found.
     */
    byte[] getFaceImage(String mobileNumber, boolean thumbnail) throws Exception;

    /**
     * Query Zipwhip Face Ecosystem for a user's preferred profile image.
     *
     * @param mobileNumber The mobile number of the user you wish to query.
     * @param size the size of thumnail in pixels
     * @return A byte[] of the user's image.
     * @throws Exception if an error occurs communicating with Zipwhip or the image is not found.
     */
    byte[] getFaceImage(String mobileNumber, int size) throws Exception;

    /**
     * The API for reporting metrics events on Zipwhip products.
     *
     * @param product The product type for which we are recording this event.
     * @param mobileNumber Cleaned mobile number for this product.
     * @param event The event which we are recording.
     * @param payload Optional extra text to record with the event.
     * @throws Exception if an error occurs communicating with Zipwhip or if required parameters are missing.
     */
    void recordMetricsEvent(ProductLine product, String mobileNumber, String event, String payload) throws Exception;

    /**
     * Connect to Zipwhip Signals if setup.
     *
     * @param presence a Presence object to pass to the SignalServer
     * @throws Exception any connection problem
     * @return so you can wait until login succeeds
     */
    Future connect(Presence presence) throws Exception;

    /**
     * Connect to Zipwhip Signals if setup.
     *
     * @throws Exception any connection problem
     * @return so you can wait until login succeeds
     */
    Future connect() throws Exception;

    /**
     * Tell the SignalProvider to disconnect from the server.
     *
     * @return an event that tells you its complete
     * @throws Exception if an I/O happens while disconnecting
     */
    Future disconnect() throws Exception;

    /**
     * Listen for signals. This is a convenience method
     *
     * @param observer An observer object to receive callbacks on
     */
    void addSignalObserver(Observer> observer);

    /**
     * Listen for connection changes. This is a convenience method
     *
     * This observer will be called if:
     * We lose our TCP/IP connection to the SignalServer
     *
     * @param observer An observer object to receive callbacks on
     */
    void addSignalsConnectionObserver(Observer observer);

    /**
     * A connection to Zipwhip over a medium.
     *
     * @return the current connection
     */
    ApiConnection getConnection();

    /**
     *
     * @param connection the connection to use
     */
    void setConnection(ApiConnection connection);

    /**
     * Getter for the SignalProvider. SignalProvider manages the connection to the SignalServer
     * and provides events when messages are received or connection state changes.
     *
     * @return An implementation of SignalProvider or null if none has been set.
     */
    SignalProvider getSignalProvider();

    /**
     * Setter for the SignalProvider. SignalProvider manages the connection to the SignalServer
     * and provides events when messages are received or connection state changes.
     *
     * @param provider An implementation of SignalProvider.
     */
    void setSignalProvider(SignalProvider provider);

    /**
     * Get the setting settingsStore
     *
     * @return the setting settingsStore
     */
    SettingsStore getSettingsStore();

    /**
     * Set the setting settingsStore
     *
     * @param store the setting settingsStore
     */
    void setSettingsStore(SettingsStore store);

}
>>>>>>> 0e01d57538f40e2824a8e9877d1adf37983cd7b7
Solution content
package com.zipwhip.api;

import com.zipwhip.api.dto.*;
import com.zipwhip.api.settings.SettingsStore;
import com.zipwhip.api.signals.Signal;
import com.zipwhip.api.signals.SignalProvider;
import com.zipwhip.events.Observer;
import com.zipwhip.lifecycle.Destroyable;
import com.zipwhip.signals.presence.Presence;
import com.zipwhip.signals.presence.PresenceCategory;
import com.zipwhip.signals.presence.ProductLine;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

/**
 * Implementations of this class provide a high level way to communicate with the Zipwhip web API.
 * The communication takes place over a {@code ApiConnection} connection.
 *
 * @author Michael
 */
public interface ZipwhipClient extends Destroyable {


    public User getUser() throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param message A {@code Message} object from which to send the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Message message) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address Zipwhip {@link Address} scheme.
     * @param body The body of the message to be sent.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Address address, String body) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address Zipwhip {@link Address} scheme.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Address address, String body, String fromName) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(String address, String body) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Collection address, String body) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param uuid - message uuid
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Collection address, String body, String fromName) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @param advertisement A code indicating to Zipwhip what should be appended to the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(Collection address, String body, String fromName, String advertisement) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
    /**
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromName The name of the sender of the message.
     * @param advertisement A code indicating to Zipwhip what should be appended to the message.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(String address, String body, String fromName, String advertisement) throws Exception;

    /**
     * Send a message via Zipwhip.
     *
     * @param address The address, generally the mobile number, of the message recipient.
     * @param body The body of the message to be sent.
     * @param fromAddress The send strategy.
     * @return A {@code List} of {@code MessageToken}s, indicating the status of the message.
     * @throws Exception If an error occurred while sending the message or parsing the response.
     */
    List sendMessage(String address, String body, int fromAddress) throws Exception;

    /**
     * Create a new group.
     *
     * @param type The type of group, eg. reply-all.
     * @param advertisement A code indicating to Zipwhip what should be appended to the message.
     * @return A {@link Contact} representing the new group.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact saveGroup(String type, String advertisement) throws Exception;

    /**
     * Create a new group.
     *
     * @return A {@link Contact} representing the new group.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact saveGroup() throws Exception;

    /**
     * Save or update the user's information.
     *
     * @param contact A {@link Contact} object representing the user to be saved.
     * @return The {@link Contact} object representing the user that has been saved.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact saveUser(Contact contact) throws Exception;

    /**
     * Saves or updates the user information.  For all values for which null is passed in, that value will remain unchanged, relative to
     * the website.
     * to the website.
     * @param firstName
     * @param lastName
     * @param email
     * @param phoneKey
     * @param location
     * @param notes
     */
    public void saveUser(String firstName, String lastName, String email, String phoneKey, String location, String notes) throws Exception;

    /**
     * Returns a Message object
     *
     * @deprecated Use {@code getMessage(Long id)}
     * @return A Message DTO matching the uuid.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Message getMessage(String uuid) throws Exception;

    /**
     * Returns a Message object
     *
     * @param id - message id
     * @return A Message DTO matching the id.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Message getMessage(Long id) throws Exception;

    /**
     * 
     * @return A list of all {@link Device}s associated with the user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listDevices() throws Exception;

    /**
     * 
     * @return A list of the most recent {@link Conversation}s associated with the user, up to the server's predefined limit.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listConversations() throws Exception;

     *
     * @param limit The maximum limit of how many conversations to return.
     * @return A list of the most recent {@link Conversation}s associated with the user, up to the specified limit.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listConversations(int limit) throws Exception;

    /**
     * @param start Where to start list conversations.  (Zero indexed)
     * @param limit The maximum limit of how many conversations to return.
     * @return A list of the most recent {@link Conversation}s associated with the user, up to the specified limit.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listConversations(int start, int limit) throws Exception;

    /**
     *
     * @return A list of all {@link Contact}s associated with the supplied user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response, or the server returns a failure message.
     */
    public List listContacts() throws Exception;

    /**
     * 
     * @param fingerprint The fingerprint of the conversation that you wish to mark as read.
     * @return A boolean which represents whether or not the operation completed successfully.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public boolean readConversation(String fingerprint) throws Exception;

    /**
     *
     * @param fingerprint The fingerprint of the conversation that you wish to mark as read.
     * @return A boolean which represents whether or not the operation completed successfully.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public boolean deleteConversation(String fingerprint) throws Exception;

    /**
     * Returns the contact for the provided contact id.
     *
     * @param contactId The id of the contact to be deleted.
     * @return A boolean which represents whether or not the operation completed successfully.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    public boolean deleteContact(long contactId) throws Exception;

    /**
     * Returns the most recent messages for the user, up to a limit maintained by the zipwhip server.
     * @param fingerprint The fingerprint for which you wish to load messages.
     * @return A list consisting of the most recent messages associated with the supplied fingerprint.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessagesByFingerprint(String fingerprint) throws Exception;

    /**
     * Returns the most recent messages for the supplied conversation, up to a the supplied limit.
     * @param fingerprint The fingerprint for which you wish to load messages.
     * @param limit The maximum number of messages that this call will return.
     * @return A list consisting of the most recent messages associated with the supplied fingerprint.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessagesByFingerprint(String fingerprint, int limit) throws Exception;

    /**
     * Returns the most recent messages for the supplied conversation, up to a the supplied limit.
     * @param fingerprint The fingerprint for which you wish to load messages.
     * @param start Where in the list to start. (Zero indexed)
     * @param limit The maximum number of messages that this call will return.
     * @return A list consisting of the most recent messages associated with the supplied fingerprint.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessagesByFingerprint(String fingerprint, int start, int limit) throws Exception;

    /**
     *
     * @return A list consisting of the most recent messages associated with the user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessages() throws Exception;

    /**
     * @param channel The channel the signal is on.
     * Returns the most recent messages for the user, up to the supplied limit.
     * @param limit The maximum number of messages that this call will return.
     * @return A list consisting of the most recent messages associated with this user.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    public List listMessages(int limit) throws Exception;

    /**
     * Delete messages by their corresponding UUIDs.
     *
     * @deprecated use {@code readMessage(List id)}
     * @param uuids A list of message uuids to delete.
     * @return True for a successful delete otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean messageRead(List uuids) throws Exception;

    /**
     * Delete messages by their corresponding IDs.
     *
     * @param ids A list of message ids to delete.
     * @return True for a successful delete otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean readMessage(List ids) throws Exception;

    /**
     * Read messages by their corresponding UUIDs.
     *
     * @deprecated use {@code deleteMessage(List ids)}
     * @param uuids A list of message uuids to mark as read.
     * @return True for a successful read otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean messageDelete(List uuids) throws Exception;

    /**
     * Read messages by their corresponding IDs.
     *
     * @param ids A list of message ids to mark as read.
     * @return True for a successful read otherwise false.
     * @throws Exception If an error occurred while sending or parsing the response.
     */
    boolean deleteMessage(List ids) throws Exception;

    /**
     * Returns a MessageStatus object
     *
     * @deprecated use {@code getMessageStatus(Long id)}
     * @param uuid - message uuid
     * @return A MessageStatus DTO matching the uuid.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    MessageStatus getMessageStatus(String uuid) throws Exception;

    /**
     * Returns a MessageStatus object
     *
     * @param id - message id
     * @return A MessageStatus DTO matching the id.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    MessageStatus getMessageStatus(Long id) throws Exception;

    /**
     * Returns the contact for the provided contact id.
     *
     * @param id The id of the contact.
     * @return A Connect DTO matching the id.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    Contact getContact(long id) throws Exception;

    /**
     * Returns the contact for the provided mobile number.
     *
     * @param mobileNumber The mobile number of the contact to get.
     * @return contact The contact corresponding to the mobile number.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    Contact getContact(String mobileNumber) throws Exception;

    /**
     * Query for the list of presences for your session
     *
     * @param category The category of presence to query for
     * @return List of presences for category and session
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    List getPresence(PresenceCategory category) throws Exception;

    /**
     * Send a signal via Zipwhip SignalServer.
     * Generally this is for debug since the SignalServer protocol is proprietary.
     *
     * @param scope The scope of the signal, ie device.
     * @param event The event of the signal.
     * @param payload The content of the signal.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void sendSignal(String scope, String channel, String event, String payload) throws Exception;

    /**
     * A debug call to generate a SIGNAL_VERIFICATION command back to the client
     * associated with the {@param clientId}.
     *
     * @param clientId The client ID to send the SIGNAL_VERIFICATION to.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void sendSignalsVerification(String clientId) throws Exception;

    /**
     * Save a new contact for the user or update an existing contact.
     *
     * @param address The address of the contact, generally mobile number.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void saveContact(String address, String firstName, String lastName, String phoneKey) throws Exception;

    /**
     * Save a new contact for the user or update an existing contact.
     *
     * @param address The address of the contact, generally mobile number.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @param notes Free text.
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void saveContact(String address, String firstName, String lastName, String phoneKey, String notes) throws Exception;

    /**
     * Save a new contact for the user or update an existing contact.
     *
     * @param address The address of the contact, generally mobile number.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @param notes Free text.
     * @param location Contact's location
     * @param email Contact's e-mail address.                 
     * @throws Exception if an error occurs communicating with Zipwhip
     */
    void saveContact(String address, String firstName, String lastName, String phoneKey, String notes, String location, String email) throws Exception;
    
    /**
     * Add a member to an existing group.
     *
     * @param groupAddress The address of the group to add a new member to.
     * @param contactAddress The address, mobile number, of the new contact.
     * @return A {@link Contact} representing the new group member.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact addMember(String groupAddress, String contactAddress) throws Exception;

    /**
     * Add a member to an existing group.
     *
     * @param groupAddress The address of the group to add a new member to.
     * @param contactAddress The address, mobile number, of the new contact.
     * @param firstName Contact's first name.
     * @param lastName Contact's last name.
     * @param phoneKey  Contact's phone type.
     * @param notes Free text.
     * @return A {@link Contact} representing the new group member.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Contact addMember(String groupAddress, String contactAddress, String firstName, String lastName, String phoneKey, String notes) throws Exception;

    /**
     * Toggles the on/off value of Device Carbon in the cloud. The cloud holds the master value that Device Carbon uses
     * to override any other value it has.
     *
     * @param enabled: turn Device Carbon on/off in the cloud
     * @param versionCode: What version of Device Carbon is being used?
     * @throws Exception if an error occurs communicating with Zipwhip.
     */
    void carbonEnable(boolean enabled, Integer versionCode) throws Exception;

    /**
     * Returns the on/off state Device Carbon should be in according to the cloud.
     *
     * @param enabled: The on/off state Device Carbon is currently in
     * @return What state the cloud thinks device carbon is in
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Boolean carbonEnabled(boolean enabled, Integer versionCode) throws Exception;

    /**
     * Register Device Carbon for Push Notifications from Google
     * @param registrationId - Google provided registrationId to send push notifications too
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    Boolean carbonRegister(String registrationId) throws Exception;

    /**
     * Informs Zipwhip of Device Carbon usage statistics
     * @param totalPhoneMessages - total messages sent/receive on the device
     * @throws Exception
     */
    void carbonStats(int totalPhoneMessages) throws Exception;

    boolean acceptedTCs() throws Exception;

    /**
     * Initiates the signup process to:
     * 1) Enroll a new account if one doesn't exist
     * 2) Create necessary subscriptions
     * 3) Eventually return a valid session key for this device
     *
     * @param mobileNumber: mobile number of the account
     * @param portal: product that is retrieving a session
     * @return clientId that is used to finish the challenge process
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    String sessionChallenge(String mobileNumber, String portal) throws Exception;

    /**
     * Finishes the challenge process and returns a session key
     *
     * @param clientId: clientId returned by the original sessionChallenge call
     * @param securityToken: The random string that is sent in an ".signup verify" sms to the phone
     * @param portal: product line to customize the user account for
     * @param arguments: any extra arguments for the cloud to react to (previously this was ".signup devicecarbonall")
     * @param userAgent: Device's user agent
     * @return A session key
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    String sessionChallengeConfirm(String clientId, String securityToken, String portal, String arguments, String userAgent) throws Exception;

    /**
     *
     * @param packageName
     * @return
     * @throws Exception
     */
    boolean userUnenroll(String packageName) throws Exception;

    /**
     * Query Zipwhip Face Ecosystem for a user's preferred profile name.
     *
     * @param mobileNumber The mobile number of the user you wish to query.
     * @return The user's full name if it exists or empty string.
     * @throws Exception if an error occurs communicating with Zipwhip or parsing the response.
     */
    String getFaceName(String mobileNumber) throws Exception;

    /**
     * Query Zipwhip Face Ecosystem for a user's preferred profile image.
     *
     * @param mobileNumber The mobile number of the user you wish to query.
     * @param thumbnail true if you want a thumbnail, false for the full image
     * @return A byte[] of the user's image.
     * @throws Exception if an error occurs communicating with Zipwhip or the image is not found.
     */
    byte[] getFaceImage(String mobileNumber, boolean thumbnail) throws Exception;

    /**
     * Query Zipwhip Face Ecosystem for a user's preferred profile image.
     *
     * @param mobileNumber The mobile number of the user you wish to query.
     * @param size the size of thumnail in pixels
     * @return A byte[] of the user's image.
     * @throws Exception if an error occurs communicating with Zipwhip or the image is not found.
     */
    byte[] getFaceImage(String mobileNumber, int size) throws Exception;

    /**
     * The API for reporting metrics events on Zipwhip products.
     *
     * @param product The product type for which we are recording this event.
     * @param mobileNumber Cleaned mobile number for this product.
     * @param event The event which we are recording.
     * @param payload Optional extra text to record with the event.
     * @throws Exception if an error occurs communicating with Zipwhip or if required parameters are missing.
     */
    void recordMetricsEvent(ProductLine product, String mobileNumber, String event, String payload) throws Exception;

    /**
     * Connect to Zipwhip Signals if setup.
     *
     * @param presence a Presence object to pass to the SignalServer
     * @throws Exception any connection problem
     * @return so you can wait until login succeeds
     */
    Future connect(Presence presence) throws Exception;

    /**
     * Connect to Zipwhip Signals if setup.
     *
     * @throws Exception any connection problem
     * @return so you can wait until login succeeds
     */
    Future connect() throws Exception;

    /**
     * Tell the SignalProvider to disconnect from the server.
     *
     * @return an event that tells you its complete
     * @throws Exception if an I/O happens while disconnecting
     */
    Future disconnect() throws Exception;

    /**
     * Listen for signals. This is a convenience method
     *
     * @param observer An observer object to receive callbacks on
     */
    void addSignalObserver(Observer> observer);

    /**
     * Listen for connection changes. This is a convenience method
     *
     * This observer will be called if:
     * We lose our TCP/IP connection to the SignalServer
     *
     * @param observer An observer object to receive callbacks on
     */
    void addSignalsConnectionObserver(Observer observer);

    /**
     * A connection to Zipwhip over a medium.
     *
     * @return the current connection
     */
    ApiConnection getConnection();

    /**
     *
     * @param connection the connection to use
     */
    void setConnection(ApiConnection connection);

    /**
     * Getter for the SignalProvider. SignalProvider manages the connection to the SignalServer
     * and provides events when messages are received or connection state changes.
     *
     * @return An implementation of SignalProvider or null if none has been set.
     */
    SignalProvider getSignalProvider();

    /**
     * Setter for the SignalProvider. SignalProvider manages the connection to the SignalServer
     * and provides events when messages are received or connection state changes.
     *
     * @param provider An implementation of SignalProvider.
     */
    void setSignalProvider(SignalProvider provider);

    /**
     * Get the setting settingsStore
     *
     * @return the setting settingsStore
     */
    SettingsStore getSettingsStore();

    /**
     * Set the setting settingsStore
     *
     * @param store the setting settingsStore
     */
    void setSettingsStore(SettingsStore store);

}
File
ZipwhipClient.java
Developer's decision
Combination
Kind of conflict
Comment
Import
Interface declaration
Package declaration