Bugs item #845157, was opened at 2003-11-19 15:38
Message generated for change (Comment added) made by dobytek
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=376685&aid=845157&group_id=22866

Category: JBossServer
Group: v3.2
Status: Open
Resolution: None
Priority: 7
Submitted By: Kevin Gilpin (kgilpin)
Assigned to: Nobody/Anonymous (nobody)
Summary: ClassCastException with PortableRemoteObject.narrow using jb

Initial Comment:
 I have 2 EJB applications which are each deployed with
a jboss-app.xml file so that they will have separate
classloader hierarchies. The reason for this is that
the two applications share some common JAR files such
as some base utilities, Hibernate beans, and 3rd party
ones such as struts.

Both applications have an EJB session bean which
implements the same home and session interfaces. These
beans register themselves in JNDI, and a common UI
finds them in a generic manner and exposes a UI for
invoking them (the session interface is IScriptRemote).

The problem occurs when the first application looks up
the IScriptRemote from the second application in the
following code. A ClassCastException occurs on the last
line you see here. Before I created the jboss-app.xml
files, no exception occurred (but I had other problems
with LinkerErrors).

InitialContext ic = J2EEUtil.getInitialContext(port,
principal, credentials);
try {
NamingEnumeration e = ic.listBindings(JNDI_SCRIPT_ROOT);
while ( e.hasMoreElements() ) {
Binding binding = (Binding)e.next();
Object obj = binding.getObject();
LOG.debug("Got object ", obj, " from binding ", binding);
try {
if ( obj instanceof EJBHome ) {
IScriptRemoteHome home =
(IScriptRemoteHome)PortableRemoteObject.narrow(obj,
IScriptRemoteHome.class);

The reported exception is:

15:24:30,609 WARN [Repository] Exception processing
binding ReloadMetadataScriptHome:
$Proxy44:ikp/script/ReloadMetadataScriptHomeHome
java.lang.ClassCastException
at
com.sun.corba.se.internal.javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:293)
at
javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:134)
at com.ipi.script.Repository.findAll(Repository.java:102)

----------------------------------------------------------------------

Comment By: Paul Anderson (dobytek)
Date: 2004-01-12 00:03

Message:
Logged In: YES 
user_id=948886

I have a similar scenario - multiple EAR files, configured
with their own class repositories in jboss-app.xml, to avoid
conflicts with library jars.
I also have separate WAR files that I'd like to keep outside
EARs. These have the home and remote interfaces in
WEB-INF/lib. I was using JBoss 3.2.1.

When calling an EJB from a webapp I kept getting
ClassCastExceptions, either with a straight cast or
PortableRemoteObject.narrow of the home interface stub
returned by JNDI. Removing the interfaces from WEB-INF/lib
just caused ClassNotFoundException.

This did not happen when the EARs used the global
repository, but then of course there were library problems..

I checked the ClassLoaders that loaded the stub home
interface and the version in my servlet code. The stub and
its home interface were loaded by a JBoss
UnifiedClassLoader, the servlet version of the home
interface by a Tomcat classloader. Configuring servlet
2.3/Java 2 classloading behaviour or a JBoss
UnifiedClassLoader for WEB-INF/lib didn't change much, as
the EAR dedicated UnifiedClassLoader version of the class
was not accessible anyway.

Upgrading to 3.2.3 made no difference.
This JNDI behaviour for the proxy made no sense for RMI so I
assumed in-VM optimisation was happening for JNDI and the
invocation.
I specifically configured use of jrmp for the EJB with
bean-invoker and home-invoker in the JBoss-specific EJB
deployment descriptor. No effect - presumably automatic
optimisation to 'local' was happening.

I then configured JNDI in conf to force RMI
(jndi.properties, java.naming.provider.url=localhost). This
meant that the stub classes were loaded by the same
classloader as my servlet lib and the ClassCastException
stopped.

However, now there was an InvocationException when invoking
the EJB's create method on the home interface - "check
deployment packaging".

I guessed that because in-VM optimisation required
additional access to the bean implementation class, this
class (and therefore the method) couldn't be loaded by the
webapp. (I put only the EJB interfaces in the webapp).
In the stack trace I could see the local invoker being used,
not jrmp.
Trying to disable the optimisation, I put
container-invoker-conf|Optimized as false into
standardjboss.xml (could have put into jboss.xml) for
stateless session beans. This seemed to be ignored - the
local invoker was still used and the stub was still returned
by reference from JNDI.

I had found many references to this option on the Internet,
so I guessed it had been dropped in recent JBoss versions.
The element had gone from the jboss_3_2.dtd compared with
jboss_3_0.dtd.

So I guessed that a cleaner way had been implemented to
choose the strategy the client invoker would use to find a
transport for the call.
Checking the JBoss source code, I found the jrmp invoker
only knows RMI, and that the invoker interceptor
automatically optimises by choosing the local invoker
instead of the jrmp invoker.
Fortunately a non-optimising invoker interceptor is
available - org.jboss.invocation.ByValueInvokerInterceptor.
This can be put in the interceptor chain for a bean's proxy
by changing standardjboss.xml or jboss.xml:

jboss|invoker-proxy-bindings|invoker-proxy-binding(name=stateless-rmi-invoker)|proxy-factory-config|client-interceptors|home/bean|interceptor
org.jboss.invocation.interceptor becomes
org.jboss.invocation.ByValueInvokerInterceptor

Hope this helps. I still have to find something that uses
RMI for JNDI only here where needed and not globally.
Seems like some documentation is needed, and that JBoss
needs to detect deployment arrangements where an optimised
call is not possible instead of requiring arcane configuration.


----------------------------------------------------------------------

Comment By: Kevin Gilpin (kgilpin)
Date: 2003-12-12 14:40

Message:
Logged In: YES 
user_id=44882

Thanks for taking a look at this. Your suggestion does not quite 
address the problem, because while there are two EJBs, they 
already have different JNDI names. Let me further describe the 
situation.

Script.ear contains EJB session and home interfaces, plus an EJB 
called TestBean that implements IScriptRemote
  IScriptRemoteHome
  IScriptRemote
  TestBean(IScriptRemote)

Search.ear contains an EJB called ReloadMetadataBean that 
implements IScriptRemote. It also contains the EJB interfaces:
  IScriptRemoteHome
  IScriptRemote
  ReloadMetadataBean(IScriptRemote)

TestBean and ReloadMetadataBean are bound to different JNDI 
names.

Some code in the Script.ear application attempts to access the 
ReloadMetadataBean. When it does so, the ClassCastException 
occurs. My educated guess as to why this is happening is that 
the Script application is trying to cast the 
ReloadMetadataBeanHome to its instance of the 
IScriptRemoteHome interface Class, but the object it gets from 
JNDI actually implements the IScriptRemoteHome interface that 
is loaded by the Search application. This interface is improperly 
being handed across EJB applications.

I think that JBoss is trying to optimize the RMI call by handing 
the ReloadMetadataBeanHome directly to the Script application, 
but this causes the ClassCastException because both applications 
have loaded the IScriptRemoteHome interface Class.

I would think that the solution to this problem would involve 
something like creating a proxy around ReloadMetadataBean that 
implements the right instance of the IScriptRemoteHome 
interface (which is probably basically what the non-optimized RMI 
implementation would do).

----------------------------------------------------------------------

Comment By: Dario Oliveros (doliveros)
Date: 2003-12-12 13:38

Message:
Logged In: YES 
user_id=927266

Hi Kevin,

Try to give different JNDI names to the EJB beans that are 
common to both EARs by editing the jboss.xml (use the ant 
task to replace the jndi-name at compile time). In that way, 
you should be able to do a lookup without a problem.
Let me know if it works.

D�rio

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=376685&aid=845157&group_id=22866


-------------------------------------------------------
This SF.net email is sponsored by: Perforce Software.
Perforce is the Fast Software Configuration Management System offering
advanced branching capabilities and atomic changes on 50+ platforms.
Free Eval! http://www.perforce.com/perforce/loadprog.html
_______________________________________________
JBoss-Development mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to