blob: e9c9bc39c8946da6bc1278f3cedc22afadc16a62 [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;
Sho SHIMIZUb5638b82016-02-11 14:55:05 -080042import java.util.Optional;
Thomas Vachuskaadba1522015-06-04 15:08:30 -070043import java.util.Random;
Ray Milkey36992c82015-11-17 13:31:15 -080044import java.util.Set;
Madan Jampani27b69c62015-05-15 15:49:02 -070045import java.util.concurrent.CompletableFuture;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070046import java.util.concurrent.ExecutionException;
47import java.util.concurrent.Future;
Jian Li1b4cb332016-03-02 16:32:51 -080048import java.util.concurrent.ScheduledExecutorService;
tom5f38b3a2014-08-27 23:50:54 -070049import java.util.concurrent.ThreadFactory;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070050import java.util.concurrent.TimeUnit;
51import java.util.concurrent.TimeoutException;
Madan Jampania29c6772015-08-17 13:17:07 -070052import java.util.function.Function;
53import java.util.function.Supplier;
Sho SHIMIZU85803e22016-01-13 21:53:43 -080054import java.util.stream.Collectors;
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -070055import java.util.stream.Stream;
56import java.util.stream.StreamSupport;
tom5f38b3a2014-08-27 23:50:54 -070057
Madan Jampani2bfa94c2015-04-11 05:03:49 -070058import org.slf4j.Logger;
59
Madan Jampanif2f086c2016-01-13 16:15:39 -080060import com.google.common.base.Charsets;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070061import com.google.common.base.Strings;
62import com.google.common.primitives.UnsignedLongs;
63import com.google.common.util.concurrent.ThreadFactoryBuilder;
Ray Milkey705d9bc2014-11-18 08:19:00 -080064
Thomas Vachuskac13b90a2015-02-18 18:19:55 -080065/**
66 * Miscellaneous utility methods.
67 */
tom5f38b3a2014-08-27 23:50:54 -070068public abstract class Tools {
69
70 private Tools() {
71 }
72
Thomas Vachuska02aeb032015-01-06 22:36:30 -080073 private static final Logger log = getLogger(Tools.class);
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080074
Thomas Vachuskaadba1522015-06-04 15:08:30 -070075 private static Random random = new Random();
76
tom5f38b3a2014-08-27 23:50:54 -070077 /**
78 * Returns a thread factory that produces threads named according to the
79 * supplied name pattern.
80 *
81 * @param pattern name pattern
82 * @return thread factory
83 */
84 public static ThreadFactory namedThreads(String pattern) {
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080085 return new ThreadFactoryBuilder()
86 .setNameFormat(pattern)
Thomas Vachuska480adad2015-03-06 10:27:09 -080087 .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on " + t.getName(), e))
88 .build();
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080089 }
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080090
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080091 /**
92 * Returns a thread factory that produces threads named according to the
93 * supplied name pattern and from the specified thread-group. The thread
94 * group name is expected to be specified in slash-delimited format, e.g.
Thomas Vachuskac13b90a2015-02-18 18:19:55 -080095 * {@code onos/intent}. The thread names will be produced by converting
96 * the thread group name into dash-delimited format and pre-pended to the
97 * specified pattern.
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080098 *
99 * @param groupName group name in slash-delimited format to indicate hierarchy
100 * @param pattern name pattern
101 * @return thread factory
102 */
103 public static ThreadFactory groupedThreads(String groupName, String pattern) {
Jian Li03e9fb02016-03-01 17:13:54 -0800104 return groupedThreads(groupName, pattern, log);
105 }
106
107 /**
108 * Returns a thread factory that produces threads named according to the
109 * supplied name pattern and from the specified thread-group. The thread
110 * group name is expected to be specified in slash-delimited format, e.g.
111 * {@code onos/intent}. The thread names will be produced by converting
112 * the thread group name into dash-delimited format and pre-pended to the
113 * specified pattern. If a logger is specified, it will use the logger to
114 * print out the exception if it has any.
115 *
116 * @param groupName group name in slash-delimited format to indicate hierarchy
117 * @param pattern name pattern
118 * @param logger logger
119 * @return thread factory
120 */
121 public static ThreadFactory groupedThreads(String groupName, String pattern, Logger logger) {
122 if (logger == null) {
123 return groupedThreads(groupName, pattern);
124 }
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -0800125 return new ThreadFactoryBuilder()
126 .setThreadFactory(groupedThreadFactory(groupName))
Thomas Vachuskac13b90a2015-02-18 18:19:55 -0800127 .setNameFormat(groupName.replace(GroupedThreadFactory.DELIMITER, "-") + "-" + pattern)
Jian Li03e9fb02016-03-01 17:13:54 -0800128 .setUncaughtExceptionHandler((t, e) -> logger.error("Uncaught exception on " + t.getName(), e))
Thomas Vachuska480adad2015-03-06 10:27:09 -0800129 .build();
tom5f38b3a2014-08-27 23:50:54 -0700130 }
131
tom782a7cf2014-09-11 23:58:38 -0700132 /**
Jian Li1b4cb332016-03-02 16:32:51 -0800133 * Returns a loggable scheduled executor service that allows to capture and
134 * log any exceptions if the scheduled tasks are failed during execution.
135 *
136 * @param executor scheduled executor service
137 * @return loggable scheduled executor service
138 */
139 public static ScheduledExecutorService loggableScheduledExecutor(ScheduledExecutorService executor) {
140 return new LogScheduledExecutorService(executor);
141 }
142
143 /**
Yuta HIGUCHI06586272014-11-25 14:27:03 -0800144 * Returns a thread factory that produces threads with MIN_PRIORITY.
145 *
146 * @param factory backing ThreadFactory
147 * @return thread factory
148 */
149 public static ThreadFactory minPriority(ThreadFactory factory) {
150 return new ThreadFactoryBuilder()
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800151 .setThreadFactory(factory)
152 .setPriority(Thread.MIN_PRIORITY)
153 .build();
Yuta HIGUCHI06586272014-11-25 14:27:03 -0800154 }
155
156 /**
Brian O'Connore2eac102015-02-12 18:30:22 -0800157 * Returns true if the collection is null or is empty.
158 *
159 * @param collection collection to test
160 * @return true if null or empty; false otherwise
161 */
162 public static boolean isNullOrEmpty(Collection collection) {
163 return collection == null || collection.isEmpty();
164 }
165
166 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700167 * Returns the specified item if that item is not null; otherwise throws
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700168 * not found 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 org.onlab.util.ItemNotFoundException if item is null
175 */
176 public static <T> T nullIsNotFound(T item, String message) {
177 if (item == null) {
178 throw new ItemNotFoundException(message);
179 }
180 return item;
181 }
182
183 /**
Ray Milkey36992c82015-11-17 13:31:15 -0800184 * Returns the specified set if the set is not null and not empty;
185 * otherwise throws a not found exception.
186 *
187 * @param item set to check
188 * @param message not found message
189 * @param <T> Set item type
190 * @return item if not null and not empty
191 * @throws org.onlab.util.ItemNotFoundException if set is null or empty
192 */
193 public static <T> Set<T> emptyIsNotFound(Set<T> item, String message) {
194 if (item == null || item.isEmpty()) {
195 throw new ItemNotFoundException(message);
196 }
197 return item;
198 }
199
200 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700201 * Returns the specified item if that item is not null; otherwise throws
202 * bad argument exception.
203 *
204 * @param item item to check
205 * @param message not found message
206 * @param <T> item type
207 * @return item if not null
208 * @throws IllegalArgumentException if item is null
209 */
210 public static <T> T nullIsIllegal(T item, String message) {
211 if (item == null) {
212 throw new IllegalArgumentException(message);
213 }
214 return item;
215 }
216
217 /**
tom782a7cf2014-09-11 23:58:38 -0700218 * Converts a string from hex to long.
219 *
220 * @param string hex number in string form; sans 0x
221 * @return long value
222 */
223 public static long fromHex(String string) {
224 return UnsignedLongs.parseUnsignedLong(string, 16);
225 }
226
227 /**
228 * Converts a long value to hex string; 16 wide and sans 0x.
229 *
230 * @param value long value
231 * @return hex string
232 */
233 public static String toHex(long value) {
234 return Strings.padStart(UnsignedLongs.toString(value, 16), 16, '0');
235 }
236
237 /**
238 * Converts a long value to hex string; 16 wide and sans 0x.
239 *
240 * @param value long value
241 * @param width string width; zero padded
242 * @return hex string
243 */
244 public static String toHex(long value, int width) {
245 return Strings.padStart(UnsignedLongs.toString(value, 16), width, '0');
246 }
tomf110fff2014-09-26 00:38:18 -0700247
248 /**
Madan Jampanif2f086c2016-01-13 16:15:39 -0800249 * Returns the UTF-8 encoded byte[] representation of a String.
Jian Lidfba7392016-01-22 16:46:58 -0800250 * @param input input string
251 * @return UTF-8 encoded byte array
Madan Jampanif2f086c2016-01-13 16:15:39 -0800252 */
253 public static byte[] getBytesUtf8(String input) {
254 return input.getBytes(Charsets.UTF_8);
255 }
256
257 /**
258 * Returns the String representation of UTF-8 encoded byte[].
Jian Lidfba7392016-01-22 16:46:58 -0800259 * @param input input byte array
260 * @return UTF-8 encoded string
Madan Jampanif2f086c2016-01-13 16:15:39 -0800261 */
262 public static String toStringUtf8(byte[] input) {
263 return new String(input, Charsets.UTF_8);
264 }
265
266 /**
Madan Jampani9eb55d12015-08-14 07:47:56 -0700267 * Returns a copy of the input byte array.
268 *
269 * @param original input
270 * @return copy of original
271 */
272 public static byte[] copyOf(byte[] original) {
273 return Arrays.copyOf(original, original.length);
274 }
275
276 /**
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700277 * Get property as a string value.
278 *
279 * @param properties properties to be looked up
280 * @param propertyName the name of the property to look up
281 * @return value when the propertyName is defined or return null
282 */
283 public static String get(Dictionary<?, ?> properties, String propertyName) {
284 Object v = properties.get(propertyName);
285 String s = (v instanceof String) ? (String) v :
286 v != null ? v.toString() : null;
287 return Strings.isNullOrEmpty(s) ? null : s.trim();
288 }
289
290 /**
tomf110fff2014-09-26 00:38:18 -0700291 * Suspends the current thread for a specified number of millis.
292 *
293 * @param ms number of millis
294 */
295 public static void delay(int ms) {
296 try {
297 Thread.sleep(ms);
298 } catch (InterruptedException e) {
299 throw new RuntimeException("Interrupted", e);
300 }
301 }
302
tom53efab52014-10-07 17:43:48 -0700303 /**
Madan Jampania29c6772015-08-17 13:17:07 -0700304 * Returns a function that retries execution on failure.
305 * @param base base function
306 * @param exceptionClass type of exception for which to retry
307 * @param maxRetries max number of retries before giving up
308 * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from
309 * the interval (0, maxDelayBetweenRetries]
310 * @return function
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700311 * @param <U> type of function input
312 * @param <V> type of function output
Madan Jampania29c6772015-08-17 13:17:07 -0700313 */
314 public static <U, V> Function<U, V> retryable(Function<U, V> base,
315 Class<? extends Throwable> exceptionClass,
316 int maxRetries,
317 int maxDelayBetweenRetries) {
318 return new RetryingFunction<>(base, exceptionClass, maxRetries, maxDelayBetweenRetries);
319 }
320
321 /**
322 * Returns a Supplier that retries execution on failure.
323 * @param base base supplier
324 * @param exceptionClass type of exception for which to retry
325 * @param maxRetries max number of retries before giving up
326 * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from
327 * the interval (0, maxDelayBetweenRetries]
328 * @return supplier
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700329 * @param <V> type of supplied result
Madan Jampania29c6772015-08-17 13:17:07 -0700330 */
331 public static <V> Supplier<V> retryable(Supplier<V> base,
332 Class<? extends Throwable> exceptionClass,
333 int maxRetries,
334 int maxDelayBetweenRetries) {
335 return () -> new RetryingFunction<>(v -> base.get(),
336 exceptionClass,
337 maxRetries,
338 maxDelayBetweenRetries).apply(null);
339 }
340
341 /**
Thomas Vachuskaadba1522015-06-04 15:08:30 -0700342 * Suspends the current thread for a random number of millis between 0 and
343 * the indicated limit.
344 *
345 * @param ms max number of millis
346 */
347 public static void randomDelay(int ms) {
348 try {
349 Thread.sleep(random.nextInt(ms));
350 } catch (InterruptedException e) {
351 throw new RuntimeException("Interrupted", e);
352 }
353 }
354
355 /**
Thomas Vachuskac40d4632015-04-09 16:55:03 -0700356 * Suspends the current thread for a specified number of millis and nanos.
357 *
358 * @param ms number of millis
359 * @param nanos number of nanos
360 */
361 public static void delay(int ms, int nanos) {
362 try {
363 Thread.sleep(ms, nanos);
364 } catch (InterruptedException e) {
365 throw new RuntimeException("Interrupted", e);
366 }
367 }
368
369 /**
tom53efab52014-10-07 17:43:48 -0700370 * Slurps the contents of a file into a list of strings, one per line.
371 *
372 * @param path file path
373 * @return file contents
HIGUCHI Yuta3b3bd1e2015-09-22 16:39:33 -0700374 * @deprecated in Emu release
tom53efab52014-10-07 17:43:48 -0700375 */
HIGUCHI Yuta3b3bd1e2015-09-22 16:39:33 -0700376 @Deprecated
tom53efab52014-10-07 17:43:48 -0700377 public static List<String> slurp(File path) {
HIGUCHI Yutacf4d6172015-09-22 16:39:33 -0700378 try (
Ray Milkey705d9bc2014-11-18 08:19:00 -0800379 BufferedReader br = new BufferedReader(
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800380 new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8));
HIGUCHI Yutacf4d6172015-09-22 16:39:33 -0700381 ) {
tom53efab52014-10-07 17:43:48 -0700382 List<String> lines = new ArrayList<>();
383 String line;
384 while ((line = br.readLine()) != null) {
385 lines.add(line);
386 }
387 return lines;
388
389 } catch (IOException e) {
390 return null;
391 }
392 }
393
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800394 /**
395 * Purges the specified directory path.&nbsp;Use with great caution since
396 * no attempt is made to check for symbolic links, which could result in
397 * deletion of unintended files.
398 *
399 * @param path directory to be removed
400 * @throws java.io.IOException if unable to remove contents
401 */
402 public static void removeDirectory(String path) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800403 DirectoryDeleter visitor = new DirectoryDeleter();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700404 File dir = new File(path);
405 if (dir.exists() && dir.isDirectory()) {
406 walkFileTree(Paths.get(path), visitor);
407 if (visitor.exception != null) {
408 throw visitor.exception;
409 }
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800410 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800411 }
412
413 /**
414 * Purges the specified directory path.&nbsp;Use with great caution since
415 * no attempt is made to check for symbolic links, which could result in
416 * deletion of unintended files.
417 *
418 * @param dir directory to be removed
419 * @throws java.io.IOException if unable to remove contents
420 */
421 public static void removeDirectory(File dir) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800422 DirectoryDeleter visitor = new DirectoryDeleter();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700423 if (dir.exists() && dir.isDirectory()) {
424 walkFileTree(Paths.get(dir.getAbsolutePath()), visitor);
425 if (visitor.exception != null) {
426 throw visitor.exception;
427 }
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800428 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800429 }
430
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800431 // Auxiliary path visitor for recursive directory structure removal.
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800432 private static class DirectoryDeleter extends SimpleFileVisitor<Path> {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800433
434 private IOException exception;
435
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800436 @Override
437 public FileVisitResult visitFile(Path file, BasicFileAttributes attributes)
438 throws IOException {
439 if (attributes.isRegularFile()) {
440 delete(file);
441 }
442 return FileVisitResult.CONTINUE;
443 }
444
445 @Override
446 public FileVisitResult postVisitDirectory(Path directory, IOException ioe)
447 throws IOException {
448 delete(directory);
449 return FileVisitResult.CONTINUE;
450 }
451
452 @Override
453 public FileVisitResult visitFileFailed(Path file, IOException ioe)
454 throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800455 this.exception = ioe;
456 return FileVisitResult.TERMINATE;
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800457 }
458 }
459
Madan Jampani30a57f82015-03-02 12:19:41 -0800460 /**
461 * Returns a human friendly time ago string for a specified system time.
Thomas Vachuska480adad2015-03-06 10:27:09 -0800462 *
Madan Jampani30a57f82015-03-02 12:19:41 -0800463 * @param unixTime system time in millis
464 * @return human friendly time ago
465 */
466 public static String timeAgo(long unixTime) {
467 long deltaMillis = System.currentTimeMillis() - unixTime;
468 long secondsSince = (long) (deltaMillis / 1000.0);
469 long minsSince = (long) (deltaMillis / (1000.0 * 60));
470 long hoursSince = (long) (deltaMillis / (1000.0 * 60 * 60));
471 long daysSince = (long) (deltaMillis / (1000.0 * 60 * 60 * 24));
472 if (daysSince > 0) {
473 return String.format("%dd ago", daysSince);
474 } else if (hoursSince > 0) {
475 return String.format("%dh ago", hoursSince);
476 } else if (minsSince > 0) {
477 return String.format("%dm ago", minsSince);
478 } else if (secondsSince > 0) {
479 return String.format("%ds ago", secondsSince);
480 } else {
481 return "just now";
482 }
483 }
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800484
485 /**
486 * Copies the specified directory path.&nbsp;Use with great caution since
487 * no attempt is made to check for symbolic links, which could result in
488 * copy of unintended files.
489 *
490 * @param src directory to be copied
491 * @param dst destination directory to be removed
492 * @throws java.io.IOException if unable to remove contents
493 */
494 public static void copyDirectory(String src, String dst) throws IOException {
495 walkFileTree(Paths.get(src), new DirectoryCopier(src, dst));
496 }
497
498 /**
499 * Copies the specified directory path.&nbsp;Use with great caution since
500 * no attempt is made to check for symbolic links, which could result in
501 * copy of unintended files.
502 *
503 * @param src directory to be copied
504 * @param dst destination directory to be removed
505 * @throws java.io.IOException if unable to remove contents
506 */
507 public static void copyDirectory(File src, File dst) throws IOException {
508 walkFileTree(Paths.get(src.getAbsolutePath()),
509 new DirectoryCopier(src.getAbsolutePath(),
510 dst.getAbsolutePath()));
511 }
512
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700513 /**
514 * Returns the future value when complete or if future
515 * completes exceptionally returns the defaultValue.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700516 *
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700517 * @param future future
518 * @param defaultValue default value
519 * @param <T> future value type
520 * @return future value when complete or if future
521 * completes exceptionally returns the defaultValue.
522 */
523 public static <T> T futureGetOrElse(Future<T> future, T defaultValue) {
524 try {
525 return future.get();
526 } catch (InterruptedException e) {
527 Thread.currentThread().interrupt();
528 return defaultValue;
529 } catch (ExecutionException e) {
530 return defaultValue;
531 }
532 }
533
534 /**
535 * Returns the future value when complete or if future
536 * completes exceptionally returns the defaultValue.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700537 *
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700538 * @param future future
539 * @param timeout time to wait for successful completion
540 * @param timeUnit time unit
541 * @param defaultValue default value
542 * @param <T> future value type
543 * @return future value when complete or if future
544 * completes exceptionally returns the defaultValue.
545 */
546 public static <T> T futureGetOrElse(Future<T> future,
547 long timeout,
548 TimeUnit timeUnit,
549 T defaultValue) {
550 try {
551 return future.get(timeout, timeUnit);
552 } catch (InterruptedException e) {
553 Thread.currentThread().interrupt();
554 return defaultValue;
555 } catch (ExecutionException | TimeoutException e) {
556 return defaultValue;
557 }
558 }
559
Madan Jampani27b69c62015-05-15 15:49:02 -0700560 /**
561 * Returns a future that is completed exceptionally.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700562 *
Madan Jampani27b69c62015-05-15 15:49:02 -0700563 * @param t exception
564 * @param <T> future value type
565 * @return future
566 */
567 public static <T> CompletableFuture<T> exceptionalFuture(Throwable t) {
568 CompletableFuture<T> future = new CompletableFuture<>();
569 future.completeExceptionally(t);
570 return future;
571 }
572
573 /**
Sho SHIMIZU85803e22016-01-13 21:53:43 -0800574 * Returns a new CompletableFuture completed with a list of computed values
575 * when all of the given CompletableFuture complete.
576 *
577 * @param futures the CompletableFutures
578 * @param <T> value type of CompletableFuture
579 * @return a new CompletableFuture that is completed when all of the given CompletableFutures complete
580 */
581 public static <T> CompletableFuture<List<T>> allOf(List<CompletableFuture<T>> futures) {
582 return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]))
583 .thenApply(v -> futures.stream()
584 .map(CompletableFuture::join)
585 .collect(Collectors.toList())
586 );
587 }
588
589 /**
Madan Jampani27b69c62015-05-15 15:49:02 -0700590 * Returns the contents of {@code ByteBuffer} as byte array.
591 * <p>
592 * WARNING: There is a performance cost due to array copy
593 * when using this method.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700594 *
Madan Jampani27b69c62015-05-15 15:49:02 -0700595 * @param buffer byte buffer
596 * @return byte array containing the byte buffer contents
597 */
598 public static byte[] byteBuffertoArray(ByteBuffer buffer) {
599 int length = buffer.remaining();
600 if (buffer.hasArray()) {
601 int offset = buffer.arrayOffset() + buffer.position();
602 return Arrays.copyOfRange(buffer.array(), offset, offset + length);
603 }
604 byte[] bytes = new byte[length];
605 buffer.duplicate().get(bytes);
606 return bytes;
607 }
608
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700609 /**
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700610 * Converts an iterable to a stream.
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700611 *
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700612 * @param it iterable to convert
613 * @param <T> type if item
614 * @return iterable as a stream
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700615 */
616 public static <T> Stream<T> stream(Iterable<T> it) {
617 return StreamSupport.stream(it.spliterator(), false);
618 }
619
Sho SHIMIZUb5638b82016-02-11 14:55:05 -0800620 /**
621 * Converts an optional to a stream.
622 *
623 * @param optional optional to convert
624 * @param <T> type of enclosed value
625 * @return optional as a stream
626 */
627 public static <T> Stream<T> stream(Optional<T> optional) {
628 return optional.map(Stream::of).orElse(Stream.empty());
629 }
630
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800631 // Auxiliary path visitor for recursive directory structure copying.
632 private static class DirectoryCopier extends SimpleFileVisitor<Path> {
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800633 private Path src;
634 private Path dst;
635 private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING;
636
637 DirectoryCopier(String src, String dst) {
638 this.src = Paths.get(src);
639 this.dst = Paths.get(dst);
640 }
641
642 @Override
643 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
644 Path targetPath = dst.resolve(src.relativize(dir));
645 if (!Files.exists(targetPath)) {
646 Files.createDirectory(targetPath);
647 }
648 return FileVisitResult.CONTINUE;
649 }
650
651 @Override
652 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
653 Files.copy(file, dst.resolve(src.relativize(file)), copyOption);
654 return FileVisitResult.CONTINUE;
655 }
656 }
657
tom5f38b3a2014-08-27 23:50:54 -0700658}