blob: f469b90677f32b4fcfb90016cb18b40b960e5252 [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;
Andrew Browndb457052015-02-21 15:41:58 -080017import java.io.IOException;
18import java.util.ArrayList;
19import java.util.List;
20import java.util.concurrent.ExecutionException;
andrewsbrown69d53292015-03-17 19:37:34 +010021import java.util.concurrent.Future;
andrewsbrown0cf35f92015-03-09 12:00:00 -070022import java.util.logging.Level;
Andrew Browndb457052015-02-21 15:41:58 -080023import java.util.logging.Logger;
24import net.named_data.jndn.Data;
25import net.named_data.jndn.Face;
26import net.named_data.jndn.Interest;
27import net.named_data.jndn.Name;
28import net.named_data.jndn.encoding.EncodingException;
Andrew Browndb457052015-02-21 15:41:58 -080029
30/**
31 * Provide a client to simplify retrieving segmented Data packets over the NDN
32 * network. This class expects the Data producer to follow the NDN naming
33 * conventions (see http://named-data.net/doc/tech-memos/naming-conventions.pdf)
34 * and produce Data packets with a valid segment as the last component of their
35 * name; additionally, at least the first packet should set the FinalBlockId of
36 * the packet's MetaInfo (see
37 * http://named-data.net/doc/ndn-tlv/data.html#finalblockid).
38 *
39 * @author Andrew Brown <andrew.brown@intel.com>
40 */
andrewsbrown69d53292015-03-17 19:37:34 +010041public class SegmentedClient implements Client {
Andrew Browndb457052015-02-21 15:41:58 -080042
43 private static SegmentedClient defaultInstance;
44 private static final Logger logger = Logger.getLogger(SegmentedClient.class.getName());
Andrew Browndb457052015-02-21 15:41:58 -080045
46 /**
andrewsbrown69d53292015-03-17 19:37:34 +010047 * Singleton access for simpler client use.
Andrew Browndb457052015-02-21 15:41:58 -080048 *
49 * @return
50 */
51 public static SegmentedClient getDefault() {
52 if (defaultInstance == null) {
53 defaultInstance = new SegmentedClient();
54 }
55 return defaultInstance;
56 }
57
58 /**
59 * Asynchronously send Interest packets for a segmented result; will block
60 * until the first packet is received and then send remaining interests until
61 * the specified FinalBlockId.
62 *
63 * @param face
64 * @param interest should include either a ChildSelector or an initial segment
andrewsbrownb005ee62015-03-31 14:45:54 -070065 * number; the initial segment number will be cut off in the de-segmented
66 * packet.
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);
andrewsbrownb005ee62015-03-31 14:45:54 -070073 Name name = hasSegment(interest.getName()) ? interest.getName().getPrefix(-1) : interest.getName();
74 return new SegmentedFutureData(name, segments);
andrewsbrown69d53292015-03-17 19:37:34 +010075 }
76
andrewsbrownb005ee62015-03-31 14:45:54 -070077 /**
andrewsbrown69d53292015-03-17 19:37:34 +010078 * Asynchronously send Interest packets for a segmented result; will block
79 * until the first packet is received and then send remaining interests until
80 * the specified FinalBlockId.
81 *
82 * @param face
andrewsbrownb005ee62015-03-31 14:45:54 -070083 * @param name the {@link Name} of the packet to retrieve using a default
84 * interest
andrewsbrown69d53292015-03-17 19:37:34 +010085 * @return an aggregated data packet from all received segments
86 */
87 public Future<Data> getAsync(Face face, Name name) {
88 return getAsync(face, SimpleClient.getDefaultInterest(name));
89 }
90
91 /**
92 * Asynchronously send Interest packets for a segmented result; will block
93 * until the first packet is received and then send remaining interests until
94 * the specified FinalBlockId.
95 *
96 * @param face
97 * @param interest should include either a ChildSelector or an initial segment
98 * number
99 * @return a list of FutureData packets; if the first segment fails, the list
100 * will contain one FutureData with the failure exception
101 */
102 public List<Future<Data>> getAsyncList(Face face, Interest interest) {
Andrew Browndb457052015-02-21 15:41:58 -0800103 // get first segment; default 0 or use a specified start segment
104 long firstSegment = 0;
105 boolean specifiedSegment = false;
106 try {
107 firstSegment = interest.getName().get(-1).toSegment();
108 specifiedSegment = true;
109 } catch (EncodingException e) {
110 // check for interest selector if no initial segment found
111 if (interest.getChildSelector() == -1) {
andrewsbrown0cf35f92015-03-09 12:00:00 -0700112 logger.log(Level.WARNING, "No child selector set for a segmented Interest; this may result in incorrect retrieval.");
andrewsbrown69d53292015-03-17 19:37:34 +0100113 // allow this interest to pass without a segment marker since it may still succeed
Andrew Browndb457052015-02-21 15:41:58 -0800114 }
115 }
116
117 // setup segments
andrewsbrown69d53292015-03-17 19:37:34 +0100118 final List<Future<Data>> segments = new ArrayList<>();
119 segments.add(SimpleClient.getDefault().getAsync(face, interest));
Andrew Browndb457052015-02-21 15:41:58 -0800120
121 // retrieve first packet to find last segment value
122 long lastSegment;
123 try {
124 lastSegment = segments.get(0).get().getMetaInfo().getFinalBlockId().toSegment();
125 } catch (ExecutionException | InterruptedException | EncodingException e) {
andrewsbrown0cf35f92015-03-09 12:00:00 -0700126 logger.log(Level.SEVERE, "Failed to retrieve first segment: ", e);
127 return segments;
Andrew Browndb457052015-02-21 15:41:58 -0800128 }
129
130 // cut interest segment off
131 if (specifiedSegment) {
132 interest.setName(interest.getName().getPrefix(-1));
133 }
134
135 // send interests in remaining segments
136 for (long i = firstSegment + 1; i <= lastSegment; i++) {
137 Interest segmentedInterest = new Interest(interest);
138 segmentedInterest.getName().appendSegment(i);
andrewsbrown69d53292015-03-17 19:37:34 +0100139 Future<Data> futureData = SimpleClient.getDefault().getAsync(face, segmentedInterest);
Andrew Browndb457052015-02-21 15:41:58 -0800140 segments.add((int) i, futureData);
141 }
142
143 return segments;
144 }
145
146 /**
147 * Asynchronously send Interests for a segmented Data packet using a default
148 * interest (e.g. 2 second timeout); this will block until complete (i.e.
andrewsbrown0cf35f92015-03-09 12:00:00 -0700149 * either data is received or the interest times out). See getAsync(Face face)
150 * for more information.
Andrew Browndb457052015-02-21 15:41:58 -0800151 *
152 * @param face
153 * @param name
154 * @return
155 */
andrewsbrown69d53292015-03-17 19:37:34 +0100156 public List<Future<Data>> getAsyncList(Face face, Name name) {
157 return getAsyncList(face, SimpleClient.getDefaultInterest(name));
Andrew Browndb457052015-02-21 15:41:58 -0800158 }
159
160 /**
161 * Retrieve a segmented Data packet; will block until all segments are
162 * received and will re-assemble these.
163 *
164 * @param face
165 * @param interest should include either a ChildSelector or an initial segment
166 * number
andrewsbrown0cf35f92015-03-09 12:00:00 -0700167 * @return a Data packet; the name will inherit from the sent Interest, not
andrewsbrown69d53292015-03-17 19:37:34 +0100168 * the returned packets and the content will be a concatenation of all of the
169 * packet contents.
170 * @throws java.io.IOException
Andrew Browndb457052015-02-21 15:41:58 -0800171 */
andrewsbrown69d53292015-03-17 19:37:34 +0100172 @Override
andrewsbrownb005ee62015-03-31 14:45:54 -0700173 public Data getSync(Face face, Interest interest) throws IOException {
andrewsbrown69d53292015-03-17 19:37:34 +0100174 try {
175 return getAsync(face, interest).get();
176 } catch (ExecutionException | InterruptedException e) {
177 logger.log(Level.WARNING, "Failed to retrieve data.", e);
178 throw new IOException("Failed to retrieve data.", e);
Andrew Browndb457052015-02-21 15:41:58 -0800179 }
Andrew Browndb457052015-02-21 15:41:58 -0800180 }
181
182 /**
183 * Synchronously retrieve the Data for a Name using a default interest (e.g. 2
184 * second timeout); this will block until complete (i.e. either data is
andrewsbrown0cf35f92015-03-09 12:00:00 -0700185 * received or the interest times out). See getSync(Face face) for more
186 * information.
Andrew Browndb457052015-02-21 15:41:58 -0800187 *
188 * @param face
189 * @param name
190 * @return
andrewsbrown69d53292015-03-17 19:37:34 +0100191 * @throws java.io.IOException
Andrew Browndb457052015-02-21 15:41:58 -0800192 */
andrewsbrown69d53292015-03-17 19:37:34 +0100193 public Data getSync(Face face, Name name) throws IOException {
194 return getSync(face, SimpleClient.getDefaultInterest(name));
Andrew Browndb457052015-02-21 15:41:58 -0800195 }
196
197 /**
198 * Check if a name ends in a segment component; uses marker value found in the
199 * NDN naming conventions (see
200 * http://named-data.net/doc/tech-memos/naming-conventions.pdf).
201 *
202 * @param name
203 * @return
204 */
205 public static boolean hasSegment(Name name) {
206 return name.get(-1).getValue().buf().get(0) == 0x00;
207 }
Andrew Browndb457052015-02-21 15:41:58 -0800208}