blob: 9e690c00b1d5f86a1718a4e99b27a88a5a64962c [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 {
185 walkFileTree(Paths.get(path), new DirectoryDeleter());
186 }
187
188 /**
189 * Purges the specified directory path.&nbsp;Use with great caution since
190 * no attempt is made to check for symbolic links, which could result in
191 * deletion of unintended files.
192 *
193 * @param dir directory to be removed
194 * @throws java.io.IOException if unable to remove contents
195 */
196 public static void removeDirectory(File dir) throws IOException {
197 walkFileTree(Paths.get(dir.getAbsolutePath()), new DirectoryDeleter());
198 }
199
200
201 private static class DirectoryDeleter extends SimpleFileVisitor<Path> {
202 @Override
203 public FileVisitResult visitFile(Path file, BasicFileAttributes attributes)
204 throws IOException {
205 if (attributes.isRegularFile()) {
206 delete(file);
207 }
208 return FileVisitResult.CONTINUE;
209 }
210
211 @Override
212 public FileVisitResult postVisitDirectory(Path directory, IOException ioe)
213 throws IOException {
214 delete(directory);
215 return FileVisitResult.CONTINUE;
216 }
217
218 @Override
219 public FileVisitResult visitFileFailed(Path file, IOException ioe)
220 throws IOException {
221 log.warn("Unable to delete file {}", file);
222 log.warn("Boom", ioe);
223 return FileVisitResult.CONTINUE;
224 }
225 }
226
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800227
228 /**
229 * Copies the specified directory path.&nbsp;Use with great caution since
230 * no attempt is made to check for symbolic links, which could result in
231 * copy of unintended files.
232 *
233 * @param src directory to be copied
234 * @param dst destination directory to be removed
235 * @throws java.io.IOException if unable to remove contents
236 */
237 public static void copyDirectory(String src, String dst) throws IOException {
238 walkFileTree(Paths.get(src), new DirectoryCopier(src, dst));
239 }
240
241 /**
242 * Copies the specified directory path.&nbsp;Use with great caution since
243 * no attempt is made to check for symbolic links, which could result in
244 * copy of unintended files.
245 *
246 * @param src directory to be copied
247 * @param dst destination directory to be removed
248 * @throws java.io.IOException if unable to remove contents
249 */
250 public static void copyDirectory(File src, File dst) throws IOException {
251 walkFileTree(Paths.get(src.getAbsolutePath()),
252 new DirectoryCopier(src.getAbsolutePath(),
253 dst.getAbsolutePath()));
254 }
255
256
257 public static class DirectoryCopier extends SimpleFileVisitor<Path> {
258 private Path src;
259 private Path dst;
260 private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING;
261
262 DirectoryCopier(String src, String dst) {
263 this.src = Paths.get(src);
264 this.dst = Paths.get(dst);
265 }
266
267 @Override
268 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
269 Path targetPath = dst.resolve(src.relativize(dir));
270 if (!Files.exists(targetPath)) {
271 Files.createDirectory(targetPath);
272 }
273 return FileVisitResult.CONTINUE;
274 }
275
276 @Override
277 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
278 Files.copy(file, dst.resolve(src.relativize(file)), copyOption);
279 return FileVisitResult.CONTINUE;
280 }
281 }
282
tom5f38b3a2014-08-27 23:50:54 -0700283}