blob: 61b1a8edd23ee22d5ce7d56711cdbf067e5c49e9 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
tom5f38b3a2014-08-27 23:50:54 -070016package org.onlab.util;
17
Madan Jampani2bfa94c2015-04-11 05:03:49 -070018import static java.nio.file.Files.delete;
19import static java.nio.file.Files.walkFileTree;
20import static org.onlab.util.GroupedThreadFactory.groupedThreadFactory;
21import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080022
tom53efab52014-10-07 17:43:48 -070023import java.io.BufferedReader;
24import java.io.File;
Ray Milkey705d9bc2014-11-18 08:19:00 -080025import java.io.FileInputStream;
tom53efab52014-10-07 17:43:48 -070026import java.io.IOException;
Ray Milkey705d9bc2014-11-18 08:19:00 -080027import java.io.InputStreamReader;
Madan Jampani27b69c62015-05-15 15:49:02 -070028import java.nio.ByteBuffer;
Ray Milkey705d9bc2014-11-18 08:19:00 -080029import java.nio.charset.StandardCharsets;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080030import java.nio.file.FileVisitResult;
Thomas Vachuska90b453f2015-01-30 18:57:14 -080031import java.nio.file.Files;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080032import java.nio.file.Path;
33import java.nio.file.Paths;
34import java.nio.file.SimpleFileVisitor;
Thomas Vachuska90b453f2015-01-30 18:57:14 -080035import java.nio.file.StandardCopyOption;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080036import java.nio.file.attribute.BasicFileAttributes;
tom53efab52014-10-07 17:43:48 -070037import java.util.ArrayList;
Madan Jampani27b69c62015-05-15 15:49:02 -070038import java.util.Arrays;
Brian O'Connore2eac102015-02-12 18:30:22 -080039import java.util.Collection;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070040import java.util.Dictionary;
tom53efab52014-10-07 17:43:48 -070041import java.util.List;
Thomas Vachuskaadba1522015-06-04 15:08:30 -070042import java.util.Random;
Ray Milkey36992c82015-11-17 13:31:15 -080043import java.util.Set;
Madan Jampani27b69c62015-05-15 15:49:02 -070044import java.util.concurrent.CompletableFuture;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070045import java.util.concurrent.ExecutionException;
46import java.util.concurrent.Future;
tom5f38b3a2014-08-27 23:50:54 -070047import java.util.concurrent.ThreadFactory;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070048import java.util.concurrent.TimeUnit;
49import java.util.concurrent.TimeoutException;
Madan Jampania29c6772015-08-17 13:17:07 -070050import java.util.function.Function;
51import java.util.function.Supplier;
Sho SHIMIZU85803e22016-01-13 21:53:43 -080052import java.util.stream.Collectors;
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -070053import java.util.stream.Stream;
54import java.util.stream.StreamSupport;
tom5f38b3a2014-08-27 23:50:54 -070055
Madan Jampani2bfa94c2015-04-11 05:03:49 -070056import org.slf4j.Logger;
57
Madan Jampanif2f086c2016-01-13 16:15:39 -080058import com.google.common.base.Charsets;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070059import com.google.common.base.Strings;
60import com.google.common.primitives.UnsignedLongs;
61import com.google.common.util.concurrent.ThreadFactoryBuilder;
Ray Milkey705d9bc2014-11-18 08:19:00 -080062
Thomas Vachuskac13b90a2015-02-18 18:19:55 -080063/**
64 * Miscellaneous utility methods.
65 */
tom5f38b3a2014-08-27 23:50:54 -070066public abstract class Tools {
67
68 private Tools() {
69 }
70
Thomas Vachuska02aeb032015-01-06 22:36:30 -080071 private static final Logger log = getLogger(Tools.class);
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080072
Thomas Vachuskaadba1522015-06-04 15:08:30 -070073 private static Random random = new Random();
74
tom5f38b3a2014-08-27 23:50:54 -070075 /**
76 * Returns a thread factory that produces threads named according to the
77 * supplied name pattern.
78 *
79 * @param pattern name pattern
80 * @return thread factory
81 */
82 public static ThreadFactory namedThreads(String pattern) {
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080083 return new ThreadFactoryBuilder()
84 .setNameFormat(pattern)
Thomas Vachuska480adad2015-03-06 10:27:09 -080085 .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on " + t.getName(), e))
86 .build();
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080087 }
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080088
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080089 /**
90 * Returns a thread factory that produces threads named according to the
91 * supplied name pattern and from the specified thread-group. The thread
92 * group name is expected to be specified in slash-delimited format, e.g.
Thomas Vachuskac13b90a2015-02-18 18:19:55 -080093 * {@code onos/intent}. The thread names will be produced by converting
94 * the thread group name into dash-delimited format and pre-pended to the
95 * specified pattern.
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080096 *
97 * @param groupName group name in slash-delimited format to indicate hierarchy
98 * @param pattern name pattern
99 * @return thread factory
100 */
101 public static ThreadFactory groupedThreads(String groupName, String pattern) {
102 return new ThreadFactoryBuilder()
103 .setThreadFactory(groupedThreadFactory(groupName))
Thomas Vachuskac13b90a2015-02-18 18:19:55 -0800104 .setNameFormat(groupName.replace(GroupedThreadFactory.DELIMITER, "-") + "-" + pattern)
Thomas Vachuska480adad2015-03-06 10:27:09 -0800105 .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on " + t.getName(), e))
106 .build();
tom5f38b3a2014-08-27 23:50:54 -0700107 }
108
tom782a7cf2014-09-11 23:58:38 -0700109 /**
Yuta HIGUCHI06586272014-11-25 14:27:03 -0800110 * Returns a thread factory that produces threads with MIN_PRIORITY.
111 *
112 * @param factory backing ThreadFactory
113 * @return thread factory
114 */
115 public static ThreadFactory minPriority(ThreadFactory factory) {
116 return new ThreadFactoryBuilder()
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800117 .setThreadFactory(factory)
118 .setPriority(Thread.MIN_PRIORITY)
119 .build();
Yuta HIGUCHI06586272014-11-25 14:27:03 -0800120 }
121
122 /**
Brian O'Connore2eac102015-02-12 18:30:22 -0800123 * Returns true if the collection is null or is empty.
124 *
125 * @param collection collection to test
126 * @return true if null or empty; false otherwise
127 */
128 public static boolean isNullOrEmpty(Collection collection) {
129 return collection == null || collection.isEmpty();
130 }
131
132 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700133 * Returns the specified item if that item is not null; otherwise throws
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700134 * not found exception.
135 *
136 * @param item item to check
137 * @param message not found message
138 * @param <T> item type
139 * @return item if not null
140 * @throws org.onlab.util.ItemNotFoundException if item is null
141 */
142 public static <T> T nullIsNotFound(T item, String message) {
143 if (item == null) {
144 throw new ItemNotFoundException(message);
145 }
146 return item;
147 }
148
149 /**
Ray Milkey36992c82015-11-17 13:31:15 -0800150 * Returns the specified set if the set is not null and not empty;
151 * otherwise throws a not found exception.
152 *
153 * @param item set to check
154 * @param message not found message
155 * @param <T> Set item type
156 * @return item if not null and not empty
157 * @throws org.onlab.util.ItemNotFoundException if set is null or empty
158 */
159 public static <T> Set<T> emptyIsNotFound(Set<T> item, String message) {
160 if (item == null || item.isEmpty()) {
161 throw new ItemNotFoundException(message);
162 }
163 return item;
164 }
165
166 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700167 * Returns the specified item if that item is not null; otherwise throws
168 * bad argument exception.
169 *
170 * @param item item to check
171 * @param message not found message
172 * @param <T> item type
173 * @return item if not null
174 * @throws IllegalArgumentException if item is null
175 */
176 public static <T> T nullIsIllegal(T item, String message) {
177 if (item == null) {
178 throw new IllegalArgumentException(message);
179 }
180 return item;
181 }
182
183 /**
tom782a7cf2014-09-11 23:58:38 -0700184 * Converts a string from hex to long.
185 *
186 * @param string hex number in string form; sans 0x
187 * @return long value
188 */
189 public static long fromHex(String string) {
190 return UnsignedLongs.parseUnsignedLong(string, 16);
191 }
192
193 /**
194 * Converts a long value to hex string; 16 wide and sans 0x.
195 *
196 * @param value long value
197 * @return hex string
198 */
199 public static String toHex(long value) {
200 return Strings.padStart(UnsignedLongs.toString(value, 16), 16, '0');
201 }
202
203 /**
204 * Converts a long value to hex string; 16 wide and sans 0x.
205 *
206 * @param value long value
207 * @param width string width; zero padded
208 * @return hex string
209 */
210 public static String toHex(long value, int width) {
211 return Strings.padStart(UnsignedLongs.toString(value, 16), width, '0');
212 }
tomf110fff2014-09-26 00:38:18 -0700213
214 /**
Madan Jampanif2f086c2016-01-13 16:15:39 -0800215 * Returns the UTF-8 encoded byte[] representation of a String.
Jian Lidfba7392016-01-22 16:46:58 -0800216 * @param input input string
217 * @return UTF-8 encoded byte array
Madan Jampanif2f086c2016-01-13 16:15:39 -0800218 */
219 public static byte[] getBytesUtf8(String input) {
220 return input.getBytes(Charsets.UTF_8);
221 }
222
223 /**
224 * Returns the String representation of UTF-8 encoded byte[].
Jian Lidfba7392016-01-22 16:46:58 -0800225 * @param input input byte array
226 * @return UTF-8 encoded string
Madan Jampanif2f086c2016-01-13 16:15:39 -0800227 */
228 public static String toStringUtf8(byte[] input) {
229 return new String(input, Charsets.UTF_8);
230 }
231
232 /**
Madan Jampani9eb55d12015-08-14 07:47:56 -0700233 * Returns a copy of the input byte array.
234 *
235 * @param original input
236 * @return copy of original
237 */
238 public static byte[] copyOf(byte[] original) {
239 return Arrays.copyOf(original, original.length);
240 }
241
242 /**
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700243 * Get property as a string value.
244 *
245 * @param properties properties to be looked up
246 * @param propertyName the name of the property to look up
247 * @return value when the propertyName is defined or return null
248 */
249 public static String get(Dictionary<?, ?> properties, String propertyName) {
250 Object v = properties.get(propertyName);
251 String s = (v instanceof String) ? (String) v :
252 v != null ? v.toString() : null;
253 return Strings.isNullOrEmpty(s) ? null : s.trim();
254 }
255
256 /**
tomf110fff2014-09-26 00:38:18 -0700257 * Suspends the current thread for a specified number of millis.
258 *
259 * @param ms number of millis
260 */
261 public static void delay(int ms) {
262 try {
263 Thread.sleep(ms);
264 } catch (InterruptedException e) {
265 throw new RuntimeException("Interrupted", e);
266 }
267 }
268
tom53efab52014-10-07 17:43:48 -0700269 /**
Madan Jampania29c6772015-08-17 13:17:07 -0700270 * Returns a function that retries execution on failure.
271 * @param base base function
272 * @param exceptionClass type of exception for which to retry
273 * @param maxRetries max number of retries before giving up
274 * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from
275 * the interval (0, maxDelayBetweenRetries]
276 * @return function
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700277 * @param <U> type of function input
278 * @param <V> type of function output
Madan Jampania29c6772015-08-17 13:17:07 -0700279 */
280 public static <U, V> Function<U, V> retryable(Function<U, V> base,
281 Class<? extends Throwable> exceptionClass,
282 int maxRetries,
283 int maxDelayBetweenRetries) {
284 return new RetryingFunction<>(base, exceptionClass, maxRetries, maxDelayBetweenRetries);
285 }
286
287 /**
288 * Returns a Supplier that retries execution on failure.
289 * @param base base supplier
290 * @param exceptionClass type of exception for which to retry
291 * @param maxRetries max number of retries before giving up
292 * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from
293 * the interval (0, maxDelayBetweenRetries]
294 * @return supplier
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700295 * @param <V> type of supplied result
Madan Jampania29c6772015-08-17 13:17:07 -0700296 */
297 public static <V> Supplier<V> retryable(Supplier<V> base,
298 Class<? extends Throwable> exceptionClass,
299 int maxRetries,
300 int maxDelayBetweenRetries) {
301 return () -> new RetryingFunction<>(v -> base.get(),
302 exceptionClass,
303 maxRetries,
304 maxDelayBetweenRetries).apply(null);
305 }
306
307 /**
Thomas Vachuskaadba1522015-06-04 15:08:30 -0700308 * Suspends the current thread for a random number of millis between 0 and
309 * the indicated limit.
310 *
311 * @param ms max number of millis
312 */
313 public static void randomDelay(int ms) {
314 try {
315 Thread.sleep(random.nextInt(ms));
316 } catch (InterruptedException e) {
317 throw new RuntimeException("Interrupted", e);
318 }
319 }
320
321 /**
Thomas Vachuskac40d4632015-04-09 16:55:03 -0700322 * Suspends the current thread for a specified number of millis and nanos.
323 *
324 * @param ms number of millis
325 * @param nanos number of nanos
326 */
327 public static void delay(int ms, int nanos) {
328 try {
329 Thread.sleep(ms, nanos);
330 } catch (InterruptedException e) {
331 throw new RuntimeException("Interrupted", e);
332 }
333 }
334
335 /**
tom53efab52014-10-07 17:43:48 -0700336 * Slurps the contents of a file into a list of strings, one per line.
337 *
338 * @param path file path
339 * @return file contents
HIGUCHI Yuta3b3bd1e2015-09-22 16:39:33 -0700340 * @deprecated in Emu release
tom53efab52014-10-07 17:43:48 -0700341 */
HIGUCHI Yuta3b3bd1e2015-09-22 16:39:33 -0700342 @Deprecated
tom53efab52014-10-07 17:43:48 -0700343 public static List<String> slurp(File path) {
HIGUCHI Yutacf4d6172015-09-22 16:39:33 -0700344 try (
Ray Milkey705d9bc2014-11-18 08:19:00 -0800345 BufferedReader br = new BufferedReader(
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800346 new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8));
HIGUCHI Yutacf4d6172015-09-22 16:39:33 -0700347 ) {
tom53efab52014-10-07 17:43:48 -0700348 List<String> lines = new ArrayList<>();
349 String line;
350 while ((line = br.readLine()) != null) {
351 lines.add(line);
352 }
353 return lines;
354
355 } catch (IOException e) {
356 return null;
357 }
358 }
359
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800360 /**
361 * Purges the specified directory path.&nbsp;Use with great caution since
362 * no attempt is made to check for symbolic links, which could result in
363 * deletion of unintended files.
364 *
365 * @param path directory to be removed
366 * @throws java.io.IOException if unable to remove contents
367 */
368 public static void removeDirectory(String path) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800369 DirectoryDeleter visitor = new DirectoryDeleter();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700370 File dir = new File(path);
371 if (dir.exists() && dir.isDirectory()) {
372 walkFileTree(Paths.get(path), visitor);
373 if (visitor.exception != null) {
374 throw visitor.exception;
375 }
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800376 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800377 }
378
379 /**
380 * Purges the specified directory path.&nbsp;Use with great caution since
381 * no attempt is made to check for symbolic links, which could result in
382 * deletion of unintended files.
383 *
384 * @param dir directory to be removed
385 * @throws java.io.IOException if unable to remove contents
386 */
387 public static void removeDirectory(File dir) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800388 DirectoryDeleter visitor = new DirectoryDeleter();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700389 if (dir.exists() && dir.isDirectory()) {
390 walkFileTree(Paths.get(dir.getAbsolutePath()), visitor);
391 if (visitor.exception != null) {
392 throw visitor.exception;
393 }
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800394 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800395 }
396
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800397 // Auxiliary path visitor for recursive directory structure removal.
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800398 private static class DirectoryDeleter extends SimpleFileVisitor<Path> {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800399
400 private IOException exception;
401
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800402 @Override
403 public FileVisitResult visitFile(Path file, BasicFileAttributes attributes)
404 throws IOException {
405 if (attributes.isRegularFile()) {
406 delete(file);
407 }
408 return FileVisitResult.CONTINUE;
409 }
410
411 @Override
412 public FileVisitResult postVisitDirectory(Path directory, IOException ioe)
413 throws IOException {
414 delete(directory);
415 return FileVisitResult.CONTINUE;
416 }
417
418 @Override
419 public FileVisitResult visitFileFailed(Path file, IOException ioe)
420 throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800421 this.exception = ioe;
422 return FileVisitResult.TERMINATE;
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800423 }
424 }
425
Madan Jampani30a57f82015-03-02 12:19:41 -0800426 /**
427 * Returns a human friendly time ago string for a specified system time.
Thomas Vachuska480adad2015-03-06 10:27:09 -0800428 *
Madan Jampani30a57f82015-03-02 12:19:41 -0800429 * @param unixTime system time in millis
430 * @return human friendly time ago
431 */
432 public static String timeAgo(long unixTime) {
433 long deltaMillis = System.currentTimeMillis() - unixTime;
434 long secondsSince = (long) (deltaMillis / 1000.0);
435 long minsSince = (long) (deltaMillis / (1000.0 * 60));
436 long hoursSince = (long) (deltaMillis / (1000.0 * 60 * 60));
437 long daysSince = (long) (deltaMillis / (1000.0 * 60 * 60 * 24));
438 if (daysSince > 0) {
439 return String.format("%dd ago", daysSince);
440 } else if (hoursSince > 0) {
441 return String.format("%dh ago", hoursSince);
442 } else if (minsSince > 0) {
443 return String.format("%dm ago", minsSince);
444 } else if (secondsSince > 0) {
445 return String.format("%ds ago", secondsSince);
446 } else {
447 return "just now";
448 }
449 }
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800450
451 /**
452 * Copies the specified directory path.&nbsp;Use with great caution since
453 * no attempt is made to check for symbolic links, which could result in
454 * copy of unintended files.
455 *
456 * @param src directory to be copied
457 * @param dst destination directory to be removed
458 * @throws java.io.IOException if unable to remove contents
459 */
460 public static void copyDirectory(String src, String dst) throws IOException {
461 walkFileTree(Paths.get(src), new DirectoryCopier(src, dst));
462 }
463
464 /**
465 * Copies the specified directory path.&nbsp;Use with great caution since
466 * no attempt is made to check for symbolic links, which could result in
467 * copy of unintended files.
468 *
469 * @param src directory to be copied
470 * @param dst destination directory to be removed
471 * @throws java.io.IOException if unable to remove contents
472 */
473 public static void copyDirectory(File src, File dst) throws IOException {
474 walkFileTree(Paths.get(src.getAbsolutePath()),
475 new DirectoryCopier(src.getAbsolutePath(),
476 dst.getAbsolutePath()));
477 }
478
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700479 /**
480 * Returns the future value when complete or if future
481 * completes exceptionally returns the defaultValue.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700482 *
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700483 * @param future future
484 * @param defaultValue default value
485 * @param <T> future value type
486 * @return future value when complete or if future
487 * completes exceptionally returns the defaultValue.
488 */
489 public static <T> T futureGetOrElse(Future<T> future, T defaultValue) {
490 try {
491 return future.get();
492 } catch (InterruptedException e) {
493 Thread.currentThread().interrupt();
494 return defaultValue;
495 } catch (ExecutionException e) {
496 return defaultValue;
497 }
498 }
499
500 /**
501 * Returns the future value when complete or if future
502 * completes exceptionally returns the defaultValue.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700503 *
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700504 * @param future future
505 * @param timeout time to wait for successful completion
506 * @param timeUnit time unit
507 * @param defaultValue default value
508 * @param <T> future value type
509 * @return future value when complete or if future
510 * completes exceptionally returns the defaultValue.
511 */
512 public static <T> T futureGetOrElse(Future<T> future,
513 long timeout,
514 TimeUnit timeUnit,
515 T defaultValue) {
516 try {
517 return future.get(timeout, timeUnit);
518 } catch (InterruptedException e) {
519 Thread.currentThread().interrupt();
520 return defaultValue;
521 } catch (ExecutionException | TimeoutException e) {
522 return defaultValue;
523 }
524 }
525
Madan Jampani27b69c62015-05-15 15:49:02 -0700526 /**
527 * Returns a future that is completed exceptionally.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700528 *
Madan Jampani27b69c62015-05-15 15:49:02 -0700529 * @param t exception
530 * @param <T> future value type
531 * @return future
532 */
533 public static <T> CompletableFuture<T> exceptionalFuture(Throwable t) {
534 CompletableFuture<T> future = new CompletableFuture<>();
535 future.completeExceptionally(t);
536 return future;
537 }
538
539 /**
Sho SHIMIZU85803e22016-01-13 21:53:43 -0800540 * Returns a new CompletableFuture completed with a list of computed values
541 * when all of the given CompletableFuture complete.
542 *
543 * @param futures the CompletableFutures
544 * @param <T> value type of CompletableFuture
545 * @return a new CompletableFuture that is completed when all of the given CompletableFutures complete
546 */
547 public static <T> CompletableFuture<List<T>> allOf(List<CompletableFuture<T>> futures) {
548 return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]))
549 .thenApply(v -> futures.stream()
550 .map(CompletableFuture::join)
551 .collect(Collectors.toList())
552 );
553 }
554
555 /**
Madan Jampani27b69c62015-05-15 15:49:02 -0700556 * Returns the contents of {@code ByteBuffer} as byte array.
557 * <p>
558 * WARNING: There is a performance cost due to array copy
559 * when using this method.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700560 *
Madan Jampani27b69c62015-05-15 15:49:02 -0700561 * @param buffer byte buffer
562 * @return byte array containing the byte buffer contents
563 */
564 public static byte[] byteBuffertoArray(ByteBuffer buffer) {
565 int length = buffer.remaining();
566 if (buffer.hasArray()) {
567 int offset = buffer.arrayOffset() + buffer.position();
568 return Arrays.copyOfRange(buffer.array(), offset, offset + length);
569 }
570 byte[] bytes = new byte[length];
571 buffer.duplicate().get(bytes);
572 return bytes;
573 }
574
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700575 /**
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700576 * Converts an iterable to a stream.
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700577 *
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700578 * @param it iterable to convert
579 * @param <T> type if item
580 * @return iterable as a stream
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700581 */
582 public static <T> Stream<T> stream(Iterable<T> it) {
583 return StreamSupport.stream(it.spliterator(), false);
584 }
585
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800586 // Auxiliary path visitor for recursive directory structure copying.
587 private static class DirectoryCopier extends SimpleFileVisitor<Path> {
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800588 private Path src;
589 private Path dst;
590 private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING;
591
592 DirectoryCopier(String src, String dst) {
593 this.src = Paths.get(src);
594 this.dst = Paths.get(dst);
595 }
596
597 @Override
598 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
599 Path targetPath = dst.resolve(src.relativize(dir));
600 if (!Files.exists(targetPath)) {
601 Files.createDirectory(targetPath);
602 }
603 return FileVisitResult.CONTINUE;
604 }
605
606 @Override
607 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
608 Files.copy(file, dst.resolve(src.relativize(file)), copyOption);
609 return FileVisitResult.CONTINUE;
610 }
611 }
612
tom5f38b3a2014-08-27 23:50:54 -0700613}