Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 1 | /* |
| 2 | * File name: Client.java |
| 3 | * |
| 4 | * Purpose: Provide a client to simplify information retrieval over the NDN |
| 5 | * network. |
| 6 | * |
| 7 | * © Copyright Intel Corporation. All rights reserved. |
| 8 | * Intel Corporation, 2200 Mission College Boulevard, |
| 9 | * Santa Clara, CA 95052-8119, USA |
| 10 | */ |
| 11 | package com.intel.jndn.utils; |
| 12 | |
| 13 | import java.io.IOException; |
| 14 | import net.named_data.jndn.Data; |
| 15 | import net.named_data.jndn.Face; |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 16 | import net.named_data.jndn.Interest; |
| 17 | import net.named_data.jndn.Name; |
| 18 | import net.named_data.jndn.OnData; |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 19 | import net.named_data.jndn.OnTimeout; |
| 20 | import net.named_data.jndn.encoding.EncodingException; |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 21 | import org.apache.logging.log4j.LogManager; |
| 22 | import org.apache.logging.log4j.Logger; |
| 23 | |
| 24 | /** |
Andrew Brown | 070dc89 | 2015-01-21 09:55:12 -0800 | [diff] [blame] | 25 | * Provide a client to simplify information retrieval over the NDN network. |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 26 | * |
| 27 | * @author Andrew Brown <andrew.brown@intel.com> |
| 28 | */ |
| 29 | public class Client { |
| 30 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 31 | public static final long DEFAULT_SLEEP_TIME = 20; |
| 32 | public static final long DEFAULT_TIMEOUT = 2000; |
| 33 | private static final Logger logger = LogManager.getLogger(); |
Andrew Brown | 070dc89 | 2015-01-21 09:55:12 -0800 | [diff] [blame] | 34 | private static Client defaultInstance; |
| 35 | |
| 36 | /** |
| 37 | * Singleton access for simpler client use |
| 38 | * |
| 39 | * @return |
| 40 | */ |
| 41 | public static Client getDefault() { |
| 42 | if (defaultInstance == null) { |
| 43 | defaultInstance = new Client(); |
| 44 | } |
| 45 | return defaultInstance; |
| 46 | } |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 47 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 48 | /** |
| 49 | * Synchronously retrieve the Data for an Interest; this will block until |
| 50 | * complete (i.e. either data is received or the interest times out). |
| 51 | * |
| 52 | * @param face |
| 53 | * @param interest |
| 54 | * @return Data packet or null |
| 55 | */ |
| 56 | public Data getSync(Face face, Interest interest) { |
| 57 | // setup event |
| 58 | long startTime = System.currentTimeMillis(); |
Andrew Brown | a450fad | 2015-01-22 11:24:40 -0800 | [diff] [blame] | 59 | final NDNEvent event = new NDNEvent(); // this event is used without observer/observables for speed; just serves as a final reference into the callbacks |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 60 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 61 | // send interest |
| 62 | try { |
| 63 | face.expressInterest(interest, new OnData() { |
| 64 | @Override |
| 65 | public void onData(Interest interest, Data data) { |
Andrew Brown | 070dc89 | 2015-01-21 09:55:12 -0800 | [diff] [blame] | 66 | event.fromPacket(data); |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 67 | } |
| 68 | }, new OnTimeout() { |
| 69 | @Override |
| 70 | public void onTimeout(Interest interest) { |
Andrew Brown | 070dc89 | 2015-01-21 09:55:12 -0800 | [diff] [blame] | 71 | event.fromPacket(new Exception("Interest timed out: " + interest.getName().toUri())); |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 72 | } |
| 73 | }); |
| 74 | } catch (IOException e) { |
| 75 | logger.warn("IO failure while sending interest.", e); |
| 76 | return null; |
| 77 | } |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 78 | |
Andrew Brown | 070dc89 | 2015-01-21 09:55:12 -0800 | [diff] [blame] | 79 | // process eventCount until a response is received or timeout |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 80 | while (event.getPacket() == null) { |
| 81 | try { |
| 82 | synchronized (face) { |
| 83 | face.processEvents(); |
| 84 | } |
| 85 | } catch (IOException | EncodingException e) { |
| 86 | logger.warn("Failed to process events.", e); |
| 87 | return null; |
| 88 | } |
| 89 | sleep(); |
| 90 | } |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 91 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 92 | // return |
| 93 | logger.debug("Request time (ms): " + (event.getTimestamp() - startTime)); |
| 94 | return (event.isSuccess()) ? (Data) event.getPacket() : null; |
| 95 | } |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 96 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 97 | /** |
| 98 | * Synchronously retrieve the Data for a Name using a default interest (e.g. 2 |
| 99 | * second timeout); this will block until complete (i.e. either data is |
| 100 | * received or the interest times out). |
| 101 | * |
| 102 | * @param face |
| 103 | * @param name |
| 104 | * @return |
| 105 | */ |
| 106 | public Data getSync(Face face, Name name) { |
| 107 | return getSync(face, getDefaultInterest(name)); |
| 108 | } |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 109 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 110 | /** |
| 111 | * Asynchronously retrieve the Data for a given interest; use the returned |
Andrew Brown | a450fad | 2015-01-22 11:24:40 -0800 | [diff] [blame] | 112 | NDNObserver to handle the Data when it arrives. For example (with lambdas): |
Andrew Brown | 070dc89 | 2015-01-21 09:55:12 -0800 | [diff] [blame] | 113 | * <pre><code> |
| 114 | * Client.getDefault().get(face, interest).then((event) -> doSomething(event)); |
| 115 | * </code></pre> |
| 116 | * |
| 117 | * If you want to block until the response returns, try something like: |
| 118 | * <pre><code> |
Andrew Brown | a450fad | 2015-01-22 11:24:40 -0800 | [diff] [blame] | 119 | NDNObserver observer = Client.getDefault().get(face, interest); |
| 120 | while(observer.eventCount() == 0){ |
| 121 | Thread.sleep(50); |
| 122 | } |
| 123 | doSomething(observer.getFirst()); |
| 124 | </code></pre> |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 125 | * |
| 126 | * @param face |
| 127 | * @param interest |
| 128 | * @return |
| 129 | */ |
Andrew Brown | a450fad | 2015-01-22 11:24:40 -0800 | [diff] [blame] | 130 | public NDNObserver get(final Face face, final Interest interest) { |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 131 | // setup observer |
Andrew Brown | a450fad | 2015-01-22 11:24:40 -0800 | [diff] [blame] | 132 | final NDNObserver observer = new NDNObserver(); |
| 133 | final NDNObservable eventHandler = new NDNObservable(); |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 134 | eventHandler.addObserver(observer); |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 135 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 136 | // setup background thread |
| 137 | Thread backgroundThread = new Thread(new Runnable() { |
| 138 | @Override |
| 139 | public void run() { |
| 140 | // send interest |
| 141 | try { |
| 142 | face.expressInterest(interest, eventHandler, eventHandler); |
| 143 | } catch (IOException e) { |
| 144 | logger.warn("IO failure while sending interest.", e); |
| 145 | eventHandler.notify(e); |
| 146 | } |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 147 | |
Andrew Brown | 070dc89 | 2015-01-21 09:55:12 -0800 | [diff] [blame] | 148 | // process eventCount until a response is received or timeout |
| 149 | while (observer.dataCount() == 0 && observer.errorCount() == 0 && !observer.mustStop()) { |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 150 | try { |
| 151 | synchronized (face) { |
| 152 | face.processEvents(); |
| 153 | } |
| 154 | } catch (IOException | EncodingException e) { |
| 155 | logger.warn("Failed to process events.", e); |
| 156 | eventHandler.notify(e); |
| 157 | } |
| 158 | sleep(); |
| 159 | } |
Andrew Brown | 070dc89 | 2015-01-21 09:55:12 -0800 | [diff] [blame] | 160 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 161 | // finished |
| 162 | logger.trace("Received response; stopping thread."); |
| 163 | } |
| 164 | }); |
| 165 | backgroundThread.setName(String.format("Client.get(%s)", interest.getName().toUri())); |
| 166 | backgroundThread.setDaemon(true); |
| 167 | backgroundThread.start(); |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 168 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 169 | // return |
| 170 | return observer; |
| 171 | } |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 172 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 173 | /** |
| 174 | * Asynchronously retrieve the Data for a Name using default Interest |
| 175 | * parameters; see get(Face, Interest) for examples. |
| 176 | * |
| 177 | * @param face |
| 178 | * @param name |
| 179 | * @return |
| 180 | */ |
Andrew Brown | a450fad | 2015-01-22 11:24:40 -0800 | [diff] [blame] | 181 | public NDNObserver get(Face face, Name name) { |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 182 | return get(face, getDefaultInterest(name)); |
| 183 | } |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 184 | |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 185 | /** |
Andrew Brown | 7b1daf3 | 2015-01-19 16:36:01 -0800 | [diff] [blame] | 186 | * Put the current thread to sleep to allow time for IO |
| 187 | */ |
| 188 | protected void sleep() { |
| 189 | try { |
| 190 | Thread.currentThread().sleep(DEFAULT_SLEEP_TIME); |
| 191 | } catch (InterruptedException e) { |
| 192 | logger.error("Event loop interrupted.", e); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | /** |
| 197 | * Create a default interest for a given Name using some common settings: - |
| 198 | * lifetime: 2 seconds |
| 199 | * |
| 200 | * @param name |
| 201 | * @return |
| 202 | */ |
| 203 | public Interest getDefaultInterest(Name name) { |
| 204 | Interest interest = new Interest(name, DEFAULT_TIMEOUT); |
| 205 | return interest; |
| 206 | } |
Andrew Brown | 3f2521a | 2015-01-17 22:10:15 -0800 | [diff] [blame] | 207 | } |