how to get logged in user id in jsf 2.0
I am unable to get the user id. I tried the following methods.
xhtml page
<h:outputText value="#{request.remoteUser}"></h:outputText>
<h:outputText value="#{userDetails.userId}"></h:outputText>
Viewscoped bean class.
public String getUserId() {
FacesContext ctx = FacesContext.getCurrentInstance();
System.out.println ("User"+ctx.getExternalContext().getRemoteUser());
userId =ctx.getExternalContext().getRemoteUser();
return userId;
}
Should i do any initialization in web.xml? or should my bean class extend or implement any other class?
Related
I have started learning JSF, but sadly most tutorials out there present only a log in or a register section.
Can you point me to some more in depth examples? One thing I'm interested in is a page presenting a list of products. I'm on page home and I press on page products so that I can see the latest products added. And every time I visit the page, the product list will be created from the latest entries in the database. How can I handle this?
One way to solve this would be to create a session scoped managed bean in which I would place different entities updated through other managed beans. I found this kind of approach in some tutorials, but it seems quite difficult and clumsy.
Which would be the best approach to solve a thing like this? What is the correct usage of session scope in two-page master-detail user interface?
What is the correct usage of session scope
Use it for session scoped data only, nothing else. For example, the logged-in user, its settings, the chosen language, etcetera.
See also:
How to choose the right bean scope?
And every time I visit the page, the product list will be created from the latest entries in the database. How can I handle this?
Typically you use the request or view scope for it. Loading of the list should happen in a #PostConstruct method. If the page doesn't contain any <h:form>, then the request scope is fine. A view scoped bean would behave like a request scoped when there's no <h:form> anyway.
All "view product" and "edit product" links/buttons which just retrieve information (i.e. idempotent) whould be just plain GET <h:link> / <h:button> wherein you pass the entity identifier as a request parameter by <f:param>.
All "delete product" and "save product" links/buttons which will manipulate information (i.e. non-idempotent) should perform POST by <h:commandLink>/<h:commandButton> (you don't want them to be bookmarkable/searchbot-indexable!). This in turn requires a <h:form>. In order to preserve the data for validations and ajax requests (so that you don't need to reload/preinitialize the entity on every request), the bean should preferably be view scoped.
Note that you should basically have a separate bean for each view and also note that those beans doesn't necessarily need to reference each other.
So, given this "product" entity:
#Entity
public class Product {
#Id
private Long id;
private String name;
private String description;
// ...
}
And this "product service" EJB:
#Stateless
public class ProductService {
#PersistenceContext
private EntityManager em;
public Product find(Long id) {
return em.find(Product.class, id);
}
public List<Product> list() {
return em.createQuery("SELECT p FROM Product p", Product.class).getResultList();
}
public void create(Product product) {
em.persist(product);
}
public void update(Product product) {
em.merge(product);
}
public void delete(Product product) {
em.remove(em.contains(product) ? product : em.merge(product));
}
// ...
}
You can have this "view products" on /products.xhtml:
<h:dataTable value="#{viewProducts.products}" var="product">
<h:column>#{product.id}</h:column>
<h:column>#{product.name}</h:column>
<h:column>#{product.description}</h:column>
<h:column>
<h:link value="Edit" outcome="/products/edit">
<f:param name="id" value="#{product.id}" />
</h:link>
</h:column>
</h:dataTable>
#Named
#RequestScoped
public class ViewProducts {
private List<Product> products; // +getter
#EJB
private ProductService productService;
#PostConstruct
public void init() {
products = productService.list();
}
// ...
}
And you can have this "edit product" on /products/edit.xhtml:
<f:metadata>
<f:viewParam name="id" value="#{editProduct.product}"
converter="#{productConverter}" converterMessage="Unknown product, please use a link from within the system."
required="true" requiredMessage="Bad request, please use a link from within the system."
/>
</f:metadata>
<h:messages />
<h:form rendered="#{not empty editProduct.product}>
<h:inputText value="#{editProduct.product.name}" />
<h:inputTextarea value="#{editProduct.product.description}" />
...
<h:commandButton value="save" action="#{editProduct.save}" />
</h:form>
#Named
#ViewScoped
public class EditProduct {
private Product product; // +getter +setter
#EJB
private ProductService productService;
public String save() {
productService.update(product);
return "/products?faces-redirect=true";
}
// ...
}
And this converter for <f:viewParam> of "edit product":
#Named
#RequestScoped
public class ProductConverter implements Converter {
#EJB
private ProductService productService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
Long id = Long.valueOf(value);
return productService.find(id);
} catch (NumberFormatException e) {
throw new ConverterException("The value is not a valid Product ID: " + value, e);
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
}
if (value instanceof Product) {
Long id = ((Product) value).getId();
return (id != null) ? String.valueOf(id) : null;
} else {
throw new ConverterException("The value is not a valid Product instance: " + value);
}
}
}
You can even use a generic converter, this is explained in Implement converters for entities with Java Generics.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
JSF Controller, Service and DAO
JSF Service Layer
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
Communication in JSF 2.0 - Contains several examples/hints
As a small improvement to what BalusC recommended, sometimes you can remove the required / requiredMessage part from the <f:viewParam> of your "details" screen and instead use the conditional rendering of the editing form (as BalusC did) with a reverse condition for recommending a specific link for the "list/master" screen or, even use a viewAction that would test the param and force a redirect to that list.
I've a simple #Stateless EJB that looks like this (stripped of all logging and error handling):
#Stateless
public class CurrentUserBean {
#PersistenceContext
private EntityManager em;
#Produces #Named #LoggedIn
#SessionScoped
public User produceCurrentUser() {
Principal principal = Faces.getExternalContext().getUserPrincipal();
String username = (principal == null ? null : principal.getName());
return em.createNamedQuery("findByLogin", User.class)
.setParameter("login", username)
.getSingleResult();
}
}
Works fine when the user logs in with JSF. But the same user can also authenticate via webservice, where I can (need to?) get the user principal from SecurityContext in a bean controlled by JAX-RS (resteasy in my case):
public User doAuth(#Context SecurityContext ctx) {
return em.createNamedQuery("findByLogin", User.class)
.setParameter("login", ctx.getUserPrincial().getName())
.getSingleResult();
}
How can I unify these approaches so that the production of the current user object is the responsibility of only one class?
CDI allows you to inject the Principal directly. Just do this:
#Inject Principal userPrincipal;
And that will have the user name.
I would like to get outcome value from navigation rules into a request scoped JSF 2 bean. How can I do that?
For example, when I press on a <h:link outcome="contacts"> and end up in the contacts page, then I would like to get the outcome "contacts" in the backing bean associated with the navigation menu.
faces-config.xml
<navigation-rule>
...
<navigation-case>
<from-outcome>contacts</from-outcome>
<to-view-id>/pages/contacts.xhtml</to-view-id>
</navigation-case>
...
</navigation-rule>
In JSF, AFAIK, only the ConfigurableNavigationHandler will have that information. So create a custom ConfigurableNavigationHandler that will stash the outcome in a request parameter for your consumption in the destination page.
Your custom navigation handler
public class NavigationHandlerTest extends ConfigurableNavigationHandler {
private NavigationHandlerTest concreteHandler;
public NavigationHandlerTest(NavigationHandler concreteHandler) {
this.concreteHandler = concreteHandler;
}
#Override
public void handleNavigation(FacesContext context, String fromAction, String outcome){
//Grab a hold of the request parameter part and save the outcome in it for
//later retrieval
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext ctx = context.getExternalContext();
ctx.getRequestMap().put("currentOutcome", outcome);
//resume normal navigation
concreteHandler.handleNavigation(context, fromAction, outcome);
}
}
Configure your handler in faces-config.xml
<application>
<navigation-handler>com.foo.bar.NavigationHandlerTest</navigation-handler>
</application>
Retrieve in your destination bean
#ManagedProperty(value="#{param.currentOutcome}")
String outcome;
//getter and setter
I have already one session scoped CDI bean, which keeps currently logged in user data.
Now, from another, request scoped I would like to access to this bean to get some data. I have some operation to do, which is dependent on user login. That's the only information I need.
How to access it?
AccountBean.java:
#Named("accountBean")
#SessionScoped
public class AccountBean implements Serializable {
private static final long serialVersionUID = 16472027766900196L;
#Inject
AccountService accountService;
private String login;
private String password;
// getters and setters ommited
}
Part of login.xhtml:
<h:form>
<h:panelGrid columns="2">
#{msgs.loginPrompt}
<h:inputText id="login" value="#{accountBean.login}" />
#{msgs.passwordPrompt}
<h:inputSecret id="password" value="#{accountBean.password}" />
<h:commandButton value="#{msgs.loginButtonText}"
action="#{accountBean.login}" />
</h:panelGrid>
</h:form>
SearchBean.java:
#Named("searchBean")
#RequestScoped
public class SearchBean {
#Inject AccountBean accountBean;
// some other stuff
}
Just #Inject it.
#Inject
private Bean bean;
Note that this isn't available in the constructor of the receiving bean (it's not possible to inject something in an unconstructed instance, you see). The earliest access point is a #PostConstruct method.
#PostConstruct
public void init() {
bean.doSomething();
}
I am using jsf 2.0 and I have two bean Navigation (Application Scope ) and Module (Request Scope). I want to use methods of Navigation bean in Module Bean. I am doing in this way
In Module Bean
#ManagedProperty(value = "#{navigationBean}")
private NavigationBean navigationBean;
But when I am trying to get navigationBean.SomeMethod it is not working as navigation bean is null . How to do this?
The both beans needs to be a fullworthy #ManagedBean. The acceptor should have a public setter method for the injected bean. The injected bean is only available in #PostConstruct and beyond (i.e. in all normal event methods, but thus not in the constructor of the acceptor).
So, this ought to work:
#ManagedBean
#ApplicationScoped
public class Navigation {
// ...
}
#ManagedBean
#RequestScoped
public class Module {
#ManagedProperty(value="#{navigation}")
private Navigation navigation;
#PostConstruct
public void init() {
navigation.doSomething();
}
public void setNavigation(Navigation navigation) {
this.navigation = navigation;
}
}
I think #ManagedProperty requires a public set method to work.
I got The solution
I have a method in application signature boolean getReadAccess(String role, String module ). If i want to use in another bean then i have to follow these steps
`javax.el.MethodExpression readAccess;
javax.el.ELContext elContext = null;
javax.faces.context.FacesContext context = FacesContext.getCurrentInstance();
elContext = ((FacesContext) context).getELContext();
javax.faces.application.Application application = FacesContext.getCurrentInstance().getApplication();
javax.el.ExpressionFactory expressionFactory = application.getExpressionFactory();
readAccess = expressionFactory.createMethodExpression(elContext,
"#{navigationBean.getReadAccess}", Void.class, new Class[] {
String.class, String.class });
//--------Call----------------------------
return (Boolean) readAccess.invoke(elContext, new Object[] {
"roleName", "moduleName" });
`