Hibernate/JPA TransactionManagment - java

First of All I have to apologize for the semi-psuedo code as the classes I am going to reference are all too big and are pointless except for a few lines of each class to ask my question.
To Start off I am using
Jboss 6.3.2 EAP
Hibernate
EJB 3.0
I have two different EJB Classes
They are
Service Layer
#Stateless
#TransactionManagement
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class ServiceClass implements ILocalService
{
#EJB
ILocalDao localDao;
#Override
public myObject find(String id)
{
localDao.findByPK(id);
}
#TransactionalAttribute(TransactionAttributeType.REQUIRED)
#Override
public void create(myObject obj)
{
localDao.create(obj);
}
#TransactionalAttribute(TransactionAttributeType.REQUIRED)
#Override
public void update(myObject obj)
{
localDao.findByPK(obj.getId());
localDao.update(obj);
}
}
DAO Layer
#Stateless
#TransactionalAttribute(TransactionAttributeType.MANDATORY)
public class DaoClass extends AbstractDaoClass<myObject> implements ILocalDao
{
#Override
public myObject findByPK(String id)
{
super.find(id);
}
}
Okay with those two classes laid out. Trust me that everything else is correctly configured interface Classes, Abstract Class, persistence.xml, etc.
The question is How does the find method in the ServiceClass work? With the NOT_SUPPORTED being assigned to this method I would think that the DaoClass call would throw a Exception because no Transaction has been started yet and I am making the entire class MANDATORY. But my running app says otherwise.
To verify that no transaction is being created on the DaoClass.find method. I put in the #TransactionalAttribute(TransactionAttributeType.NEVER). And re-ran the application. Still works.
To verify that the NEVER works I call the ServiceClass's update method. Throws an exception as expected.
To round this all out I have looked at many online resources(http://docs.oracle.com/javaee/6/tutorial/doc/bncij.html, etc) I have looked into the source files for the EJB 3.0 and Jboss...I am not seeing anything.
So questions I have pondered
Is the TransctionAttributeType.MANDATORY on the class level not
working as I expect it to in the DaoClass?
TransactionManagement on the ServiceClass creating a Transaction on init of the ServiceClass and then the NOT_SUPPORTED suspending this transaction?
I am in the process of writing up some tests to hopefully log the transaction's behavior and see what is going on. But hopefully someone here can shed some light sooner and relieve this huge question mark I have.
Thanks in advance.

First, #TransactionManagement without parameters is useless, since default value is TransactionManagementType.CONTAINER and EJB uses TransactionManagementType.CONTAINER implicitly.

Related

using spring transactionManager with Hibernate after transaction committed only one repository of two is actually being committed

I have a #Transactional method that changes the state of two entities of different, not related, repositories.
something like this:
#Transactional
public void foo() {
A a = repoA.findById(1);
a.setState(s1);
B b = repoB.findById(1);
b.setState(s2);
// (and I also do repoA.save(a); and repoB.save(b); although it is redundant)
}
I also have a transactional method bar that calls foo and publishes an event that is being caught by a TransactionalEventListener like this:
#Transactional
public void bar() {
foo();
applicationEventPublisher.publishEvent(new AppEvent(123));
}
and
#Component
public class MyApplicationEventListener {
#TransactionalEventListener
public void handleAfterCommit(AppEvent appEvent){
//do something;
}
}
Now the issue is that in 80% of the time when handleAfterCommit method is invoked, only (A a ) is being committed but (B b) is losing its changes.
I need help to understand what is going on here, I tried to debug and explore the
TransactionAspectSupport.currentTransactionStatus() but didn't find any insights.
Thanks,
Eilon
I found the issue, we are using a custom AttributeConverter and we didnt implement Equals for the relevant javav object, this caused every dirty check on select to fail and do a full update (overriding values that meanwhile have been changed)
Thanks

How to activate an OSGI bundle only when the certain condition is satisfied?

I'm a bit new in OSGI and I want the following: to activate my bundle only when some prerequisites are satisfied (which, btw, we get form a native library, but that's another story). AFAIK it could be achieved through the #Reference DS, but I don't get the idea fully. I mean if I write something like this before my #Activate DS:
#Reference
public AnotherService as
#Activate
public void activate() {
//some code
}
this actually means, that my bundle won't be activated until the AnotherService is activated. But could I write in AnotherService or in my bundle something like this?:
#Activate
public void activate() {
if (condition){
deactivate()
}
//some code
}
#Deactivate
public void deactivate() {
//some code
}
As far as I understand, that's impossible. Then the questions arises: how could I control the activation of my bundle or its references depending on certain condition(s)? I.e. I want my bundle to be either activated, when the condition is satisfied (before activation) or deactivated, when not. It won't suit for me the way: "just make if-statement, if it is not satisfied, do nothing, but still be activated", because the 'activiy' of this bundle is very resource heavy. Maybe I just have a fully wrong idea of OSGI.
This is not something you should do. Your bundle should always be activated as long as it can be resolved (i.e. all of its imports and other static dependencies are satisfied).
In fact, unless you are coding OSGi at an advanced level, you should not write BundleActivators at all. If you are reading an OSGi tutorial in 2020 that tells you to write a BundleActivator, stop reading... that tutorial is junk.
You should use Declarative Services components. A component is an object managed by OSGi and can have its lifecycle bound to the availability of a service. For example:
#Component
public class MyComponent implements MyService {
private final AnotherService service;
#Activate
public MyComponent(#Reference AnotherService service) {
this.service = service;
}
#Override
public void doSomething() {
// ...
}
}
In this example, an instance of MyComponent will be created and published as a service of type MyService only when a service of type AnotherService is available. You will be able to invoke the AnotherService via the final service field. This is a mandatory service reference, which is the default in DS, but it's also possible to create optional and dynamic references (i.e. references that can re-bind to other service instances during the lifetime of your component), but don't worry about those use-cases until later in your OSGi learning.

transactional method throwing "no transactional entityManager available"

I have a method that is defined as #transactional. In fact I have a method calling a method that calls a method and all three are #transactional. The transactional logic worked fine, until I pulled a few methods out into an abstract class for some code reuse, which appears to have broken my logic somehow.
The transactional method is from an abstract class, here is a partial snippet of the relevant parts (I have to rewrite this by hand so forgive me for typos):
public abstract class ReadWriteService<ReadEntityTempalte extends IEntity, WriteEntityTemplate extends IEntity>
//extends jpaRepository, created using #enableJpaRepositories
private searchRepository<WriteEntityTemplate, String> writeRepository;
#PersistenceContext
private EntityManager em;
#transactional
public ReadEntityTemplate save(final WriteEntityTemplate entity){
if(entity == null) return null;
WriteEntityTemplate returnValue = writeRepository_.save(entity);
postSave(returnValue); //checks our security logic
flush();
ReadEntityTemplate returnEntity = find(returnValue.getId());
//required to detect changes made to the view by our save
em.refresh(returnEntity);
}
It's written this way because we are using views so the return value may be modified in the find() to the view. This logic worked in the past, and still works for a number of calls.
The method that fails is:
#Override
#transational
public void configure(EntityFileConfig config) throws ClassNotFoundException{
//load config from file
for(EntityConfig entityConfig: entityConfigs){
EntityType entityType=EntityTypeService_.find(entityConfig.getKey());
if(entityType==null){
entityType = EntityType.createByRequiredFields(entityConfig.getKey());
}
//update entityType to reflect config file.
entityType = entityTypeService_.save(entityType);
for(String permissionName: entityConfig.getPermissions()){
if(!entityTypeService_.hasPermission(entityType, permissionName)){
Permission permission = permissionSetup.getPermission(permissionName);
if(permission!=null)
//fails on below lines
permissionService._.addPermission(entityType, permission);
}
}
}
}
both the entityTypeService and the permissionService extend the above abstract class and use the same save method without alteration, addPermissions is a forloop that calls save on each permission.
The entityTypeService works, but the permissionService fails. When The permission service is called if I do em.isTransactionalEntity it returns false.
All #transactional annotations are using the spring annotation, not the javax one.
Actually, it seems as if a few of the permissions would save and others wouldn't, almost as if it's non-deterministic, but this may simple be due to modifying a database file that had some of the values already set and thus didn't need to run some of the logic the first time through.
I've done quite a bit of stumbling around but am no closer to determining what would cause my transaction to end. I had thought perhaps it was the #persistenceContext, since the JPARepos get their entityManager through a different approach then autowireing with #persistenceContext, but if that were the case everything would fail?
Any help would be appreciated, I'm pretty stumped on the cause of this.
Assuming you have enabled #EnableTransactionManagement on #Configuration class.
Since you didn't set any propagation on #Transaction the default value is Required. It means all methods must be part of transaction. Since one of your abstract methods is not part of the #Transactional hence the error.
For more information on Spring Transactions.
Note: Image taken from above link.

Creating custom rollback method EJB3

I'm using EJB3.1 in my application which is running on JBoss AS 6. I'm working as integration developer and I have use case where as part of my transaction there are multiple calls to various external systems via REST, SOAP etc. If any of these calls throw exception I have to rollback changes to previously called systems.
Currently I'm having situation:
public class SystemAException extends RuntimeException {...}
public class SystemBException extends RuntimeException {...}
public class SystemCException extends RuntimeException {...}
System classes
public class SystemA{
public static makeChanges() throws SystemAException{...}
public static cancelChanges() {...}
}
public class SystemB{
public static makeChanges() throws SystemBException{...}
public static cancelChanges() {...}
}
public class SystemC{
public static makeChanges() throws SystemCException{...}
public static cancelChanges() {...}
}
Call
static makeChanges(Object o){
persist(o); //DB work
try {
SystemA.makeChange();
SystemB.makeChange();
SystemC.makeChange();
} catch(SystemBException eb){
SystemA.cancelChanges();
throw eb;
} catch(SystemCException ec){
SystemA.cancelChanges();
SystemB.cancelChanges();
throw ec;
}
update(o); //more DB work
}
I would like to get rid off try-catch and to instruct JBoss to call method cancelChanges() whenever RuntimeException occurs like it does when it rollback changes made to DB.
I'm aware that I could use Commander pattern to undo previously made changes, but I would like to know if container can do that for me.
If it is possible, I would like to accomplish following thing
static makeChanges(Object o){
persist(o); //DB work
SystemA.makeChange();
SystemB.makeChange();
SystemC.makeChange();
update(o); //more DB work
}
If you're calling non-XA external systems via REST/SOAP, what happens if your JVM/network crashes before you can undo the changes? That sounds like a fragile architecture.
Regardless, ther is no way to get the EJB container to do this for you automatically. The best idea I have is to have SystemA/SystemB/SystemC call TransactionSynchronizationRegistry.registerInterposedSynchronization, and then you can be notified when the transaction is rolling back (since the EJB container will roll back transactions automatically if a system exception or application with rollback=true is thrown), and then you can try to undo whatever. Of course, if the JVM crashes then your interposed synchronization listeners will be lost and you can't undo, so it still doesn't solve that problem.

Testing DAO and Service / Spring

The question has already been asked at Stackoverflow but I haven't found the answer. I can't understand how to test (unit) my DAO and Service layers (you will be able to find the methods I would like to test below). So, there are two opposite notions regarding testing of DAO: the one is not to test it at all, the opposite one is to test it only with in-memory DB. As for service layer there are meaning that method should be tested only if it has business logic. So, frankly I can't even imaging what to do because I'm not sure which the way is correct. At my last pet project I tested DAO by using jUnit only (examle for saveEntity()): I explicitly created entity, populated it, saved it by using DAO-method, when retrieved it, asserted result and explicitly deleted the object from the DB. I'm sure that it is not the proper way to test it. So, please take a look at the code below and give me an advice how to test these layers' methods properly:
DAO
#Override
public void saveEntity(Artist entity) throws ConstraintViolationException {
sessionFactory.getCurrentSession().save(entity);
}
Service
#Transactional
#Override
public void saveEntity(Artist entity) throws ConstraintViolationException {
artistDAO.saveEntity(entity);
}
I wanted to do it with Mockito but all examples I found not similar to my case.
Thank you for any ideas how to do that.

Categories

Resources