Problem using Quartz library in Liferay/Glassfish with Vaadin - osgi

I am facing a weird problem to get the Quartz library run in my liferay portal in Glassfish server. The application is divided into two parts a Vaadin based web app which will start/stop the quartz job and another which contains the jobs logic.
As the job logic part is dependent on the Job interface I have to deploy the Quartz as an osgi library. By doing that everything works fine and my web application can see the installed job module but at the time of starting the job it gives following error.
previously initiated loading for a different type with name "org/quartz/Trigger"
I guess this comes because I have given the Quartz library in my web-inf/lib as well. But if I remove that it throws another error for Quartz dependencies.
The only possible solution I have right now is to remove the Quartz dependencies from the second component which has the job business logic (rather implements org.quartz.Job; create another interface).
Is there any other way to sort this out???

Trying fixing your quartz dependencies in the WAR file - use import-package and remove the 2nd quartz from WEB-INF/lib.
Also make sure the quartz dependency is actually a bundle or that you are dynamically wrapping it.
It sounds like you have classloading issues due to multiple copies of Trigger. The error message is quartz telling you it's loaded Trigger from a different classloader than previously. You definitely don't want two identical versions of a jar in your app.

Related

Can you replace a Spring Boot jar while the application is running?

In our Linux environment applications are restarted periodically (the reasons aren't important here). It would be convenient for us to deploy new versions of an application by copying the application Spring Boot jar on top of the existing (old) jar thereby overwriting it and then simply wait for the application to restart (that is, the JVM running the application to restart).
However, this seems to not work. We get different kinds of errors - sometimes the app just hangs, sometimes we get a ClassNotFoundException. It's as if Spring Boot (or something inside Spring Boot) reopens the jar and expects it to be the same one it was when the application was originally started.
We had a look through Spring's common application properties, but didn't see anything appropriate. Is there a way to make this work? When we were using WAR files we configured the servlet container to unpack the WAR file and run from the unpacked version. Can we do something similar with Spring Boot?
First of all the errors you are experiencing can come from multiple sources. Usually replacing the file from a process is not a big problem as the whole file is loaded into memory before execution. Java is a little bit different, because the actual process that is running is the JVM and it only loads the jar file from disk. The JVM loads classes only on demand, this means if there was any class that was not loaded before it will try to load it and most likely fail, if the jar file is different. In the case of spring boot there are also other resources (such as HTML files) inside the jar file that are dynamically loaded.
You mentioned you are using a linux environment. If you can just replace your startup with a script you can just copy the jar and start it from the copied location:
#!/bin/bash
JAR_NAME="spring-boot.jar"
NEW_JAR_NAME=".$JAR_NAME" # Use an appropriate name here
cp $JAR_NAME $NEW_JAR_NAME
java -jar $NEW_JAR_NAME
rm $NEW_JAR_NAME
Now every time you start the application a copy is being made and started from there. You can replace the original jar and on the next restart the new application will load.
You coud also use rsync instead of cp to avoid copying the same jar twice, if the application is restarted multiple times without changing the jar.
It would be convenient for us to deploy new versions of an application
by copying the Spring Boot jar on top of the existing (old) jar and
then simply wait for the application to restart
Why would you do such a thing to yourself? You are trying solve a usecase that's against best practices, sound like asking for trouble just to avoid an app restart. When you are doing a deployment, you need to make sure the deployment went through, otherwise how will you troubleshoot if something goes wrong in your application, you will have one more variable in hand when you troubleshoot, i,e the uncertainty of current version of the code.
If you are having downtime while deploying (I am assuming thats why you want to limit the restarts), why don't you bring up another instance with the newer version of code and once its healthy shutdown the old one

How can I tell Spring Boot to place some of the classes at the root of the jar instead of BOOT-INF?

I'm trying to set a custom log Handler in my Spring Boot (version 2.6.3) application. The result is a ClassNotFound as described in this other question
Can't override java.util.logging.LogManager in a Spring Boot web application: Getting java.lang.ClassNotFoundException on already loaded class
Based on the answer to that question, it seems I need my Handler and all its dependencies to be placed into the root of the executable jar.
Is there a direct way to accomplish this during the Maven build, i.e. not by extracting and repackaging the jar myself post-build?
This issue is a result of BOOT-INF fat jar structure introduced by Spring Boot 1.4.
There is currently no straightforward solution, and it appears some of the Spring Boot maintainers do not agree there is a problem, so it could be a long time before the situation changes:
Issue #6626: Make it easier to package certain content in the root of a fat jar
Issue #12659: Starting executable war with -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager produces a ClassNotFoundException
WORKAROUND #1
I had to do two things to get my application working again with a custom log handler. 1) use Maven Shade to package up the log handler with all its dependencies, and 2) launch the app with using the PropertiesLauncher class in the command line instead of using java -jar:
java -cp executable.jar:logger-shaded.jar -Dloader.main=mypackage.myapp org.springframework.boot.loader.PropertiesLauncher
The executable.jar, logger-shaded.jar, and mypackage.myapp are placeholders specific to my project, so adjust accordingly.
WORKAROUND #2
If the handler is loaded from code in a config class or from main() instead of being specified in the file loaded via java.util.logging.config.file, as discussed in the comments to the answer in this other question, then everything works as expected. I actually prefer this over Workaround #1 as it results in a smaller deployment, but it does require writing a few more lines of code.

Spring Batch disable Spring Boot AutoConfiguration for specific jobs

I have multiple jobs for my Spring Batch application, but only a single job uses some specific Spring Boot auto configuration features:
a job that uses spring-data-jpa auto configuration, to configure a database for business transactions (not for Spring Batch management)
a job that does not use the database at all
I have packaged both jobs in the same unit because it makes sense from business perspective. Both jobs will work together and the output of one job will be the input of the other job.
Is it possible to disable database specific auto configuration when I run the second job?
I just tried using profiles and I have disabled the autoconfiguration for a specific profile. I am pretty happy with this solution but I wonder if there are other solutions?
This is similar to trying to lazy load beans specific to a given job: How to apply something like #Lazy to Spring Batch?. While the Spring profiles feature may fix your issue, I believe it is working around the root issue which is packaging all jobs in a monolithic way.
I would package each job separately and this problem (and many others) disappears by design. There are several advantages to this approach:
Independent lifecyle management (bugs, features, etc)
Flexible deployment
Separate logs
Separate configurations (as in the current issue)
Easier/Better scalability
And all the good reasons to make one thing do one thing and do it well.

Spring Integration Invoking Spring Batch

Just looking for some information if others have solved this pattern. I want to use Spring Integration and Spring Batch together. Both of these are SpringBoot applications and ideally I'd like to keep them and their respective configuration separated, so they are both their own executable jar. I'm having problems executing them in their own process space and I believe I want, unless someone can convince me otherwise, each to run like they are their own Spring Boot app and initialize themselves with their own profiles and properties. What I'm having trouble with though is the invocation of the job in my SpringBatch project from my SpringIntegration project. At first I couldn't get the properties loaded from the batch project, so I realized I need to pass the spring.active.profiles as a Job Parameter and that seemed to solve that. But there are other things in the Spring Boot Batch application that aren't loading correctly like the schema-platform.sql file and the database isn't getting initialized, etc.
On this initial launch of the job I might want the response to go back to Spring Integration for some messaging on Job Status. There might be times when I want to run a job without Spring Integration kicking off the job, but still take advantage of sending statuses back to the Spring Integration project providing its listening on a channel or something.
I've reviewed quite a few Spring samples and have yet to find my exact scenario, most are with the two dependencies in the same project, so maybe I'm doing something that's not possible, but I'm sure I'm just missing a little something in the Spring configuration.
My questions/issues are:
I don't want the Spring Integration project to know anything about the SpringBatch configuration other than the job its kicking off. I have found a good way to do that reference to the Job Bean without getting my entire batch configuration loading.
Should I keep these two projects separated or would it be better to combine them since I have two-way communication between both.
How should the Job be launch from the integration project. We're using the spring-batch-integration project with JobLaunchRequest and JobLauncher. This seems to run it in the same process as the Spring Integration project and I'm missing a lot of my SpringBootBatch projects initialization
Should I be using a CommandLineRunner instead to force it to another process.
Is SpringApplication.run(BatchConfiguration.class) the answer?
Looking for some general project configuration setup to meet these requirements.
Spring Cloud Data Flow in combination with Spring Cloud Task does exactly what you're asking. It launches Spring Cloud Task applications (which can contain batch jobs) as new processes on the platform you choose. I'd encourage you to check out that project here: http://cloud.spring.io/spring-cloud-dataflow/

class casting of runtime added classes

I'm having a problem I simply can't get my head around.
I'm creating a jsf application where I (as administrator) can upload a jar file, and that way around update the application.
Through this tutorial: http://docs.oracle.com/javase/tutorial/deployment/jar/jarclassloader.html I have managed to classload the jar file. The first issue is that I can only class load as "Object" and not cast to an other class type. I get a ClassCastException.
JarClassLoader jcl=new JarClassLoader(url);
Class cl= jcl.retreiveClass(jcl.getMainClassName());
Object ob=cl.newInstance(); //I would like to make this a RouteBuilder object instead of Object
Concretely I'm using Apache Camel, where I can add routes to an existing "core" (CamelContext). What's happening is that I have the core of apache camel running in my web app, and I can then add routes runtime. It's a route I want to package as a jar and load into the app runtime (I want to develop and test the route in my local environment, and then afterwords upload it to the production application). A concrete route is just a simple java class that extends RouteBuilder. I want to upload the jar, classLoad (URLClassLoader) the main class (maybe the whole jar? - does that make sense?), and convert it to a RouteBuilder. This seems to be impossible. I have chosen to upload the jar file to a folder outside my war, so that the routes do not get erased when I restart the webapp (is this smart or should this be done in an other way?). Is that a problem regarding name spaces? Furthermore, I haven't been able to find out whether I need to traverse my entire jar file and classload ever single class inside. Any comments on that?
To me it seems like I have some fundamental misconceptions on how extending / updating a java application is done. I simply can't find any good examples/explanations on how to solve my problem and therefore I conclude that I don't get this on a conceptual level.
Could someone elaborate on how to extend a running jsf application (I guess the same issues are relevant in native java apps), explain how to upload and class load a jar at runtime, and how to cast loaded classes to other class types than Object?
Thanks
Lasse
If you are interested in loading Routes without stopping your application you could consider using an OSGi container like Karaf. Karaf provides support for Apache Camel routes out-of-the-box: http://camel.apache.org/karaf.html
All class loading is managed by the OSGi container and you just need to run some commands to update things. I am not sure if this could work with your JSF application but it worths to take a look.

Resources