simple string value by JNDI in Java - java

How can i set simple string value in configuration of tomcat and then read in java application?
context.xml
<ResourceLink name="global/test" global="testing" type="java.lang.String" />
server.xml
<Enviroment name="testing" value="myUser" type="java.lang.String"/>
web.xml in application
<resource-env-ref>
<resource-env-ref-name>global/test</resource-env-ref-name>
<resource-env-ref-type>java.lang.String</resource-env-ref-type>
</resource-env-ref>
in my java application
public String getValue(){
return new JndiDataSourceLookup().getDataSource("global/test").toString();
}
When i Run tomcat, i see these errors...
org.springframework.jdbc.datasource.lookup.DataSourceLookupFailureException: Failed to look up JNDI DataSource with name 'global/test'; nested exception is javax.naming.NameNotFoundException: Name [global/test] is not bound in this Context. Unable to find [global].
javax.naming.NameNotFoundException: Name [global/test] is not bound in this Context. Unable to find [global].

In your web.xml use,
<env-entry>
<description>Sample env entry</description>
<env-entry-name>isConnected</env-entry-name>
<env-entry-type>java.lang.Boolean</env-entry-type><!--order matters -->
<env-entry-value>true</env-entry-value>
</env-entry>
In code,
try {
Context initCxt = new InitialContext();
Boolean isConn = (Boolean)initCxt.lookup("java:comp/env/isConnected");
System.out.println(isConn.toString());
// one could use relative names into the sub-context
Context envContext = (Context) initCxt.lookup("java:comp/env");
Boolean isConn2 = (Boolean)envContext.lookup("isConnected");
System.out.println(isConn2.toString());
} catch (NamingException e) {
e.printStackTrace();
}
Have a look here Naming service tutorial to get a good understanding of InitialContext and JNDI.

I don't know what's inside JndiDataSourceLookup().getDataSource("global/test") but by the name of it, it should return a DataSoruce not a string.
If your lookup is local, simply do
Context ctx = new InitialContext();
String s = (String) ctx.lookup("global/test");
or if you are in a javaee container,
#Resource(name="global/test")
String testString;
and finally in your ejb-jar.xml
<env-entry>
<description>The name was explicitly set in the annotation so the classname prefix isn't required</description>
<env-entry-name>global/test</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>StringValue</env-entry-value>
</env-entry>
Refer this link: http://tomee.apache.org/examples-trunk/injection-of-env-entry/README.html
Your configuration of context.xml, server.xml, and web.xml aren't gonna work.

Related

JNDI Lookup with Resource annotation always NULL

I've got a WebApp with Tomcat 10, Java11 using Jersey3.
I defined a ConnectionPool in my context.xml for handling the connection to my OracleDB and now I'm trying to access the DataSource within my controller through a #Resource annotation. This should invoke a JNDI-lookup. Unfortunately, I always get a NPE as it seems not to find the resource while running... What am I doing wrong? Or what would the correct mappedName / lookup be?
#Path("/data")
public class DataController {
#Context
ServletContext context;
#Resource(lookup = "java:/jdbc/myDB") //also tried java:/comp/env/jdbc/myDB and mappedName="jdbc/myDB"
protected DataSource ds; //always null
<Context name="myapp">
<Resource type="javax.sql.DataSource"
name="jdbc/myDB"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#//localhost:1521/orcl"
username="xy"
password="xy"/>
According to the tutorials, a ref-link is optional when I define the resource directly in the context.xml.
Thanks for any input!
This link is about jboss, but would seem relevant to you too. It says that according to the specification, Resource annotation to do JNDI lookups would only work with EJBs, so it wouldn't work for your case.
A workaround is to do the programmatic way to see if your datasource is working:
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource bean = (DataSource ) envCtx.lookup("jdbc/myDB");
If you can find your datasource you can then try to optimize to avoid "manual" lookup above.

How to configure JDBC Resource in Embedded Tomcat 8?

I need to set up a connection pool for an application that uses an embedded Tomcat 8 application server. Normally, I would configure a new resource in the context.xml file. But of course, such a file does not exist when using the embedded version. The definition of the resource would look like this:
<Context>
<Resource name="jdbc/dbname" auth="Container" type="javax.sql.DataSource" username="username" password="password" driverClassName="org.postgresql.Driver" description="Database" url="jdbc:postgresql://localhost:5432/dbname" maxActive="20" maxIdle="3" />
</Context>
Therefore, there must be another solution for adding resources to a context. Is it possible to add the data source resource directly to the Standardcontext in code? If yes, how? Or how else can this be done when using the embedded version?
You can write your own factory and integrate it into Tomcat, and then configure the use of this factory in the element for the web application.
1. Write A Resource Factory Class
You must write a class that implements the JNDI service provider javax.naming.spi.ObjectFactory interface. Every time your web application calls lookup() on a context entry that is bound to this factory (assuming that the factory is configured with singleton="false"), the getObjectInstance() method is called.
To create a resource factory that knows how to produce MyBean instances, you might create a class like this:
package com.mycompany;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
public class MyBeanFactory implements ObjectFactory {
public Object getObjectInstance(Object obj,
Name name2, Context nameCtx, Hashtable environment)
throws NamingException {
// Acquire an instance of our specified bean class
MyBean bean = new MyBean();
// Customize the bean properties from our attributes
Reference ref = (Reference) obj;
Enumeration addrs = ref.getAll();
while (addrs.hasMoreElements()) {
RefAddr addr = (RefAddr) addrs.nextElement();
String name = addr.getType();
String value = (String) addr.getContent();
if (name.equals("foo")) {
bean.setFoo(value);
} else if (name.equals("bar")) {
try {
bean.setBar(Integer.parseInt(value));
} catch (NumberFormatException e) {
throw new NamingException("Invalid 'bar' value " + value);
}
}
}
// Return the customized instance
return (bean);
}
}
In this example, we are unconditionally creating a new instance of the com.mycompany.MyBean class, and populating its properties based on the parameters included in the element that configures this factory (see below). You should note that any parameter named factory should be skipped - that parameter is used to specify the name of the factory class itself (in this case, com.mycompany.MyBeanFactory) rather than a property of the bean being configured.
2. Declare Your Resource Requirements
Next, modify your web application deployment descriptor (/WEB-INF/web.xml) to declare the JNDI name under which you will request new instances of this bean. The simplest approach is to use a element, like this:
<resource-env-ref>
<description>
Object factory for MyBean instances.
</description>
<resource-env-ref-name>
bean/MyBeanFactory
</resource-env-ref-name>
<resource-env-ref-type>
com.mycompany.MyBean
</resource-env-ref-type>
</resource-env-ref>
WARNING - Be sure you respect the element ordering that is required by
the DTD for web application deployment descriptors! See the Servlet
Specification for details.
3. Code Your Application's Use Of This Resource
A typical use of this resource environment reference might look like this:
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");
writer.println("foo = " + bean.getFoo() + ", bar = " +
bean.getBar());
4. Configure Tomcat's Resource Factory
To configure Tomcat's resource factory, add an elements like this to the element for this web application.
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"
factory="com.mycompany.MyBeanFactory"
singleton="false"
bar="23"/>
...
</Context>
Resource Link:
Adding Custom Resource Factories
How to Configure JNDI DataSource in Tomcat 8 with Java Configuration:
For adding external resource in tomcat 8, you can follow this link: Adding external resources to class-path in Tomcat 8
The question was about embedded tomcat.

Cannot find dataSource, even though the dataSource is defined in context.xml

I have the following bean declared for one particular dao method to use a different data source than the rest of the project.
#Bean(name="kingsDataSource")
public DataSource kingsDataSource(){
JndiDataSourceLookup jndi = new JndiDataSourceLookup();
jndi.setResourceRef(true);
return jndi.getDataSource("dataSource/kings");
Here's the use of that bean.
#Resource(name="kingsDataSource")
private DataSource ds;
Here's from the context.xml (omitting the user and password, which have been verified to be correct, and would have been throwing a different error if they were wrong anyway.) I have also played with putting this in the context.xml of the server, having it in one place and not the other, and having it in both places.
<Resource
name="dataSource/kings"
auth="Container"
type="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
factory="org.apache.naming.factory.BeanFactory"
URL="jdbc:mysql://kings/db_netlogs" />
The error is a name not found exception -
Caused by: javax.naming.NameNotFoundException: Name [dataSource/kings] is
not bound in this Context. Unable to find [dataSource].
My question, then, is - to what do I bind this and how?
try to add a resource-ref to your web.xml
<resource-ref>
<res-ref-name>dataSource/kings</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

How to store string values in context.xml

I'd like to store connection URLs in a JNDI binding for my Tomcat application. Since Tomcat uses context.xml for JNDI resource defining, I need to figure out the propert way to store a String (or multiple strings for multiple connections) in context.xml.
My reason for doing this is so that I can define different strings for different environments, and load them through JNDI.
Usually, I see entries like so:
<Context ...>
<Resource name="someName" auth="Container"
type="someFullyQualifiedClassName"
description="Some description."/>
</Context>
Is it really just as simple as:
<Context ...>
<Resource name="myConnectionURL" auth="Container"
type="java.lang.String"
description="A connection URL string."/>
</Context>
If so, where do I actually store the String value?!?! And if it's not correct, then what is the proper way for me to store, for instance, "amqp:5272//blah.example.com&param1=4" in context.xml so I could then look it up like so:
Context ctx = new InitialContext();
String connectionURL = (String)ctx.lookup("myConnectionURL");
Thanks in advance!
You can use an Environmenttag:
<Context>
<Environment name="myConnectionURL" value="amqp:5272//blah.example.com&param1=4" type="java.lang.String"/>
</Context>
And you can read it almost as you specified in the question:
InitialContext initialContext = new InitialContext();
Context environmentContext = (Context) initialContext.lookup("java:/comp/env");
String connectionURL = (String) environmentContext.lookup("myConnectionURL");
This is much the same as using a Parameter tag, but without the need for a ServletContext.
You can configure named values that will be made visible to the web application as servlet context initialization parameters by nesting elements inside this element. For example, you can create an initialization parameter like this:
<Context>
...
<Parameter name="companyName" value="My Company, Incorporated"
override="false"/>
...
</Context>
This is equivalent to the inclusion of the following element in the web application deployment descriptor (/WEB-INF/web.xml):
<context-param>
<param-name>companyName</param-name>
<param-value>My Company, Incorporated</param-value>
</context-param>
Your java code looks like this
ServletContext sc = getServletContext();
String companyName = sc.getInitParameter("companyName");
Please see the reference http://tomcat.apache.org/tomcat-7.0-doc/config/context.html

JNDI path Tomcat vs. Jboss

I have DataSource which is configured on Tomcat 6 in context.xml as MyDataSource.
And I'm fetching it the following way:
DataSource dataSource;
try {
dataSource = (DataSource) new InitialContext().lookup("java:comp/env/MyDataSource");
} catch (NamingException e) {
throw new DaoConfigurationException(
"DataSource '" + url + "' is missing in JNDI.", e);
}
Everything works fine. Now I'm exporting this code to Jboss AP 6. and I configured my dataSource and its connection pool as local-tx dataSource under the same name.
When I'm executing the code above, I'm getting NamingException exception. after some investigation I've found that correct way to call my DataSource under Jboss is
dataSource = (DataSource) new InitialContext().lookup("java:/MyDataSource");
Can anybody explain me why should I omit "comp/env" in my JNDI path under Jboss?
The portable approach for defining data sources is to use a resource reference. Resource references enable you to define the JNDI name for your data source, relative to your application naming context (java:comp/env), and then map that logical reference to the physical resource defined in the application server, whose JNDI name is proprietary to the application server vendor. This approach enables your code and assembly to be portable to any compliant application server.
Step 1: Declare and Lookup Resource Reference
Option 1
This can be done by declaring a resource-ref in your web deployment descriptor (WEB-INF/web.xml):
<resource-ref>
<description>My Data Source.</description>
<res-ref-name>jdbc/MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Within your code, you can then lookup this resource using the JNDI name java:comp/env/jdbc/MyDataSource:
dataSource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/MyDataSource");
This JNDI name will not change regardless of the server where the application is deployed.
Option 2
Alternatively, starting in Java EE 5 (Servlet 2.5), this can be done even easier within your code using the #Resource annotation. This eliminates the need for configuring the resource-ref in your web deployment descriptor (web.xml) and prevents the need to perform an explicit JNDI lookup:
public class MyServlet extends HttpServlet {
#Resource(name = "jdbc/MyDataSource")
private DataSource dataSource;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// dataSource may be accessed directly here since the container will automatically
// inject an instance of the data source when the servlet is initialized
}
This approach has the same results as the previous option, but cuts down on the boilerplate code and configuration in your assembly.
Step 2: Map Resource Reference to Data Source
Then, you will need to use your application server's proprietary approach for mapping the resource reference to the physical data source that you created on the server, for example, using JBoss's custom deployment descriptors (WEB-INF/jboss-web.xml):
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<resource-ref>
<res-ref-name>jdbc/MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<jndi-name>java:/MyDataSource</jndi-name>
</resource-ref>
</jboss-web>
Or, for example, using Tomcat's context.xml:
<Resource name="jdbc/MyDataSource" . . . />
You can add to your data source definition the 'jndi-name' tag:
jndi-name - the JNDI name under which the DataSource should be bound.
You can find data source documentation on JBoss wiki: ConfigDataSources

Categories