I am attempting to use JNDI with a custom DataSource called CEDataSource. From my understanding for this to work I would have to create a custom factory as well.
So I created a custom factory that would return the CEDataSource object but now when I attempt to use this in Java with
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
// Look up our data source
CEDataSource ds = (CEDataSource)envCtx.lookup("jdbc/cePu");
I get the exception ClassCastException
"CEDataSource cannot be mapped to CEDataSource". I added the CEDataSource and the CEDataSourceFactory to the TOMCAT/lib folder as well as referenced this same jar on my deployed application.
Any help would be greatly appreciated on why this possible error may occur. Thanks
"CEDataSource cannot be mapped to CEDataSource" seems to point to the fact that it's not the same "CEDataSource" in both places.
What could be different is the classloader and this usually happens if you have the same jars/.class(es) in multiple locations.
Do you have multiple copies of your jar?
Try to have a single copy, maybe in the shared tomcat lib so it's loaded by the same classloader no matter from where you access it from.
It is actually not too difficult to start Tomcat under an Eclipse debug session (just put all the Bootstrap.jar in a project and add the System properties in the JVM parameters). II've done that many times, if only to dissect the bowels of that feline. Once this is done you can break on the class cast exception of the JNDI connection factory and you will then be able to see if your factory is called or not.
From what I remember Tomcat uses the DBCP DataSource. Actually repackaged under com.apache.tomcat.dbcp.dbcp.DataSource (IIRC).
So I would not be surprised if this is what you end up with as a result of your look-up.
With hindsight, I now realize I also forgot to mention that if any underlying class (for instance a JDBC driver) needed to create the instance of your CEDataSource is missing you also get this ClassCastException. Fair enough, but you always focus on the class itself and not on the other jars...
CEDataSource ds = (CEDataSource)envCtx.lookup("jdbc/cePu");
The lookup you are doing on jdbc/cePu is not of class type CEDataSource , it belongs to some other class type, that is why you are getting class cast exception. if you could show me the configuration for jdbc/cePu that would be helpful.
Related
I am in the process of writing a JCA Resource Adapter for FTP and SFTP. As my goal is to be able to use one protocol completely independent from the other, I have two different ManagedConnectionFactory classes, one for each protocol. Both have different ConnectionDefinition annotations; the Glassfish domain.xml contains a resource definition for the FTP Adapter but not for the SFTP Adapter. Now, when I inject the FTPConnectionFactory into an EJB, I sometimes get an InjectionException as WELD tries to inject the SFTPConnectionFactory instead (this is of course consistent during a run of the appserver; I either consistently get the right or the wrong one). Removing the ConnectionDefinition annotation for the SFTP adapter seems to fix the problem.
So, Questions:
How can I fix this and make Glassfish inject the correct class? Can this be caused by a problem in my code or is this a Glassfish issue?
According to the spec it is legal for a RA to have multiple ConnectionDefinition annotations, as well as multiple instances of a class implementing ManagedConnectionFactory; but I couldn't find any information about having multiple different classes implementing ManagedConnectionFactory inside of the same Resource Adapter. Glassfish clearly seems to have a problem with it - is this explicitly allowed or disallowed somewhere?
The ConnectionDefinition (with FTP replaced by SFTP for the SFTP case):
#ConnectionDefinition(connectionFactory = FTPConnectionFactory.class,
connectionFactoryImpl = FTPConnectionFactoryImpl.class,
connection = FTPConnection.class, connectionImpl = FTPConnectionImpl.class)
The FTP and SFTP Factory and ManagedConnection classes share common ancestors but are not directly related - but this doesn't seem to matter as completely separating the implementations makes no difference.
The domain.xml snippet:
<resource-adapter-config resource-adapter-name="ftpconnector" thread-pool-ids="thread-pool-1" />
<connector-connection-pool name="jca/ftpConnectorPool"
resource-adapter-name="ftpconnector"
connection-definition-name="foo.bar.ftp.FTPConnection"
transaction-support="NoTransaction" match-connections="false" />
<connector-resource pool-name="jca/ftpConnectorPool" jndi-name="jca/ftpConnector" />
And the injected field:
#Resource(lookup = "jca/ftpConnector")
private FTPConnectionFactory ftpConnectionFactory;
TL;DR: This was caused by an incorrectly configured Connection Pool, where connection-definition-name does not point to a class implementing ConnectionFactory. The observed behaviour is IMO a bug and has been reported here.
While trying to reproduce this issue with Adam Biens connectorz Filesystem Resource Adapter (by adding a second set of classes and another connection definition), I found I could only reproduce the behaviour if the connector-connection-pool in the domain.xml is incorrectly defined: If I changed the connection-definition-name to point to a nonexistent class, Glassfish would randomly take one of the two defined connectors. Doublechecking my Connection Pool, I found out that I mistakenly used the Connection class instead of the ConnectionFactory class in the xml. So when the attribute does not point to a class implementing the ConnectionFactory interface, Glassfish seems to randomly choose any class from the Resource Adapter which implements ConnectionFactory, without even printing an error message.
I am facing problem as the actual imported java file is not being called. Please have a look of my code :-
import javax.naming.Context;
import javax.naming.InitialContext;
.....
public class ABC{
.....
1. Context lContext = null;
2. ObjectDataSourceFactory lSource = null;
3. try
4. {
5. lContext = new InitialContext();
6. lSource = ((ObjectDataSourceFactory)lContext.lookup(....));
}
catch (Exception e)
{
}
The Problem I am facing here is : when flow control goes into line number 6. it calls the "lookup method" from "SelectorContext.java" but not from "InitialContext.java", I have found this with the help of DEBUGGING mode in eclipse . As a result it cannot find the proper JNDI and gives exception.
FYI..
My code is running on Tomcat6.
I have set the classpath of jar files from my JRE1.6 and so the JDK.
Can someone please suggest me -
how can I know from which JAR this "SelectorContext.java" is being called and how to make it to Look into the InitialContext.class which is present inside RT.JAR, if I am not wrong ?
Your understanding is not correct. SelectorContext is one of the JNDI implementations of the tomcat.
There is an option to use external JNDI context by setting java.naming.factory.initial as system variable. This is set by Tomcat (javaURLContextFactory) to provide it's own JNDI services.
When you call new InitialContext(), JVM sees if there is user provided naming factory, and if it is available, JVM calls initialFactory.getInitialContext to get the custom JNDI implementation and makes this default and all the method calls to context is inturn routed to custom implementation.
In your case, call to SelectorContext is right, see if you have the required configuration in place to have the resource in JNDI.
EDIT:
I found classloader leak in my webapplication.
It boils down to 3rd party library initializing CORBA via JNDI's COS naming service and not exposing a call to cleanly shutdown JNDI's context. This leaves some CORBA related threads and other resources referencing my webapp classloader and preventing it from being garbage collected. This results in OutOfMemory Error: PermGen after few redeploys/reloads.
For now I increased the PermGen memory in JVM and it makes the intervals between server crashes longer. This obviously is not a fix but a workaround (and a poor one for that matter).
I guess my question is is there any way I can cleanly shutdown JNDI context without holding reference to it. My instincts tell me no, but maybe I don't know about some magic feature of JNDI that would allow me to get hold of that context.
So the way the 3rd party library initializes CORBA objects is something along this lines (exception handling and other details omited for brevity):
private CorbaObjectAggregate initCorba() {
InitialContext ctx = null;
CorbaObjectAggregate corbaObjects = new CorbaObjectAggregate();
ORB orb = null;
Properties env = getContextEnvironment();
String[] args = null;
orb = ORB.init(args, null);
env.put("java.naming.corba.orb", orb);
ctx = new InitialContext(env);
//a bunch of object lookups follow
corbaObjects.someCorbaObjectReference = (SomeCorbaObjectClass) ctx.lookup("somePaht");
return corbaObjects;
}
So the reference to ctx is gone after that method finishes executing...
I tried stopping the threads manually but it didn't fix the leak. I guess there are some other corba resources holding onto classloader. I suppose I could try to hunt them down in some cleanup method and free the classloader this way, but I was hoping for some cleaner solution.
Just for clarity, the 3rd party library is closed source and I can't really change it. It's also not viable option to get support form the company behind it.
That is going to be tricky to fix. There are likely to be two issues:
- classes loaded from the JAR holding a reference to the web-app class loader
- threads started by that process having the web-app class loader as their context class-loader.
Something along the following lines should help:
Move the JAR to $CATALINA_BASE/lib. That will mean that the classes are loaded by the common class loader. The down side is that they are also visible to and shared by every web application.
Find out where in your application the initialisation is triggered. Before that code executes, set the thread context class loader to the system class loader (or the parent of the current (web-app) class loader) and reset the thread context class loader after the init call. That should mean any threads created do not have the web-app class loader as the context class loader.
If threads get created at other points in time, fixing this could get very tricky, very quickly.
For some background that may help understand what is going on, see:
http://people.apache.org/~markt/presentations/2010-11-04-Memory-Leaks-60mins.pdf
To see the sort of thing Tomcat does internally to work-around these issues see:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java?view=annotate
Note that I'm mirroring the example given here very closely.
In fact, my situation is somewhat simpler as I'm not even testing with a persistence unit at this point. My test project provides a simple MDB and a session bean; both the MDB and the session bean are getting loaded as normal, and can be successfully tested (in a constrained fashion) without injection.
The suggested injection with the #LocalClient annotation on my unit tests is failing with the known error:
javax.naming.NamingException: Unable to find injection meta-data for [your-class]. Ensure that class was annotated with #org.apache.openejb.api.LocalClient and was successfully discovered and deployed. See http://openejb.apache.org/3.0/local-client-injection.html
When I visit this page it informs me that I may need to add an extra property to my test case context setup. So that now looks like:
#Override
public void setUp() throws Exception {
initializeContext();
}
public void initializeContext() {
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
// the property i've added
p.put("openejb.tempclassloader.skip", "annotations");
try {
InitialContext initialContext = new InitialContext(p);
initialContext.bind("inject", this);
} catch (Throwable throwable) {
throwable.printStackTrace();
throw new RuntimeException(throwable);
}
}
But it's still failing. I really like this idiom and would be very excited if I could successfully use it in my projects.
A few other notes:
I am providing an 'empty' ejb-jar.xml (in src/main/resources) and an application-client.xml (in src/test/resources) as suggested by Apache to tell OpenEJB to scan the classpath [UPDATE: as it turns out, I was doing this wrong. See my answer below for the suggestion that worked for me.]
The test cases annotated with #LocalClient aren't identified by the OpenEJB engine as actually getting picked up and processed properly (as my MDBs are, for example)
Thanks in advance for any help or guidance.
This issue is likely caused by improper location of the descriptors which hint OpenEJB which sorts of modules are available.
To ensure the test-classes get picked up properly, make sure you're placing a file named application-client.xml at src/test/resources/META-INF with the following content:
<application-client/>
This should force OpenEJB to scan and react to the presence of #LocalClient annotations.
I had a similar issue when I tried to test stuff in a test project called tomee-embedded-trial and it turned out that openejb ignores stuff called tomee-.* .
I fixed it for me by specifying the following system properties:
openejb.deployments.classpath.include=".*-trial.*" openejb.deployments.package.include=".*-trial.*"
I'm having problems calling EJB3 stateless bean outside the container.
Code for getting the object reference:
Context envCtx = (Context) context.lookup("ejb");
MyObject o = (MyObject) envCtx.lookup(MyObject);
The second row results in exception:
java.lang.ClassCastException: javax.naming.Reference
I use JBoss.org 5.1.0 GA.
Based on some other posts I suspect this might be due to wrong version of client libraries. However, I'm unsure which library jar(s) I should include in the jar? (I get the error using 5.0.4.GA jnpserver.)
For JBoss, your code should look something like that:
Properties properties = new Properties();
properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces");
properties.put("java.naming.provider.url","localhost:1099");
Context context = new InitialContext(properties);
(EchoBeanRemote) c.lookup("EchoBean/remote");
If you prefer, you can put the JNDI environement settings in a jndi.properties file (that needs to be on the classpath):
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=jnp://localhost:1099
And use the non-arg InitialContext constructor:
Context context = new InitialContext();
(EchoBeanRemote) c.lookup("EchoBean/remote");
This is obviously more portable.
And in both case, you'll need jbossall-client.jar on the classpath on the client side.
P.S.: You can check the Global JNDI Name your bean is registered at in the JNDI View of the web-based JMX console (if it still exists).