While trying to port our application from WAS 8.5.5 to tomcat 8.0.33, we have hit a roadblock and we are unable to proceed. Hence requesting for your inputs.
Following is the scenario: we have DataSourceManager class which looks for datasource in the context as shown below.
Properties prop = new Properties();
prop.put("java.naming.factory.initial", "org.apache.naming.java.javaURLContextFactory");
prop.put("java.naming.provider.url", “rmi://localhost:1099”);
InitialContext context = new InitialContext(prop);
dataSource = (DataSource) context.lookup(“apl_datasource”);
The preceding code perfectly works well when code is run within the Tomcat container. But we are unable to access the context remotely, i.e. from outside the Tomcat container.
But this works fine in case of WAS when com.ibm.websphere.naming.WsnInitialContextFactory class is used.
While running a standalone client from a shell script, when inside DataSourceManager class we do a context lookup for a data source and the lookup fails with following exception.
javax.naming.NameNotFoundException: Name
[java:comp/env/jdbc/apl_datasource] is not bound in this Context.
Unable to find [java:comp].
It seems tomcat does not support remote access to its JNDI tree, and context initialized is empty. Tomcat does have the data source in the context but it is only accessible to the process running inside the containers and not accessible to processes running outside the container. PFB the following link for your reference.
Tomcat: what is the init context params to use for making an external client connection to Tomcat 5.5 JNDI tree?
Kindly provide your inputs on 3 points:
This link is for tomcat 5.5 and we are porting to tomcat 8. Has scenario changed in tomcat8
Is there any other way to access the JNDI tree remotely by standalone application.
Is the rmi protocol mentioned in provider url is supported by tomcat, or we should change it to some another protocol.
Related
I am developed a service that use the DataSource from a local JNDI (Server where to live the service and the JNDI).
In Spring boot this information is declared like this:
spring: datasource:
jndi-name: java:/comp/env/jdbc/MyLocalDB
I want to know if is possible to do something like this:
spring: datasource:
jndi-name: java:192.168.0.1:8080/comp/env/jdbc/MyLocalDB
Thanks
JNDI is an API to access directories. Application servers include directories to maintain information of the applications, the datasources and the EJB beans. JNDI can be used to access other types of directories. For instance, it can be used to access user information on Active Directoy and LDAP directory servers.
You can create client programs that access these JNDI directories and obtain data such as configuration data and RMI remote references to invoke EJB beans.
Accessing remote JNDI directories
If you are creating a client program, you can define an InitialContext describing the JNDI directory your program will use. You must define a Hashtable with the configuration, defining a Context.PROVIDER_URL and create the InitialContext.
For instance, you can create a program that access information in an LDAP directory.
// Set up the environment for creating the initial context
Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
// Create the initial context
DirContext ctx = new InitialDirContext(env);
// ... do something useful with ctx
Depending on the library you use, you can define a configuration file describing the JNDI remote host. For instance, for the JBoss EJB Client library, you can define a jboss-ejb-client.propertiesfile. Glassfish uses a jndi.properties file.
Accessing remote resources
A resource is data (e.g an image, audio, or text) that a program needs to access independently of the location of the program code. You can use the JNDI API or the #Resource annotation to access the information.
For instance, you can use the API to ask for data of users in an LDAP directory.
try {
// Create the initial directory context
DirContext ctx = new InitialDirContext(env);
// Ask for all attributes of the object
Attributes attrs = ctx.getAttributes("cn=Ted Geisel, ou=People");
// Find the surname attribute ("sn") and print it
System.out.println("sn: " + attrs.get("sn").get());
} catch (NamingException e) {
System.err.println("Problem getting attribute:" + e);
}
Accessing remote EJBs
You can access EJBs with remote interfaces located in other VMs. On the one hand, you must create the EJBs using CORBA-style remote interfaces and register the EJBs in the java: namespace in the server. On the other hand, the applications can use a corbaname URL to access these beans.
In Websphere/Liberty, if you define an EJB bound to:
java:global/ExampleApp/ExampleModule/ExampleBean!com.ibm.example.ExampleRemoteInterface
java:app/ExampleModule/ExampleBean!com.ibm.example.ExampleRemoteInterface
java:module/ExampleBean!com.ibm.example.ExampleRemoteInterface
You can access remotely the EJB using RMI-IIOP (to invoke methods)
corbaname::test.ibm.com:2809#ejb/global/ExampleApp/ExampleModule/ExampleHomeBean!com.ibm.example.ExampleEJBHome
corbaname:rir:#ejb/global/ExampleApp/ExampleModule/ExampleHomeBean!com.ibm.example.ExampleEJBHome
Detailed configuration of these remote EJBs may vary from one application server to another. If you use Glassfish, you can check the documentation. There is an example in the Oracle blogs.
If you configure a cluster, there are many other options to access the remote resources using the names of the nodes in the cluster.
Accessing a remote Datasources
Datasources defined in a server cannot be accessed remotely. If you want to keep the configuration of the datasources in the JNDI directory, you can solutions define a custom class that implements the DataSource interface. A client can obtain the datasource configuration from the server and create a local database connection using that connection.
I'm working on a web application using netbeans and MS Acces as my database, in my connection class I tried to get the path of my acces file (located inside my project) via the following command:
File f = new File("softTech.accdb");
String path = f.getAbsolutePath();
The problem is, as soon as I run the project and it tries to connect, when trying to get the path, the system gives me a path inside the tomcat's paste
I need your help, don't know what to do
Thanks in advance
There are two points:
First: MS Access is really the worst choice as a database for a Java web application.
MS Access is a desktop database not made for using it at the server side.
The JDBC-ODBC bridge was never meant for production use and was removed in Java 8.
The alternate driver Ucanaccess is nice for data exchange scenarios with a MS Access database but it uses a pure Java database (HSQLDB) as a buffer and an emulation layer to avoid the use of the original Jet Engine. This alone is a performance nightmare.
So you should consider to use another database for your web application. There are plenty of alternatives like SQLite, Apache Derby or H2 as embedded database engines or MySQL, PostgreSQL as client-server database systems. All with dedicated JDBC driver support.
Second: The database path or the connection shouldn't be hardcoded inside your web application. You should configure a named datasource in your application server (e.g. Tomcat). And inside your web application you can access the datasource via JNDI.
Example: Configure the database connection factory in Tomcat:
<Context ...>
...
<Resource name="jdbc/EmployeeDB"
auth="Container"
type="javax.sql.DataSource"
username="dbusername"
password="dbpassword"
driverClassName="org.hsql.jdbcDriver"
url="jdbc:HypersonicSQL:database"
maxActive="8"
maxIdle="4"/>
...
</Context>
Example: Access the datasource via JNDI:
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource)
envCtx.lookup("jdbc/EmployeeDB");
Connection conn = ds.getConnection();
... use this connection to access the database ...
conn.close();
The examples are part of the Tomcat documentation.
The benifit is, the web application only knows the logical database name. You can have multiple Tomcat installation, e.g. one for testing with a test database and one production. You can use the same WAR file for both installations. Each Tomcat has to be configured only once.
If you are using servlets then following code should work.
getServletContext().getRealPath("/yourFileName")
In case of normal java class, you can use
new File("yourFileName").getCanonicalPath();
As part of my application requirement, I have to configure a attribute called "ORBInitRef.NameService=corbaloc:iiop:ABCDE012:14888/NameService" in Websphere 8.5.5. Earlier i have used Jboss for my applciation deployment but now have to use WAS. In, WAS where should i have to configure this attribute in admin console? Is there any way to do it through orb.properties file in WAS root folder. Please let me know to approach??
Please follow the below steps to configurable Corba Name service in WAS 8.5.5 in admin console.
--> Environment --> Name Space Bindings --> New --> Provide your corba details here.
Example:
1) corba URL : corbaloc:iiop:ABCDE012:14888/NameService
2) provide Lookup name. using this, u will get a RootContext by lookup like JNDI.
Code Example :
InitialContext context = new InitialContext();
org.omg.CosNaming.NamingContext rootContext=(NamingContext)context.lookup("testing");
using the rootContext, you can fetch the server stubs and preform the operation required.
This may be a somewhat strange question, but I'm not sure how to do this another way. Basically, I am sharing connection code between two maven projects. One is a Maven Web application and the other is a regular Maven project.
To set up the database connection context, I'm using META_INF/context.xml in the Maven web application.
However, the regular Maven project doesn't use this file, so when the code to get the data source is run:
Context envCtx = (Context) new InitialContext().lookup("java:comp/env");
dbPool = (DataSource) envCtx.lookup("jdbc/MyAppUCP");
of course a NamingException is thrown. How can I reuse this method of getting the database connection with the regular Maven java application? Copying the META_INF/ directory into the project doesn't work.
The InitialContext with default constructor works only in managed environment (j2EE container). If you need to lookup for JNDI from a Java SE process, you need to pass in a property object as parameter to the overloaded constructor.
Each app/webserver has it's own set of properties that needs to be set in the property object. Refer to app server's documentation (http://docs.oracle.com/javase/jndi/tutorial/beyond/env/source.html).
Again, there would be security constraint on looking up for JNDI entries from external process.
I have a .properties file in my application which contains dataSource properties.
I set up a JNDI reference to this dataSource using the following code :
// first I create MyDataSource from the properties found in the .properties file
//then :
Context initContext = new InitialContext();
initContext.createSubcontext("jdbc");
initContext.createSubcontext("jdbc/oracle");
initContext.rebind(jdbc/oracle/myDataSource, MyDataSource);
If I use a lookup in this application, the dataSource is found :
Context initContext = new InitialContext();
BasicDataSource dataSource =
(BasicDataSource) initContext.lookup("jdbc/oracle/myDataSource")
//everything works fine and I can use my dataSource to getConnection,
//requests, etc...
Now I would like to use this dataSource in another application. But if I do the same lookup than previously, I don't find myDataSource (whereas there is still the previous application in tomcat and the jndi binding is done on start-up with the help of a listener).
How can I get myDataSource in this second application, given that I can't use a Tomcat's resource in server.xml or a context.xml file (for different reasons I have to use this .properties file)?
Thanks
"local" JDNI directories are read-only in Tomcat. Nevertheless, you can bind "global" JNDI resources in a LifecycleListener, and then "link" them to your context(s)(*):
You need to implement org.apache.catalina.LifecycleListener http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/LifecycleListener.html
Then register it in your server.xml like this (along with the other listeners):
<Listener className="yourlistener.YourLifecycleListener"/>
Your listener should await for 2 events:
public void lifecycleEvent(final LifecycleEvent event) {
if (Lifecycle.START_EVENT.equals(event.getType())) {
// Create your datasource instance...
Context initContext = new InitialContext();
initContext.createSubcontext("jdbc");
initContext.createSubcontext("jdbc/oracle");
initContext.rebind("jdbc/oracle/myDataSource", myDataSource);
} else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
// unbind...
}
}
Then you'll have to propagate resource accesses by "linking" them from "global" JNDI directory to "local" JNDI directory using ResourceLink element in your META-INF/context.xml:
<ResourceLink name="jdbc/oracle/myDataSource" global="jdbc/oracle/myDataSource"
type="javax.sql.DataSource" />
That worked for me so far.
(*) Some notes:
There's an advantage on using lifecycle listeners. Since the order of context creation is not guaranteed. The advantage is that all of your contexts will see this object created.
If you need to create and configure datasource creation more dynamically that on lifecycle listener creation, note that you can bind a custom class implementing the Factory pattern.
To avoid classloading incompatibility problems, consider putting your listener, datasource, etc. classes in a jar file in the Tomcat lib directory, so they're included y the common classloader.
Regards.
What you are trying to do is not going to work. J2EE applications are not allowed to modify the JNDI environment provided by the application server (J2EE spec, section 5.2.2) and the Tomcat JNDI documentation also states, that each web applications gets each own read-only JNDI environment. I'm not sure why binding/rebinding your datasource is not failing immediately and why it's working within the same web application, but even such application-internal usage of the JNDI environment is undocumented behaviour, which I would not rely on.
A couple people have already commented on this, but I think the answer to your question is: Tomcat has a file called server.xml that you need to use. A good reference I have used before is below:
http://tomcat.apache.org/tomcat-5.5-doc/jndi-resources-howto.html
Resources defined here will be visible to all apps deployed (if set up correctly). If you set up a JNDI resource in your apps context or web xml file, it should only be available to your app.
JNDI context are private to each webapp. Context created in one app can't be accessed by others.
Try to create an entry in GlobalNamingResources and links in both webapps using <ResourceLink> to see if it works.
I used this setup before to read from both apps but never tried to write from one. So not sure if it will work.
Actually, it is possible to access others JNDI resources, if the servlet implements org.apache.catalina.ContainerServlet. This interface has a org.apache.catalina.Wrapper attribute, that is "populated" by the container itself.
through that, I created a simple application to monitor resources.
BUT, I would like to do that in a listener, so my resource monitor could start when the container starts. Anyone knows a way?