blob: 81c9bce9fa73a073923b79a835156b50b7a65b2b [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present 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
Jian Li66f15262016-03-03 11:18:40 -080018import com.google.common.base.Charsets;
19import com.google.common.base.Strings;
20import com.google.common.primitives.UnsignedLongs;
21import com.google.common.util.concurrent.ThreadFactoryBuilder;
22import org.slf4j.Logger;
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080023
tom53efab52014-10-07 17:43:48 -070024import java.io.File;
tom53efab52014-10-07 17:43:48 -070025import java.io.IOException;
Madan Jampani27b69c62015-05-15 15:49:02 -070026import java.nio.ByteBuffer;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080027import java.nio.file.FileVisitResult;
Thomas Vachuska90b453f2015-01-30 18:57:14 -080028import java.nio.file.Files;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080029import java.nio.file.Path;
30import java.nio.file.Paths;
31import java.nio.file.SimpleFileVisitor;
Thomas Vachuska90b453f2015-01-30 18:57:14 -080032import java.nio.file.StandardCopyOption;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080033import java.nio.file.attribute.BasicFileAttributes;
Madan Jampani27b69c62015-05-15 15:49:02 -070034import java.util.Arrays;
Brian O'Connore2eac102015-02-12 18:30:22 -080035import java.util.Collection;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070036import java.util.Dictionary;
tom53efab52014-10-07 17:43:48 -070037import java.util.List;
Sho SHIMIZUb5638b82016-02-11 14:55:05 -080038import java.util.Optional;
Thomas Vachuskaadba1522015-06-04 15:08:30 -070039import java.util.Random;
Ray Milkey36992c82015-11-17 13:31:15 -080040import java.util.Set;
Madan Jampani27b69c62015-05-15 15:49:02 -070041import java.util.concurrent.CompletableFuture;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070042import java.util.concurrent.ExecutionException;
43import java.util.concurrent.Future;
tom5f38b3a2014-08-27 23:50:54 -070044import java.util.concurrent.ThreadFactory;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070045import java.util.concurrent.TimeUnit;
46import java.util.concurrent.TimeoutException;
Madan Jampania29c6772015-08-17 13:17:07 -070047import java.util.function.Function;
48import java.util.function.Supplier;
Sho SHIMIZU85803e22016-01-13 21:53:43 -080049import java.util.stream.Collectors;
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -070050import java.util.stream.Stream;
51import java.util.stream.StreamSupport;
tom5f38b3a2014-08-27 23:50:54 -070052
Jian Li66f15262016-03-03 11:18:40 -080053import static java.nio.file.Files.delete;
54import static java.nio.file.Files.walkFileTree;
55import static org.onlab.util.GroupedThreadFactory.groupedThreadFactory;
56import static org.slf4j.LoggerFactory.getLogger;
Ray Milkey705d9bc2014-11-18 08:19:00 -080057
Thomas Vachuskac13b90a2015-02-18 18:19:55 -080058/**
59 * Miscellaneous utility methods.
60 */
tom5f38b3a2014-08-27 23:50:54 -070061public abstract class Tools {
62
63 private Tools() {
64 }
65
Thomas Vachuska02aeb032015-01-06 22:36:30 -080066 private static final Logger log = getLogger(Tools.class);
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080067
Thomas Vachuskaadba1522015-06-04 15:08:30 -070068 private static Random random = new Random();
69
tom5f38b3a2014-08-27 23:50:54 -070070 /**
71 * Returns a thread factory that produces threads named according to the
72 * supplied name pattern.
73 *
74 * @param pattern name pattern
75 * @return thread factory
76 */
77 public static ThreadFactory namedThreads(String pattern) {
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080078 return new ThreadFactoryBuilder()
79 .setNameFormat(pattern)
Thomas Vachuska480adad2015-03-06 10:27:09 -080080 .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on " + t.getName(), e))
81 .build();
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080082 }
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080083
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080084 /**
85 * Returns a thread factory that produces threads named according to the
86 * supplied name pattern and from the specified thread-group. The thread
87 * group name is expected to be specified in slash-delimited format, e.g.
Thomas Vachuskac13b90a2015-02-18 18:19:55 -080088 * {@code onos/intent}. The thread names will be produced by converting
89 * the thread group name into dash-delimited format and pre-pended to the
90 * specified pattern.
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080091 *
92 * @param groupName group name in slash-delimited format to indicate hierarchy
93 * @param pattern name pattern
94 * @return thread factory
95 */
96 public static ThreadFactory groupedThreads(String groupName, String pattern) {
Jian Li03e9fb02016-03-01 17:13:54 -080097 return groupedThreads(groupName, pattern, log);
98 }
99
100 /**
101 * Returns a thread factory that produces threads named according to the
102 * supplied name pattern and from the specified thread-group. The thread
103 * group name is expected to be specified in slash-delimited format, e.g.
104 * {@code onos/intent}. The thread names will be produced by converting
105 * the thread group name into dash-delimited format and pre-pended to the
106 * specified pattern. If a logger is specified, it will use the logger to
107 * print out the exception if it has any.
108 *
109 * @param groupName group name in slash-delimited format to indicate hierarchy
110 * @param pattern name pattern
111 * @param logger logger
112 * @return thread factory
113 */
114 public static ThreadFactory groupedThreads(String groupName, String pattern, Logger logger) {
115 if (logger == null) {
116 return groupedThreads(groupName, pattern);
117 }
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -0800118 return new ThreadFactoryBuilder()
119 .setThreadFactory(groupedThreadFactory(groupName))
Thomas Vachuskac13b90a2015-02-18 18:19:55 -0800120 .setNameFormat(groupName.replace(GroupedThreadFactory.DELIMITER, "-") + "-" + pattern)
Jian Li03e9fb02016-03-01 17:13:54 -0800121 .setUncaughtExceptionHandler((t, e) -> logger.error("Uncaught exception on " + t.getName(), e))
Thomas Vachuska480adad2015-03-06 10:27:09 -0800122 .build();
tom5f38b3a2014-08-27 23:50:54 -0700123 }
124
tom782a7cf2014-09-11 23:58:38 -0700125 /**
Yuta HIGUCHI06586272014-11-25 14:27:03 -0800126 * Returns a thread factory that produces threads with MIN_PRIORITY.
127 *
128 * @param factory backing ThreadFactory
129 * @return thread factory
130 */
131 public static ThreadFactory minPriority(ThreadFactory factory) {
132 return new ThreadFactoryBuilder()
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800133 .setThreadFactory(factory)
134 .setPriority(Thread.MIN_PRIORITY)
135 .build();
Yuta HIGUCHI06586272014-11-25 14:27:03 -0800136 }
137
138 /**
Brian O'Connore2eac102015-02-12 18:30:22 -0800139 * Returns true if the collection is null or is empty.
140 *
141 * @param collection collection to test
142 * @return true if null or empty; false otherwise
143 */
144 public static boolean isNullOrEmpty(Collection collection) {
145 return collection == null || collection.isEmpty();
146 }
147
148 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700149 * Returns the specified item if that item is not null; otherwise throws
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700150 * not found exception.
151 *
152 * @param item item to check
153 * @param message not found message
154 * @param <T> item type
155 * @return item if not null
156 * @throws org.onlab.util.ItemNotFoundException if item is null
157 */
158 public static <T> T nullIsNotFound(T item, String message) {
159 if (item == null) {
160 throw new ItemNotFoundException(message);
161 }
162 return item;
163 }
164
165 /**
Ray Milkey36992c82015-11-17 13:31:15 -0800166 * Returns the specified set if the set is not null and not empty;
167 * otherwise throws a not found exception.
168 *
169 * @param item set to check
170 * @param message not found message
171 * @param <T> Set item type
172 * @return item if not null and not empty
173 * @throws org.onlab.util.ItemNotFoundException if set is null or empty
174 */
175 public static <T> Set<T> emptyIsNotFound(Set<T> item, String message) {
176 if (item == null || item.isEmpty()) {
177 throw new ItemNotFoundException(message);
178 }
179 return item;
180 }
181
182 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700183 * Returns the specified item if that item is not null; otherwise throws
184 * bad argument exception.
185 *
186 * @param item item to check
187 * @param message not found message
188 * @param <T> item type
189 * @return item if not null
190 * @throws IllegalArgumentException if item is null
191 */
192 public static <T> T nullIsIllegal(T item, String message) {
193 if (item == null) {
194 throw new IllegalArgumentException(message);
195 }
196 return item;
197 }
198
199 /**
tom782a7cf2014-09-11 23:58:38 -0700200 * Converts a string from hex to long.
201 *
202 * @param string hex number in string form; sans 0x
203 * @return long value
204 */
205 public static long fromHex(String string) {
206 return UnsignedLongs.parseUnsignedLong(string, 16);
207 }
208
209 /**
210 * Converts a long value to hex string; 16 wide and sans 0x.
211 *
212 * @param value long value
213 * @return hex string
214 */
215 public static String toHex(long value) {
216 return Strings.padStart(UnsignedLongs.toString(value, 16), 16, '0');
217 }
218
219 /**
220 * Converts a long value to hex string; 16 wide and sans 0x.
221 *
222 * @param value long value
223 * @param width string width; zero padded
224 * @return hex string
225 */
226 public static String toHex(long value, int width) {
227 return Strings.padStart(UnsignedLongs.toString(value, 16), width, '0');
228 }
tomf110fff2014-09-26 00:38:18 -0700229
230 /**
Madan Jampanif2f086c2016-01-13 16:15:39 -0800231 * Returns the UTF-8 encoded byte[] representation of a String.
Jian Lidfba7392016-01-22 16:46:58 -0800232 * @param input input string
233 * @return UTF-8 encoded byte array
Madan Jampanif2f086c2016-01-13 16:15:39 -0800234 */
235 public static byte[] getBytesUtf8(String input) {
236 return input.getBytes(Charsets.UTF_8);
237 }
238
239 /**
240 * Returns the String representation of UTF-8 encoded byte[].
Jian Lidfba7392016-01-22 16:46:58 -0800241 * @param input input byte array
242 * @return UTF-8 encoded string
Madan Jampanif2f086c2016-01-13 16:15:39 -0800243 */
244 public static String toStringUtf8(byte[] input) {
245 return new String(input, Charsets.UTF_8);
246 }
247
248 /**
Madan Jampani9eb55d12015-08-14 07:47:56 -0700249 * Returns a copy of the input byte array.
250 *
251 * @param original input
252 * @return copy of original
253 */
254 public static byte[] copyOf(byte[] original) {
255 return Arrays.copyOf(original, original.length);
256 }
257
258 /**
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700259 * Get property as a string value.
260 *
261 * @param properties properties to be looked up
262 * @param propertyName the name of the property to look up
263 * @return value when the propertyName is defined or return null
264 */
265 public static String get(Dictionary<?, ?> properties, String propertyName) {
266 Object v = properties.get(propertyName);
267 String s = (v instanceof String) ? (String) v :
268 v != null ? v.toString() : null;
269 return Strings.isNullOrEmpty(s) ? null : s.trim();
270 }
271
272 /**
Jian Lid9b5f552016-03-11 18:15:31 -0800273 * Get Integer property from the propertyName
274 * Return null if propertyName is not found.
275 *
276 * @param properties properties to be looked up
277 * @param propertyName the name of the property to look up
278 * @return value when the propertyName is defined or return null
279 */
280 public static Integer getIntegerProperty(Dictionary<?, ?> properties,
281 String propertyName) {
282 Integer value;
283 try {
284 String s = get(properties, propertyName);
285 value = Strings.isNullOrEmpty(s) ? null : Integer.valueOf(s);
286 } catch (NumberFormatException | ClassCastException e) {
287 value = null;
288 }
289 return value;
290 }
291
292 /**
293 * Get Integer property from the propertyName
294 * Return default value if propertyName is not found.
295 *
296 * @param properties properties to be looked up
297 * @param propertyName the name of the property to look up
298 * @param defaultValue the default value that to be assigned
299 * @return value when the propertyName is defined or return default value
300 */
301 public static int getIntegerProperty(Dictionary<?, ?> properties,
302 String propertyName,
303 int defaultValue) {
304 try {
305 String s = get(properties, propertyName);
306 return Strings.isNullOrEmpty(s) ? defaultValue : Integer.valueOf(s);
307 } catch (NumberFormatException | ClassCastException e) {
308 return defaultValue;
309 }
310 }
311
312 /**
313 * Check property name is defined and set to true.
314 *
315 * @param properties properties to be looked up
316 * @param propertyName the name of the property to look up
317 * @return value when the propertyName is defined or return null
318 */
319 public static Boolean isPropertyEnabled(Dictionary<?, ?> properties,
320 String propertyName) {
321 Boolean value;
322 try {
323 String s = get(properties, propertyName);
324 value = Strings.isNullOrEmpty(s) ? null : Boolean.valueOf(s);
325 } catch (ClassCastException e) {
326 value = null;
327 }
328 return value;
329 }
330
331 /**
332 * Check property name is defined as set to true.
333 *
334 * @param properties properties to be looked up
335 * @param propertyName the name of the property to look up
336 * @param defaultValue the default value that to be assigned
337 * @return value when the propertyName is defined or return the default value
338 */
339 public static boolean isPropertyEnabled(Dictionary<?, ?> properties,
340 String propertyName,
341 boolean defaultValue) {
342 try {
343 String s = get(properties, propertyName);
344 return Strings.isNullOrEmpty(s) ? defaultValue : Boolean.valueOf(s);
345 } catch (ClassCastException e) {
346 return defaultValue;
347 }
348 }
349
350 /**
Deepa Vaddireddy50ad0802016-08-08 19:27:36 +0530351 * Get Long property from the propertyName
352 * Return null if propertyName is not found.
353 *
354 * @param properties properties to be looked up
355 * @param propertyName the name of the property to look up
356 * @return value when the propertyName is defined or return null
357 */
358 public static Long getLongProperty(Dictionary<?, ?> properties,
359 String propertyName) {
360 Long value;
361 try {
362 String s = get(properties, propertyName);
363 value = Strings.isNullOrEmpty(s) ? null : Long.valueOf(s);
364 } catch (NumberFormatException | ClassCastException e) {
365 value = null;
366 }
367 return value;
368 }
369
370 /**
tomf110fff2014-09-26 00:38:18 -0700371 * Suspends the current thread for a specified number of millis.
372 *
373 * @param ms number of millis
374 */
375 public static void delay(int ms) {
376 try {
377 Thread.sleep(ms);
378 } catch (InterruptedException e) {
379 throw new RuntimeException("Interrupted", e);
380 }
381 }
382
tom53efab52014-10-07 17:43:48 -0700383 /**
Madan Jampania29c6772015-08-17 13:17:07 -0700384 * Returns a function that retries execution on failure.
385 * @param base base function
386 * @param exceptionClass type of exception for which to retry
387 * @param maxRetries max number of retries before giving up
388 * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from
389 * the interval (0, maxDelayBetweenRetries]
390 * @return function
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700391 * @param <U> type of function input
392 * @param <V> type of function output
Madan Jampania29c6772015-08-17 13:17:07 -0700393 */
394 public static <U, V> Function<U, V> retryable(Function<U, V> base,
395 Class<? extends Throwable> exceptionClass,
396 int maxRetries,
397 int maxDelayBetweenRetries) {
398 return new RetryingFunction<>(base, exceptionClass, maxRetries, maxDelayBetweenRetries);
399 }
400
401 /**
402 * Returns a Supplier that retries execution on failure.
403 * @param base base supplier
404 * @param exceptionClass type of exception for which to retry
405 * @param maxRetries max number of retries before giving up
406 * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from
407 * the interval (0, maxDelayBetweenRetries]
408 * @return supplier
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700409 * @param <V> type of supplied result
Madan Jampania29c6772015-08-17 13:17:07 -0700410 */
411 public static <V> Supplier<V> retryable(Supplier<V> base,
412 Class<? extends Throwable> exceptionClass,
413 int maxRetries,
414 int maxDelayBetweenRetries) {
415 return () -> new RetryingFunction<>(v -> base.get(),
416 exceptionClass,
417 maxRetries,
418 maxDelayBetweenRetries).apply(null);
419 }
420
421 /**
Thomas Vachuskaadba1522015-06-04 15:08:30 -0700422 * Suspends the current thread for a random number of millis between 0 and
423 * the indicated limit.
424 *
425 * @param ms max number of millis
426 */
427 public static void randomDelay(int ms) {
428 try {
429 Thread.sleep(random.nextInt(ms));
430 } catch (InterruptedException e) {
431 throw new RuntimeException("Interrupted", e);
432 }
433 }
434
435 /**
Thomas Vachuskac40d4632015-04-09 16:55:03 -0700436 * Suspends the current thread for a specified number of millis and nanos.
437 *
438 * @param ms number of millis
439 * @param nanos number of nanos
440 */
441 public static void delay(int ms, int nanos) {
442 try {
443 Thread.sleep(ms, nanos);
444 } catch (InterruptedException e) {
445 throw new RuntimeException("Interrupted", e);
446 }
447 }
448
449 /**
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800450 * Purges the specified directory path.&nbsp;Use with great caution since
451 * no attempt is made to check for symbolic links, which could result in
452 * deletion of unintended files.
453 *
454 * @param path directory to be removed
455 * @throws java.io.IOException if unable to remove contents
456 */
457 public static void removeDirectory(String path) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800458 DirectoryDeleter visitor = new DirectoryDeleter();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700459 File dir = new File(path);
460 if (dir.exists() && dir.isDirectory()) {
461 walkFileTree(Paths.get(path), visitor);
462 if (visitor.exception != null) {
463 throw visitor.exception;
464 }
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800465 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800466 }
467
468 /**
469 * Purges the specified directory path.&nbsp;Use with great caution since
470 * no attempt is made to check for symbolic links, which could result in
471 * deletion of unintended files.
472 *
473 * @param dir directory to be removed
474 * @throws java.io.IOException if unable to remove contents
475 */
476 public static void removeDirectory(File dir) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800477 DirectoryDeleter visitor = new DirectoryDeleter();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700478 if (dir.exists() && dir.isDirectory()) {
479 walkFileTree(Paths.get(dir.getAbsolutePath()), visitor);
480 if (visitor.exception != null) {
481 throw visitor.exception;
482 }
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800483 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800484 }
485
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800486 // Auxiliary path visitor for recursive directory structure removal.
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800487 private static class DirectoryDeleter extends SimpleFileVisitor<Path> {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800488
489 private IOException exception;
490
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800491 @Override
492 public FileVisitResult visitFile(Path file, BasicFileAttributes attributes)
493 throws IOException {
494 if (attributes.isRegularFile()) {
495 delete(file);
496 }
497 return FileVisitResult.CONTINUE;
498 }
499
500 @Override
501 public FileVisitResult postVisitDirectory(Path directory, IOException ioe)
502 throws IOException {
503 delete(directory);
504 return FileVisitResult.CONTINUE;
505 }
506
507 @Override
508 public FileVisitResult visitFileFailed(Path file, IOException ioe)
509 throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800510 this.exception = ioe;
511 return FileVisitResult.TERMINATE;
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800512 }
513 }
514
Madan Jampani30a57f82015-03-02 12:19:41 -0800515 /**
516 * Returns a human friendly time ago string for a specified system time.
Thomas Vachuska480adad2015-03-06 10:27:09 -0800517 *
Madan Jampani30a57f82015-03-02 12:19:41 -0800518 * @param unixTime system time in millis
519 * @return human friendly time ago
520 */
521 public static String timeAgo(long unixTime) {
522 long deltaMillis = System.currentTimeMillis() - unixTime;
523 long secondsSince = (long) (deltaMillis / 1000.0);
524 long minsSince = (long) (deltaMillis / (1000.0 * 60));
525 long hoursSince = (long) (deltaMillis / (1000.0 * 60 * 60));
526 long daysSince = (long) (deltaMillis / (1000.0 * 60 * 60 * 24));
527 if (daysSince > 0) {
528 return String.format("%dd ago", daysSince);
529 } else if (hoursSince > 0) {
530 return String.format("%dh ago", hoursSince);
531 } else if (minsSince > 0) {
532 return String.format("%dm ago", minsSince);
533 } else if (secondsSince > 0) {
534 return String.format("%ds ago", secondsSince);
535 } else {
536 return "just now";
537 }
538 }
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800539
540 /**
541 * Copies the specified directory path.&nbsp;Use with great caution since
542 * no attempt is made to check for symbolic links, which could result in
543 * copy of unintended files.
544 *
545 * @param src directory to be copied
546 * @param dst destination directory to be removed
547 * @throws java.io.IOException if unable to remove contents
548 */
549 public static void copyDirectory(String src, String dst) throws IOException {
550 walkFileTree(Paths.get(src), new DirectoryCopier(src, dst));
551 }
552
553 /**
554 * Copies the specified directory path.&nbsp;Use with great caution since
555 * no attempt is made to check for symbolic links, which could result in
556 * copy of unintended files.
557 *
558 * @param src directory to be copied
559 * @param dst destination directory to be removed
560 * @throws java.io.IOException if unable to remove contents
561 */
562 public static void copyDirectory(File src, File dst) throws IOException {
563 walkFileTree(Paths.get(src.getAbsolutePath()),
564 new DirectoryCopier(src.getAbsolutePath(),
565 dst.getAbsolutePath()));
566 }
567
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700568 /**
569 * Returns the future value when complete or if future
570 * completes exceptionally returns the defaultValue.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700571 *
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700572 * @param future future
573 * @param defaultValue default value
574 * @param <T> future value type
575 * @return future value when complete or if future
576 * completes exceptionally returns the defaultValue.
577 */
578 public static <T> T futureGetOrElse(Future<T> future, T defaultValue) {
579 try {
580 return future.get();
581 } catch (InterruptedException e) {
582 Thread.currentThread().interrupt();
583 return defaultValue;
584 } catch (ExecutionException e) {
585 return defaultValue;
586 }
587 }
588
589 /**
590 * Returns the future value when complete or if future
591 * completes exceptionally returns the defaultValue.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700592 *
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700593 * @param future future
594 * @param timeout time to wait for successful completion
595 * @param timeUnit time unit
596 * @param defaultValue default value
597 * @param <T> future value type
598 * @return future value when complete or if future
599 * completes exceptionally returns the defaultValue.
600 */
601 public static <T> T futureGetOrElse(Future<T> future,
602 long timeout,
603 TimeUnit timeUnit,
604 T defaultValue) {
605 try {
606 return future.get(timeout, timeUnit);
607 } catch (InterruptedException e) {
608 Thread.currentThread().interrupt();
609 return defaultValue;
610 } catch (ExecutionException | TimeoutException e) {
611 return defaultValue;
612 }
613 }
614
Madan Jampani27b69c62015-05-15 15:49:02 -0700615 /**
616 * Returns a future that is completed exceptionally.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700617 *
Madan Jampani27b69c62015-05-15 15:49:02 -0700618 * @param t exception
619 * @param <T> future value type
620 * @return future
621 */
622 public static <T> CompletableFuture<T> exceptionalFuture(Throwable t) {
623 CompletableFuture<T> future = new CompletableFuture<>();
624 future.completeExceptionally(t);
625 return future;
626 }
627
628 /**
Sho SHIMIZU85803e22016-01-13 21:53:43 -0800629 * Returns a new CompletableFuture completed with a list of computed values
630 * when all of the given CompletableFuture complete.
631 *
632 * @param futures the CompletableFutures
633 * @param <T> value type of CompletableFuture
634 * @return a new CompletableFuture that is completed when all of the given CompletableFutures complete
635 */
636 public static <T> CompletableFuture<List<T>> allOf(List<CompletableFuture<T>> futures) {
637 return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]))
638 .thenApply(v -> futures.stream()
639 .map(CompletableFuture::join)
640 .collect(Collectors.toList())
641 );
642 }
643
644 /**
Madan Jampani27b69c62015-05-15 15:49:02 -0700645 * Returns the contents of {@code ByteBuffer} as byte array.
646 * <p>
647 * WARNING: There is a performance cost due to array copy
648 * when using this method.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700649 *
Madan Jampani27b69c62015-05-15 15:49:02 -0700650 * @param buffer byte buffer
651 * @return byte array containing the byte buffer contents
652 */
653 public static byte[] byteBuffertoArray(ByteBuffer buffer) {
654 int length = buffer.remaining();
655 if (buffer.hasArray()) {
656 int offset = buffer.arrayOffset() + buffer.position();
657 return Arrays.copyOfRange(buffer.array(), offset, offset + length);
658 }
659 byte[] bytes = new byte[length];
660 buffer.duplicate().get(bytes);
661 return bytes;
662 }
663
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700664 /**
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700665 * Converts an iterable to a stream.
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700666 *
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700667 * @param it iterable to convert
668 * @param <T> type if item
669 * @return iterable as a stream
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700670 */
671 public static <T> Stream<T> stream(Iterable<T> it) {
672 return StreamSupport.stream(it.spliterator(), false);
673 }
674
Sho SHIMIZUb5638b82016-02-11 14:55:05 -0800675 /**
676 * Converts an optional to a stream.
677 *
678 * @param optional optional to convert
679 * @param <T> type of enclosed value
680 * @return optional as a stream
681 */
Sho SHIMIZU6ac20982016-05-04 09:50:54 -0700682 public static <T> Stream<T> stream(Optional<? extends T> optional) {
HIGUCHI Yuta0bc256f2016-05-06 15:28:26 -0700683 return optional.map(x -> Stream.<T>of(x)).orElse(Stream.empty());
Sho SHIMIZUb5638b82016-02-11 14:55:05 -0800684 }
685
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800686 // Auxiliary path visitor for recursive directory structure copying.
687 private static class DirectoryCopier extends SimpleFileVisitor<Path> {
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800688 private Path src;
689 private Path dst;
690 private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING;
691
692 DirectoryCopier(String src, String dst) {
693 this.src = Paths.get(src);
694 this.dst = Paths.get(dst);
695 }
696
697 @Override
698 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
699 Path targetPath = dst.resolve(src.relativize(dir));
700 if (!Files.exists(targetPath)) {
701 Files.createDirectory(targetPath);
702 }
703 return FileVisitResult.CONTINUE;
704 }
705
706 @Override
707 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
708 Files.copy(file, dst.resolve(src.relativize(file)), copyOption);
709 return FileVisitResult.CONTINUE;
710 }
711 }
712
tom5f38b3a2014-08-27 23:50:54 -0700713}