Insert a bean into a Converter - jsf-2

I have the following ApplicationScoped bean
package es.caib.gesma.gesman.data;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import es.caib.gesma.gesman.ejb.Dao;
#ManagedBean(name="priorityList")
#ApplicationScoped
public class PriorityList {
#EJB
Dao daoEjb;
private List<Priority> priorities = null;
public PriorityList() {
}
#PostConstruct
public void refresh() {
this.priorities = daoEjb.findPriorities();
}
public List<Priority> getPriorities() {
return this.priorities;
}
public Priority fromId(int id) {
for(Priority priority : this.priorities) {
if (priority.getId() == id) {
return priority;
}
}
return null;
}
}
I try to inject that bean inside a Converter
package es.caib.gesma.gesman.data.converter;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import es.caib.gesma.gesman.data.Priority;
import es.caib.gesma.gesman.data.PriorityList;
#ManagedBean
#ApplicationScoped
public class PriorityConverter implements Converter {
#ManagedProperty("#{priorityList}")
private PriorityList priorityList;
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
...
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
...
}
public void setPriorityList(PriorityList priorityList) {
System.out.println("SET PRIORITYLIST " + priorityList);
this.priorityList = priorityList;
}
}
Whenever I try to access the property, it is null. The setter is never called.
From this question and this one, it looks like it is not possible to inject the bean the usual way (please correct me if I am wrong). There is any alternative so I avoid having to get the entire list of values from the EJB (= database access) each time?

You can't (currently) inject dependencies into converters. However, if you can use Seam 3, the seam-faces module will enable this. You don't need to do anything special, just have the seam-faces JAR (and any of its dependencies) in the classpath and injection into converters will magically work. Just watch out for other unintended side-effects (I've noticed differences in transaction boundaries when the seam-persistence JAR is in the classpath).

I think you should be able to pull this bean out from the HttpSession (it works for me in PhaseListener with SessionScoped bean)
FacesContext context = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) context.getExternalContext().getSession(true);
SessionForm sessionBean = (SessionForm) session.getAttribute("priorityList");
Or if I may borrow article from BalusC about JSF communication, on the bottom is described how to make a converter from ManagedBean (so you could easily inject your ApplicationScoped bean there)

Related

Primefaces datatable with CDI Bean not paginating [duplicate]

I'm currently evaluating Java EE 6 / JSF 2.1 with RichFaces.
A bean which is declared as
#ManagedBean
#ViewScoped
Gets an ID set (to prepare e.g. a delete operation).
Via JSF a confirmation popup is displayed.
If the user confirms, the delete method is invoked and removes the row for which the ID was stored in step 1.
Since CDI beans don't have a ViewScope I tried to declare the bean as:
#Named
#ConversationScoped
Now the processing fails in step 3. because the value that was set in step 1 (checked that) is no longer available.
Do I have to use Conversation.begin() and Conversation.end() methods?
If so, where would be good place to invoke them?
If you can upgrade to JSF 2.2, immediately do it. It offers a native #ViewScoped annotation for CDI.
import javax.faces.view.ViewScoped;
import javax.inject.Named;
#Named
#ViewScoped
public class Bean implements Serializable {
// ...
}
Alternatively, install OmniFaces which brings its own CDI compatible #ViewScoped, including a working #PreDestroy (which is broken on JSF #ViewScoped).
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#Named
#ViewScoped
public class Bean implements Serializable {
// ...
}
Another alternative is to install MyFaces CODI which transparently bridges JSF 2.0/2.1 #ViewScoped to CDI. This only adds an autogenerated request parameter to the URL (like #ConversationScoped would do).
import javax.faces.bean.ViewScoped;
import javax.inject.Named;
#Named
#ViewScoped
public class Bean implements Serializable {
// ...
}
If you really need to use #ConversationScoped, then you indeed need to manually begin and end it. You need to #Inject a Conversation and invoke begin() in the #PostConstruct and end() in the latest step of the conversation, usually an action method which redirects to a new view.
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;
#Named
#ConversationScoped
public class Bean implements Serializable {
#Inject
private Conversation conversation;
// ...
#PostConstruct
public void init() {
conversation.begin();
}
public String submit() {
// ...
conversation.end();
return "some.xhtml?faces-redirect=true";
}
}
See also:
How to choose the right bean scope?
I think you can benefit from CDI extension to create your own scope so you can implement the context and use the #NormalScope.
CDI fires an event AfterBeanDiscovery after each bean call
You can use CDI extension to #Observes this event and add your context implementation
In your scope implementation you can :
Use Contextual to get your bean by its name from FacesContext ViewRoot Map and return it after each ajax call back
Use CreationalContext if the bean name from first step is not found to create it in the FacesContext ViewRoot Map
For a more in-depth explanation, I recommend this link : http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/
Inject the conversation into your bean and in the #PostConstructor method start the conversation if the conversation is transient.
And after deleting the record, end your conversation and navigate to your destination page. When beginning a conversation. Here is an example
public class BaseWebBean implements Serializable {
private final static Logger logger = LoggerFactory.getLogger(BaseWebBean.class);
#Inject
protected Conversation conversation;
#PostConstruct
protected void initBean(){
}
public void continueOrInitConversation() {
if (conversation.isTransient()) {
conversation.begin();
logger.trace("conversation with id {} has started by {}.", conversation.getId(), getClass().getName());
}
}
public void endConversationIfContinuing() {
if (!conversation.isTransient()) {
logger.trace("conversation with id {} has ended by {}.", conversation.getId(), getClass().getName());
conversation.end();
}
}
}
#ConversationScoped
#Named
public class yourBean extends BaseWebBean implements Serializable {
#PostConstruct
public void initBean() {
super.initBean();
continueOrInitConversation();
}
public String deleteRow(Row row)
{
/*delete your row here*/
endConversationIfContinuing();
return "yourDestinationPageAfter removal";
}
}
There is a project which holds an extentions to the Java EE stack features: DeltaSpike. It is a consolidation of Seam 3, Apache CODI. Above others, it includes the #ViewScoped into CDI. This is an old article and by now it has reached version 1.3.0
You can use:
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
#Named
#ViewScoped
public class PageController implements Serializable {
private String value;
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void execute() {
setValue("value");
}
#PostConstruct
public void init() {
System.out.println("postcontructor");
}
}

Grails Spring Security Get Roles for the Current Page

I was wondering if anyone knows an elegant way to get all the roles in the spring security plugin that have access to the current page.
I am using spring security and it's configured to use RequestMap domain objects.
The permissions in my app are pretty complex so I wanted to make a tag at the bottom of each page displaying the roles need to use the page.
I was doing a query for the request map but I want to make sure the way I match the url is the same as the way the plugin does.
Ideally I wouldn't have to run a query at all.
Grails version 2.2.1 Spring Security Plugin version 1.2.7.3
Thanks in advance
I got this to work by adding the following two classes to my src/java.
Class 1
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
FilterInvocationSecurityMetadataSource oldBean;
#Override
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
FilterInvocation filterInvocation = (FilterInvocation) o;
HttpServletRequest request = filterInvocation.getHttpRequest();
request.setAttribute("PAGEROLES", oldBean.getAttributes(filterInvocation));
return oldBean.getAttributes(o);
}
#Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return oldBean.getAllConfigAttributes();
}
#Override
public boolean supports(Class<?> aClass) {
return FilterInvocation.class.isAssignableFrom(aClass);
}
public Object getOldBean() { return oldBean; }
public void setOldBean(FilterInvocationSecurityMetadataSource oldBean) { this.oldBean = oldBean; }
}
Class 2
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
public class FilterSecurityMDSExtractor implements BeanPostProcessor, BeanFactoryAware {
private ConfigurableListableBeanFactory bf;
private FilterInvocationSecurityMetadataSource metadataSource = new MyFilterInvocationSecurityMetadataSource();
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof FilterInvocationSecurityMetadataSource) {
((MyFilterInvocationSecurityMetadataSource) metadataSource).setOldBean((FilterInvocationSecurityMetadataSource) bean);
return metadataSource;
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.bf = (ConfigurableListableBeanFactory)beanFactory;
}
}
I then added the following to resources.groovy
beans = {
filterSecurityMDSExtractor(FilterSecurityMDSExtractor)
}
Basically I am stuffing the user roles into the request
request.setAttribute("PAGEROLES", oldBean.getAttributes(filterInvocation));
then all I have to do is call the following
request.getAttribute("PAGEROLES");
to get the roles back out. I pieced together my solution by stealing from other great posts on Stackoverflow. Someone else might have a better solution but so far this is working for me.

Can't access one managed bean from another

I'm a beginner in JSF and I'm having problems accessing data stored in one session scoped bean from another bean. I've read similar questions here, but they didn't help.
Anyway, here's one bean:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name = "loginBean")
#SessionScoped
public class loginBean
{
private String username;
private String password;
/*etc*/
I want to access the username and password from that bean in this second bean:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
/*rest of the imports*/
#ManagedBean
#SessionScoped
public class glavnaStrBean
{
#ManagedProperty(value="#{loginBean}")
loginBean logBin;
public loginBean getLogBin() {
return logBin;
}
public void setLogBin(loginBean logBin) {
this.logBin = logBin;
}
Problem is that variable logBin is always null.
Any ideas what I'm doing wrong here?

Managed bean converter injection

Hi guys I have a problem with jsf managed bean and #PersistenceUnit. I'm using this converter
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import mn.bsoft.crasmonclient.model.Customer;
/**
*
* #author D
*/
#ManagedBean
#RequestScoped
#FacesConverter(value="convertToConverter")
public class ConvertToCustomer implements Converter{
#PersistenceUnit(unitName = "CrasmonClientPU")
private EntityManagerFactory entityManagerFactory;
private EntityManager em;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
try {
em = entityManagerFactory.createEntityManager();
Object ret = em.find(Customer.class, new Integer(value));
return ret;
} catch (ConverterException e) {
System.out.println(e.getFacesMessage());
}
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
try {
Customer pa = (Customer) value;
return String.valueOf(pa.getCustomerId());
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
}
and I got null pointer exception on EntityManagerFactory. In my faces-config file I have:
<converter>
<converter-id>convertToCustomer</converter-id>
<converter-class>crasmonclient.converter.ConvertToCustomer</converter-class>
</converter>
Did I miss something? I don't understand why getting null pointer.
Make sure in your WAR project, there is a persistence.xml file. Furthermore, it's not possible to use #ManagedBean and #FacesConverter at the same time. You need to remove #FacesConverter and <converter> to avoid confusion and use the converter exclusively as managed bean as follows:
<h:inputText converter="#{convertToCustomer} />
Besides, why don't you inject the #PersistenceContext directly:
#PersistenceContext
EntityManager em;

Select Menu JSF to CDI differences

I want to use the arquillian warp test framework for a JSF project I am developing. I understand that I need to use the CDI annotations instead of the JSF ones to get this to work. I am using #ViewScoped beans so I have included seam-faces in my project to deal with this (i am running on JBoss 7). I have modified my beans to use #Named and where I was using #PostConstruct I have put this into the constructor which all seems to be okay.
When I access a view with a selectOneMenu it never has any list items. Here is the code form the view and the bean.
View:
<h:selectOneMenu value="#{ngoBean.ngo.country}" >
<f:selectItems value="#{ngoBean.countryValues}" />
</h:selectOneMenu>
Bean:
import com.a.Facade;
import com.a.CountryEnum;
import com.a.GoverningBody;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ViewScoped;
import javax.faces.model.SelectItem;
import javax.inject.Named;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Created with IntelliJ IDEA.
*/
#Named("ngoBean")
#ViewScoped
public class NgoBean implements Serializable {
private GoverningBody ngo = new GoverningBody();
private List<GoverningBody> ngoList;
private boolean edit;
private List<SelectItem> countryValues;
#EJB(beanName = "NgoFacadeImpl")
private Facade<GoverningBody> ngoController;
public NgoBean(){
}
#PostConstruct
public void init(){
//TODO this is a bad way of loading db data i should change it
ngoList = ngoController.findAll();
countryValues = initCountryValues();
}
public void add(){
ngoList.add(ngoController.save(ngo));
//reset the variable
ngo = new GoverningBody();
}
public void edit(GoverningBody item) {
this.ngo = item;
edit = true;
}
public void save() {
ngo = ngoController.update(ngo);
edit = false;
}
public void delete(GoverningBody item) {
ngoController.delete(item);
ngoList.remove(item);
}
public List<GoverningBody> getNgoList() {
return ngoList;
}
public GoverningBody getNgo() {
return ngo;
}
public boolean isEdit() {
return edit;
}
public List<SelectItem> getCountryValues() {
return countryValues;
}
public void setCountryValues(List<SelectItem> countryValues) {
this.countryValues = countryValues;
}
public List<SelectItem> initCountryValues() {
List<SelectItem> items = new ArrayList<>(CountryEnum.values().length);
int i = 0;
for(CountryEnum g: CountryEnum.values()) {
items.add(new SelectItem(g, g.getName()));
}
System.out.println("items = " + items);
return items;
}
}
I tried annotating the method with #Factory("countryValues") but this didn't seem to help.
This problem was unrelated to the symptom. The root cause of the problem was an incorrectly located beans.xml this should have be in the WEB-INF directory of the war not the META-INF directory of the ear.
I also changed the seam-faces dependency to use apache CODI, this is not necessary but this uses #ViewAccessScoped instead of #ViewScoped the different name is less ambiguous I think.

Resources