In our setup, we perform some STATIC-INIT build steps including adding all resource paths to a list in an object. We use a Recorder for this, because the object cannot be accessed during the static init phase. In JVM mode, we see that the list does indeed contain all resource paths. However, this is not the case in Native mode. The list remains empty, even though the build logs show that we iterated over the resources and added them to the list.
This is what our setup looks like:
First: The file that is accessible at runtime and contains all resource paths.
#ApplicationScoped
public class ServiceResourcesList {
private List<String> resources;
public ServiceResourcesList() {
resources = new ArrayList<>();
}
public void addResource(String resource) {
this.resources.add(resource);
}
public List<String> getResources() {
return resources;
}
public List<String> getResources(Predicate<String> filter) {
return resources.stream().filter(filter).collect(Collectors.toList());
}
}
The recorder, which returns a BeanContainerListener:
#Recorder
public class ServiceResourcesListRecorder {
public BeanContainerListener addResourceToList(String resource) {
return beanContainer -> {
ServiceResourcesList producer = beanContainer.instance(ServiceResourcesList.class);
producer.addResource(resource);
};
}
}
And finally the (simplified) buildstep. Note that we use a BuildProducer which should make sure that the objects have been registered already before applying the Recorder methods.
#BuildStep
#Record(STATIC_INIT)
void createResourceList(final BuildProducer<BeanContainerListenerBuildItem> containerListenerProducer, ServiceResourcesListRecorder recorder) {
// Some code to get the resource paths, but this could be anything
// ...
for (String resourcePath: resourcePaths) {
LOGGER.info(resourcePath + " added to recorder");
containerListenerProducer.produce(new BeanContainerListenerBuildItem(recorder.addResourceToList(resourcePath)));
}
}
Am I doing something wrong? Are recorders not meant to be used for native executables? Should I add RegisterForReflection somewhere?
Thanks
We solved this problem by using RUNTIME-INIT and static methods instead.
Related
I am sorry to ask you this basic question but I am not able to understand the concept.
I read many SO post but I could not understand. Could you please give me code example to understand.
As said in this post
Static variables cannot be elected for garbage collection while the class is loaded. They can be collected when the respective class loader (that was responsible for loading this class) is itself collected for garbage.
I understand as per theory that Classloader cannot be collected if it has a reference but I do not understand how it is possible practically.
Could you please kindly explain with a code example?
Many thanks for your help!
Lets see this code to understand how classloader leaks possible
Main.java
public class Main {
public static void main(String...args) throws Exception {
List<Object> list = new ArrayList<>();
loadClass(list);
while (true) {
System.gc();
Thread.sleep(1000);
}
}
private static void loadClass(List list) throws Exception {
URL url = Main.class.getProtectionDomain().getCodeSource().getLocation();
MyCustomClassLoader cl = new MyCustomClassLoader(url);
Class<?> clazz = cl.loadClass("com.test.Foo");
list.add(clazz.newInstance());
cl = null;
}
}
class MyCustomClassLoader extends URLClassLoader {
public MyCustomClassLoader(URL... urls) {
super(urls, null);
}
#Override
protected void finalize() {
System.out.println("*** CustomClassLoader finalized!");
}
}
Foo.java
public class Foo {
public Foo() {
System.out.println("Test ClassLoader: " + this.getClass().getClassLoader());
}
#Override
protected void finalize() {
System.out.println( this + " finalized!");
}
}
The output of this as follows:
Test ClassLoader: com.test.MyCustomClassLoader#71dac704
So, here we can see "*** CustomClassLoader finalized!" is not called and this is because MyCustomClassLoader is holding a reference of object list as the instances loaded by classloader are kept in it.
Now, lets change the code a bit, so here we will set list to null
public static void main(String...args) throws Exception {
List<Object> list = new ArrayList<>();
loadClass(list);
while (true) {
System.gc();
Thread.sleep(1000);
list = null;
}
}
And now see the output
Test ClassLoader: com.test.MyCustomClassLoader#71dac704
com.test.Foo#650de12 finalized!
*** CustomClassLoader finalized!
I am posting my understanding hope it helps,
Background understanding:
Simple way to understand this is to take an example of a Tomcat or any such application. Which is java based.
Tomcat can run multiple webapps. Even if you deploy same application with different name they will be treated differently. Here these both applications will have same classes but still they are treated differently. So here comes the class loaders.
So you can think in a way like Tomcat is creating a class loader for each application and loading them under it.
Reclaiming of loaders: above if Tomcat is holding reference to the loader object then the loader object will not be reclaimed. And unless loader gets garbage collected the classes loaded by it stays.
So if you shutdown an application, Tomcat will ultimately drefrence it's respective loader so that gc can reclaim it an clean it including the classed loaded by it.
Quick links that may help:
https://stackoverflow.com/questions/2433261/when-and-how-are-classes-garbage-collected-in-java#:~:text=A%20class%20in%20Java%20can,that%20class%20are%20still%20reachable.
https://www.dynatrace.com/resources/ebooks/javabook/class-loader-issues/#:~:text=Classloader%20Cannot%20Be%20Garbage-Collected,hold%20references%20to%20their%20classes.
I am really needing some help on this.
I have adopted the JNOTIFY approach to detecting any new files in a directory. When the file arrives the Listener informs that a new file is in the location.
#BeforeTest(alwaysRun=true)
public void Polling() throws Exception {
ListenToNotifications.checkFolderPickup();
}
I have attempted this where I addded a call to my Setup function in order to call my setup function after the file is detected.
//snippet from Listener Class from checkFolderPickup();
public void fileCreated(int wd, String rootPath, String name) {
print("New File just created " + rootPath + " : " + name);
Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
try {
BaseTest.setup();
} catch (Exception e) {
e.printStackTrace();
}
}
My question is //Thread.sleep(1000000) i feel this is not a safe approach and I wanted to know if there is any other approach that I could possibly use instead of a Thread.Sleep, because this function will have to be executed once each time a new file is available and the old file will be deleted eventually and so on, I cannot make the Sleep to short , it will just ignore and continue with Base.Setup()
public static void checkFolderPickup() throws Exception {
...removed other code
boolean watchSubtree = true;
int watchID = JNotify.addWatch(path, mask, watchSubtree, new Listener());
//Thread.sleep(1000000);
Thread.sleep(20000);
boolean res = JNotify.removeWatch(watchID);
if (!res) {
// invalid watch ID specified.
}
}
I basically need my framework to keep polling that directory and each time it will execute the base setup process and follow a workflow, delete the file then poll again and so on.
Can anyone please advise?
You don't need any other modules , you can use custom expected condition:##
using:
import java.io.File;
define the method inside any pageobject class:
private ExpectedCondition<Boolean> newfilepresent() {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
File f = new File("D:\\workplace");
return f.listFiles().length>1;
}
#Override
public String toString() {
return String.format("wait for new file to be present within the time specified");
}
};
}
we created a custom expected condition method now use it as:
and in code wait like:
wait.until(pageobject.filepresent());
Output:
Failed:
Passed
Once you register a watch on a directory with JNotify, it will continue to deliver events for files in that directory. You should not remove the watch if you wish to continue to receive events for that directory.
My installer is storing some information in a singleton class during the installation process. Now, I have noticed that in elevated action, the singleton class does not have the same instance. So far, I have not found any workaround/solution so that they share the same instance. So, I have decided to make sure that if anyone wants to get an instance of the singleton, they must call from an unelevated environment. Let's say the singleton looks like the following:
public class InvestigatorReport {
private final List<Report> reports = new ArrayList<>();
private final static InvestigatorReport INSTANCE = new InvestigatorReport();
private InvestigatorReport() {
MyLogger.logInfo(getClass(), "initiating...");
}
public static InvestigatorReport getInstance(Context context) {
if (context.hasBeenElevated()) {
throw new IllegalAccessError(
"this method must be called unelevated!");
}
return INSTANCE;
}
private boolean addReport(Report report) {
return reports.add(report);
}
}
But the problem is, There are some cases when I have to call this add report from an action class that is elevated. So I have tried the following in my elevated action class:
if (context.hasBeenElevated()) {
return (Boolean) context.runUnelevated(new RemoteCallable() {
#Override
public Serializable execute() {
return getInstance(context).addReport(report);
}
});
}
But, as you can see if I am passing the same context object from the elevated action class to the RemoteCallable class so, even though I am running the class unelevated, the context.hasBeenElevated() still returns true.
Is there any other way that I can check the elevation level other than the context? If you have any other better idea on preventing anyone from calling the singleton getInstance() method, I am all ears.
I would use a different pattern. Make all methods of your singleton static and wrap the data access with runUnelevated calls:
public static boolean addReport(Report report, Context context) {
context.runUnelevated(new RemoteCallable() {
#Override
public Serializable execute() {
InvestigatorReport.reports.add(report);
return null;
}
});
}
In that way, you can call the methods from both elevated and unelevated code without having to check anything at the call site.
For a project we have a requirement to create an interfacedefinition that will return all available filetype extensions that our component can export...
The problem is that we want avoid configuration/properties files. We don't want to edit our configuration/propertie file when another filetype is added (in the future). The structure of this part of our component is as follows:
public abstract class FileType {
protected String filetype;
public FileType(String filetype){
this.filetype = filetype;
}
public abstract void export(String path, Object information);
}
public class PdfExport extends FileType {
public PdfExport() {
super("pdf");
}
public void export(String path, Object information){
//pdf specific logic
}
}
But how do we solve this when another component calls the interfacedefinition getExportTypes()? (How do we get a list of all available filetypes?) Taking into account the requirement to add in the future new classes that extend abstract class filetype (add new filetypes)?
Does anyone has suggestions, maybe another structure of above example? Or any (design) that discuss above issue?
Thanks in advance!
You could do something like this:
public interface FileType {
public String getFileType();
public void export(String path, Object info);
}
public enum DefaultFileType implements FileType {
PDF(".pdf"){
public void export(String path, Object info) {
// do pdf stuff
}
}, TXT(".txt"){
public void export(String path, Object info) {
//do txt stuff
}
};
private final String fileType;
private DefaultFileType(String fileType) {
this.fileType = fileType;
}
public String getFileType() {
return fileType;
}
public abstract void export(String path, Object info);
}
Then you can have a Set<FileType> in your class of all the supported FileTypes. This way anyone who wants to add a supported FileType but cannot edit your enum can still do so.
This is the exact purpose of the strategy pattern. The strategies here are the FileTypes that encapsulate an algorithm that exports a file.
In the following example:
public class Application{
List<FileType> exporters = new ArrayList<FileType>();
public void addExporter(FileType fileExporter){
exporters.add(fileExporter);
}
public void exportData(Object information){
for(FileType exporter : exporters){
exporter.export("d:\Export", information);
}
}
}
The Application class holds a list of exporters that can be filled out on the go. The Application class does not have to know what type of file exporter is registered nor how the file can be exported. When the data is exported, the Applicaiton class loops through registered exporters and delegates the export task to each one of them.
EDIT Below is an example of the Application class usage.
// Define a pdf exporter
PdfExport pdfExport = new pdfExport();
Application app = new Application();
// Register the new exporter
app.addExporter(pdfExport);
// Export some data...
app.export(information);
EDIT How to avoid configuration files and changing the code everytime you have a new FileType?
You can load the exporters at runtime using reflexion (see this link for details)
You can use reflection to scan classes which implement your interface.
Have a look at similar question: At runtime, find all classes in a Java application that extend a base class
I would like to check the existence of a ResourceBundle without actually loading it.
Typically, I'm using Guice, and at initialization time, I want to check the existence, while at execution time, I want to load it. If the bundle doesn't exist, I want an early report of the inexistence of the RB.
If it was possible to get the ResourceBundle.Control instance used for a specific ResourceBundle, I would have no problem getting the basic information to build the actual resource name (using toBundleName() and toResourceName()), but it is not the case at that level.
Edit:
Ok, I found the way to do it. I'll create a ResourceBundle.Control that is extensible (using a custome addFormat(String, Class)) to store all the bundle formats, then use another method of my own to check all possible file names for a specific locale (using Class.getResource as indicated here below).
Coding speaking:
class MyControl extends ResourceBundle.Control {
private Map<String,Class<? extends ResourceBundle>> formats = new LinkedHashMap();
public void addFormat(String format,Class<? extends ResourceBundle> rbType) {
formats.put(format, rbType);
}
public boolean resourceBundleExists(ClassLoader loader, String baseName, Locale locale) {
for (String format: formats.keySet()) {
// for (loop on locale hierarchy) {
if (loader.getResource(toResourceName(toBundleName(baseName, locale), format)) != null) {
return true;
}
// }
}
return false;
}
}
If the default bundle must exists you can do:
Class.getResource("/my/path/to/bundle.properties")
and it will return an URL to the file or null if it doesn't exists.
Of course use the correct class or classloader if you have many.
EDIT: if you have resources as classes you have to check also
Class.getResource("/my/path/to/bundle.class")
In Java 6 you can store resource bundles in XML. I don't know how ResourceBundle class lookups this resource, but I bet it's in the same way.
You can load the bundles, thus making your checks, and then call ResourceBundle.clearCache() so that they are loaded again next time.
This happens once (at initialization time), and it isn't such a heavy operation, so it won't be a problem.
Or you can simply try to find whether a resource is present on the classpath. For example the fallback .properties file, or the properties file for your default locale.
Finally, after having a look at the code for ResourceBundle.Control, you have the option to do what they do in the newBundle() method.
Something like this, maybe
ResourceBundle bundle;
public PropertiesExist() {
String propsFile = "log4j";
String propsPath = this.getClass().getClassLoader().getResource(".").getPath();
File f = new File(propsPath, propsFile + ".properties");
if(!f.exists()){
System.out.println("File not found!!!!");
System.exit(-1);
}
bundle = ResourceBundle.getBundle(propsFile);
System.out.println(bundle.getString("log4j.rootLogger"));
}
public static void main(String[] args) {
new PropertiesExist();
}
This will look for the logging file, log4.properties, if not found program will exit