1 package com.github.sbugat.rundeckmonitor;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.net.URL;
6 import java.nio.file.DirectoryStream;
7 import java.nio.file.FileSystems;
8 import java.nio.file.Files;
9 import java.nio.file.NoSuchFileException;
10 import java.nio.file.Path;
11 import java.nio.file.Paths;
12 import java.util.zip.ZipEntry;
13 import java.util.zip.ZipInputStream;
14
15 import javax.swing.JOptionPane;
16
17 import org.eclipse.egit.github.core.Repository;
18 import org.eclipse.egit.github.core.RepositoryTag;
19 import org.eclipse.egit.github.core.client.GitHubClient;
20 import org.eclipse.egit.github.core.service.RepositoryService;
21 import org.slf4j.ext.XLogger;
22 import org.slf4j.ext.XLoggerFactory;
23
24 import com.github.sbugat.rundeckmonitor.tools.EnvironmentTools;
25
26
27
28
29
30
31
32
33
34 public final class VersionChecker implements Runnable {
35
36
37 private static final XLogger LOG = XLoggerFactory.getXLogger(VersionChecker.class);
38
39
40 private static final int ONE_MEGABYTE = 1_024 * 1_024;
41
42
43 private static final String JAR_EXTENSION = ".jar";
44
45 private static final String TMP_EXTENSION = ".tmp";
46
47 private static final String WINDOWS_EXE_EXTENSION = ".exe";
48
49 private static final String JAVA_HOME_PROPERTY = "java.home";
50
51 private static final String TARGET_DIRECTORY = "target";
52
53
54 private static final String BIN_DIRECTORY_AND_JAVA = "bin" + FileSystems.getDefault().getSeparator() + "java";
55
56
57 private static final String JAR_ARGUMENT = "-jar";
58
59
60 private final String gitHubUser;
61
62 private final String gitHubRepository;
63
64
65 private final String mavenArtifactId;
66
67
68 private final String jarWithDependenciesSuffix;
69
70
71 private boolean downloadDone;
72
73
74 private boolean versionCheckerDisabled;
75
76
77 private String downloadedJar;
78
79
80
81
82
83
84
85
86
87 public VersionChecker(final String gitHubUserArg, final String gitHubRepositoryArg, final String mavenArtifactIdArg, final String jarWithDependenciesSuffixArg) {
88
89 gitHubUser = gitHubUserArg;
90 gitHubRepository = gitHubRepositoryArg;
91
92 mavenArtifactId = mavenArtifactIdArg;
93 jarWithDependenciesSuffix = jarWithDependenciesSuffixArg;
94 }
95
96
97
98
99 @Override
100 public void run() {
101
102 LOG.entry();
103
104 final String currentJar = currentJar();
105
106 if (null == currentJar) {
107 LOG.exit();
108 return;
109 }
110
111 try {
112
113 final GitHubClient gitHubClient = new GitHubClient();
114
115 final RepositoryService rs = new RepositoryService(gitHubClient);
116 final Repository repository = rs.getRepository(gitHubUser, gitHubRepository);
117
118 final String currentVersion = 'v' + currentJar.replaceFirst("^" + mavenArtifactId + '-', "").replaceFirst(jarWithDependenciesSuffix + ".*$", "");
119 RepositoryTag recentRelease = null;
120 for (final RepositoryTag tag : rs.getTags(repository)) {
121
122 if (null != recentRelease && tag.getName().compareTo(recentRelease.getName()) > 0) {
123 recentRelease = tag;
124 }
125 else if (tag.getName().compareTo(currentVersion) > 0) {
126 recentRelease = tag;
127 }
128 }
129
130 if (null == recentRelease) {
131 LOG.exit();
132 return;
133 }
134
135 if (!findAndDownloadReleaseJar(recentRelease, true)) {
136 findAndDownloadReleaseJar(recentRelease, false);
137 }
138
139 LOG.exit();
140 }
141 catch (final Exception e) {
142
143
144
145 cleanOldAndTemporaryJar();
146 LOG.exit(e);
147 }
148 }
149
150
151
152
153
154
155
156
157
158 private boolean findAndDownloadReleaseJar(final RepositoryTag release, final boolean withDependenciesSuffix) throws IOException {
159
160 LOG.entry(release, withDependenciesSuffix);
161
162 final String jarSuffix;
163 if (withDependenciesSuffix) {
164 jarSuffix = jarWithDependenciesSuffix;
165 }
166 else {
167 jarSuffix = "";
168 }
169 try (final InputStream remoteJarInputStream = new URL(release.getZipballUrl()).openStream()) {
170
171 final ZipInputStream zis = new ZipInputStream(remoteJarInputStream);
172
173 ZipEntry entry = zis.getNextEntry();
174
175 while (null != entry) {
176
177 if (entry.getName().matches(".*/" + TARGET_DIRECTORY + '/' + mavenArtifactId + "-[0-9\\.]*" + jarSuffix + JAR_EXTENSION)) {
178
179 final Object[] options = { "Yes", "No", "Never ask me again" };
180 final int confirmDialogChoice = JOptionPane.showOptionDialog(null, "An update is available, download it? (" + entry.getCompressedSize() / ONE_MEGABYTE + "MB)", "Rundeck Monitor update found!", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
181 if (JOptionPane.YES_OPTION == confirmDialogChoice) {
182
183 final String jarFileBaseName = entry.getName().replaceFirst("^.*/", "");
184
185 downloadFile(zis, jarFileBaseName + TMP_EXTENSION);
186 Files.move(Paths.get(jarFileBaseName + TMP_EXTENSION), Paths.get(jarFileBaseName));
187
188 downloadedJar = jarFileBaseName;
189 downloadDone = true;
190 }
191 else if (JOptionPane.CANCEL_OPTION == confirmDialogChoice) {
192
193 versionCheckerDisabled = true;
194 }
195
196 LOG.exit(true);
197 return true;
198 }
199
200 entry = zis.getNextEntry();
201 }
202 }
203
204 LOG.exit(false);
205 return false;
206 }
207
208
209
210
211
212
213 public boolean restart() {
214
215 LOG.entry();
216
217 if (Files.exists(Paths.get(downloadedJar))) {
218
219 String javaExecutable = null;
220 try {
221
222 javaExecutable = getJavaExecutable();
223 final ProcessBuilder processBuilder = new ProcessBuilder(javaExecutable, JAR_ARGUMENT, downloadedJar);
224 processBuilder.start();
225
226 LOG.exit(true);
227 return true;
228 }
229 catch (final IOException e) {
230
231
232 LOG.error("Error during restarting process {} with arguments: {} {}", javaExecutable, JAR_ARGUMENT, downloadedJar, e);
233 }
234 }
235
236 LOG.exit(false);
237 return false;
238 }
239
240
241
242
243 public void cleanOldAndTemporaryJar() {
244
245 LOG.entry();
246
247 final String currentJar = currentJar();
248
249 try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get("."))) {
250
251 for (final Path path : directoryStream) {
252
253 final String fileName = path.getFileName().toString();
254 if (fileName.startsWith(mavenArtifactId)) {
255
256 if (fileName.endsWith(JAR_EXTENSION) && null != currentJar && currentJar.compareTo(fileName) > 0) {
257
258 deleteJar(path);
259 }
260 else if (fileName.endsWith(JAR_EXTENSION + TMP_EXTENSION)) {
261
262 deleteJar(path);
263 }
264 }
265 }
266
267 LOG.exit();
268 }
269 catch (final IOException e) {
270
271 LOG.exit(e);
272 }
273 }
274
275
276
277
278
279
280 private static void deleteJar(final Path jarFileToDelete) {
281
282 LOG.entry();
283
284 if (Files.exists(jarFileToDelete)) {
285
286 try {
287 Files.delete(jarFileToDelete);
288 LOG.exit();
289 }
290 catch (final IOException e) {
291
292
293 LOG.exit(e);
294 }
295 }
296 }
297
298
299
300
301
302
303 private String currentJar() {
304
305 LOG.entry();
306
307 String currentJar = null;
308 try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get("."))) {
309
310 for (final Path path : directoryStream) {
311
312 final String fileName = path.getFileName().toString();
313 if (fileName.startsWith(mavenArtifactId) && fileName.endsWith(JAR_EXTENSION) && (null == currentJar || currentJar.compareTo(fileName) < 0)) {
314
315 currentJar = fileName;
316 }
317 }
318 }
319 catch (final IOException e) {
320
321 currentJar = null;
322 }
323
324 LOG.exit(currentJar);
325 return currentJar;
326 }
327
328
329
330
331
332
333 public boolean isDownloadDone() {
334
335 return downloadDone;
336 }
337
338
339
340
341 public void resetVersionCheckerDisabled() {
342
343 versionCheckerDisabled = false;
344 }
345
346
347
348
349
350
351 public boolean isversionCheckerDisabled() {
352
353 return versionCheckerDisabled;
354 }
355
356
357
358
359
360
361
362
363 private static void downloadFile(final InputStream inputStream, final String destinationFile) throws IOException {
364
365 Files.copy(inputStream, Paths.get(destinationFile));
366 }
367
368
369
370
371
372
373
374 private static String getJavaExecutable() throws NoSuchFileException {
375
376 LOG.entry();
377
378 final String javaDirectory = System.getProperty(JAVA_HOME_PROPERTY);
379
380 if (javaDirectory == null) {
381 throw new IllegalStateException(JAVA_HOME_PROPERTY);
382 }
383
384 final String javaExecutableFilePath;
385
386 if (EnvironmentTools.isWindows()) {
387 javaExecutableFilePath = javaDirectory + FileSystems.getDefault().getSeparator() + BIN_DIRECTORY_AND_JAVA + WINDOWS_EXE_EXTENSION;
388 }
389 else {
390 javaExecutableFilePath = javaDirectory + FileSystems.getDefault().getSeparator() + BIN_DIRECTORY_AND_JAVA;
391 }
392
393
394 final Path javaExecutablePath = Paths.get(javaExecutableFilePath);
395 if (!Files.exists(javaExecutablePath) || !Files.isExecutable(javaExecutablePath)) {
396
397 final NoSuchFileException exception = new NoSuchFileException(javaExecutableFilePath);
398 LOG.exit(exception);
399 throw exception;
400 }
401
402 LOG.exit(javaExecutableFilePath);
403 return javaExecutableFilePath;
404 }
405 }