Currently I am using a Transaction View pattern to make lazy-loading of collections possible in views.
I have the following in web.xml
<filter>
<filter-name>view</filter-name>
<filter-class>com.jasoni.ViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>view</filter-name>
<url-pattern>*.xhtml</url-pattern>
</filter-mapping>
And the Filter class has the following...
public class ViewFilter implements Filter {
@Resource UserTransaction tx;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
tx.begin();
chain.doFilter(request, response);
}
//catch here
finally {
//another try-catch
tx.commit();
}
}
}
Then assuming I have the following (rather contrived) backing bean
@ManagedBean
@RequestScoped
public class DepartmentEmployees {
@EJB
private DepartmentServiceBean deptService;
@ManagedProperty(value="#{param.deptId}")
private Integer deptId;
private Department dept;
@PostConstruct
public String init() {
dept = deptService.findById(deptId);
}
}
I can do something like this in my view (.xhtml file)
<ul>
<c:forEach var="emp" items="#{departmentEmployees.dept.employees}">
<li>#{emp.firstName} #{emp.lastName}</li>
</c:forEach>
</ul>
Just wondering if anybody knows of a different way to accomplish the same thing without using filters (or servlets).
This approach ("open session in view") has a couple of major disadvantages. Besides being kind of hacky (it's certainly not the design idea of a servlet filter to control a business session) you don't have many options to appropriately process any "real" exception that occurs while rendering the JSF page.
You don't write much about your infrastructure / technology stack, but I assume that you are on a Java EE 6 server.
I usually use the EntityManger
in Extended Mode and flush it with transactions which I control explicitly by annotating only certain methods of my business facade. Have a look at this example (taken from Adam Bien - Real World Java EE Patterns, Rethinking Best Practices):
@Stateful
@TransactionAttribute(TransactionAttributeType.NEVER)
public class BookFacadeBean implements BookFacade {
@PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
private Book currentBook;
public Book find(long id){
this.currentBook = this.em.find(Book.class, id);
return this.currentBook;
}
public void create(Book book){
this.em.persist(book);
this.currentBook = book;
}
public Book getCurrentBook() {
return currentBook;
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void save(){
//nothing to do here
}
}
A next level in this approach would be to bind the EntityManager to a CDI conversation scope. Have a look at (a) Weld (b) Seam 3 Persistence for further discussions on that topic.
This is rather a rough sketch of an alternative than a detailed how-to. I hope this level of information is what you were asking about - feel free to ask further questions. :-)