History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/misc/ExtensionDependency.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/misc/ExtensionDependency.java+568−0
@@ -0,0 +1,568 @@
1+/*
2+ * Copyright (c) 1999, 2008, 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 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 attibute 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+
352+ Vector currentProviders;
353+ synchronized(providers) {
354+ currentProviders = (Vector) providers.clone();
355+ }
356+ for (Enumeration e=currentProviders.elements();e.hasMoreElements();) {
357+ ExtensionInstallationProvider eip =
358+ (ExtensionInstallationProvider) e.nextElement();
359+
360+ if (eip!=null) {
361+ // delegate the installation to the provider
362+ if (eip.installExtension(reqInfo, instInfo)) {
363+ debug(reqInfo.name + " installation successful");
364+ Launcher.ExtClassLoader cl = (Launcher.ExtClassLoader)
365+ Launcher.getLauncher().getClassLoader().getParent();
366+ addNewExtensionsToClassLoader(cl);
367+ return true;
368+ }
369+ }
370+ }
371+ // We have tried all of our providers, noone could install this
372+ // extension, we just return failure at this point
373+ debug(reqInfo.name + " installation failed");
374+ return false;
375+ }
376+
377+ /**
378+ * <p>
379+ * Checks if the extension, that is specified in the extension-list in
380+ * the applet jar manifest, is already installed (i.e. exists in the
381+ * extension directory).
382+ * </p>
383+ *
384+ * @param extensionName extension name in the extension-list
385+ *
386+ * @return the extension if it exists in the extension directory
387+ */
388+ private File checkExtensionExists(String extensionName) {
389+ // Function added to fix bug 4504166
390+ final String extName = extensionName;
391+ final String[] fileExt = {".jar", ".zip"};
392+
393+ return AccessController.doPrivileged(
394+ new PrivilegedAction<File>() {
395+ public File run() {
396+ try {
397+ File fExtension;
398+ File[] dirs = getExtDirs();
399+
400+ // Search the extension directories for the extension that is specified
401+ // in the attribute extension-list in the applet jar manifest
402+ for (int i=0;i<dirs.length;i++) {
403+ for (int j=0;j<fileExt.length;j++) {
404+ if (extName.toLowerCase().endsWith(fileExt[j])) {
405+ fExtension = new File(dirs[i], extName);
406+ } else {
407+ fExtension = new File(dirs[i], extName+fileExt[j]);
408+ }
409+ debug("checkExtensionExists:fileName " + fExtension.getName());
410+ if (fExtension.exists()) {
411+ return fExtension;
412+ }
413+ }
414+ }
415+ return null;
416+
417+ } catch(Exception e) {
418+ debugException(e);
419+ return null;
420+ }
421+ }
422+ });
423+ }
424+
425+ /**
426+ * <p>
427+ * @return the java.ext.dirs property as a list of directory
428+ * </p>
429+ */
430+ private static File[] getExtDirs() {
431+ String s = java.security.AccessController.doPrivileged(
432+ new sun.security.action.GetPropertyAction("java.ext.dirs"));
433+
434+ File[] dirs;
435+ if (s != null) {
436+ StringTokenizer st =
437+ new StringTokenizer(s, File.pathSeparator);
438+ int count = st.countTokens();
439+ debug("getExtDirs count " + count);
440+ dirs = new File[count];
441+ for (int i = 0; i < count; i++) {
442+ dirs[i] = new File(st.nextToken());
443+ debug("getExtDirs dirs["+i+"] "+ dirs[i]);
444+ }
445+ } else {
446+ dirs = new File[0];
447+ debug("getExtDirs dirs " + dirs);
448+ }
449+ debug("getExtDirs dirs.length " + dirs.length);
450+ return dirs;
451+ }
452+
453+ /*
454+ * <p>
455+ * Scan the directories and return all files installed in those
456+ * </p>
457+ * @param dirs list of directories to scan
458+ *
459+ * @return the list of files installed in all the directories
460+ */
461+ private static File[] getExtFiles(File[] dirs) throws IOException {
462+ Vector<File> urls = new Vector<File>();
463+ for (int i = 0; i < dirs.length; i++) {
464+ String[] files = dirs[i].list(new JarFilter());
465+ if (files != null) {
466+ debug("getExtFiles files.length " + files.length);
467+ for (int j = 0; j < files.length; j++) {
468+ File f = new File(dirs[i], files[j]);
469+ urls.add(f);
470+ debug("getExtFiles f["+j+"] "+ f);
471+ }
472+ }
473+ }
474+ File[] ua = new File[urls.size()];
475+ urls.copyInto(ua);
476+ debug("getExtFiles ua.length " + ua.length);
477+ return ua;
478+ }
479+
480+ /*
481+ * <p>
482+ * @return the list of installed extensions jar files
483+ * </p>
484+ */
485+ private File[] getInstalledExtensions() throws IOException {
486+ return AccessController.doPrivileged(
487+ new PrivilegedAction<File[]>() {
488+ public File[] run() {
489+ try {
490+ return getExtFiles(getExtDirs());
491+ } catch(IOException e) {
492+ debug("Cannot get list of installed extensions");
493+ debugException(e);
494+ return new File[0];
495+ }
496+ }
497+ });
498+ }
499+
500+ /*
501+ * <p>
502+ * Add the newly installed jar file to the extension class loader.
503+ * </p>
504+ *
505+ * @param cl the current installed extension class loader
506+ *
507+ * @return true if successful
508+ */
509+ private Boolean addNewExtensionsToClassLoader(Launcher.ExtClassLoader cl) {
510+ try {
511+ File[] installedExts = getInstalledExtensions();
512+ for (int i=0;i<installedExts.length;i++) {
513+ final File instFile = installedExts[i];
514+ URL instURL = AccessController.doPrivileged(
515+ new PrivilegedAction<URL>() {
516+ public URL run() {
517+ try {
518+ return ParseUtil.fileToEncodedURL(instFile);
519+ } catch (MalformedURLException e) {
520+ debugException(e);
521+ return null;
522+ }
523+ }
524+ });
525+ if (instURL != null) {
526+ URL[] urls = cl.getURLs();
527+ boolean found=false;
528+ for (int j = 0; j<urls.length; j++) {
529+ debug("URL["+j+"] is " + urls[j] + " looking for "+
530+ instURL);
531+ if (urls[j].toString().compareToIgnoreCase(
532+ instURL.toString())==0) {
533+ found=true;
534+ debug("Found !");
535+ }
536+ }
537+ if (!found) {
538+ debug("Not Found ! adding to the classloader " +
539+ instURL);
540+ cl.addExtURL(instURL);
541+ }
542+ }
543+ }
544+ } catch (MalformedURLException e) {
545+ e.printStackTrace();
546+ } catch (IOException e) {
547+ e.printStackTrace();
548+ // let's continue with the next installed extension
549+ }
550+ return Boolean.TRUE;
551+ }
552+
553+ // True to display all debug and trace messages
554+ static final boolean DEBUG = false;
555+
556+ private static void debug(String s) {
557+ if (DEBUG) {
558+ System.err.println(s);
559+ }
560+ }
561+
562+ private void debugException(Throwable e) {
563+ if (DEBUG) {
564+ e.printStackTrace();
565+ }
566+ }
567+
568+}