/* * Copyright (c) 2013-2017 Cinchapi Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cinchapi.concourse; import java.nio.ByteBuffer; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import java.util.concurrent.Callable; import javax.annotation.Nullable; import org.apache.thrift.TException; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; import com.cinchapi.concourse.config.ConcourseClientPreferences; import com.cinchapi.concourse.lang.BuildableState; import com.cinchapi.concourse.lang.Criteria; import com.cinchapi.concourse.lang.Language; import com.cinchapi.concourse.security.ClientSecurity; import com.cinchapi.concourse.thrift.AccessToken; import com.cinchapi.concourse.thrift.ComplexTObject; import com.cinchapi.concourse.thrift.ConcourseService; import com.cinchapi.concourse.thrift.Diff; import com.cinchapi.concourse.thrift.Operator; import com.cinchapi.concourse.thrift.SecurityException; import com.cinchapi.concourse.thrift.TObject; import com.cinchapi.concourse.thrift.TransactionToken; import com.cinchapi.concourse.util.ByteBuffers; import com.cinchapi.concourse.util.Collections; import com.cinchapi.concourse.util.Conversions; import com.cinchapi.concourse.util.Convert; import com.cinchapi.concourse.util.PrettyLinkedHashMap; import com.cinchapi.concourse.util.PrettyLinkedTableMap; import com.cinchapi.concourse.util.Transformers; import com.google.common.base.Throwables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; /** * An implementation of the {@link Concourse} interface that interacts with the * server via Thrift's RPC protocols. * * @author Jeff Nelson */ class ConcourseThriftDriver extends Concourse { private static String ENVIRONMENT; private static String PASSWORD; private static String SERVER_HOST; private static int SERVER_PORT; private static String USERNAME; static { // If there is a concourse_client.prefs file located in the working // directory, parse it and use its values as defaults. ConcourseClientPreferences config; try { config = ConcourseClientPreferences.open("concourse_client.prefs"); } catch (Exception e) { config = null; } SERVER_HOST = "localhost"; SERVER_PORT = 1717; USERNAME = "admin"; PASSWORD = "admin"; ENVIRONMENT = ""; if(config != null) { SERVER_HOST = config.getString("host", SERVER_HOST); SERVER_PORT = config.getInt("port", SERVER_PORT); USERNAME = config.getString("username", USERNAME); PASSWORD = config.getString("password", PASSWORD); ENVIRONMENT = config.getString("environment", ENVIRONMENT); } } /** * The Thrift client that actually handles all RPC communication. */ private final ConcourseService.Client client; /** * The client keeps a copy of its {@link AccessToken} and passes it to * the server for each remote procedure call. The client will * re-authenticate when necessary using the username/password read from * the prefs file. */ private AccessToken creds = null; /** * The environment to which the client is connected. */ private final String environment; /** * The host of the connection. */ private final String host; /** * An encrypted copy of the password passed to the constructor. */ private final ByteBuffer password; /** * The port of the connection. */ private final int port; /** * Whenever the client starts a Transaction, it keeps a * {@link TransactionToken} so that the server can stage the changes in * the appropriate place. */ private TransactionToken transaction = null; /** * An encrypted copy of the username passed to the constructor. */ private final ByteBuffer username; /** * Create a new Client connection to the environment of the Concourse * Server described in {@code concourse_client.prefs} (or the default * environment and server if the prefs file does not exist) and return a * handler to facilitate database interaction. */ public ConcourseThriftDriver() { this(ENVIRONMENT); } /** * Create a new Client connection to the specified {@code environment} * of the Concourse Server described in {@code concourse_client.prefs} * (or the default server if the prefs file does not exist) and return a * handler to facilitate database interaction. * * @param environment */ public ConcourseThriftDriver(String environment) { this(SERVER_HOST, SERVER_PORT, USERNAME, PASSWORD, environment); } /** * Create a new Client connection to the default environment of the * specified Concourse Server and return a handler to facilitate * database interaction. * * @param host * @param port * @param username * @param password */ public ConcourseThriftDriver(String host, int port, String username, String password) { this(host, port, username, password, ""); } /** * Create a new Client connection to the specified {@code environment} * of the specified Concourse Server and return a handler to facilitate * database interaction. * * @param host * @param port * @param username * @param password * @param environment */ public ConcourseThriftDriver(String host, int port, String username, String password, String environment) { this.host = host; this.port = port; this.username = ClientSecurity.encrypt(username); this.password = ClientSecurity.encrypt(password); this.environment = environment; final TTransport transport = new TSocket(host, port); try { transport.open(); TProtocol protocol = new TBinaryProtocol(transport); client = new ConcourseService.Client(protocol); authenticate(); Runtime.getRuntime().addShutdownHook(new Thread("shutdown") { @Override public void run() { if(transaction != null && transport.isOpen()) { abort(); transport.close(); } } }); } catch (TTransportException e) { throw new RuntimeException( "Could not connect to the Concourse Server at " + host + ":" + port); } } @Override public void abort() { execute(() -> { if(transaction != null) { final TransactionToken token = transaction; transaction = null; client.abort(creds, token, environment); } return null; }); } @Override public <T> long add(String key, T value) { return execute(() -> { return client.addKeyValue(key, Convert.javaToThrift(value), creds, transaction, environment); }); } @Override public <T> Map<Long, Boolean> add(String key, T value, Collection<Long> records) { return execute(() -> { Map<Long, Boolean> raw = client.addKeyValueRecords(key, Convert.javaToThrift(value), Collections.toLongList(records), creds, transaction, environment); Map<Long, Boolean> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", "Successful"); for (long record : records) { pretty.put(record, raw.get(record)); } return pretty; }); } @Override public <T> boolean add(String key, T value, long record) { return execute(() -> { return client.addKeyValueRecord(key, Convert.javaToThrift(value), record, creds, transaction, environment); }); } @Override public Map<Timestamp, String> audit(long record) { return execute(() -> { Map<Long, String> audit = client.auditRecord(record, creds, transaction, environment); return ((PrettyLinkedHashMap<Timestamp, String>) Transformers .transformMap(audit, Conversions.timestampToMicros())) .setKeyName("DateTime").setValueName("Revision"); }); } @Override public Map<Timestamp, String> audit(long record, Timestamp start) { return execute(() -> { Map<Long, String> audit; if(start.isString()) { audit = client.auditRecordStartstr(record, start.toString(), creds, transaction, environment); } else { audit = client.auditRecordStart(record, start.getMicros(), creds, transaction, environment); } return ((PrettyLinkedHashMap<Timestamp, String>) Transformers .transformMap(audit, Conversions.timestampToMicros())) .setKeyName("DateTime").setValueName("Revision"); }); } @Override public Map<Timestamp, String> audit(long record, Timestamp start, Timestamp end) { return execute(() -> { Map<Long, String> audit; if(start.isString()) { audit = client.auditRecordStartstrEndstr(record, start.toString(), end.toString(), creds, transaction, environment); } else { audit = client.auditRecordStartEnd(record, start.getMicros(), end.getMicros(), creds, transaction, environment); } return ((PrettyLinkedHashMap<Timestamp, String>) Transformers .transformMap(audit, Conversions.timestampToMicros())) .setKeyName("DateTime").setValueName("Revision"); }); } @Override public Map<Timestamp, String> audit(String key, long record) { return execute(() -> { Map<Long, String> audit = client.auditKeyRecord(key, record, creds, transaction, environment); return ((PrettyLinkedHashMap<Timestamp, String>) Transformers .transformMap(audit, Conversions.timestampToMicros())) .setKeyName("DateTime").setValueName("Revision"); }); } @Override public Map<Timestamp, String> audit(String key, long record, Timestamp start) { return execute(() -> { Map<Long, String> audit; if(start.isString()) { audit = client.auditKeyRecordStartstr(key, record, start.toString(), creds, transaction, environment); } else { audit = client.auditKeyRecordStart(key, record, start.getMicros(), creds, transaction, environment); } return ((PrettyLinkedHashMap<Timestamp, String>) Transformers .transformMap(audit, Conversions.timestampToMicros())) .setKeyName("DateTime").setValueName("Revision"); }); } @Override public Map<Timestamp, String> audit(String key, long record, Timestamp start, Timestamp end) { return execute(() -> { Map<Long, String> audit; if(start.isString()) { audit = client.auditKeyRecordStartstrEndstr(key, record, start.toString(), end.toString(), creds, transaction, environment); } else { audit = client.auditKeyRecordStartEnd(key, record, start.getMicros(), end.getMicros(), creds, transaction, environment); } return ((PrettyLinkedHashMap<Timestamp, String>) Transformers .transformMap(audit, Conversions.timestampToMicros())) .setKeyName("DateTime").setValueName("Revision"); }); } @Override public Map<String, Map<Object, Set<Long>>> browse(Collection<String> keys) { return execute(() -> { Map<String, Map<TObject, Set<Long>>> raw = client.browseKeys( Collections.toList(keys), creds, transaction, environment); Map<String, Map<Object, Set<Long>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Key"); for (Entry<String, Map<TObject, Set<Long>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.thriftToJava(), Conversions.<Long> none())); } return pretty; }); } @Override public Map<String, Map<Object, Set<Long>>> browse(Collection<String> keys, Timestamp timestamp) { return execute(() -> { Map<String, Map<TObject, Set<Long>>> raw; if(timestamp.isString()) { raw = client.browseKeysTimestr(Collections.toList(keys), timestamp.toString(), creds, transaction, environment); } else { raw = client.browseKeysTime(Collections.toList(keys), timestamp.getMicros(), creds, transaction, environment); } Map<String, Map<Object, Set<Long>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Key"); for (Entry<String, Map<TObject, Set<Long>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.thriftToJava(), Conversions.<Long> none())); } return pretty; }); } @Override public Map<Object, Set<Long>> browse(String key) { return execute(() -> { Map<TObject, Set<Long>> raw = client.browseKey(key, creds, transaction, environment); Map<Object, Set<Long>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap(key, "Records"); for (Entry<TObject, Set<Long>> entry : raw.entrySet()) { pretty.put(Convert.thriftToJava(entry.getKey()), entry.getValue()); } return pretty; }); } @Override public Map<Object, Set<Long>> browse(String key, Timestamp timestamp) { return execute(() -> { Map<TObject, Set<Long>> raw; if(timestamp.isString()) { raw = client.browseKeyTimestr(key, timestamp.toString(), creds, transaction, environment); } else { raw = client.browseKeyTime(key, timestamp.getMicros(), creds, transaction, environment); } Map<Object, Set<Long>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap(key, "Records"); for (Entry<TObject, Set<Long>> entry : raw.entrySet()) { pretty.put(Convert.thriftToJava(entry.getKey()), entry.getValue()); } return pretty; }); } @Override public Map<Timestamp, Set<Object>> chronologize(String key, long record) { return execute(() -> { Map<Long, Set<TObject>> raw = client.chronologizeKeyRecord(key, record, creds, transaction, environment); Map<Timestamp, Set<Object>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("DateTime", "Values"); for (Entry<Long, Set<TObject>> entry : raw.entrySet()) { pretty.put(Timestamp.fromMicros(entry.getKey()), Transformers.transformSetLazily(entry.getValue(), Conversions.thriftToJava())); } return pretty; }); } @Override public Map<Timestamp, Set<Object>> chronologize(String key, long record, Timestamp start) { return execute(() -> { Map<Long, Set<TObject>> raw; if(start.isString()) { raw = client.chronologizeKeyRecordStartstr(key, record, start.toString(), creds, transaction, environment); } else { raw = client.chronologizeKeyRecordStart(key, record, start.getMicros(), creds, transaction, environment); } Map<Timestamp, Set<Object>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("DateTime", "Values"); for (Entry<Long, Set<TObject>> entry : raw.entrySet()) { pretty.put(Timestamp.fromMicros(entry.getKey()), Transformers.transformSetLazily(entry.getValue(), Conversions.thriftToJava())); } return pretty; }); } @Override public Map<Timestamp, Set<Object>> chronologize(String key, long record, Timestamp start, Timestamp end) { return execute(() -> { Map<Long, Set<TObject>> raw; if(start.isString()) { raw = client.chronologizeKeyRecordStartstrEndstr(key, record, start.toString(), end.toString(), creds, transaction, environment); } else { raw = client.chronologizeKeyRecordStartEnd(key, record, start.getMicros(), end.getMicros(), creds, transaction, environment); } Map<Timestamp, Set<Object>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("DateTime", "Values"); for (Entry<Long, Set<TObject>> entry : raw.entrySet()) { pretty.put(Timestamp.fromMicros(entry.getKey()), Transformers.transformSetLazily(entry.getValue(), Conversions.thriftToJava())); } return pretty; }); } @Override public void clear(Collection<Long> records) { execute(() -> { client.clearRecords(Collections.toLongList(records), creds, transaction, environment); return null; }); } @Override public void clear(Collection<String> keys, Collection<Long> records) { execute(() -> { client.clearKeysRecords(Collections.toList(keys), Collections.toLongList(records), creds, transaction, environment); return null; }); } @Override public void clear(Collection<String> keys, long record) { execute(() -> { client.clearKeysRecord(Collections.toList(keys), record, creds, transaction, environment); return null; }); } @Override public void clear(long record) { execute(() -> { client.clearRecord(record, creds, transaction, environment); return null; }); } @Override public void clear(String key, Collection<Long> records) { execute(() -> { client.clearKeyRecords(key, Collections.toLongList(records), creds, transaction, environment); return null; }); } @Override public void clear(String key, long record) { execute(() -> { client.clearKeyRecord(key, record, creds, transaction, environment); return null; }); } @Override public boolean commit() { return execute(() -> { final TransactionToken token = transaction; transaction = null; return token != null ? client.commit(creds, token, environment) : false; }); } @Override public Map<Long, Set<String>> describe(Collection<Long> records) { return execute(() -> { Map<Long, Set<String>> raw = client.describeRecords( Collections.toLongList(records), creds, transaction, environment); Map<Long, Set<String>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", "Keys"); for (Entry<Long, Set<String>> entry : raw.entrySet()) { pretty.put(entry.getKey(), entry.getValue()); } return pretty; }); } @Override public Map<Long, Set<String>> describe(Collection<Long> records, Timestamp timestamp) { return execute(() -> { Map<Long, Set<String>> raw; if(timestamp.isString()) { raw = client.describeRecordsTimestr( Collections.toLongList(records), timestamp.toString(), creds, transaction, environment); } else { raw = client.describeRecordsTime( Collections.toLongList(records), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Set<String>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", "Keys"); for (Entry<Long, Set<String>> entry : raw.entrySet()) { pretty.put(entry.getKey(), entry.getValue()); } return pretty; }); } @Override public Set<String> describe(long record) { return execute(() -> { Set<String> result = client.describeRecord(record, creds, transaction, environment); return result; }); } @Override public Set<String> describe(long record, Timestamp timestamp) { return execute(() -> { if(timestamp.isString()) { return client.describeRecordTimestr(record, timestamp.toString(), creds, transaction, environment); } else { return client.describeRecordTime(record, timestamp.getMicros(), creds, transaction, environment); } }); } @Override public <T> Map<String, Map<Diff, Set<T>>> diff(long record, Timestamp start) { return execute(() -> { Map<String, Map<Diff, Set<TObject>>> raw; if(start.isString()) { raw = client.diffRecordStartstr(record, start.toString(), creds, transaction, environment); } else { raw = client.diffRecordStart(record, start.getMicros(), creds, transaction, environment); } PrettyLinkedTableMap<String, Diff, Set<T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap(); pretty.setRowName("Key"); for (Entry<String, Map<Diff, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<Diff> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<String, Map<Diff, Set<T>>> diff(long record, Timestamp start, Timestamp end) { return execute(() -> { Map<String, Map<Diff, Set<TObject>>> raw; if(start.isString()) { raw = client.diffRecordStartstrEndstr(record, start.toString(), end.toString(), creds, transaction, environment); } else { raw = client.diffRecordStartEnd(record, start.getMicros(), end.getMicros(), creds, transaction, environment); } PrettyLinkedTableMap<String, Diff, Set<T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap(); pretty.setRowName("Key"); for (Entry<String, Map<Diff, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<Diff> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Diff, Set<T>> diff(String key, long record, Timestamp start) { return execute(() -> { Map<Diff, Set<TObject>> raw; if(start.isString()) { raw = client.diffKeyRecordStartstr(key, record, start.toString(), creds, transaction, environment); } else { raw = client.diffKeyRecordStart(key, record, start.getMicros(), creds, transaction, environment); } Map<Diff, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Operation", "Value"); for (Entry<Diff, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Diff, Set<T>> diff(String key, long record, Timestamp start, Timestamp end) { return execute(() -> { Map<Diff, Set<TObject>> raw; if(start.isString()) { raw = client.diffKeyRecordStartstrEndstr(key, record, start.toString(), end.toString(), creds, transaction, environment); } else { raw = client.diffKeyRecordStartEnd(key, record, start.getMicros(), end.getMicros(), creds, transaction, environment); } Map<Diff, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Operation", "Value"); for (Entry<Diff, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> Map<T, Map<Diff, Set<Long>>> diff(String key, Timestamp start) { return execute(() -> { Map<TObject, Map<Diff, Set<Long>>> raw; if(start.isString()) { raw = client.diffKeyStartstr(key, start.toString(), creds, transaction, environment); } else { raw = client.diffKeyStart(key, start.getMicros(), creds, transaction, environment); } PrettyLinkedTableMap<T, Diff, Set<Long>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap(); pretty.setRowName("Value"); for (Entry<TObject, Map<Diff, Set<Long>>> entry : raw.entrySet()) { pretty.put((T) Convert.thriftToJava(entry.getKey()), entry.getValue()); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> Map<T, Map<Diff, Set<Long>>> diff(String key, Timestamp start, Timestamp end) { return execute(() -> { Map<TObject, Map<Diff, Set<Long>>> raw; if(start.isString()) { raw = client.diffKeyStartstrEndstr(key, start.toString(), end.toString(), creds, transaction, environment); } else { raw = client.diffKeyStartEnd(key, start.getMicros(), end.getMicros(), creds, transaction, environment); } PrettyLinkedTableMap<T, Diff, Set<Long>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap(); pretty.setRowName("Value"); for (Entry<TObject, Map<Diff, Set<Long>>> entry : raw.entrySet()) { pretty.put((T) Convert.thriftToJava(entry.getKey()), entry.getValue()); } return pretty; }); } @Override public void exit() { try { client.logout(creds, environment); client.getInputProtocol().getTransport().close(); client.getOutputProtocol().getTransport().close(); } catch (com.cinchapi.concourse.thrift.SecurityException | TTransportException e) { // Handle corner case where the client is existing because of // (or after the occurrence of) a password change, which means // it can't perform a traditional logout. Its worth nothing that // we're okay with this scenario because a password change will // delete all previously issued tokens. } catch (Exception e) { throw Throwables.propagate(e); } } @Override public Set<Long> find(Criteria criteria) { return execute(() -> { return client.findCriteria( Language.translateToThriftCriteria(criteria), creds, transaction, environment); }); } @Override public Set<Long> find(Object criteria) { if(criteria instanceof BuildableState) { return find(((BuildableState) criteria).build()); } else { throw new IllegalArgumentException( criteria + " is not a valid argument for the find method"); } } @Override public Set<Long> find(String ccl) { return execute(() -> { return client.findCcl(ccl, creds, transaction, environment); }); } @Override public Set<Long> find(String key, Object value) { return executeFind(key, Operator.EQUALS, value); } @Override public Set<Long> find(String key, Object value, Timestamp timestamp) { return executeFind(key, Operator.EQUALS, value, timestamp); } @Override public Set<Long> find(String key, Operator operator, Object value) { return executeFind(key, operator, value); } @Override public Set<Long> find(String key, Operator operator, Object value, Object value2) { return executeFind(key, operator, value, value2); } @Override public Set<Long> find(String key, Operator operator, Object value, Object value2, Timestamp timestamp) { return executeFind(timestamp, key, operator, value, value2); } @Override public Set<Long> find(String key, Operator operator, Object value, Timestamp timestamp) { return executeFind(timestamp, key, operator, value); } @Override public Set<Long> find(String key, String operator, Object value) { return executeFind(key, operator, value); } @Override public Set<Long> find(String key, String operator, Object value, Object value2) { return executeFind(key, operator, value, value2); } @Override public Set<Long> find(String key, String operator, Object value, Object value2, Timestamp timestamp) { return executeFind(timestamp, key, operator, value, value2); } @Override public Set<Long> find(String key, String operator, Object value, Timestamp timestamp) { return executeFind(timestamp, key, operator, value); } @Override public <T> long findOrAdd(String key, T value) throws DuplicateEntryException { return execute(() -> { return client.findOrAddKeyValue(key, Convert.javaToThrift(value), creds, transaction, environment); }); } @Override public long findOrInsert(Criteria criteria, String json) throws DuplicateEntryException { return execute(() -> { return client.findOrInsertCriteriaJson( Language.translateToThriftCriteria(criteria), json, creds, transaction, environment); }); } @Override public long findOrInsert(String ccl, String json) throws DuplicateEntryException { return execute(() -> { return client.findOrInsertCclJson(ccl, json, creds, transaction, environment); }); } @Override public <T> Map<Long, Map<String, T>> get(Collection<String> keys, Collection<Long> records) { return execute(() -> { Map<Long, Map<String, TObject>> raw = client.getKeysRecords( Collections.toList(keys), Collections.toLongList(records), creds, transaction, environment); Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, T>> get(Collection<String> keys, Collection<Long> records, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, TObject>> raw; if(timestamp.isString()) { raw = client.getKeysRecordsTimestr(Collections.toList(keys), Collections.toLongList(records), timestamp.toString(), creds, transaction, environment); } else { raw = client.getKeysRecordsTime(Collections.toList(keys), Collections.toLongList(records), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, T>> get(Collection<String> keys, Criteria criteria) { return execute(() -> { Map<Long, Map<String, TObject>> raw = client.getKeysCriteria( Collections.toList(keys), Language.translateToThriftCriteria(criteria), creds, transaction, environment); Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, T>> get(Collection<String> keys, Criteria criteria, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, TObject>> raw; if(timestamp.isString()) { raw = client.getKeysCriteriaTimestr(Collections.toList(keys), Language.translateToThriftCriteria(criteria), timestamp.toString(), creds, transaction, environment); } else { raw = client.getKeysCriteriaTime(Collections.toList(keys), Language.translateToThriftCriteria(criteria), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> Map<String, T> get(Collection<String> keys, long record) { return execute(() -> { Map<String, TObject> raw = client.getKeysRecord( Collections.toList(keys), record, creds, transaction, environment); Map<String, T> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Key", "Value"); for (Entry<String, TObject> entry : raw.entrySet()) { pretty.put(entry.getKey(), (T) Convert.thriftToJava(entry.getValue())); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> Map<String, T> get(Collection<String> keys, long record, Timestamp timestamp) { return execute(() -> { Map<String, TObject> raw; if(timestamp.isString()) { raw = client.getKeysRecordTimestr(Collections.toList(keys), record, timestamp.toString(), creds, transaction, environment); } else { raw = client.getKeysRecordTime(Collections.toList(keys), record, timestamp.getMicros(), creds, transaction, environment); } Map<String, T> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Key", "Value"); for (Entry<String, TObject> entry : raw.entrySet()) { pretty.put(entry.getKey(), (T) Convert.thriftToJava(entry.getValue())); } return pretty; }); } @Override public <T> Map<Long, Map<String, T>> get(Collection<String> keys, Object criteria) { if(criteria instanceof BuildableState) { return get(keys, ((BuildableState) criteria).build()); } else { throw new IllegalArgumentException( criteria + " is not a valid argument for the get method"); } } @Override public <T> Map<Long, Map<String, T>> get(Collection<String> keys, Object criteria, Timestamp timestamp) { if(criteria instanceof BuildableState) { return get(keys, ((BuildableState) criteria).build(), timestamp); } else { throw new IllegalArgumentException( criteria + " is not a valid argument for the get method"); } } @Override public <T> Map<Long, Map<String, T>> get(Collection<String> keys, String ccl) { return execute(() -> { Map<Long, Map<String, TObject>> raw = client.getKeysCcl( Collections.toList(keys), ccl, creds, transaction, environment); Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, T>> get(Collection<String> keys, String ccl, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, TObject>> raw; if(timestamp.isString()) { raw = client.getKeysCclTimestr(Collections.toList(keys), ccl, timestamp.toString(), creds, transaction, environment); } else { raw = client.getKeysCclTime(Collections.toList(keys), ccl, timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, T>> get(Criteria criteria) { return execute(() -> { Map<Long, Map<String, TObject>> raw = client.getCriteria( Language.translateToThriftCriteria(criteria), creds, transaction, environment); Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, T>> get(Criteria criteria, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, TObject>> raw; if(timestamp.isString()) { raw = client.getCriteriaTimestr( Language.translateToThriftCriteria(criteria), timestamp.toString(), creds, transaction, environment); } else { raw = client.getCriteriaTime( Language.translateToThriftCriteria(criteria), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, T>> get(Object criteria) { if(criteria instanceof BuildableState) { return get(((BuildableState) criteria).build()); } else { throw new IllegalArgumentException( criteria + " is not a valid argument for the get method"); } } @Override public <T> Map<Long, Map<String, T>> get(Object criteria, Timestamp timestamp) { if(criteria instanceof BuildableState) { return get(((BuildableState) criteria).build(), timestamp); } else { throw new IllegalArgumentException( criteria + " is not a valid argument for the get method"); } } @Override public <T> Map<Long, Map<String, T>> get(String ccl) { return execute(() -> { Map<Long, Map<String, TObject>> raw = client.getCcl(ccl, creds, transaction, environment); Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> Map<Long, T> get(String key, Collection<Long> records) { return execute(() -> { Map<Long, TObject> raw = client.getKeyRecords(key, Collections.toLongList(records), creds, transaction, environment); Map<Long, T> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, TObject> entry : raw.entrySet()) { pretty.put(entry.getKey(), (T) Convert.thriftToJava(entry.getValue())); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> Map<Long, T> get(String key, Collection<Long> records, Timestamp timestamp) { return execute(() -> { Map<Long, TObject> raw; if(timestamp.isString()) { raw = client.getKeyRecordsTimestr(key, Collections.toLongList(records), timestamp.toString(), creds, transaction, environment); } else { raw = client.getKeyRecordsTime(key, Collections.toLongList(records), timestamp.getMicros(), creds, transaction, environment); } Map<Long, T> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, TObject> entry : raw.entrySet()) { pretty.put(entry.getKey(), (T) Convert.thriftToJava(entry.getValue())); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> Map<Long, T> get(String key, Criteria criteria) { return execute(() -> { Map<Long, TObject> raw = client.getKeyCriteria(key, Language.translateToThriftCriteria(criteria), creds, transaction, environment); Map<Long, T> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, TObject> entry : raw.entrySet()) { pretty.put(entry.getKey(), (T) Convert.thriftToJava(entry.getValue())); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> Map<Long, T> get(String key, Criteria criteria, Timestamp timestamp) { return execute(() -> { Map<Long, TObject> raw; if(timestamp.isString()) { raw = client.getKeyCriteriaTimestr(key, Language.translateToThriftCriteria(criteria), timestamp.toString(), creds, transaction, environment); } else { raw = client.getKeyCriteriaTime(key, Language.translateToThriftCriteria(criteria), timestamp.getMicros(), creds, transaction, environment); } Map<Long, T> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, TObject> entry : raw.entrySet()) { pretty.put(entry.getKey(), (T) Convert.thriftToJava(entry.getValue())); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> T get(String key, long record) { return execute(() -> { TObject raw = client.getKeyRecord(key, record, creds, transaction, environment); return raw == TObject.NULL ? null : (T) Convert.thriftToJava(raw); }); } @SuppressWarnings("unchecked") @Override public <T> T get(String key, long record, Timestamp timestamp) { return execute(() -> { TObject raw; if(timestamp.isString()) { raw = client.getKeyRecordTimestr(key, record, timestamp.toString(), creds, transaction, environment); } else { raw = client.getKeyRecordTime(key, record, timestamp.getMicros(), creds, transaction, environment); } return raw == TObject.NULL ? null : (T) Convert.thriftToJava(raw); }); } @Override public <T> Map<Long, T> get(String key, Object criteria) { if(criteria instanceof BuildableState) { return get(key, ((BuildableState) criteria).build()); } else { throw new IllegalArgumentException( criteria + " is not a valid argument for the get method"); } } @Override public <T> Map<Long, T> get(String key, Object criteria, Timestamp timestamp) { if(criteria instanceof BuildableState) { return get(key, ((BuildableState) criteria).build(), timestamp); } else { throw new IllegalArgumentException( criteria + " is not a valid argument for the get method"); } } @SuppressWarnings("unchecked") @Override public <T> Map<Long, T> get(String key, String ccl) { return execute(() -> { Map<Long, TObject> raw = client.getKeyCcl(key, ccl, creds, transaction, environment); Map<Long, T> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, TObject> entry : raw.entrySet()) { pretty.put(entry.getKey(), (T) Convert.thriftToJava(entry.getValue())); } return pretty; }); } @SuppressWarnings("unchecked") @Override public <T> Map<Long, T> get(String key, String ccl, Timestamp timestamp) { return execute(() -> { Map<Long, TObject> raw; if(timestamp.isString()) { raw = client.getKeyCclTimestr(key, ccl, timestamp.toString(), creds, transaction, environment); } else { raw = client.getKeyCclTime(key, ccl, timestamp.getMicros(), creds, transaction, environment); } Map<Long, T> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, TObject> entry : raw.entrySet()) { pretty.put(entry.getKey(), (T) Convert.thriftToJava(entry.getValue())); } return pretty; }); } @Override public <T> Map<Long, Map<String, T>> get(String ccl, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, TObject>> raw; if(timestamp.isString()) { raw = client.getCclTimestr(ccl, timestamp.toString(), creds, transaction, environment); } else { raw = client.getCclTime(ccl, timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, T>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapValues(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public String getServerEnvironment() { return execute(() -> { return client.getServerEnvironment(creds, transaction, environment); }); } @Override public String getServerVersion() { return execute(() -> { return client.getServerVersion(); }); } @Override public Set<Long> insert(String json) { return execute(() -> { return client.insertJson(json, creds, transaction, environment); }); } @Override public Map<Long, Boolean> insert(String json, Collection<Long> records) { return execute(() -> { return client.insertJsonRecords(json, Collections.toLongList(records), creds, transaction, environment); }); } @Override public boolean insert(String json, long record) { return execute(() -> { return client.insertJsonRecord(json, record, creds, transaction, environment); }); } @Override public Set<Long> inventory() { return execute(() -> { return client.inventory(creds, transaction, environment); }); } @Override public <T> T invokePlugin(String id, String method, Object... args) { return execute(() -> { List<ComplexTObject> params = Lists .newArrayListWithCapacity(args.length); for (Object arg : args) { params.add(ComplexTObject.fromJavaObject(arg)); } ComplexTObject result = client.invokePlugin(id, method, params, creds, transaction, environment); return result.getJavaObject(); }); } @Override public String jsonify(Collection<Long> records) { return jsonify(records, true); } @Override public String jsonify(Collection<Long> records, boolean includeId) { return execute(() -> { return client.jsonifyRecords(Collections.toLongList(records), includeId, creds, transaction, environment); }); } @Override public String jsonify(Collection<Long> records, Timestamp timestamp) { return jsonify(records, timestamp, true); } @Override public String jsonify(Collection<Long> records, Timestamp timestamp, boolean includeId) { return execute(() -> { if(timestamp.isString()) { return client.jsonifyRecordsTimestr( Collections.toLongList(records), timestamp.toString(), includeId, creds, transaction, environment); } else { return client.jsonifyRecordsTime( Collections.toLongList(records), timestamp.getMicros(), includeId, creds, transaction, environment); } }); } @Override public String jsonify(long record) { return jsonify(java.util.Collections.singletonList(record), true); } @Override public String jsonify(long record, boolean includeId) { return jsonify(java.util.Collections.singletonList(record), includeId); } @Override public String jsonify(long record, Timestamp timestamp) { return jsonify(java.util.Collections.singletonList(record), timestamp, true); } @Override public String jsonify(long record, Timestamp timestamp, boolean includeId) { return jsonify(java.util.Collections.singletonList(record), timestamp, includeId); } @Override public Map<Long, Boolean> link(String key, Collection<Long> destinations, long source) { Map<Long, Boolean> result = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", "Result"); for (long destination : destinations) { result.put(destination, link(key, destination, source)); } return result; } @Override public boolean link(String key, long destination, long source) { return add(key, Link.to(destination), source); } @Override public Map<Long, Boolean> ping(Collection<Long> records) { return execute(() -> { return client.pingRecords(Collections.toLongList(records), creds, transaction, environment); }); } @Override public boolean ping(long record) { return execute(() -> { return client.pingRecord(record, creds, transaction, environment); }); } @Override public <T> void reconcile(String key, long record, Collection<T> values) { execute(() -> { Set<TObject> valueSet = Sets .newHashSetWithExpectedSize(values.size()); for (T value : values) { valueSet.add(Convert.javaToThrift(value)); } client.reconcileKeyRecordValues(key, record, valueSet, creds, transaction, environment); return null; }); } @Override public <T> Map<Long, Boolean> remove(String key, T value, Collection<Long> records) { return execute(() -> { Map<Long, Boolean> raw = client.removeKeyValueRecords(key, Convert.javaToThrift(value), Collections.toLongList(records), creds, transaction, environment); Map<Long, Boolean> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", "Result"); for (long record : records) { pretty.put(record, raw.get(record)); } return pretty; }); } @Override public <T> boolean remove(String key, T value, long record) { return execute(() -> { return client.removeKeyValueRecord(key, Convert.javaToThrift(value), record, creds, transaction, environment); }); } @Override public void revert(Collection<String> keys, Collection<Long> records, Timestamp timestamp) { execute(() -> { if(timestamp.isString()) { client.revertKeysRecordsTimestr(Collections.toList(keys), Collections.toLongList(records), timestamp.toString(), creds, transaction, environment); } else { client.revertKeysRecordsTime(Collections.toList(keys), Collections.toLongList(records), timestamp.getMicros(), creds, transaction, environment); } return null; }); } @Override public void revert(Collection<String> keys, long record, Timestamp timestamp) { execute(() -> { if(timestamp.isString()) { client.revertKeysRecordTimestr(Collections.toList(keys), record, timestamp.toString(), creds, transaction, environment); } else { client.revertKeysRecordTime(Collections.toList(keys), record, timestamp.getMicros(), creds, transaction, environment); } return null; }); } @Override public void revert(String key, Collection<Long> records, Timestamp timestamp) { execute(() -> { if(timestamp.isString()) { client.revertKeyRecordsTimestr(key, Collections.toLongList(records), timestamp.toString(), creds, transaction, environment); } else { client.revertKeyRecordsTime(key, Collections.toLongList(records), timestamp.getMicros(), creds, transaction, environment); } return null; }); } @Override public void revert(String key, long record, Timestamp timestamp) { execute(() -> { if(timestamp.isString()) { client.revertKeyRecordTimestr(key, record, timestamp.toString(), creds, transaction, environment); } else { client.revertKeyRecordTime(key, record, timestamp.getMicros(), creds, transaction, environment); } return null; }); } @Override public Set<Long> search(String key, String query) { return execute(() -> { return client.search(key, query, creds, transaction, environment); }); } @Override public Map<Long, Map<String, Set<Object>>> select( Collection<Long> records) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw = client.selectRecords( Collections.toLongList(records), creds, transaction, environment); Map<Long, Map<String, Set<Object>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.thriftToJava())); } return pretty; }); } @Override public Map<Long, Map<String, Set<Object>>> select(Collection<Long> records, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw; if(timestamp.isString()) { raw = client.selectRecordsTimestr( Collections.toLongList(records), timestamp.toString(), creds, transaction, environment); } else { raw = client.selectRecordsTime(Collections.toLongList(records), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, Set<Object>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.thriftToJava())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(Collection<String> keys, Collection<Long> records) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw = client.selectKeysRecords( Collections.toList(keys), Collections.toLongList(records), creds, transaction, environment); Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(Collection<String> keys, Collection<Long> records, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw; if(timestamp.isString()) { raw = client.selectKeysRecordsTimestr(Collections.toList(keys), Collections.toLongList(records), timestamp.toString(), creds, transaction, environment); } else { raw = client.selectKeysRecordsTime(Collections.toList(keys), Collections.toLongList(records), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(Collection<String> keys, Criteria criteria) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw = client .selectKeysCriteria(Collections.toList(keys), Language.translateToThriftCriteria(criteria), creds, transaction, environment); Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(Collection<String> keys, Criteria criteria, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw; if(timestamp.isString()) { raw = client.selectKeysCriteriaTimestr(Collections.toList(keys), Language.translateToThriftCriteria(criteria), timestamp.toString(), creds, transaction, environment); } else { raw = client.selectKeysCriteriaTime(Collections.toList(keys), Language.translateToThriftCriteria(criteria), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<String, Set<T>> select(Collection<String> keys, long record) { return execute(() -> { Map<String, Set<TObject>> raw = client.selectKeysRecord( Collections.toList(keys), record, creds, transaction, environment); Map<String, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Key", "Values"); for (Entry<String, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<String, Set<T>> select(Collection<String> keys, long record, Timestamp timestamp) { return execute(() -> { Map<String, Set<TObject>> raw; if(timestamp.isString()) { raw = client.selectKeysRecordTimestr(Collections.toList(keys), record, timestamp.toString(), creds, transaction, environment); } else { raw = client.selectKeysRecordTime(Collections.toList(keys), record, timestamp.getMicros(), creds, transaction, environment); } Map<String, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Key", "Values"); for (Entry<String, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(Collection<String> keys, Object criteria) { if(criteria instanceof BuildableState) { return select(keys, ((BuildableState) criteria).build()); } else { throw new IllegalArgumentException(criteria + " is not a valid argument for the select method"); } } @Override public <T> Map<Long, Map<String, Set<T>>> select(Collection<String> keys, Object criteria, Timestamp timestamp) { if(criteria instanceof BuildableState) { return select(keys, ((BuildableState) criteria).build(), timestamp); } else { throw new IllegalArgumentException(criteria + " is not a valid argument for the select method"); } } @Override public <T> Map<Long, Map<String, Set<T>>> select(Collection<String> keys, String ccl) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw = client.selectKeysCcl( Collections.toList(keys), ccl, creds, transaction, environment); Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(Collection<String> keys, String ccl, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw; if(timestamp.isString()) { raw = client.selectKeysCclTimestr(Collections.toList(keys), ccl, timestamp.toString(), creds, transaction, environment); } else { raw = client.selectKeysCclTime(Collections.toList(keys), ccl, timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(Criteria criteria) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw = client.selectCriteria( Language.translateToThriftCriteria(criteria), creds, transaction, environment); Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(Criteria criteria, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw; if(timestamp.isString()) { raw = client.selectCriteriaTimestr( Language.translateToThriftCriteria(criteria), timestamp.toString(), creds, transaction, environment); } else { raw = client.selectCriteriaTime( Language.translateToThriftCriteria(criteria), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public Map<String, Set<Object>> select(long record) { return execute(() -> { Map<String, Set<TObject>> raw = client.selectRecord(record, creds, transaction, environment); Map<String, Set<Object>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Key", "Values"); for (Entry<String, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily( entry.getValue(), Conversions.thriftToJava())); } return pretty; }); } @Override public Map<String, Set<Object>> select(long record, Timestamp timestamp) { return execute(() -> { Map<String, Set<TObject>> raw; if(timestamp.isString()) { raw = client.selectRecordTimestr(record, timestamp.toString(), creds, transaction, environment); } else { raw = client.selectRecordTime(record, timestamp.getMicros(), creds, transaction, environment); } Map<String, Set<Object>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Key", "Values"); for (Entry<String, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily( entry.getValue(), Conversions.thriftToJava())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(Object criteria) { if(criteria instanceof BuildableState) { return select(((BuildableState) criteria).build()); } else { throw new IllegalArgumentException( criteria + " is not a valid argument for the get method"); } } @Override public <T> Map<Long, Map<String, Set<T>>> select(Object criteria, Timestamp timestamp) { if(criteria instanceof BuildableState) { return select(((BuildableState) criteria).build(), timestamp); } else { throw new IllegalArgumentException( criteria + " is not a valid argument for the get method"); } } @Override public <T> Map<Long, Map<String, Set<T>>> select(String ccl) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw = client.selectCcl(ccl, creds, transaction, environment); Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Set<T>> select(String key, Collection<Long> records) { return execute(() -> { Map<Long, Set<TObject>> raw = client.selectKeyRecords(key, Collections.toLongList(records), creds, transaction, environment); Map<Long, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Set<T>> select(String key, Collection<Long> records, Timestamp timestamp) { return execute(() -> { Map<Long, Set<TObject>> raw; if(timestamp.isString()) { raw = client.selectKeyRecordsTimestr(key, Collections.toLongList(records), timestamp.toString(), creds, transaction, environment); } else { raw = client.selectKeyRecordsTime(key, Collections.toLongList(records), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Set<T>> select(String key, Criteria criteria) { return execute(() -> { Map<Long, Set<TObject>> raw = client.selectKeyCriteria(key, Language.translateToThriftCriteria(criteria), creds, transaction, environment); Map<Long, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Set<T>> select(String key, Criteria criteria, Timestamp timestamp) { return execute(() -> { Map<Long, Set<TObject>> raw; if(timestamp.isString()) { raw = client.selectKeyCriteriaTimestr(key, Language.translateToThriftCriteria(criteria), timestamp.toString(), creds, transaction, environment); } else { raw = client.selectKeyCriteriaTime(key, Language.translateToThriftCriteria(criteria), timestamp.getMicros(), creds, transaction, environment); } Map<Long, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Set<T> select(String key, long record) { return execute(() -> { Set<TObject> values = client.selectKeyRecord(key, record, creds, transaction, environment); return Transformers.transformSetLazily(values, Conversions.<T> thriftToJavaCasted()); }); } @Override public <T> Set<T> select(String key, long record, Timestamp timestamp) { return execute(() -> { Set<TObject> values; if(timestamp.isString()) { values = client.selectKeyRecordTimestr(key, record, timestamp.toString(), creds, transaction, environment); } else { values = client.selectKeyRecordTime(key, record, timestamp.getMicros(), creds, transaction, environment); } return Transformers.transformSetLazily(values, Conversions.<T> thriftToJavaCasted()); }); } @Override public <T> Map<Long, Set<T>> select(String key, Object criteria) { if(criteria instanceof BuildableState) { return select(key, ((BuildableState) criteria).build()); } else { throw new IllegalArgumentException(criteria + " is not a valid argument for the select method"); } } @Override public <T> Map<Long, Set<T>> select(String key, Object criteria, Timestamp timestamp) { if(criteria instanceof BuildableState) { return select(key, ((BuildableState) criteria).build(), timestamp); } else { throw new IllegalArgumentException(criteria + " is not a valid argument for the select method"); } } @Override public <T> Map<Long, Set<T>> select(String key, String ccl) { return execute(() -> { Map<Long, Set<TObject>> raw = client.selectKeyCcl(key, ccl, creds, transaction, environment); Map<Long, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Set<T>> select(String key, String ccl, Timestamp timestamp) { return execute(() -> { Map<Long, Set<TObject>> raw; if(timestamp.isString()) { raw = client.selectKeyCclTimestr(key, ccl, timestamp.toString(), creds, transaction, environment); } else { raw = client.selectKeyCclTime(key, ccl, timestamp.getMicros(), creds, transaction, environment); } Map<Long, Set<T>> pretty = PrettyLinkedHashMap .newPrettyLinkedHashMap("Record", key); for (Entry<Long, Set<TObject>> entry : raw.entrySet()) { pretty.put(entry.getKey(), Transformers.transformSetLazily(entry.getValue(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public <T> Map<Long, Map<String, Set<T>>> select(String ccl, Timestamp timestamp) { return execute(() -> { Map<Long, Map<String, Set<TObject>>> raw; if(timestamp.isString()) { raw = client.selectCclTimestr(ccl, timestamp.toString(), creds, transaction, environment); } else { raw = client.selectCclTime(ccl, timestamp.getMicros(), creds, transaction, environment); } Map<Long, Map<String, Set<T>>> pretty = PrettyLinkedTableMap .newPrettyLinkedTableMap("Record"); for (Entry<Long, Map<String, Set<TObject>>> entry : raw .entrySet()) { pretty.put(entry.getKey(), Transformers.transformMapSet(entry.getValue(), Conversions.<String> none(), Conversions.<T> thriftToJavaCasted())); } return pretty; }); } @Override public void set(String key, Object value, Collection<Long> records) { execute(() -> { client.setKeyValueRecords(key, Convert.javaToThrift(value), Collections.toLongList(records), creds, transaction, environment); return null; }); } @Override public <T> void set(String key, T value, long record) { execute(() -> { client.setKeyValueRecord(key, Convert.javaToThrift(value), record, creds, transaction, environment); return null; }); } @Override public void stage() throws TransactionException { execute(() -> { transaction = client.stage(creds, environment); return null; }); } @Override public Timestamp time() { return execute(() -> { return Timestamp .fromMicros(client.time(creds, transaction, environment)); }); } @Override public Timestamp time(String phrase) { return execute(() -> { return Timestamp.fromMicros( client.timePhrase(phrase, creds, transaction, environment)); }); } @Override public String toString() { return "Connected to " + host + ":" + port + " as " + new String(ClientSecurity.decrypt(username).array()); } @Override public boolean unlink(String key, long destination, long source) { return remove(key, Link.to(destination), source); } @Override public boolean verify(String key, Object value, long record) { return execute(() -> { return client.verifyKeyValueRecord(key, Convert.javaToThrift(value), record, creds, transaction, environment); }); } @Override public boolean verify(String key, Object value, long record, Timestamp timestamp) { return execute(() -> { if(timestamp.isString()) { return client.verifyKeyValueRecordTimestr(key, Convert.javaToThrift(value), record, timestamp.toString(), creds, transaction, environment); } else { return client.verifyKeyValueRecordTime(key, Convert.javaToThrift(value), record, timestamp.getMicros(), creds, transaction, environment); } }); } @Override public boolean verifyAndSwap(String key, Object expected, long record, Object replacement) { return execute(() -> { return client.verifyAndSwap(key, Convert.javaToThrift(expected), record, Convert.javaToThrift(replacement), creds, transaction, environment); }); } @Override public void verifyOrSet(String key, Object value, long record) { execute(() -> { client.verifyOrSet(key, Convert.javaToThrift(value), record, creds, transaction, environment); return null; }); } @Override protected Concourse copyConnection() { return new ConcourseThriftDriver(host, port, ByteBuffers.getString(ClientSecurity.decrypt(username)), ByteBuffers.getString(ClientSecurity.decrypt(password)), environment); } /** * Authenticate the {@link #username} and {@link #password} and populate * {@link #creds} with the appropriate AccessToken. */ private void authenticate() { try { creds = client.login(ClientSecurity.decrypt(username), ClientSecurity.decrypt(password), environment); } catch (TException e) { throw Throwables.propagate(e); } } /** * Perform an old-school/simple find operation where {@code key} * satisfied {@code operation} in relation to the specified * {@code values}. * * @param key * @param operator * @param values * @return the records that match the criteria. */ private Set<Long> executeFind(final String key, final Object operator, final Object... values) { final List<TObject> tValues = Lists.transform( Lists.newArrayList(values), Conversions.javaToThrift()); return execute(() -> { if(operator instanceof Operator) { return client.findKeyOperatorValues(key, (Operator) operator, tValues, creds, transaction, environment); } else { return client.findKeyOperatorstrValues(key, operator.toString(), tValues, creds, transaction, environment); } }); } /** * Perform an old-school/simple find operation where {@code key} * satisfied {@code operation} in relation to the specified * {@code values} at {@code timestamp}. * * @param key * @param operator * @param values * @param timestamp a {@link Timestamp} that represents the historical * instant to use in the lookup – created from either a * {@link Timestamp#fromString(String) natural language * description} of a point in time (i.e. two weeks ago), OR * the {@link Timestamp#fromMicros(long) number * of microseconds} since the Unix epoch, OR * a {@link Timestamp#fromJoda(org.joda.time.DateTime) Joda * DateTime} object * @return the records that match the criteria. */ private Set<Long> executeFind(final Timestamp timestamp, final String key, final Object operator, final Object... values) { final List<TObject> tValues = Lists.transform( Lists.newArrayList(values), Conversions.javaToThrift()); return execute(() -> { if(operator instanceof Operator) { return client.findKeyOperatorValuesTime(key, (Operator) operator, tValues, timestamp.getMicros(), creds, transaction, environment); } else { return client.findKeyOperatorstrValuesTime(key, operator.toString(), tValues, timestamp.getMicros(), creds, transaction, environment); } }); } /** * Execute the task defined in {@code callable}. This method contains * retry logic to handle cases when {@code creds} expires and must be * updated. * * @param callable * @return the task result */ <T> T execute(Callable<T> callable) { try { return callable.call(); } catch (SecurityException e) { authenticate(); return execute(callable); } catch (com.cinchapi.concourse.thrift.TransactionException e) { throw new TransactionException(); } catch (com.cinchapi.concourse.thrift.DuplicateEntryException e) { throw new DuplicateEntryException(e); } catch (com.cinchapi.concourse.thrift.InvalidArgumentException e) { throw new InvalidArgumentException(e); } catch (com.cinchapi.concourse.thrift.ParseException e) { throw new ParseException(e); } catch (Exception e) { throw Throwables.propagate(e); } } /** * Return the thrift RPC client. * * @return the {@link ConcourseService#Client} */ ConcourseService.Client thrift() { return client; } /** * Return the current {@link AccessToken} * * @return the creds */ AccessToken creds() { return creds; } /** * Return the current {@link TransactionToken}. * * @return the transaction token */ @Nullable TransactionToken transaction() { return transaction; } /** * Return the environment to which the driver is connected. * * @return the environment */ String environment() { return environment; } }