blob: 296e14b5d72eed0903e44dbfb45af9ba64b72cac [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;
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -070052import java.util.stream.Stream;
53import java.util.stream.StreamSupport;
tom5f38b3a2014-08-27 23:50:54 -070054
Madan Jampani2bfa94c2015-04-11 05:03:49 -070055import org.slf4j.Logger;
56
Madan Jampanif2f086c2016-01-13 16:15:39 -080057import com.google.common.base.Charsets;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070058import com.google.common.base.Strings;
59import com.google.common.primitives.UnsignedLongs;
60import com.google.common.util.concurrent.ThreadFactoryBuilder;
Ray Milkey705d9bc2014-11-18 08:19:00 -080061
Thomas Vachuskac13b90a2015-02-18 18:19:55 -080062/**
63 * Miscellaneous utility methods.
64 */
tom5f38b3a2014-08-27 23:50:54 -070065public abstract class Tools {
66
67 private Tools() {
68 }
69
Thomas Vachuska02aeb032015-01-06 22:36:30 -080070 private static final Logger log = getLogger(Tools.class);
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080071
Thomas Vachuskaadba1522015-06-04 15:08:30 -070072 private static Random random = new Random();
73
tom5f38b3a2014-08-27 23:50:54 -070074 /**
75 * Returns a thread factory that produces threads named according to the
76 * supplied name pattern.
77 *
78 * @param pattern name pattern
79 * @return thread factory
80 */
81 public static ThreadFactory namedThreads(String pattern) {
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080082 return new ThreadFactoryBuilder()
83 .setNameFormat(pattern)
Thomas Vachuska480adad2015-03-06 10:27:09 -080084 .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on " + t.getName(), e))
85 .build();
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080086 }
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080087
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080088 /**
89 * Returns a thread factory that produces threads named according to the
90 * supplied name pattern and from the specified thread-group. The thread
91 * group name is expected to be specified in slash-delimited format, e.g.
Thomas Vachuskac13b90a2015-02-18 18:19:55 -080092 * {@code onos/intent}. The thread names will be produced by converting
93 * the thread group name into dash-delimited format and pre-pended to the
94 * specified pattern.
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080095 *
96 * @param groupName group name in slash-delimited format to indicate hierarchy
97 * @param pattern name pattern
98 * @return thread factory
99 */
100 public static ThreadFactory groupedThreads(String groupName, String pattern) {
101 return new ThreadFactoryBuilder()
102 .setThreadFactory(groupedThreadFactory(groupName))
Thomas Vachuskac13b90a2015-02-18 18:19:55 -0800103 .setNameFormat(groupName.replace(GroupedThreadFactory.DELIMITER, "-") + "-" + pattern)
Thomas Vachuska480adad2015-03-06 10:27:09 -0800104 .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on " + t.getName(), e))
105 .build();
tom5f38b3a2014-08-27 23:50:54 -0700106 }
107
tom782a7cf2014-09-11 23:58:38 -0700108 /**
Yuta HIGUCHI06586272014-11-25 14:27:03 -0800109 * Returns a thread factory that produces threads with MIN_PRIORITY.
110 *
111 * @param factory backing ThreadFactory
112 * @return thread factory
113 */
114 public static ThreadFactory minPriority(ThreadFactory factory) {
115 return new ThreadFactoryBuilder()
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800116 .setThreadFactory(factory)
117 .setPriority(Thread.MIN_PRIORITY)
118 .build();
Yuta HIGUCHI06586272014-11-25 14:27:03 -0800119 }
120
121 /**
Brian O'Connore2eac102015-02-12 18:30:22 -0800122 * Returns true if the collection is null or is empty.
123 *
124 * @param collection collection to test
125 * @return true if null or empty; false otherwise
126 */
127 public static boolean isNullOrEmpty(Collection collection) {
128 return collection == null || collection.isEmpty();
129 }
130
131 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700132 * Returns the specified item if that item is not null; otherwise throws
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700133 * not found exception.
134 *
135 * @param item item to check
136 * @param message not found message
137 * @param <T> item type
138 * @return item if not null
139 * @throws org.onlab.util.ItemNotFoundException if item is null
140 */
141 public static <T> T nullIsNotFound(T item, String message) {
142 if (item == null) {
143 throw new ItemNotFoundException(message);
144 }
145 return item;
146 }
147
148 /**
Ray Milkey36992c82015-11-17 13:31:15 -0800149 * Returns the specified set if the set is not null and not empty;
150 * otherwise throws a not found exception.
151 *
152 * @param item set to check
153 * @param message not found message
154 * @param <T> Set item type
155 * @return item if not null and not empty
156 * @throws org.onlab.util.ItemNotFoundException if set is null or empty
157 */
158 public static <T> Set<T> emptyIsNotFound(Set<T> item, String message) {
159 if (item == null || item.isEmpty()) {
160 throw new ItemNotFoundException(message);
161 }
162 return item;
163 }
164
165 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700166 * Returns the specified item if that item is not null; otherwise throws
167 * bad argument exception.
168 *
169 * @param item item to check
170 * @param message not found message
171 * @param <T> item type
172 * @return item if not null
173 * @throws IllegalArgumentException if item is null
174 */
175 public static <T> T nullIsIllegal(T item, String message) {
176 if (item == null) {
177 throw new IllegalArgumentException(message);
178 }
179 return item;
180 }
181
182 /**
tom782a7cf2014-09-11 23:58:38 -0700183 * Converts a string from hex to long.
184 *
185 * @param string hex number in string form; sans 0x
186 * @return long value
187 */
188 public static long fromHex(String string) {
189 return UnsignedLongs.parseUnsignedLong(string, 16);
190 }
191
192 /**
193 * Converts a long value to hex string; 16 wide and sans 0x.
194 *
195 * @param value long value
196 * @return hex string
197 */
198 public static String toHex(long value) {
199 return Strings.padStart(UnsignedLongs.toString(value, 16), 16, '0');
200 }
201
202 /**
203 * Converts a long value to hex string; 16 wide and sans 0x.
204 *
205 * @param value long value
206 * @param width string width; zero padded
207 * @return hex string
208 */
209 public static String toHex(long value, int width) {
210 return Strings.padStart(UnsignedLongs.toString(value, 16), width, '0');
211 }
tomf110fff2014-09-26 00:38:18 -0700212
213 /**
Madan Jampanif2f086c2016-01-13 16:15:39 -0800214 * Returns the UTF-8 encoded byte[] representation of a String.
215 */
216 public static byte[] getBytesUtf8(String input) {
217 return input.getBytes(Charsets.UTF_8);
218 }
219
220 /**
221 * Returns the String representation of UTF-8 encoded byte[].
222 */
223 public static String toStringUtf8(byte[] input) {
224 return new String(input, Charsets.UTF_8);
225 }
226
227 /**
Madan Jampani9eb55d12015-08-14 07:47:56 -0700228 * Returns a copy of the input byte array.
229 *
230 * @param original input
231 * @return copy of original
232 */
233 public static byte[] copyOf(byte[] original) {
234 return Arrays.copyOf(original, original.length);
235 }
236
237 /**
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700238 * Get property as a string value.
239 *
240 * @param properties properties to be looked up
241 * @param propertyName the name of the property to look up
242 * @return value when the propertyName is defined or return null
243 */
244 public static String get(Dictionary<?, ?> properties, String propertyName) {
245 Object v = properties.get(propertyName);
246 String s = (v instanceof String) ? (String) v :
247 v != null ? v.toString() : null;
248 return Strings.isNullOrEmpty(s) ? null : s.trim();
249 }
250
251 /**
tomf110fff2014-09-26 00:38:18 -0700252 * Suspends the current thread for a specified number of millis.
253 *
254 * @param ms number of millis
255 */
256 public static void delay(int ms) {
257 try {
258 Thread.sleep(ms);
259 } catch (InterruptedException e) {
260 throw new RuntimeException("Interrupted", e);
261 }
262 }
263
tom53efab52014-10-07 17:43:48 -0700264 /**
Madan Jampania29c6772015-08-17 13:17:07 -0700265 * Returns a function that retries execution on failure.
266 * @param base base function
267 * @param exceptionClass type of exception for which to retry
268 * @param maxRetries max number of retries before giving up
269 * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from
270 * the interval (0, maxDelayBetweenRetries]
271 * @return function
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700272 * @param <U> type of function input
273 * @param <V> type of function output
Madan Jampania29c6772015-08-17 13:17:07 -0700274 */
275 public static <U, V> Function<U, V> retryable(Function<U, V> base,
276 Class<? extends Throwable> exceptionClass,
277 int maxRetries,
278 int maxDelayBetweenRetries) {
279 return new RetryingFunction<>(base, exceptionClass, maxRetries, maxDelayBetweenRetries);
280 }
281
282 /**
283 * Returns a Supplier that retries execution on failure.
284 * @param base base supplier
285 * @param exceptionClass type of exception for which to retry
286 * @param maxRetries max number of retries before giving up
287 * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from
288 * the interval (0, maxDelayBetweenRetries]
289 * @return supplier
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700290 * @param <V> type of supplied result
Madan Jampania29c6772015-08-17 13:17:07 -0700291 */
292 public static <V> Supplier<V> retryable(Supplier<V> base,
293 Class<? extends Throwable> exceptionClass,
294 int maxRetries,
295 int maxDelayBetweenRetries) {
296 return () -> new RetryingFunction<>(v -> base.get(),
297 exceptionClass,
298 maxRetries,
299 maxDelayBetweenRetries).apply(null);
300 }
301
302 /**
Thomas Vachuskaadba1522015-06-04 15:08:30 -0700303 * Suspends the current thread for a random number of millis between 0 and
304 * the indicated limit.
305 *
306 * @param ms max number of millis
307 */
308 public static void randomDelay(int ms) {
309 try {
310 Thread.sleep(random.nextInt(ms));
311 } catch (InterruptedException e) {
312 throw new RuntimeException("Interrupted", e);
313 }
314 }
315
316 /**
Thomas Vachuskac40d4632015-04-09 16:55:03 -0700317 * Suspends the current thread for a specified number of millis and nanos.
318 *
319 * @param ms number of millis
320 * @param nanos number of nanos
321 */
322 public static void delay(int ms, int nanos) {
323 try {
324 Thread.sleep(ms, nanos);
325 } catch (InterruptedException e) {
326 throw new RuntimeException("Interrupted", e);
327 }
328 }
329
330 /**
tom53efab52014-10-07 17:43:48 -0700331 * Slurps the contents of a file into a list of strings, one per line.
332 *
333 * @param path file path
334 * @return file contents
HIGUCHI Yuta3b3bd1e2015-09-22 16:39:33 -0700335 * @deprecated in Emu release
tom53efab52014-10-07 17:43:48 -0700336 */
HIGUCHI Yuta3b3bd1e2015-09-22 16:39:33 -0700337 @Deprecated
tom53efab52014-10-07 17:43:48 -0700338 public static List<String> slurp(File path) {
HIGUCHI Yutacf4d6172015-09-22 16:39:33 -0700339 try (
Ray Milkey705d9bc2014-11-18 08:19:00 -0800340 BufferedReader br = new BufferedReader(
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800341 new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8));
HIGUCHI Yutacf4d6172015-09-22 16:39:33 -0700342 ) {
tom53efab52014-10-07 17:43:48 -0700343 List<String> lines = new ArrayList<>();
344 String line;
345 while ((line = br.readLine()) != null) {
346 lines.add(line);
347 }
348 return lines;
349
350 } catch (IOException e) {
351 return null;
352 }
353 }
354
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800355 /**
356 * Purges the specified directory path.&nbsp;Use with great caution since
357 * no attempt is made to check for symbolic links, which could result in
358 * deletion of unintended files.
359 *
360 * @param path directory to be removed
361 * @throws java.io.IOException if unable to remove contents
362 */
363 public static void removeDirectory(String path) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800364 DirectoryDeleter visitor = new DirectoryDeleter();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700365 File dir = new File(path);
366 if (dir.exists() && dir.isDirectory()) {
367 walkFileTree(Paths.get(path), visitor);
368 if (visitor.exception != null) {
369 throw visitor.exception;
370 }
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800371 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800372 }
373
374 /**
375 * Purges the specified directory path.&nbsp;Use with great caution since
376 * no attempt is made to check for symbolic links, which could result in
377 * deletion of unintended files.
378 *
379 * @param dir directory to be removed
380 * @throws java.io.IOException if unable to remove contents
381 */
382 public static void removeDirectory(File dir) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800383 DirectoryDeleter visitor = new DirectoryDeleter();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700384 if (dir.exists() && dir.isDirectory()) {
385 walkFileTree(Paths.get(dir.getAbsolutePath()), visitor);
386 if (visitor.exception != null) {
387 throw visitor.exception;
388 }
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800389 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800390 }
391
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800392 // Auxiliary path visitor for recursive directory structure removal.
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800393 private static class DirectoryDeleter extends SimpleFileVisitor<Path> {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800394
395 private IOException exception;
396
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800397 @Override
398 public FileVisitResult visitFile(Path file, BasicFileAttributes attributes)
399 throws IOException {
400 if (attributes.isRegularFile()) {
401 delete(file);
402 }
403 return FileVisitResult.CONTINUE;
404 }
405
406 @Override
407 public FileVisitResult postVisitDirectory(Path directory, IOException ioe)
408 throws IOException {
409 delete(directory);
410 return FileVisitResult.CONTINUE;
411 }
412
413 @Override
414 public FileVisitResult visitFileFailed(Path file, IOException ioe)
415 throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800416 this.exception = ioe;
417 return FileVisitResult.TERMINATE;
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800418 }
419 }
420
Madan Jampani30a57f82015-03-02 12:19:41 -0800421 /**
422 * Returns a human friendly time ago string for a specified system time.
Thomas Vachuska480adad2015-03-06 10:27:09 -0800423 *
Madan Jampani30a57f82015-03-02 12:19:41 -0800424 * @param unixTime system time in millis
425 * @return human friendly time ago
426 */
427 public static String timeAgo(long unixTime) {
428 long deltaMillis = System.currentTimeMillis() - unixTime;
429 long secondsSince = (long) (deltaMillis / 1000.0);
430 long minsSince = (long) (deltaMillis / (1000.0 * 60));
431 long hoursSince = (long) (deltaMillis / (1000.0 * 60 * 60));
432 long daysSince = (long) (deltaMillis / (1000.0 * 60 * 60 * 24));
433 if (daysSince > 0) {
434 return String.format("%dd ago", daysSince);
435 } else if (hoursSince > 0) {
436 return String.format("%dh ago", hoursSince);
437 } else if (minsSince > 0) {
438 return String.format("%dm ago", minsSince);
439 } else if (secondsSince > 0) {
440 return String.format("%ds ago", secondsSince);
441 } else {
442 return "just now";
443 }
444 }
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800445
446 /**
447 * Copies the specified directory path.&nbsp;Use with great caution since
448 * no attempt is made to check for symbolic links, which could result in
449 * copy of unintended files.
450 *
451 * @param src directory to be copied
452 * @param dst destination directory to be removed
453 * @throws java.io.IOException if unable to remove contents
454 */
455 public static void copyDirectory(String src, String dst) throws IOException {
456 walkFileTree(Paths.get(src), new DirectoryCopier(src, dst));
457 }
458
459 /**
460 * Copies the specified directory path.&nbsp;Use with great caution since
461 * no attempt is made to check for symbolic links, which could result in
462 * copy of unintended files.
463 *
464 * @param src directory to be copied
465 * @param dst destination directory to be removed
466 * @throws java.io.IOException if unable to remove contents
467 */
468 public static void copyDirectory(File src, File dst) throws IOException {
469 walkFileTree(Paths.get(src.getAbsolutePath()),
470 new DirectoryCopier(src.getAbsolutePath(),
471 dst.getAbsolutePath()));
472 }
473
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700474 /**
475 * Returns the future value when complete or if future
476 * completes exceptionally returns the defaultValue.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700477 *
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700478 * @param future future
479 * @param defaultValue default value
480 * @param <T> future value type
481 * @return future value when complete or if future
482 * completes exceptionally returns the defaultValue.
483 */
484 public static <T> T futureGetOrElse(Future<T> future, T defaultValue) {
485 try {
486 return future.get();
487 } catch (InterruptedException e) {
488 Thread.currentThread().interrupt();
489 return defaultValue;
490 } catch (ExecutionException e) {
491 return defaultValue;
492 }
493 }
494
495 /**
496 * Returns the future value when complete or if future
497 * completes exceptionally returns the defaultValue.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700498 *
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700499 * @param future future
500 * @param timeout time to wait for successful completion
501 * @param timeUnit time unit
502 * @param defaultValue default value
503 * @param <T> future value type
504 * @return future value when complete or if future
505 * completes exceptionally returns the defaultValue.
506 */
507 public static <T> T futureGetOrElse(Future<T> future,
508 long timeout,
509 TimeUnit timeUnit,
510 T defaultValue) {
511 try {
512 return future.get(timeout, timeUnit);
513 } catch (InterruptedException e) {
514 Thread.currentThread().interrupt();
515 return defaultValue;
516 } catch (ExecutionException | TimeoutException e) {
517 return defaultValue;
518 }
519 }
520
Madan Jampani27b69c62015-05-15 15:49:02 -0700521 /**
522 * Returns a future that is completed exceptionally.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700523 *
Madan Jampani27b69c62015-05-15 15:49:02 -0700524 * @param t exception
525 * @param <T> future value type
526 * @return future
527 */
528 public static <T> CompletableFuture<T> exceptionalFuture(Throwable t) {
529 CompletableFuture<T> future = new CompletableFuture<>();
530 future.completeExceptionally(t);
531 return future;
532 }
533
534 /**
535 * Returns the contents of {@code ByteBuffer} as byte array.
536 * <p>
537 * WARNING: There is a performance cost due to array copy
538 * when using this method.
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700539 *
Madan Jampani27b69c62015-05-15 15:49:02 -0700540 * @param buffer byte buffer
541 * @return byte array containing the byte buffer contents
542 */
543 public static byte[] byteBuffertoArray(ByteBuffer buffer) {
544 int length = buffer.remaining();
545 if (buffer.hasArray()) {
546 int offset = buffer.arrayOffset() + buffer.position();
547 return Arrays.copyOfRange(buffer.array(), offset, offset + length);
548 }
549 byte[] bytes = new byte[length];
550 buffer.duplicate().get(bytes);
551 return bytes;
552 }
553
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700554 /**
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700555 * Converts an iterable to a stream.
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700556 *
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700557 * @param it iterable to convert
558 * @param <T> type if item
559 * @return iterable as a stream
HIGUCHI Yutabfc8b7a2015-07-01 23:47:43 -0700560 */
561 public static <T> Stream<T> stream(Iterable<T> it) {
562 return StreamSupport.stream(it.spliterator(), false);
563 }
564
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800565 // Auxiliary path visitor for recursive directory structure copying.
566 private static class DirectoryCopier extends SimpleFileVisitor<Path> {
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800567 private Path src;
568 private Path dst;
569 private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING;
570
571 DirectoryCopier(String src, String dst) {
572 this.src = Paths.get(src);
573 this.dst = Paths.get(dst);
574 }
575
576 @Override
577 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
578 Path targetPath = dst.resolve(src.relativize(dir));
579 if (!Files.exists(targetPath)) {
580 Files.createDirectory(targetPath);
581 }
582 return FileVisitResult.CONTINUE;
583 }
584
585 @Override
586 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
587 Files.copy(file, dst.resolve(src.relativize(file)), copyOption);
588 return FileVisitResult.CONTINUE;
589 }
590 }
591
tom5f38b3a2014-08-27 23:50:54 -0700592}