EJB class not identified in context lookup - ejb-3.0

I have written a sample EJB class as shown below :
#Stateless(mappedName = "BusinessSLSB")
#Local(BusinessLocal.class)
#TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
public class BusinessSLSB implements BusinessLocal{
//body of the class
}
I have a non-EJB class in the same project and I try to lookup the file in the following way :
public class GetTransactionData {
private BusinessLocal business;
public GetTransactionDataForMercury(){
notifier.info("Creating an object of GetTransactionData");
try{
InitialContext ctx = new InitialContext();
business = (BusinessLocal) ctx.lookup("BusinessSLSB");
}catch(Exception ne){
notifier.error("Error occurred --> " + ne.getMessage());
}
}
When I am executing the code, I am getting the following exception :
Error occurred --> Unable to resolve BusinessSLSB. Resolved '
Am I going wrong in providing the lookup name? How can I resolve this issue?

No usage of mappedName is ever portable. You thus can't assume that the name you assign via that attribute will always end up being a top-level JNDI name.
Which server are you using? If it supports EJB 3.1, drop mappedName and use the portable JNDI names. Otherwise drop mappedName anyway and find out what proprietary JNDI name your server assigns. Many will print this in the log when starting up.

I have found the solution for such a problem. The solution is add the following lines in the web.xml file :
<ejb-local-ref>
<ejb-ref-name>ejb/BusinessLocal</ejb-ref-name>
<local>dk.tdc.soa.smo.draco.ejb.BusinessLocal</local>
</ejb-local-ref>
and the following lines in GetTransactionData :
public class GetTransactionData {
private BusinessLocal business;
public GetTransactionDataForMercury(){
notifier.info("Creating an object of GetTransactionData");
try{
InitialContext ctx = new InitialContext();
business = (BusinessLocal) ctx.lookup("java:comp/env/ejb/BusinessLocal");
}catch(Exception ne){
notifier.error("Error occurred --> " + ne.getMessage());
}
}

Related

Spring 2.5 to 4.2 upgrade issue - BeanWrapperImpl

I am upgrading Spring 2.5 to 4.2.
The issue is with one bean which has property type org.springframework.core.io.ClassPathResource. The resource value is defined in xml as p:location="classpath:/<the resource path>"
This worked perfect and bean property was populated with the resource. But in 4.2 the value is not getting set.
So I debugged the code and found that the class org.springframework.beans.BeanWrapperImpl was manipulating the value and removing classpath: string from actual value in Spring 2.5.
However the same is not true in 4.2 and class org.springframework.beans.BeanWrapperImpl isn't modifying the value which results in spring not finding the resource.
Anyone faced similar situation? What solution did you apply?
Thanks,
Hanumant
EDIT 1: code sample
spring config file
<bean class="com.test.sample.TestBean" id="testBean"
p:schemaLocation="classpath:/com/test/sample/Excalibur_combined.xsd" />
TestBean.java
public class TestBean {
private ClassPathResource schemaLocation;
public ClassPathResource getSchemaLocation() {
return schemaLocation;
}
public void setSchemaLocation(ClassPathResource schemaLocation) {
this.schemaLocation = schemaLocation;
}
}
App.java
public class App {
public static void main(String[] args) {
ApplicationContext ap = new ClassPathXmlApplicationContext("classpath:/com/test/sample/spring-config.xml");
TestBean tb = (TestBean) ap.getBean("testBean");
try {
URL url = tb.getSchemaLocation().getURL();
System.out.println(url);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Error Message
INFO: Loading XML bean definitions from class path resource
[com/test/sample/spring-config.xml] java.io.FileNotFoundException:
class path resource
[classpath:/com/test/sample/Excalibur_combined.xsd] cannot be resolved
to URL because it does not exist at
org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:187)> at com.test.sample.App.main(App.java:20)
However if I remove the classpath: from bean definition it works.
So is classpth: necessary in bean definition xml file?? And why it was working fine in Spring 2.5??
The main issue is that you aren't programming to interfaces. Instead of the concrete org.springframework.core.io.ClassPathResource use org.springframework.core.io.Resource. When doing to the org.springframework.core.io.ResourceEditor will kick in and convert the String into a Resource instance. The location you are providing classpath:/<the resource path> will be passed to the ResourceLoader which will get the resource or throw an error if it doesn't exist.
If, however, you are using the concrete type ClassPathResouce directly this mechanism doesn't kick in and the location is set to what you provide classpath:/<the resource path>. However this is actually not a valid location for the URL class and that will eventually fail with the message you see.
It worked in earlier versions due to a hack/workaround/patch in the BeanWrapperImpl to strip the prefix.
Basically it now fails because you where doing things you shouldn't have been doing in the first place.

Weblogic,EJB, $Proxy99 class cast exception

Following are the modules in my project,
1. EJB module (version 3): We prepare ejb jar of this module and deploy on Weblogic11g server. It deals with database operation. It has #local, #Remote interface and #stateless classes implementing #local,#Remote interfaces.
2. Web Application : This web application takes inputs (user uploads file) from users, validates file and inserts data into database. It uses RMI.
Problem: On production (weblogic 11g server ) sometimes we observe exception saying $Proxy99 cannot be cast to "Remote interface name" (for different different classes) e.g com.xyz.fileProcessSetting.FileProcessSttgFacadeRemote.
But after some time when we again upload file, it gets uploaded successfully without any error.
Now, I do not understand how come these remote objects becomes temporarily unavailable? Never faced this issue on development/UAT environment. Also no idea how to reproduce and fix it.
Please help. Thanks in advance.
#Remote
public interface FileProcessSttgFacadeRemote {
//methods
}
#Local
public interface FileProcessSttgFacadeLocal {
//methods
}
#Stateless
public class FileProcessSttgFacade implements FileProcessSttgFacadeLocal, FileProcessSttgFacadeRemote {
//methods
}
in weblogic-ejb-jar.xml
<weblogic-enterprise-bean>
<ejb-name>FileProcessSttgFacade</ejb-name>
<stateless-session-descriptor>
<business-interface-jndi-name-map>
<business-remote>com.xyz.fileProcessSetting.FileProcessSttgFacadeRemote</business-remote>
<jndi-name>FileProcessSttgFacade</jndi-name>
</business-interface-jndi-name-map>
</stateless-session-descriptor>
</weblogic-enterprise-bean>
In web application also in ejb module whenever we want to call methods we use following lookup method to get remote object:
public class someclass extends EjbLocator {
public void someMethod(){
FileProcessSttgFacadeRemote fpfr = (FileProcessSttgFacadeRemote) getService("FileProcessSttgFacade");
//other code
}
}
Following is the class used for JNDI lookup:
public class EjbLocator {
public Object getService(final String jndiName) throws Exception {
try {
obj = getDefaultContext().lookup(jndiName);
} catch (final Exception exp) {
exp.printStackTrace();
}
return obj;
}
protected Context getDefaultContext() {
try {
final Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
env.put(Context.SECURITY_PRINCIPAL,"weblogic");
env.put(Context.SECURITY_CREDENTIALS, "password");
env.put(Context.PROVIDER_URL, "t3://<ip>:<port>");
defaultContext = new InitialContext(env);
return defaultContext;
} catch (final NamingException nExp) {
nExp.printStackTrace();
}
return null;
}
}

Can I programmatically add a qualifier to a bean?

I am registering transaction managers in my code, I would normally use annotation based configuration but as I don't know until runtime how many data sources (and hence transaction managers) there will be, I have to programmatically register these, as follows:
private final void registerTransactionManagerBean(final DataSource dataSource, ConfigurableApplicationContext context) {
String transactionManagerName = this.getName() + "-transactionManager";
context.getBeanFactory().registerSingleton(transactionManagerName, new DataSourceTransactionManager(dataSource));
LOG.info("Registering transaction manager under name : " + transactionManagerName);
}
Assuming this.getName() returned 'mydb', I originally expected to be able to qualify a transaction manager like this:
#Transactional("mydb-transactionManager")
What I've realised however is the value of that annotation refers to the qualifier and not the name. I did a quick test by declaring a bean as below and it works:
#Bean
#Qualifier("mydb-transactionManager")
public PlatformTransactionManager test() {
return new DataSourceTransactionManager(new EmbeddedDatabaseBuilder().build());
}
My question is, is there a way I can programmatically add a qualifier when registering a bean?
UPDATE
I've worked this out, I'm falling foul of this problem (in BeanFactoryAnnotationUtils:isQualifierMatch):
catch (NoSuchBeanDefinitionException ex) {
// ignore - can't compare qualifiers for a manually registered singleton object
}
I am manually registering my transaction manager bean so I presume this is why I'm stuck. I'm not really sure what options that gives me apart from to not programmatically register transaction managers as a runtime thing sadly.
I've worked this out, I'm falling foul of this problem:
catch (NoSuchBeanDefinitionException ex) {
// ignore - can't compare qualifiers for a manually registered singleton object
}
I am manually registering my transaction manager bean so I presume this is why I'm stuck. I'm not really sure what options that gives me apart from to not programatically register transaction managers as a runtime thing sadly.
Raised as a JIRA issue - https://jira.spring.io/browse/SPR-11915
public class RuntimeRegistrationWithQualifierTest {
private AnnotationConfigApplicationContext context;
#Test
public void beanWithQualifier() {
final GenericBeanDefinition helloBeanDefinition = new GenericBeanDefinition();
helloBeanDefinition.addQualifier(new AutowireCandidateQualifier(Hello.class));
final GenericBeanDefinition worldBeanDefinition = new GenericBeanDefinition();
worldBeanDefinition.addQualifier(new AutowireCandidateQualifier(World.class));
final DefaultListableBeanFactory factory = context.getDefaultListableBeanFactory();
factory.registerBeanDefinition("helloBean", helloBeanDefinition);
factory.registerSingleton("helloBean", "hello");
factory.registerBeanDefinition("worldBean", worldBeanDefinition);
factory.registerSingleton("worldBean", "world");
context.register(Foo.class);
context.refresh();
final Foo foo = context.getBean(Foo.class);
assertThat(foo.hello).isEqualTo("hello");
assertThat(foo.world).isEqualTo("world");
}
#Before
public void newContext() {
context = new AnnotationConfigApplicationContext();
}
#Qualifier
#Retention(RUNTIME)
#Target({FIELD, PARAMETER})
#interface Hello {}
#Qualifier
#Retention(RUNTIME)
#Target({FIELD, PARAMETER})
#interface World {}
static class Foo {
final String hello;
final String world;
Foo(#Hello final String hello, #World final String world) {
this.hello = hello;
this.world = world;
}
}
}

Intermittent issue with Remote EJB invocation on WAS 7.0

We have a business functionality which is exposed as a Remote EJB. We shared the remote interface with the client. Below is the Remote interface that we shared.
public interface EmployeeRemoteEJB {
public Output saveEmployee(Input input);
}
public Output extends BaseObj{
private static final long serialVersionUID = -7096731222829800554L;
//some fields are there
}
public Input extends BaseObj{
private static final long serialVersionUID = -70967312228423800554L;
//some fields
}
public BaseObj implements Serializable{
}
Now Input class and Output class has some fields, which also extends from BaseObj and has a generated SerialVersion UID.
Now we have deployed this EJB on WebSphere Application Server 7.0. The Remote invocation of EJB works fine. It breaks when we do a deployment of the Client web app which calls the EJB or the
web application which has the EJB. We get the ClassCastException that the
com.test.ejb._EmployeeRemoteEJB_Stub incompatible with com.test.ejb.EmployeeRemoteEJB
When we restart the applications, it starts working again.
This is how we invoke the Remote EJB
//This JNDI name is configured for the remote EJB.
String REMOTE_LOOKUP_KEY = "empremotesvc";
String JNDI_PROVIDER_URL = "iiop://10.222.232.111:2809";
Properties props = new Properties();
props.put( Context.INITIAL_CONTEXT_FACTORY,"com.ibm.websphere.naming.WsnInitialContextFactory");
props.put( Context.PROVIDER_URL, JNDI_PROVIDER_URL );
Object lobj;
InitialContext ctx;
try{
ctx = new InitialContext( props );
lobj = ctx.lookup( REMOTE_LOOKUP_KEY );
EmployeeRemoteEJB empObjRemote = (EmployeeRemoteEJB) lobj;
return empObjRemote ;
}
catch( NamingException e ){
e.printStackTrace();
}
Can someone please let me know what is causing this issue? Please let me know if you need any further details.
You need to call PortableRemoteObject.narrow:
lobj = ctx.lookup( REMOTE_LOOKUP_KEY );
EmployeeRemoteEJB empObjRemote = (EmployeeRemoteEJB)
PortableRemoteObject.narrow(lobj, EmployeeRemoteEJB.class);
The problem does not always occur because JNDI caches resolved IOR-to-stub using the class loader of first client app to look up the EJB, so the first application to use the target EJB will work, but the second and subsequent will not unless they use PortableRemoteObject.narrow.

EJB 3.0 CMP Transaction after a rollback

I'm having some trouble with transaction management in EJB3.0. What I want to do is to log an error into the database in case an exception happens.
For that purpose I have 2 stateless beans: Bean A and Bean B.
Bean A does the following:
save something
call Bean B to log an error if needed
In Step 1, the save is basically using the EntityManager#merge(-) method.
In Step 2, I have put the following lines at the top of Bean B:
#Stateless(name = "ErrorLogDAO", mappedName = "ErrorLogDAO")
#Remote
#Local
#TransactionManagement(TransactionManagementType.CONTAINER)
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class ErrorLogDAOBean {...}
However, when an exception is taking place in the save method, I'm catching it and then I manually invoke the ctx.setRollBackOnly() method and after that I call ErrorLogDAOBean that inserts an error log to the DB. But the error log is not being inserted and the error I'm getting is:
javax.transaction.TransactionRolledbackException: EJB Exception: :
weblogic.transaction.internal.AppSetRollbackOnlyException at
weblogic.transaction.internal.TransactionImpl.setRollbackOnly(TransactionImpl.java:551)
at
weblogic.transaction.internal.TransactionManagerImpl.setRollbackOnly(TransactionManagerImpl.java:319)
at
weblogic.transaction.internal.TransactionManagerImpl.setRollbackOnly(TransactionManagerImpl.java:312)
at
org.eclipse.persistence.transaction.JTATransactionController.markTransactionForRollback_impl(JTATransactionController.java:145)
at
org.eclipse.persistence.transaction.AbstractTransactionController.markTransactionForRollback(AbstractTransactionController.java:196)
at
org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.rollbackTransaction(UnitOfWorkImpl.java:4486)
at
org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1351)
at
org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:468)
at
org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithPreBuiltChangeSet(UnitOfWorkImpl.java:1439)
at
org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.writeChanges(RepeatableWriteUnitOfWork.java:316)
at
org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:527)
....
I'm well familiar with transaction management logic, and based on the code above I assumed I had this covered, but it appears not.
Any ideas?
UPDATE
Bean A Code:
#TransactionManagement(value = TransactionManagementType.CONTAINER)
#TransactionAttribute(value = REQUIRED)
public class WMServiceBOBean {
public void saveInBeanA {
int errorCode = save();
if (errorCode != SUCCESS)
{
ClassX.logError();
ctx.setRollbackOnly();
return errorCode;
}
}
}
Class X Code:
public class classX
{
...
public void logError()
{
ErrorLog e = new ErrorLog;
BeanB beanB = //Local lookup of Bean B
beanB.insertErrorLog (e);
}
...
}
BEAN B Code:
#TransactionManagement(TransactionManagementType.CONTAINER)
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class ErrorLogDAOBean
{
...
public void insertErrorLog (ErrorLog e)
{
merge (e);
}
...
}
I finally figured out the problem.
Here's the problem, when looking up the ErrorLogBean, i was instantiating a new Persistence Manager. When the transaction gets flagged for rollback, the process of getting a new PM was failing. I know it doesn't make sense to get a new Persistence Manager but it was part of test we are conducting.
Thanks Piotr for all your help in this!

Resources