URLClassLoader.java revision b1396870f92135aa140bd2b86221768dea5bc11d
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.net;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.BufferedReader;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.ByteArrayOutputStream;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.File;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileInputStream;
24f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.FileNotFoundException;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FilePermission;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
28f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.InputStreamReader;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.UnsupportedEncodingException;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessControlContext;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessController;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.CodeSource;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PermissionCollection;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PrivilegedAction;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.SecureClassLoader;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.cert.Certificate;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collections;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Enumeration;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap;
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.List;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Map;
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.StringTokenizer;
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.Attributes;
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.JarEntry;
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.JarFile;
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.Manifest;
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class loader is responsible for loading classes and resources from a
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * list of URLs which can refer to either directories or JAR files. Classes
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * loaded by this {@code URLClassLoader} are granted permission to access the
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * URLs contained in the URL search list.
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class URLClassLoader extends SecureClassLoader {
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
57f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    ArrayList<URL> originalUrls;
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
59f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    List<URL> searchList;
60f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    ArrayList<URLHandler> handlerList;
61f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    Map<URL, URLHandler> handlerMap = new HashMap<URL, URLHandler>();
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private URLStreamHandlerFactory factory;
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private AccessControlContext currentContext;
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static class SubURLClassLoader extends URLClassLoader {
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // The subclass that overwrites the loadClass() method
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private boolean checkingPackageAccess = false;
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SubURLClassLoader(URL[] urls) {
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            super(urls, ClassLoader.getSystemClassLoader());
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SubURLClassLoader(URL[] urls, ClassLoader parent) {
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            super(urls, parent);
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Overrides the {@code loadClass()} of {@code ClassLoader}. It calls
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * the security manager's {@code checkPackageAccess()} before
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * attempting to load the class.
83f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson         *
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return the Class object.
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @param className
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         *            String the name of the class to search for.
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @param resolveClass
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         *            boolean indicates if class should be resolved after
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         *            loading.
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @throws ClassNotFoundException
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         *             If the class could not be found.
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        protected synchronized Class<?> loadClass(String className,
95f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                                  boolean resolveClass) throws ClassNotFoundException {
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            SecurityManager sm = System.getSecurityManager();
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (sm != null && !checkingPackageAccess) {
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int index = className.lastIndexOf('.');
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (index > 0) { // skip if class is from a default package
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        checkingPackageAccess = true;
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        sm.checkPackageAccess(className.substring(0, index));
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } finally {
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        checkingPackageAccess = false;
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return super.loadClass(className, resolveClass);
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
112f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    static class IndexFile {
113f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
114f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        private HashMap<String, ArrayList<URL>> map;
115f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        //private URLClassLoader host;
116f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
117f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
118f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        static IndexFile readIndexFile(JarFile jf, JarEntry indexEntry, URL url) {
119f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            BufferedReader in = null;
120f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            InputStream is = null;
121f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            try {
122f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // Add mappings from resource to jar file
123f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                String parentURLString = getParentURL(url).toExternalForm();
124f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                String prefix = "jar:"
125f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                        + parentURLString + "/";
126f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                is = jf.getInputStream(indexEntry);
127f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                in = new BufferedReader(new InputStreamReader(is, "UTF8"));
128f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                HashMap<String, ArrayList<URL>> pre_map = new HashMap<String, ArrayList<URL>>();
129f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // Ignore the 2 first lines (index version)
130f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (in.readLine() == null) return null;
131f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (in.readLine() == null) return null;
132f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                TOP_CYCLE:
133f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                while (true) {
134f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    String line = in.readLine();
135f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (line == null) {
136f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        break;
137f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
138f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    URL jar = new URL(prefix + line + "!/");
139f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    while (true) {
140f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        line = in.readLine();
141f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        if (line == null) {
142f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            break TOP_CYCLE;
143f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        }
14480a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes                        if (line.isEmpty()) {
145f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            break;
146f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        }
147f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        ArrayList<URL> list;
148f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        if (pre_map.containsKey(line)) {
149f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            list = pre_map.get(line);
150f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        } else {
151f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            list = new ArrayList<URL>();
152f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            pre_map.put(line, list);
153f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        }
154f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        list.add(jar);
155f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
156f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
157f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (!pre_map.isEmpty()) {
158f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    return new IndexFile(pre_map);
159f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
160f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (MalformedURLException e) {
161f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // Ignore this jar's index
162f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (IOException e) {
163f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // Ignore this jar's index
164f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
165f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            finally {
166f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (in != null) {
167f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    try {
168f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        in.close();
169f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    } catch (IOException e) {
170f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
171f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
172f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (is != null) {
173f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    try {
174f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        is.close();
175f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    } catch (IOException e) {
176f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
177f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
178f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
179f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return null;
180f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
181f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
182f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        private static URL getParentURL(URL url) throws IOException {
183f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL fileURL = ((JarURLConnection) url.openConnection()).getJarFileURL();
184f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String file = fileURL.getFile();
185f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String parentFile = new File(file).getParent();
186f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            parentFile = parentFile.replace(File.separatorChar, '/');
187f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (parentFile.charAt(0) != '/') {
188f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                parentFile = "/" + parentFile;
189f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
190f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL parentURL = new URL(fileURL.getProtocol(), fileURL
191f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    .getHost(), fileURL.getPort(), parentFile);
192f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return parentURL;
193f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
194f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
195f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        public IndexFile(HashMap<String, ArrayList<URL>> map) {
196f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.map = map;
197f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
198f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
199f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        ArrayList<URL> get(String name) {
200f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return map.get(name);
201f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
202f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
203f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
204f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    class URLHandler {
205f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        URL url;
206f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        URL codeSourceUrl;
207f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
208f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        public URLHandler(URL url) {
209f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.url = url;
210f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.codeSourceUrl = url;
211f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
212f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
213f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        void findResources(String name, ArrayList<URL> resources) {
214f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL res = findResource(name);
215f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (res != null && !resources.contains(res)) {
216f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                resources.add(res);
217f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
218f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
219f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
220f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        Class<?> findClass(String packageName, String name, String origName) {
221f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL resURL = targetURL(url, name);
222f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (resURL != null) {
223f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                try {
224f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    InputStream is = resURL.openStream();
225f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    return createClass(is, packageName, origName);
226f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } catch (IOException e) {
227f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
228f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
229f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return null;
230f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
231f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
232f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
233f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        Class<?> createClass(InputStream is, String packageName, String origName) {
234f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (is == null) {
235f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
236f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
237f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            byte[] clBuf = null;
238f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            try {
239f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                clBuf = getBytes(is);
240f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (IOException e) {
241f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
242f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } finally {
243f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                try {
244f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    is.close();
245f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } catch (IOException e) {
246f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
247f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
248f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (packageName != null) {
249f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                String packageDotName = packageName.replace('/', '.');
250f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                Package packageObj = getPackage(packageDotName);
251f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (packageObj == null) {
252f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    definePackage(packageDotName, null, null,
253f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            null, null, null, null, null);
254f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } else {
255f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (packageObj.isSealed()) {
256b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                        throw new SecurityException("Package is sealed");
257f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
258f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
259f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
260f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return defineClass(origName, clBuf, 0, clBuf.length, new CodeSource(codeSourceUrl, (Certificate[]) null));
261f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
262f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
263f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        URL findResource(String name) {
264f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL resURL = targetURL(url, name);
265f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (resURL != null) {
266f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                try {
267f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    URLConnection uc = resURL.openConnection();
268f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    uc.getInputStream().close();
269f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // HTTP can return a stream on a non-existent file
270f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // So check for the return code;
271f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    if (!resURL.getProtocol().equals("http")) {
272f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        return resURL;
273f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
274f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    int code;
275f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if ((code = ((HttpURLConnection) uc).getResponseCode()) >= 200
276f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            && code < 300) {
277f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        return resURL;
278f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
279f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } catch (SecurityException e) {
280f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    return null;
281f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } catch (IOException e) {
282f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    return null;
283f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
284f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
285f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return null;
286f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
287f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
288f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        URL targetURL(URL base, String name) {
289f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            try {
290f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                String file = base.getFile() + URIEncoderDecoder.quoteIllegal(name,
29138607710cdc82cb1a0e81c2fc5c78278b435e4fcJesse Wilson                        "/@" + URI.SOME_LEGAL);
292f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
293f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return new URL(base.getProtocol(), base.getHost(), base.getPort(),
294f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        file, null);
295f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (UnsupportedEncodingException e) {
296f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
297f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (MalformedURLException e) {
298f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
299f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
300f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
301f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
302f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
303f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
304f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    class URLJarHandler extends URLHandler {
305f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        final JarFile jf;
306f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        final String prefixName;
307f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        final IndexFile index;
308f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        final Map<URL, URLHandler> subHandlers = new HashMap<URL, URLHandler>();
309f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
310f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        public URLJarHandler(URL url, URL jarURL, JarFile jf, String prefixName) {
311f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            super(url);
312f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.jf = jf;
313f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.prefixName = prefixName;
314f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.codeSourceUrl = jarURL;
315f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            final JarEntry je = jf.getJarEntry("META-INF/INDEX.LIST");
316f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.index = (je == null ? null : IndexFile.readIndexFile(jf, je, url));
317f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
318f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
319f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        public URLJarHandler(URL url, URL jarURL, JarFile jf, String prefixName, IndexFile index) {
320f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            super(url);
321f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.jf = jf;
322f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.prefixName = prefixName;
323f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.index = index;
324f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            this.codeSourceUrl = jarURL;
325f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
326f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
327f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        IndexFile getIndex() {
328f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return index;
329f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
330f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
331f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        @Override
332f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        void findResources(String name, ArrayList<URL> resources) {
333f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL res = findResourceInOwn(name);
334f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (res != null && !resources.contains(res)) {
335f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                resources.add(res);
336f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
337f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (index != null) {
338f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                int pos = name.lastIndexOf("/");
339f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // only keep the directory part of the resource
340f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // as index.list only keeps track of directories and root files
341f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                String indexedName = (pos > 0) ? name.substring(0, pos) : name;
342f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                ArrayList<URL> urls = index.get(indexedName);
343f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (urls != null) {
344f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    urls.remove(url);
345f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    for (URL url : urls) {
346f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        URLHandler h = getSubHandler(url);
347f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        if (h != null) {
348f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            h.findResources(name, resources);
349f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        }
350f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
351f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
352f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
353f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
354f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
355f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
356f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        @Override
357f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        Class<?> findClass(String packageName, String name, String origName) {
358f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String entryName = prefixName + name;
359f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            JarEntry entry = jf.getJarEntry(entryName);
360f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (entry != null) {
361f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                /**
362f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                 * Avoid recursive load class, especially the class
363f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                 * is an implementation class of security provider
364f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                 * and the jar is signed.
365f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                 */
366f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                try {
367f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    Manifest manifest = jf.getManifest();
368f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    return createClass(entry, manifest, packageName, origName);
369f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } catch (IOException e) {
370f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
371f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
372f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (index != null) {
373f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                ArrayList<URL> urls;
374f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (packageName == null) {
375f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    urls = index.get(name);
376f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } else {
377f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    urls = index.get(packageName);
378f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
379f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (urls != null) {
380f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    urls.remove(url);
381f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    for (URL url : urls) {
382f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        URLHandler h = getSubHandler(url);
383f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        if (h != null) {
384f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            Class<?> res = h.findClass(packageName, name, origName);
385f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            if (res != null) {
386f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                return res;
387f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            }
388f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        }
389f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
390f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
391f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
392f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return null;
393f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
394f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
395f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        private Class<?> createClass(JarEntry entry, Manifest manifest, String packageName, String origName) {
396f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            InputStream is = null;
397f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            byte[] clBuf = null;
398f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            try {
399f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                is = jf.getInputStream(entry);
400f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                clBuf = getBytes(is);
401f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (IOException e) {
402f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
403f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } finally {
404f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (is != null) {
405f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    try {
406f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        is.close();
407f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    } catch (IOException e) {
408f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
409f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
410f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
411f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (packageName != null) {
412f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                String packageDotName = packageName.replace('/', '.');
413f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                Package packageObj = getPackage(packageDotName);
414f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (packageObj == null) {
415f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (manifest != null) {
416f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        definePackage(packageDotName, manifest,
417f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                codeSourceUrl);
418f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    } else {
419f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        definePackage(packageDotName, null, null,
420f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                null, null, null, null, null);
421f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
422f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } else {
423f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    boolean exception = packageObj.isSealed();
424f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (manifest != null) {
425f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        if (isSealed(manifest, packageName + "/")) {
426f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            exception = !packageObj
427f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                    .isSealed(codeSourceUrl);
428f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        }
429f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
430f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (exception) {
431b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                        throw new SecurityException(String.format("Package %s is sealed",
432b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                                packageName));
433f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
434f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
435f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
436f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            CodeSource codeS = new CodeSource(codeSourceUrl, entry.getCertificates());
437f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return defineClass(origName, clBuf, 0, clBuf.length, codeS);
438f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
439f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
440f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        URL findResourceInOwn(String name) {
441f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String entryName = prefixName + name;
442f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (jf.getEntry(entryName) != null) {
443f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return targetURL(url, name);
444f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
445f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return null;
446f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
447f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
448f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        @Override
449f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        URL findResource(String name) {
450f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL res = findResourceInOwn(name);
451f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (res != null) {
452f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return res;
453f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
454f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (index != null) {
455f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                int pos = name.lastIndexOf("/");
456f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // only keep the directory part of the resource
457f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // as index.list only keeps track of directories and root files
458f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                String indexedName = (pos > 0) ? name.substring(0, pos) : name;
459f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                ArrayList<URL> urls = index.get(indexedName);
460f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (urls != null) {
461f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    urls.remove(url);
462f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    for (URL url : urls) {
463f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        URLHandler h = getSubHandler(url);
464f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        if (h != null) {
465f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            res = h.findResource(name);
466f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            if (res != null) {
467f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                return res;
468f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            }
469f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        }
470f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
471f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
472f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
473f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return null;
474f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
475f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
476f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        private synchronized URLHandler getSubHandler(URL url) {
477f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URLHandler sub = subHandlers.get(url);
478f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (sub != null) {
479f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return sub;
480f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
481f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String protocol = url.getProtocol();
482f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            if (protocol.equals("jar")) {
483f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                sub = createURLJarHandler(url);
484f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            } else if (protocol.equals("file")) {
485f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                sub = createURLSubJarHandler(url);
486f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } else {
487f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                sub = createURLHandler(url);
488f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
489f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (sub != null) {
490f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                subHandlers.put(url, sub);
491f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
492f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return sub;
493f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
494f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
495f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        private URLHandler createURLSubJarHandler(URL url) {
496f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String prefixName;
497f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String file = url.getFile();
498f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            if (url.getFile().endsWith("!/")) {
499f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                prefixName = "";
500f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } else {
501f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                int sepIdx = file.lastIndexOf("!/");
502f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (sepIdx == -1) {
503f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // Invalid URL, don't look here again
504f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    return null;
505f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
506f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                sepIdx += 2;
507f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                prefixName = file.substring(sepIdx);
508f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
509f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            try {
510f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                URL jarURL = ((JarURLConnection) url
511f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        .openConnection()).getJarFileURL();
512f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                JarURLConnection juc = (JarURLConnection) new URL(
513f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                        "jar", "",
514f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                        jarURL.toExternalForm() + "!/").openConnection();
515f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                JarFile jf = juc.getJarFile();
516f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                URLJarHandler jarH = new URLJarHandler(url, jarURL, jf, prefixName, null);
517f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // TODO : to think what we should do with indexes & manifest.class file here
518f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return jarH;
519f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (IOException e) {
520f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
521f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return null;
522f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
523f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
524f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
525f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
526f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    class URLFileHandler extends URLHandler {
527f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        private String prefix;
528f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
529f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        public URLFileHandler(URL url) {
530f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            super(url);
531f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String baseFile = url.getFile();
532f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String host = url.getHost();
533f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            int hostLength = 0;
534f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (host != null) {
535f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                hostLength = host.length();
536f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
537f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            StringBuilder buf = new StringBuilder(2 + hostLength
538f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    + baseFile.length());
539f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (hostLength > 0) {
540f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                buf.append("//").append(host);
541f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
542f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            // baseFile always ends with '/'
543f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            buf.append(baseFile);
544f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            prefix = buf.toString();
545f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
546f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
547f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        @Override
548f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        Class<?> findClass(String packageName, String name, String origName) {
549f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String filename = prefix + name;
550f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            try {
551f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                filename = URLDecoder.decode(filename, "UTF-8");
552f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (IllegalArgumentException e) {
553f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
554f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (UnsupportedEncodingException e) {
555f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
556f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
557f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
558f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            File file = new File(filename);
559f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (file.exists()) {
560f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                try {
561f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    InputStream is = new FileInputStream(file);
562f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    return createClass(is, packageName, origName);
563f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } catch (FileNotFoundException e) {
564f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
565f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
566f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return null;
567f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
568f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
569f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        @Override
570f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        URL findResource(String name) {
571f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            int idx = 0;
572f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            String filename;
573f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
574f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            // Do not create a UNC path, i.e. \\host
575f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            while (idx < name.length() &&
576f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                   ((name.charAt(idx) == '/') || (name.charAt(idx) == '\\'))) {
577f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                idx++;
578f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
579f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
580f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (idx > 0) {
581f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                name = name.substring(idx);
582f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
583f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
584f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            try {
585f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                filename = URLDecoder.decode(prefix, "UTF-8") + name;
586f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
587f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (new File(filename).exists()) {
588f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    return targetURL(url, name);
589f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
590f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
591f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (IllegalArgumentException e) {
592f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
593f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } catch (UnsupportedEncodingException e) {
594f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // must not happen
595f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                throw new AssertionError(e);
596f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
597f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
598f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
599f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
600f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
601f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new {@code URLClassLoader} instance. The newly created
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * instance will have the system ClassLoader as its parent. URLs that end
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * with "/" are assumed to be directories, otherwise they are assumed to be
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * JAR files.
607f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param urls
609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the list of URLs where a specific class or file could be
610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            found.
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws SecurityException
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if a security manager exists and its {@code
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             checkCreateClassLoader()} method doesn't allow creation of
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             new ClassLoaders.
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URLClassLoader(URL[] urls) {
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(urls, ClassLoader.getSystemClassLoader(), null);
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new URLClassLoader instance. The newly created instance will
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * have the system ClassLoader as its parent. URLs that end with "/" are
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * assumed to be directories, otherwise they are assumed to be JAR files.
624f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param urls
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the list of URLs where a specific class or file could be
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            found.
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param parent
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the class loader to assign as this loader's parent.
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws SecurityException
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if a security manager exists and its {@code
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             checkCreateClassLoader()} method doesn't allow creation of
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             new class loaders.
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URLClassLoader(URL[] urls, ClassLoader parent) {
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(urls, parent, null);
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Adds the specified URL to the search list.
641f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param url
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the URL which is to add.
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void addURL(URL url) {
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
647f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            originalUrls.add(url);
648f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            searchList.add(createSearchURL(url));
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (MalformedURLException e) {
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns all known URLs which point to the specified resource.
655f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the requested resource.
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the enumeration of URLs which point to the specified resource.
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an I/O error occurs while attempting to connect.
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Enumeration<URL> findResources(final String name) throws IOException {
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (name == null) {
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
667f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        ArrayList<URL> result = AccessController.doPrivileged(
668f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                new PrivilegedAction<ArrayList<URL>>() {
669f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    public ArrayList<URL> run() {
670f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        ArrayList<URL> results = new ArrayList<URL>();
671f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        findResourcesImpl(name, results);
672f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        return results;
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }, currentContext);
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SecurityManager sm;
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = result.size();
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length > 0 && (sm = System.getSecurityManager()) != null) {
678f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            ArrayList<URL> reduced = new ArrayList<URL>(length);
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 0; i < length; i++) {
680f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                URL url = result.get(i);
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    sm.checkPermission(url.openConnection().getPermission());
683f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    reduced.add(url);
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (IOException e) {
685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (SecurityException e) {
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = reduced;
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
690f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return Collections.enumeration(result);
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
693f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    void findResourcesImpl(String name, ArrayList<URL> result) {
694f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        int n = 0;
695f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        while (true) {
696f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URLHandler handler = getHandler(n++);
697f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (handler == null) {
698f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                break;
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
700f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            handler.findResources(name, result);
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Converts an input stream into a byte array.
707f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param is
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input stream
710f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @return byte[] the byte array
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
712f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private static byte[] getBytes(InputStream is)
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] buf = new byte[4096];
715f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        ByteArrayOutputStream bos = new ByteArrayOutputStream(4096);
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int count;
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while ((count = is.read(buf)) > 0) {
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            bos.write(buf, 0, count);
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return bos.toByteArray();
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets all permissions for the specified {@code codesource}. First, this
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method retrieves the permissions from the system policy. If the protocol
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * is "file:/" then a new permission, {@code FilePermission}, granting the
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * read permission to the file is added to the permission collection.
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Otherwise, connecting to and accepting connections from the URL is
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * granted.
730f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param codesource
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the code source object whose permissions have to be known.
733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the list of permissions according to the code source object.
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected PermissionCollection getPermissions(final CodeSource codesource) {
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        PermissionCollection pc = super.getPermissions(codesource);
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        URL u = codesource.getLocation();
739f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        if (u.getProtocol().equals("jar")) {
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Create a URL for the resource the jar refers to
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                u = ((JarURLConnection) u.openConnection()).getJarFileURL();
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (IOException e) {
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // This should never occur. If it does continue using the jar
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // URL
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
748f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        if (u.getProtocol().equals("file")) {
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String path = u.getFile();
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String host = u.getHost();
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (host != null && host.length() > 0) {
752f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                path = "//" + host + path;
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (File.separatorChar != '/') {
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                path = path.replace('/', File.separatorChar);
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (isDirectory(u)) {
759f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                pc.add(new FilePermission(path + "-", "read"));
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
761f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                pc.add(new FilePermission(path, "read"));
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String host = u.getHost();
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (host.length() == 0) {
766f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                host = "localhost";
767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
768f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            pc.add(new SocketPermission(host, "connect, accept"));
769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
770adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return pc;
771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the search list of this {@code URLClassLoader}.
775f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the list of all known URLs of this instance.
777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
778adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URL[] getURLs() {
779f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return originalUrls.toArray(new URL[originalUrls.size()]);
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Determines if the URL is pointing to a directory.
784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
785adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static boolean isDirectory(URL url) {
786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String file = url.getFile();
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return (file.length() > 0 && file.charAt(file.length() - 1) == '/');
788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
789adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a new {@code URLClassLoader} instance for the given URLs and the
792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * system {@code ClassLoader} as its parent. The method {@code loadClass()}
793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * of the new instance will call {@code
794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * SecurityManager.checkPackageAccess()} before loading a class.
795f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param urls
797adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the list of URLs that is passed to the new {@code
798adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            URLClassloader}.
799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the created {@code URLClassLoader} instance.
800adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static URLClassLoader newInstance(final URL[] urls) {
802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        URLClassLoader sub = AccessController
803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .doPrivileged(new PrivilegedAction<URLClassLoader>() {
804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    public URLClassLoader run() {
805adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return new SubURLClassLoader(urls);
806adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
807adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                });
808adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sub.currentContext = AccessController.getContext();
809adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sub;
810adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
811adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
812adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
813adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a new {@code URLClassLoader} instance for the given URLs and the
814adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specified {@code ClassLoader} as its parent. The method {@code
815adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * loadClass()} of the new instance will call the SecurityManager's {@code
816adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * checkPackageAccess()} before loading a class.
817f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
818adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param urls
819adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the list of URLs that is passed to the new URLClassloader.
820adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param parentCl
821adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the parent class loader that is passed to the new
822adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            URLClassloader.
823adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the created {@code URLClassLoader} instance.
824adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
825adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static URLClassLoader newInstance(final URL[] urls,
826f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                             final ClassLoader parentCl) {
827adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        URLClassLoader sub = AccessController
828adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .doPrivileged(new PrivilegedAction<URLClassLoader>() {
829adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    public URLClassLoader run() {
830adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return new SubURLClassLoader(urls, parentCl);
831adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
832adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                });
833adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sub.currentContext = AccessController.getContext();
834adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sub;
835adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
836adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
837adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
838adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new {@code URLClassLoader} instance. The newly created
839adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * instance will have the specified {@code ClassLoader} as its parent and
840adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * use the specified factory to create stream handlers. URLs that end with
841adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * "/" are assumed to be directories, otherwise they are assumed to be JAR
842adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * files.
843f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
844adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param searchUrls
845adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the list of URLs where a specific class or file could be
846adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            found.
847adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param parent
848adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code ClassLoader} to assign as this loader's parent.
849adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param factory
850adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the factory that will be used to create protocol-specific
851adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            stream handlers.
852adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws SecurityException
853adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if a security manager exists and its {@code
854adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             checkCreateClassLoader()} method doesn't allow creation of
855adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             new {@code ClassLoader}s.
856adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
857adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URLClassLoader(URL[] searchUrls, ClassLoader parent,
858f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                          URLStreamHandlerFactory factory) {
859adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(parent);
860adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Required for pre-v1.2 security managers to work
861adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SecurityManager security = System.getSecurityManager();
862adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (security != null) {
863adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            security.checkCreateClassLoader();
864adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
865adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.factory = factory;
866adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // capture the context of the thread that creates this URLClassLoader
867adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        currentContext = AccessController.getContext();
868adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int nbUrls = searchUrls.length;
869f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        originalUrls = new ArrayList<URL>(nbUrls);
870f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        handlerList = new ArrayList<URLHandler>(nbUrls);
871f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        searchList = Collections.synchronizedList(new ArrayList<URL>(nbUrls));
872adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = 0; i < nbUrls; i++) {
873f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            originalUrls.add(searchUrls[i]);
874adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
875f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                searchList.add(createSearchURL(searchUrls[i]));
876adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (MalformedURLException e) {
877adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
878adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
879adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
880adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
881adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
882adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Tries to locate and load the specified class using the known URLs. If the
883adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * class could be found, a class object representing the loaded class will
884adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * be returned.
885f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
886adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param clsName
887adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the class which has to be found.
888f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @return the class that has been loaded.
889adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws ClassNotFoundException
890adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified class cannot be loaded.
891adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
892adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
893adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected Class<?> findClass(final String clsName)
894adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws ClassNotFoundException {
895adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Class<?> cls = AccessController.doPrivileged(
896adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                new PrivilegedAction<Class<?>>() {
897adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    public Class<?> run() {
898f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        return findClassImpl(clsName);
899adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
900adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }, currentContext);
901adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (cls != null) {
902adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return cls;
903adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
904adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        throw new ClassNotFoundException(clsName);
905adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
906adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
907adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
908adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an URL that will be checked if it contains the class or resource.
909adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * If the file component of the URL is not a directory, a Jar URL will be
910adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * created.
911f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
912adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return java.net.URL a test URL
913adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
914adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private URL createSearchURL(URL url) throws MalformedURLException {
915adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (url == null) {
916adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return url;
917adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
918adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
919adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String protocol = url.getProtocol();
920adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
921f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        if (isDirectory(url) || protocol.equals("jar")) {
922adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return url;
923adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
924adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (factory == null) {
925f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            return new URL("jar", "",
926f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    -1, url.toString() + "!/");
927adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
928f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // use jar protocol as the stream handler protocol
929f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        return new URL("jar", "",
930f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                -1, url.toString() + "!/",
931fd6bb3510c2f94d636f3572dcf5f7f4dcd1a2726Elliott Hughes                factory.createURLStreamHandler("jar"));
932adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
933adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
934adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
935adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an URL referencing the specified resource or {@code null} if the
936adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * resource could not be found.
937f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
938adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
939adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the requested resource.
940adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the URL which points to the given resource.
941adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
942adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
943adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URL findResource(final String name) {
944adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (name == null) {
945adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
946adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
947adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        URL result = AccessController.doPrivileged(new PrivilegedAction<URL>() {
948adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            public URL run() {
949f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return findResourceImpl(name);
950adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
951adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }, currentContext);
952adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SecurityManager sm;
953adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result != null && (sm = System.getSecurityManager()) != null) {
954adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
955adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                sm.checkPermission(result.openConnection().getPermission());
956adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (IOException e) {
957adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
958adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (SecurityException e) {
959adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
960adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
961adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
962adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
963adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
964adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
965adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
966adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a URL among the given ones referencing the specified resource or
967adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * null if no resource could be found.
968f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
969f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @param resName java.lang.String the name of the requested resource
970adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return URL URL for the resource.
971adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
972f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    URL findResourceImpl(String resName) {
973f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        int n = 0;
974f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
975f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        while (true) {
976f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URLHandler handler = getHandler(n++);
977f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (handler == null) {
978f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                break;
979f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
980f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL res = handler.findResource(resName);
981f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (res != null) {
982f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return res;
983f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
984f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
985f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return null;
986f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
987f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
988f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    URLHandler getHandler(int num) {
989f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (num < handlerList.size()) {
990f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return handlerList.get(num);
991f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
992f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        makeNewHandler();
993f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (num < handlerList.size()) {
994f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return handlerList.get(num);
995f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
996f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return null;
997f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
998f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
999f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private synchronized void makeNewHandler() {
1000f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        while (!searchList.isEmpty()) {
1001f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL nextCandidate = searchList.remove(0);
1002b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            if (nextCandidate == null) {
1003b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new NullPointerException("A URL is null");
1004f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
1005f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (!handlerMap.containsKey(nextCandidate)) {
1006f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                URLHandler result;
1007f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                String protocol = nextCandidate.getProtocol();
1008f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                if (protocol.equals("jar")) {
1009f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    result = createURLJarHandler(nextCandidate);
1010f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                } else if (protocol.equals("file")) {
1011f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    result = createURLFileHandler(nextCandidate);
1012f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                } else {
1013f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    result = createURLHandler(nextCandidate);
1014f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
1015f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (result != null) {
1016f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    handlerMap.put(nextCandidate, result);
1017f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    handlerList.add(result);
1018f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    return;
1019f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
1020f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
1021f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
1022f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
1023adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1024f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private URLHandler createURLHandler(URL url) {
1025f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return new URLHandler(url);
1026f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
1027f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
1028f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private URLHandler createURLFileHandler(URL url) {
1029f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return new URLFileHandler(url);
1030f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
1031f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
1032f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private URLHandler createURLJarHandler(URL url) {
1033f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        String prefixName;
1034f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        String file = url.getFile();
1035f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        if (url.getFile().endsWith("!/")) {
1036f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            prefixName = "";
1037f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        } else {
1038f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            int sepIdx = file.lastIndexOf("!/");
1039f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (sepIdx == -1) {
1040f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // Invalid URL, don't look here again
1041f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return null;
1042f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
1043f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            sepIdx += 2;
1044f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            prefixName = file.substring(sepIdx);
1045f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
1046f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        try {
1047f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URL jarURL = ((JarURLConnection) url
1048f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    .openConnection()).getJarFileURL();
1049f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            JarURLConnection juc = (JarURLConnection) new URL(
1050f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    "jar", "",
1051f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    jarURL.toExternalForm() + "!/").openConnection();
1052f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            JarFile jf = juc.getJarFile();
1053f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URLJarHandler jarH = new URLJarHandler(url, jarURL, jf, prefixName);
1054f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
1055f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (jarH.getIndex() == null) {
1056f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                try {
1057f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    Manifest manifest = jf.getManifest();
1058f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (manifest != null) {
1059f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        String classpath = manifest.getMainAttributes().getValue(
1060f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                Attributes.Name.CLASS_PATH);
1061f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        if (classpath != null) {
1062f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            searchList.addAll(0, getInternalURLs(url, classpath));
1063adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
1064adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
1065adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (IOException e) {
1066adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
1067adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1068f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return jarH;
1069f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        } catch (IOException e) {
1070adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1071adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
1072adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1073adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1074adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1075adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Defines a new package using the information extracted from the specified
1076adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * manifest.
1077f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
1078adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param packageName
1079adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the new package.
1080adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param manifest
1081adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the manifest containing additional information for the new
1082adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            package.
1083adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param url
1084adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the URL to the code source for the new package.
1085adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the created package.
1086adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
1087adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if a package with the given name already exists.
1088adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1089adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected Package definePackage(String packageName, Manifest manifest,
1090f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                    URL url) throws IllegalArgumentException {
1091adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Attributes mainAttributes = manifest.getMainAttributes();
1092f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        String dirName = packageName.replace('.', '/') + "/";
1093adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Attributes packageAttributes = manifest.getAttributes(dirName);
1094adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean noEntry = false;
1095adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (packageAttributes == null) {
1096adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            noEntry = true;
1097adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            packageAttributes = mainAttributes;
1098adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1099adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String specificationTitle = packageAttributes
1100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .getValue(Attributes.Name.SPECIFICATION_TITLE);
1101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (specificationTitle == null && !noEntry) {
1102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            specificationTitle = mainAttributes
1103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getValue(Attributes.Name.SPECIFICATION_TITLE);
1104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String specificationVersion = packageAttributes
1106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .getValue(Attributes.Name.SPECIFICATION_VERSION);
1107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (specificationVersion == null && !noEntry) {
1108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            specificationVersion = mainAttributes
1109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getValue(Attributes.Name.SPECIFICATION_VERSION);
1110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String specificationVendor = packageAttributes
1112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .getValue(Attributes.Name.SPECIFICATION_VENDOR);
1113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (specificationVendor == null && !noEntry) {
1114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            specificationVendor = mainAttributes
1115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getValue(Attributes.Name.SPECIFICATION_VENDOR);
1116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String implementationTitle = packageAttributes
1118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .getValue(Attributes.Name.IMPLEMENTATION_TITLE);
1119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (implementationTitle == null && !noEntry) {
1120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            implementationTitle = mainAttributes
1121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getValue(Attributes.Name.IMPLEMENTATION_TITLE);
1122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String implementationVersion = packageAttributes
1124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .getValue(Attributes.Name.IMPLEMENTATION_VERSION);
1125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (implementationVersion == null && !noEntry) {
1126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            implementationVersion = mainAttributes
1127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getValue(Attributes.Name.IMPLEMENTATION_VERSION);
1128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String implementationVendor = packageAttributes
1130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
1131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (implementationVendor == null && !noEntry) {
1132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            implementationVendor = mainAttributes
1133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
1134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return definePackage(packageName, specificationTitle,
1137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                specificationVersion, specificationVendor, implementationTitle,
1138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                implementationVersion, implementationVendor, isSealed(manifest,
1139f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                dirName) ? url : null);
1140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean isSealed(Manifest manifest, String dirName) {
1143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Attributes mainAttributes = manifest.getMainAttributes();
1144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String value = mainAttributes.getValue(Attributes.Name.SEALED);
1145f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        boolean sealed = value != null && value.toLowerCase().equals("true");
1146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Attributes attributes = manifest.getAttributes(dirName);
1147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (attributes != null) {
1148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            value = attributes.getValue(Attributes.Name.SEALED);
1149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (value != null) {
1150f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                sealed = value.toLowerCase().equals("true");
1151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sealed;
1154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * returns URLs referenced in the string classpath.
1158f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
1159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param root
1160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the jar URL that classpath is related to
1161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param classpath
1162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the relative URLs separated by spaces
1163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return URL[] the URLs contained in the string classpath.
1164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1165f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private ArrayList<URL> getInternalURLs(URL root, String classpath) {
1166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Class-path attribute is composed of space-separated values.
11675839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson        StringTokenizer tokenizer = new StringTokenizer(classpath);
1168f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        ArrayList<URL> addedURLs = new ArrayList<URL>();
1169f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        String file = root.getFile();
1170f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        int jarIndex = file.lastIndexOf("!/") - 1;
1171f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        int index = file.lastIndexOf("/", jarIndex) + 1;
1172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (index == 0) {
1173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            index = file.lastIndexOf(
1174f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    System.getProperty("file.separator"), jarIndex) + 1;
1175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        file = file.substring(0, index);
1177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (tokenizer.hasMoreElements()) {
1178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String element = tokenizer.nextToken();
117980a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            if (!element.isEmpty()) {
1180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
1181a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson                    // Take absolute path case into consideration
1182a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson                    URL url = new URL(new URL(file), element);
1183a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson                    addedURLs.add(createSearchURL(url));
1184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (MalformedURLException e) {
1185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Nothing is added
1186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
1187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1189f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return addedURLs;
1190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1192f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    Class<?> findClassImpl(String className) {
1193f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        String partialName = className.replace('.', '/');
1194f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        final String classFileName = new StringBuilder(partialName).append(".class").toString();
1195f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        String packageName = null;
1196f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        int position = partialName.lastIndexOf('/');
1197f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if ((position = partialName.lastIndexOf('/')) != -1) {
1198f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            packageName = partialName.substring(0, position);
1199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1200f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        int n = 0;
1201f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        while (true) {
1202f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            URLHandler handler = getHandler(n++);
1203f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (handler == null) {
1204f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                break;
1205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1206f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            Class<?> res = handler.findClass(packageName, classFileName, className);
1207f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (res != null) {
1208f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return res;
1209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1211f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return null;
1212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1214f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
1215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
1216