how to reflect changes by replacing class files in tomcat? - java

I have a java application. All I have with me is a set on class files. Iwant to replace one class file with a new one. Replacing the old class file with the new one and restrting tomcat is not reflecting the changes. How can I do this? I know its not a recommended way, but all I have is just one new class file.

I've done this the way you describe before, and Tomcat reflected the changes just fine after restart.
Perhaps your application's files are in multiple locations, and you aren't replacing the class file in the correct deployment? Make sure if Tomcat is auto-expanding the WAR that you are replacing it in the expanded folder of files. If you app is deployed somewhere besides webapps, double-check where your <Context> is pointing to for its doc base.

You can configure Tomcat and make your webapp "reloadable". To do so, add reloadable=true to the <Context> element of your webapp.
Set to true if you want Catalina to monitor classes in /WEB-INF/classes/ and /WEB-INF/lib for changes, and automatically reload the web application if a change is detected. You can use the Manager web application, however, to trigger reloads of deployed applications on demand.

Related

How can a servlet do a hot re-deploy of itself

Is there a way for a Servlet to do a hot re-deploy the webapp it is part of?
I know that I can configure Tomcat to do a hot re-deploy on changes to web.xml but I can't find any way to do the same from java code. I don't want tomcat to having to watch the web.xml for changes all the time.
I believe it can be done using JMX.
The Tomcat Manager is a web application that can be used interactively (via HTML GUI) or programmatically (via URL-based API) to deploy and manage web applications.
There is the link - http://tomcat.apache.org/tomcat-7.0-doc/deployer-howto.html
A Servlet has a life cycle that depends on the container. This is explained here
http://docs.oracle.com/javaee/5/tutorial/doc/bnafi.html
What this means is from the web.xml the container figures out a match depending on a request and if there is such a class that exists it loads it as a classloader resource. Once this has happened the instance stays loaded till the container is shutdown so replacing .class files wont actually achieve the "hot-deploy" unless you set the reloadable flag in the tomcat's context.xml
http://tomcat.apache.org/tomcat-5.5-doc/config/context.html#Common_Attributes
In any case, Tomcat or not, once a resource has been loaded by a ClassLoader changing the .class files wont exactly change the behaviour of the running jvm which you would probably know. So even deleting the class files from the file system also wont affect the running java process in ordinary situations.
However it may be possible that a servlet can start a background task that does a basic file copy of the new .class files you want to 'hot deploy' (if the context attribute 'reloadable' is true). This then forces these classes to be reloaded and so you achieve a hot deploy. So although this is out of the scope of what a servlet is designed to achieve the answer is yes.
Hope this helps.

Java class reloading

I'm using jboss server and having all my classes inside a jar file.
Now if I change any of the java files, I need to replace the class file in the jar and have to restart the server.
Is there any way to dynamically load the newly created class file without the server restart?
Thanks in advance.
I've had great success with JRebel (http://www.zeroturnaround.com/jrebel/). This is a very good product that enables seamless class reloading for the vast majority of modifications you can make to a Java class. There is no restarting of the app sever or even the application required, classes simply reload behind the scenes.
It comes with a free 30 day trial so you can see if it works for you.
(Disclaimer: I'm in no way connected to Zero Turnaround)
It appears that you have to trick the server into reloading your application by modifying web.xml -- meaning you can open web.xml in an editor enter a space then delete and save the file or change the modification date on the file with a utility.
JBoss doesn't seem to have a handy feature like Tomcat's reloadable="true" flag in Tomcat's Server.xml file.
there are a number of solutions, none of them particularly clean or easy.
As stated, changing the web.xml will cause the context to reload and hence refresh the source code and this can be done without restarting the server. This works because "WEB-INF/web.xml" is configured as WatchedResource in the TOMCAT/conf/Context.xml file. That is every context inherits this setting and automatically watches this file. You can remove this behaviour but you can also provide WatchedResource values in your own web.xml to watch additional files. While I don't recommend it, you could add all of your class files to this and the context would reload when you change one file.
A better solution relies on the fact that a Class can be reloaded when you discard the ClassLoader that loaded the Class. Therefore if you manage your hot swappable code in your own ClassLoader then you can refresh your code without restarting the context if you refresh the ClassLoader. Easier said than done, unfortunately but it may get you started.

Java EE EAR shared location of read/write resources within clustered environment

Within a Java EE environment (happens to be WAS 6.1 but could be any application server) I need to place a XML file, which is a configuration file, so that I can read and write to it.
This needs to be available in a clustered environment so I am looking at using the class path to load the file.
I am thinking I can store this file in the EAR root, reference it in the manifest and then load and save it.
I have tried this approach by having my file in a JAR and making this available via the MANIFES and I can load the config file from the class path no problem using the following.
this.getClass().getClassLoader().getResourceAsStream("configFileName");
That loads the file that is in the JAR, which is fantastic. But if I want to edit this file, programmatically, I cannot access the JAR files location (the EAR root) it returns me an interpreted path like this:
/usr/IBM/WebSphere/AppServer/profiles/AppSrv01/installedApps/localhostNode01Cell/MyApp.ear/MyApp.war/TB_config.jar
That is not the correct location of the JAR the correct location is at MyApp.ear.
So the question is: how can I access and update (copy contents, create new, save, delete old) the JAR with my config file.
Or should I put the config file somewhere else?
What is the standard Java EE to make files that need read/write access available to WARs on a cluster?
Ok I have built a solution for this. It is more WebSphere based (our platform) but it is J2EE and I am suprised it was not mentioned. Basically I have used JMX to synchronise the nodes. The files are stored, and saved to, the deployment manager the nodes are then resynchronised using JMX calls and then the engines withing the applicaitons are restarted by calling servlets within the applications.
It works a dream
So #stacker, nodes are managed and the manager distributes files to the nodes.
The problem that you've hit is not unique. A lot of Java EE programmers can struggle with providing a "configurable" property file to administrators of a cluster. And the solution that you've chosen, well, has its limitations.
The problem with embedding a config file inside a JAR, is absolute path or the physical path of the file, in case you need to update it. If your container will not explode your EAR and WAR files, then placing the config file alongside the code is a bad idea - the administrator will have to deploy a newer version of the EAR/WAR/JAR. That is unless, of course, you can configure the container to explode the artifacts - WebLogic Server does this, I'm not sure about WAS.
There are several ways to resolve this problem:
Store the config file in a SAN that is accessible to all the nodes in the cluster via a 'canonical' path. That way, you could locate the file from any node in the cluster and update it. Remind yourself to restrict access to this directory. Although this sounds simple, it need not be - Java objects might have to be 'flushed' across nodes, once the configuration file has been updated. Moreover, you might have to cater to the scenario where property files can get edited outside the application.
Use a database. Much simpler and almost hasslefree, except that the Java objects might have to be flushed again.
Use a MBean. As good as a database, except that I haven't known a lot of people vouching for the MBean support in WAS. Also, I'm not really sure if object states can go haywire across a cluster, in this case.
You cannot write to an ear file, you should place the XML file in the DB as a text lob (large object).
Actually, as I am using WebSphere, it appears I can use the dynamic cache provided by the WebSphere deployment manager. The last chapter in the link below dicusses the use of the Dynamic Cache providing a shared object in a cluster. The configuration file is XML that is parsed as such by the engine (into a Document object) of the application and so is a Java object, thus it can be placed into the DistributedMap.
Looks like a clean solution. Thanks all for reading and your replies.
http://www.ibm.com/developerworks/websphere/library/techarticles/0606_zhou/0606_zhou.html

How to configure Classpath in Websphere application server?

I need to add log4j jar in classpath of WAS server but I am unable to put it. Please suggest.
I tried to add this jar in start script of WAS server.
As Michael Ransley mentioned, you need to determine who needs log4j. If it is a web application, then WEB-INF/lib is the best location.
If it used by EJB components then place the log4j as a utility jar in the EAR.
Alternatively, create a Shared Library and associate the shared library to your application.
Another choice would be to associate the shared library to your server (instead of the application) in which case, it becomes available to all the applications that are running on that server.
Storing in the App Server lib/ext or the other base classpath(s) is usually a bad idea. The reason is this could cause conflicts (log4j does not cause conflicts but other Jars could likely cause conflicts) and might prevent the application server from even starting up.
Also remember, depending on where the log4j.jar is kept (or associated via shared libraries) different class loaders would be picking up this JAR file.
From the Admin console, select Environment->Shared Libraries
Then in the page displayed, select New and follow the directions to add you library.
It depends why you want to add it. Do you need access to log4j from within your applications, if so you can add it into the application (i.e. in the WEB-INF/lib directory), if you are writing a component that needs to run within the WebSphere runtime (i.e. a JMX library) then you can put it into WebSphere/AppServer/lib/ext.
If you have multiple webapps that needs to share the same log4j.xml, you could drop it in IBM\WebSphere\PortalServer\shared\app\\
Otherwise, put it in web-inf/lib of your web app.
PROFILE_ROOT/properties
this folder is on the classpath, and its used to store properties
if you have different profiles for example for test or integration they may have different settings
source

Restart tomcat when a class file is changed?

Why do we need to restart a tomcat server whenever a class file is changed, is there no other way?
You can configure Tomcat and make your webapp "reloadable". To do so, add reloadable=true to the <Context> element of your webapp. About the reloadable attribute, the documentation says:
Set to true if you want Catalina to monitor classes in /WEB-INF/classes/ and /WEB-INF/lib for changes, and automatically reload the web application if a change is detected. This feature is very useful during application development, but it requires significant runtime overhead and is not recommended for use on deployed production applications. That's why the default setting for this attribute is false. You can use the Manager web application, however, to trigger reloads of deployed applications on demand.
There certainly is! Start Tomcat in development mode, then each webapp will restart itself upon being redeployed.
From the Tomcat docs:
The servlet which implements Jasper is configured using init parameters in your global $CATALINA_BASE/conf/web.xml.
...
development - Is Jasper used in development mode (will check for JSP modification on every access)? true or false, default true.
There are settings you can change to adjust what exactly Tomcat will look for to check for updates. I usually deploy individual class files to their appropriate directory under WEB-INF/classes and then
touch WEB-INF/web.xml
to kick-start a restart of the application; I think web.xml is one of the files Tomcat checks by default.
On a more general note, the reason you have to do this is because in Java, when a classloader loads a class, it cannot unload it. What Tomcat has to do is use a new classloader and reload all the classes it needs.
Check out JRebel.
If you develop, your IDE should be able to do this transparently on a suitable server. E.g. the Dynamic Web Project in Eclipse knows how to talk to Tomcat.
If you deploy, then create WAR-files and deploy those. Tomcat knows how to redeploy a WAR-file.
If you're using WAR files to deploy, you can set autoDeploy=true in the Tomcat config, which causes Tomcat to watch the web application root ("webapps" by default) for new or changed WAR files. If such a file is found, it is automatically deployed.
As Pascal Thivent said, though, you can use the Tomcat Manager application (/manager/html) to start, stop, deploy, and undeploy specific applications. If the files you're changing are in a specific application, this is a good way to get Tomcat to recognize the changes.
Besides setting autoDeploy=true in server.conf , you also should be careful not to put any classes in the shared classloader. Classes which are loaded by the shared class loader cannot be re-loaded.
Your question doesn't actually say whether you are concerned about a production downtime (i.e. reduce it by reloading the classes) or you want non-stop development. So I will try to clarify using the following points:
1) using <Context reloadable=true... in your catalina.home/conf directory you can make sure that your webapp reloads when a any class changes. You can add the resource change watchlist in <WatchedResources> element.
2) But this will reload the context, re-initialise the classloader, empty it's cache, and everything will be as if the webapplication has just started.
This approach will still leave your server unusable, because you have reloaded the Servlet's context. The true "Reload" is
1) You swap the byte code of the class, with some restrictions
2) JVM will return that class when "loadClass()" is called for that classloader.
This is java instrumentation. You can write your own agent which can hook into your JVM either at the beginning or in flight. However, you cannot define new method, and change static variables. These are JVM native restrictions (for Oracle HotSpot JVM, that I know of). You can use a different JVM e.g. DCEVM which doesn't have such restriction. So it's up to you how you want to handle your problem. If you know what you are doing (!), you can get away with replacing classes one-by-one. And you can even define a "Brand New Class", reference that class object/method in an existing/loaded class and instrument it to to pick up changes.
I hope this helps. All the answers here are what you need to make your decision.

Categories

Resources