How do bean managed transactions work? - jsf

I am new both to EJB and Bean Managed Transactions. After scrapping the Internet, I found that I could write a EJ session Bean which does transactions the "bean-managed way", like this:
#TransactionManagement(value=TransactionManagementType.BEAN)
#Stateless
public class OperationBean {
#Resource
private UserTransaction userTransaction;
public void operation() {
try{
userTransaction.begin();
Op1();
Op2();
Op3();
userTransaction.commit();
} catch(Exception e){
userTransaction.rollback();
}
}
}
However, I do not understand what happens if an exception is thrown by Op3(). How are Op1() and Op2() undone?
Another question is how do I bind this to JSF? I need to write a form in JSF that sends its data to the server and the OperationBean does 3 operations based on the received data. These operations do involve database operations(3 updates) and do not make sense individually.
Thanks!

When you call userTransaction.begin(), simply saying JTA begins transaction on database level.
Now all the data modifications you perform are done inside transaction.
If everything is OK, execution comes to userTransaction.commit() and database fixes transaction.
If something's going wrong, you call userTransaction.rollback() in catch block and database drops all the modifications you do after begin().
In two words it is difficult to explain how database transactions work, but basically database isolates all changes during transaction from other clients until commit() or rollback() is called and prevents external updates of data you are working with.
In JSF you can create #ManagedBean and inject your OperationBean into it with #EJB annotation.
You should get something like this
#ManagedBean
public class Operation {
#EJB
private OperationBean operationBean;
public void doOperation() {
operationBean.operation();
}
}
and in your view
<h:form>
<h:commandButton action="#{operation.doOperation}" value="Do Operation"/>
</h:form>
So you're doing it right. Assuming you really need bean managed transactions, not container managed.

Related

Can I use an EJB in an infinite thread

I would like to know if it's prohibited to use an EJB in an infinite thread(since it can't be given back to the container).
Something like this:
#ManagedBean(eager = true)
#ApplicationScoped
public class TestListenner {
private ResultThread result;
#PostConstruct
public void init() {
result = new ResultThread ();
Thread myThread = new Thread(result);
myThread.start();
}
public ResultThread getResult() {
return result;
}
}
And the thread:
public class ResultThread implements Runnable{
#EJB
private SomeService service;
private boolean continueWork = true;
public void run(){
while(continueWork){
service.doSomething();
//some proccessing
}
}
I'm working with EJB's since I started working with databases. I went over daofactories and the likes but I forgot about them(it was a year ago). I use them to do actions on my database when an user request a web page on my web app. But now I need to have a thread that calculate things in my database continuously to decrease the response time. If I cannot use EJB for the reason the container needs to have an handle on them, then what should I use ?
Hopefully I can use a class similar to what I'm used to use :
#Stateless
public class SomeServiceImpl implements SomeService {
#PersistenceContext(unitName = "my-pu")
private EntityManager em;
#Override
public void updateCategory(SomeClass theclass) {
em.merge(theclass);
}
}
Edit: The first answer by BalusC in this topic seems to imply that spawning threads in a ManagedBean wouldn't be dangerous in a case where no additional threads could be spawned. Since my bean is ApplicationScoped, which the web-app uses 1 and only 1 instance of it to do background work on the database (I've actually like a TOP 100 "posts" table that needs to be continually recalculated over time so I can query the table -with another bean- to have a fast answer).
What you have now won't work for at least one reason:
You can't inject resources into non-managed components. For the #EJB annotation to work, ResultThread ought to be a managed bean, and injected by the container. That means, that you must at least use CDI to inject it, rather than the new ResultThread you have now. What will work will look something like:
#Inject
private ResultThread result;
This way, the container gets in on the action.
The bottom line however, is that there are better ways of doing what you appear to be trying to do.
An EJB Timer
The new ManagedExecutor
Async EJBs
It may also interest you to know that EJBs are not allowed to spawn their own threads; in fact, it's frowned upon to do any handmade threading in the container. Why? The container is a managed environment - one where memory and concurrency have already been well thought out and designed. Your handspun thread breaks that model and any guarantees that the container may have been able to give you on your beans and other app components
Related:
Why is spawning threads in Java EE container discouraged?
You can't use your own Threads on Java EE container.
http://www.oracle.com/technetwork/java/restrictions-142267.html#threads
The Java EE spec provide TimerServices for this kind of work.
https://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html

Real time updates from database using JSF/Java EE

I have one application running in the following environment.
GlassFish Server 4.0
JSF 2.2.8-02
PrimeFaces 5.1 final
PrimeFaces Extension 2.1.0
OmniFaces 1.8.1
EclipseLink 2.5.2 having JPA 2.1
MySQL 5.6.11
JDK-7u11
There are several public pages which are lazily loaded from the database. A few CSS menus are displayed on the header of the template page like displaying category/subcategory-wise featured, top seller, new arrival etc products.
The CSS menus are populated dynamically from the database based on various categories of products in the database.
These menus are populated on every page load which is completely unnecessary. Some of these menus require complex/expensive JPA criteria queries.
Currently the JSF managed beans that populate these menus are view scoped. They all should be application scoped, be loaded only once on application start up and be updated only when something in the corresponding database tables (category/subcategory/product etc) is updated/changed.
I made some attempts to understand WebSokets (never tried before, completely new to WebSokets) like this and this. They worked fine on GlassFish 4.0 but they don't involve databases. I'm still not able to understand properly how WebSokets work. Especially when database is involved.
In this scenario, how to notify the associated clients and update the above-mentioned CSS menus with the latest values from the database, when something is updated/deleted/added to the corresponding database tables?
A simple example/s would be great.
Preface
In this answer, I'll assume the following:
You're not interested in using <p:push> (I'll leave the exact reason in the middle, you're at least interested in using the new Java EE 7 / JSR356 WebSocket API).
You want an application scoped push (i.e. all users gets the same push message at once; thus you're not interested in a session nor view scoped push).
You want to invoke push directly from (MySQL) DB side (thus you're not interested in invoking push from JPA side using an entity listener). Edit: I'll cover both steps anyway. Step 3a describes DB trigger and step 3b describes JPA trigger. Use them either-or, not both!
1. Create a WebSocket endpoint
First create a #ServerEndpoint class which basically collects all websocket sessions into an application wide set. Note that this can in this particular example only be static as every websocket session basically gets its own #ServerEndpoint instance (they are unlike servlets thus stateless).
#ServerEndpoint("/push")
public class Push {
private static final Set<Session> SESSIONS = ConcurrentHashMap.newKeySet();
#OnOpen
public void onOpen(Session session) {
SESSIONS.add(session);
}
#OnClose
public void onClose(Session session) {
SESSIONS.remove(session);
}
public static void sendAll(String text) {
synchronized (SESSIONS) {
for (Session session : SESSIONS) {
if (session.isOpen()) {
session.getAsyncRemote().sendText(text);
}
}
}
}
}
The example above has an additional method sendAll() which sends the given message to all open websocket sessions (i.e. application scoped push). Note that this message can also quite good be a JSON string.
If you intend to explicitly store them in application scope (or (HTTP) session scope), then you can use the ServletAwareConfig example in this answer for that. You know, ServletContext attributes map to ExternalContext#getApplicationMap() in JSF (and HttpSession attributes map to ExternalContext#getSessionMap()).
2. Open the WebSocket in client side and listen on it
Use this piece of JavaScript to open a websocket and listen on it:
if (window.WebSocket) {
var ws = new WebSocket("ws://example.com/contextname/push");
ws.onmessage = function(event) {
var text = event.data;
console.log(text);
};
}
else {
// Bad luck. Browser doesn't support it. Consider falling back to long polling.
// See http://caniuse.com/websockets for an overview of supported browsers.
// There exist jQuery WebSocket plugins with transparent fallback.
}
As of now it merely logs the pushed text. We'd like to use this text as an instruction to update the menu component. For that, we'd need an additional <p:remoteCommand>.
<h:form>
<p:remoteCommand name="updateMenu" update=":menu" />
</h:form>
Imagine that you're sending a JS function name as text by Push.sendAll("updateMenu"), then you could interpret and trigger it as follows:
ws.onmessage = function(event) {
var functionName = event.data;
if (window[functionName]) {
window[functionName]();
}
};
Again, when using a JSON string as message (which you could parse by $.parseJSON(event.data)), more dynamics is possible.
3a. Either trigger WebSocket push from DB side
Now we need to trigger the command Push.sendAll("updateMenu") from the DB side. One of simplest ways it letting the DB to fire a HTTP request on a web service. A plain vanilla servlet is more than sufficient to act like a web service:
#WebServlet("/push-update-menu")
public class PushUpdateMenu extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Push.sendAll("updateMenu");
}
}
You've of course the opportunity to parameterize the push message based on request parameters or path info, if necessary. Don't forget to perform security checks if the caller is allowed to invoke this servlet, otherwise anyone else in the world other then the DB itself would be able to invoke it. You could check the caller's IP address, for example, which is handy if both DB server and web server run at the same machine.
In order to let the DB fire a HTTP request on that servlet, you need to create a reusable stored procedure which basically invokes the operating system specific command to execute a HTTP GET request, e.g. curl. MySQL doesn't natively support executing an OS specific command, so you'd need to install a user defined function (UDF) for that first. At mysqludf.org you can find a bunch of which SYS is of our interest. It contains the sys_exec() function which we need. Once installed it, create the following stored procedure in MySQL:
DELIMITER //
CREATE PROCEDURE menu_push()
BEGIN
SET #result = sys_exec('curl http://example.com/contextname/push-update-menu');
END //
DELIMITER ;
Now you can create insert/update/delete triggers which will invoke it (assuming table name is named menu):
CREATE TRIGGER after_menu_insert
AFTER INSERT ON menu
FOR EACH ROW CALL menu_push();
CREATE TRIGGER after_menu_update
AFTER UPDATE ON menu
FOR EACH ROW CALL menu_push();
CREATE TRIGGER after_menu_delete
AFTER DELETE ON menu
FOR EACH ROW CALL menu_push();
3b. Or trigger WebSocket push from JPA side
If your requirement/situation allows to listen on JPA entity change events only, and thus external changes to the DB does not need to be covered, then you can instead of DB triggers as described in step 3a also just use a JPA entity change listener. You can register it via #EntityListeners annotation on the #Entity class:
#Entity
#EntityListeners(MenuChangeListener.class)
public class Menu {
// ...
}
If you happen to use a single web profile project wherein everything (EJB/JPA/JSF) is thrown together in the same project, then you can just directly invoke Push.sendAll("updateMenu") in there.
public class MenuChangeListener {
#PostPersist
#PostUpdate
#PostRemove
public void onChange(Menu menu) {
Push.sendAll("updateMenu");
}
}
However, in "enterprise" projects, service layer code (EJB/JPA/etc) is usually separated in EJB project while web layer code (JSF/Servlets/WebSocket/etc) is kept in Web project. The EJB project should have no single dependency on web project. In that case, you'd better fire a CDI Event instead which the Web project could #Observes.
public class MenuChangeListener {
// Outcommented because it's broken in current GF/WF versions.
// #Inject
// private Event<MenuChangeEvent> event;
#Inject
private BeanManager beanManager;
#PostPersist
#PostUpdate
#PostRemove
public void onChange(Menu menu) {
// Outcommented because it's broken in current GF/WF versions.
// event.fire(new MenuChangeEvent(menu));
beanManager.fireEvent(new MenuChangeEvent(menu));
}
}
(note the outcomments; injecting a CDI Event is broken in both GlassFish and WildFly in current versions (4.1 / 8.2); the workaround fires the event via BeanManager instead; if this still doesn't work, the CDI 1.1 alternative is CDI.current().getBeanManager().fireEvent(new MenuChangeEvent(menu)))
public class MenuChangeEvent {
private Menu menu;
public MenuChangeEvent(Menu menu) {
this.menu = menu;
}
public Menu getMenu() {
return menu;
}
}
And then in the web project:
#ApplicationScoped
public class Application {
public void onMenuChange(#Observes MenuChangeEvent event) {
Push.sendAll("updateMenu");
}
}
Update: at 1 april 2016 (half a year after above answer), OmniFaces introduced with version 2.3 the <o:socket> which should make this all less circuitous. The upcoming JSF 2.3 <f:websocket> is largely based on <o:socket>. See also How can server push asynchronous changes to a HTML page created by JSF?
Since you are using Primefaces and Java EE 7 it should be easy to implement:
use Primefaces Push ( example here http://www.primefaces.org/showcase/push/notify.xhtml )
Create a view which listen to a Websocket endpoint
Create a database listener which produces a CDI event on database change
The payload of the event could either be the delta of the latest data or just and update information
Propagate the CDI event via Websocket to all clients
Clients updating the data
Hope this helps
If you need some more details just ask
Regards
PrimeFaces has poll features to update the component automatically. In the following example, <h:outputText> will be auto updated every 3 seconds by <p:poll>.
How to notify the associated clients and update the above-mentioned CSS menus with the latest values from the database?
Create a listener method like process() to select your menu data. <p:poll> will be auto-update your menu component.
<h:form>
<h:outputText id="count"
value="#{AutoCountBean.count}"/> <!-- Replace your menu component-->
<p:poll interval="3" listener="#{AutoCountBean.process}" update="count" />
</h:form>
#ManagedBean
#ViewScoped
public class AutoCountBean implements Serializable {
private int count;
public int getCount() {
return count;
}
public void process() {
number++; //Replace your select data from db.
}
}

Automatically add FacesMessage when a certain business exception is thrown in JSF 2

I would like to know if the following is possible with JSF2.
When my business classes or DAO classes are throwing a certain exception (e.g. a custom exception called BusinessException) a FacesMessage gets added to the current page with a standard message string for this exception class. The business classes and the managed beans are in two different projects. Only the managed beans have access to the business classes.
You can use a snippet like this in your managed bean:
try
{
... do your staff here ...
} catch (YourBusinessException ex)
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Your custom message"));
}
This is a general approach and it will work if your business method throws a YourBusinessException instead of catching it.
You can implement a parent bean from which every single managed bean could extend from. There, implement an access point for each of your service calls.
That solution depends of course in how many service operations you have and if they're reused by diferent managed beans. Apart from that, keep in mind that you could need to handle the exceptions on the parent in other way that could not be just adding a message. That question depends a lot in your current implementation and application type.
Just think about it:
public abstract class ParentBean{
Service service;
public void performOperationAtService(){
try{
service.operation();
}catch(YourBusinessException ex){
FacesContext.getCurrentInstance()
.addMessage(null, new FacesMessage("An error occured. Please contact your administrator"));
}
}
}
#ManagedBean
#ViewScoped
public class ConcreteBean extends ParentBean{
public void someAction(){
//Do some stuff
super.performOperationAtService();
}
}

Non-lazy instantiation of CDI SessionScoped beans

CDI newbie question. Simple test scenario: JSF + CDI SessionScoped beans.
I need an elegant way to instantiate a known set of session scoped CDI beans without mentioning them on a JSF page or calling their methods from other beans. As a test case - a simple logging bean, which simply logs start and end time of an http session.
Sure, I could create an empty JSF component, place it inside of a site-wide template and make it trigger dummy methods of the required session beans, but it's kinda ugly from my pov.
Another option I see, is to choose a single session bean (which gets initialized 100% either by EL in JSF or by references from other beans), and use its #PostConstruct method to trigger other session beans - the solution a little less uglier than the previous one.
Looks like I'm missing something here, I'd appreciate any other ideas.
While accepting the Karl's answer and being thankful to Luiggi for his hint, I also post my solution which is based on HttpSessionListener but does not require messing with BeanProvider or BeanManager whatsoever.
#WebListener
public class SessionListener implements HttpSessionListener {
#Inject
Event<SessionStartEvent> startEvent;
#Inject
Event<SessionEndEvent> endEvent;
#Override
public void sessionCreated(HttpSessionEvent se) {
SessionStartEvent e = new SessionStartEvent();
startEvent.fire(e);
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
SessionEndEvent e = new SessionEndEvent();
endEvent.fire(e);
}
}
To my surprise, the code above instantiates all the beans which methods are observing these events:
#Named
#SessionScoped
public class SessionLogger implements Serializable {
#PostConstruct
public void init() {
// is called first
}
public void start(#Observes SessionStartEvent event) {
// is called second
}
}
Yes, HttpSessionListener would do it. Simply inject the beans and invoke them.
If you container does not support injection in a HttpSessionListener you could have a look at deltaspike core and BeanProvider
http://deltaspike.apache.org/core.html

ApplicationScoped Bean with postconstruct method

I have an application scoped bean to hold the information in my database. After its instantiation it should fetch the data, so I annotated the method with #PostConstruct. As soon as I request the jsf page where this bean is referenced the server log explodes! I think it somehow recurses and the only stacktrace I get is that a System Exception occurred during the repBean.acceptVisitor(Visitor); method. The server log then gets several GB big and I have to manually delete it in order to have free disk space. If I delete the #PostConstruct annotation there are no exceptions. After calling the update() method from another bean the repositoryContent variable is updated properly and contains the information. The only problem then is that my jsf page doesn't display the content for some strange reason.
#ManagedBean(eager=true)
#ApplicationScoped
public class IndexBean implements Serializable {
private ArrayList<ViewFolder> repositoryContent;
#EJB
RepositoryService repBean;
#PostConstruct
public void update() {
RepositoryVisitor Visitor = new RepositoryVisitor();
repBean.acceptVisitor(Visitor);
repositoryContent = Visitor.getList();
}
}
This is not normal behaviour.
One of the following lines
RepositoryVisitor Visitor = new RepositoryVisitor();
repBean.acceptVisitor(Visitor);
repositoryContent = Visitor.getList();
is indirectly evaluating the EL expression #{indexBean} which in turn causes the bean being constructed once again, because it is not been put in service yet. It would only be put in service (and thus available as a concrete #{indexBean}) when the #PostConstruct finishes. This all causes an infinite loop.
You might need to do some refactoring, or to pass the application scoped bean instance itself to the method call so that it can be used directly instead of being referenced by an EL expression.

Resources