1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html#License
3 /*
4  ******************************************************************************
5  * Copyright (C) 2005-2015, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ******************************************************************************
8  */
9 
10 package com.ibm.icu.impl;
11 
12 import java.io.BufferedReader;
13 import java.io.File;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.InputStreamReader;
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.net.JarURLConnection;
20 import java.net.URISyntaxException;
21 import java.net.URL;
22 import java.util.Enumeration;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.jar.JarEntry;
26 import java.util.jar.JarFile;
27 
28 public abstract class URLHandler {
29     public static final String PROPNAME = "urlhandler.props";
30 
31     private static final Map<String, Method> handlers;
32 
33     private static final boolean DEBUG = ICUDebug.enabled("URLHandler");
34 
35     static {
36         Map<String, Method> h = null;
37 
38         BufferedReader br = null;
39         try {
40             @SuppressWarnings("resource")  // Closed by BufferedReader.
41             ClassLoader loader = ClassLoaderUtil.getClassLoader(URLHandler.class);
42             InputStream is = loader.getResourceAsStream(PROPNAME);
43 
44             if (is != null) {
45                 Class<?>[] params = { URL.class };
46                 br = new BufferedReader(new InputStreamReader(is));
47 
48                 for (String line = br.readLine(); line != null; line = br.readLine()) {
49                     line = line.trim();
50 
51                     if (line.length() == 0 || line.charAt(0) == '#') {
52                         continue;
53                     }
54 
55                     int ix = line.indexOf('=');
56 
57                     if (ix == -1) {
58                         if (DEBUG) System.err.println("bad urlhandler line: '" + line + "'");
59                         break;
60                     }
61 
62                     String key = line.substring(0, ix).trim();
63                     String value = line.substring(ix+1).trim();
64 
65                     try {
66                         Class<?> cl = Class.forName(value);
67                         Method m = cl.getDeclaredMethod("get", params);
68 
69                         if (h == null) {
70                             h = new HashMap<String, Method>();
71                         }
72 
h.put(key, m)73                         h.put(key, m);
74                     }
75                     catch (ClassNotFoundException e) {
76                         if (DEBUG) System.err.println(e);
77                     }
78                     catch(NoSuchMethodException e) {
79                         if (DEBUG) System.err.println(e);
80                     }
81                     catch(SecurityException e) {
82                         if (DEBUG) System.err.println(e);
83                     }
84                 }
br.close()85                 br.close();
86             }
87         } catch (Throwable t) {
88             if (DEBUG) System.err.println(t);
89         } finally {
90             if (br != null) {
91                 try {
br.close()92                     br.close();
93                 } catch (IOException ignored) {
94                 }
95             }
96         }
97 
98         handlers = h;
99     }
100 
get(URL url)101     public static URLHandler get(URL url) {
102         if (url == null) {
103             return null;
104         }
105 
106         String protocol = url.getProtocol();
107 
108         if (handlers != null) {
109             Method m = handlers.get(protocol);
110 
111             if (m != null) {
112                 try {
113                     URLHandler handler = (URLHandler)m.invoke(null, new Object[] { url });
114 
115                     if (handler != null) {
116                         return handler;
117                     }
118                 }
119                 catch(IllegalAccessException e) {
120                     if (DEBUG) System.err.println(e);
121                 }
122                 catch(IllegalArgumentException e) {
123                     if (DEBUG) System.err.println(e);
124                 }
125                 catch(InvocationTargetException e) {
126                     if (DEBUG) System.err.println(e);
127                 }
128             }
129         }
130 
131         return getDefault(url);
132     }
133 
getDefault(URL url)134     protected static URLHandler getDefault(URL url) {
135         URLHandler handler = null;
136 
137         String protocol = url.getProtocol();
138         try {
139             if (protocol.equals("file")) {
140                 handler = new FileURLHandler(url);
141             } else if (protocol.equals("jar") || protocol.equals("wsjar")) {
142                 handler = new JarURLHandler(url);
143             }
144         } catch (Exception e) {
145             // ignore - just return null
146         }
147         return handler;
148     }
149 
150     private static class FileURLHandler extends URLHandler {
151         File file;
152 
FileURLHandler(URL url)153         FileURLHandler(URL url) {
154             try {
155                 file = new File(url.toURI());
156             } catch (URISyntaxException use) {
157                 // fall through
158             }
159             if (file == null || !file.exists()) {
160                 if (DEBUG) System.err.println("file does not exist - " + url.toString());
161                 throw new IllegalArgumentException();
162             }
163         }
164 
165         @Override
guide(URLVisitor v, boolean recurse, boolean strip)166         public void guide(URLVisitor v, boolean recurse, boolean strip) {
167             if (file.isDirectory()) {
168                 process(v, recurse, strip, "/", file.listFiles());
169             } else {
170                 v.visit(file.getName());
171             }
172         }
173 
process(URLVisitor v, boolean recurse, boolean strip, String path, File[] files)174         private void process(URLVisitor v, boolean recurse, boolean strip, String path, File[] files) {
175             if (files != null) {
176                 for (int i = 0; i < files.length; i++) {
177                     File f = files[i];
178 
179                     if (f.isDirectory()) {
180                         if (recurse) {
181                             process(v, recurse, strip, path + f.getName()+ '/', f.listFiles());
182                         }
183                     } else {
184                         v.visit(strip? f.getName() : path + f.getName());
185                     }
186                 }
187             }
188         }
189     }
190 
191     private static class JarURLHandler extends URLHandler {
192         JarFile jarFile;
193         String prefix;
194 
JarURLHandler(URL url)195         JarURLHandler(URL url) {
196             try {
197                 prefix = url.getPath();
198 
199                 int ix = prefix.lastIndexOf("!/");
200 
201                 if (ix >= 0) {
202                     prefix = prefix.substring(ix + 2); // truncate after "!/"
203                 }
204 
205                 String protocol = url.getProtocol();
206                 if (!protocol.equals("jar")) {
207                     // change the protocol to "jar"
208                     // Note: is this really OK?
209                     String urlStr = url.toString();
210                     int idx = urlStr.indexOf(":");
211                     if (idx != -1) {
212                         url = new URL("jar" + urlStr.substring(idx));
213                     }
214                 }
215 
216                 JarURLConnection conn = (JarURLConnection)url.openConnection();
217                 jarFile = conn.getJarFile();
218             }
219             catch (Exception e) {
220                 if (DEBUG) System.err.println("icurb jar error: " + e);
221                 throw new IllegalArgumentException("jar error: " + e.getMessage());
222             }
223         }
224 
225         @Override
guide(URLVisitor v, boolean recurse, boolean strip)226         public void guide(URLVisitor v, boolean recurse, boolean strip) {
227             try {
228                 Enumeration<JarEntry> entries = jarFile.entries();
229 
230                 while (entries.hasMoreElements()) {
231                     JarEntry entry = entries.nextElement();
232 
233                     if (!entry.isDirectory()) { // skip just directory paths
234                         String name = entry.getName();
235 
236                         if (name.startsWith(prefix)) {
237                             name = name.substring(prefix.length());
238                             int ix = name.lastIndexOf('/');
239                             if (ix > 0 && !recurse) {
240                                 continue;
241                             }
242                             if (strip && ix != -1) {
243                                 name = name.substring(ix+1);
244                             }
245                             v.visit(name);
246                         }
247                     }
248                 }
249             }
250             catch (Exception e) {
251                 if (DEBUG) System.err.println("icurb jar error: " + e);
252             }
253         }
254     }
255 
guide(URLVisitor visitor, boolean recurse)256     public void guide(URLVisitor visitor, boolean recurse)
257     {
258         guide(visitor, recurse, true);
259     }
260 
guide(URLVisitor visitor, boolean recurse, boolean strip)261     public abstract void guide(URLVisitor visitor, boolean recurse, boolean strip);
262 
263     public interface URLVisitor {
visit(String str)264         void visit(String str);
265     }
266 }
267