Java container managed transactions - java

I have encountered a problem and I can't figure out the cause. For the rest of the post, we shall assume that every transaction is container managed and that we use jboss AS 7.X. We have three stateless ejb's. We will call them RestEJB, IntEJB and ProviderEJB. The provider base methods are:
save(){
return getEm().merge(ob);
The core line of the load method is:
load(){
Query query = getEm().createQuery(criteriaQuery);
The base order is something along the lines of RestEJB -> IntEJB -> ProviderEJB.
Now, depending on the order of the operations, we may receive a ARJUNA012117 error in jboss.
The problematic code is this:
RestEJB.someMethod(){
item = IntEJB.save(item)
}
IntEJB.save(Item item){
...
ProviderEJB.save(item)
return ProviderEJB.load(item)
}
However if we rewrite it like this:
RestEJB.someMethod(){
item = IntEJB.save(item)
item = IntEJB.load(item)
}
IntEJB.save(){
...
return ProviderEJB.save(item)
}
IntEJB.load(){
...
return ProviderEJB.load(item)
}
Then everything will work properly. In the above examples, item represents the same Object. Thus, the save and load are done on the same object (which may in turn trigger other fetches). There is no code written between save and load in either of the examples.
The question is this: How come it works when we move the load one ejb up as opposed to loading at the same level ejb as the save?
Since we use hibernate, all the code will be commited to the database only after we exit RestEJB.

Related

Mandatory Flush for a repository

Situation: JPA, SpringBoot, Hibernate
public interface ViewRepository
extends JpaRepository<SomeView, Long>, JpaSpecificationExecutor<SomeView> {
Optional<SomeView> findByIdAndLanguageId(Long id,Long lid);
}
//service
SomeView getSomeView(){
SomeView someView1 = repo.findByIdAndLanguageId(id,lid1);
....
//now get in it in different lang id
SomeView someView2 = repo.findByIdAndLanguageId(id,lid2);
//the problem here is that the value for someView2is the same as someView1 since hibernate cash this.
}
Is there an annotation / way to prevent this caching for any call to this repository only?(not application wide turning of the caching) at service level or repository level ....
This is main feature of Hibernate.
If you look something up and change new found entity, changes will be saved to database without any additional code.
If you don't want that you need to use thing called "stateless session". But please warn everyone around about it, because otherwise you end up with many surprised people. This "stateless session" isn't very popular thing and no one will expect you use it.
If you don't want this caching to happen, you can immediately detach the entity after reading it i.e.:
SomeView someView1 = repo.findByIdAndLanguageId(id,lid1);
entityManager.detach(someView1);

Upgraded spring-boot/spring-framework to 2.x.x/5.x.x for Spring Batch Java project and now data not being written/saved to Database (Postgresql)

I recently upgraded/migrated my Spring Batch Java application from spring-boot-starter-parent-1.5.9.RELEASE to -> spring-boot-starter-parent-2.2.4.RELEASE, which subsequently pulls in the 5.X.X (5.2.3.RELEASE to be exact) springframework dependencies (before I was using 4.X.X). Some of the main ones I'm using are:
spring-boot-starter-parent-2.2.4
spring-boot-starter-batch
spring-boot-starter-jpa
spring-boot-starter-web
hibernate-core
hibernate-envers
hibernate-entitymanager
postgresql
For context, my application reads in .csv files and parses out the data and simply writes it to a postgresql database.
After many hours of debugging today, I know see that my first call to write data to the database, which is done by a JpaRepository method called saveAll(), which basically takes an ArrayList (Iterable) of Entities and batch inserts them to database, is failing somewhere when it enters the JdkDynamicAopProxyClass from the Spring AOP library. Previously, I was using the save() method, but this didn't work anymore once I upgraded my dependencies.
I know its failing here because I debugged meticulously and see that once it hits the saveAll() method in my java class that implements the ItemWriter<S> for Spring Batch, it enters the public Object invoke(Object proxy, Method method, Object[] args) method in the JdkDynamicAopProxyClass, and ends up throwing an exception, after doing a huge weird loop in the library code that's hard to follow.
I also debugged my old Application that WAS WORKING when it was running on spring-boot-starter-1.5.9 as I stated previously, and I see that when it gets to that public Object invoke() method (I mentioned above), it returns an ArrayList of the entities (which is correct) to write to the Database when it hits this line of code inside that method:
public Object invoke(Object proxy, Method method, Object[] args) {
// code here...
// this is where I notice a difference in return type from the "working" code vs. "broken
// code"
retVal = invocation.proceed();
// more code here...
Object var12 = retVal;
return var12;
HOWEVER, when I debugged my new migrated code (that was upgraded to spring 2.X.X/5.X.X, I see it returns a DefaultTransactionStatus#14037 object, which clearly is wrong. It then enters the protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary() method in the TransactionAspectSupport class from the spring-tx library. It will then have the retVal variable in the invoke method I mentioned above equal to null and it will start looping a few times more, over the same parts of code in a circle. It will have the txInfo set as PROPAGATION_REQUIRES_NEW,ISOLATION_SERIALIZABLE. I can click the "Step Into" button in IntelliJ and it will let me step through forever. Its like a infinite loop.
I'm not sure what to post, or if there are any clues here. I googled and found other people have similiar issues, and it seemed to revolve around (possibly) the transaction manager or entity manager and how the Beans were setup in the configuration class.
I tried everything I read, but nothing worked. I'm not an expert with Spring Batch or Spring so maybe I am missing something here.
I also noticed when I was debugging my working code, it had a variable Target = SimpleJpaRepository#11243 and it had some properties like a ArrayList of Providers
Em = Shared EntityManager proxy for target factory [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6f2b608e]
Provider = HIBERNATE
org.hibernate.Session [0]
org.hibernate.jpa.HibernateEntityManager [1]
org.hibernate.ejb.HibernateEntityManager [2]
The odd thing was when I debugged my "broken" code, it seemed to only have the org.hibernate.jpa.HibernateEntityManager in its List in this variable
If anyone can please let me know if there are some clues pointing to something, I would immensely appreciate it. I really think its a Bean config, Entity Manager/Transaction-issue, but I'm not an expert so I'm not sure. I thought it was a dependency issue at first, but after being on google that changed my mind.

How to get a navigation node without setting hardcoded catalog version in Hybris?

I call a method from a custom Category Service within an AfterSaveListener and in this method i need root navigation nodes which is returned by cmsNavigationService but whenever I call this method, it throws an error:
de.hybris.platform.cms2.exceptions.CMSItemNotFoundException: No NavigationNode with id.
When i set hardcoded content catalog via
getCatalogVersionService().setSessionCatalogVersion(".....")
I handle this problem but it does not seem true to me. I can handle the same problem for categories by using
userService.setCurrentUser(userService.getAdminUser());
in order to remove all restrictions for flexible search but this solution did not work for navigation node.
How can I solve this problem?
In general you can't get navigation nodes without a Catalog Version because they are Catalog aware, this means you have several instances of one NavigationNode. In this case Hybris can't know which exactly you need. However, your workarounds can be handled in a better way. When you need a specific user for something in your code, you can use it like this. Just to be sure, you can add a try - finally block in execute() and set your params in try and remove them in finally.
private Object myMethod()
{
return getSessionService().executeInLocalView(new SessionExecutionBody()
{
#Override
public Object execute()
{
// Your code for an isolated session. Set session params here, remove restrictions and so on.
//searchRestrictionService.disableSearchRestrictions(); for example
return new Object();
}
}, userService.getAdminUser()); // You can also specify as which user you want to execute the code
}
Another interesting thing is this.
final Map<String, Object> params = ImmutableMap.of(InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_TYPES,
ImmutableSet.of(InterceptorExecutionPolicy.InterceptorType.VALIDATE));
sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody()
Where you can specify different params. For example this one disables some interceptors.
The CMSNavigationService offers two methods for getting root navigation nodes:
One, that accepts nothing as parameters and one that accepts a catalog version as parameter. When you pass a catalog version, the service will search for navigation nodes in this specific catalog version.
When you do not specify one, it will search in the sessions catalog version. hybris does not set up catalog versions in the session for cronjobs. So you should not find a navigation node. When you manually set a catalog version into the session (with the snippet in your question), it will work again.
I hope I understood the question correctly.

NewRelic Java API and Transaction boundaries

I want to monitor a critical part of our Java Application (Glassfish v3.1.2 JSF2 application).
I want to track a specific function call as a new transaction. This method can be called within the "/Faces Servlet" or any other JAX-RS transactions.
The #Trace annotation seems to be perfect for my case but reading the doc it is not clear if it supports nested transactions (like the REQUIRES_NEW J2EE transaction semantic).
Here is the method I want to track
#Trace(dispatcher=true, matricName="Internal/Query")
public void query(Query q) {
long st = -System.currentTimeMillis();
// do my stuff
st += System.currentTimeMillis();
NewRelic.addCustomParameter("Client", q.getClient());
// Add useful parameters
NewRelic.recordResponseTimeMetric("Internal/Query/queryTime", st); // Is this needed?
}
And for example a JAX-RS WS like this :
#GET
public Response wsquery(...) { // <- Start NewRelic Transaction T1
myBean.query(q1); // <- Start nested Transaction T1.1
myBean.query(q2); // <- Start nested Transaction T1.2
}
Will I Have 3 transactions tracked?
One for the JAX-RS call to wsquery and two for Internal/Query.
Thanks.
Based off of the information provided it's not certain exactly what you're going to get. I recommend giving it a test. You can also bump up the logging level to the "finest" level and see exactly what is being instrumented. If you run into issues beyond that contact us at http://support.newrelic.com

Seam/Hibernate validator listener

We use a standard SEAM setup here ... complete with the validation system that uses hibernate.
Basically what happens is a user enters a value into an html input and seam validates the value they entered using the hibernate validation.
Works fine for the most part except here's my problem: We need to record the results of validation on each field and I can't figure out a good way to do it ... ideally it would be done through communicating with the seam/hibernate validation system and just recording the validation results but as far as I can tell there isn't a way to do this?
Has anyone done anything like this in the past? There are a couple nasty work arounds but I'd prefer to do it cleanly.
Just a quick overview of the process that we have happening right now for context:
1) user enters field value
2) onblur value is set with ajax (a4j:support) at this point the validators fire and the div is re-rendered, if any validation errors occured they're now visible on the page
What I'd like to have happen at step2 is a 'ValidationListener' or something similar is called which would allow us to record the results of the validation.
Thanks if anyone is able to help :o
You should be able to do it by creating a Bean that has a method observing the org.jboss.seam.validationFailed event. That method can then do whatever logging you want.
#Name("validationObserver")
public class ValidationObserver() {
#Observer("org.jboss.seam.validationFailed")
public void validationFailed() {
//Do stuff
}
}
The validationFailed event doesn't pass any parameters so you'll have to interrogate the FacesMessages or possibly the Hibernate Validation framework itself if you want to record what the error was.
I you are only using Hibernate for validation, you can use the Hibernate ClassValidator in the validationFailed() method, as recommended by Damo.
Example:
public <T> InvalidValue[] validateWithHibernate(T object) {
ClassValidator<T> validator = new ClassValidator(object.getClass());
InvalidValue[] invalidValues = validator.getInvalidValues(object);
return invalidValues;
}

Categories