blob: e3661720aec3463352ba78ad676a92c9810a964a [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 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
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080018import com.google.common.base.Strings;
19import com.google.common.primitives.UnsignedLongs;
20import com.google.common.util.concurrent.ThreadFactoryBuilder;
21import org.slf4j.Logger;
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;
28import java.nio.charset.StandardCharsets;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080029import java.nio.file.FileVisitResult;
Thomas Vachuska90b453f2015-01-30 18:57:14 -080030import java.nio.file.Files;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080031import java.nio.file.Path;
32import java.nio.file.Paths;
33import java.nio.file.SimpleFileVisitor;
Thomas Vachuska90b453f2015-01-30 18:57:14 -080034import java.nio.file.StandardCopyOption;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080035import java.nio.file.attribute.BasicFileAttributes;
tom53efab52014-10-07 17:43:48 -070036import java.util.ArrayList;
Brian O'Connore2eac102015-02-12 18:30:22 -080037import java.util.Collection;
tom53efab52014-10-07 17:43:48 -070038import java.util.List;
tom5f38b3a2014-08-27 23:50:54 -070039import java.util.concurrent.ThreadFactory;
40
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080041import static java.nio.file.Files.delete;
42import static java.nio.file.Files.walkFileTree;
43import static org.onlab.util.GroupedThreadFactory.groupedThreadFactory;
44import static org.slf4j.LoggerFactory.getLogger;
Ray Milkey705d9bc2014-11-18 08:19:00 -080045
tom5f38b3a2014-08-27 23:50:54 -070046public abstract class Tools {
47
48 private Tools() {
49 }
50
Thomas Vachuska02aeb032015-01-06 22:36:30 -080051 private static final Logger log = getLogger(Tools.class);
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080052
tom5f38b3a2014-08-27 23:50:54 -070053 /**
54 * Returns a thread factory that produces threads named according to the
55 * supplied name pattern.
56 *
57 * @param pattern name pattern
58 * @return thread factory
59 */
60 public static ThreadFactory namedThreads(String pattern) {
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080061 return new ThreadFactoryBuilder()
62 .setNameFormat(pattern)
Thomas Vachuska02aeb032015-01-06 22:36:30 -080063 // FIXME remove UncaughtExceptionHandler before release
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080064 .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on {}", t.getName(), e)).build();
65 }
Yuta HIGUCHI683e9782014-11-25 17:26:36 -080066
Thomas Vachuska9c17a6d2015-02-17 23:36:43 -080067 /**
68 * Returns a thread factory that produces threads named according to the
69 * supplied name pattern and from the specified thread-group. The thread
70 * group name is expected to be specified in slash-delimited format, e.g.
71 * {@code onos/intent}.
72 *
73 * @param groupName group name in slash-delimited format to indicate hierarchy
74 * @param pattern name pattern
75 * @return thread factory
76 */
77 public static ThreadFactory groupedThreads(String groupName, String pattern) {
78 return new ThreadFactoryBuilder()
79 .setThreadFactory(groupedThreadFactory(groupName))
80 .setNameFormat(pattern)
81 // FIXME remove UncaughtExceptionHandler before release
82 .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on {}", t.getName(), e)).build();
tom5f38b3a2014-08-27 23:50:54 -070083 }
84
tom782a7cf2014-09-11 23:58:38 -070085 /**
Yuta HIGUCHI06586272014-11-25 14:27:03 -080086 * Returns a thread factory that produces threads with MIN_PRIORITY.
87 *
88 * @param factory backing ThreadFactory
89 * @return thread factory
90 */
91 public static ThreadFactory minPriority(ThreadFactory factory) {
92 return new ThreadFactoryBuilder()
Thomas Vachuska02aeb032015-01-06 22:36:30 -080093 .setThreadFactory(factory)
94 .setPriority(Thread.MIN_PRIORITY)
95 .build();
Yuta HIGUCHI06586272014-11-25 14:27:03 -080096 }
97
98 /**
Brian O'Connore2eac102015-02-12 18:30:22 -080099 * Returns true if the collection is null or is empty.
100 *
101 * @param collection collection to test
102 * @return true if null or empty; false otherwise
103 */
104 public static boolean isNullOrEmpty(Collection collection) {
105 return collection == null || collection.isEmpty();
106 }
107
108 /**
tom782a7cf2014-09-11 23:58:38 -0700109 * Converts a string from hex to long.
110 *
111 * @param string hex number in string form; sans 0x
112 * @return long value
113 */
114 public static long fromHex(String string) {
115 return UnsignedLongs.parseUnsignedLong(string, 16);
116 }
117
118 /**
119 * Converts a long value to hex string; 16 wide and sans 0x.
120 *
121 * @param value long value
122 * @return hex string
123 */
124 public static String toHex(long value) {
125 return Strings.padStart(UnsignedLongs.toString(value, 16), 16, '0');
126 }
127
128 /**
129 * Converts a long value to hex string; 16 wide and sans 0x.
130 *
131 * @param value long value
132 * @param width string width; zero padded
133 * @return hex string
134 */
135 public static String toHex(long value, int width) {
136 return Strings.padStart(UnsignedLongs.toString(value, 16), width, '0');
137 }
tomf110fff2014-09-26 00:38:18 -0700138
139 /**
140 * Suspends the current thread for a specified number of millis.
141 *
142 * @param ms number of millis
143 */
144 public static void delay(int ms) {
145 try {
146 Thread.sleep(ms);
147 } catch (InterruptedException e) {
148 throw new RuntimeException("Interrupted", e);
149 }
150 }
151
tom53efab52014-10-07 17:43:48 -0700152 /**
153 * Slurps the contents of a file into a list of strings, one per line.
154 *
155 * @param path file path
156 * @return file contents
157 */
158 public static List<String> slurp(File path) {
Ray Milkey705d9bc2014-11-18 08:19:00 -0800159 try {
160 BufferedReader br = new BufferedReader(
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800161 new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8));
Ray Milkey705d9bc2014-11-18 08:19:00 -0800162
tom53efab52014-10-07 17:43:48 -0700163 List<String> lines = new ArrayList<>();
164 String line;
165 while ((line = br.readLine()) != null) {
166 lines.add(line);
167 }
168 return lines;
169
170 } catch (IOException e) {
171 return null;
172 }
173 }
174
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800175
176 /**
177 * Purges the specified directory path.&nbsp;Use with great caution since
178 * no attempt is made to check for symbolic links, which could result in
179 * deletion of unintended files.
180 *
181 * @param path directory to be removed
182 * @throws java.io.IOException if unable to remove contents
183 */
184 public static void removeDirectory(String path) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800185 DirectoryDeleter visitor = new DirectoryDeleter();
186 walkFileTree(Paths.get(path), visitor);
187 if (visitor.exception != null) {
188 throw visitor.exception;
189 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800190 }
191
192 /**
193 * Purges the specified directory path.&nbsp;Use with great caution since
194 * no attempt is made to check for symbolic links, which could result in
195 * deletion of unintended files.
196 *
197 * @param dir directory to be removed
198 * @throws java.io.IOException if unable to remove contents
199 */
200 public static void removeDirectory(File dir) throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800201 DirectoryDeleter visitor = new DirectoryDeleter();
202 walkFileTree(Paths.get(dir.getAbsolutePath()), visitor);
203 if (visitor.exception != null) {
204 throw visitor.exception;
205 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800206 }
207
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800208 // Auxiliary path visitor for recursive directory structure removal.
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800209 private static class DirectoryDeleter extends SimpleFileVisitor<Path> {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800210
211 private IOException exception;
212
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800213 @Override
214 public FileVisitResult visitFile(Path file, BasicFileAttributes attributes)
215 throws IOException {
216 if (attributes.isRegularFile()) {
217 delete(file);
218 }
219 return FileVisitResult.CONTINUE;
220 }
221
222 @Override
223 public FileVisitResult postVisitDirectory(Path directory, IOException ioe)
224 throws IOException {
225 delete(directory);
226 return FileVisitResult.CONTINUE;
227 }
228
229 @Override
230 public FileVisitResult visitFileFailed(Path file, IOException ioe)
231 throws IOException {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800232 this.exception = ioe;
233 return FileVisitResult.TERMINATE;
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800234 }
235 }
236
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800237
238 /**
239 * Copies the specified directory path.&nbsp;Use with great caution since
240 * no attempt is made to check for symbolic links, which could result in
241 * copy of unintended files.
242 *
243 * @param src directory to be copied
244 * @param dst destination directory to be removed
245 * @throws java.io.IOException if unable to remove contents
246 */
247 public static void copyDirectory(String src, String dst) throws IOException {
248 walkFileTree(Paths.get(src), new DirectoryCopier(src, dst));
249 }
250
251 /**
252 * Copies the specified directory path.&nbsp;Use with great caution since
253 * no attempt is made to check for symbolic links, which could result in
254 * copy of unintended files.
255 *
256 * @param src directory to be copied
257 * @param dst destination directory to be removed
258 * @throws java.io.IOException if unable to remove contents
259 */
260 public static void copyDirectory(File src, File dst) throws IOException {
261 walkFileTree(Paths.get(src.getAbsolutePath()),
262 new DirectoryCopier(src.getAbsolutePath(),
263 dst.getAbsolutePath()));
264 }
265
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800266 // Auxiliary path visitor for recursive directory structure copying.
267 private static class DirectoryCopier extends SimpleFileVisitor<Path> {
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800268 private Path src;
269 private Path dst;
270 private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING;
271
272 DirectoryCopier(String src, String dst) {
273 this.src = Paths.get(src);
274 this.dst = Paths.get(dst);
275 }
276
277 @Override
278 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
279 Path targetPath = dst.resolve(src.relativize(dir));
280 if (!Files.exists(targetPath)) {
281 Files.createDirectory(targetPath);
282 }
283 return FileVisitResult.CONTINUE;
284 }
285
286 @Override
287 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
288 Files.copy(file, dst.resolve(src.relativize(file)), copyOption);
289 return FileVisitResult.CONTINUE;
290 }
291 }
292
tom5f38b3a2014-08-27 23:50:54 -0700293}