blob: 40ef7bb8bfef5a584ea4db3407fcd2ef3d388c2e [file] [log] [blame]
Andrew Browndb457052015-02-21 15:41:58 -08001/*
andrewsbrown4feb2da2015-03-03 16:05:29 -08002 * jndn-utils
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 Browndb457052015-02-21 15:41:58 -080013 */
14package com.intel.jndn.utils;
15
andrewsbrown69d53292015-03-17 19:37:34 +010016import com.intel.jndn.utils.client.SegmentedFutureData;
17import com.intel.jndn.utils.client.FutureData;
Andrew Browndb457052015-02-21 15:41:58 -080018import java.io.IOException;
19import java.util.ArrayList;
20import java.util.List;
21import java.util.concurrent.ExecutionException;
andrewsbrown69d53292015-03-17 19:37:34 +010022import java.util.concurrent.Future;
andrewsbrown0cf35f92015-03-09 12:00:00 -070023import java.util.logging.Level;
Andrew Browndb457052015-02-21 15:41:58 -080024import java.util.logging.Logger;
25import net.named_data.jndn.Data;
26import net.named_data.jndn.Face;
27import net.named_data.jndn.Interest;
28import net.named_data.jndn.Name;
29import net.named_data.jndn.encoding.EncodingException;
Andrew Browndb457052015-02-21 15:41:58 -080030
31/**
32 * Provide a client to simplify retrieving segmented Data packets over the NDN
33 * network. This class expects the Data producer to follow the NDN naming
34 * conventions (see http://named-data.net/doc/tech-memos/naming-conventions.pdf)
35 * and produce Data packets with a valid segment as the last component of their
36 * name; additionally, at least the first packet should set the FinalBlockId of
37 * the packet's MetaInfo (see
38 * http://named-data.net/doc/ndn-tlv/data.html#finalblockid).
39 *
40 * @author Andrew Brown <andrew.brown@intel.com>
41 */
andrewsbrown69d53292015-03-17 19:37:34 +010042public class SegmentedClient implements Client {
Andrew Browndb457052015-02-21 15:41:58 -080043
44 private static SegmentedClient defaultInstance;
45 private static final Logger logger = Logger.getLogger(SegmentedClient.class.getName());
Andrew Browndb457052015-02-21 15:41:58 -080046
47 /**
andrewsbrown69d53292015-03-17 19:37:34 +010048 * Singleton access for simpler client use.
Andrew Browndb457052015-02-21 15:41:58 -080049 *
50 * @return
51 */
52 public static SegmentedClient getDefault() {
53 if (defaultInstance == null) {
54 defaultInstance = new SegmentedClient();
55 }
56 return defaultInstance;
57 }
58
59 /**
60 * Asynchronously send Interest packets for a segmented result; will block
61 * until the first packet is received and then send remaining interests until
62 * the specified FinalBlockId.
63 *
64 * @param face
65 * @param interest should include either a ChildSelector or an initial segment
66 * number
andrewsbrown0cf35f92015-03-09 12:00:00 -070067 * @return a list of FutureData packets; if the first segment fails, the list
68 * will contain one FutureData with the failure exception
Andrew Browndb457052015-02-21 15:41:58 -080069 */
andrewsbrown69d53292015-03-17 19:37:34 +010070 @Override
71 public Future<Data> getAsync(Face face, Interest interest) {
72 List<Future<Data>> segments = getAsyncList(face, interest);
73 return new SegmentedFutureData(interest.getName().getPrefix(-1), segments);
74 }
75
76 /**
77 * Asynchronously send Interest packets for a segmented result; will block
78 * until the first packet is received and then send remaining interests until
79 * the specified FinalBlockId.
80 *
81 * @param face
82 * @param name
83 * @return an aggregated data packet from all received segments
84 */
85 public Future<Data> getAsync(Face face, Name name) {
86 return getAsync(face, SimpleClient.getDefaultInterest(name));
87 }
88
89 /**
90 * Asynchronously send Interest packets for a segmented result; will block
91 * until the first packet is received and then send remaining interests until
92 * the specified FinalBlockId.
93 *
94 * @param face
95 * @param interest should include either a ChildSelector or an initial segment
96 * number
97 * @return a list of FutureData packets; if the first segment fails, the list
98 * will contain one FutureData with the failure exception
99 */
100 public List<Future<Data>> getAsyncList(Face face, Interest interest) {
Andrew Browndb457052015-02-21 15:41:58 -0800101 // get first segment; default 0 or use a specified start segment
102 long firstSegment = 0;
103 boolean specifiedSegment = false;
104 try {
105 firstSegment = interest.getName().get(-1).toSegment();
106 specifiedSegment = true;
107 } catch (EncodingException e) {
108 // check for interest selector if no initial segment found
109 if (interest.getChildSelector() == -1) {
andrewsbrown0cf35f92015-03-09 12:00:00 -0700110 logger.log(Level.WARNING, "No child selector set for a segmented Interest; this may result in incorrect retrieval.");
andrewsbrown69d53292015-03-17 19:37:34 +0100111 // allow this interest to pass without a segment marker since it may still succeed
Andrew Browndb457052015-02-21 15:41:58 -0800112 }
113 }
114
115 // setup segments
andrewsbrown69d53292015-03-17 19:37:34 +0100116 final List<Future<Data>> segments = new ArrayList<>();
117 segments.add(SimpleClient.getDefault().getAsync(face, interest));
Andrew Browndb457052015-02-21 15:41:58 -0800118
119 // retrieve first packet to find last segment value
120 long lastSegment;
121 try {
122 lastSegment = segments.get(0).get().getMetaInfo().getFinalBlockId().toSegment();
123 } catch (ExecutionException | InterruptedException | EncodingException e) {
andrewsbrown0cf35f92015-03-09 12:00:00 -0700124 logger.log(Level.SEVERE, "Failed to retrieve first segment: ", e);
125 return segments;
Andrew Browndb457052015-02-21 15:41:58 -0800126 }
127
128 // cut interest segment off
129 if (specifiedSegment) {
130 interest.setName(interest.getName().getPrefix(-1));
131 }
132
133 // send interests in remaining segments
134 for (long i = firstSegment + 1; i <= lastSegment; i++) {
135 Interest segmentedInterest = new Interest(interest);
136 segmentedInterest.getName().appendSegment(i);
andrewsbrown69d53292015-03-17 19:37:34 +0100137 Future<Data> futureData = SimpleClient.getDefault().getAsync(face, segmentedInterest);
Andrew Browndb457052015-02-21 15:41:58 -0800138 segments.add((int) i, futureData);
139 }
140
141 return segments;
142 }
143
144 /**
145 * Asynchronously send Interests for a segmented Data packet using a default
146 * interest (e.g. 2 second timeout); this will block until complete (i.e.
andrewsbrown0cf35f92015-03-09 12:00:00 -0700147 * either data is received or the interest times out). See getAsync(Face face)
148 * for more information.
Andrew Browndb457052015-02-21 15:41:58 -0800149 *
150 * @param face
151 * @param name
152 * @return
153 */
andrewsbrown69d53292015-03-17 19:37:34 +0100154 public List<Future<Data>> getAsyncList(Face face, Name name) {
155 return getAsyncList(face, SimpleClient.getDefaultInterest(name));
Andrew Browndb457052015-02-21 15:41:58 -0800156 }
157
158 /**
159 * Retrieve a segmented Data packet; will block until all segments are
160 * received and will re-assemble these.
161 *
162 * @param face
163 * @param interest should include either a ChildSelector or an initial segment
164 * number
andrewsbrown0cf35f92015-03-09 12:00:00 -0700165 * @return a Data packet; the name will inherit from the sent Interest, not
andrewsbrown69d53292015-03-17 19:37:34 +0100166 * the returned packets and the content will be a concatenation of all of the
167 * packet contents.
168 * @throws java.io.IOException
Andrew Browndb457052015-02-21 15:41:58 -0800169 */
andrewsbrown69d53292015-03-17 19:37:34 +0100170 @Override
171 public Data getSync(Face face, Interest interest) throws IOException {
172 try {
173 return getAsync(face, interest).get();
174 } catch (ExecutionException | InterruptedException e) {
175 logger.log(Level.WARNING, "Failed to retrieve data.", e);
176 throw new IOException("Failed to retrieve data.", e);
Andrew Browndb457052015-02-21 15:41:58 -0800177 }
Andrew Browndb457052015-02-21 15:41:58 -0800178 }
179
180 /**
181 * Synchronously retrieve the Data for a Name using a default interest (e.g. 2
182 * second timeout); this will block until complete (i.e. either data is
andrewsbrown0cf35f92015-03-09 12:00:00 -0700183 * received or the interest times out). See getSync(Face face) for more
184 * information.
Andrew Browndb457052015-02-21 15:41:58 -0800185 *
186 * @param face
187 * @param name
188 * @return
andrewsbrown69d53292015-03-17 19:37:34 +0100189 * @throws java.io.IOException
Andrew Browndb457052015-02-21 15:41:58 -0800190 */
andrewsbrown69d53292015-03-17 19:37:34 +0100191 public Data getSync(Face face, Name name) throws IOException {
192 return getSync(face, SimpleClient.getDefaultInterest(name));
Andrew Browndb457052015-02-21 15:41:58 -0800193 }
194
195 /**
196 * Check if a name ends in a segment component; uses marker value found in the
197 * NDN naming conventions (see
198 * http://named-data.net/doc/tech-memos/naming-conventions.pdf).
199 *
200 * @param name
201 * @return
202 */
203 public static boolean hasSegment(Name name) {
204 return name.get(-1).getValue().buf().get(0) == 0x00;
205 }
Andrew Browndb457052015-02-21 15:41:58 -0800206}