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.File; 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileInputStream; 23f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.FileNotFoundException; 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FilePermission; 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 27f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.InputStreamReader; 28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.UnsupportedEncodingException; 296aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughesimport java.nio.charset.Charsets; 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.CodeSource; 31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PermissionCollection; 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.SecureClassLoader; 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.cert.Certificate; 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList; 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collections; 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Enumeration; 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap; 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.List; 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Map; 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.StringTokenizer; 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.Attributes; 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.JarEntry; 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.JarFile; 44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.Manifest; 45a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilsonimport libcore.io.IoUtils; 46244449b9ccd108197d1c117edda99cd93a891d49Elliott Hughesimport libcore.io.Streams; 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class loader is responsible for loading classes and resources from a 50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * list of URLs which can refer to either directories or JAR files. Classes 51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * loaded by this {@code URLClassLoader} are granted permission to access the 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * URLs contained in the URL search list. 53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 540d4daefcf389b6433a0af481ef44a84a2546541aElliott Hughes@FindBugsSuppressWarnings({ "DMI_COLLECTION_OF_URLS", "DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED" }) 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class URLClassLoader extends SecureClassLoader { 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 57f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> originalUrls; 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 59f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson List<URL> searchList; 60f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URLHandler> handlerList; 61f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Map<URL, URLHandler> handlerMap = new HashMap<URL, URLHandler>(); 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private URLStreamHandlerFactory factory; 64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 65f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson static class IndexFile { 66f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 67f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private HashMap<String, ArrayList<URL>> map; 68f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson //private URLClassLoader host; 69f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 70f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 71f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson static IndexFile readIndexFile(JarFile jf, JarEntry indexEntry, URL url) { 72f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson BufferedReader in = null; 73f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson InputStream is = null; 74f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 75f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Add mappings from resource to jar file 76f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String parentURLString = getParentURL(url).toExternalForm(); 776aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes String prefix = "jar:" + parentURLString + "/"; 78f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson is = jf.getInputStream(indexEntry); 796aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes in = new BufferedReader(new InputStreamReader(is, Charsets.UTF_8)); 80f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson HashMap<String, ArrayList<URL>> pre_map = new HashMap<String, ArrayList<URL>>(); 81f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Ignore the 2 first lines (index version) 82f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (in.readLine() == null) return null; 83f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (in.readLine() == null) return null; 84f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson TOP_CYCLE: 85f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (true) { 86f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String line = in.readLine(); 87f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (line == null) { 88f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break; 89f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 90f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes URL jar = new URL(prefix + line + "!/"); 91f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (true) { 92f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson line = in.readLine(); 93f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (line == null) { 94f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break TOP_CYCLE; 95f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 9680a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes if (line.isEmpty()) { 97f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break; 98f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 99f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> list; 100f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (pre_map.containsKey(line)) { 101f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson list = pre_map.get(line); 102f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 103f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson list = new ArrayList<URL>(); 104f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson pre_map.put(line, list); 105f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 106f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson list.add(jar); 107f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 108f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 109f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (!pre_map.isEmpty()) { 110f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return new IndexFile(pre_map); 111f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 112f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (MalformedURLException e) { 113f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Ignore this jar's index 114f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 115f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Ignore this jar's index 116a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson } finally { 117a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson IoUtils.closeQuietly(in); 118a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson IoUtils.closeQuietly(is); 119f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 120f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 121f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 122f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 123f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private static URL getParentURL(URL url) throws IOException { 124f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL fileURL = ((JarURLConnection) url.openConnection()).getJarFileURL(); 125f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String file = fileURL.getFile(); 126f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String parentFile = new File(file).getParent(); 127f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson parentFile = parentFile.replace(File.separatorChar, '/'); 128f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (parentFile.charAt(0) != '/') { 129f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes parentFile = "/" + parentFile; 130f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 131f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL parentURL = new URL(fileURL.getProtocol(), fileURL 132f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson .getHost(), fileURL.getPort(), parentFile); 133f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return parentURL; 134f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 135f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 136f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public IndexFile(HashMap<String, ArrayList<URL>> map) { 137f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.map = map; 138f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 139f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 140f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> get(String name) { 141f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return map.get(name); 142f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 143f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 144f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 145f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson class URLHandler { 146f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL url; 147f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL codeSourceUrl; 148f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 149f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public URLHandler(URL url) { 150f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.url = url; 151f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.codeSourceUrl = url; 152f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 153f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 154f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson void findResources(String name, ArrayList<URL> resources) { 155f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL res = findResource(name); 156f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null && !resources.contains(res)) { 157f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson resources.add(res); 158f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 159f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 160f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 161f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> findClass(String packageName, String name, String origName) { 162f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL resURL = targetURL(url, name); 163f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (resURL != null) { 164f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 165f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson InputStream is = resURL.openStream(); 166f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return createClass(is, packageName, origName); 167f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 168f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 169f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 170f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 171f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 172f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 173f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 174f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> createClass(InputStream is, String packageName, String origName) { 175f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (is == null) { 176f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 177f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 178f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson byte[] clBuf; 179f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 180f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson clBuf = Streams.readFully(is); 181f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 182f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 183f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 184f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageName != null) { 185f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String packageDotName = packageName.replace('/', '.'); 186f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Package packageObj = getPackage(packageDotName); 187f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageObj == null) { 188f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson definePackage(packageDotName, null, null, 189f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson null, null, null, null, null); 190f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 191f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageObj.isSealed()) { 192b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes throw new SecurityException("Package is sealed"); 193f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 194f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 195f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 196f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return defineClass(origName, clBuf, 0, clBuf.length, new CodeSource(codeSourceUrl, (Certificate[]) null)); 197f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 198f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 199f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL findResource(String name) { 200f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL resURL = targetURL(url, name); 201f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (resURL != null) { 202f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 203f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLConnection uc = resURL.openConnection(); 204f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson uc.getInputStream().close(); 205f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // HTTP can return a stream on a non-existent file 206f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // So check for the return code; 207f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (!resURL.getProtocol().equals("http")) { 208f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return resURL; 209f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 210f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int code; 211f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if ((code = ((HttpURLConnection) uc).getResponseCode()) >= 200 212f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson && code < 300) { 213f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return resURL; 214f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 215f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (SecurityException e) { 216f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 217f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 218f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 219f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 220f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 221f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 222f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 223f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 224f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL targetURL(URL base, String name) { 225f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 22656099d23fcb002b164bff8fb7f14d6ec0453509eJesse Wilson StringBuilder fileBuilder = new StringBuilder(); 22756099d23fcb002b164bff8fb7f14d6ec0453509eJesse Wilson fileBuilder.append(base.getFile()); 22856099d23fcb002b164bff8fb7f14d6ec0453509eJesse Wilson URI.PATH_ENCODER.appendEncoded(fileBuilder, name); 22956099d23fcb002b164bff8fb7f14d6ec0453509eJesse Wilson String file = fileBuilder.toString(); 230f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 23156099d23fcb002b164bff8fb7f14d6ec0453509eJesse Wilson return new URL(base.getProtocol(), base.getHost(), base.getPort(), file, null); 232f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (MalformedURLException e) { 233f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 234f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 235f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 236f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 237f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 238f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 239f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson class URLJarHandler extends URLHandler { 240f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final JarFile jf; 241f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final String prefixName; 242f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final IndexFile index; 243f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final Map<URL, URLHandler> subHandlers = new HashMap<URL, URLHandler>(); 244f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 245f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public URLJarHandler(URL url, URL jarURL, JarFile jf, String prefixName) { 246f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson super(url); 247f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.jf = jf; 248f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.prefixName = prefixName; 249f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.codeSourceUrl = jarURL; 250f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes final JarEntry je = jf.getJarEntry("META-INF/INDEX.LIST"); 251f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.index = (je == null ? null : IndexFile.readIndexFile(jf, je, url)); 252f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 253f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 254f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public URLJarHandler(URL url, URL jarURL, JarFile jf, String prefixName, IndexFile index) { 255f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson super(url); 256f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.jf = jf; 257f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.prefixName = prefixName; 258f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.index = index; 259f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.codeSourceUrl = jarURL; 260f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 261f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 262f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson IndexFile getIndex() { 263f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return index; 264f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 265f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 266f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 267f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson void findResources(String name, ArrayList<URL> resources) { 268f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL res = findResourceInOwn(name); 269f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null && !resources.contains(res)) { 270f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson resources.add(res); 271f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 272f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (index != null) { 273f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int pos = name.lastIndexOf("/"); 274f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // only keep the directory part of the resource 275f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // as index.list only keeps track of directories and root files 276f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String indexedName = (pos > 0) ? name.substring(0, pos) : name; 277f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> urls = index.get(indexedName); 278f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (urls != null) { 279f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls.remove(url); 280f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson for (URL url : urls) { 281f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler h = getSubHandler(url); 282f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (h != null) { 283f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson h.findResources(name, resources); 284f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 285f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 286f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 287f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 288f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 289f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 290f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 291f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 292f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> findClass(String packageName, String name, String origName) { 293f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String entryName = prefixName + name; 294f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarEntry entry = jf.getJarEntry(entryName); 295f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (entry != null) { 296f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson /** 297f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * Avoid recursive load class, especially the class 298f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * is an implementation class of security provider 299f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * and the jar is signed. 300f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson */ 301f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 302f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Manifest manifest = jf.getManifest(); 303f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return createClass(entry, manifest, packageName, origName); 304f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 305f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 306f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 307f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (index != null) { 308f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> urls; 309f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageName == null) { 310f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls = index.get(name); 311f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 312f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls = index.get(packageName); 313f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 314f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (urls != null) { 315f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls.remove(url); 316f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson for (URL url : urls) { 317f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler h = getSubHandler(url); 318f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (h != null) { 319f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> res = h.findClass(packageName, name, origName); 320f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null) { 321f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return res; 322f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 323f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 324f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 325f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 326f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 327f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 328f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 329f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 330f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private Class<?> createClass(JarEntry entry, Manifest manifest, String packageName, String origName) { 331f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson byte[] clBuf; 332f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 333f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson InputStream is = jf.getInputStream(entry); 334f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson clBuf = Streams.readFully(is); 335f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 336f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 337f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 338f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageName != null) { 339f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String packageDotName = packageName.replace('/', '.'); 340f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Package packageObj = getPackage(packageDotName); 341f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageObj == null) { 342f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (manifest != null) { 343f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson definePackage(packageDotName, manifest, 344f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson codeSourceUrl); 345f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 346f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson definePackage(packageDotName, null, null, 347f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson null, null, null, null, null); 348f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 349f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 350f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson boolean exception = packageObj.isSealed(); 351f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (manifest != null) { 352f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (isSealed(manifest, packageName + "/")) { 353f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson exception = !packageObj 354f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson .isSealed(codeSourceUrl); 355f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 356f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 357f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (exception) { 358b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes throw new SecurityException(String.format("Package %s is sealed", 359b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes packageName)); 360f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 361f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 362f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 363f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson CodeSource codeS = new CodeSource(codeSourceUrl, entry.getCertificates()); 364f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return defineClass(origName, clBuf, 0, clBuf.length, codeS); 365f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 366f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 367f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL findResourceInOwn(String name) { 368f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String entryName = prefixName + name; 369f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (jf.getEntry(entryName) != null) { 370f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return targetURL(url, name); 371f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 372f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 373f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 374f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 375f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 376f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL findResource(String name) { 377f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL res = findResourceInOwn(name); 378f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null) { 379f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return res; 380f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 381f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (index != null) { 382f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int pos = name.lastIndexOf("/"); 383f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // only keep the directory part of the resource 384f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // as index.list only keeps track of directories and root files 385f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String indexedName = (pos > 0) ? name.substring(0, pos) : name; 386f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> urls = index.get(indexedName); 387f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (urls != null) { 388f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls.remove(url); 389f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson for (URL url : urls) { 390f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler h = getSubHandler(url); 391f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (h != null) { 392f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson res = h.findResource(name); 393f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null) { 394f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return res; 395f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 396f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 397f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 398f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 399f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 400f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 401f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 402f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 403f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private synchronized URLHandler getSubHandler(URL url) { 404f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler sub = subHandlers.get(url); 405f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (sub != null) { 406f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return sub; 407f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 408f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String protocol = url.getProtocol(); 409f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (protocol.equals("jar")) { 410f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sub = createURLJarHandler(url); 411f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } else if (protocol.equals("file")) { 412f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sub = createURLSubJarHandler(url); 413f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 414f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sub = createURLHandler(url); 415f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 416f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (sub != null) { 417f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson subHandlers.put(url, sub); 418f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 419f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return sub; 420f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 421f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 422f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private URLHandler createURLSubJarHandler(URL url) { 423f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String prefixName; 424f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String file = url.getFile(); 425f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (url.getFile().endsWith("!/")) { 426f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefixName = ""; 427f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 428f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int sepIdx = file.lastIndexOf("!/"); 429f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (sepIdx == -1) { 430f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Invalid URL, don't look here again 431f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 432f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 433f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sepIdx += 2; 434f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefixName = file.substring(sepIdx); 435f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 436f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 437f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL jarURL = ((JarURLConnection) url 438f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson .openConnection()).getJarFileURL(); 439f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarURLConnection juc = (JarURLConnection) new URL( 440f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes "jar", "", 441f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes jarURL.toExternalForm() + "!/").openConnection(); 442f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarFile jf = juc.getJarFile(); 443f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLJarHandler jarH = new URLJarHandler(url, jarURL, jf, prefixName, null); 444f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // TODO : to think what we should do with indexes & manifest.class file here 445f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return jarH; 446f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 447f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 448f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 449f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 450f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 451f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 452f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 453f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson class URLFileHandler extends URLHandler { 454f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private String prefix; 455f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 456f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public URLFileHandler(URL url) { 457f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson super(url); 458f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String baseFile = url.getFile(); 459f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String host = url.getHost(); 460f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int hostLength = 0; 461f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (host != null) { 462f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson hostLength = host.length(); 463f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 464f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson StringBuilder buf = new StringBuilder(2 + hostLength 465f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson + baseFile.length()); 466f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (hostLength > 0) { 467f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes buf.append("//").append(host); 468f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 469f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // baseFile always ends with '/' 470f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson buf.append(baseFile); 471f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefix = buf.toString(); 472f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 473f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 474f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 475f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> findClass(String packageName, String name, String origName) { 476f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String filename = prefix + name; 477f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 478f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes filename = URLDecoder.decode(filename, "UTF-8"); 479f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IllegalArgumentException e) { 480f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 481f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (UnsupportedEncodingException e) { 482f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 483f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 484f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 485f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson File file = new File(filename); 486f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (file.exists()) { 487f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 488f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson InputStream is = new FileInputStream(file); 489f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return createClass(is, packageName, origName); 490f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (FileNotFoundException e) { 491f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 492f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 493f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 494f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 495f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 496f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 497f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL findResource(String name) { 498f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int idx = 0; 499f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String filename; 500f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 501f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Do not create a UNC path, i.e. \\host 502f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (idx < name.length() && 503f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ((name.charAt(idx) == '/') || (name.charAt(idx) == '\\'))) { 504f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson idx++; 505f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 506f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 507f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (idx > 0) { 508f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson name = name.substring(idx); 509f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 510f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 511f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 512f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes filename = URLDecoder.decode(prefix, "UTF-8") + name; 513f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 514f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (new File(filename).exists()) { 515f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return targetURL(url, name); 516f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 517f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 518f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IllegalArgumentException e) { 519f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 520f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (UnsupportedEncodingException e) { 521f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // must not happen 522f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson throw new AssertionError(e); 523f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 524f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 525f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 526f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 527f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 528f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs a new {@code URLClassLoader} instance. The newly created 531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * instance will have the system ClassLoader as its parent. URLs that end 532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * with "/" are assumed to be directories, otherwise they are assumed to be 533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * JAR files. 534f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param urls 536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the list of URLs where a specific class or file could be 537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * found. 538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URLClassLoader(URL[] urls) { 540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(urls, ClassLoader.getSystemClassLoader(), null); 541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs a new URLClassLoader instance. The newly created instance will 545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * have the system ClassLoader as its parent. URLs that end with "/" are 546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * assumed to be directories, otherwise they are assumed to be JAR files. 547f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param urls 549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the list of URLs where a specific class or file could be 550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * found. 551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param parent 552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the class loader to assign as this loader's parent. 553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URLClassLoader(URL[] urls, ClassLoader parent) { 555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(urls, parent, null); 556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Adds the specified URL to the search list. 560f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param url 562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the URL which is to add. 563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected void addURL(URL url) { 565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 566f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson originalUrls.add(url); 567f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson searchList.add(createSearchURL(url)); 568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (MalformedURLException e) { 569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns all known URLs which point to the specified resource. 574f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param name 576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the requested resource. 577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the enumeration of URLs which point to the specified resource. 578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an I/O error occurs while attempting to connect. 580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Enumeration<URL> findResources(final String name) throws IOException { 583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (name == null) { 584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 586ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes ArrayList<URL> result = new ArrayList<URL>(); 587f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int n = 0; 588f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (true) { 589f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler handler = getHandler(n++); 590f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (handler == null) { 591f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break; 592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 593f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson handler.findResources(name, result); 594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 595ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes return Collections.enumeration(result); 596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Gets all permissions for the specified {@code codesource}. First, this 600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * method retrieves the permissions from the system policy. If the protocol 601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * is "file:/" then a new permission, {@code FilePermission}, granting the 602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * read permission to the file is added to the permission collection. 603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Otherwise, connecting to and accepting connections from the URL is 604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * granted. 605f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param codesource 607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the code source object whose permissions have to be known. 608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the list of permissions according to the code source object. 609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected PermissionCollection getPermissions(final CodeSource codesource) { 612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project PermissionCollection pc = super.getPermissions(codesource); 613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project URL u = codesource.getLocation(); 614f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (u.getProtocol().equals("jar")) { 615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Create a URL for the resource the jar refers to 617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project u = ((JarURLConnection) u.openConnection()).getJarFileURL(); 618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (IOException e) { 619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // This should never occur. If it does continue using the jar 620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // URL 621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 623f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (u.getProtocol().equals("file")) { 624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String path = u.getFile(); 625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String host = u.getHost(); 626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (host != null && host.length() > 0) { 627f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes path = "//" + host + path; 628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (File.separatorChar != '/') { 631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project path = path.replace('/', File.separatorChar); 632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (isDirectory(u)) { 634f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes pc.add(new FilePermission(path + "-", "read")); 635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 636f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes pc.add(new FilePermission(path, "read")); 637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String host = u.getHost(); 640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (host.length() == 0) { 641f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes host = "localhost"; 642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 643f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes pc.add(new SocketPermission(host, "connect, accept")); 644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return pc; 646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the search list of this {@code URLClassLoader}. 650f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the list of all known URLs of this instance. 652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URL[] getURLs() { 654f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return originalUrls.toArray(new URL[originalUrls.size()]); 655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Determines if the URL is pointing to a directory. 659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private static boolean isDirectory(URL url) { 661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String file = url.getFile(); 662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return (file.length() > 0 && file.charAt(file.length() - 1) == '/'); 663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns a new {@code URLClassLoader} instance for the given URLs and the 667ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes * system {@code ClassLoader} as its parent. 668f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param urls 670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the list of URLs that is passed to the new {@code 671ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes * URLClassLoader}. 672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the created {@code URLClassLoader} instance. 673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public static URLClassLoader newInstance(final URL[] urls) { 675ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes return new URLClassLoader(urls, ClassLoader.getSystemClassLoader()); 676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns a new {@code URLClassLoader} instance for the given URLs and the 680ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes * specified {@code ClassLoader} as its parent. 681f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param urls 683ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes * the list of URLs that is passed to the new URLClassLoader. 684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param parentCl 685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the parent class loader that is passed to the new 686ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes * URLClassLoader. 687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the created {@code URLClassLoader} instance. 688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 689ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes public static URLClassLoader newInstance(final URL[] urls, final ClassLoader parentCl) { 690ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes return new URLClassLoader(urls, parentCl); 691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs a new {@code URLClassLoader} instance. The newly created 695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * instance will have the specified {@code ClassLoader} as its parent and 696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * use the specified factory to create stream handlers. URLs that end with 697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * "/" are assumed to be directories, otherwise they are assumed to be JAR 698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * files. 699f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param searchUrls 701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the list of URLs where a specific class or file could be 702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * found. 703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param parent 704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the {@code ClassLoader} to assign as this loader's parent. 705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param factory 706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the factory that will be used to create protocol-specific 707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * stream handlers. 708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 709ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes public URLClassLoader(URL[] searchUrls, ClassLoader parent, URLStreamHandlerFactory factory) { 710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(parent); 711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this.factory = factory; 712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int nbUrls = searchUrls.length; 713f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson originalUrls = new ArrayList<URL>(nbUrls); 714f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson handlerList = new ArrayList<URLHandler>(nbUrls); 715f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson searchList = Collections.synchronizedList(new ArrayList<URL>(nbUrls)); 716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (int i = 0; i < nbUrls; i++) { 717f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson originalUrls.add(searchUrls[i]); 718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 719f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson searchList.add(createSearchURL(searchUrls[i])); 720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (MalformedURLException e) { 721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Tries to locate and load the specified class using the known URLs. If the 727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * class could be found, a class object representing the loaded class will 728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * be returned. 729f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws ClassNotFoundException 731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the specified class cannot be loaded. 732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 73487548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes protected Class<?> findClass(final String className) throws ClassNotFoundException { 73587548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes String partialName = className.replace('.', '/'); 73687548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes final String classFileName = new StringBuilder(partialName).append(".class").toString(); 73787548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes String packageName = null; 73887548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes int position = partialName.lastIndexOf('/'); 73987548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes if ((position = partialName.lastIndexOf('/')) != -1) { 74087548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes packageName = partialName.substring(0, position); 741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 74287548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes int n = 0; 74387548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes while (true) { 74487548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes URLHandler handler = getHandler(n++); 74587548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes if (handler == null) { 74687548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes break; 74787548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes } 74887548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes Class<?> res = handler.findClass(packageName, classFileName, className); 74987548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes if (res != null) { 75087548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes return res; 75187548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes } 75287548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes } 75387548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes throw new ClassNotFoundException(className); 754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns an URL that will be checked if it contains the class or resource. 758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If the file component of the URL is not a directory, a Jar URL will be 759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * created. 760f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return java.net.URL a test URL 762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private URL createSearchURL(URL url) throws MalformedURLException { 764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (url == null) { 765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return url; 766adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 768adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String protocol = url.getProtocol(); 769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 770f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (isDirectory(url) || protocol.equals("jar")) { 771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return url; 772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (factory == null) { 774f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes return new URL("jar", "", 775f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes -1, url.toString() + "!/"); 776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 777f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // use jar protocol as the stream handler protocol 778f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes return new URL("jar", "", 779f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes -1, url.toString() + "!/", 780fd6bb3510c2f94d636f3572dcf5f7f4dcd1a2726Elliott Hughes factory.createURLStreamHandler("jar")); 781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns an URL referencing the specified resource or {@code null} if the 785adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * resource could not be found. 786f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param name 788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the requested resource. 789adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the URL which points to the given resource. 790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URL findResource(final String name) { 793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (name == null) { 794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 796f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int n = 0; 797f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (true) { 798f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler handler = getHandler(n++); 799f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (handler == null) { 800f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break; 801f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 80287548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes URL res = handler.findResource(name); 803f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null) { 804f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return res; 805f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 806f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 807f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 808f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 809f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 81087548e8585334658c3ee89050ec917a10ca35e5aElliott Hughes private URLHandler getHandler(int num) { 811f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (num < handlerList.size()) { 812f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return handlerList.get(num); 813f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 814f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson makeNewHandler(); 815f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (num < handlerList.size()) { 816f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return handlerList.get(num); 817f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 818f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 819f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 820f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 821f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private synchronized void makeNewHandler() { 822f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (!searchList.isEmpty()) { 823f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL nextCandidate = searchList.remove(0); 824b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes if (nextCandidate == null) { 82586acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("nextCandidate == null"); 826f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 827f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (!handlerMap.containsKey(nextCandidate)) { 828f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler result; 829f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String protocol = nextCandidate.getProtocol(); 830f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (protocol.equals("jar")) { 831f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson result = createURLJarHandler(nextCandidate); 832f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } else if (protocol.equals("file")) { 833f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson result = createURLFileHandler(nextCandidate); 834f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 835f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson result = createURLHandler(nextCandidate); 836f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 837f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (result != null) { 838f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson handlerMap.put(nextCandidate, result); 839f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson handlerList.add(result); 840f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return; 841f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 842f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 843f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 844f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 845adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 846f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private URLHandler createURLHandler(URL url) { 847f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return new URLHandler(url); 848f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 849f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 850f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private URLHandler createURLFileHandler(URL url) { 851f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return new URLFileHandler(url); 852f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 853f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 854f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private URLHandler createURLJarHandler(URL url) { 855f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String prefixName; 856f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String file = url.getFile(); 857f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (url.getFile().endsWith("!/")) { 858f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefixName = ""; 859f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 860f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int sepIdx = file.lastIndexOf("!/"); 861f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (sepIdx == -1) { 862f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Invalid URL, don't look here again 863f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 864f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 865f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sepIdx += 2; 866f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefixName = file.substring(sepIdx); 867f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 868f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 869f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL jarURL = ((JarURLConnection) url 870f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson .openConnection()).getJarFileURL(); 871f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarURLConnection juc = (JarURLConnection) new URL( 872f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes "jar", "", 873f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes jarURL.toExternalForm() + "!/").openConnection(); 874f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarFile jf = juc.getJarFile(); 875f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLJarHandler jarH = new URLJarHandler(url, jarURL, jf, prefixName); 876f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 877f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (jarH.getIndex() == null) { 878f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 879f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Manifest manifest = jf.getManifest(); 880f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (manifest != null) { 881f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String classpath = manifest.getMainAttributes().getValue( 882f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Attributes.Name.CLASS_PATH); 883f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (classpath != null) { 884f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson searchList.addAll(0, getInternalURLs(url, classpath)); 885adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 886adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 887adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (IOException e) { 888adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 889adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 890f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return jarH; 891f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 892adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 893adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 894adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 895adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 896adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 897adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Defines a new package using the information extracted from the specified 898adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * manifest. 899f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 900adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param packageName 901adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the new package. 902adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param manifest 903adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the manifest containing additional information for the new 904adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * package. 905adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param url 906adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the URL to the code source for the new package. 907adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the created package. 908adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IllegalArgumentException 909adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if a package with the given name already exists. 910adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 911adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected Package definePackage(String packageName, Manifest manifest, 912f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL url) throws IllegalArgumentException { 913adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes mainAttributes = manifest.getMainAttributes(); 914f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes String dirName = packageName.replace('.', '/') + "/"; 915adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes packageAttributes = manifest.getAttributes(dirName); 916adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project boolean noEntry = false; 917adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (packageAttributes == null) { 918adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project noEntry = true; 919adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project packageAttributes = mainAttributes; 920adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 921adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String specificationTitle = packageAttributes 922adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_TITLE); 923adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (specificationTitle == null && !noEntry) { 924adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project specificationTitle = mainAttributes 925adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_TITLE); 926adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 927adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String specificationVersion = packageAttributes 928adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_VERSION); 929adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (specificationVersion == null && !noEntry) { 930adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project specificationVersion = mainAttributes 931adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_VERSION); 932adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 933adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String specificationVendor = packageAttributes 934adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_VENDOR); 935adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (specificationVendor == null && !noEntry) { 936adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project specificationVendor = mainAttributes 937adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_VENDOR); 938adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 939adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String implementationTitle = packageAttributes 940adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_TITLE); 941adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (implementationTitle == null && !noEntry) { 942adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project implementationTitle = mainAttributes 943adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_TITLE); 944adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 945adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String implementationVersion = packageAttributes 946adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_VERSION); 947adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (implementationVersion == null && !noEntry) { 948adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project implementationVersion = mainAttributes 949adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_VERSION); 950adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 951adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String implementationVendor = packageAttributes 952adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 953adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (implementationVendor == null && !noEntry) { 954adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project implementationVendor = mainAttributes 955adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 956adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 957adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 958adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return definePackage(packageName, specificationTitle, 959adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project specificationVersion, specificationVendor, implementationTitle, 960adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project implementationVersion, implementationVendor, isSealed(manifest, 961f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson dirName) ? url : null); 962adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 963adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 964adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private boolean isSealed(Manifest manifest, String dirName) { 965adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes attributes = manifest.getAttributes(dirName); 966adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (attributes != null) { 96778e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes String value = attributes.getValue(Attributes.Name.SEALED); 968adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (value != null) { 96978e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes return value.equalsIgnoreCase("true"); 970adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 971adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 97278e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes Attributes mainAttributes = manifest.getMainAttributes(); 97378e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes String value = mainAttributes.getValue(Attributes.Name.SEALED); 97478e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes return (value != null && value.equalsIgnoreCase("true")); 975adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 976adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 977adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 978adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * returns URLs referenced in the string classpath. 979f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 980adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param root 981adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the jar URL that classpath is related to 982adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param classpath 983adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the relative URLs separated by spaces 984adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return URL[] the URLs contained in the string classpath. 985adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 986f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private ArrayList<URL> getInternalURLs(URL root, String classpath) { 987adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Class-path attribute is composed of space-separated values. 9885839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson StringTokenizer tokenizer = new StringTokenizer(classpath); 989f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> addedURLs = new ArrayList<URL>(); 990f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String file = root.getFile(); 991f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int jarIndex = file.lastIndexOf("!/") - 1; 992f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int index = file.lastIndexOf("/", jarIndex) + 1; 993adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (index == 0) { 994adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project index = file.lastIndexOf( 995f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes System.getProperty("file.separator"), jarIndex) + 1; 996adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 997adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project file = file.substring(0, index); 998adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (tokenizer.hasMoreElements()) { 999adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String element = tokenizer.nextToken(); 100080a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes if (!element.isEmpty()) { 1001adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 1002a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson // Take absolute path case into consideration 1003a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson URL url = new URL(new URL(file), element); 1004a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson addedURLs.add(createSearchURL(url)); 1005adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (MalformedURLException e) { 1006adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Nothing is added 1007adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1008adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1009adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1010f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return addedURLs; 1011adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1012adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 1013