Reputation: 750
I have two applications on the same WAS 8.5 JVM. The "server application" contains a @Remote bean and the "client application" calls it.
The "server application" is packaged as an EAR file. The "client application" is a JAR file which grafts itself into an existing web app.
All is well when I build an "EJB interface JAR" and include it in both applications.
However, I am working in an esoteric environment which precludes me from doing that in production. Instead, I can include the remote EJB interface in a "fat JAR" incarnation of the "client application".
I am using Maven to assemble this "fat client application JAR". I have a Maven module that builds the "EJB interface JAR" referenced above. I declare this module as a dependency of the "client application" module. Then I do this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>assemble-all</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
The resulting "jar-with-dependencies" does include the EJB interface. However, I get an error when casting the bean to the said interface.
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
environment.put(javax.naming.Context.PROVIDER_URL, "corbaloc:iiop:localhost:2810");
javax.naming.Context ctx = new InitialContext(environment);
engine = (UXServerRemote) ctx.lookup("java:global/myapp/my-ejb/UXServerBean!com.myapp.client.UXServerRemote");
The error:
java.lang.ClassCastException: com.myapp.client._UXServerRemote_Stub incompatible with com.myapp.client.UXServerRemote
Clearly, WAS is being thoroughly cautious when casting objects. How can I place my EJB interface in the "client application JAR" in a manner that WAS would accept as identical to its "EJB interface JAR" copy?
Upvotes: 0
Views: 307
Reputation: 33956
I don't know what you mean by "grafts itself into an existing web app", but based on the mention of java.net.FactoryURLClassLoader, I guess you're using URLClassLoader.newInstance to somehow load this JAR outside of normal EE class loading. In that case, I'd suggest something like this:
Thread thread = Thread.currentThread();
ClassLoader saveContextClassLoader = thread.getContextClassLoader();
thread.setContextClassLoader(getClass().getClassLoader());
try {
javax.naming.Context ctx = new InitialContext();
engine = (UXServerRemote) ctx.lookup("java:global/myapp/my-ejb/UXServerBean!com.myapp.client.UXServerRemote");
} finally {
thread.setContextClassLoader(saveContextClassLoader);
}
By swapping in the context class loader to your custom class loader around the call to lookup, you allow the java:global
lookup internals to find the UXServerRemote class that is only accessible to your custom class loader. The lookup basically attempts that same Thread.currentThread().getContextClassLoader().loadClass(UXServerRemote.class.getName())
call; if the class cannot be found, the java:global
lookup internals will returns the stub from the "server application" rather than failing with a ClassNotFoundException. That's useful in case you're writing a client that doesn't actually need to directly invoke methods on the returned object (e.g., maybe the client is just a proxy, and it will pass the object along). In your case, that "server application" stub will be incompatible with your "client application" custom class loader, which is why you see the ClassCastException.
Note: you don't need to specify InitialContext constructor properties when your code is running inside a managed server. INITIAL_CONTEXT_FACTORY is only required if you're running in a standalone Java SE client, and PROVIDER_URL is only required if you're connecting to another process (because you're running in a standalone Java SE client or because you're running in a server and don't want to loopback to the same process).
Upvotes: 1