/** * Copyright 2013-2015 Seagate Technology LLC. * * This Source Code Form is subject to the terms of the Mozilla * Public License, v. 2.0. If a copy of the MPL was not * distributed with this file, You can obtain one at * https://mozilla.org/MP:/2.0/. * * This program is distributed in the hope that it will be useful, * but is provided AS-IS, WITHOUT ANY WARRANTY; including without * the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or * FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public * License for more details. * * See www.openkinetic.org for more project information */ package com.seagate.kinetic.example.client.async; import java.io.UnsupportedEncodingException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import kinetic.client.ClientConfiguration; import kinetic.client.Entry; import kinetic.client.KineticClient; import kinetic.client.KineticClientFactory; import kinetic.client.KineticException; /** * Kinetic Asynchronous API with SSL/TLS usage sample code. * <p> * This example assumes that a simulator is running on the localhost:8443 * (SSL/TLS port) * <p> * This example performs the following operations in a loop * <ul> * <li>1. start Kinetic client with SSL/TLS enabled. * <li>2. (forced) put entry asynchronously ("hello", "world"); * <li>3. get entry asynchronously ("hello"); * <li>4. (forced) delete entry asynchronously ("hello"); * <li>5. repeat step #2 to step #4 until reached MAX_ITERATION (1000). * <li>6. wait for operation to complete * <li>7. close Kinetic client. * </ul> */ public class AsyncApiUsage { // iteration to put messages to the kinetic store public static final int MAX_ITERATION = 1000; // String to byte[] encoding public static final String UTF8 = "utf8"; // kinetic client private KineticClient client = null; // cache to store async put entry private final Map<String, Entry> map = new ConcurrentHashMap<String, Entry>(); // async put callback handler private PutAsyncCallbackHandler putCallbackHandler = null; // async delete callback handler private DeleteAsyncCallbackHandler deleteCallbackHandler = null; // async get callback handler private GetCallbackHandler getCallbackHandler = null; // count down signal for async put/get/delete private CountDownLatch doneSignal = null; /** * Start the async API usage example. * * @throws KineticException * if any Kinetic internal error occurred. * @throws InterruptedException * if the example is interrupted before it is completed. */ public void runExample() throws KineticException, InterruptedException { // Client configuration and initialization ClientConfiguration clientConfig = new ClientConfiguration(); // set use SSL/TLS clientConfig.setUseSsl(true); // set SSL/TLS service port clientConfig.setPort(8443); client = KineticClientFactory.createInstance(clientConfig); // count down signal -- total 3 asynchronous operations doneSignal = new CountDownLatch(3 * MAX_ITERATION); // async put putCallbackHandler handler putCallbackHandler = new PutAsyncCallbackHandler(this); // async get callback handler getCallbackHandler = new GetCallbackHandler(this); // async delete putCallbackHandler handler deleteCallbackHandler = new DeleteAsyncCallbackHandler(this); // put a simple entry asynchronously, this starts async loops. this.putSimpleEntry(); // wait for async put/get/delete to complete this.doneSignal.await(); // close kinetic client this.client.close(); } /** * put a simple entry asynchronously * * @throws KineticException * any kinetic internal error occurred */ private void putSimpleEntry() { // create a simple key/value entry Entry simpleEntry = createSimpleEntry("hello", "world"); /** * added the entry to cache, this will be deleted when received * putCallbackHandler confirmation. */ this.map.put(bytesToString(simpleEntry.getKey()), simpleEntry); /** * put forced asynchronously. Upon completion, the * PutAsyncCallbackHandler#onSuccess() is invoked by kinetic client * runtime. */ try { client.putForcedAsync(simpleEntry, putCallbackHandler); } catch (KineticException e) { e.printStackTrace(); } } /** * utility method to create a simple entry. * * @param key * string key * @param value * string value * @return kinetic entry * * @throws UnsupportedEncodingException */ public static Entry createSimpleEntry(String key, String value) { Entry entry = null; try { // get key bytes byte[] keyBytes = key.getBytes(UTF8); // get value bytes byte[] valueBytes = value.getBytes(UTF8); // create entry entry = new Entry(keyBytes, valueBytes); // return simple entry return entry; } catch (Exception e) { e.printStackTrace(); } return entry; } /** * This method is called by the PutAsyncCallbackHandler when received put * callback successfully. * * @param entry * the entry that was put successfully to the kinetic store. */ public void asyncPutInStore(Entry entry) { // count down operation for put successfully this.doneSignal.countDown(); try { // get entry form cache, the entry has successfully put in store Entry eInMap = map.get(bytesToString(entry.getKey())); if (eInMap == null) { System.out.println("cannot find entry from cache ..."); } else { System.out .println("put successful, found entry from cache, calling get async ..."); // get the entry asynchronously from kinetic store this.client.getAsync(entry.getKey(), getCallbackHandler); } } catch (Exception e) { e.printStackTrace(); } } /** * This method is called by the GetCallbackHandler when received an * asynchronous get entry. * * @param entry * received from asynchronous get callback handler. */ public void asyncGetReceived(Entry entry) { // get entry form cache, the entry has successfully put in store Entry eInMap = map.get(bytesToString(entry.getKey())); if (eInMap == null) { System.out.println("cannot find entry from cache ..."); } else { // count down signal for async get operation this.doneSignal.countDown(); System.out .println("get async received entry, calling async delete ..."); // delete the entry this.deleteEntry(entry.getKey()); } } /** * async delete an entry. * * @param key * the key of the entry to be deleted asynchronously */ private void deleteEntry(byte[] key) { try { // async forced delete this.client.deleteForcedAsync(key, this.deleteCallbackHandler); } catch (KineticException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * This method is called when the DeleteAsyncCallbackHandler received * confirmation that an entry is deleted. */ public void asyncDeletedInStore(byte[] key) { // remove entry form cache, the entry has successfully put in store Entry eInMap = map.remove(bytesToString(key)); if (eInMap == null) { System.out.println("error remove entry from cache ..."); } else { // count down so that we can exit this.doneSignal.countDown(); System.out.println("async delete successfully ..., done counter=" + this.doneSignal.getCount()); } if (this.doneSignal.getCount() > 0) { // a new iteration of async put/get/delete this.putSimpleEntry(); } } /** * convert byte[] to string using UTF8 encoding. * * @param bytes * byte[] to be converted to string. * * @return the string representation of the specified byte[] */ private static String bytesToString(byte[] bytes) { try { return new String(bytes, UTF8); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } public static void main(String[] args) throws KineticException, InterruptedException { AsyncApiUsage asyncUsage = new AsyncApiUsage(); asyncUsage.runExample(); } }