1 package com.starphoenixmedia.candle_pos;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.net.MalformedURLException;
9 import java.net.URL;
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Enumeration;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.Objects;
16 import java.util.function.Consumer;
17 import java.util.jar.Attributes;
18 import java.util.jar.Attributes.Name;
19 import java.util.jar.JarEntry;
20 import java.util.jar.JarFile;
21 import java.util.jar.Manifest;
22 import java.util.logging.Level;
23 import java.util.logging.Logger;
24 import java.util.zip.ZipEntry;
25
26
27
28
29
30 public class FireCodeClassLoader extends ClassLoader
31 {
32
33
34
35
36 private static HashMap<String, File> jars;
37
38
39
40
41 private static HashMap<String, File> flds;
42
43
44
45 public static final int BUFFER_LEN = 4096;
46
47
48
49 private static HashMap<String, Package> pkgs;
50
51
52
53 private static HashMap<String, String> maps;
54
55
56
57 private static HashMap<String, Class<?>> clss;
58
59
60
61 private final ClassLoader parent;
62
63
64
65
66 public FireCodeClassLoader()
67 {
68 parent = getClass().getClassLoader();
69 jars = new HashMap<>();
70 flds = new HashMap<>();
71 pkgs = new HashMap<>();
72 clss = new HashMap<>();
73 maps = new HashMap<>();
74 }
75
76
77
78
79
80 public FireCodeClassLoader(ClassLoader cl)
81 {
82 parent = cl;
83 jars = new HashMap<>();
84 flds = new HashMap<>();
85 pkgs = new HashMap<>();
86 clss = new HashMap<>();
87 maps = new HashMap<>();
88 }
89
90
91
92 public void init()
93 {
94 Iterator<String> paths;
95 paths = cpDirs(System.getProperty("java.class.path"));
96
97 File f;
98 String s;
99 while ( paths.hasNext() )
100 {
101 s = paths.next();
102 f = new File(s);
103 if ( f.isDirectory() ) { addDir(f); }
104 else if ( s.toLowerCase().endsWith(".jar") ) { addJar(f); }
105 }
106 }
107
108 @Override public Class<?> findClass(String name) throws ClassNotFoundException
109 {
110 if ( clss.containsKey(name) ) { return clss.get(name); }
111 else { throw new ClassNotFoundException(name); }
112 }
113
114 @Override public URL getResource(final String path) { return getResource(true, path); }
115 private URL getResource(boolean goup, final String path)
116 {
117 String pth;
118 URL u = null;
119
120 if ( path.startsWith("/") ) { pth = path.substring(1); } else { pth = path; }
121 try { u = this.getResourceLocator(pth); } catch ( Throwable t ) { }
122 if ( (u == null) && goup ) { u = parent.getResource(path); }
123
124 return u;
125 }
126
127 @Override public Package getPackage(String name) { return pkgs.get(name); }
128 @Override public Package[] getPackages() { return pkgs.values().toArray(new Package[]{}); }
129
130 private URL getResourceLocator(final String path) throws Throwable
131 {
132 JarFile jf;
133 ZipEntry ze;
134 Iterator<File> it;
135 File f;
136
137
138 if ( !maps.isEmpty() )
139 {
140 String pack = path.replace("/", ".").substring(0, path.lastIndexOf("/"));
141 if ( maps.containsKey(pack) )
142 {
143 f = new File(maps.get(pack));
144 if ( f.isDirectory() )
145 { return new URL("file:".concat(maps.get(pack)).concat(File.separator).concat(path)); }
146 else { return new URL("jar:file:".concat(maps.get(pack)).concat("!/").concat(path)); }
147 }
148 }
149
150
151 if ( !jars.isEmpty() )
152 {
153 System.err.println("Warning: Slow search: ".concat(path));
154 it = jars.values().iterator();
155 while ( it.hasNext() )
156 {
157 f = it.next();
158 jf = new JarFile(f);
159 ze = jf.getEntry(path);
160 jf.close();
161 if ( ze != null )
162 { return new URL("jar:file:".concat(f.getCanonicalPath()).concat("!/").concat(path)); }
163 }
164 }
165 File t;
166 if ( !flds.isEmpty() )
167 {
168 System.err.println("Warning: Slow search: ".concat(path));
169 it = flds.values().iterator();
170 while ( it.hasNext() )
171 {
172 f = it.next();
173 try
174 {
175 t = new File("file:".concat(f.getCanonicalPath()).concat(File.separator).concat(path));
176 if ( t.exists() ) { return new URL(t.getCanonicalPath()); }
177 }
178 catch ( IOException x ) {}
179 }
180 }
181 return null;
182 }
183
184 @Override public InputStream getResourceAsStream(final String path)
185 { return getResourceAsStream(true, path); }
186 private InputStream getResourceAsStream(boolean goup, final String path)
187 {
188 final URL u = getResource(goup, path);
189 if ( u == null ) { return null; }
190 try { return u.openStream(); } catch ( IOException e ) { e.printStackTrace(System.out); }
191 return null;
192 }
193
194 @Override public Enumeration<URL> getResources(String name) throws IOException
195 {
196 if ( jars.isEmpty() ) { return null; }
197 ArrayList<URL> ar = new ArrayList<>();
198 Iterator<File> it = jars.values().iterator();
199 File f;
200 JarFile jf;
201 ZipEntry ze;
202
203 while ( it.hasNext() )
204 {
205 f = it.next();
206 jf = new JarFile(f);
207 ze = jf.getEntry(name);
208 jf.close();
209 if ( ze != null ) { ar.add(new URL("jar:file:".concat(f.getCanonicalPath()).concat("!/").concat(name))); }
210 }
211
212 return new Iterator2Enum<>(ar.iterator());
213 }
214
215 @Override public Class<?> loadClass(final String name) throws ClassNotFoundException
216 { return loadClass(name, true); }
217 @Override protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException
218 {
219
220 String pack = name.substring(0, name.lastIndexOf('.'));
221 if ( !maps.containsKey(pack) ) { return parent.loadClass(name); }
222
223
224 Class<?> cls = findLoadedClass(name);
225 if ( cls != null ) { return cls; }
226
227 final InputStream is = getResourceAsStream(false, name.replaceAll("\\.", "/").concat(".class"));
228 if ( is == null ) { cls = parent.loadClass(name); }
229 else
230 {
231 try { return loadClassWorker(name, resolve, is); }
232 catch ( IOException ex ) { throw new ClassNotFoundException("Couln't load ".concat(name)); }
233 }
234
235 return cls;
236 }
237
238 private Class<?> loadClassWorker(final String name, final boolean resolve, final InputStream is)
239 throws ClassNotFoundException, IOException
240 {
241 getClassLoadingLock(name);
242 Class<?> cls;
243
244 final byte[] buffer = new byte[BUFFER_LEN];
245 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
246 byte[] bytecode;
247
248 int i;
249 while ( (i = is.read(buffer, 0, BUFFER_LEN)) > 0 ) { baos.write(buffer, 0, i); }
250 is.close();
251
252 bytecode = baos.toByteArray();
253 if ( bytecode == null ) { throw new ClassNotFoundException("Cannot load class: " + name); }
254
255 try
256 {
257 cls = this.defineClass(name, bytecode, 0, bytecode.length);
258 if ( resolve ) { this.resolveClass(cls); }
259 }
260 catch ( SecurityException e ) { cls = parent.loadClass(name); }
261
262 return cls;
263 }
264
265 private String addDefHelper(Attributes manifest, Attributes file, me key)
266 {
267 if ( (file != null) && !file.isEmpty() )
268 { if ( file.containsKey(key.getPrimary()) ) { return file.getValue(key.getPrimary()); } }
269
270 if ( (manifest != null) && !manifest.isEmpty() )
271 {
272 if ( manifest.containsKey(key.getPrimary()) ) { return manifest.getValue(key.getPrimary()); }
273 else { return key.getDefault(); }
274 }
275
276 return "null";
277 }
278
279 private void defPkg(String pack, String file, Attributes master, Attributes pkg)
280 throws MalformedURLException
281 {
282 Package p;
283 if ( !pkgs.containsKey(pack) )
284 {
285 p = definePackage(pack,
286 addDefHelper(master, pkg, me.SPECTITLE), addDefHelper(master, pkg, me.SPECVERSION),
287 addDefHelper(master, pkg, me.SPECVENDOR),
288 addDefHelper(master, pkg, me.IMPLTITLE), addDefHelper(master, pkg, me.IMPLVERSION),
289 addDefHelper(master, pkg, me.IMPLVENDOR),
290 new URL("file:".concat(file))
291 );
292 pkgs.put(pack, p);
293 maps.put(pack, file);
294 }
295 }
296
297 public void addDir(File dir)
298 {
299 String pt = null;
300 try { pt = dir.getCanonicalPath(); }
301 catch (IOException ex) { Logger.getLogger(FireCodeClassLoader.class.getName()).log(Level.SEVERE, null, ex); }
302 if ( pt != null )
303 {
304 if ( !flds.containsKey(pt) )
305 {
306 flds.put(pt, new File(pt));
307
308
309 StringBuilder sb = new StringBuilder(pt);
310 sb.append(File.separator);
311 sb.append("META-INF");
312 sb.append(File.separator);
313 sb.append("MANIFEST.MF");
314 File f = new File(sb.toString());
315 try
316 {
317 Manifest mf;
318 if ( f.exists() )
319 {
320 FileInputStream fis = new FileInputStream(f);
321 mf = new Manifest(fis);
322 }
323 else { mf = new Manifest(); }
324 if ( mf.getMainAttributes().containsKey(Name.CLASS_PATH) )
325 { addClassPath(mf.getMainAttributes().getValue(Name.CLASS_PATH)); }
326 addDirHelper(dir, null, "", mf);
327 System.out.println("Added Dir ".concat(pt));
328 }
329 catch (IOException x) {}
330 }
331 }
332 }
333
334 private void addDirHelper(File root, File dir, String name, Manifest mf) throws IOException
335 {
336 File[] files;
337 if ( dir != null ) { files = dir.listFiles(); } else { files = root.listFiles(); }
338 String n;
339 for ( File f : files )
340 {
341 if ( f.isDirectory() )
342 {
343 if ( name.isEmpty() ) { addDirHelper(root, f, f.getName(), mf); }
344 else
345 {
346 n = name.concat(".").concat(f.getName());
347 if ( n.startsWith(".") ) { n = n.substring(1); }
348 if ( !flds.containsKey(n) )
349 { defPkg(n, root.getCanonicalPath(), mf.getMainAttributes(), mf.getAttributes(n)); }
350 addDirHelper(root, f, n, mf);
351 }
352 }
353 else if ( f.isFile() && f.getName().endsWith(".jar") ) { addJar(f); }
354 }
355 }
356
357 public void addJar(File jar)
358 {
359 String pt = null;
360 try { pt = jar.getCanonicalPath(); }
361 catch (IOException ex) { Logger.getLogger(FireCodeClassLoader.class.getName()).log(Level.SEVERE, null, ex); }
362 if ( pt != null )
363 {
364 if ( !jars.containsKey(pt) )
365 {
366 jars.put(pt, new File(pt));
367 String tp;
368
369
370 try
371 {
372 JarFile jf = new JarFile(jars.get(pt));
373 Enumeration<JarEntry> en = jf.entries();
374 Manifest mf = jf.getManifest();
375 Attributes msf = mf.getMainAttributes();
376
377 JarEntry je;
378
379 if ( msf.containsKey(Name.CLASS_PATH) ) { addClassPath(msf.getValue(Name.CLASS_PATH)); }
380 while ( en.hasMoreElements() )
381 {
382 je = en.nextElement();
383 tp = je.getName();
384 if ( tp.endsWith("/") ) { tp = tp.substring(0, tp.lastIndexOf("/")); }
385 if ( je.isDirectory() && !tp.startsWith("META-INF") && tp.contains("/") )
386 {
387 tp = je.getName().replace('/', '.');
388 tp = tp.substring(0, tp.lastIndexOf("."));
389 defPkg(tp, jf.getName(), msf, je.getAttributes());
390 }
391 }
392 System.out.println("Added Jar ".concat(pt));
393 }
394 catch ( IOException x ) {}
395 }
396 }
397 }
398
399 private Iterator<String> cpDirs(String cp)
400 {
401 String[] pt;
402 ArrayList<String> al = new ArrayList<>();
403 if ( cp.contains(File.pathSeparator) || cp.contains(" ") )
404 { pt = cp.split("[ ".concat(File.pathSeparator).concat("]")); }
405 else { pt = new String[]{cp}; }
406
407 al.addAll(Arrays.asList(pt));
408
409 return al.iterator();
410 }
411
412 private void addClassPath(String list) { addClassPath(cpDirs(list)); }
413 private void addClassPath(Iterator<String> it)
414 {
415 String st;
416 File finale;
417 String[] lists = new String[]
418 {
419 System.getProperty("user.home").concat("/.m2/repository/"),
420 "./libs/",
421 "./"
422 };
423 File f;
424 File t;
425 while ( it.hasNext() )
426 {
427 finale = null;
428 st = it.next();
429 f = new File(st);
430 if ( f.exists() ) { finale = f; }
431 for ( String s : lists )
432 {
433 if ( finale == null )
434 {
435 t = new File(s.concat(f.getPath()));
436 if ( t.exists() ) { finale = t; }
437 }
438 }
439 if ( finale != null )
440 {
441 if ( finale.isDirectory() ) { addDir(finale); }
442 else if ( finale.getName().endsWith(".jar") ) { addJar(finale); }
443 }
444 }
445 }
446
447 private enum me
448 {
449 NAME(new Name("Package"), "App"),
450 SPECTITLE(Name.SPECIFICATION_TITLE, "Default"),
451 SPECVERSION(Name.SPECIFICATION_VERSION, "1.0"),
452 SPECVENDOR(Name.SPECIFICATION_VENDOR, "Developer"),
453 IMPLTITLE(Name.IMPLEMENTATION_TITLE, "Default"),
454 IMPLVERSION(Name.IMPLEMENTATION_VERSION, "1.0"),
455 IMPLVENDOR(Name.IMPLEMENTATION_VENDOR, "Developer"),
456 SEALED(Name.SEALED, "false");
457
458 private final Name p;
459 private final String d;
460 me(Name pri, String def)
461 {
462 p = pri;
463 d = def;
464 }
465 public Name getPrimary() { return p; }
466 public String getDefault() { return d; }
467 }
468
469 public class Enum2Iterator<E> implements Iterator<E>
470 {
471 Enumeration<E> en;
472 public Enum2Iterator(Enumeration<E> enumer) { en = enumer; }
473
474 @Override public void forEachRemaining(Consumer<? super E> action)
475 {
476 Objects.requireNonNull(action);
477 while ( en.hasMoreElements() ) { action.accept(en.nextElement()); }
478 }
479
480 @Override public boolean hasNext() { return en.hasMoreElements(); }
481 @Override public E next() { return en.nextElement(); }
482 }
483
484 public class Iterator2Enum<E> implements Enumeration<E>
485 {
486 Iterator<E> it;
487 public Iterator2Enum(Iterator<E> iter) { it = iter; }
488
489 @Override public boolean hasMoreElements() { return it.hasNext(); }
490 @Override public E nextElement() { return it.next(); }
491 }
492 }