blob: c36b16ebec37655925aa0712aa50d794a728e209 [file] [log] [blame]
Andrew Brown3831baf2015-01-19 13:38:52 -08001/*
andrewsbrown533c6ef2015-03-03 16:08:41 -08002 * jndn-mock
3 * Copyright (c) 2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU Lesser General Public License,
7 * version 3, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
12 * more details.
Andrew Brown3831baf2015-01-19 13:38:52 -080013 */
14package com.intel.jndn.mock;
15
16import java.io.IOException;
andrewsbrown1f28bcf2015-04-20 13:29:20 -070017import java.nio.ByteBuffer;
Andrew Brown3831baf2015-01-19 13:38:52 -080018import java.util.HashMap;
19import java.util.Map.Entry;
Andrew Brownec1b0d02015-02-21 13:11:42 -080020import java.util.logging.Logger;
Alexander Afanasyev8e9330f2016-01-25 19:13:40 -080021
22import net.named_data.jndn.*;
Andrew Brown3831baf2015-01-19 13:38:52 -080023import net.named_data.jndn.encoding.EncodingException;
24import net.named_data.jndn.encoding.WireFormat;
andrewsbrown1f28bcf2015-04-20 13:29:20 -070025import net.named_data.jndn.security.SecurityException;
Andrew Brown3831baf2015-01-19 13:38:52 -080026
27/**
Andrew Brownb91e6902015-02-12 09:01:50 -080028 * <p>
29 * Use the MockTransport to mock sending data over the network. Allows for
30 * testing NDN applications while simulating network IO. TODO implement longest
31 * prefix match here for comprehensive testing.
32 * </p>
33 * <p>
34 * Usage
35 * </p>
36 * <pre><code>
37 * Face mockFace = new MockFace();
38 * mockFace.registerPrefix(...); // as usual
39 * mockFace.expressInterest(...); // as usual
40 *
41 * // also, simply inject a response that will be returned for an expressed interest
42 * mockFace.addResponse(interestName, data);
43 * </pre></code>
Andrew Brown3831baf2015-01-19 13:38:52 -080044 *
45 * @author Andrew Brown <andrew.brown@intel.com>
46 */
andrewsbrown1f28bcf2015-04-20 13:29:20 -070047public class MockFace extends FaceExtension {
Andrew Brown3831baf2015-01-19 13:38:52 -080048
Andrew Brownec1b0d02015-02-21 13:11:42 -080049 private static final Logger logger = Logger.getLogger(MockFace.class.getName());
Andrew Brown3831baf2015-01-19 13:38:52 -080050 private final Node node_;
Alexander Afanasyev8e9330f2016-01-25 19:13:40 -080051 HashMap<String, Data> responseMap = new HashMap<String, Data>();
52 HashMap<Long, MockOnInterestHandler> handlerMap = new HashMap<Long, MockOnInterestHandler>();
andrewsbrown2304a342015-09-16 20:09:53 +010053 long lastPendingInterestId = 0;
54 long lastInterestFilterId = 0;
55 long lastRegisteredPrefixId = 0;
Andrew Brown3831baf2015-01-19 13:38:52 -080056
57 /**
58 * Create a new Face to mock communication over the network; all packets are
59 * maintained in memory
60 */
61 public MockFace() {
62 node_ = new Node(new MockTransport(), null);
63 }
64
65 /**
andrewsbrownebb72a82015-03-31 13:31:18 -070066 * @return a reference to the current MockTransport
67 */
68 public MockTransport getTransport() {
69 return (MockTransport) node_.getTransport();
70 }
71
72 /**
Andrew Brown3831baf2015-01-19 13:38:52 -080073 * Add a response Data packet to send immediately when an Interest with a
74 * matching name is received; will continue to respond with the same packet
75 * over multiple requests. This will preempt any registered OnInterest
76 * handlers.
77 *
78 * @param name
79 * @param data
80 */
81 public void addResponse(Name name, Data data) {
Andrew Brownec1b0d02015-02-21 13:11:42 -080082 logger.fine("Added response for: " + name.toUri());
Andrew Brown3831baf2015-01-19 13:38:52 -080083 responseMap.put(name.toUri(), data);
84 }
85
86 /**
87 * Stop sending a response for the given name.
88 *
89 * @param name
90 */
91 public void removeResponse(Name name) {
Andrew Brownec1b0d02015-02-21 13:11:42 -080092 logger.fine("Removed response for: " + name.toUri());
Andrew Brown3831baf2015-01-19 13:38:52 -080093 responseMap.remove(name);
94 }
95
96 /**
97 * Handle incoming Interest packets; when an Interest is expressed through
98 * expressInterest(), this will run to determine if: 1) any responses have
Andrew Brown8d8535b2015-01-19 15:22:06 -080099 * been registered or 2) if any OnInterest handlers have been registered. If
100 * one of these two succeeds, this method then re-directs the Interest from
Andrew Brown3831baf2015-01-19 13:38:52 -0800101 * traveling down the network stack and returns data.
Andrew Brown8d8535b2015-01-19 15:22:06 -0800102 *
Andrew Brown3831baf2015-01-19 13:38:52 -0800103 * @param interest
104 */
105 protected void handleIncomingRequests(Interest interest) {
106 String interestName = interest.getName().toUri();
107 long registeredPrefixId = findRegisteredHandler(interest);
108 // check if response registered
109 if (responseMap.containsKey(interestName)) {
Andrew Brownec1b0d02015-02-21 13:11:42 -0800110 logger.fine("Found response for: " + interestName);
Andrew Brown3831baf2015-01-19 13:38:52 -0800111 Data data = responseMap.get(interestName);
112 ((MockTransport) node_.getTransport()).respondWith(data);
Andrew Brown8d8535b2015-01-19 15:22:06 -0800113 } // check if handler registered
Andrew Brown3831baf2015-01-19 13:38:52 -0800114 else if (registeredPrefixId != -1) {
Andrew Brownec1b0d02015-02-21 13:11:42 -0800115 logger.fine("Found handler for: " + interestName);
Andrew Brown3831baf2015-01-19 13:38:52 -0800116 MockOnInterestHandler handler = handlerMap.get(findRegisteredHandler(interest));
andrewsbrown1f28bcf2015-04-20 13:29:20 -0700117 handler.signal(interest, registeredPrefixId);
Andrew Brown8d8535b2015-01-19 15:22:06 -0800118 } // log failure
Andrew Brown3831baf2015-01-19 13:38:52 -0800119 else {
Andrew Brownec1b0d02015-02-21 13:11:42 -0800120 logger.warning("No response found for interest (aborting): " + interestName);
Andrew Brown3831baf2015-01-19 13:38:52 -0800121 }
122 }
123
124 /**
125 * Find a handler that matches the incoming interest; currently, the only
126 * flags supported are the ChildInherit flags.
Andrew Brown8d8535b2015-01-19 15:22:06 -0800127 *
Andrew Brown3831baf2015-01-19 13:38:52 -0800128 * @param interest
Andrew Brown8d8535b2015-01-19 15:22:06 -0800129 * @return
Andrew Brown3831baf2015-01-19 13:38:52 -0800130 */
131 protected long findRegisteredHandler(Interest interest) {
132 for (Entry<Long, MockOnInterestHandler> entry : handlerMap.entrySet()) {
133 MockOnInterestHandler handler = entry.getValue();
134 if (handler.flags.getChildInherit() && handler.prefix.match(interest.getName())) {
135 return entry.getKey();
136 }
137 if (handler.prefix.equals(interest.getName())) {
138 return entry.getKey();
139 }
140 }
141 return -1;
142 }
143
144 /**
145 * Helper class for holding references to OnInterest handlers
146 */
147 class MockOnInterestHandler {
148
149 Name prefix;
150 OnInterest onInterest;
andrewsbrown1f28bcf2015-04-20 13:29:20 -0700151 OnInterestCallback onInterestCallback;
Andrew Brown3831baf2015-01-19 13:38:52 -0800152 ForwardingFlags flags;
153
154 public MockOnInterestHandler(Name prefix, OnInterest onInterest, ForwardingFlags flags) {
155 this.prefix = prefix;
156 this.onInterest = onInterest;
157 this.flags = flags;
158 }
andrewsbrown1f28bcf2015-04-20 13:29:20 -0700159
160 public MockOnInterestHandler(Name prefix, OnInterestCallback onInterestCallback, ForwardingFlags flags) {
161 this.prefix = prefix;
162 this.onInterestCallback = onInterestCallback;
163 this.flags = flags;
164 }
165
166 public void signal(Interest interest, long registeredPrefixId){
167 if(onInterest != null){
168 onInterest.onInterest(prefix, interest, node_.getTransport(), registeredPrefixId);
169 }
170 if(onInterestCallback != null){
171 onInterestCallback.onInterest(prefix, interest, MockFace.this, registeredPrefixId, null);
172 }
173 }
Andrew Brown3831baf2015-01-19 13:38:52 -0800174 }
175
176 /**
177 * Send the Interest through the transport, read the entire response and call
178 * onData(interest, data).
179 *
180 * @param interest The Interest to send. This copies the Interest.
181 * @param onData When a matching data packet is received, this calls
182 * onData.onData(interest, data) where interest is the interest given to
183 * expressInterest and data is the received Data object. NOTE: You must not
184 * change the interest object - if you need to change it then make a copy.
185 * @param onTimeout If the interest times out according to the interest
186 * lifetime, this calls onTimeout.onTimeout(interest) where interest is the
187 * interest given to expressInterest. If onTimeout is null, this does not use
188 * it.
189 * @param wireFormat A WireFormat object used to encode the message.
190 * @return The pending interest ID which can be used with
191 * removePendingInterest.
192 * @throws IOException For I/O error in sending the interest.
193 */
Andrew Brownb91e6902015-02-12 09:01:50 -0800194 @Override
Andrew Brown3831baf2015-01-19 13:38:52 -0800195 public long expressInterest(Interest interest, OnData onData, OnTimeout onTimeout,
196 WireFormat wireFormat) throws IOException {
andrewsbrown2304a342015-09-16 20:09:53 +0100197 long id = lastPendingInterestId++;
198 node_.expressInterest(id, interest, onData, onTimeout, wireFormat, this);
Andrew Brown3831baf2015-01-19 13:38:52 -0800199 handleIncomingRequests(interest);
200 return id;
201 }
202
203 /**
Andrew Brown3831baf2015-01-19 13:38:52 -0800204 * Register prefix with the connected NDN hub and call onInterest when a
205 * matching interest is received. If you have not called
206 * setCommandSigningInfo, this assumes you are connecting to NDNx. If you have
207 * called setCommandSigningInfo, this first sends an NFD registration request,
208 * and if that times out then this sends an NDNx registration request. If you
209 * need to register a prefix with NFD, you must first call
210 * setCommandSigningInfo.
211 *
212 * @param prefix A Name for the prefix to register. This copies the Name.
213 * @param onInterest When an interest is received which matches the name
214 * prefix, this calls onInterest.onInterest(prefix, interest, transport,
215 * registeredPrefixId). NOTE: You must not change the prefix object - if you
216 * need to change it then make a copy.
217 * @param onRegisterFailed If register prefix fails for any reason, this calls
218 * onRegisterFailed.onRegisterFailed(prefix).
219 * @param flags The flags for finer control of which interests are forwarded
220 * to the application.
221 * @param wireFormat A WireFormat object used to encode the message.
andrewsbrown2304a342015-09-16 20:09:53 +0100222 * @return The lastRegisteredPrefixId prefix ID which can be used with
223 removeRegisteredPrefix.
Andrew Brown3831baf2015-01-19 13:38:52 -0800224 * @throws IOException For I/O error in sending the registration request.
225 * @throws SecurityException If signing a command interest for NFD and cannot
226 * find the private key for the certificateName.
227 */
Andrew Brownb91e6902015-02-12 09:01:50 -0800228 @Override
Alexander Afanasyev8e9330f2016-01-25 19:13:40 -0800229 public long registerPrefix(Name prefix,
230 OnInterestCallback onInterest, OnRegisterFailed onRegisterFailed,
231 OnRegisterSuccess onRegisterSuccess, ForwardingFlags flags,
232 WireFormat wireFormat) throws IOException, net.named_data.jndn.security.SecurityException {
andrewsbrown1f28bcf2015-04-20 13:29:20 -0700233 // since we don't send an Interest, ensure the transport is connected
234 if (!getTransport().getIsConnected()) {
andrewsbrown2304a342015-09-16 20:09:53 +0100235 getTransport().connect(node_.getConnectionInfo(), node_, null);
andrewsbrown1f28bcf2015-04-20 13:29:20 -0700236 }
237
andrewsbrown2304a342015-09-16 20:09:53 +0100238 lastRegisteredPrefixId++;
239 handlerMap.put(lastRegisteredPrefixId, new MockOnInterestHandler(prefix, onInterest, flags));
240 return lastRegisteredPrefixId;
Andrew Brown3831baf2015-01-19 13:38:52 -0800241 }
242
243 /**
Andrew Brown3831baf2015-01-19 13:38:52 -0800244 * Process any packets to receive and call callbacks such as onData,
245 * onInterest or onTimeout. This returns immediately if there is no data to
246 * receive. This blocks while calling the callbacks. You should repeatedly
247 * call this from an event loop, with calls to sleep as needed so that the
248 * loop doesn’t use 100% of the CPU. Since processEvents modifies the pending
249 * interest table, your application should make sure that it calls
250 * processEvents in the same thread as expressInterest (which also modifies
251 * the pending interest table). This may throw an exception for reading data
252 * or in the callback for processing the data. If you call this from an main
253 * event loop, you may want to catch and log/disregard all exceptions.
254 */
Andrew Brownb91e6902015-02-12 09:01:50 -0800255 @Override
Andrew Brown3831baf2015-01-19 13:38:52 -0800256 public void processEvents() throws IOException, EncodingException {
257 // Just call Node's processEvents.
258 node_.processEvents();
259 }
260
andrewsbrown1f28bcf2015-04-20 13:29:20 -0700261 @Override
262 public void removeRegisteredPrefix(long registeredPrefixId) {
263 handlerMap.remove(registeredPrefixId);
264 }
265
266 @Override
267 public long setInterestFilter(InterestFilter filter, OnInterestCallback onInterest) {
andrewsbrown2304a342015-09-16 20:09:53 +0100268 long id = lastInterestFilterId++;
269 node_.setInterestFilter(id, filter, onInterest, this);
270 return id;
andrewsbrown1f28bcf2015-04-20 13:29:20 -0700271 }
272
273 @Override
274 public void unsetInterestFilter(long interestFilterId) {
andrewsbrown0f36eee2015-05-07 01:37:48 +0100275 node_.unsetInterestFilter(interestFilterId);
andrewsbrown1f28bcf2015-04-20 13:29:20 -0700276 }
277
278 @Override
279 public void putData(Data data, WireFormat wireFormat) throws IOException {
280 node_.putData(data, wireFormat);
281 }
282
283 @Override
284 public void send(ByteBuffer encoding) throws IOException {
285 node_.send(encoding);
286 }
287
288 @Override
289 public boolean isLocal() throws IOException {
290 return true;
291 }
292
293 @Override
294 public void shutdown() {
295 node_.shutdown();
296 }
297
Andrew Brown3831baf2015-01-19 13:38:52 -0800298}