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