When using Tomcat, I've always treated web.xml as a kind of .htaccess or httpd.conf equivalent. It seems natural that there might have to be some way of configuring a web server.
However, I don't quite understand the purpose of context.xml. For instance, when working with JDBC, why do I have to add a resource-ref in web.xml and also a Resource with even more info in context.xml? Could I eliminate the context.xml file and somehow instantiate the DataSource in my code? I am asking because hypothetical examples like that help me understand.
EDIT: I am trying to understand what is happening in configs like this, in /META-INF/context.xml:
<Context>
<Resource name="jdbc/postgres" auth="Container" type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver" url="jdbc:postgresql://127.0.0.1:5432"
username="postgres" password="yes" maxActive="20" maxIdle="10"
maxWait="-1" />
</Context>
and, in WEB-INF/web.xml:
<resource-ref>
<description>postgreSQL Datasource example</description>
<res-ref-name>jdbc/postgres</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Why do I have to put both of those in there to use JDBC? What are they doing exactly and is there another way of doing the same thing but in the Java code? Like I said, not because I want to, but because I want to understand what they are doing better.
I don't quite understand the purpose of context.xml
context.xml is called from the web.xml through <context-param> tag. As you web.xml loads first when an application is created and it will create the references for the contexts that are configured in it.
I don't quite understand the purpose of context.xml
So, the purpose of context.xml is adding separation of codes. you can have separate contexts for different purposes . for example For Database connectivity, using other frameworks etc..,
Could I eliminate the context.xml file and somehow instantiate the DataSource in my code?
Yes ,you can do that by configuring the datasource in web.xml itself.
Hope this helps !!
To your initial questions:
I don't quite understand the purpose of context.xml
In Tomcat, you'll frequently see the term "Context". When you see this it's just referring to your application (i.e. Context == your web app). Thus /META-INF/context.xml is the configuration file specific to your application (actually, it's one of the configuration files because there are others).
For instance, when working with JDBC, why do I have to add a resource-ref in web.xml and also a Resource with even more info in context.xml?
You don't. You do not need to add anything to web.xml. If you define the resource in /META-INF/context.xml, Tomcat will create your resource and expose it through JNDI. You can then retrieve it as you would any resource from JNDI.
Could I eliminate the context.xml file and somehow instantiate the DataSource in my code?
Possibly. It's common to see Spring users create a DataSource in their Spring bean definitions. If you're not using Spring, you could still do it, but it would be more work.
Regardless of how you do this, if you setup the DataSource in your application you lose some flexibility. For example, you cannot share the DataSource across multiple applications and your application has to know how to set up the DataSource. If you define the DataSource in the server's configuration (i.e. with a Resource tag) then your application does not need this information.
To the response by san krish:
So, the purpose of context.xml is adding separation of codes. you can have separate contexts for different purposes . for example For Database connectivity, using other frameworks etc..,
The purpose of the Context tag is to configure the context (i.e. your application). It might provide you with the ability to pull certain aspects of your application, like the DataSource, out of the code and into configuration, but that's just the benefit of externalizing your configuration. It's not the purpose of this file.
Yes ,you can do that by configuring the datasource in web.xml itself.
No, with Tomcat you cannot configure a DataSource strictly through web.xml. It's just not possible to provide all of the information in web.xml that is required to create a DataSource. Because of this, you need to define a Resource tag for your DataSource and it is redundant to specify your DataSource in web.xml.
Related
I got a legacy EJB 2 application which I deploy to Websphere 8.5. The application has dependencies, which define JNDI bindings to a DataSource in /META-INF/ejb-jar.xml and /META-INF/ibm-ejb-jar-bnd.xml.
I'm not allowed to change the code in those dependencies and neither can I change the Websphere's config. But I could make changes to the config files in the jar files.
I want to override the effective JNDI bindings in my application. Is it possible to define a file that will be added to the Ear to override those bindings?
snippet of the ejb-jar.xml:
<resource-ref id="ResourceRef_1248968390265">
<res-ref-name>jdbc/CentralDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
ibm-ejb-jar-bnd.xml:
<session name="FooJob">
<resource-ref name="jdbc/CentralDS" binding-name="jdbc/VeryCentralDs" />
</session>
Is it possible to override this JNDI name (VeryCentralDs) somewhere?
Yes, it is possible to override resource reference bindings at deployment time. This knowledge center article steps through deploying an application. Watch for the step "Map resource references to resources" which is documented here. This is where you can fill in the target JNDI name that you want the resource reference bound to.
Tomee has several locations where Resources can be defined:
Inherited from Tomcat/Catalina
Server
${catalina_home}/conf/server.xml
${catalina_home}/conf/context.xml
Application
${catalina_home}/conf/Catalina/localhost/appcontext.xml
${webapp}/META-INF/context.xml
Introduced by Tomee
Server
${catalina_home}/conf/tomee.xml
${catalina_home}/system.properties
Application
${webapp}/WEB-INF/resources.xml
Not sure, but I assume also some per application properties.
This is all confusing to me. I simply want to install a connection pool at java:comp/env/jdbc/mydb.
There are additional several notes I want to take:
I might want to consider defining the resource server side - so passwords are not part of the deployment.
I might want to consider the choice of one connection pool instantiated per webapp deployed, or one globally connection pool shared for all webapps.
I might want to restrict a connection pool (with given username/password) for just one webapp, although not deployed with the webapp (hence the choice of conf/Catalina/localhost/appcontext.xml).
I am aware of following documentation:
Tomee Directory Structure
Tomee Application Resources
Tomee Admin/Configuration/Resources
Tomee Datasources
I did test out setting a simple resource in WEB-INF/resources.xml, and it was reachable as simply jdbc/mydb used for example in a WEB-INF/classes/META-INF/persistence.xml. I did not have the same success when defining the resource in conf/Catalina/localhost/appcontext.xml.
It also seems to me that Tomee has a special way for choosing root contexts where services and our resources are deployed. During startup I see attempts to remap some of the resources. Example output:
[...].createRecipe Creating Resource(id=webapp/jdbc/mydb)
[...].AutoConfig.processResourceRef Auto-linking resource-ref 'openejb/Resource/webapp/jdbc/mydb' in bean MyService to Resource(id=webapp/jdbc/mydb)
And from Tomee Documentation:
<Resource id="Derby Database" type="DataSource">
. . . . .
</Resource>
The global jndi name would be java:openejb/Resource/Derby Database
So how do I refer to that in a portable way?
It seems I can solve that by simply putting this in the WEB-INF/web.xml:
<resource-ref>
<res-ref-name>jdbc/mydb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
</resource-ref>
This allows me to access this in JNDI as java:comp/env/jdbc/mydb.
My apologies for inserting parts of answer here - but I am just adding info to this as I find it. Later, I will either move this into answers, or leave as is if someone finds a better satisfying answer.
I hope to understand:
What the mechanisms are for instantiating resources (when)
How they are reachable (directly through JNDI, persistence.xml, and or a #Resource tag).
Any standard practices around those resources
Hoping that someone can clear up a few things -
For a project I need to be able to switch between a Sybase and an Oracle database. Using Spring I have been to come up with a solution using AbstractRoutingDataSource to allow switching between the sybase and oracle data source as needed.
However, within my tomcat context.xml, I have listed all data sources - so for each one I have "jdbc/myDbSybaseDataSource" and "jdbc/myDbOracleDataSource". I was wondering, does tomcat attempt to create all of these data sources on start up, or does it wait until something in the code has invoked it?
I know in spring you can lazy load your beans, but would tomcat still create each resource in the context.xml anyways?
Any help is much appreciated!
Edit
The reason for asking is - if for example, the Sybase database is down, we need to know that we can switch to the Oracle, but Tomcat will not try and load the Sybase resource from the context.xml at start up (unfortunately I am not in a position to turn off one of the databases to test this! :) ).
From what I can tell, Tomcat is loading the resources - but not trying to actually connect to the database until part of the code invokes the data source, at which point Spring kicks in and does its work. It simply loads in the resources and keeps the info stored somewhere, when Spring tries to create the data source it looks up the corresponding resource info and uses this
Yes, Tomcat will create these datasources at startup. I cannot tell you how far this initialization goes but I would try to avoid any overhead that you dont need.
Do you need both datasources at runtime or is it just to be able to decide at startup of your application?
In the second case you can see the cotext.xml file as an (external) configuration file. You can then use springs jndi reference feature to connect to the desired database for the current application.
In the root-context.xml you reference ONE datasource by name:
<jee:jndi-lookup id="mvcDatasource" jndi-name="jdbc/mvcDatasource"
expected-type="javax.sql.DataSource" />
And depending on which type should be used you declare the correct implementation in the context.xml:
<Context>
<Environment name="configDirectory" type="java.lang.String" value="file:///tmp/app1" />
<Resource name="jdbc/mvcDatasource" type="javax.sql.DataSource" auth="Container" driverClassName="org.h2.Driver" maxActive="8" maxIdle="4" username="user" password="" url="jdbc:h2:file:/tmp/app1/db" />
</Context>
As you can see you can use other declarations too. In my case i inject the external config location here to be able to load properties files for the propertyconfigurer too. So this location will be application specific.
I developed a sample web application which will read the data from an external properties file. The properties file is in the source folder in my system and is not included inside the WAR file.
The property file is accessed like this:
Properties prop = new Properties();
//File f1 = new File("Property.properties");
prop.load(getClass().getClassLoader().getResourceAsStream("Property.properties"));
How do I access this property file externally inside the WAR file?
What changes have to be made in the code to read it in the WAR file?
I think the most versatile approach is to define a simple environment entry as described in the section EE.5.4 Simple Environment Entries of Java™ Platform, Enterprise Edition (Java EE) Specification, v5.
From the section (page 68):
A simple environment entry is a configuration parameter used to
customize an application component’s business logic. The environment
entry values may be one of the following Java types: String,
Character, Byte, Short, Integer, Long, Boolean, Double, and Float.
You may also use URL connection factory as described in the section EE.5.6.1.4 Standard Resource Manager Connection Factory Types of the specification.
The Application Component Provider must use the java.net.URL resource
manager connection factory type for obtaining URL connections.
Both require a definition of a resource reference in the deployment descriptor WEB-INF/web.xml of your web application so you can inject the value using #Resource or use JNDI API with java:comp/env as the entry point.
The benefit is that you can change the configuration of your web application without having to recompile the code as well as let you change it using an application server's administrative tools your admins are accustomed with.
In web.xml you define the resource reference.
<resource-ref>
<res-ref-name>propertiesURL</res-ref-name>
<res-type>java.net.URL</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
<resource-ref>
<res-ref-name>propertiesPath</res-ref-name>
<res-type>java.lang.String</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
Then in your code you use the following to access the values:
#Resource
String propertiesPath;
#Resource
URL propertiesURL;
With this you met the requirements of Java EE and you can use propertiesPath or propertiesURL as if they were passed as input parameters to your methods.
Now, it's time to meet expectations of WebSphere Application Server.
What you defined are logical names that need to be mapped to their administered names (an application server knows about and can provide to the application).
In WebSphere Application Server you use WebSphere Binding descriptor WEB-INF/ibm-web-bnd.xml with the following configuration:
<?xml version="1.0" encoding="UTF-8"?>
<web-bnd xmlns="http://websphere.ibm.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-bnd_1_1.xsd"
version="1.1">
<virtual-host name="default_host" />
<resource-ref name="propertyURL" binding-name="propertyURL" />
<resource-ref name="propertyURL" binding-name="propertyURL" />
</web-bnd>
When the application gets deployed WAS allows you to map these mappings to its administered resources. Use the ISC console to define values of the environment entries and map them to the application.
It has became easier with WebSphere Liberty Profile. I described the mechanism as offered by WLP in my article Using #Resource to access JNDI in WebSphere AS 8.5 Liberty Profile.
You have three options:
configure the Websphere to include the directory which contains the property file in the classpath. Don't know how to do it, but I'm sure it is possible, since our application does the same thing
include the property file in the war archive. You probably don't want to do that.
instead using the classloader to load the property file use the file api with an absolute path. I'm not completely sure WAS does allow that, but it is a bad idea anyway, because it makes your application very dependent on things that it really shouldn't care about, such as the installation path of your application.
WebSphere has two folders on the classpath, properties can be loaded from there:
Enterprise Applications > myear > Manage Modules > myjar.jar > Class loader viewer
4 - Extension - com.ibm.ws.bootstrap.ExtClassLoader
file:/projekte/IBM/WebSphere/AppServer-8.5/classes/
file:/projekte/IBM/WebSphere/AppServer-8.5/lib/
I'm trying to figure out how to use datasources for my web service. I have the oracle-ds.xml deployed on my jboss 4.2.3 server, and the datasources are showing as bounded to JNDI names java:TestDS, java:WeatherDS, etc.
I try doing an initialcontext.lookup but I can't find it. I tried referencing the resource in the web.xml but I get "java:WeatherDS has no valid JNDI binding"... I've tried referencing "java:/WeatherDS", "WeatherDS", "java:WeatherDS", "jdbc/WeatherDS" and some others, but I think I need to somehow map the reference name to the jndi name.
I found a snippet of code that says:
...
<resource-ref>
<res-ref-name>jdbc/DefaultDS</res-ref-name>
<jndi-name>java:/DefaultDS</jndi-name>
</resource-ref>
...
But, it doesn't say where this file is and what else is needed. I don't know if I need a resource reference for sure or not. Can anyone point me in the direction of some more complete information of how to access the datasource from the code once it has been deployed? I am trying to make it so the connections are pooled for my web service.
In JBoss-4.2.3 you define a datasource in an XML-File in folder [JBOSS_HOME]/server/[MYSERVER]/deploy/
Create a file in this folder with name: mydatasource-ds.xml.
XML-File content:
<datasources>
<local-tx-datasource>
<jndi-name>mydatasource</jndi-name>
<!-- Properties for SQLServer -->
<connection-url>jdbc:jtds:sqlserver://hostname:1433/db-name;TDS=8.0;lastUpdateCount=true;sendStringParametersAsUnicode=false</connection-url>
<driver-class>net.sourceforge.jtds.jdbc.Driver</driver-class>
<!-- Properties for SQLServer end -->
<user-name>name</user-name>
<password>pwd</password>
<min-pool-size>5</min-pool-size>
<max-pool-size>50</max-pool-size>
<idle-timeout-minutes>15</idle-timeout-minutes>
<blocking-timeout-millis>15000</blocking-timeout-millis>
</local-tx-datasource>
</datasources>
To can access these datasource from every application deployed in the same JBoss by normal JNDI lookup.
IMPORTANT: Use prefix java:/ in the jndi name in your code. Full JNDI-Name in your application for the datasource above is java:/mydatasource