I have a web application trying to access a JNDI declared in WebSphere Application Server.
The JNDI is declared under Object pool managers. However, I'm receiving an error when I access the pool. The error says that comp/env/pool is not found in context "java:".
My code is written as follows:
InitialContext initialContext = new InitialContext();
ObjectPoolManager opm = (ObjectPoolManager)initialContext.lookup("java:comp/env/pool");
Accessing the pool via the code below works:
ObjectPoolManager opm = (ObjectPoolManager)initialContext.lookup("pool");
I'm confused because according to what I've found on the internet, java:comp/env/ is a default prefix for JNDI. So why does it cause an error in my case?
Thank you!
you can only use java:comp/env if you have declared a reference to the Object Pool in your web.xml under the resource-ref section.
See What is resource-ref in web.xml used for? for further explanation.
Related
I am working on a Java Web Application, and is getting deployed in Websphere Application Server,
I have a class Database.java, which is returning the JDBC Connection with DB2 Database,
jndiName = "jdbc/TestDataSource";
Context ctx = new InitialContext();
envContext = (Context) ctx.lookup("java:comp/env");
javax.sql.DataSource ds = (javax.sql.DataSource) envContext.lookup(jndiName);
conn = ds.getConnection();
and in other classes where am performing operations am creating an object of Database.java class and get the connection and did the jdbc operations, so far it was working fine, but in latest development I have to introduce a thread in servlet class, so the other classes which are doing the operations are running in thread in background and returned the control to servlet immediately. But after implementing this application crashed in Websphere Application Server with below mentioned error, but surprisingly its working perfectly fine Tomcat server.
PFB the Web.xml
<resource-ref>
<description>Connection-ConnectionPool</description>
<res-ref-name>jdbc/TestDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
<mapped-name>jdbc/TestDataSource</mapped-name>
</resource-ref>
Error:
000000e9 SystemOut O Error in NamingException - Database.getConnection(datasource) :- javax.naming.ConfigurationException: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operations thread with any J2EE application component. This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request. Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application. Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names. [Root exception is javax.naming.NameNotFoundException: Name jdbc not found in context "java:comp/env".]
The exception means that the thread which you created doesn't have the context of the Java EE application and thus it cannot know which Java EE component namespace to get java:comp/env/jdbc/TestDataSource from. Note that you can define this same name to mean different things for different Java EE apps/components. There is an easy way around this, which follows Java EE spec standards. Instead of creating your own threads, use a ManagedExecutorService (also part of Java EE) that automatically propagates your application's context to a managed thread, in which case the app server will be able to resolve the lookup properly.
Here is an example:
ExecutorService executor = InitialContext.doLookup("java:comp/DefaultManagedExecutorService");
executor.submit(new Callable<Object>() {
public Object call() throws Exception {
DataSource ds = InitialContext.doLookup("java:comp/env/jdbc/TestDataSource");
Connection conn = ds.getConnection();
try {
// ... do useful stuff with connection
} finally {
conn.close();
}
return result;
}
});
I saw a stackoverflow answer to a question on JNDI.
The answer showed a few lines of code using InitialContext to retrieve a DataSource.
However, the instance of InitialContext was not created with any properties to use any sort of service such as LDAP or the file system.
Where does the entry go when you bind it to an InitialContext with the null constructor ?
Will the entry only visible within the application ?
Will it not persist when you shutdown the application ?
Where does the entry go when you bind it to an InitialContext with the null constructor?
If there is a resource file named /jndi.properties it uses whatever environment is defined in there. Servlet containers typically use this to define an extra object factory for the java: namespace.
Will the entry only [be] visible within the application?
Yes.
Will it not persist when you shutdown the application?
It will not persist unless the container implements that.
I'm trying to run a remote lookup to another Glassfish from a Servlet. So, I was following the link documentation (http://docs.oracle.com/cd/E19798-01/821-1752/beanv/index.html). First I created a Sateless Session Ben called CalculatorBean, packaged in an EJB JAR of the same name (CalculatorBean), the JNDI name was java:global/CalculatorBean/CalculatorBean.
According to the documentation, I created a Web project and declared my EJB in sub-web.xml the following file:
<ejb-ref>
<ejb-ref-name>ejb/CalculatorBean</ejb-ref-name>
<jndi-name>corbaname:iiop:127.0.0.1:3700#CalculatorBean/CalculatorBean</jndi-name>
</ejb-ref>
where 127.0.0.1 is the host of the machine (local!), 3700 is the default port for querying and, CalculatorBean/CalculatorBean is the global JNDI name. First question, theoretically the JNDI name passes into an interoperable String "CalculatorBean/CalculatorBean" instead of "java: global/CalculatorBean/CalculatorBean", right?
After that, I created a Servlet and put the following code snippet:
ctx = new InitialContext ();
bean = (CalculatorRemote) ctx.lookup ("java:comp/env/ejb/CalculatorBean");
Where, CalculatorRemote is the name of the remote interface that we included in the java project:comp/env/ is the directory section to access Java EE components and ejb/CalculatorBean is the name of my bean in the configuration of the sun-web.xml file
When put to run my Servlet I'm getting the exception:
Caused by: javax.naming.NameNotFoundException: No object bound to name java:comp/env/ejb/CalculatorBean
Obviously, it's not finding the name, however, do not really know what name I should use to set the lookup.
I had the same problem, and I solved it.
By default, your EJB is not visilbe into java:comp/env/ and you can not lookup for an EJB into InitialContext instance. But, you can successful lookup for an EJB after when at least one EJB instance is injected using #EJB annotation, like, for your example:
#EJB(name = "ejb/CalculatorBean")
private CalculatorRemote calc;
After that, CalculatorRemote EJB is visible in InitialContext instance.
Helo masters, I have to create a JNDI Datasource dynamically, I tried to do it with a listener called SetupApplicationListener. Here is the beginning of WEB-LIB/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee">
<display-name>pri-web</display-name>
<!-- Listeners -->
<listener>
<listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
</listener>
<listener>
<listener-class>myapp.SetupApplicationListener</listener-class>
</listener>
The code of the listener:
public class SetupApplicationListener implements ServletContextListener {
public static Log LOG = null;
public void contextInitialized(ServletContextEvent ctx){
try {
createOracleDataSource();
.....
}
}
private void createOracleDataSource() throws SQLException, NamingException {
OracleDataSource ds = new OracleDataSource();
ds.setDriverType(...);
ds.setServerName(...);
ds.setPortNumber(...);
ds.setDatabaseName(...);
ds.setUser(...);
ds.setPassword(...);
new InitialContext().bind("java:comp/env/jdbc/myDS", ds);
}
.....
}
And there is the error:
[ERROR] 29/01/2013 09:44:50,517 (SetupApplicationListener.java:86) -> Error
javax.naming.NamingException: Context is read only
at org.apache.naming.NamingContext.checkWritable(NamingContext.java:903)
at org.apache.naming.NamingContext.bind(NamingContext.java:831)
at org.apache.naming.NamingContext.bind(NamingContext.java:171)
at org.apache.naming.NamingContext.bind(NamingContext.java:187)
at org.apache.naming.SelectorContext.bind(SelectorContext.java:186)
at javax.naming.InitialContext.bind(InitialContext.java:359)
at myapp.SetupApplicationListener.createOracleDataSource(SetupApplicationListener.java:102)
Can I set the read-only properties of the Context to "true"? Thanks! :)
Tomcat 6.0
Oracle 11g
jdk1.5
EDIT: Don't need to be dynamically, i have to define a jndi datasource internally I can't modify the server files because it is a shared server. It must be jndi because other modules use it in that way, thanks.
If you need to create a datasource dynamically is there really any need for a JNDI lookup? JNDI is designed to make the connection external to the application, while in your scenario its tightly coupled to the application due to a legitimate requirement. Why not just use a JDBC connection?
You need to create a ServletContextListener and there you can make the InitialContext writable - it's not the way it should be done, but if you really need it, this is one way you can do it.
This also works with Java Melody!
protected void makeJNDIContextWritable(ServletContextEvent sce) {
try {
Class<?> contextAccessControllerClass = sce.getClass().getClassLoader().loadClass("org.apache.naming.ContextAccessController");
Field readOnlyContextsField = contextAccessControllerClass.getDeclaredField("readOnlyContexts");
readOnlyContextsField.setAccessible(true);
Hashtable readOnlyContexts = (Hashtable) readOnlyContextsField.get(null);
String context = null;
for (Object key : readOnlyContexts.keySet()) {
String keyString = key + "";
if (keyString.endsWith(sce.getServletContext().getContextPath())) {
context = keyString;
}
}
readOnlyContexts.remove(context);
} catch (Exception ex) {
ex.printStackTrace();
}
}
I haven't got this problem before since I usually defined JNDI in application server(tomcat, weblogic and etc). Just like what Kevin said, this is exactly what JNDI was designed for; separating datasource config from your source code and retrieving JNDI resources through lookup and inject;
Back to your question, I think tomcat has every strict rules on modifying JNDI at runtime. In another word, you cannot re-bind or remove jndi from Context. If you go through the tomcat specification you will probably see some thing about jndi lookup but no re-bind.
From section EE.5.3.4 of the EE 6 platform specification (JSR 316):
The container must ensure that the application component instances
have only read access to their naming context. The container must
throw the javax.naming.OperationNotSupportedException from all the
methods of the javax.naming.Context interface that modify the
environment naming context and its subcontexts.
Note that "their naming context" in this section is referring to java:comp.
I solved this problem when found that I was closing environmentContext object
For example:
Context context=new InitialContext();
Context environmentContext=(Context) context.lookup("java:comp/env");
And my code was:
environmentContext.close();
After removing close function from environmentContext problem was solded for me;
I also had this problem, but being new to Tomee, I didn't know that there is a simple solution. When I deployed my web app to the webapps folder, the app worked fine, but when I deployed it to a service folder, I got the same abort. The problem was that the folder name did not match the war name (minus the .war). Once I fixed that, the app worked fine. Make sure the war name, folder name and service name are identical. This problem produces several different errors, including Context is read only and Error merging Java EE JNDI entries.
I solved this issue by setting useNaming="false" in my context.xml.
From the documentation:
useNaming : Set to true (the default) to have Catalina enable a JNDI InitialContext for this web application that is compatible with Java2 Enterprise Edition (J2EE) platform conventions.
This question already has answers here:
What does java:comp/env/ do?
(3 answers)
Closed 2 years ago.
what is meant by java:comp/env ?
What does the look up like :
Context envContext = (Context)initContext.lookup("java:comp/env");
do ?
I understand that a look-up like :
(DataSource)envContext.lookup("jdbc/MyDatasource")
looks up for the name MyDatasource in the context.xml or web.xml to get the URL of the database. Is it so ? !! But what does the former look up do ?
java:comp/env is the node in the JNDI tree where you can find properties for the current Java EE component (a webapp, or an EJB).
Context envContext = (Context)initContext.lookup("java:comp/env");
allows defining a variable pointing directly to this node. It allows doing
SomeBean s = (SomeBean) envContext.lookup("ejb/someBean");
DataSource ds = (DataSource) envContext.lookup("jdbc/dataSource");
rather than
SomeBean s = (SomeBean) initContext.lookup("java:comp/env/ejb/someBean");
DataSource ds = (DataSource) initContext.lookup("java:comp/env/jdbc/dataSource");
Relative paths instead of absolute paths. That's what it's used for.
It's an in-memory global hashtable where you can store global variables by name.
The "java:" url scheme causes JNDI to look for a javaURLContextFactory class, which is usually provided by your app container, e.g. here is Tomcat's implementation javadoc
See also NamingManager.getURLContext
I know I'm far late, but I was asking the same question, and I think I came some answer. So, if I may put my two cents.
java:comp/env/jdbc/myDataSource
java: is just like jdbc: from connection string. Acts as a protocol.
comp is the root for all JNDI contexts.
env is the subcontext for all resource related. There is another for user. Check this out.
jdbc is the subcontext for jdbc resources. There are types. Check the link from the previous bullet.
myDataSource is the name of your jdbc resource.