View Javadoc
1   /*
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   */
14  package de.softwareforge.testing.postgres.embedded;
15  
16  import static com.google.common.base.Preconditions.checkArgument;
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.net.ServerSocket;
21  import java.nio.file.Files;
22  import java.nio.file.Path;
23  import java.time.Duration;
24  import java.util.Comparator;
25  import java.util.Locale;
26  import java.util.Objects;
27  import java.util.concurrent.ThreadLocalRandom;
28  import java.util.stream.Stream;
29  
30  import com.google.common.base.Joiner;
31  import com.google.common.base.Strings;
32  import com.google.common.collect.ImmutableList;
33  import edu.umd.cs.findbugs.annotations.NonNull;
34  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35  
36  final class EmbeddedUtil {
37  
38      static final String OS_NAME;
39      static final String OS_ARCH;
40  
41      static final boolean IS_OS_WINDOWS;
42      static final boolean IS_OS_MAC;
43      static final boolean IS_OS_LINUX;
44      static final boolean IS_ALPINE_LINUX;
45  
46      static final boolean IS_ARCH_X86_64;
47      static final boolean IS_ARCH_AARCH64;
48      static final boolean IS_ARCH_AARCH32;
49  
50      private static final String ALPHANUM;
51      private static final String LOWERCASE;
52  
53      static {
54          OS_NAME = getSystemProperty("os.name");
55          OS_ARCH = getSystemProperty("os.arch");
56  
57          IS_OS_WINDOWS = getOsMatchesName("Windows");
58          IS_OS_LINUX = getOsMatchesName("Linux");
59          IS_OS_MAC = getOsMatchesName("Mac");
60  
61          IS_ARCH_X86_64 = OS_ARCH.equals("x86_64") || OS_ARCH.equals("amd64");
62          IS_ARCH_AARCH64 = OS_ARCH.equals("aarch64");
63          IS_ARCH_AARCH32 = OS_ARCH.equals("aarch32") || OS_ARCH.equals("arm");
64  
65          // this is a glorious hack
66          IS_ALPINE_LINUX = new File("/etc/alpine-release").exists();
67  
68          String numbers = sequence('0', 10);
69          LOWERCASE = sequence('a', 26);
70          String uppercase = sequence('A', 26);
71          ALPHANUM = numbers + LOWERCASE + uppercase;
72      }
73  
74      private EmbeddedUtil() {
75          throw new AssertionError("EmbeddedUtil can not be instantiated");
76      }
77  
78      static File getWorkingDirectory() {
79          File tmpDir = new File(System.getProperty("java.io.tmpdir"));
80          // personalize the unpack folder to allow systems with many users using the same tmp folder to work
81          return new File(tmpDir, "embedded-pg-" + Objects.requireNonNullElse(System.getProperty("user.name"), "unknown"));
82      }
83  
84      //
85      // taken from apache commons io
86      //
87      static String getFileBaseName(final String fileName) {
88          if (fileName == null) {
89              return null;
90          }
91          failIfNullBytePresent(fileName);
92          final int index = indexOfLastSeparator(fileName);
93          return fileName.substring(index + 1);
94      }
95  
96      private static void failIfNullBytePresent(final String path) {
97          final int len = path.length();
98          for (int i = 0; i < len; i++) {
99              checkArgument(path.charAt(i) != 0,
100                     "Null byte present in file/path name.");
101         }
102     }
103 
104     private static int indexOfLastSeparator(final String fileName) {
105         if (fileName == null) {
106             return -1;
107         }
108         final int lastUnixPos = fileName.lastIndexOf('/'); // unix
109         final int lastWindowsPos = fileName.lastIndexOf('\\'); // windows
110         return Math.max(lastUnixPos, lastWindowsPos);
111     }
112 
113     //
114     // taken from apache commons io
115     //
116 
117     static void mkdirs(@NonNull File dir) {
118         if (!dir.mkdirs() && !(dir.isDirectory() && dir.exists())) {
119             throw new IllegalStateException("could not create " + dir);
120         }
121     }
122 
123     @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE")
124     static void rmdirs(File dir) throws IOException {
125         try (Stream<Path> walk = Files.walk(dir.toPath())) {
126             walk.sorted(Comparator.reverseOrder())
127                     .map(Path::toFile)
128                     .forEach(File::delete);
129         }
130     }
131 
132     static String formatDuration(Duration duration) {
133         long millis = duration.toMillis();
134         long hours;
135         long minutes;
136         long secs;
137         long ms;
138         ImmutableList.Builder<String> builder = ImmutableList.builder();
139         if (millis == 0) {
140             builder.add("0 ms");
141         } else {
142             long seconds = millis / 1000L;
143             hours = seconds / 3600L;
144             minutes = (seconds % 3600L) / 60L;
145             secs = (seconds % 60L);
146             ms = millis % 1000L;
147 
148             if (hours != 0) {
149                 builder.add(hours + " hours");
150             }
151             if (minutes != 0) {
152                 builder.add(minutes + " minutes");
153             }
154             if (secs != 0) {
155                 builder.add(secs + " seconds");
156             }
157             if (ms != 0) {
158                 builder.add(ms + " ms");
159             }
160         }
161 
162         return Joiner.on(' ').join(builder.build());
163     }
164 
165     static int allocatePort() throws IOException {
166         try (ServerSocket socket = new ServerSocket(0)) {
167             while (!socket.isBound()) {
168                 Thread.sleep(50);
169             }
170             return socket.getLocalPort();
171         } catch (InterruptedException e) {
172             Thread.currentThread().interrupt();
173             throw new IOException("Thread interrupted!", e);
174         }
175     }
176 
177     static String randomAlphaNumeric(int length) {
178         return randomString(ALPHANUM, length);
179     }
180 
181     static String randomLowercase(int length) {
182         return randomString(LOWERCASE, length);
183     }
184 
185     private static String sequence(char start, int count) {
186         StringBuilder sb = new StringBuilder();
187         for (int i = 0; i < count; i++) {
188             sb.append((char) (start + i));
189         }
190         return sb.toString();
191     }
192 
193     private static String randomString(String alphabet, int length) {
194         StringBuilder sb = new StringBuilder();
195         for (int i = 0; i < length; i++) {
196             int random = ThreadLocalRandom.current().nextInt(alphabet.length());
197             sb.append(alphabet.charAt(random));
198         }
199         return sb.toString();
200     }
201 
202     private static String getSystemProperty(String propertyName) {
203         try {
204             return Strings.nullToEmpty(System.getProperty(propertyName, ""));
205         } catch (SecurityException e) {
206             return "<unknown>";
207         }
208     }
209 
210     private static boolean getOsMatchesName(final String osNamePrefix) {
211         return OS_NAME.toLowerCase(Locale.ROOT).startsWith(osNamePrefix.toLowerCase(Locale.ROOT));
212     }
213 }