I am new to Java EE world, in my application I would like to connect to the Database. I was able to accomplish this task with the code below, but can someone explains it to me? What each line does?
code:
try {
InitialContext initContext = new InitialContext();
Context env = (Context) initContext.lookup("java:comp/env");
ds = (DataSource) env.lookup("jdbc/test2");
} catch (NamingException e) {
throw new ServletException();
}
I also found out that I can use the annotation below in my JSP using tomcat which accomplish the same result as above. Can I use this annotation with any web server, ex GlassFish or Jboos ?
Anotation code:
#Resource(name = "jdbc/test2")
private DataSource ds;
The Java Naming and Directory Interface™ (JNDI) is an application
programming interface (API) that provides naming and directory
functionality to applications written using the Java™ programming
language. 1
The Context object provides the methods for binding names to objects, unbinding names from objects, renaming objects and listing the bindings.
JDNI performs all naming operations relative to a context. Therefore the JDNI defines an InitialContext, which provides a starting point for naming and directory operations. Once you have an initial context, you can use it to look up other contexts and objects.
Many methods in the JDNI package throw a NamingException when they need to indicate that the operation requested cannot be performed. The JDNI has a rich exception hierarchy stemming from the NamingException class. The class names of the exceptions are self-explanatory and are listed here.
You can use the #Resource annotation to inject resources. You can find more information on the correct use here.
Sources:
https://docs.oracle.com/javase/tutorial/jndi/overview/index.html
http://www.javaworld.com/article/2076888/core-java/jndi-overview--part-1--an-introduction-to-naming-services.html
Related
It's really not funny. There is no information in internet how to run weld-osgi second version (2.1.2.final) in se app. Instructions for ver 1 don't work.
Let the developers be ashamed that they didn't provide necessary samples. I wrote them here.
So, I have and OSGi activator and I want to get beans from it. In GF4 I used this:
private BeanManager getBeanManager() throws NamingException
{
try{
InitialContext initialContext = new InitialContext();
return (BeanManager) initialContext.lookup("java:comp/BeanManager");
}
catch (NamingException e) {
System.out.println("Couldn't get BeanManager through JNDI");
return null;
}
}
But in SE application I can't get it through JNDI.
Also I tried:
Weld weld=new Weld();
BeanManager beanManager=weld.getBeanManager();
But at the second line I get
Caused by: java.lang.IllegalStateException: Singleton is not set. Is
your Thread.currentThread().getContextClassLoader() set correctly?
How can I use CDI starting from activator? What is my mistake?
EDIT:
What I did - I found two source code of two programs that use it, but it's really no so easy to write on their base (at least for me). The first is here and the second is here
The weld-osgi subproject is not supported anymore with Weld 2. Instead, integration with OSGi is provided using the Pax CDI project.
Pax CDI documentation can be found here: https://ops4j1.jira.com/wiki/display/PAXCDI/Pax+CDI
Additional information can be found at:
- http://karaf.apache.org/manual/latest/users-guide/cdi.html
- https://github.com/weld/core/blob/master/examples/osgi/README.md
"javax.naming.Context" is commonly used inside Java EE development. It's quite convenient to use it to establish dynamical database connection by calling its lookup function with given names of resources inside context.xml. The sample code is shown as following where "db_name" is the name you used to identify the database resource.
Context ctx = new InitialContext();
DataSource ds = ctx.lookup("java:comp/env/jdbc/db_name");
My concern is what are the differences between lookup resources by using the same context and lookup resources by using different contexts. And which approach makes more sense or suitable? Suppose all database resources are defined inside the same context.xml file. For example:
Context ctx = new InitialContext();
DataSource ds1 = ctx.lookup("java:comp/env/jdbc/db_name_ds1");
DataSource ds2 = ctx.lookup("java:comp/env/jdbc/db_name_ds2");
and
Context ctx_ds1 = new InitialContext();
Context ctx_ds2 = new InitialContext();
DataSource ds1 = ctx_ds1.lookup("java:comp/env/jdbc/db_name_ds1");
DataSource ds2 = ctx_ds2.lookup("java:comp/env/jdbc/db_name_ds2");
Thank you for your sharing.
there is no difference except you created an unnecessary extra java object. however, if the jndi server was remote, you would have created two different network connections and iverhead of managing them - definetly not what one should do.
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.
I'm writing a Java servlet that needs to read some site-specific
configuration data; I would like it to be easily accessible/modifiable
by the sysadmins at deployment time. There is no sensible default,
so the data has to be provided by the site admin.
It consists of a few string key/value pairs (think Properties).
It would only be read once (at initialization time).
I'm aware of this SO question
and the ServletContext.getInitParameter() mechanism, but as far as
my understanding goes, they require the data to be bundled in the
servlet package (either as a properties file, or specified in the
web.xml), which makes it inconvenient to upgrade the servlet code.
Is there any "standard" interface for a servlet to get this kind of
key/value configuration data? It would be ok if the programming
interface is the same everywhere, but the actual way of setting the
configuration data depends on the actual servlet container being used.
I'm looking preferably at portable solutions, but I'd be content with
something that only works in Tomcat and Jetty.
The recommended way to configure an application server for a web application is per JNDI.
Every application server (including Jetty and Tomcat) allows you to configure JNDI parameters.
For Jetty you can add the following to your jetty.xml to add the JNDI parameter param.file:
<!-- JNDI java:comp/env -->
<New id="param.file" class="org.mortbay.jetty.plus.naming.EnvEntry">
<Arg>param.file</Arg>
<Arg type="java.lang.String"><SystemProperty name="jetty.home" default="."/>etc/config.properties</Arg>
<Arg type="boolean">true</Arg>
</New>
Then in your servlet you can read the JNDI parameter:
import javax.naming.InitialContext;
import javax.naming.NamingException;
...
public Object readJndi(String paramName) {
Object jndiValue = null;
try {
final InitialContext ic = new InitialContext();
jndiValue = ic.lookup("java:comp/env/" + paramName);
} catch (NamingException e) {
// handle exception
}
return jndiValue;
}
public String getConfigPath() {
return (String) readJndi("param.file");
}
The way to set JNDI values differs for other application servers but the code to read the configuration is always the same.
The Servlet init parameters are the right (and standardized) way of defining properties which can be configured by the administrator. Many of the application servers provide a GUI backend where the parameters can be configured.
For an example for Tomcat, see Defining Tomcat servlet context parameters
Configure the external location of the properties - either via a jvm argument (when starting the servlet container), or in the web.xml
in the external location use config.properties and read it with java.util.Properties
You may take Preferences or hack with user.home, user.dir, etc. But for a few key/value keep things simple.
Write a small Singleton to wrap around Properties and load them from a fix & absolute location
public class LocalConfig extends Properties {
public static LocalConfig $ = new LocalConfig();
private LocalConfig() throws IOException {
load(new File("/etc/myconfig.properties"));
}
}
Here's my Java class
import endpoint.NewSessionRemote;
import javax.naming.Context;
import javax.naming.InitialContext;
public class HelloClient {
public static void main(String[] args) {
try {
Context ctx = new InitialContext();
NewSessionRemote hello = (NewSessionRemote) ctx.lookup("endpoint.NewSessionRemote");
System.out.println(hello.stringChange(4));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
When I run this class I'm getting an exception.
javax.naming.NameNotFoundException: endpoint.NewSessionRemote not found
at com.sun.enterprise.naming.TransientContext.doLookup(TransientContext.java:216)
at com.sun.enterprise.naming.TransientContext.lookup(TransientContext.java:188)
at com.sun.enterprise.naming.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:74)
at com.sun.enterprise.naming.RemoteSerialContextProviderImpl.lookup(RemoteSerialContextProviderImpl.java:129)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:154)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
java.lang.NullPointerException
All the other enterprise bean classes are written according to the EJB 3.0 standard.
Your valuable contribution is expected.
Solution
The exception was
javax.naming.NameNotFoundException: endpoint.NewSessionRemote not found
It occurs because the JNDI name that was given by the application side didn't match the servser's (Glassfish) actual JNDI name, so I did was check the JNDI tree in Glassish through its admin console (vendor specific) and I did notice that the JNDI for the NewSessionRemote interface (which is the business interface of the session bean NewSessionBean) is different from the name which I have given in the application side. So how did this happen then suddenly something came in to my mind that's the ejb-jar.xml there is another name JNDI name assigned to the same NewSessionRemote using tag. So I simply remove it and redeploy EJB module. That's it.
Looks like you have no RMI registry (i.e. active server) you are lookingUp() against.
You supplied no Context.INITIAL_CONTEXT_FACTORY variable, so the lookup should be a valid URL, which it is not.
Hence, you should put something like this on your env (on the iCtx):
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
I suggest you read the the simple examples over at http://java.sun.com/j2se/1.5.0/docs/guide/jndi/jndi-rmi.html
When using JNDI, you're using an API that requires a specific configuration underlying it in order to connect to the server (see the Javadoc for details on what that configuration is). For example, java.naming.factory.initial is the property which indicates which implementation of JNDI you want to use.
Now, when running code inside a JavaEE server, this configuration is available implicitly, and all you need to do is what you have done in your code - instantiate InitialContext, and perform a lookup. However, when running outside the server, this implicit configuration is not present, and so you need to configure your InitialContext explicitly.
Your sample code uses a main() method, which suggests that you're running outside the container. The config you need will depend on your specific application server, you'll need to look up that documentation to see what config to supply.