Ultrakompakter HTTP Server
ulrich
2024-12-01 47e67b0aa12758fcbe6eb68f95a35ceb66c268e7
commit | author | age
f4025a 1 /*
c2e8cf 2   neon - Embeddable HTTP Server based on jdk.httpserver
U 3   Copyright (C) 2024  Ulrich Hilger
f4025a 4
c2e8cf 5   This program is free software: you can redistribute it and/or modify
U 6   it under the terms of the GNU Affero General Public License as
7   published by the Free Software Foundation, either version 3 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU Affero General Public License for more details.
14
15   You should have received a copy of the GNU Affero General Public License
16   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
f4025a 18 package de.uhilger.neon;
U 19
20 import java.io.File;
21 import java.io.IOException;
22 import java.net.MalformedURLException;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.net.URL;
26 import java.net.URLClassLoader;
27 import java.util.Enumeration;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30 import java.util.zip.ZipEntry;
31 import java.util.zip.ZipFile;
32
33 /**
47e67b 34  * Die Klasse JarScanner enthaelt Methoden, um fuer eine Klasse zu bestimmen, in welcher JAR-Datei
U 35  * sie liegt und diese JAR-Datei nach Klassen zu durchsuchen.
36  *
f4025a 37  * @author Ulrich Hilger
U 38  * @version 0.1, 30.11.2024
39  */
47e67b 40 public final class JarScanner {
U 41
42   private final URI path;
43   private final Class annotation;
44   private final Class cls;
45   private final ClassLoader urlCL;
46
47   /**
48    * Einen JarScanner erzeugen, der das Archiv, in dem sich eine gegebene Klasse befindet, nach
49    * Klassen durchsucht, die eine bestimmte Annotation besitzen
50    *
51    * @param c eine Klasse die sich im Archiv befindet, das durchsucht werden soll
52    * @param annotation die Annotation, nach der gesucht wird
53    */
54   public JarScanner(Class c, Class annotation) {
55     this.annotation = annotation;
56     this.cls = c;
57     this.urlCL = getUrlClassLoader(cls);
58     this.path = getPath(c);
59  }
60
61   /**
62    * Den Inhalt einer Jar-Datei nach Klassen durchsuchen, die die dem Konstruktor gegebene
63    * Annotation besitzen.
64    *
65    * @param packageName Name der Package, die einschl. Unterpackages durchsucht wird, nur Klassen
66    * dieser Package und ihrer Unterpackages werden geladen und auf die Anotation ueberprueft
67    * @param l eine Klasse, die verstaendigt wird, wenn eine annotierte Klasse gefunden wurde
68    * @param h der Handler, dem die gefundene Klasse hinzugefuegt werden soll
69    * @param contextName Name des Kontext, dem gefundene Klassen hinzugefuegt werden sollen
70    */
71   public void processZipContent(String packageName, JarScannerListener l, Handler h, String contextName) {
f4025a 72     try {
47e67b 73       ZipFile zipfile = new ZipFile(new File(path));
f4025a 74       Enumeration en = zipfile.entries();
47e67b 75       //ClassLoader cl = getUrlClassLoader(cls);
f4025a 76       while (en.hasMoreElements()) {
U 77         ZipEntry zipentry = (ZipEntry) en.nextElement();
78         if (!zipentry.isDirectory()) {
47e67b 79           processZipEntry(zipentry, packageName, l, h, contextName);
f4025a 80         } else {
U 81           // ZIP-Dir muss nicht bearbeitet werden
82         }
83       }
84     } catch (IOException ex) {
85       log(Level.SEVERE, ex.getLocalizedMessage());
86     }
87   }
88
47e67b 89   @SuppressWarnings("unchecked")
U 90   private void processZipEntry(ZipEntry zipentry, String packageName, JarScannerListener l, Handler h, String contextName) {
7456da 91     finest(zipentry.getName());
f4025a 92     String zName = zipentry.getName();
U 93     if (zName.toLowerCase().endsWith(".class")) {
94       int pos = zName.indexOf(".class");
95       String fullClassName = zName.substring(0, pos);
7456da 96       finest("full class name: " + zName);
f4025a 97       String fullClassNameDots = fullClassName.replace('/', '.');
7456da 98       finest("full class name dots: " + fullClassNameDots);
f4025a 99       String pkgName = getPackageName(fullClassNameDots);
7456da 100       finest(" -- package name: " + pkgName);
f4025a 101       if (null != urlCL && pkgName.toLowerCase().startsWith(packageName)) {
U 102         try {
47e67b 103           Class c = urlCL.loadClass(fullClassNameDots);
f4025a 104           if (c != null) {
47e67b 105             if (c.isAnnotationPresent(annotation)) {
7456da 106               finest(" ---- ACTOR ---- " + fullClassNameDots);
47e67b 107               l.annotationFound(c, h, contextName);
f4025a 108             } else {
7456da 109               finest("kein Actor " + fullClassNameDots);
f4025a 110             }
U 111           } else {
7456da 112             finest("class NOT loaded: " + zName);
f4025a 113           }
U 114         } catch (ClassNotFoundException ex) {
7456da 115           finest(" +++++ Class not found: " + ex.getMessage());
f4025a 116         }
U 117       }
118     }
119   }
47e67b 120
f4025a 121   private String getPackageName(String fullClassName) {
U 122     String packageName;
123     int pos = fullClassName.lastIndexOf(".");
124     if (pos > 0) {
125       packageName = fullClassName.substring(0, pos);
126     } else {
127       packageName = fullClassName;
128     }
129     return packageName;
130   }
47e67b 131
f4025a 132   public ClassLoader getUrlClassLoader(Class c) {
47e67b 133     ClassLoader cl = null;
f4025a 134     try {
47e67b 135       URL url = getPath(c).toURL();
7456da 136       finer("url: " + url.getPath());
47e67b 137       cl = new URLClassLoader(new URL[]{url});
f4025a 138     } catch (MalformedURLException ex) {
U 139       log(Level.SEVERE, ex.getMessage());
140     } finally {
47e67b 141       return cl;
f4025a 142     }
U 143   }
47e67b 144
U 145   public String getPathStr() {
146     if (path != null) {
147       return path.toString();
148     } else {
149       return "";
150     }
151   }
152
153   public boolean isJar() {
154     return !getPathStr().toLowerCase().endsWith(".class");
155   }
156
157   private URI getPath(Class c) {
f4025a 158     String className = c.getName();
7456da 159     finest("this name: " + className);
47e67b 160     String classNameWoPkg = c.getSimpleName();//className.substring(className.lastIndexOf(".") + 1);
7456da 161     finest("Class name: " + classNameWoPkg);
f4025a 162     String classPath = c.getResource(classNameWoPkg + ".class").getPath();
47e67b 163     int pos = classPath.indexOf("!");
f4025a 164     String jarPath;
47e67b 165     if (pos > -1) {
f4025a 166       jarPath = /*"jar:" + */ classPath.substring(0, pos);
U 167     } else {
168       jarPath = classPath;
169     }
7456da 170     finest("path: " + jarPath);
47e67b 171     try {
U 172       return new URI(jarPath);
173     } catch (URISyntaxException ex) {
174       Logger.getLogger(JarScanner.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
175       return null;
176     }
f4025a 177   }
47e67b 178
7456da 179   private void finest(String msg) {
U 180     log(Level.FINEST, msg);
181   }
47e67b 182
f4025a 183   private void finer(String msg) {
U 184     log(Level.FINER, msg);
185   }
47e67b 186
f4025a 187   private void log(Level l, String msg) {
U 188     Logger.getLogger(JarScanner.class.getName()).log(l, msg);
189   }
47e67b 190
f4025a 191   public interface JarScannerListener {
47e67b 192
U 193     public void annotationFound(Class foundClass, Handler h, String contextName);
f4025a 194   }
47e67b 195
f4025a 196 }