Given I have context.xml with Resource definitions and I copy it to /usr/local/tomcat/conf/context.xml
How can I check that Resources were created as expected?
Is there any way how to view JNDI tree after context.xml is applied?
If you want to see what is going on inside Tomcat, you should enable JMX.
See Monitoring and Managing Tomcat 8.5.
You can then connect using the jconsole command that comes with Java, where you can see the Resources available to each of the webapps running in that Tomcat instance.
I personally never put Data Sources <Resource> elements in the context.xml file, but instead put them in server.xml and then put <ResourceLink> elements in the context's XML file (not .../conf/context.xml, but .../conf/Catalina/localhost/mywebapp.xml).
This allows multiple webapps running in the same Tomcat instance to share the database connection pool(s).
So in my instance, I can see the Resource Links for my webapp (from mywebapp.xml) below the /Catalina/ResourceLink/Context node, and the Resources (from server.xml) below the /Catalina/Resource/Global node.
I can also see the Data Sources below the /Catalina/DataSource/javax.sql.DataSource node.
Related
There's a web application and a number of environments in which it works. In each environment it has different settings like DB connection and SOAP ends-points that in their turn are defined in properties-files and accessed in the following way:
config.load(AppProp.class.getClassLoader().getResourceAsStream(
PROPERTIES_FILE_PATH + PROPERTIES_FILE_NAME));
Thus the WAR-files are different for every environment.
What we need is to build a unified WAR-file that doesn't contain any configuration and works in any environment (for now, Tomcat instance) getting its configuration from outside its WAR-file.
The answer Java Web Application Configuration Patterns, to my mind, gives the full set of common approaches but with just few examples. The most attractive way is configuring JNDI lookup mechanism. As I can guess it allows to separately configure web-applications by their context paths. But couldn't find a simple (step-by-step) instructions in both the Internet and the Tomcat's docs. Unfortunately cannot spend much time on studying this complicated stuff in order to just meet so seemingly simple and natural demand :(
Would appreciate your links at the relevant descriptions or any alternative suggestion on the problem.
If its a case of simply deploying your WAR on different environment (executed by different OS user), then you can put all your config files in the user's home folder and load them as:
config.load(new FileInputStream(System.getProperty("user.home") + PROPERTIES_FILE_NAME));
This gives you the isolation and security and makes your WAR completely portable. Ideally though, you should still provide built-in default configuration if that makes sense in your case.
The approach we've taken is based on our existing deployment method, namely to put the WAR files in the filesystem next to the Tomcat, and deploy a context.xml pointing to the WAR file to Tomcat.
The context descriptor allows for providing init parameters which is easily accessible in a servlet. We've also done some work on making this work with CDI (for Glassfish and TomEE dependency injection).
If you only have a single WAR file deployed to this Tomcat instance, you can also add init parameters to the default global context XML. These will be global and you can then deploy the WAR file directly. This is very useful during development.
I have a webservice that uses Java, REST, Jersey and runs on Tomcat8. The webservice requires access to a database. Depending on where we are in the process the we may be using a testdatabase, production database or something else. Ideally we would like to be able to set which database to use without requiring a code change and recompile.
The approach we have tried is to have a properties file defining the database parameters and use an environment variable to point to the file. This has proved troublesome, first we've had a hard time defining system properties on the Tomcat server that we can read from the application, also it seems like all the files will have to be defined on the classpath, i.e already configured ahead of time and part of the codebase.
This seems like fairly common scenario, so I'm sure there is a recommended way to handle situations like this?
Zack Macomber has a point here. Don't enable your app/service to look up its settings dynamically.
Make your build process dynamic instead.
Maven, Gradle and friends all provide simple ways to modify output depending on build parameters and or tasks/profiles.
In your code always link to the same file (name). The actual file will then be included based on your task and/or build environment. Test config for tests. Production config for production.
In many cases a complete recompilation is not necessary and will therefore be skipped (this depends on your tool, of course).
No code changes at all. Moreover the code will be dumb as hell as it does not need to know anything about context.
Especially when working on something with multiple people this approach provides the most stable long-term-solution. Customizable for those who need some special, local config and most important transparent for all who don't need or don't want to know about runtime environment requirements!
We have a similar case. We have created a second web service on the same endpoint (/admin) which we call to set a few configuration parameters. We also have a DB for persisting the configuration once set. To make life easier, we also created a simple UI to set these values. The user configures the values in the UI, the UI calls the /admin web service, and the /admin service sets the configuration in memory (as properties) as well as in the DB. The main web service uses the properties as dynamic configuration.
Note: we use JWT based authorization to prevent unauthorized access to /admin. But depending upon your need you can keep it unsecure, use basic HTTP auth or go with something more detailed.
Not sure if in this particular case it is wise, but it is possible indeed to create a .properties file anywhere on the filesystem - and link it into your application by means of a Resources element.
https://tomcat.apache.org/tomcat-8.0-doc/config/resources.html
The Resources element represents all the resources available to the web application. This includes classes, JAR files, HTML, JSPs and any other files that contribute to the web application. Implementations are provided to use directories, JAR files and WARs as the source of these resources and the resources implementation may be extended to provide support for files stored in other forms such as in a database or a versioned repository.
You would need a PreResources element here, linking to a folder, the contents of which will be made available to the application at /WEB-INF/classes.
<Context antiResourceLocking="false" privileged="true" docBase="${catalina.home}/webapps/myapp">
<Resources className="org.apache.catalina.webresources.StandardRoot">
<!-- external res folder (contains settings.properties) -->
<PreResources className="org.apache.catalina.webresources.DirResourceSet"
base="/home/whatever/path/config/"
webAppMount="/WEB-INF/classes" />
</Resources>
</Context>
Your application now 'sees' the files in /home/whatever/path/config/ as if they were located at /WEB-INF/classes.
Typically, the Resources element is put inside a Context element. The Context element must be put in a file located at:
$CATALINA_BASE/conf/[enginename]/[hostname]/ROOT.xml
See https://tomcat.apache.org/tomcat-8.0-doc/config/context.html#Defining_a_context
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 context.xml in my web/meta-inf/ folder containing database connection (pool) details. Now i want the database details for my application to be provided by end user in some properties file and context.xml reading the db connection info from the properties file instead of hard coing them in the file directly.
is it possible for tomcat to replace the placeholders from some properties file?
i read about context-manager but not sure where to place that.
Please provide your inputs.
Thanks
Abhishek
You can do it in a better way.
In our case we had different databases for different profiles, like dev, UAT, pre-prod, support etc.
So what I did was, I put my context.xml in its default location <TOMCAT_HOME>/conf.
Had the following in the resource config of context.xml:
<Resource name="jdbc/someDS"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.OracleDriver"
url="${appName.db.url}"
username="${appName.db.user}"
password="${appName.db.password}"
maxActive="30"
maxIdle="10"
defaultAutoCommit="true"
maxWait="-1"/>
I created three tomcat servers - server-dev, server-uat, server-support
and passed the corresponding values for each database in the vm arguments of tomcat in eclipse/intellij's tomcat server config (like shown below):
-DappName.db.url=jdbc:oracle:thin:#<DB_SERVER>:1521:<SID> -DappName.db.user=DB_USER -appName.db.password=DB_PASSWORD
The advantage is, the developers then don't need to change the database every-time, they just need to start a particular server. This was very handy and saved a lot of time during our development.
Adding the JNDI resources to Context.xml isn't enough. You will need to define their use in WEB-INF/web.xml also. Check this for a step by step.
As I understand it, your goal is to have application configuration outside of your .war to allow a system administrator to configure the system.
One way to achieve that is to not place the context.xml in your .war file but to distribute that file alongside with your .war.
This file then has to be placed placed in CATALINA_HOME/conf/Catalina/HOSTNAME/APPLICATIONPATH.xml (e.g. CATALINA_HOME/conf/Catalina/localhost/myapp.xml).
This way, the database connection information can be edited directly in the external context configuration file without changing the .war file, you won't need placeholders in that scenario.
This is not the most comfortable way for the user as he/she has to edit an xml file but it should be feasible for most system administrators...
You can find more information on tomcat context configuration at tomcat.apache.org/tomcat-5.5-doc/config/context.html
I'm not sure it's possible to load the details from a properties file but you can have the details in the central server.xml file rather than context.xml. Once you've achieved that, you could probably externalize the connection details using a standard XML entity reference.
Instead of putting your database connection details in the context.xml, put them in the server.xml under a section, and then add a ResourceLink element to the context.xml that creates a link between the global data source and your context.
Unfortunately the documentation is fairly weak for what you're trying to achieve.
Follow the instructions on the "Resource Definitions" section of this page (about half way down), and pay particular attention to the (tiny) ResourceLink section below it:
http://tomcat.apache.org/tomcat-5.5-doc/config/globalresources.html
If I don't have database connection information at build time, I'll just configure a resource reference and tell the admin what name they need to give the connection pool. They can configure everything in the Tomcat admin console and I never have to know about it. This also makes it easier to build a single WAR file and use it in multiple environments since the database configuration details aren't part of the WAR.
See also:
Apache Tomcat 6.0 JNDI Resources
If you do know the details at build time and want to bake them into the WAR, try Ant filters.
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.