How to call dbms_application_info with EntityManager injection - jpa

We are building a Java EE / JPA / CDI app with an Oracle Database. The data model (this we can't change) implements security partly by using views and client_info...something like..
create view the_view
as select *
from the_table
where organization_id = USERENV('CLIENT_INFO')
where userenv('CLIENT_INFO') is basically set by calling
dbms_application_info.set_client_info(11);
Now, we have a series of Stateless Beans that basically inject Persistence Context and execute queries (both native queries and regular POJO) and we need a way to inject the client info (that we can get from the security context) into the PersistenceContext before making calls to the EntityManager
in a nutshell I need to be able to call this..
#PersistenceContext
EntityManager em;
#Inject
UserInfo userInfo;
public TheView getTableData(long id) {
// At this point security Information should be set..
// Call the query
return em.find(TheView.class, id);
}
without having to call a setClientInfo() manually..
One way of doing this would probably be using interceptors and annotate the method and make the call there (providing I can get hold of the PersistenceContext that the method will use.. ).. will this even work??
Any other way of doing this??
TIA!

The interceptor approach you are writing about sounds like an excellent fit.
I'm not 100% sure if I understood your requirements correctly, but it seems as if would be a good idea to decouple authorization logic from the actual business logic to be able to write something like this:
...
#IsEditor("someMoreData")
public X getData() {
...
}
IsEditor is an interceptor and will encapsulate the relevant DB lookup.
Seam Security as an independent CDI modules comes with a couple of concepts (& implementations), you should definitely check it out.

If you are using EclipseLink, there is some info here on using EclipseLink with Oracle VPD, which seems similar.
Nasically, you can use events to execute your call.
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/Shared_and_Isolated#Oracle_Virtual_Private_Database_.28VPD.29

Related

CDI with JEE: how handle dependency injection in the backend without EJB

I'm working on a REST api with Java, using JAX-RS, EJB, JPA and JasperReports, basically the API call a oracle function that return an id, with that id i make a select and generate reports with Jasper Reports, then i send the report as a response, works fine.
But, i have some questions if i should use or not use EJB, because i dont see why i should use EJB in this case, since the oracle function have commit inside of it, if something goes wrong, the rollback triggered by the EJB will not do nothing right? Also, the select that generates the report is simple, just one table, and i saw some articles saying that if you do just a select theres no need for using EJB to control the transaction.
Also, how to use CDI in this case? #Named in the classes and #Inject in the fields? I have some coworkers saying that #Named should be used just with JSF, but i'm a junior, seeking for the truth about this, after researching a lot i still dont know how to handle this, i apreciate any help.
Thanks!
Do I need EJBs for transactions?
If you are using JEE-7+ then you can use #Transactional for your CDI Beans instead of EJB-Beans with #Stateless and #TransactionManagement and #TransactionAttribute. #Transactional provides the same properties as #TransactionAttribute and makes any CDI Bean transactional without the need for an EJB Container. All of these approaches require JPA to be used, which for a simple single query is maybe an overkill.
https://docs.oracle.com/javaee/7/api/javax/transaction/Transactional.html
What can I use instead of EJBs and #Transactional?
If you don't need/want to use an EntityManager, then just use plain JDBC.
What does #Named do?
#Named makes CDI Beans accessible to Java-EL via their defined name, or if no one is defined then via their simple class name. You can also use #Named to distinguish between implementations, but I think CDI Qualifiers are more suitable to achieve that. So, if you don't need it, then don't annotate it.
How to provide CDI Beans to other CDI Beans?
In my opinion CDI Beans should be injected via Fields and not constructor arguments. Injection in constructor arguments is done because of testability, so you can test your beans without using CDI, which these days is not that hard to achieve anymore.
https://deltaspike.apache.org/documentation/test-control.html

Why JPA entities are treated like this outside a session?

Hy,
I am having a "Solve failed to lazily initialize a collection of role.... exception" in jpa. I understand that outside a session, when you want to retrieve a lazy collection if there is not session bound you will get this error, fine. But what I dont understand is if I have this spring controller(the code is not 100% correct, is just to explain my case):
#Controller
#Autowired
EnterpriseService enterpriseService ;
public List<Enterprise> getAll(){
List<Enterprise> enterprises = enterpriseService.getAll();
for(Enterprise enterprise:enterprises){
enterprise.getEmployees();
}
return enterprises;
}
When I call "enterprise.getEmployees()", I know there is not anymore a session but why when I try to do "enterprise.getEmployees()", why enterprise is treated like a jpa entity and not just like a normal bean?, I mean; for what I understand a jpa entity is treated like this inside a session but outside like in this case it should be treated like a normal java bean so the calling to enterprise.getEmployees() should be treated like the calling of a get method of a java bean and should not throw any lazy exception....
Maybe is because spring controller treats the enterprise objects like jpa entities and not just only like java beans? this behaviour is specific to spring controllers?
Thanks
An entity returned from an EntityManager is not necessarily an instance of your entity class, but a proxy class which extends your class. In many cases the same is true for the persistent properties of such entities (especially for those annotated with (One/Many)To(One/Many)).
For example if you are using field based access:
#Entity
public class Enterprise {
#OneToMany
private List<Employee> employees = new ArrayList<>();
public List<Employee> getEmployees() {
return employees;
}
}
Here the JPA provider will create a proxy class that extends Enterprise and remembers the previous state from the DB somehow. In addition it will change the employees list to its own implementation of List (which does not need to extend ArrayList).
Because the proxy class can "overwrite" your methods, it could know when you are calling getEmployees() and check for the session. But I don't think that this would happen here, as the method is not annotated with any JPA specific annotation.
In addition some frameworks like Hibernate do support byte code enhancement or byte code instrumentation. That changes the implementation of your class (in byte code) and replaces every access to employees with some provider specific code. I don't know if Spring JPA provides this, but this could lead to check for a session.
Otherwise any call to enterprise.getEmployees() should just return the current value of employees - without any check for the session and without the LazyInitializationException.
But calling enterprise.getEmployees().size() will try to initialize the list and check for the session - this could lead to the mentioned exception.
If you are using property based access things are a little bit different:
#Entity
public class Enterprise {
private List<Employee> employees = new ArrayList<>();
#OneToMany
public List<Employee> getEmployees() {
return employees;
}
}
Here the proxy class will not delegate to your implementation, but overwrite the getEmployees() method and return its own List implementation, without changing employees. Thus here it is possible to get a LazyInitalizationException for enterprise.getEmployees().
Remark: This describes how most JPA implementations are working - but as this is implementation specific some unusual frameworks could do things differently.
It can't do anything else. The only alternative would be to return an empty collection of employees, which would be much much worse: you would incorrectly assume that the enterprise has 0 employee, which is a valid, but completely incorrect result.
To realize how much worse it would be to do that, let's imagine a HospitalAnalysis entity, having a collection of DetectedDisease entities. And let's say you try to display the result of the analysis but forget to initialize the collection. The page would tell you that you're perfectly healthy and that you can safely go home, whereas in reality, you have a cancer, and the program has a bug. I'd much prefer the program to crash with an exception and be fixed rather than not starting my treatment.
Trying to access employees without having initialized the collection, and thus without knowing the actual collection of employees, is just a bug. This bug is signalled by throwing a runtime exception.

Update database with JPA

I'm trying to update my (MySQL) database but it does'nt work.
Persistence code (called by a JSF managed bean):
#Override
public void changeEntrepriseStatut(int idEntreprise, int newStatut) {
Entreprise entr = em.find(Entreprise.class, idEntreprise);
em.persist(entr);
entr.setEntrepriseStatutInscription(newStatut);
em.merge(entr);
}
Ensure that you have an open transaction.
How you can do that does depend on how you manage your beans with jsf. There are at least four ways.
#ManagedBean - is the less power full possibility you should never do an operation which needs a transaction in there. (Call an EJB for example)
CDI beans - more powerfull but does also not have support for transactions build in when I am correct (not sure what the status of JavaEE7 is)
EJB - this is probably the easiest way, because of the support for #Transactional
Spring - never used that, if your using that please search the net for how to do that.
Additional never call em.persist on an already persisted bean. Just drop the line.

Transaction needed if multiple EJB methods called?

My question is about the need to define a UserTransaction in a JSF Bean if multiple EJB methods are called.
This is my general scenario:
//jsf bean...
#EJB ejb1;
...
public String process(businessobject) {
ejb1.op1(businessobject);
ejb1.op2(businessobject);
....
}
both ejbs methods manipulate the same complex jpa entity bean object (including flush and detachment). I recognized in the database that some of the #oneToMany relations form my entity bean where duplicated when ejb1.op1() is called before ejb1.op2().
I understand that both ejbs start a new transaction. And to me anything looks ok so far.
But the JSF code only works correctly if I add a UserTransaction to my jsf method like this:
//jsf bean...
#Resource UserTransaction tx;
#EJB ejb1;
...
public String process(businessobject) {
try {
tx.begin();
ejb1.op1(businessobject);
ejb1.op2(businessobject);
finaly {
tx.commit();
}....
}
I did not expect that it is necessary to encapsulate both ejb calls into one usertransaction. Why is this necessary?
Each #Stateless EJB method call from a client (in your case, the JSF managed bean), counts by default indeed as one full transaction. This lasts as long as until the EJB method call returns, including nested EJB method calls.
Just merge them both into a single EJB method call if it must represent a single transaction.
public String process(Entity entity) {
ejb1.op1op2(entity);
// ...
}
with
public void op1op2(Entity entity) {
op1(entity);
op2(entity);
}
No need to fiddle with UserTransaction in the client. In a well designed JSF based client application you should never have the need for it, either.
As to the why of transactions, it locks the DB in case you're performing a business action on the entity. Your mistake was that you performed two apparently dependent business actions completely separately. This may in a high concurrent system indeed cause a corrupted DB state as you encountered yourself.
As to the why of transactions, this may be a good read: When is it necessary or convenient to use Spring or EJB3 or all of them together?
Is a user transaction needed for you? Generally, container managed transactions are good enough and serve the purpose.
Even if you need to have user managed transactions, it is not a good to have transaction management logic mingled with JSF logic.
For using container managed transactions, you should look at using the #TransactionAttribute on the EJBs.
If all the methods in your ejb need to have the same level of transaction support, you could have the annotation at the class level. Else you could also use the #TransactionAttribute annotation against each individual ejb method.

Spring Data JPA - Using #Transactional in a CDI environment instead of Spring environment

I realized after writing this question I could sum it up in a few sentences. How can I manage transactions in Spring-Data-JPA with CDI the same way you would by using #Transactional in Spring itself?
First thing I did was set up Spring Data JPA CDI based on the documentation here. http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/jpa.repositories.html#jpd.misc.cdi-integration
I set this up and it is working fine for read operations but not write operations
For Example, Their example in the docs would work fine.
List<Person> people = repository.findAll();
So I have the basic setup complete.
Written by hand may have typos. This is similar to the code I execute.
#Inject
UserRepository userRepository;
User user;
#Transactional
public void signUpUserAction() {
userRepository.saveAndFlush(user);
}
Then I receive this error
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
At first I realized I did not have the #Transactional so I added it and still did not work.(I believe in spring you need to use the AOP xml file to set up #Transactional so it makes sense this does not work in EE out of the box, I just do not know how to make it work.)
FYI annotating with this does not work
#TransactionAttribute(TransactionAttributeType.REQUIRED)
Something I tried while I was writing this post and I got it to work sort of... but I don't like the code and am still interested in using #Transactinoal, this code feels dirty, I'm pretty sure #Transactional handles calling other methods that are transactional in a clean way while this code would not.
This saves and I verify it's in the database.
#Inject
EntityManager em;
#Inject
UserRepository userRepository;
private User user;
public void signUpUserAction() {
em.getTransaction().begin();
userRepository.saveAndFlush(user);
em.getTransaction().commit();
}
So in short, how can I use #Transactional or something similar to manage my transactions?
Thank you for any help.
If you run Spring Data in a CDI environment, you're not running a Spring container at all. So you'll need to use EJB session beans to work with the repositories as CDI currently does not have support for transactions out of the box. The CDI extensions shipping with Spring Data is basically providing an entry point into the JavaEE world and you'll use the standard transaction mechanisms you can use in that environment.
So you either inject a repository into an #Stateless bean directly or you inject the CDI bean into one. This will allow you to use EJB transaction annotations on the EJB then.
for everyone who have this question yet.
I have this experimental project that support #Transactional in a CDI environment.
This project uses a custom code of Narayana as interceptor and provide compatibility with it and Spring Data Jpa implementation.
Key points to take in consideration:
Custom (Spring Data) Cdi Configuration -> add a Custom Transactional Post Processor custom spring data cdi configuration
Implement a custom Transactional Post Processor:
sample of a Custom Transactional Post Processor
Implement a custom Transactional Interceptor sample of a custom transactional interceptor
Add a Cdi Producer for your custom Tx Interceptor cdi producers
Create your custom repository fragments using #Transactional (JTA) custom fragments
Compose your Repository interface extending Repository interface and your fragments with #NoRepositoryBean annotation custom repositories
Take a look at this link that have some tips:
tips
Regards,