JCA Connector Classloading - java

in my Scenario, i try to use JCA Adapters to connect to an external storage - just to try this feature of J2EE.
I use JBoss EAP 7 and its packed implementation ironjacamar.
i deploy an adapter.rar, which contains an adapter.jar (this contains the Connection and ConnectionFactory Interfaces and all implementations) and META-INF/ironjacamar.xml.
I then deploy a app.war file, containing a Bean with an annotated field:
#RequestScoped
public class Bean {
...
#Resource(lookup = "java:/eis/StorageConnectionFactory")
private StorageConnectionFactory connectionFactory;
}
The war also contains the adapter.jar as library - as it needs to know of all the classes at runtime (NoClassDefFound etc.)
To my amazement, the Connector itself seems to work - as is get the Exception:
java.lang.IllegalArgumentException: Can not set conn.StorageConnectionFactoryImpl field Bean.connectionFactory to conn.HsmConnectionFactoryImp
and on ommitting the interfaces even:
#Resource(lookup = "java:/eis/StorageConnectionFactory")
private StorageConnectionFactoryImpl connectionFactory;
still
java.lang.IllegalArgumentException: Can not set conn.StorageConnectionFactoryImpl field Bean.connectionFactory to conn.HsmConnectionFactoryImp
I see that the Problem is, that the adapter.rar does nto share the same classloader as the app.war and both contain the corresponding classes, leading to a sort of ClassCastException - how do i solve this issue correctly?

It seems you haven't configure resource adapter properly.
See the below guide, it will help you to configure:
https://access.redhat.com/documentation/en/red-hat-jboss-enterprise-application-platform/version-7.0/configuration-guide/#configuring_jca_subsystem

Related

ClassCastException while reading from Infinispan Cache after redeployment on Wildfly 8.2

I have a simple Infinispan local-cache (also tried distributed cache) on Wildfly 8.2. Everything is working fine until I do redeployment of my .WAR. After redeployment of my .WAR I get the following error:
Caused by: java.lang.ClassCastException: my.package.MyClass cannot be cast to my.package.MyClass
Full stacktrace: https://gist.github.com/bagges/07af1842a874f7c99ef3
I lookup the Cache in a CDI Bean like this:
#Path("/mypath")
#Stateless
public class MyServiceClass {
#Resource(lookup = "java:jboss/infinispan/myContainer")
private CacheContainer container;
private Cache<Integer, MyCacheObject> myCache;
#PostConstruct
public void start() {
myCache = container.getCache("myCache");
}
#GET
public String get() {
if(!myCache.containsKey(1)) {
myCache.put(1, new MyCacheObject(1, "Hello Cache"));
}
return myCache.get(1).getName();
}
}
Wildfly-Config:
<cache-container name="myContainer" jndi-name="java:jboss/infinispan/myContainer" start="EAGER">
<local-cache name="myCache"/>
</cache-container>
I know that the error occured because off different class loaders. Infinispan tries to cast the entity stored with the previous classloader which cannot work. But how to avoid this?
Don't use start="EAGER". That will fix your problem.
We've removed this from WildFly 9, since its misuse has been the source of many user headaches.
Also, I recommend injecting your cache directly (instead of just the cache container). That way the cache lifecycle will be bound to the lifecycle of your deployment.
e.g.
#Resource(lookup = "java:jboss/infinispan/cache/myContainer/myCache")
private Cache<Integer, MyCacheObject> myCache;
Lastly, feel free to use a resource-ref to avoid referencing a vendor-specific jndi namespace in your application.
You should be able to share the cache if you enable store-as-binary in the Infinispan configuration and you force the cache to use the application's classloader instead of the one in the GlobalConfiguration:
Cache appSpecificCache = cacheFromJndi.getAdvancedCache().with(applicationClassLoader)

Remote lookup to another Glassfish from a Servlet

I'm trying to run a remote lookup to another Glassfish from a Servlet. So, I was following the link documentation (http://docs.oracle.com/cd/E19798-01/821-1752/beanv/index.html). First I created a Sateless Session Ben called CalculatorBean, packaged in an EJB JAR of the same name (CalculatorBean), the JNDI name was java:global/CalculatorBean/CalculatorBean.
According to the documentation, I created a Web project and declared my EJB in sub-web.xml the following file:
<ejb-ref>
<ejb-ref-name>ejb/CalculatorBean</ejb-ref-name>
<jndi-name>corbaname:iiop:127.0.0.1:3700#CalculatorBean/CalculatorBean</jndi-name>
</ejb-ref>
where 127.0.0.1 is the host of the machine (local!), 3700 is the default port for querying and, CalculatorBean/CalculatorBean is the global JNDI name. First question, theoretically the JNDI name passes into an interoperable String "CalculatorBean/CalculatorBean" instead of "java: global/CalculatorBean/CalculatorBean", right?
After that, I created a Servlet and put the following code snippet:
ctx = new InitialContext ();
bean = (CalculatorRemote) ctx.lookup ("java:comp/env/ejb/CalculatorBean");
Where, CalculatorRemote is the name of the remote interface that we included in the java project:comp/env/ is the directory section to access Java EE components and ejb/CalculatorBean is the name of my bean in the configuration of the sun-web.xml file
 
When put to run my Servlet I'm getting the exception:
Caused by: javax.naming.NameNotFoundException: No object bound to name java:comp/env/ejb/CalculatorBean
Obviously, it's not finding the name, however, do not really know what name I should use to set the lookup.
I had the same problem, and I solved it.
By default, your EJB is not visilbe into java:comp/env/ and you can not lookup for an EJB into InitialContext instance. But, you can successful lookup for an EJB after when at least one EJB instance is injected using #EJB annotation, like, for your example:
#EJB(name = "ejb/CalculatorBean")
private CalculatorRemote calc;
After that, CalculatorRemote EJB is visible in InitialContext instance.

RunTime Retention policy java annotations doesn't work in Weblogic 12C

We are planning to upgrade our product to Web-logic 12.C and WebSphere 8 stack ( Earlier it was WLC 10.3.5 and WAS 7). But issue in one of the web service component causing entire application failed to deploy in web logic. It works perfectly fine with WebSphere 8.
When deploying the EAR, Application sever throws 'Exception [EclipseLink-59] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DescriptorException' . After more analysis, I found below code in one of the WebServce dependant class causing the problem,
#ExcludeAttribute
public Map getOperations(){
Map map = new HashMap();
//some operation
return map;
}
#ExcludeAttribute describes Runtime retention policies, which is defined as shown below
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface ExcludeAttribute {
}
getOperations method returns java.util.Map which does not work with RunTime retention annotations, but works with any other data types such as (Integer, Customer etc) . I have changed to java.uitl.HashMap and did not work.
I was able to fix this (rather I would call work around) by using following annotation,
#XmlTransient
I have no other clue why does it not working with java.uitl.Map. Any thoughts would really give thumbs up!! I have posted to Oracle support, even they have not came back yet. Is there any know issues with java.util.Map/Collection class with combination of WEblogic12c/Annotations.
[EDIT - 1]
To answer Doughan question, methods which return non collection data type does not throw any exception, for eg:
#ExcludeAttribute
public Integer getOperations(){
return 1;
}
Where #ExcludeAttribute is custom annotation defines '#Retention(RetentionPolicy.RUNTIME)', and I do not need to define #XmlTransient to ignore.
I am bit confused to with usage of retention run time annotation , and not sure if I need to keep it or should use XMLTransient annotation.
[Edit 2 ,Based on #Doughan's answer]
I understand that we need to explicitly annotate getter methods ( as #XMLTransient) if they are not to be mapped from Weblogic 12C, and this is no way related to RuntTime Retention annotations. So any stack upgrade to 12C should update code base with this annotation if there unmapped public getter methods. I think is pretty much answers my concerns.
Correct me if I am wrong.
The existing code base already has annotated with Runtime annotation, and I thought its the one causing issue.
Detailed stack trace follows
weblogic.application.ModuleException: [HTTP:101216]Servlet:
"com.chordiant.component.cxradecisions.decision.impl.internal.AssessmentDecisionInterfaceWebServiceWrapper"
failed to preload on startup in Web application: "/ra".
com.sun.xml.ws.spi.db.DatabindingException: Descriptor Exceptions:
Exception [EclipseLink-59] (Eclipse Persistence Services -
2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DescriptorException Exception
Description: The instance variable [responseButtons] is not defined in
the domain class [com.chordiant.dm.ra.bean.Assessment], or it is not
accessible. Internal Exception: java.lang.NoSuchFieldException:
responseButtons Mapping:
org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping[responseButtons]
Descriptor: XMLDescriptor(com.chordiant.dm.ra.bean.Assessment --> [])
Runtime Exceptions:
at com.sun.xml.ws.db.toplink.JAXBContextFactory.newContext(JAXBContextFactory.java:185)
at com.sun.xml.ws.spi.db.BindingContextFactory.create(BindingContextFactory.java:179)
at com.sun.xml.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:211)
at com.sun.xml.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:185)
And I have a method getResponseButtons() defined in Assessment class
#ExcludeAttribute
public Map getResponseButtons() {
Map map = new HashMap();
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
In WebLogic 12.1.1 you will need to annotate that property with #XmlTransient:
#ExcludeAttribute
public Map getOperations(){
Map map = new HashMap();
//some operation
return map;
}
#ExcludeAttribute is custom annotation created by us, which uses
#Retention(RetentionPolicy.RUNTIME), ( I have provided snippet of this
annotation)
Custom annotations do not affect how MOXy produces its mapping metadata. There is no way that it could, just because the annotation is called #ExcludeAttribute MOXy couldn't assume it should be treated like #XmlTransient.
But issue in one of the web service component causing entire
application failed to deploy in web logic. It works perfectly fine
with WebSphere 8.
EclipseLink MOXy is the default JAXB provider in WebLogic as of version 12.1.1. You may be hitting an issue where previously MOXy treated all properties with only a getmethod as write only properties. New versions of MOXy will ignore these properties unless they are explicitly annotated. This may have caused it to appear to you that the #ExcludeAttribute annotation was having an effect.
I am bit confused to with usage of retention run time annotation
This setting is related to whether or not you can access this annotation via reflection at runtime. Are you creating your own annotation for your own purposes?
When deploying the EAR, Application sever throws 'Exception
[EclipseLink-59] (Eclipse Persistence Services -
2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DescriptorException'
If the contents of that property are meant to be mapped could you share the complete stack trace?

Spring : How to inject manually a bean which is not managed by actual application?

Here the context :
we have a java library, which is a factory code.
this library is deployed directly on Tomcat
Application "A", "B" & "C" use this library (jar) to compile, and it is the deployed version on Tomcat which is used when an application call it.
In the library, we have these packages :
- old.service
- old.service.impl
- new.service
- new.service.impl
The old services are some classic classes with setters. It is a spring bean declared in XML configuration of application "A".
In the new services, we have an annotated class (#Service) with some #Autowired attributes in order to be managed by application "B" & "C" which have an autoscan in XML configuration.
We would like to change the implementation of a old services, in order to use the new one without changing anything in application "A".
For that, we can call the new class from the older. But the pb is Spring......
How can we instanciate the new class, and the #autowired attributes ?
Can we instanciate manually the new class in older class, and instanciate attributes by reflection ?
Thank you.
ps: there is no XML configuration in the java library.
Two ways:
In app A where you instantiate old.service.impl Spring bean inject reference to new.service.impl into it
< bean class="old.service.impl">
< property name="newService" ref="newServiceBean"/>
< /bean>
< bean class="new.service.impl" id="newServiceBean" />
Obviously this means you will have to modify your old.service.impl to add setter for "newService", then use it in old service impl code
Get "new.service.impl" reference directly from web application context:
WebApplicationContextUtils.getWebApplicationContext(servletContext).getBean(newServiceImpl.class);
You will need to obtain ServletContext in this case. One way to do it is to get it from HttpRequest
Option 1 is preferred - you are not relying on running inside a servlet then, and requires very few changes in your code.

Context is read only

Helo masters, I have to create a JNDI Datasource dynamically, I tried to do it with a listener called SetupApplicationListener. Here is the beginning of WEB-LIB/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee">
<display-name>pri-web</display-name>
<!-- Listeners -->
<listener>
<listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
</listener>
<listener>
<listener-class>myapp.SetupApplicationListener</listener-class>
</listener>
The code of the listener:
public class SetupApplicationListener implements ServletContextListener {
public static Log LOG = null;
public void contextInitialized(ServletContextEvent ctx){
try {
createOracleDataSource();
.....
}
}
private void createOracleDataSource() throws SQLException, NamingException {
OracleDataSource ds = new OracleDataSource();
ds.setDriverType(...);
ds.setServerName(...);
ds.setPortNumber(...);
ds.setDatabaseName(...);
ds.setUser(...);
ds.setPassword(...);
new InitialContext().bind("java:comp/env/jdbc/myDS", ds);
}
.....
}
And there is the error:
[ERROR] 29/01/2013 09:44:50,517 (SetupApplicationListener.java:86) -> Error
javax.naming.NamingException: Context is read only
at org.apache.naming.NamingContext.checkWritable(NamingContext.java:903)
at org.apache.naming.NamingContext.bind(NamingContext.java:831)
at org.apache.naming.NamingContext.bind(NamingContext.java:171)
at org.apache.naming.NamingContext.bind(NamingContext.java:187)
at org.apache.naming.SelectorContext.bind(SelectorContext.java:186)
at javax.naming.InitialContext.bind(InitialContext.java:359)
at myapp.SetupApplicationListener.createOracleDataSource(SetupApplicationListener.java:102)
Can I set the read-only properties of the Context to "true"? Thanks! :)
Tomcat 6.0
Oracle 11g
jdk1.5
EDIT: Don't need to be dynamically, i have to define a jndi datasource internally I can't modify the server files because it is a shared server. It must be jndi because other modules use it in that way, thanks.
If you need to create a datasource dynamically is there really any need for a JNDI lookup? JNDI is designed to make the connection external to the application, while in your scenario its tightly coupled to the application due to a legitimate requirement. Why not just use a JDBC connection?
You need to create a ServletContextListener and there you can make the InitialContext writable - it's not the way it should be done, but if you really need it, this is one way you can do it.
This also works with Java Melody!
protected void makeJNDIContextWritable(ServletContextEvent sce) {
try {
Class<?> contextAccessControllerClass = sce.getClass().getClassLoader().loadClass("org.apache.naming.ContextAccessController");
Field readOnlyContextsField = contextAccessControllerClass.getDeclaredField("readOnlyContexts");
readOnlyContextsField.setAccessible(true);
Hashtable readOnlyContexts = (Hashtable) readOnlyContextsField.get(null);
String context = null;
for (Object key : readOnlyContexts.keySet()) {
String keyString = key + "";
if (keyString.endsWith(sce.getServletContext().getContextPath())) {
context = keyString;
}
}
readOnlyContexts.remove(context);
} catch (Exception ex) {
ex.printStackTrace();
}
}
I haven't got this problem before since I usually defined JNDI in application server(tomcat, weblogic and etc). Just like what Kevin said, this is exactly what JNDI was designed for; separating datasource config from your source code and retrieving JNDI resources through lookup and inject;
Back to your question, I think tomcat has every strict rules on modifying JNDI at runtime. In another word, you cannot re-bind or remove jndi from Context. If you go through the tomcat specification you will probably see some thing about jndi lookup but no re-bind.
From section EE.5.3.4 of the EE 6 platform specification (JSR 316):
The container must ensure that the application component instances
have only read access to their naming context. The container must
throw the javax.naming.OperationNotSupportedException from all the
methods of the javax.naming.Context interface that modify the
environment naming context and its subcontexts.
Note that "their naming context" in this section is referring to java:comp.
I solved this problem when found that I was closing environmentContext object
For example:
Context context=new InitialContext();
Context environmentContext=(Context) context.lookup("java:comp/env");
And my code was:
environmentContext.close();
After removing close function from environmentContext problem was solded for me;
I also had this problem, but being new to Tomee, I didn't know that there is a simple solution. When I deployed my web app to the webapps folder, the app worked fine, but when I deployed it to a service folder, I got the same abort. The problem was that the folder name did not match the war name (minus the .war). Once I fixed that, the app worked fine. Make sure the war name, folder name and service name are identical. This problem produces several different errors, including Context is read only and Error merging Java EE JNDI entries.
I solved this issue by setting useNaming="false" in my context.xml.
From the documentation:
useNaming : Set to true (the default) to have Catalina enable a JNDI InitialContext for this web application that is compatible with Java2 Enterprise Edition (J2EE) platform conventions.

Categories