As I understand it, JBoss* monitors a variety of file types in /deploy and performs certain actions when the file changes. For example, JBoss will redeploy an EAR when its last-modified time changes.
Therefore, I could use some really nasty code to make an EAR redeploy itself, like this:
URL url = this.getClass().getClassLoader().getResource("../RavenWeb.ear");
String path = url.getPath();
File ear = new File(path);
ear.setLastModified(System.currentTimeMillis());
But what I really want to do is just have JBoss redeploy the webapp when an external config file changes. Say the config file lives at C:/foo/bar.properties.
Is there an MBean or some other way getting this done that won't get me mauled by velociraptors?
*I'm using JBoss 5.1.0, if it matters.
I think your best shot is having a MBean that will reload your config file whenever you call a function on it. If you wan't this to happen automatically, you can also consider having a MBean handling the configuration file for you. This way, you can just update MBean properties instead of changing a configuration file.
I've copied the Log4JService implementation and put it in a .sar.
It just simply polls the configuration file, parse it and put a Configuration object in the JNDI, so that I can retrieve it in my application. In this way you don't have to redeploy the entire application, and you can use the new configuration in the app.
If you have to do something else than simply reloading the app, you can do it in this service.
Related
I'm using spring mvc and tomcat as a server. I want to be able to change a jndi field that is Autowired(as String):
<jee:jndi-lookup id="someMessage" jndi-name="someMessage"/>
in one of the my services, that is referenced to conf/context.xml of Tomcat, that looks something like this:
<Environment name="someMessage" value="Change this." type="java.lang.String" />.
However, when I change the value on context.xml, this change is not reflected on my service managed by spring, unless I restart server. Is there anyway to reflect this change without restarting or redeploying war? I know there is a solution to include such a dynamic field in one of properties file and then use commons configuration library to reload the changes, but I'm looking for a solution to keep this field on my conf/context.xml...
I think that is not possible. Why don't use a property file or a static class?
As far as I know, it's impossible if you put it into the conf/context.xml of your tomcat home as the following doc shows:
StandardContext.html#reload(): If the context.xml has changed, you should stop this Context and create (and start) a new Context instance instead. -- i.e. can't achieve by original context
Reload Existing App: Reload an existing web application, to reflect changes in the contents of /WEB-INF/classes or /WEB-INF/lib. -- i.e. not reflect the change of context.xml
But you can define your app's /META-INF/context.xml, which will be packed into war and you can replace war without restart server.
I need to load a file from within a directory in the root of a WAR using Spring
This is the directory structure
rootOfWar
--static-dir
---- my-file.css
--WEB-INF
---- classes
.....
It is a normal WAR.
In a Spring #RestController I need to be able to read and write to my-file.css file. What is the best way to get the File, ServletContextResource or?
More Details
- The location of the file is out of my control I cannot move the file.
- The jee container is Tomcat.
- The Spring version is current 4.1.6
- The Spring environment is not using XML only annotations with WebApplicationInitializer, WebMvcConfigurerAdapter and an annotation configuration class.
Is there another way to do this like specify a file as a resource in the configuration so that it is loaded by the frame work and accessible within the application?
Basically I have JEE knowledge but my Spring knowledge on best practices concerning read/write are lacking.
If you need to modify a file you should not make it part of the WAR. Store it somewhere outside the web package and reference it there. Everything else will lead to problems, especially when you deploy to Websphere which is often run in a restricted environment where writes are rejected.
But I consider overwriting files in the web path bad design, because you are likely to run into caching issues. Better write a servlet that generates the CSS you need. If you would be able to name the content that should overwrite your css file, you are also able to render this dynamically.
Something like this may be already sufficient:
#RequestMapping(value = "/my.css", produces = "text/css;charset=UTF-8")
public String showCss() {
return "<here goes your css>";
}
(This is written from my memory and not tested).
The good thing is that you can modify the css any time you want and even set caching information as needed.
I have to deploy my web app to a shared server where I can't edit the context.xml file to set a new resource factory. Is there a way I could place ALL my hibernate datasource configurations in a file outside my .war, but still inside the deployment folder (the one I have access to).
My ultimate goal is to develop a "portable" web app, so I can easily migrate from one server to another, just editing manually my database configurations in a datasource file. Does anyone knows a functional way to do it?
Ps. I imagine Spring would help with this matter. But I don't feel like to set up it for a simple web app or just for this purpose.
According to http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html#context.xml_configuration you can have a per-application context file as well, however that must of course be deployed inside your war file. Your best bet might be to modify your build file so that it uses the correct context.xml when creating the war.
In ASP.NET, there is web.config which can hold application-wide settings. Is there a corresponding file (residing outside of the war or jar archive) for a Java EE Servlet?
What I need is some place to point out a configuration file, which currently holds four attributes which in turn, taken together, leads to the database where the rest of the data and configuration is stored. (Server, database, username and password.) These values need to be easy to change without repackaging and redeploying the entire application, hence the configuration file, but hardcoding the path to the configuration file in the application (even if it is as a constant) seems far from optimal.
Any hints? I've tried Google but found very little that seemed relevant - and what I did find appeared hideously over-engineered for my needs.
In ASP.NET, there is web.config which can hold application-wide settings. Is there a corresponding file (residing outside of the war or jar archive) for a Java EE Servlet?
That's the web.xml. You can define settings as <context-param> entries.
<context-param>
<param-name>foo</param-name>
<param-value>bar</param-value>
</context-param>
It's available by ServletContext#getInitParameter(). The ServletContext is in turn available anywhere.
String foo = getServletContext().getInitParameter("foo"); // Contains "bar"
You can also access it by EL.
#{initParam.foo} <!-- prints "bar" -->
What I need is some place to point out a configuration file, which currently holds four attributes which in turn, taken together, leads to the database where the rest of the data and configuration is stored. (Server, database, username and password.) These values need to be easy to change without repackaging and redeploying the entire application, hence the configuration file, but hardcoding the path to the configuration file in the application (even if it is as a constant) seems far from optimal.
As per the emphasis, I'd use a properties file for this particular purpose which is then placed in a path outside the WAR. You just need to add this path to the Java runtime classpath. Then you can obtain it as classpath resource:
Properties properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("filename.properties"));
// ...
However, with the particular sole purpose to serve a DB connection, you're indeed better off with a servletcontainer-managed datasource as answered by Qwerky. All you possibly would need to configure is then just the datasource name.
If this is a web app then you'd be better served configuring the database connection as a resource on the server, then getting your app to retrieve it using JNDI. Your app server will have documentation on how to do this, its a basic task.
99% of serious web apps do this, the other 1% should.
You can have your application load an arbitrary external file by simply passing the path as a command-line parameter (to the servlet container startup script). Then store the values in the ServletContext
I've managed to deploy a .war to the Jboss web container containing and read the pom.properties located under /META-INF/groupid-dir/artifactid-dir/
To access the file I've used the following code inside a JSP in the same war:
ServletContext servletContext = getServletConfig().getServletContext();
InputStream in = servletContext.getResourceAsStream("META-INF/maven/groupid-dir/artifactid-dir/pom.properties");
This works just fine. But I want to be able to dynamically read pom.propertes from ALL .war deployed in the container. Is this possible or do I only have access to the context for the one war holder my jsp?
-mb
Basically, your application is running on the same machine as the JBoss container, so accessing the files on the local filesystem should be possible, much in the same way you're accessing your own .properties file. I'm not familiar with anything that should prevent you from doing this.
If you want to access files within the war file, you'll need to use the java.util.zip package, as war files are of course normal zip files. Just a friendly reminder.
You will likely have to do something tricky like go through the JBoss MBeans. I realize this is vague, but consider looking into that approach. Here is a link on how to get the MBean server from an application within JBoss (add http://) www.jboss.org/community/wiki/FindMBeanServer (Stackoverflow is preventing me from pasting a link). I would imagine that you could find the Jboss Web mbean, peel off all web application mbeans, then ask each one for its classloader, then proceed to do what you already mentioned.
I don't think that reading a zip or using a jboss mbean are the right way.
I don't think it is tricky and you were on the right track by using ServletContext.getResourceAsStream.
You can probably use ServletContext.getResourcePaths, but several times it seems, to identify subdirectories groupid and artifactid.
Something like
servletContext.getResourceAsStream(servletContext.getResourcePaths(
(String) servletContext.getResourcePaths("/META-INF/maven/")
.iterator().next())
.iterator().next() + "pom.properties")
or
servletContext.getResourceAsStream(servletContext.getResourcePaths(
(String) servletContext.getResourcePaths("/META-INF/maven/")
.iterator().next())
.iterator().next() + "pom.xml")
for pom.xml
If the WAR file is exploded as folder , you should be able to use
String basePath=getServletContext().getRealPath("/");
This approach may not work if WAR file is in archive format
You can only look for resources in your current classpath. The normal operation of a web container is to create a specific classpath for each deployed artifact without access to the other artifacts deployed in the container.
This is very important to avoid artifact A which uses foo-1.0.jar to not accidentially use foo-0.9.jar which is deployed with artifact B.
Hence you will need ask the container for help. This in turn mean you need to write container specific code to do so. This will make you vendor dependent - you may not want that.