1
1
package net .playeranalytics .plugin .dependencies ;
2
2
3
- import me .lucko .jarrelocator .JarRelocator ;
4
3
import me .lucko .jarrelocator .Relocation ;
5
4
import net .playeranalytics .plugin .PluginInformation ;
6
- import net .playeranalytics .plugin .server .PluginLogger ;
7
- import ninja .egg82 .maven .Artifact ;
8
- import ninja .egg82 .maven .Repository ;
9
- import ninja .egg82 .maven .Scope ;
10
- import ninja .egg82 .utils .InjectUtil ;
11
- import org .xml .sax .SAXException ;
5
+ import ninja .egg82 .mvn .JarBuilder ;
6
+ import ninja .egg82 .mvn .JarInjector ;
7
+ import ninja .egg82 .mvn .classloaders .TransparentInjectableClassLoader ;
8
+ import org .apache .maven .model .building .ModelBuildingException ;
12
9
13
- import javax .xml .xpath .XPathExpressionException ;
14
10
import java .io .File ;
15
11
import java .io .IOException ;
16
- import java .io .UncheckedIOException ;
17
- import java .lang .reflect .InvocationTargetException ;
18
- import java .net .URISyntaxException ;
19
12
import java .net .URLClassLoader ;
20
- import java .nio .file .Files ;
21
- import java .util .*;
22
- import java .util .concurrent .*;
13
+ import java .util .List ;
23
14
24
15
public class DependencyLoader {
25
16
26
17
private final URLClassLoader classLoader ;
27
- private final PluginLogger pluginLogger ;
28
18
29
- private final ExecutorService downloadPool = Executors .newWorkStealingPool (Math .max (4 , Runtime .getRuntime ().availableProcessors () / 2 ));
30
- private final Set <DependencyAndRelocations > dependencies = new HashSet <>();
31
- private final File dependencyCache ;
32
- private final File libraryFolder ;
19
+ private final JarInjector jarInjector ;
33
20
34
- public DependencyLoader (URLClassLoader classLoader , PluginLogger pluginLogger , PluginInformation pluginInformation ) {
21
+ public DependencyLoader (URLClassLoader classLoader , PluginInformation pluginInformation ) {
35
22
this .classLoader = classLoader ;
36
- this .pluginLogger = pluginLogger ;
37
- dependencyCache = pluginInformation .getDataDirectory ().resolve ("dependency_cache" ).toFile ();
38
- libraryFolder = pluginInformation .getDataDirectory ().resolve ("libraries" ).toFile ();
23
+
24
+ File dependencyCache = pluginInformation .getDataDirectory ().resolve ("dep_cache" ).toFile ();
25
+
26
+ jarInjector = new JarInjector (dependencyCache );
39
27
}
40
28
41
29
public DependencyLoader addDependency (
42
30
String repositoryAddress , String group , String artifact , String version ,
43
31
List <Relocation > relocations
44
- ) throws IOException {
32
+ ) {
45
33
try {
46
- Artifact dependency = Artifact .builder (group , artifact , version , dependencyCache , Scope .COMPILE )
47
- .addRepository (Repository .builder (repositoryAddress ).build ())
48
- .build ();
49
- Stack <DependencyAndRelocations > dependencyLookup = new Stack <>();
50
- dependencyLookup .add (new DependencyAndRelocations (dependency , relocations ));
51
- while (!dependencyLookup .isEmpty () && dependencyLookup .peek () != null ) {
52
- DependencyAndRelocations current = dependencyLookup .pop ();
53
- Artifact currentArtifact = current .getArtifact ();
54
- if (currentArtifact .getScope () == Scope .COMPILE ) {
55
- currentArtifact .getDependencies ().stream ()
56
- .map (dependencyArtifact ->
57
- new DependencyAndRelocations (dependencyArtifact , relocations ))
58
- .forEach (dependencyLookup ::add );
59
- dependencies .add (current );
60
- }
34
+ jarInjector .addBuilder (new JarBuilder (group , artifact , version , repositoryAddress ));
35
+ for (Relocation relocation : relocations ) {
36
+ jarInjector .addRelocation (relocation );
61
37
}
62
- } catch (URISyntaxException | XPathExpressionException | SAXException e ) {
38
+ } catch (ClassCastException e ) {
63
39
throw new IllegalArgumentException ("Incorrect dependency definition" , e );
64
40
}
65
41
return this ;
66
42
}
67
43
68
- public void load () throws IOException {
44
+ public void load () throws IOException , ModelBuildingException {
69
45
ClassLoader origClassLoader = Thread .currentThread ().getContextClassLoader ();
70
46
try {
71
47
Thread .currentThread ().setContextClassLoader (classLoader );
72
- loadDependencies ( );
48
+ jarInjector . inject ( new TransparentInjectableClassLoader ( classLoader ) );
73
49
} finally {
74
50
Thread .currentThread ().setContextClassLoader (origClassLoader );
75
51
}
@@ -85,99 +61,4 @@ public <T extends Runnable> void executeWithDependencyClassloaderContext(T runna
85
61
Thread .currentThread ().setContextClassLoader (origClassLoader );
86
62
}
87
63
}
88
-
89
- private void loadDependencies () throws IOException {
90
- List <CompletableFuture <?>> loading = new ArrayList <>();
91
- List <Throwable > downloadErrors = new CopyOnWriteArrayList <>();
92
- for (DependencyAndRelocations dependency : dependencies ) {
93
- loading .add (scheduleLoading (downloadErrors , dependency ));
94
- }
95
- CompletableFuture .allOf (loading .toArray (new CompletableFuture [0 ])).join ();
96
- shutdownPool (downloadErrors );
97
-
98
- if (!downloadErrors .isEmpty ()) {
99
- throwError (downloadErrors );
100
- }
101
- }
102
-
103
- private CompletableFuture <Void > scheduleLoading (List <Throwable > downloadErrors , DependencyAndRelocations dependency ) {
104
- return CompletableFuture .runAsync (() -> {
105
- try {
106
- loadDependency (dependency );
107
- } catch (IOException e ) {
108
- throw new UncheckedIOException (e );
109
- }
110
- }, downloadPool ).exceptionally (throwable -> {
111
- downloadErrors .add (throwable );
112
- return null ;
113
- });
114
- }
115
-
116
- private void shutdownPool (List <Throwable > downloadErrors ) {
117
- downloadPool .shutdown ();
118
- try {
119
- if (!downloadPool .awaitTermination (1 , TimeUnit .HOURS )) {
120
- downloadErrors .add (0 , new IOException ("Download timeout exceeded" ));
121
- }
122
- } catch (InterruptedException e ) {
123
- Thread .currentThread ().interrupt ();
124
- }
125
- }
126
-
127
- private void throwError (List <Throwable > downloadErrors ) throws IOException {
128
- IOException firstError = new IOException ("Failed to download all dependencies (see suppressed exceptions for why it failed)" );
129
- for (Throwable downloadError : downloadErrors ) {
130
- firstError .addSuppressed (downloadError .getCause ());
131
- }
132
- throw firstError ;
133
- }
134
-
135
- private void loadDependency (DependencyAndRelocations toLoad ) throws IOException {
136
- Artifact dependency = toLoad .getArtifact ();
137
- String artifactCoordinates = dependency .getGroupId () + "-" +
138
- dependency .getArtifactId () + "-" + dependency .getVersion ();
139
- Files .createDirectories (libraryFolder .toPath ());
140
- File artifactFile = libraryFolder .toPath ().resolve (artifactCoordinates + ".jar" ).toFile ();
141
- File relocatedArtifactFile = libraryFolder .toPath ().resolve (artifactCoordinates + "-relocated.jar" ).toFile ();
142
-
143
- if (!relocatedArtifactFile .exists () && !toLoad .getRelocations ().isEmpty ()) {
144
- if (!dependency .fileExists (artifactFile )) {
145
- pluginLogger .info ("Downloading library: " + dependency .getArtifactId () + ".." );
146
- download (dependency , artifactCoordinates , artifactFile );
147
- }
148
- new JarRelocator (artifactFile , relocatedArtifactFile , toLoad .getRelocations ()).run ();
149
-
150
- inject (relocatedArtifactFile );
151
- } else if (relocatedArtifactFile .exists ()) {
152
- inject (relocatedArtifactFile );
153
- } else {
154
- if (!dependency .fileExists (artifactFile )) {
155
- pluginLogger .info ("Downloading library: " + dependency .getArtifactId () + ".." );
156
- download (dependency , artifactCoordinates , artifactFile );
157
- }
158
-
159
- inject (artifactFile );
160
- }
161
- }
162
-
163
- private void inject (File artifactFile ) throws IOException {
164
- try {
165
- InjectUtil .injectFile (artifactFile , classLoader );
166
- } catch (IllegalAccessException | InvocationTargetException e ) {
167
- throw new IOException ("Failed to download " + artifactFile + ", " + e .getMessage (), e );
168
- }
169
- }
170
-
171
- private void download (Artifact dependency , String artifactCoordinates , File artifactFile ) throws IOException {
172
- try {
173
- dependency .downloadJar (artifactFile );
174
- } catch (IOException e ) {
175
- StringBuilder repositories = new StringBuilder ();
176
- for (Repository repository : dependency .getRepositories ()) {
177
- repositories .append (" " ).append (repository .getURL ());
178
- }
179
- pluginLogger .warn ("Failed to download " + artifactCoordinates + " from repositories (" + repositories + "), " + e .getMessage ());
180
- throw e ;
181
- }
182
- }
183
64
}
0 commit comments