blob: fca6609043372757bd2648bf77cdc53bfbb6c9f3 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.misc;
27
28import java.io.File;
29import java.io.IOException;
30import java.io.FilePermission;
31import java.net.URL;
32import java.net.URLClassLoader;
33import java.net.MalformedURLException;
34import java.net.URLStreamHandler;
35import java.net.URLStreamHandlerFactory;
36import java.util.HashSet;
37import java.util.StringTokenizer;
38import java.util.Set;
39import java.util.Vector;
40import java.security.AccessController;
41import java.security.PrivilegedAction;
42import java.security.PrivilegedExceptionAction;
43import java.security.AccessControlContext;
44import java.security.PermissionCollection;
45import java.security.Permissions;
46import java.security.Permission;
47import java.security.ProtectionDomain;
48import java.security.CodeSource;
49import sun.security.action.GetPropertyAction;
50import sun.security.util.SecurityConstants;
51import sun.net.www.ParseUtil;
52
53
54/**
55 * This class is used by the system to launch the main application.
56Launcher */
57public class Launcher {
58 private static URLStreamHandlerFactory factory = new Factory();
59 private static Launcher launcher = new Launcher();
60
61 public static Launcher getLauncher() {
62 return launcher;
63 }
64
65 private ClassLoader loader;
66
67 public Launcher() {
68 // Create the extension class loader
69 ClassLoader extcl;
70 try {
71 extcl = ExtClassLoader.getExtClassLoader();
72 } catch (IOException e) {
73 throw new InternalError(
74 "Could not create extension class loader");
75 }
76
77 // Now create the class loader to use to launch the application
78 try {
79 loader = AppClassLoader.getAppClassLoader(extcl);
80 } catch (IOException e) {
81 throw new InternalError(
82 "Could not create application class loader");
83 }
84
85 // Also set the context class loader for the primordial thread.
86 Thread.currentThread().setContextClassLoader(loader);
87
88 // Finally, install a security manager if requested
89 String s = System.getProperty("java.security.manager");
90 if (s != null) {
91 SecurityManager sm = null;
92 if ("".equals(s) || "default".equals(s)) {
93 sm = new java.lang.SecurityManager();
94 } else {
95 try {
96 sm = (SecurityManager)loader.loadClass(s).newInstance();
97 } catch (IllegalAccessException e) {
98 } catch (InstantiationException e) {
99 } catch (ClassNotFoundException e) {
100 } catch (ClassCastException e) {
101 }
102 }
103 if (sm != null) {
104 System.setSecurityManager(sm);
105 } else {
106 throw new InternalError(
107 "Could not create SecurityManager: " + s);
108 }
109 }
110 }
111
112 /*
113 * Returns the class loader used to launch the main application.
114 */
115 public ClassLoader getClassLoader() {
116 return loader;
117 }
118
119 /*
120 * The class loader used for loading installed extensions.
121 */
122 static class ExtClassLoader extends URLClassLoader {
123 private File[] dirs;
124
125 /**
126 * create an ExtClassLoader. The ExtClassLoader is created
127 * within a context that limits which files it can read
128 */
129 public static ExtClassLoader getExtClassLoader() throws IOException
130 {
131 final File[] dirs = getExtDirs();
132
133 try {
134 // Prior implementations of this doPrivileged() block supplied
135 // aa synthesized ACC via a call to the private method
136 // ExtClassLoader.getContext().
137
138 return (ExtClassLoader) AccessController.doPrivileged(
139 new PrivilegedExceptionAction() {
140 public Object run() throws IOException {
141 int len = dirs.length;
142 for (int i = 0; i < len; i++) {
143 MetaIndex.registerDirectory(dirs[i]);
144 }
145 return new ExtClassLoader(dirs);
146 }
147 });
148 } catch (java.security.PrivilegedActionException e) {
149 throw (IOException) e.getException();
150 }
151 }
152
153 void addExtURL(URL url) {
154 super.addURL(url);
155 }
156
157 /*
158 * Creates a new ExtClassLoader for the specified directories.
159 */
160 public ExtClassLoader(File[] dirs) throws IOException {
161 super(getExtURLs(dirs), null, factory);
162 this.dirs = dirs;
163 }
164
165 private static File[] getExtDirs() {
166 String s = System.getProperty("java.ext.dirs");
167 File[] dirs;
168 if (s != null) {
169 StringTokenizer st =
170 new StringTokenizer(s, File.pathSeparator);
171 int count = st.countTokens();
172 dirs = new File[count];
173 for (int i = 0; i < count; i++) {
174 dirs[i] = new File(st.nextToken());
175 }
176 } else {
177 dirs = new File[0];
178 }
179 return dirs;
180 }
181
182 private static URL[] getExtURLs(File[] dirs) throws IOException {
183 Vector urls = new Vector();
184 for (int i = 0; i < dirs.length; i++) {
185 String[] files = dirs[i].list();
186 if (files != null) {
187 for (int j = 0; j < files.length; j++) {
188 if (!files[j].equals("meta-index")) {
189 File f = new File(dirs[i], files[j]);
190 urls.add(getFileURL(f));
191 }
192 }
193 }
194 }
195 URL[] ua = new URL[urls.size()];
196 urls.copyInto(ua);
197 return ua;
198 }
199
200 /*
201 * Searches the installed extension directories for the specified
202 * library name. For each extension directory, we first look for
203 * the native library in the subdirectory whose name is the value
204 * of the system property <code>os.arch</code>. Failing that, we
205 * look in the extension directory itself.
206 */
207 public String findLibrary(String name) {
208 name = System.mapLibraryName(name);
209 for (int i = 0; i < dirs.length; i++) {
210 // Look in architecture-specific subdirectory first
211 String arch = System.getProperty("os.arch");
212 if (arch != null) {
213 File file = new File(new File(dirs[i], arch), name);
214 if (file.exists()) {
215 return file.getAbsolutePath();
216 }
217 }
218 // Then check the extension directory
219 File file = new File(dirs[i], name);
220 if (file.exists()) {
221 return file.getAbsolutePath();
222 }
223 }
224 return null;
225 }
226
227 private static AccessControlContext getContext(File[] dirs)
228 throws IOException
229 {
230 PathPermissions perms =
231 new PathPermissions(dirs);
232
233 ProtectionDomain domain = new ProtectionDomain(
234 new CodeSource(perms.getCodeBase(),
235 (java.security.cert.Certificate[]) null),
236 perms);
237
238 AccessControlContext acc =
239 new AccessControlContext(new ProtectionDomain[] { domain });
240
241 return acc;
242 }
243 }
244
245 /**
246 * The class loader used for loading from java.class.path.
247 * runs in a restricted security context.
248 */
249 static class AppClassLoader extends URLClassLoader {
250
251 public static ClassLoader getAppClassLoader(final ClassLoader extcl)
252 throws IOException
253 {
254 final String s = System.getProperty("java.class.path");
255 final File[] path = (s == null) ? new File[0] : getClassPath(s);
256
257 // Note: on bugid 4256530
258 // Prior implementations of this doPrivileged() block supplied
259 // a rather restrictive ACC via a call to the private method
260 // AppClassLoader.getContext(). This proved overly restrictive
261 // when loading classes. Specifically it prevent
262 // accessClassInPackage.sun.* grants from being honored.
263 //
264 return (AppClassLoader)
265 AccessController.doPrivileged(new PrivilegedAction() {
266 public Object run() {
267 URL[] urls =
268 (s == null) ? new URL[0] : pathToURLs(path);
269 return new AppClassLoader(urls, extcl);
270 }
271 });
272 }
273
274 /*
275 * Creates a new AppClassLoader
276 */
277 AppClassLoader(URL[] urls, ClassLoader parent) {
278 super(urls, parent, factory);
279 }
280
281 /**
282 * Override loadClass so we can checkPackageAccess.
283 */
284 public synchronized Class loadClass(String name, boolean resolve)
285 throws ClassNotFoundException
286 {
287 int i = name.lastIndexOf('.');
288 if (i != -1) {
289 SecurityManager sm = System.getSecurityManager();
290 if (sm != null) {
291 sm.checkPackageAccess(name.substring(0, i));
292 }
293 }
294 return (super.loadClass(name, resolve));
295 }
296
297 /**
298 * allow any classes loaded from classpath to exit the VM.
299 */
300 protected PermissionCollection getPermissions(CodeSource codesource)
301 {
302 PermissionCollection perms = super.getPermissions(codesource);
303 perms.add(new RuntimePermission("exitVM"));
304 return perms;
305 }
306
307 /**
308 * This class loader supports dynamic additions to the class path
309 * at runtime.
310 *
311 * @see java.lang.instrument.Instrumentation#appendToSystemClassPathSearch
312 */
313 private void appendToClassPathForInstrumentation(String path) {
314 assert(Thread.holdsLock(this));
315
316 // addURL is a no-op if path already contains the URL
317 super.addURL( getFileURL(new File(path)) );
318 }
319
320 /**
321 * create a context that can read any directories (recursively)
322 * mentioned in the class path. In the case of a jar, it has to
323 * be the directory containing the jar, not just the jar, as jar
324 * files might refer to other jar files.
325 */
326
327 private static AccessControlContext getContext(File[] cp)
328 throws java.net.MalformedURLException
329 {
330 PathPermissions perms =
331 new PathPermissions(cp);
332
333 ProtectionDomain domain =
334 new ProtectionDomain(new CodeSource(perms.getCodeBase(),
335 (java.security.cert.Certificate[]) null),
336 perms);
337
338 AccessControlContext acc =
339 new AccessControlContext(new ProtectionDomain[] { domain });
340
341 return acc;
342 }
343 }
344
345 public static URLClassPath getBootstrapClassPath() {
346 String prop = AccessController.doPrivileged(
347 new GetPropertyAction("sun.boot.class.path"));
348 URL[] urls;
349 if (prop != null) {
350 final String path = prop;
351 urls = (URL[])AccessController.doPrivileged(
352 new PrivilegedAction() {
353 public Object run() {
354 File[] classPath = getClassPath(path);
355 int len = classPath.length;
356 Set seenDirs = new HashSet();
357 for (int i = 0; i < len; i++) {
358 File curEntry = classPath[i];
359 // Negative test used to properly handle
360 // nonexistent jars on boot class path
361 if (!curEntry.isDirectory()) {
362 curEntry = curEntry.getParentFile();
363 }
364 if (curEntry != null && seenDirs.add(curEntry)) {
365 MetaIndex.registerDirectory(curEntry);
366 }
367 }
368 return pathToURLs(classPath);
369 }
370 }
371 );
372 } else {
373 urls = new URL[0];
374 }
375 return new URLClassPath(urls, factory);
376 }
377
378 private static URL[] pathToURLs(File[] path) {
379 URL[] urls = new URL[path.length];
380 for (int i = 0; i < path.length; i++) {
381 urls[i] = getFileURL(path[i]);
382 }
383 // DEBUG
384 //for (int i = 0; i < urls.length; i++) {
385 // System.out.println("urls[" + i + "] = " + '"' + urls[i] + '"');
386 //}
387 return urls;
388 }
389
390 private static File[] getClassPath(String cp) {
391 File[] path;
392 if (cp != null) {
393 int count = 0, maxCount = 1;
394 int pos = 0, lastPos = 0;
395 // Count the number of separators first
396 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) {
397 maxCount++;
398 lastPos = pos + 1;
399 }
400 path = new File[maxCount];
401 lastPos = pos = 0;
402 // Now scan for each path component
403 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) {
404 if (pos - lastPos > 0) {
405 path[count++] = new File(cp.substring(lastPos, pos));
406 } else {
407 // empty path component translates to "."
408 path[count++] = new File(".");
409 }
410 lastPos = pos + 1;
411 }
412 // Make sure we include the last path component
413 if (lastPos < cp.length()) {
414 path[count++] = new File(cp.substring(lastPos));
415 } else {
416 path[count++] = new File(".");
417 }
418 // Trim array to correct size
419 if (count != maxCount) {
420 File[] tmp = new File[count];
421 System.arraycopy(path, 0, tmp, 0, count);
422 path = tmp;
423 }
424 } else {
425 path = new File[0];
426 }
427 // DEBUG
428 //for (int i = 0; i < path.length; i++) {
429 // System.out.println("path[" + i + "] = " + '"' + path[i] + '"');
430 //}
431 return path;
432 }
433
434 private static URLStreamHandler fileHandler;
435
436 static URL getFileURL(File file) {
437 try {
438 file = file.getCanonicalFile();
439 } catch (IOException e) {}
440
441 try {
442 return ParseUtil.fileToEncodedURL(file);
443 } catch (MalformedURLException e) {
444 // Should never happen since we specify the protocol...
445 throw new InternalError();
446 }
447 }
448
449 /*
450 * The stream handler factory for loading system protocol handlers.
451 */
452 private static class Factory implements URLStreamHandlerFactory {
453 private static String PREFIX = "sun.net.www.protocol";
454
455 public URLStreamHandler createURLStreamHandler(String protocol) {
456 String name = PREFIX + "." + protocol + ".Handler";
457 try {
458 Class c = Class.forName(name);
459 return (URLStreamHandler)c.newInstance();
460 } catch (ClassNotFoundException e) {
461 e.printStackTrace();
462 } catch (InstantiationException e) {
463 e.printStackTrace();
464 } catch (IllegalAccessException e) {
465 e.printStackTrace();
466 }
467 throw new InternalError("could not load " + protocol +
468 "system protocol handler");
469 }
470 }
471}
472
473class PathPermissions extends PermissionCollection {
474 // use serialVersionUID from JDK 1.2.2 for interoperability
475 private static final long serialVersionUID = 8133287259134945693L;
476
477 private File path[];
478 private Permissions perms;
479
480 URL codeBase;
481
482 PathPermissions(File path[])
483 {
484 this.path = path;
485 this.perms = null;
486 this.codeBase = null;
487 }
488
489 URL getCodeBase()
490 {
491 return codeBase;
492 }
493
494 public void add(java.security.Permission permission) {
495 throw new SecurityException("attempt to add a permission");
496 }
497
498 private synchronized void init()
499 {
500 if (perms != null)
501 return;
502
503 perms = new Permissions();
504
505 // this is needed to be able to create the classloader itself!
506 perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
507
508 // add permission to read any "java.*" property
509 perms.add(new java.util.PropertyPermission("java.*",
510 SecurityConstants.PROPERTY_READ_ACTION));
511
512 AccessController.doPrivileged(new PrivilegedAction() {
513 public Object run() {
514 for (int i=0; i < path.length; i++) {
515 File f = path[i];
516 String path;
517 try {
518 path = f.getCanonicalPath();
519 } catch (IOException ioe) {
520 path = f.getAbsolutePath();
521 }
522 if (i == 0) {
523 codeBase = Launcher.getFileURL(new File(path));
524 }
525 if (f.isDirectory()) {
526 if (path.endsWith(File.separator)) {
527 perms.add(new FilePermission(path+"-",
528 SecurityConstants.FILE_READ_ACTION));
529 } else {
530 perms.add(new FilePermission(
531 path + File.separator+"-",
532 SecurityConstants.FILE_READ_ACTION));
533 }
534 } else {
535 int endIndex = path.lastIndexOf(File.separatorChar);
536 if (endIndex != -1) {
537 path = path.substring(0, endIndex+1) + "-";
538 perms.add(new FilePermission(path,
539 SecurityConstants.FILE_READ_ACTION));
540 } else {
541 // XXX?
542 }
543 }
544 }
545 return null;
546 }
547 });
548 }
549
550 public boolean implies(java.security.Permission permission) {
551 if (perms == null)
552 init();
553 return perms.implies(permission);
554 }
555
556 public java.util.Enumeration elements() {
557 if (perms == null)
558 init();
559 synchronized (perms) {
560 return perms.elements();
561 }
562 }
563
564 public String toString() {
565 if (perms == null)
566 init();
567 return perms.toString();
568 }
569}