I have a web app running in Tomcat correctly that I want to run on the new OpenLiberty server, the app is starting correctly inside OpenLiberty but at the moment of the database connection initiation is throwing the following exception:
[Default Executor-thread-15] 2018-03-15 15:02:30 ERROR TomcatConnectionManager:41 - Loading jdbc/mysql/myaap failure
javax.naming.NameNotFoundException: java:/comp/env
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLName.<init>(JavaURLName.java:83)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLNameParser.parse(JavaURLNameParser.java:39)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLNameParser.parse(JavaURLNameParser.java:60)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext$NameUtil.<init>(JavaURLContext.java:474)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext.lookup(JavaURLContext.java:321)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext.lookup(JavaURLContext.java:370)
at org.apache.aries.jndi.DelegateContext.lookup(DelegateContext.java:161)
The above exception is thrown during the lookup phase:
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
Is there any way to make it work on OpenLiberty doing less changes possible?
On OpenLiberty the equivalent lookup would look like this:
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:comp/env");
The key is that you need to use java:comp/... instead of java:/comp/...
The reason why Tomcat is different than Liberty is because Tomcat is just a servlet container and Liberty conforms to the full Java EE specification.
According to section EE.5.2.2 of the Java EE 7 spec:
The application component’s naming environment is composed of four logical
namespaces, representing naming environments with different scopes. The four
namespaces are:
java:comp – Names in this namespace are per-component (for example, per enterprise
bean). Except for components in a web module, each component gets
its own java:comp namespace, not shared with any other component. Components
in a web module do not have their own private component namespace.
See note below.
java:module – Names in this namespace are shared by all components in a
module (for example, all enterprise beans in a single EJB module, or all components
in a web module).
java:app – Names in this namespace are shared by all components in all modules
in a single application, where “single application” means a single deployment
unit, such as a single ear file, a single module deployed standalone, etc.
For example, a war file and an EJB jar file in the same ear file would both have
access to resources in the java:app namespace.
java:global – Names in this namespace are shared by all applications deployed
in an application server instance. Note that an application server instance
may represent a single server, a cluster of servers, an administrative
domain containing many servers, or even more. The scope of an application
server instance is product-dependent, but it must be possible to deploy multiple
applications to a single application server instance.
Had a similar problem going between WebSphere and Tomcat. I'm developing and testing on a Tomcat server and using utilities I can't change that handle the DB connection to our DB2. On WebSphere it uses a constant set to "jdbc/COMPDB2" to retrieve the DataSource when I configure Tomcat and my Web.xml file it resolves to "java:comp/env/jdbc/SFCCDB2"
My work around for on local work space it to add a listener to copy the resource to the level in the InitialContext. I'm not very experienced with the server side of things but this is working so far using TomEE 7.0.81.
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/SFCCDB2");
javax.naming.Context envCtx = (javax.naming.Context) ctx.lookup("java:comp/env");
try{
/*
Added this because after redeploying code to the server it would error
connecting to the DB with an SQLException Datasource is closed
*/
DataSource dataSource = (DataSource) ctx.lookup("jdbc/COMPDB2");
ctx.destroySubcontext("jdbc");
} catch (NamingException e){
//Doesn't exist; safe to just add
}
ctx.createSubcontext("jdbc");
ctx.bind("jdbc/COMPDB2", ds);
ctx.close();
Related
I have been trying all day to connect to a Remote EJB on a Websphere Application Server 7. This configuration is necessary for project specific reasons. Its goal is to connect two applications together that are on independent EAR but on the same server.
I have been trying to access a dummy method that does not have any parameters.
The lookup URL is the one copied from the EJB deployment on my local server and it complies with EJB3.0 IBM specifications according to the information here.
I have seen several other posts on stackoverflow related to EJB Remote issues in WAS (but I cannot link all threads because of my user limitations) but they do not resolve or are not the same as my problem.
Local EJB invocation works fine.
Here is the implementation. I do not use any specific IBM WAS libraries in the imports:
The class that is connecting to the Remote EJB:
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
env.put(Context.PROVIDER_URL, "iiop://localhost:2809");
Context ctx = new InitialContext(env);
Object object = ctx.lookup("ejb/<component-id>#<package.qualified.interface>");
RemoteInterface interface = (RemoteInterface)javax.rmi.PortableRemoteObject.narrow(object, RemoteInterface.class);
String sResponse = (String)interface.dummy();
The definition of the remote interface is:
#Remote
public interface RemoteInterface {
public String dummy() throws Exception;
}
And my implementation is:
#Override
public String dummy() throws Exception {
return "string";
}
Environment information:
Websphere Application Server 7
JDK 1.6
EJB 3.0
EAR 5.0
Maybe someone can give me some pointers on what to do next.
I am trying to override the tomcat session manager with an embedded tomcat.
These are the steps preformed in-order to load the context.xml that defines the manager entity.
..
Context context = tomcat.addWebapp(contextPath, appBase);
File configFile = new File ("D:\\context.xml");
context.setConfigFile(configFile.toURI().toURL());
tomcat.start();
..
The session manager seems to be recognized as it's constructor is being invoked but the startInternal() method is never invoked and the session manager being used is the old tomcat session manager.
The weird thing is that when defining the same configuration in a non embedded tomcat, the session manager is being overridden without problems.
Would appriciate any help on the subject.
Non embedded tomcat uses server.xml and embedded tomcat does not uses server.xml file rather we need to pass the arguments in the method.
I'm trying to read messages from a jms queue created in "Sun App Server" from a non-hosted application (console app) but I get the following error:
NoInitialContextException
Cannot instantiate class: javax.jms.TopicConnectionFactory
with this code:
Properties env = new Properties( );
env.put(Context.INITIAL_CONTEXT_FACTORY, "javax.jms.TopicConnectionFactory");
InitialContext jndi = new InitialContext(env);
and I have referenced the j2ee.jar library that contains the class but certainly, the class is an interface.
Can I access the queue from a non-hosted application??
Aitor;
When you say "Sun App Server", I'm not sure what that means, but I will assume it is Glassfish.
There are 2 separate steps to acquiring remote JMS resources.
You need to create a remote JNDI connection which requires a valid InitialContextFactory class name.
Once you have a the connection, you can look up the TopicConnectionFactory.
For item #1, this link demonstrates how to make a remote JNDI connection.
For item #2, once you have a JNDI context, you will also need to know the JNDI name of the TopicConnectionFactory which will look something like:
TopicConnectionFactory tcf = (TopicConnectionFactory) jndi.lookup("jms/TopicConnectionFactory");
One aspect you need to keep in mind is that the j2ee.jar library contains the generic Java EE interfaces for the JMS classes, but you will also need a library in your classpath that contain the JMS implementation concrete classes. This also goes for the JNDI connection. This tutorial provides a concise list as:
Applicationserver JNDI Lookup
/lib/appserv-rt.jar
/lib/appserv-admin.jar
/lib/javaee.jar /lib/j2ee.jar
Client Lib
/imq/lib/jms.jar
/imq/lib/imq.jar
/imq/lib/imqutil.jar
/lib/install/applications/jmsra/jmsra.jar
I have a problem accessing JNDI resources from within an OSGI bundle, hosted in
WebSphere Application Server (WAS) using a servlet bridge.
It is failing on creating the JNDI initial context. My code is:
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory");
InitialContext ctx = new InitialContext(env);
This fails with:
javax.naming.NoInitialContextException:
Failed to create InitialContext using factory specified in hashtable {java.naming.provider.url=corbaloc:rir:/NameServiceServerRoot, java.naming.factory.initial=com.ibm.websphere.naming.WsnInitialContextFactory, java.naming.factory.url.pkgs=com.ibm.ws.naming:com.ibm.ws.runtime:com.ibm.iscportal.jndi} [Root exception is java.lang.NullPointerException]
When I run the same code directly within a WAR module (not using OSGI), it is successful. I assume therefore the problem is something about accessing JNDI from within OSGI.
I have seen some references to Class Loader problems when accessing JNDI from within OSGI ... not sure if this is my problem, since the above exception does not explicitly relate to class loading, but maybe it is. Anyhow, if this is the problem, I am not sure how to fix it!
Is it in fact possible to access JNDI and JDBC entries set up within WAS, from within my OSGI module?
My application is an Eclipse RAP (Rich Ajax Plugin), packaged into a WAR file using the Eclipse WAR Product Tooling described at:
http://eclipsesource.com/blogs/2010/08/17/equinoxrap-war-deployment-an-end-to-the-pain/
This works successfully so far, apart from the JNDI access.
Many thanks
David
By default the thread context classloader will be used to load the InitialContextFactory. This is probably (but no guarantee) your bundle's classloader. You have a couple of options:
Configure the org.osgi.framework.bootdelegation property. This is probably implicitly set to sun.,com.sun. so you want to change it to be sun.,com.sun.,com.ibm.websphere.naming.* I believe this can be set in the servlet bridge wars WEB-INF/launch.ini
You could also import comibm.websphere.naming which would require you to add to the launch.ini org.osgi.framework.system.packages.extra=com.ibm.websphere.naming
Either should work.
Good luck.
I have spent the last few days attempting to integrate a Grails (version 1.3.2) application with an EJB 2.1 application that is deployed on WebSphere 6.1. Once our grails apps are in production, they will be deployed to WebSphere as well. The EJB 2.1 application is widely used across our company and, in anything except a local development environment, is deployed to its own cluster. The way we handle this in our existing Java EE applications (all of which are non-Spring, non-Grails) is to bind a CORBA CosNaming Naming Context within each of our other clusters that can then be used to obtain references to our shared EJB 2.1 application. So, up to this point, if one of our application needed to interact with this application, they would do so using an approach like this:
String cosNameBinding = "ejbApp.HighAvail.cluster";
InitialContext initial = new InitialContext();
Context fedContext = (javax.naming.Context) initialCtx.lookup(cosNameBinding);
Then do the normal EJB-style lookup/narrow/invoke using the federated/CosNaming context:
Object ejbHomeAsObject = fedContext.lookup(jndiNameOfService);
EJBHome home = (EJBHome) PortableRemoteObject.narrow(ejbHomeAsObject, homeClass);
Object service = invokeMethod(homeClass, home, "create");
As you can see, there is a level of indirection that occurs here in order to go from the InitialContext to the federated naming Context that can be used to interact with the shared EJB application.
Running locally, I have both the Grails application and the EJB application deployed to the same server (non network deployment WAS, same profile&node). I have Spring configured like so:
beans = {
ejbJndi(org.springframework.jndi.JndiTemplate) {
environment = ["java.naming.factory.initial" :
"com.ibm.websphere.naming.WsnInitialContextFactory"]
}
crewMemberService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
jndiName="hotelService/ejb/HotelService"
businessInterface="com.company.appName.hotel.HotelService"
lookupHomeOnStartup="false"
cacheHome="false"
refreshHomeOnConnectFailure="true"
jndiTemplate = ref("ejbJndi")
}
}
And I can successfully inject ejb references into my Grails controllers and invoke them. However, WebSphere can only resolve the JNDI lookup because they are both deployed on the same server. When we move it to one of our development environments, we'll need jndi lookups for these services to go against the federated naming context.
So my questions are:
Is there a way to do this with the classes that are provided within Spring and if so could you give me an idea of how I would need up modify my Spring config to do so?
Given that there is no flexibility around how we deploy the other app or gain references to its services (we must use the federated context), should I consider extending JndiTemplate and do the necessary wiring myself?
If anyone has faced this situation I would be most appreciative for any insights you may be able to offer.
In case anyone has this same question down the road, I ended up implementing an extension to Spring's JndiTemplate and using that. Here is the code:
public class FederatedJndiTemplate extends org.springframework.jndi.JndiTemplate
{
protected static final String JNDI_CONTEXT_BINDING_NAME = "fed.context.jndiName";
/**
* Obtain a JNDI naming context for the specified federated naming context.
*
* #throws NamingException if no "fed.context.jndiName" has been specified in
* the environment properties for the jndiTemplate or the container throws a naming
* exception.
*/
#Override
protected Context createInitialContext() throws NamingException {
Properties props = super.getEnvironment();
if(!props.containsKey(JNDI_CONTEXT_BINDING_NAME)) {
throw new NamingException("You must specify the federated naming context JNDI binding name");
}
String jndiBinding = props.getProperty(JNDI_CONTEXT_BINDING_NAME);
InitialContext initCtx = new InitialContext();
Context fedCtx = (Context) initCtx.lookup(jndiBinding);
return fedCtx;
}
}
Then inside my resources.groovy, I just used this JndiTemplate:
ejbJndi(com.myCompany.spring.jndi.FederatedJndiTemplate) {
environment = [
"fed.context.jndiName":"myServices.HighAvail.Cluster"]
}
hotelService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
jndiName="hotelService/ejb/HotelService"
businessInterface="com.mycompany.appName.hotel.HotelService"
homeInterface="com.mycompany.appName.hotel.HotelServiceHome"
lookupHomeOnStartup="false"
jndiTemplate = ref("ejbJndi")
}