2020-01-02 16:52:38 +01:00
/ *
2022-01-02 21:01:50 +01:00
Copyright 2020 - 2022 Volker Berlin ( i - net software )
2020-01-02 16:52:38 +01:00
Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an " AS IS " BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package de.inetsoftware.jwebassembly.module ;
import java.io.IOException ;
import java.io.InputStream ;
2020-01-03 19:51:58 +01:00
import java.util.HashMap ;
2020-01-02 16:52:38 +01:00
2020-01-07 19:54:05 +01:00
import javax.annotation.Nonnull ;
2020-01-02 16:52:38 +01:00
import javax.annotation.Nullable ;
import de.inetsoftware.classparser.ClassFile ;
/ * *
* Cache and manager for the loaded ClassFiles
*
* @author Volker Berlin
* /
public class ClassFileLoader {
2020-01-03 19:51:58 +01:00
private final HashMap < String , ClassFile > replace = new HashMap < > ( ) ;
2020-12-12 20:42:46 +01:00
//A weak cache has produce problems if there are different versions of the same class in the build path and/or library path. Then the prescan can add the second version of the class.
private final HashMap < String , ClassFile > cache = new HashMap < > ( ) ;
2020-01-02 16:52:38 +01:00
private final ClassLoader loader ;
2020-01-07 19:54:05 +01:00
private final ClassLoader bootLoader ;
2020-01-02 16:52:38 +01:00
/ * *
* Create a new instance
*
* @param loader
* the classloader to find the * . class files
* /
public ClassFileLoader ( ClassLoader loader ) {
this . loader = loader ;
2020-01-07 19:54:05 +01:00
ClassLoader cl = ClassLoader . getSystemClassLoader ( ) ;
do {
ClassLoader parent = cl . getParent ( ) ;
if ( parent = = null ) {
bootLoader = cl ;
break ;
}
cl = parent ;
} while ( true ) ;
2020-01-02 16:52:38 +01:00
}
/ * *
* Get the ClassFile from cache or load it .
*
* @param className
2020-09-24 20:55:14 +02:00
* the class name like " java/lang/Object "
2020-01-02 16:52:38 +01:00
* @return the ClassFile or null
* @throws IOException
* If any I / O error occur
* /
@Nullable
public ClassFile get ( String className ) throws IOException {
2020-01-03 19:51:58 +01:00
ClassFile classFile = replace . get ( className ) ;
if ( classFile ! = null ) {
return classFile ;
}
2020-12-12 20:42:46 +01:00
classFile = cache . get ( className ) ;
2020-01-02 16:52:38 +01:00
if ( classFile ! = null ) {
return classFile ;
}
InputStream stream = loader . getResourceAsStream ( className + " .class " ) ;
if ( stream ! = null ) {
classFile = new ClassFile ( stream ) ;
2020-12-12 20:42:46 +01:00
cache . put ( className , classFile ) ;
2020-01-02 16:52:38 +01:00
}
return classFile ;
}
2020-01-07 19:54:05 +01:00
/ * *
* Add a class file to the weak cache .
*
* @param classFile
* the class file
* /
public void cache ( @Nonnull ClassFile classFile ) {
String name = classFile . getThisClass ( ) . getName ( ) ;
if ( bootLoader . getResource ( name + " .class " ) ! = null ) {
// if the same resource is exist in the JVM self then we need to hold the reference permanently
2020-12-12 20:42:46 +01:00
if ( replace . get ( name ) = = null ) {
// does not add a second version of the same file
replace . put ( name , classFile ) ;
}
2020-01-07 19:54:05 +01:00
} else {
2020-12-12 20:42:46 +01:00
if ( cache . get ( name ) = = null ) {
// does not add a second version of the same file
cache . put ( name , classFile ) ;
}
2020-01-07 19:54:05 +01:00
}
}
2020-01-03 19:51:58 +01:00
/ * *
2020-01-19 15:15:01 +01:00
* Replace the class in the cache with the given instance to the loader cache .
2020-01-03 19:51:58 +01:00
*
* @param className
* the name of the class to replace
* @param classFile
2020-01-19 15:15:01 +01:00
* the replacing ClassFile
2020-01-03 19:51:58 +01:00
* /
2020-01-19 15:15:01 +01:00
void replace ( String className , ClassFile classFile ) {
2022-01-02 21:01:50 +01:00
if ( replace . get ( className ) = = null ) {
classFile = new ClassFile ( className , classFile ) ;
replace . put ( className , classFile ) ;
}
2020-01-03 19:51:58 +01:00
}
2020-01-19 15:15:01 +01:00
/ * *
* Add a partial class with the given instance to the loader cache .
*
* @param className
2020-09-24 20:55:14 +02:00
* the name of the class to replace like " java/lang/String "
2020-01-19 15:15:01 +01:00
* @param partialClassFile
* the partial ClassFile
* @throws IOException
* If any I / O error occur
* /
void partial ( String className , ClassFile partialClassFile ) throws IOException {
ClassFile classFile = get ( className ) ;
replace . put ( className , classFile ) ;
classFile . partial ( partialClassFile ) ;
}
2020-01-02 16:52:38 +01:00
}