Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/misc/ExtensionDependency.java
38829 views
1
/*
2
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.misc;
27
28
import java.io.File;
29
import java.io.FilenameFilter;
30
import java.io.IOException;
31
import java.io.FileNotFoundException;
32
import java.util.StringTokenizer;
33
import java.util.Vector;
34
import java.util.Enumeration;
35
import java.util.jar.JarFile;
36
import java.util.jar.Manifest;
37
import java.util.jar.Attributes;
38
import java.util.jar.Attributes.Name;
39
import java.security.AccessController;
40
import java.security.PrivilegedAction;
41
import java.security.PrivilegedExceptionAction;
42
import java.security.PrivilegedActionException;
43
import java.net.URL;
44
import java.net.MalformedURLException;
45
import sun.net.www.ParseUtil;
46
47
/**
48
* <p>
49
* This class checks dependent extensions a particular jar file may have
50
* declared through its manifest attributes.
51
* </p>
52
* Jar file declared dependent extensions through the extension-list
53
* attribute. The extension-list contains a list of keys used to
54
* fetch the other attributes describing the required extension.
55
* If key is the extension key declared in the extension-list
56
* attribute, the following describing attribute can be found in
57
* the manifest :
58
* key-Extension-Name: (Specification package name)
59
* key-Specification-Version: (Specification-Version)
60
* key-Implementation-Version: (Implementation-Version)
61
* key-Implementation-Vendor-Id: (Imlementation-Vendor-Id)
62
* key-Implementation-Version: (Implementation version)
63
* key-Implementation-URL: (URL to download the requested extension)
64
* <p>
65
* This class also maintain versioning consistency of installed
66
* extensions dependencies declared in jar file manifest.
67
* </p>
68
* @author Jerome Dochez
69
*/
70
public class ExtensionDependency {
71
72
/* Callbak interfaces to delegate installation of missing extensions */
73
private static Vector<ExtensionInstallationProvider> providers;
74
75
/**
76
* <p>
77
* Register an ExtensionInstallationProvider. The provider is responsible
78
* for handling the installation (upgrade) of any missing extensions.
79
* </p>
80
* @param eip ExtensionInstallationProvider implementation
81
*/
82
public synchronized static void addExtensionInstallationProvider
83
(ExtensionInstallationProvider eip)
84
{
85
if (providers == null) {
86
providers = new Vector<>();
87
}
88
providers.add(eip);
89
}
90
91
/**
92
* <p>
93
* Unregister a previously installed installation provider
94
* </p>
95
*/
96
public synchronized static void removeExtensionInstallationProvider
97
(ExtensionInstallationProvider eip)
98
{
99
providers.remove(eip);
100
}
101
102
/**
103
* <p>
104
* Checks the dependencies of the jar file on installed extension.
105
* </p>
106
* @param jarFile containing the attriutes declaring the dependencies
107
*/
108
public static boolean checkExtensionsDependencies(JarFile jar)
109
{
110
if (providers == null) {
111
// no need to bother, nobody is registered to install missing
112
// extensions
113
return true;
114
}
115
116
try {
117
ExtensionDependency extDep = new ExtensionDependency();
118
return extDep.checkExtensions(jar);
119
} catch (ExtensionInstallationException e) {
120
debug(e.getMessage());
121
}
122
return false;
123
}
124
125
/*
126
* Check for all declared required extensions in the jar file
127
* manifest.
128
*/
129
protected boolean checkExtensions(JarFile jar)
130
throws ExtensionInstallationException
131
{
132
Manifest man;
133
try {
134
man = jar.getManifest();
135
} catch (IOException e) {
136
return false;
137
}
138
139
if (man == null) {
140
// The applet does not define a manifest file, so
141
// we just assume all dependencies are satisfied.
142
return true;
143
}
144
145
boolean result = true;
146
Attributes attr = man.getMainAttributes();
147
if (attr != null) {
148
// Let's get the list of declared dependencies
149
String value = attr.getValue(Name.EXTENSION_LIST);
150
if (value != null) {
151
StringTokenizer st = new StringTokenizer(value);
152
// Iterate over all declared dependencies
153
while (st.hasMoreTokens()) {
154
String extensionName = st.nextToken();
155
debug("The file " + jar.getName() +
156
" appears to depend on " + extensionName);
157
// Sanity Check
158
String extName = extensionName + "-" +
159
Name.EXTENSION_NAME.toString();
160
if (attr.getValue(extName) == null) {
161
debug("The jar file " + jar.getName() +
162
" appers to depend on "
163
+ extensionName + " but does not define the " +
164
extName + " attribute in its manifest ");
165
166
} else {
167
if (!checkExtension(extensionName, attr)) {
168
debug("Failed installing " + extensionName);
169
result = false;
170
}
171
}
172
}
173
} else {
174
debug("No dependencies for " + jar.getName());
175
}
176
}
177
return result;
178
}
179
180
181
/*
182
* <p>
183
* Check that a particular dependency on an extension is satisfied.
184
* </p>
185
* @param extensionName is the key used for the attributes in the manifest
186
* @param attr is the attributes of the manifest file
187
*
188
* @return true if the dependency is satisfied by the installed extensions
189
*/
190
protected synchronized boolean checkExtension(final String extensionName,
191
final Attributes attr)
192
throws ExtensionInstallationException
193
{
194
debug("Checking extension " + extensionName);
195
if (checkExtensionAgainstInstalled(extensionName, attr))
196
return true;
197
198
debug("Extension not currently installed ");
199
ExtensionInfo reqInfo = new ExtensionInfo(extensionName, attr);
200
return installExtension(reqInfo, null);
201
}
202
203
/*
204
* <p>
205
* Check if a particular extension is part of the currently installed
206
* extensions.
207
* </p>
208
* @param extensionName is the key for the attributes in the manifest
209
* @param attr is the attributes of the manifest
210
*
211
* @return true if the requested extension is already installed
212
*/
213
boolean checkExtensionAgainstInstalled(String extensionName,
214
Attributes attr)
215
throws ExtensionInstallationException
216
{
217
File fExtension = checkExtensionExists(extensionName);
218
219
if (fExtension != null) {
220
// Extension already installed, just check against this one
221
try {
222
if (checkExtensionAgainst(extensionName, attr, fExtension))
223
return true;
224
} catch (FileNotFoundException e) {
225
debugException(e);
226
} catch (IOException e) {
227
debugException(e);
228
}
229
return false;
230
231
} else {
232
// Not sure if extension is already installed, so check all the
233
// installed extension jar files to see if we get a match
234
235
File[] installedExts;
236
237
try {
238
// Get the list of installed extension jar files so we can
239
// compare the installed versus the requested extension
240
installedExts = getInstalledExtensions();
241
} catch(IOException e) {
242
debugException(e);
243
return false;
244
}
245
246
for (int i=0;i<installedExts.length;i++) {
247
try {
248
if (checkExtensionAgainst(extensionName, attr, installedExts[i]))
249
return true;
250
} catch (FileNotFoundException e) {
251
debugException(e);
252
} catch (IOException e) {
253
debugException(e);
254
// let's continue with the next installed extension
255
}
256
}
257
}
258
return false;
259
}
260
261
/*
262
* <p>
263
* Check if the requested extension described by the attributes
264
* in the manifest under the key extensionName is compatible with
265
* the jar file.
266
* </p>
267
*
268
* @param extensionName key in the attribute list
269
* @param attr manifest file attributes
270
* @param file installed extension jar file to compare the requested
271
* extension against.
272
*/
273
protected boolean checkExtensionAgainst(String extensionName,
274
Attributes attr,
275
final File file)
276
throws IOException,
277
FileNotFoundException,
278
ExtensionInstallationException
279
{
280
281
debug("Checking extension " + extensionName +
282
" against " + file.getName());
283
284
// Load the jar file ...
285
Manifest man;
286
try {
287
man = AccessController.doPrivileged(
288
new PrivilegedExceptionAction<Manifest>() {
289
public Manifest run()
290
throws IOException, FileNotFoundException {
291
if (!file.exists())
292
throw new FileNotFoundException(file.getName());
293
JarFile jarFile = new JarFile(file);
294
return jarFile.getManifest();
295
}
296
});
297
} catch(PrivilegedActionException e) {
298
if (e.getException() instanceof FileNotFoundException)
299
throw (FileNotFoundException) e.getException();
300
throw (IOException) e.getException();
301
}
302
303
// Construct the extension information object
304
ExtensionInfo reqInfo = new ExtensionInfo(extensionName, attr);
305
debug("Requested Extension : " + reqInfo);
306
307
int isCompatible = ExtensionInfo.INCOMPATIBLE;
308
ExtensionInfo instInfo = null;
309
310
if (man != null) {
311
Attributes instAttr = man.getMainAttributes();
312
if (instAttr != null) {
313
instInfo = new ExtensionInfo(null, instAttr);
314
debug("Extension Installed " + instInfo);
315
isCompatible = instInfo.isCompatibleWith(reqInfo);
316
switch(isCompatible) {
317
case ExtensionInfo.COMPATIBLE:
318
debug("Extensions are compatible");
319
return true;
320
321
case ExtensionInfo.INCOMPATIBLE:
322
debug("Extensions are incompatible");
323
return false;
324
325
default:
326
// everything else
327
debug("Extensions require an upgrade or vendor switch");
328
return installExtension(reqInfo, instInfo);
329
330
}
331
}
332
}
333
return false;
334
}
335
336
/*
337
* <p>
338
* An required extension is missing, if an ExtensionInstallationProvider is
339
* registered, delegate the installation of that particular extension to it.
340
* </p>
341
*
342
* @param reqInfo Missing extension information
343
* @param instInfo Older installed version information
344
*
345
* @return true if the installation is successful
346
*/
347
protected boolean installExtension(ExtensionInfo reqInfo,
348
ExtensionInfo instInfo)
349
throws ExtensionInstallationException
350
{
351
Vector<ExtensionInstallationProvider> currentProviders;
352
synchronized(providers) {
353
@SuppressWarnings("unchecked")
354
Vector<ExtensionInstallationProvider> tmp =
355
(Vector<ExtensionInstallationProvider>) providers.clone();
356
currentProviders = tmp;
357
}
358
for (Enumeration<ExtensionInstallationProvider> e = currentProviders.elements();
359
e.hasMoreElements();) {
360
ExtensionInstallationProvider eip = e.nextElement();
361
362
if (eip!=null) {
363
// delegate the installation to the provider
364
if (eip.installExtension(reqInfo, instInfo)) {
365
debug(reqInfo.name + " installation successful");
366
Launcher.ExtClassLoader cl = (Launcher.ExtClassLoader)
367
Launcher.getLauncher().getClassLoader().getParent();
368
addNewExtensionsToClassLoader(cl);
369
return true;
370
}
371
}
372
}
373
// We have tried all of our providers, noone could install this
374
// extension, we just return failure at this point
375
debug(reqInfo.name + " installation failed");
376
return false;
377
}
378
379
/**
380
* <p>
381
* Checks if the extension, that is specified in the extension-list in
382
* the applet jar manifest, is already installed (i.e. exists in the
383
* extension directory).
384
* </p>
385
*
386
* @param extensionName extension name in the extension-list
387
*
388
* @return the extension if it exists in the extension directory
389
*/
390
private File checkExtensionExists(String extensionName) {
391
// Function added to fix bug 4504166
392
final String extName = extensionName;
393
final String[] fileExt = {".jar", ".zip"};
394
395
return AccessController.doPrivileged(
396
new PrivilegedAction<File>() {
397
public File run() {
398
try {
399
File fExtension;
400
File[] dirs = getExtDirs();
401
402
// Search the extension directories for the extension that is specified
403
// in the attribute extension-list in the applet jar manifest
404
for (int i=0;i<dirs.length;i++) {
405
for (int j=0;j<fileExt.length;j++) {
406
if (extName.toLowerCase().endsWith(fileExt[j])) {
407
fExtension = new File(dirs[i], extName);
408
} else {
409
fExtension = new File(dirs[i], extName+fileExt[j]);
410
}
411
debug("checkExtensionExists:fileName " + fExtension.getName());
412
if (fExtension.exists()) {
413
return fExtension;
414
}
415
}
416
}
417
return null;
418
419
} catch(Exception e) {
420
debugException(e);
421
return null;
422
}
423
}
424
});
425
}
426
427
/**
428
* <p>
429
* @return the java.ext.dirs property as a list of directory
430
* </p>
431
*/
432
private static File[] getExtDirs() {
433
String s = java.security.AccessController.doPrivileged(
434
new sun.security.action.GetPropertyAction("java.ext.dirs"));
435
436
File[] dirs;
437
if (s != null) {
438
StringTokenizer st =
439
new StringTokenizer(s, File.pathSeparator);
440
int count = st.countTokens();
441
debug("getExtDirs count " + count);
442
dirs = new File[count];
443
for (int i = 0; i < count; i++) {
444
dirs[i] = new File(st.nextToken());
445
debug("getExtDirs dirs["+i+"] "+ dirs[i]);
446
}
447
} else {
448
dirs = new File[0];
449
debug("getExtDirs dirs " + dirs);
450
}
451
debug("getExtDirs dirs.length " + dirs.length);
452
return dirs;
453
}
454
455
/*
456
* <p>
457
* Scan the directories and return all files installed in those
458
* </p>
459
* @param dirs list of directories to scan
460
*
461
* @return the list of files installed in all the directories
462
*/
463
private static File[] getExtFiles(File[] dirs) throws IOException {
464
Vector<File> urls = new Vector<File>();
465
for (int i = 0; i < dirs.length; i++) {
466
String[] files = dirs[i].list(new JarFilter());
467
if (files != null) {
468
debug("getExtFiles files.length " + files.length);
469
for (int j = 0; j < files.length; j++) {
470
File f = new File(dirs[i], files[j]);
471
urls.add(f);
472
debug("getExtFiles f["+j+"] "+ f);
473
}
474
}
475
}
476
File[] ua = new File[urls.size()];
477
urls.copyInto(ua);
478
debug("getExtFiles ua.length " + ua.length);
479
return ua;
480
}
481
482
/*
483
* <p>
484
* @return the list of installed extensions jar files
485
* </p>
486
*/
487
private File[] getInstalledExtensions() throws IOException {
488
return AccessController.doPrivileged(
489
new PrivilegedAction<File[]>() {
490
public File[] run() {
491
try {
492
return getExtFiles(getExtDirs());
493
} catch(IOException e) {
494
debug("Cannot get list of installed extensions");
495
debugException(e);
496
return new File[0];
497
}
498
}
499
});
500
}
501
502
/*
503
* <p>
504
* Add the newly installed jar file to the extension class loader.
505
* </p>
506
*
507
* @param cl the current installed extension class loader
508
*
509
* @return true if successful
510
*/
511
private Boolean addNewExtensionsToClassLoader(Launcher.ExtClassLoader cl) {
512
try {
513
File[] installedExts = getInstalledExtensions();
514
for (int i=0;i<installedExts.length;i++) {
515
final File instFile = installedExts[i];
516
URL instURL = AccessController.doPrivileged(
517
new PrivilegedAction<URL>() {
518
public URL run() {
519
try {
520
return ParseUtil.fileToEncodedURL(instFile);
521
} catch (MalformedURLException e) {
522
debugException(e);
523
return null;
524
}
525
}
526
});
527
if (instURL != null) {
528
URL[] urls = cl.getURLs();
529
boolean found=false;
530
for (int j = 0; j<urls.length; j++) {
531
debug("URL["+j+"] is " + urls[j] + " looking for "+
532
instURL);
533
if (urls[j].toString().compareToIgnoreCase(
534
instURL.toString())==0) {
535
found=true;
536
debug("Found !");
537
}
538
}
539
if (!found) {
540
debug("Not Found ! adding to the classloader " +
541
instURL);
542
cl.addExtURL(instURL);
543
}
544
}
545
}
546
} catch (MalformedURLException e) {
547
e.printStackTrace();
548
} catch (IOException e) {
549
e.printStackTrace();
550
// let's continue with the next installed extension
551
}
552
return Boolean.TRUE;
553
}
554
555
// True to display all debug and trace messages
556
static final boolean DEBUG = false;
557
558
private static void debug(String s) {
559
if (DEBUG) {
560
System.err.println(s);
561
}
562
}
563
564
private void debugException(Throwable e) {
565
if (DEBUG) {
566
e.printStackTrace();
567
}
568
}
569
570
}
571
572