I'm using a Java EE 7 + GlassFish and need to perform some operation against a number of JPA entities from a stateless bean.
#Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
///do some work against entity
}
}
}
This JobRunner bean is injected into the servlet and I invoke do() method from the web UI.
The issue is that all entities are being changed within one transaction so if one fails everything is rolled back what is not desirable. Is there a way to start and close a new transaction for each entity (i.e. for each iteration of the loop)?
I can write an external client and make a loop there calling a stateless bean for each entity but it's not something that completely works for me as I prefer to keep an app monolithic. Can I somehow manage transactions form inside a container?
Maybe JMS helps? If I implement a doer as message listener and will be sending a message for each entity, will it start a new transaction for each one?
#Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
sendMessageToRealDoer(entity);
}
}
}
Create another bean, specifying #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW), at method or bean level:
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
#Stateless
public class JobWork {
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doWork(Entity entity) {
// do what you would do in the loop with the Entity
// this runs in a new transaction
}
}
I wish I could tell you that you only need to annotate a method of the same bean (JobRunner) and simply call it. This is not possible (EDIT)without workarounds - check comment from Steve C(/EDIT) because when calling methods of this object in EJBs and CDI beans the interceptors do not get called. Transactions are implemented with interceptors in both cases.
Some notes:
If the total duration of the operations in the loop is expected to be long, you will get a timeout in the outer transaction, that is implicitly started for the JobRunner stateless EJB. You will want to take measure that no "outer" transaction is started.
Sending the data to a queue will work too; but queues will process them asynchronously, meaning that the execution will return to the servlet calling JobRunner.do() most probably before all items have been processed.
Related
Most of business logic of our product consists in many automatic jobs which perform data loading from DB, processing and final persistence.
Each job is an EJB like the following:
#Stateless
#Local(Job.class)
#TransactionManagement(TransactionManagementType.BEAN)
public class JobImpl {
#Resource
private TimerService timer;
#Resource
private UserTransaction transaction;
#PersistenceUnit
private EntityManagerFactory emf;
#EJB
private BusinessLogicEJB someDependencyEJB;
}
Each job, after is started, is configured to be automatically scheduled every n seconds using EJB TimerService:
this.timer.createIntervalTimer(1000, properties.getTimeout(), new TimerConfig(properties, false));
where properties is an object wrapping that job configuration. In this configuration it is set up how many items the job is supposed to process at each cycle and if multithreading is allowed. If yes, it is also specified the max number of threads and how many items per thread must be processed.
So, when #Timeout annotated method is called, all data waiting to be processed is loaded from DB. If more than max items allowed for a single thread are loaded and if multithreading is enabled, these items are splitted into N threads, each created by
this.timer.createSingleActionTimer(0, new TimerConfig(itemsChunk, false));
which creates a single execution timer. Then, when all threads are created, the EJB father (class implementing job) waits them to finish:
private void waitToComplete(){
while(timer.getTimers().size() > 2){
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
Each child process calls #Timeout annotated method but it is detected as a child thread and it follows its own branch until it finishes:
#Timeout
public void execute(Timer tm) {
JobProperties properties = (Properties)tm.getInfo();
if(tm.isSubTask()) {
List chunk = tm.getElementsToExecute();
process(chunk);
}
}
where process() is a private method which can use some other injected business logic EJB or the EntityManager and so on.
Finally, a new schedule time is arisen and everything starts again from the beginning.
Now, I was asked to perform some refactoring and we want out EJB Job class as #Singleton while threads processing must not be created by TimerService but by #Asynchronous annotation.
Is is possible to annotate with #Asynchronous a private or a public method of the same EJB (like process()) in order to get a new generated thread?
Actually I created a brand new further EJB bean managed transaction with process() method which has injected EJB someDependencyEJB and uses UserTransaction for DB transaction but this is too bug refactoring.
Is there a way to re-use private methods (or made them public) of the #Singleton EJB to correctly perform with #Asynchronous and without having a "Trasaction already exists" exception each time a new thread is created?
We run or product in Wildfly 10 with EJB 3.1 Java EE 6, and unfortunately we cannot update to Java EE 7.
I have a following code structure, I need guidence on how to start a local transaction cascaded from a NOT_SUPPORTED transaction type method in same EJB.
#Stateless
#TransactionManagement(value = TransactionManagementType.CONTAINER)
public class SessionBean implements SessionBeanInterface{
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void methodA() {
methodB();
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void methodB() {
}
}
Currently when I try this i get below exception.
No active transaction for PuId=App#EJB.jar#Persistence
The way you have called "methodB" would not give a chance to the EJB Container to start a transactional context for you. To do that you have to invoke that method through either Remote or Local views/interface.
It is the container who supplies you these additional features and hence it is necessary to route your calls through interface than. (On a side note this is Proxy Design Pattern).
If you directly call "methodB" as you have done in above code snippet, it is just another method call without container intervention.
I have 2 Stateless EJBs StatelessA and StatelessB, both of them have interceptors InterceptorA and InterceptorB respectively. Also, StatelessB has Asynchronous methods. Something like this:
#Stateless
#Interceptors(InterceptorA.class)
public class StatelessA{...
#Stateless
#Asynchronous
#Interceptors(InterceptorB.class)
public class StatelessB{...
When calling a method on StatelessA, it calls several StatelessB methods and returns a value.
I am trying to develop 2 interceptors to store the total time and the subtotal times of StatelessB calls, this is the objective of the interceptors.
I need to do it so InterceptorA can see the detail of InterceptorB data, so I store only a value in the DB, containing the total time (of SLSB A) and the subtotal times (of SLSB B).
I tried using a ThreadLocal variable (containing a list of times, something like long[]), which works fine if StatelessB is not asyncrhonous.
The problem is that when it is asynchronous, the variable is not available, since it is running in a different thread (AFAIK).
I also tried injecting EJBContext or using the InvocationContext, but none of them works.
Can someone point me out what other alternatives do I have?
Thanks in advance.
I was thinking this over and over, and arrived to a solution, which is using the security context to pass data.
The solution involves using the only data propagated in an asynchronous invocation, as specified in EJB 3.1:
4.5.4 Security Caller security principal propagates with an asynchronous method invocation. Caller security principal propagation
behaves exactly the same for asynchronous method invocations as it
does for synchronous session bean invocations.
In JBoss, one can access the security context and use a data map in it to pass the values from InterceptorA to InterceptorB, as follows:
In InterceptorA:
SecurityContext securityContext = SecurityContextAssociation.getSecurityContext();
securityContext.getData().put("interceptorAData",data);
In InterceptorB:
SecurityContext securityContext = SecurityContextAssociation.getSecurityContext();
securityContext.getData().get("interceptorAData");
I tested it and it works great in JBoss EAP 6.1.
This solution implies couplig the interceptor to the server implementation (JBoss AS), but the principle works for other servers.
The advantage is that it decouples the application logic from the interceptors, which was the first objective.
I appreciate any comments.
Would it work to store the information you need in an #Entity object and then use the #PersistenceContext annotation to inject an EntityManager into the beans to persist and find the data? Something like:
#PersistenceContext
EntityManager entityManager;
...
method() {
MyEntityTimer met = new MyEntityTimer(getCurrentTime(), id);
entityManager.persist(met);
}
...
elsewhere:
MyEntityTimer met = entityManager.find(MyEntityTimer.class, id);
and:
#Entity
#Table(name = "TABLE")
public class MyEntityTimer {
#Id
#Column(name = "ID")
private int id;
...
}
I'll answer my question with what I ended up doing.
The only way I found to pass a variable from interceptor A to interceptor B was adding a parameter to the EJBs A and B, something like this:
#Stateless
#Interceptors(InterceptorA.class)
public class StatelessA{
public void methodA(Object reserved, ...other params )
#Stateless
#Asynchronous
#Interceptors(InterceptorB.class)
public class StatelessB{
public void methodB(Object reserved, ...other params)
This way, when InterceptorA is called, I'll set the reserved parameter with the data I need to share with InterceptorB.
InterceptorB will access this variable with no issue getting it from the parameters.
The down side to this solution is that the dummy parameters are needed, coupling in some way the EJBs with the interceptors..
I have a method A running in the transactional scope which:
Modifies an entity A to switch from state A to state B
Passes a task to a executor service that expects an Entity to be in state B when executed
The problem is when this task is run (that thing I have no control of) before the method A commits, it doesn't see the required state changed because it does not block until the method A level transaction ends.
Task is run using a spring bean and #Transactional-annotated method like this:
#Service
public class TransactionalProcessingAdapter implements ProcessingAdapter {
#Override
#Transactional
public void execute(ProcessingAdaptedMethod processingAdapter) {
processingAdapter.execute();
}
}
What am I doing wrong? Thanks!
The thing is that Spring transactions are thread bounded - eg a transaction is visible inside its initial threads only. ThreadLocal is used to implement that property.
You might want to implement your own TransactionSynchronizationManager in Spring and inject it. Use something like InheritableThreadLocal instead of ThreadLocal.
I'm using a JPA EntityListener to do some additional audit work and am injecting a Spring-managed AuditService into my AuditEntryListener using #Configurable. The AuditService generates a collection of AuditEntry objects. The AuditService is itself a Singleton scoped bean, and I'd like to gather all the AuditEntry objects under a common key that can then be accessed by the outermost service layer (the one that invoked the persist call which in turn triggered the EntityListener).
I'm looking at using Spring's TransactionSynchronizationManager to set a specific transaction name (using UID() or some other unique strategy) at the beginning of the transaction, and then using that name as a key within the AuditService that will allow me to group all AuditEntry objects created within that transaction.
Is mixing declarative and programmatic transaction management have the potential for trouble? (Though I'm doing nothing more than setting the transaction name). Is there a better way to associate the generated AuditEntry objects with the current transaction? This solution does work for me, but given that the TransactionSynchronizationManager isn't intended for application use, I'd like to make sure that my use of it won't cause some unforseen problems.
Related Question
Finally, a related, but not immediately pertinent question: I know that the documentation for JPA EntityListeners cautions against using the current EntityManager, but if I did want to use it to diff an object against it's persisted self, would I be safe using an #Transactional(propagation=REQUIRES_NEW) annotation around my preUpdate() method?
Prototype Code:
Service Class
#Transactional
public void create(MyEntity e) {
TransactionSynchronizationManager.setCurrentTransactionName(new UID().toString());
this.em.persist(e);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
#Override
public void afterCommit() {
Set<AuditEntry> entries = auditService.getAuditEntries(TransactionSynchronizationManager.getCurrentTransactionName());
if(entries != null) {
for(AuditEntry entry : entries) {
//do some stuff....
LOG.info(entry.toString());
}
}
}
});
}
JPA EntityListener
#Configurable
public class AuditEntryListener {
#Autowired
private AuditService service;
#PreUpdate
public void preUpdate(Object entity) {
service.auditUpdate(TransactionSynchronizationManager.getCurrentTransactionName(), entity);
}
public void setService(AuditService service) {
this.service = service;
}
public AuditService getService() {
return service;
}
}
AuditService
#Service
public class AuditService {
private Map<String, Set<AuditEntry>> auditEntryMap = new HashMap<String, Set<AuditEntry>>();
public void auditUpdate(String key, Object entity) {
// do some audit work
// add audit entries to map
this.auditEntryMap.get(key).add(ae);
}
}
#Filip
As far as I understand, your requirement is:
Have an unique token generated within each transaction (database
transaction of course)
Keep this unique token easily accessible across all layers
So naturally you're thinking about the TransactionSynchronizationManager provided by Spring as a facility to store the unique token (in this case, an UID)
Be very carefull with this approach, the TransactionSynchronizationManager is the main storage helper to manage all the #Transactional processing for Spring. Under the #Transactional hood, Spring is creating an appropriate EntityManager, an appropriate Synchronization object and attach them to a thread local using TransactionSynchronizationManager.
In your service class code, inside a #Transactional method your are tampering with the Synchronization object, it can end up with undesirable behavior.
I've done an indept analysis of how #Transactional works here, have a look: http://doanduyhai.wordpress.com/2011/11/20/spring-transactional-explained/
Now back to your needs. What you can do is:
Add a Thread local to the AuditService, containing the unique token when entering the #Transactional method and destroy it when exiting the method. Within this method call, you can access the unique token in any layer. Explanation for ThreadLocal usage can be found here: http://doanduyhai.wordpress.com/2011/12/04/threadlocal-explained/
Create a new annotation, let's say #Auditable(uid="AuditScenario1") to annotate methods that need to be audited and use Spring AOP to intercept these method calls and manage the Thread local processing for you
Example:
Modified AuditService
#Service
public class AuditService {
public uidThreadLocal = new ThreadLocal<String>();
...
...
}
Auditable annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#Documented
public #interface Auditable
{
String uid();
}
Usage of #Auditable annotation
#Auditable(uid="AuditScenario1")
#Transactional
public void myMethod()
{
// Something
}
Spring AOP part
#Around("execution(public * *(..)) && #annotation(auditableAnnotation))
public Object manageAuditToken(ProceedingJoinPoint jp, Auditable auditableAnnotation)
{
...
...
AuditService.uidThreadLocal.set(auditableAnnotation.uid())...
...
}
Hope this will help.
You can come up with a solution using the TransactionSynchronizationManager. We register a "TransactionInterceptorEntityListener" with JPA as an entity-listener. What we wanted to achieve is the ability to listen to CRUD events such that we can work with a spring managed "listener" that has a lifecycle tied to the current transaction (i.e., spring-managed but instance per transaction). We sub-class the JPATransactionManager and introduce in the prepareSynchronization() method, a hook to setup a "TransactionInterceptorSynchronizer." We also use the same hook for allow code (in programmatic tx) to associate and retrieve arbitrary objects with the current transaction and also register jobs that run before/after transaction commit.
The overall code is complex, but definitely do-able. If you use JPATemplates for programmatic tx, it is tough to achieve this. So we rolled our own template that simply calls the JPA template after taking care of the interceptor work. We plan to open-source our JPA library (written on top of Spring's classes) soon.
You can see a pattern of adding custom transactions and hooks with Spring managed transactions in the following library for Postgresql