1
1
/**
2
2
* MIT License
3
3
*
4
- * Copyright (c) 2021 Brandon Li
4
+ * <p> Copyright (c) 2021 Brandon Li
5
5
*
6
- * Permission is hereby granted, free of charge, to any person obtaining a copy
7
- * of this software and associated documentation files (the "Software"), to deal
8
- * in the Software without restriction, including without limitation the rights
9
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- * copies of the Software, and to permit persons to whom the Software is
6
+ * <p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software
7
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
8
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
9
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
11
10
* furnished to do so, subject to the following conditions:
12
11
*
13
- * The above copyright notice and this permission notice shall be included in all
14
- * copies or substantial portions of the Software.
12
+ * <p> The above copyright notice and this permission notice shall be included in all copies or
13
+ * substantial portions of the Software.
15
14
*
16
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- * SOFTWARE.
15
+ * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
16
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
20
*/
24
21
package io .github .pulsebeat02 .emcdependencymanagement .component .downloader ;
25
22
23
+ import io .github .pulsebeat02 .emcdependencymanagement .SimpleLogger ;
26
24
import io .github .pulsebeat02 .emcdependencymanagement .component .Artifact ;
27
25
import io .github .pulsebeat02 .emcdependencymanagement .component .Repository ;
26
+ import io .github .pulsebeat02 .emcdependencymanagement .util .FileUtils ;
28
27
import java .io .IOException ;
29
28
import java .io .InputStream ;
30
29
import java .net .HttpURLConnection ;
35
34
import java .util .Arrays ;
36
35
import java .util .Collection ;
37
36
import java .util .HashSet ;
37
+ import java .util .Locale ;
38
38
import java .util .Optional ;
39
+ import java .util .Scanner ;
39
40
import java .util .Set ;
40
41
41
42
public final class JarInstaller {
42
43
44
+ private final SimpleLogger logger ;
43
45
private final Collection <Artifact > artifacts ;
44
46
private final Collection <Repository > repositories ;
45
47
private final Set <Path > paths ;
46
48
private final Path target ;
47
49
48
50
JarInstaller (
51
+ final SimpleLogger logger ,
49
52
final Collection <Artifact > artifacts ,
50
53
final Collection <Repository > repositories ,
51
54
final Path target ) {
55
+ this .logger = logger ;
52
56
this .artifacts = artifacts ;
53
57
this .repositories = repositories ;
54
58
this .target = target ;
@@ -58,10 +62,11 @@ public final class JarInstaller {
58
62
}
59
63
60
64
public static JarInstaller ofInstaller (
65
+ final SimpleLogger logger ,
61
66
final Collection <Artifact > artifacts ,
62
67
final Collection <Repository > repositories ,
63
68
final Path target ) {
64
- return new JarInstaller (artifacts , repositories , target );
69
+ return new JarInstaller (logger , artifacts , repositories , target );
65
70
}
66
71
67
72
public Collection <Path > install () throws IOException {
@@ -87,18 +92,46 @@ private void downloadJarExceptionally(final String url) {
87
92
try {
88
93
this .downloadJar (url );
89
94
} catch (final IOException e ) {
90
- e . printStackTrace ( );
95
+ this . logger . error ( String . format ( "Failed to download JAR located at url %s!" , url ) );
91
96
}
92
97
}
93
98
94
99
private void downloadJar (final String url ) throws IOException {
100
+
101
+ final Path jarPath = this .downloadFile (url );
102
+ if (this .checkHash (jarPath , url )) {
103
+ this .downloadJar (url );
104
+ }
105
+
106
+ this .paths .add (jarPath );
107
+ }
108
+
109
+ private boolean checkHash (final Path jarPath , final String url ) throws IOException {
110
+
111
+ final String originalHash = this .getCheckSumArtifact (url );
112
+ final String newHash = FileUtils .getUppercaseHash (jarPath );
113
+ if (originalHash .isEmpty ()) {
114
+ this .logger .warning (
115
+ String .format ("Could not retrieve SHA1 hash for artifact %s! Skipping hash check!" , url ));
116
+ return false ;
117
+ }
118
+
119
+ if (!originalHash .equals (newHash )) {
120
+ Files .deleteIfExists (jarPath );
121
+ return true ;
122
+ }
123
+
124
+ return false ;
125
+ }
126
+
127
+ private Path downloadFile (final String url ) throws IOException {
95
128
final URL website = new URL (url );
96
129
final String jar = this .getFilename (url );
97
130
final Path jarPath = this .target .resolve (jar );
98
131
try (final InputStream in = website .openStream ()) {
99
132
Files .copy (in , jarPath , StandardCopyOption .REPLACE_EXISTING );
100
133
}
101
- this . paths . add ( jarPath ) ;
134
+ return jarPath ;
102
135
}
103
136
104
137
private String getFilename (final String url ) {
@@ -117,9 +150,7 @@ private Optional<String> tryRepository(final Repository repository, final String
117
150
}
118
151
119
152
private boolean isValidUrl (final String url ) throws IOException {
120
- final HttpURLConnection con = (HttpURLConnection ) new URL (url ).openConnection ();
121
- con .setRequestMethod ("HEAD" );
122
- return con .getResponseCode () == HttpURLConnection .HTTP_OK ;
153
+ return this .createConnection (url ).getResponseCode () == HttpURLConnection .HTTP_OK ;
123
154
}
124
155
125
156
private String getAppendedUrl (final Artifact artifact ) {
@@ -130,6 +161,20 @@ private String getAppendedUrl(final Artifact artifact) {
130
161
return String .format ("%s/%s/%s/%s" , groupId , artifactId , version , jar );
131
162
}
132
163
164
+ private String getCheckSumArtifact (final String url ) throws IOException {
165
+ final String hashUrl = String .format ("%s.sha1" , url );
166
+ try (final Scanner scanner =
167
+ new Scanner (new URL (hashUrl ).openStream (), "UTF-8" ).useDelimiter ("\\ A" )) {
168
+ return scanner .next ().toUpperCase (Locale .ROOT );
169
+ }
170
+ }
171
+
172
+ private HttpURLConnection createConnection (final String url ) throws IOException {
173
+ final HttpURLConnection con = (HttpURLConnection ) new URL (url ).openConnection ();
174
+ con .setRequestMethod ("HEAD" );
175
+ return con ;
176
+ }
177
+
133
178
public Collection <Artifact > getArtifacts () {
134
179
return this .artifacts ;
135
180
}
0 commit comments