Ok, here is the issue. We are using an old version of Tomcat (6.0.35) because our version of linux (ubuntu 12.04) doesn't have a repository with a newer version of it. Unfortunately, there is a bug in 6.0.35 that is affecting us ( https://issues.apache.org/bugzilla/show_bug.cgi?id=53725 ). IT doesn't want to/can't change tomcat versions. They want to use the package management system, they don't want to rebuild tomcat. They can't maintain something like this on a whole bunch of servers and we don't particularly want to disable Gzip. We can deal with the corruption until we can finally upgrade.
So with that background, the real question. The changes which fix this bug reside in one single class. We came up with a crazy solution (which will probably never see production, but was more of a "this would be so terrible, lets try it!" sort of idea), How about we compile the fixed version of the class and hotswap it in. After all, tomcat and our project use the same JVM.
Is this doable/possible/more than a little crazy?
Some hurdles. We are using Java 6. The new class adds methods and fields. I'm not sure that tomcat keeps it around.
In most cases this is unreasonable to actually do. The only way to cleanly unload a class and then load a replacement is to let the ClassLoader used to load that particular class be garbage collected. This will require you to remove all references to any of the classes that ClassLoader loads (which is probably at least all of TomCat) and reload them using a ClassLoader that loads all classes like normal, except for the class you 'fixed'. You would have to make it so that it loads that class instead of the old one, while still allowing the other classes to load normally.
In short, it is possible, however it will require digging into java ClassLoaders. I'd recommend that you do not actually attempt this, as it will be very annoying to get right and it will certainly not work without shutting down the TomCat server first (since you have to reload all of TomCat's classes).
Who is doing the unzipping, Tomcat or the application? If its the application, just make a copy of the class in error to the root of your project classpath in src/main/java and put there the patched version of the class.
Upon packaging the patched class will be in WEB-INF/classes, and override the version in the server. But its overridden only from the point of view of the application, the server cannot see the patched version and still sees the buggy version.
If its tomcat itself that needs to unzip something, then its not possible to fix that without tinkering with the server.
But if its the application doing the unzipping its for sure possible, there is no obligation to use the libraries of the server we can use our own more updated copies, usually not in patches but in jars in WEB-INF/lib - the server is designed for that.
Related
After Updating log4j - to mitigate the log4shell vulnerability (CVE-2021-44228) - in class path, (or any other library generally), Do I need to restart JVM to make updates get into count?
Here, is mentioned that the "newly added classes" inside class path are getting loaded to the JVM automatically without restart, but what about the classes that are already loaded with the same name via class loader? Do they get overwritten?
The same question applies for tomcat (Although I guess it would be the same as JVM?)
Even if the new classpath would immediately be used by the JVM, there may be a number of objects instantiated from the old classes in memory. The new classes would then only apply to new instances. AFAIK log4j would not throw away it's objects during runtime.
To be on the safe side you definitely want to restart the JVM.
Is it required to restart JVM after updating log4j in classpath?
Probably yes. It depends on which classloader loads log4j.
If the log4j libraries are exclusively part of your webapps, you might be able to get away with hot-loading all of the webapps.
But you said "in classpath" and I guess that mean's in Tomcat's classpath; i.e. the shared libraries.
My advice would be not to take the risk. Restart Tomcat.
(Your systems should be designed so that Tomcat restarts are not a significant problem. There are various ways to do that. Indeed, one could argue that if downtime of your (single) Tomcat instance is an operational concern, then you should be running multiple copies.)
... but what about the classes that are already loaded with the same name via class loader? Do they get overwritten?
A classloader won't notice things have changed in its classpath. They are not designed to work that way.
And even if it did, a classloader cannot reload a class. The JVM architecture / runtime type safety don't allow it.
The hot-loading feature that (some) people use to avoid Tomcat restarts actually involves creating a brand new classloader to load the new version. The old version of the class will still exist in its original classloader, and other code will remain bound to it.
We have a web application made in Java, which uses struts2, spring and JasperReport. This application runs on glassfish 4.0.
The libraries of the application are in the WEB-INF/lib folder, and also in glassfish are installed 4 more than uses the same libraries.
Glassfish is configured to use 1024mb for heapspace and 512m for permgen, and the most of the memory consumption when i use libraries per application is in the struts actions and spring aop classes (using netbeans profiler).
The problem we are having is the amount of memory consumed by having libraries in the classloader per application because is to high and generates PermGen errors and we have also noticed that the application run slower with more users.
because of that we try to use shared-libraries, put it in domain1/lib folder and found that with a single deployed application the load time and memory consumption is much lower, and the application works faster in general. But when we deploy the rest of the applications on the server only the first application loaded works well and the rest has errors when we calls struts2 actions.
We believe that is because each application has slightly different settings on struts2 and log4j.
We have also tried to put only certain libraries on glassfish and leaving only struts2 in the application but it shows InvocationTargetException errors because all libraries depend the lib from apache-common and it dont matter if we put those lib on one place or another. Also if we put it in both places the application don’t start.
there any special settings or best practices for using shared-libraries?
Is there a way to use shared-libraries but load settings per application? or we have to change the settings to make them all the same?
Is there any special settings or best practices for using shared-libraries? Is there a way to use shared-libraries but load settings per application? or we have to change the settings to make them all the same?
These are actually interesting questions... I don't use GlassFish but, according to the documentation :
Application-Specific Class Loading
[...]
You can specify module- or application-specific library classes [...] Use the asadmin deploy command with the --libraries option and specify comma-separated paths
[...]
Circumventing Class Loader Isolation
Since each application or individually deployed module class loader universe is isolated, an application or module cannot load classes from another application or module. This prevents two similarly named classes in different applications or modules from interfering with each other.
To circumvent this limitation for libraries, utility classes, or individually deployed modules accessed by more than one application, you can include the relevant path to the required classes in one of these ways:
Using the Common Class Loader
Sharing Libraries Across a Cluster
Packaging the Client JAR for One Application in Another Application
Using the Common Class Loader
To use the Common class loader, copy the JAR files into the domain-dir/lib or as-install/lib directory or copy the .class files (and other needed files, such as .properties files) into the domain-dir/lib/classes directory, then restart the server.
Using the Common class loader makes an application or module accessible to all applications or modules deployed on servers that share the same configuration. However, this accessibility does not extend to application clients. For more information, see Using Libraries with Application Clients. [...]
Then I would try:
Solution 1
put all the libraries except Struts2 jars under domain1/lib ,
put only Struts2 jars under domain1/lib/applibs,
then run
$ asadmin deploy --libraries struts2-core-2.3.15.2.jar FooApp1.war
$ asadmin deploy --libraries struts2-core-2.3.15.2.jar FooApp2.war
To isolate Struts2 libraries classloading while keeping the rest under Common Classloader's control.
Solution 2
put all the libraries except Struts2 jars under domain1/lib ,
put only Struts2 jars under domain1/lib/applibs, in different copies with different names, eg appending the _appname at the jar names
then run
$ asadmin deploy --libraries struts2-core-2.3.15.2_FooApp1.jar FooApp1.war
$ asadmin deploy --libraries struts2-core-2.3.15.2_FooApp2.jar FooApp2.war
To prevent sharing of the libraries by istantiating (mock) different versions of them.
Hope that helps, let me know if some of the above works.
You can try to create what is known as a skinny WAR. Pack all your WARs inside an EAR and move all the common JARs from WEB-INF/lib to the lib/ folder in the EAR (don't forget to set <library-directory> in the application.xml).
I'd bet that placing the libs under lib/ or lib/ext won't resolve your performance issues. You did not write anything about the applications or server settings, like size of application, available Heap and PermGen space, but nonetheless I would recommend to stay with separate libs per app.
If you place the libs in server dirs, they will be shared among all apps. You will loose the option to upgrade only one of your applications to a new framework or to get rid away of any of them. Your deployment will be bound to a specific server architecture.
And you wrote it did not solve your problems, it even may raise new ones.
I would recommend to invest some hours into tuning the server. If it runs with defaults, allocate more PermGen and HeapSpace.
If this does not help, you should analyze in deep what's going wrong. Shared libs might be a solution, but you don't know the problem, yet. IBM offer some cool and free tools to analyze heap dumps, this could be a good starting point.
I came here in search of guidance about installing libraries that are shared among multiple applications or projects. I am deeply disappointed to read that the accepted practice favors installing a copy of every shared library into each project. So, if you have ten Web application, all of which use, e. g., httpcomponents-client, mysql-connector-java, etc., then your installation contains ten copies of each.
This behavior reminds me, painfully, of the way of thinking that motivated me to abandon the mainframe in favor of the PC; the thinking seemed to be "I don't care how many resources my application consumes. In fact, I'd like to be able to brag about what a resource hog it is." Excuse me, please, while I hurl.
The interface exposed by a library is an immutable contract that is not subject to change at the developer's whim.
There is this concept called backwards compatibility. If you break it, you create a new interface.
I know of at least two types of interfaces that adhere to the letter and spirit of these rules.
By far the oldest is the IBM System/370 system libraries. You might have Foo and Foo2, where the latter extends and/or breaks the contract made by the Foo interface in some way that made it incompatible.
From its beginnings in the Bell Labs Unix project, the standard C runtime library has adhered to the above rules.
Though it is much newer, the Microsoft COM interface specification enforces the same rule.
To their credit, Microsoft generally adheres to those rules in the Win32 API, too, although there are a handful of exceptions in that API. To a degree, they went backwards with the .NET Framework, which seems slavishly to follow in the footsteps of the Java environment that it so eagerly seeks to replace.
I've been using libraries since 1978, and my understanding was and is that the goal of putting code into a library was to make it reusable. While maintaining copies of the library code in each application eliminates the need to implement it again for each new project, it severely complicates upgrading, since you now have ten (or more) copies of the library, each of which must be updated.
If libraries adhere to the rule that an interface is an immutable contract, why shouldn't they live in a shared library directory, as do the Unix system libraries that live in its /lib directory, from which everything that runs on the host shares a single copy of the standard C runtime library, Zlib, and so forth.
Color me seriously disappointed.
Even if we enable "deploy on save" with our IDE, we still need to wait some time to propagate changes. This can be annoying espacially when we deploy small changes.
So, is it possible to run some servlet container in-memory with IDE-compatible deployment to speed up deployment and development time? Or even run whole container in-memory with server dependencies (JSP compilator etc.).
(I know that I can install Tomcat on RAMDisk, but looking for "more native" solution)
According from their site
JRebel is a JVM-plugin that makes it possible for Java developers to instantly see any code change made to an app without redeploying. JRebel lets you see code changes instantly, versioning classes and resources individually and updating one at a time instead of as a lump application redeploy. When developers make a change to any class or resource in their IDE, the change is immediately reflected in the deployed application, skipping the build and redeploy phases and preventing an average of 5.25 work weeks per year in redeploys!
http://zeroturnaround.com/software/jrebel/
The first thing you can do is to set the deployment path to your webapps directory. This way you deploy the application "exploded" without copying the whole app to another deployment directory. Make sure to let the classes be compiled into the WEB-INF/classes directory.
A second, more problematic thing is, the class loader. When the JVM runs in debug mode, some code changes made within methods will be recognized by the class loader and you would see the changes immediately. But some changes, like method signature and structural class changes will not be detected, so a restart of the JVM will be necessary. You can provide a self brewed class loader which will be able to reload anything when the underlying class files changes.
The tomcat container is loaded in memory when you start it. And tomcat loads all the applications available in webapps directory. Later as and when application classes are required are loaded. And application may load some other resources as required.
If you open the task manager on windows or similar thing on other OS, you can see that tomcat java process is always runnning once started. You may also check its current memory footprint . So it is not unloaded and re-loaded on demand.
I want to change an application by changing a component. In Java, it would seem that the swappable object could be placed in a jar. One version of the jar could be deleted and another identically named jar would be put in its place.
Is this the best practice for swappable Java components, and if not, then what?
Edit: to be clear, the mooted organization is to have a jar with the constant objects, and a separate jar with the swappable object. Runtime swappability is neither expected nor sought. Remote installation and runtime swapping is probably more sophisticated than necessary for my needs.
You should really look at Dependency Injection for this kind of use case(either Spring or CDI).
Also you could consider OSGi
Have a look at OSGI
Applications or components can be remotely installed, started, stopped, updated, and uninstalled without requiring a reboot;
Im' running this code on a Linux Red Hat with the sun/oracle JVM 1.6_23, inside a VMWare server.
After some times the JVM seem to be unable to access my anonymous inner classes.
My classpath is fine, since it works for a period.
All i got is errors like this one :
java.lang.NoClassDefFoundError: com/mycompany/impl/MyClassImpl$1
at com.mycompany.impl.MyClassImpl.markAsDeletable(MyClassImpl.java:45).
line 45 is the first line below, it can't find my new Predicate
DomaineVO domaineVO = Iterables.find(domainesVO, new Predicate<DomaineVO>() {
#Override
public boolean apply(DomaineVO input) {
return input.getId().equals(domaine.getIdentifier().toString());
}
});
Any ideas ?
Finally, i think we might have put the finger on the problem.
We are running this code on jetty, and we use automatic deploy of the .war files.
By default jetty use the java.io.tmpdir to deploy the .war files.
Our problem was only on linux, and mostly early in the morning (as soon as the first office worker use the app).
The cause was the cleaning of the /tmp at night (made by a LOGROTATE command on our servers).
Rules of thumb : Never use /tmp for too long time, and make jetty deploy war in a directory of your own.
Thanks everyone
It sounds like the JVM can't find the class file for the anonymous class. This would be named 'MyClassImpl$1.class' - if it's not present in the classpath, something must have deleted it. If it is present then there's something wrong with the JVM.
This sounds very odd. Firstly if the code works for a time, as you say, the file must be there. Secondly, it is rare for a JVM to unload a class from memory once it has been used. Some JVMs will do it in tight memory situations or as part of a GC, but as an optimisation they normally stick around.
My only guess is you are using the JVM in a situation where ClassLoaders are changing. If you are using Netbeans (especially) but I think also eclipse, then if you partially recompile the code then classloaders might not match. Is this running within an IDE?
An alternative is a ClassLoader changing. If you re-release to a running webserver or application server, then an old class will not have a matching classloader for the new instance. The ClassLoader may not be able to find the old version, even though the file is there. Are you re-releasing to an Application/Webserver?
Finally, I guess this might be possible with Serialization. If the class is Serializable, and the serialVersionUIDs don't match I guess this might be able to happen. Are you doing any object serialisation here?