blob: d332acf14972ec7870f866e4f15e08d4c8233dc8 [file] [log] [blame]
Andrew Browna450fad2015-01-22 11:24:40 -08001/*
2 * File name: Server.java
3 *
4 * Purpose: Provide a server to simplify serving data 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 */
11package com.intel.jndn.utils;
12
13import java.io.IOException;
14import net.named_data.jndn.Data;
15import net.named_data.jndn.Face;
16import net.named_data.jndn.ForwardingFlags;
17import net.named_data.jndn.Interest;
18import net.named_data.jndn.Name;
19import net.named_data.jndn.OnInterest;
20import net.named_data.jndn.OnRegisterFailed;
21import net.named_data.jndn.encoding.EncodingException;
22import net.named_data.jndn.transport.Transport;
23import org.apache.logging.log4j.LogManager;
24import org.apache.logging.log4j.Logger;
25
26/**
27 * Provide a server to simplify serving data over the NDN network. Exposes two
28 * main methods: put() for serving static, known data packets and on() for
29 * serving dynamically created packets on-demand.
30 *
31 * @author Andrew Brown <andrew.brown@intel.com>
32 */
33public class Server {
34
35 public static final long DEFAULT_SLEEP_TIME = 20;
36 public static final long DEFAULT_TIMEOUT = 2000;
37 private static final Logger logger = LogManager.getLogger();
38 private static Server defaultInstance;
39
40 /**
41 * Singleton access for simpler server use
42 *
43 * @return
44 */
45 public static Server getDefault() {
46 if (defaultInstance == null) {
47 defaultInstance = new Server();
48 }
49 return defaultInstance;
50 }
51
52 /**
53 * Synchronously serve a Data on the given face until one request accesses the
54 * data; will return incoming Interest request.
55 * <pre><code> Interest request = Client.putSync(face, data); </code></pre>
56 *
57 * @param face
58 * @param data
59 * @return
60 */
61 public Interest putSync(Face face, final Data data) {
62 // setup event
63 long startTime = System.currentTimeMillis();
64 final String dataName = data.getName().toUri();
65 final NDNEvent event = new NDNEvent();
66
67 // setup flags
68 ForwardingFlags flags = new ForwardingFlags();
69 flags.setCapture(true);
70
71 // register the data name on the face
72 try {
73 face.registerPrefix(data.getName(), new OnInterest() {
74 @Override
75 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
76 try {
77 transport.send(data.wireEncode().buf());
78 logger.debug("Sent data: " + dataName);
79 event.fromPacket(interest);
80 } catch (IOException e) {
81 logger.error("Failed to send data for: " + dataName);
82 event.fromPacket(e);
83 }
84 }
85 }, new OnRegisterFailed() {
86 @Override
87 public void onRegisterFailed(Name prefix) {
88 event.fromPacket(new Exception("Failed to register name: " + dataName));
89 }
90 }, flags);
91 logger.info("Registered data: " + dataName);
92 } catch (IOException e) {
93 logger.error("Could not connect to face to register prefix: " + dataName, e);
94 event.fromPacket(e);
95 } catch (net.named_data.jndn.security.SecurityException e) {
96 logger.error("Error registering prefix: " + dataName, e);
97 event.fromPacket(e);
98 }
99
100 // process eventCount until one response is sent or error
101 while (event.getPacket() == null) {
102 try {
103 synchronized (face) {
104 face.processEvents();
105 }
106 } catch (IOException | EncodingException e) {
107 logger.warn("Failed to process events.", e);
108 event.fromPacket(e);
109 }
110 sleep();
111 }
112
113 // return
114 logger.debug("Request time (ms): " + (event.getTimestamp() - startTime));
115 return (event.isSuccess()) ? (Interest) event.getPacket() : null;
116 }
117
118 /**
119 * Asynchronously serve a Data on the given face until an observer stops it.
120 * E.g.: NDNObserver observer = Client.put(face, data); // when finished
121 serving the data, stop the background thread observer.stop();
122 *
123 * @param face
124 * @param data
125 * @return
126 */
127 public NDNObserver put(final Face face, final Data data) {
128 // setup observer
129 final NDNObserver observer = new NDNObserver();
130 final NDNObservable eventHandler = new NDNObservable();
131 eventHandler.addObserver(observer);
132
133 // setup handlers
134 final OnInterest interestHandler = new OnInterest() {
135 @Override
136 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
137 try {
138 transport.send(data.wireEncode().buf());
139 } catch (IOException e) {
140 logger.error("Failed to send data for: " + data.getName().toUri());
141 eventHandler.notify(e);
142 }
143 }
144 };
145 final OnRegisterFailed failureHandler = new OnRegisterFailed() {
146 @Override
147 public void onRegisterFailed(Name prefix) {
148 logger.error("Failed to register name to put: " + data.getName().toUri());
149 eventHandler.notify(new Exception("Failed to register name to put: " + data.getName().toUri()));
150 }
151 };
152 final ForwardingFlags flags = new ForwardingFlags();
153 flags.setCapture(true); // no shorter routes will answer for this prefix, see http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route-inheritance
154 flags.setChildInherit(false); // the interest name must be exact, no child components after the prefix
155
156 // setup background thread
157 Thread backgroundThread = new Thread(new Runnable() {
158 @Override
159 public void run() {
160 // register name on the face
161 try {
162 face.registerPrefix(data.getName(), interestHandler, failureHandler, flags);
163 logger.info("Registered data : " + data.getName().toUri());
164 } catch (IOException e) {
165 logger.error("Could not connect to face to register prefix: " + data.getName().toUri(), e);
166 eventHandler.notify(e);
167 } catch (net.named_data.jndn.security.SecurityException e) {
168 logger.error("Error registering prefix: " + data.getName().toUri(), e);
169 eventHandler.notify(e);
170 }
171
172 // process eventCount until a request is received
173 while (observer.interestCount() == 0 && observer.errorCount() == 0 && !observer.mustStop()) {
174 try {
175 synchronized (face) {
176 face.processEvents();
177 }
178 } catch (IOException | EncodingException e) {
179 logger.warn("Failed to process events.", e);
180 eventHandler.notify(e);
181 }
182 sleep();
183 }
184 }
185 });
186 backgroundThread.setName(String.format("Server.put(%s)", data.getName().toUri()));
187 backgroundThread.setDaemon(true);
188 backgroundThread.start();
189
190 return observer;
191 }
192
193 /**
194 * Register a prefix on the face to serve Data packets for incoming Interests.
195 * This method will create a background thread to process events until
196 * the user calls stop() on the returned observer
197 *
198 * @param face
199 * @param prefix
200 * @param handler
201 * @return
202 */
203 public NDNObserver on(final Face face, final Name prefix, final OnServeInterest handler) {
204 // setup observer
205 final NDNObserver observer = new NDNObserver();
206 final NDNObservable eventHandler = new NDNObservable();
207 eventHandler.addObserver(observer);
208
209 // setup handlers
210 final OnInterest interestHandler = new OnInterest() {
211 @Override
212 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
213 eventHandler.notify(interest);
214 try {
215 Data data = handler.onInterest(prefix, interest);
216 // TODO do signing here?
217 transport.send(data.wireEncode().buf());
218 } catch (IOException e) {
219 logger.error("Failed to send data for: " + prefix.toUri());
220 eventHandler.notify(e);
221 }
222 }
223 };
224 final OnRegisterFailed failureHandler = new OnRegisterFailed() {
225 @Override
226 public void onRegisterFailed(Name prefix) {
227 logger.error("Failed to register name to put: " + prefix.toUri());
228 eventHandler.notify(new Exception("Failed to register name to put: " + prefix.toUri()));
229 }
230 };
231 final ForwardingFlags flags = new ForwardingFlags();
232 flags.setCapture(true); // no shorter routes will answer for this prefix, see http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route-inheritance
233 flags.setChildInherit(true); // the interest name may have child components after the prefix
234
235 // setup background thread
236 Thread backgroundThread = new Thread(new Runnable() {
237 @Override
238 public void run() {
239 // register name on the face
240 try {
241 face.registerPrefix(prefix, interestHandler, failureHandler, flags);
242 logger.info("Registered data : " + prefix.toUri());
243 } catch (IOException e) {
244 logger.error("Could not connect to face to register prefix: " + prefix.toUri(), e);
245 eventHandler.notify(e);
246 } catch (net.named_data.jndn.security.SecurityException e) {
247 logger.error("Error registering prefix: " + prefix.toUri(), e);
248 eventHandler.notify(e);
249 }
250
251 // process events until told to stop or error bubbles up
252 while (observer.errorCount() == 0 && !observer.mustStop()) {
253 try {
254 synchronized (face) {
255 face.processEvents();
256 }
257 } catch (IOException | EncodingException e) {
258 logger.warn("Failed to process events.", e);
259 eventHandler.notify(e);
260 }
261 sleep();
262 }
263 }
264 });
265 backgroundThread.setName(String.format("Client.put(%s)", prefix.toUri()));
266 backgroundThread.setDaemon(true);
267 backgroundThread.start();
268
269 return observer;
270 }
271
272 /**
273 * Put the current thread to sleep to allow time for IO
274 */
275 protected void sleep() {
276 try {
277 Thread.currentThread().sleep(DEFAULT_SLEEP_TIME);
278 } catch (InterruptedException e) {
279 logger.error("Event loop interrupted.", e);
280 }
281 }
282
283}