I want to access an #SessionScoped managed bean from WebSocket Endpoint class.
I tried
#ManagedProperty(value = "#{bean}")
private Bean bean;
in WebSocket class, but it throws:
org.apache.tomcat.websocket.pojo.PojoEndpointBase onError
SEVERE: No error handling configured for [WebSocket] and the following error occurred
java.lang.NullPointerException
#ServerEndpoint("/ws")
public class WebSocket
private Session session;
#ManagedProperty(value = "#{bean}")
private Bean bean;
#OnOpen
public void connect(Session session) {
System.out.println("BAGLANTİ KURULDU");
this.session = session;
}
#OnClose
public void close() {
System.out.println("BAGLANTİ KAPANDI");
this.session = null;
}
#OnMessage
public void message(String message) {
System.out.println("Client'ten Gelen Mesaj= " + message);
//this.session.getAsyncRemote().sendText(message + bean.getTc());
System.out.println(bean.getTc());
}
#ManagedBean(name = "bean", eager = true)
#SessionScoped
public class Bean
private String tc,sifre,name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTc() {
return tc;
}
public void setTc(String tc) {
this.tc = tc;
}
public String getSifre() {
return sifre;
}
public void setSifre(String sifre) {
this.sifre = sifre;
}
Related
I´m trying to send a push notification from my EJB class:
#Stateless
public class SendEmailNotificationReminderServiceBean implements SendEmailNotificationReminderService {
#Inject
private BeanManager beanManager;
private void sendNotification {
// Push Nachricht
PushEvent event = new PushEvent("sendNotification", 1);
beanManager.fireEvent(event);
}
}
Here my socket:
#Named
#ApplicationScoped
public class NotificationSocket implements Serializable {
private static final long serialVersionUID = 7615791377170410627L;
#Inject
#Push(channel = "notificationChannel")
private PushContext push;
/**
* Push Notification
*
* #param recipientUser
*/
public void pushUser(#Observes PushEvent event) {
if (event == null)
return;
Set<Future<Void>> sent = push.send(event.getMessage(), event.getUserId());
}
}
My object:
public class PushEvent {
private String message;
private Long userId;
public PushEvent(String message) {
super();
this.message = message;
}
//////////////
public PushEvent(String message, Long userId) {
super();
this.message = message;
this.userId = userId;
}
public String getMessage() {
return message;
}
public Long getUserId() {
return userId;
}
}
My JSF page:
<o:socket channel="notificationChannel"
user="#{loginBean.currentEmployee.id}" scope="session"
onmessage="notificationLoadScript">
</o:socket>
<h:form id="notificationPushTopbarForm">
<p:remoteCommand name="notificationLoadScript"
actionListener="#{topbarMenuController.loadNotification()}"
oncomplete="changeTitleForNotification(#{topbarMenuController.numberOfNewNotificationAvailable})"
update=":notificationLink, :notificationSidebarForm" global="false" />
</h:form>
What I´m trying to do is:
Create a PushNotification from my backend (EJB layer) to the current logged in User and this channel.
As example you can imagine the Notification icon (right corner) from Stackoverflow.
I´m getting no error message, but the JSF component is also not updating (p:remoteCommand call). Any idea how I can fix this?
My app handles logins with a #ViewScoped LoginBean, which is injected with a #SessionScoped SessionBean that stores user information and the current HttpSession. This app allows a user N separate sessions. After reaching that limit the user can only create another by killing off the oldest. This is done in the same LoginBean by asking the unmanaged UserSessionManager for the oldest SessionBean, and then invalidating its HttpSession.
Thus, logging in with session "A", we invalidate session "B". This all goes according to plan. But then, sometime during the remaining JSF phases, we also lose the SessionBean for session "A". Tracing down into the CDI code it appears that the session context for session "A" is being destroyed so when the redisplay finishes we have all new session beans.
We are using MyFaces 2.3.6, OpenWebBeans 2.0.16, OpenJDK 11
Is this a bug in OWB, or expected bahavior?
I'm also wondering if I have a fundamental misconception. If I save a SessionBean in my UserSessionManager and the retrieve it during a different session, should it retain its original state or does it get re-evaluated in the new SessionScoped context? I've been finding debugging difficult because my objects seem to actually be proxies, and the UI and debugger show different values at times.
Update 4/27/20:
The #SessionScoped SessionBean is being destroyed by org.apache.webbeans.web.context.WebContextsService#destroyRequestContext() where it destroys the "PropagatedSessionContext". This PropagatedSessionContext is being set by WebContextsService#destroySessionContext(), which is designating the local session to be destroyed despite being given a different specific session. This is where I'm wondering if it's a bug in OWB.
Here's a simplified example of the code:
(In this test code I've made the SessionManager an #ApplicationScoped bean. In the original code it isn't, but the behavior is the same.)
#Named("loginbean")
#ViewScoped
public class LoginBean implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
#Inject private ExternalContext externalContext;
#Inject private SessionBean session;
#Inject private SessionManager sessionMgr;
public String killOldestDoLogin() {
List<SessionInfo> sessions = sessionMgr.getSessions();
SessionInfo oldest = sessions.get(0);
sessionMgr.killSession(oldest.getSessionId());
return doLogin();
}
public String doLogin() {
username = username.trim();
if (username != null && username.length() > 0) {
// After a successful login, avoid session fixation attacks by
// rotating the session ID. This isn't strictly necessary as Faces has
// its own session ID that a third party wouldn't have access to
if (externalContext != null) {
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
if (request != null && request.isRequestedSessionIdValid()) {
newSessionId = request.changeSessionId();
}
}
HttpSession http = (HttpSession)externalContext.getSession(false);
session.setUsername(username);
session.setHttpSession(http);
sessionMgr.addSession(http, session);
}
return "startPage.jsf");
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
.
#Named("sessionbean")
#SessionScoped
public class SessionBean implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private HttpSession httpSession;
public void reset() {
username = null;
httpSession = null;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public HttpSession getHttpSession() {
return httpSession;
}
public void setHttpSession(HttpSession session) {
this.httpSession = session;
}
public String getSessionId() {
return httpSession == null ? "null" : this.httpSession.getId();
}
}
.
#Named("sessionmanager")
#ApplicationScoped
public class SessionManager {
private HashMap<String,HttpSession> sessionMap = new HashMap<>();
private HashMap<String,SessionBean> beanMap = new HashMap<>();
public void addSession(HttpSession http, SessionBean bean) {
beanMap.put(http.getId(), bean);
sessionMap.put(http.getId(), http);
}
public boolean killSession(String sessionId) {
HttpSession session = sessionMap.get(sessionId);
sessionMap.remove(sessionId);
beanMap.remove(sessionId);
if (session != null) {
session.invalidate();
}
return session != null;
}
public List<SessionInfo> getSessions() {
List<SessionInfo> result = new ArrayList<>();
for (String sessionId : sessionMap.keySet()) {
SessionBean bean = beanMap.get(sessionId);
HttpSession http = sessionMap.get(sessionId);
SessionInfo info = new SessionInfo();
info.setUsername(bean.getUsername());
info.setSessionId(sessionId);
info.setHttpSession(http));
result.add(info);
}
return result;
}
}
.
public class SessionInfo {
private String username;
private String sessionId;
private HttpSession httpSession;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public HttpSession getHttpSession() {
return httpSession;
}
public void setHttpSession(HttpSession httpSession) {
this.httpSession = httpSession;
}
}
Here's my XHTML code:
<h:selectOneMenu id="combo" value="#{TeamsHinzufuegenBean.selectedLeagueId}">
<f:selectItems value="#{TeamsHinzufuegenBean.leagues}"
var="league" itemValue="#{league.id}"
itemLabel="#{league.name}"/>
</h:selectOneMenu>
And my bean:
#ManagedBean(name = "TeamsHinzufuegenBean")
#ViewScoped
public class TeamsHinzufügenBean implements Serializable{
private static final long serialVersionUID = 1L;
private List<League> leagues;
private ArrayList<Team> teams = new ArrayList<Team>();
private String teamname;
private int selectedLeagueId=1;
#PostConstruct
public void init() {
leagues = Database.getInstance().getAllLeagues();
for(League l : leagues)
System.out.println(l);
}
public List<League> getLeagues() {
return leagues;
}
public void setLeagues(List<League> leagues) {
this.leagues = leagues;
}
public int getSelectedLeagueId() {
return selectedLeagueId;
}
public void setSelectedLeagueId(int selectedLeagueId) {
this.selectedLeagueId = selectedLeagueId;
}
public ArrayList<Team> getTeams() {
return teams;
}
public void setTeams(ArrayList<Team> teams) {
this.teams = teams;
}
public String getTeamname() {
return teamname;
}
public void setTeamname(String teamname) {
this.teamname = teamname;
}
}
The league-class has an attribute id but if I output the value of selectedLeagueId, it is always 0.
Check if getAllLeagues() contains objects that have an id and that it is correctly set
Following is my managed bean code:
public class SelectEntries implements Serializable {
private static final long serialVersionUID = 1217595612573680L;
private List<SelectEntry> selectEntries = new ArrayList<SelectEntry>();
private SelectEntry selectEntry;
#PostConstruct
private void init() {
selectEntries.add(new SelectEntry("1001", new CheckEntry("Line 1"),
new CheckEntry("Line 2"), new CheckEntry("Line 3")));
selectEntries.add(new SelectEntry("1002", new CheckEntry("Line 4"),
new CheckEntry("Line 5"), new CheckEntry("Line 6")));
selectEntries.add(new SelectEntry("1003", new CheckEntry("Line 7"),
new CheckEntry("Line 8"), new CheckEntry("Line 9")));
}
public List<SelectEntry> getSelectEntries() {
return selectEntries;
}
public void setSelectEntries(List<SelectEntry> selectEntries) {
this.selectEntries = selectEntries;
}
public SelectEntry getSelectEntry() {
return selectEntry;
}
public void setSelectEntry(SelectEntry selectEntry) {
this.selectEntry = selectEntry;
}
public String getTemplatesString() {
String templatesString = "";
for (CheckEntry oneCheckEntry : getSelectEntry().getCheckEntries()) {
if (oneCheckEntry.getCheck()) {
templatesString += oneCheckEntry.getName();
}
}
return templatesString;
}
}
Here is the SelectEntry class:
public class SelectEntry implements Serializable {
private static final long serialVersionUID = 7298341984562171094L;
private String name;
private List<CheckEntry> checkEntries = new ArrayList<CheckEntry>();
public SelectEntry(String name, CheckEntry... checkEntries) {
this.name = name;
if (checkEntries != null) {
this.checkEntries.addAll(Arrays.asList(checkEntries));
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<CheckEntry> getCheckEntries() {
return checkEntries;
}
public void setCheckEntries(List<CheckEntry> checkEntries) {
this.checkEntries = checkEntries;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SelectEntry other = (SelectEntry) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
And the CheckEntry class:
public class CheckEntry implements Serializable {
private static final long serialVersionUID = 1730874183104100662L;
private String name;
private Boolean check;
public CheckEntry(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getCheck() {
return check;
}
public void setCheck(Boolean check) {
this.check = check;
}
}
I have a simple function in the managed bean to get create a String on the bases of which check entries have been selected.This only functions with SessionScope and if I use RequestScope, the boolean values of CheckEntries are null and I get runtime error. Why is it so?
As per JEE7 tutorial:
Request (#RequestScoped): Request scope persists during a single HTTP
request in a web application. In an application like hello1, where
the application consists of a single request and response, the bean
uses request scope.
So once your page is loaded, the resquest scoped backing bean is gone for subsequent interactions (even ajax).
You should note that it is encouraged to use the scopes from package javax.enterprise.context
For your application, looks like the minimum scope required is ViewScope. Since javax.enterprise.context doesn't implement view scope, you might consider using Omnifaces.
How can I pass an injected http session attribute (see below), along with other values (informe by the user) and save them using JPA?
The session attribute is correctly displayed and injected, but I need to pass it using the selected to be stored in the database (actually, it passess null).
The JSF:
<p:outputLabel value="UserID (the sessionAttribute):" for="userID" />
<p:inputText id="userID" value="#{userBean.myUser.xChave}" title="userID" />
<p:outputLabel value="Type the Reason:" for="reason" />
<p:inputText id="reason" value="#{viagensController.selected.reason}" />
<!-- updated (just the call to the action method: -->
<p:commandButton actionListener="#{viagensController.saveNew}" value="#{viagensBundle.Save}" update="display,:ViagensListForm:datalist,:growl" oncomplete="handleSubmit(xhr,status,args,ViagensCreateDialog);" />
The bean:
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
#Named(value = "userBean")
#SessionScoped
public class UserBean implements Serializable {
private bean_login myUser;
public bean_login getMyUser() {
return myUser;
}
public void setMyUser(bean_login myUser) {
this.myUser = myUser;
}
#PostConstruct
public void init() {
String uid = FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("xChave").toString();
myUser = new bean_login();
myUser.setxChave(uid);
System.out.print("from init:" + myUser.toString());
}
}
The AbstractFacade:
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {{ /*impl. ommited*/ }
public List<T> findAll() {{ /*impl. ommited*/ }
public List<T> findRange(int[] range) { /*impl. ommited*/ }
public int count() { /*impl. ommited*/ }
}
The AbstractController (for the selected in JSF above and other methods):
public abstract class AbstractController<T> {
#Inject
private AbstractFacade<T> ejbFacade;
private Class<T> itemClass;
private T selected;
private Collection<T> items;
private enum PersistAction {
CREATE,
DELETE,
UPDATE
}
public AbstractController() {
}
public AbstractController(Class<T> itemClass) {
this.itemClass = itemClass;
}
public T getSelected() {
return selected;
}
// Pass in the currently selected item
public void setSelected(T selected) {
this.selected = selected;
}
protected void setEmbeddableKeys() {
}
protected void initializeEmbeddableKey() {
}
public Collection<T> getItems() {
if (items == null) {
items = this.ejbFacade.findAll();
}
return items;
}
// Pass in collection of items
public void setItems(Collection<T> items) {
this.items = items;
}
// Apply changes to an existing item to the data layer.
public void save(ActionEvent event) {
String msg = ResourceBundle.getBundle("/viagensBundle").getString(itemClass.getSimpleName() + "Updated");
persist(PersistAction.UPDATE, msg);
}
// Store a new item in the data layer.
public void saveNew(ActionEvent event) {
String msg = ResourceBundle.getBundle("/viagensBundle").getString(itemClass.getSimpleName() + "Created");
persist(PersistAction.CREATE, msg);
if (!isValidationFailed()) {
items = null; // Invalidate list of items to trigger re-query.
}
}
public void delete(ActionEvent event) {/*implementations ommited*/ }
private void persist(PersistAction persistAction, String successMessage) {
if (selected != null) {
this.setEmbeddableKeys();
try {
if (persistAction != PersistAction.DELETE) {
this.ejbFacade.edit(selected);
} else {
this.ejbFacade.remove(selected);
}
JsfUtil.addSuccessMessage(successMessage);
} catch (EJBException ex) {
String msg = "";
Throwable cause = JsfUtil.getRootCause(ex.getCause());
if (cause != null) {
if (cause instanceof ConstraintViolationException) {
ConstraintViolationException excp = (ConstraintViolationException) cause;
for (ConstraintViolation s : excp.getConstraintViolations()) {
JsfUtil.addErrorMessage(s.getMessage());
}
} else {
msg = cause.getLocalizedMessage();
if (msg.length() > 0) {
JsfUtil.addErrorMessage(msg);
} else {
JsfUtil.addErrorMessage(ex, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
}
}
}
} catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
JsfUtil.addErrorMessage(ex, ResourceBundle.getBundle("/viagensBundle").getString("PersistenceErrorOccured"));
}
}
}
// Creates a new instance of an underlying entity and assigns it to Selected property.
public T prepareCreate(ActionEvent event) {
T newItem;
try {
newItem = itemClass.newInstance();
this.selected = newItem;
initializeEmbeddableKey();
return newItem;
} catch (InstantiationException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
}
return null;
}
// Inform the user interface whether any validation error exist on a page.
public boolean isValidationFailed() {
return JsfUtil.isValidationFailed();
}
// Retrieve all messages as a String to be displayed on the page.
public String getComponentMessages(String clientComponent, String defaultMessage) {
return JsfUtil.getComponentMessages(clientComponent, defaultMessage);
}
}
Thanks in advance.
updated:
The ViagensController:
#Named(value = "viagensController")
#ViewScoped
public class ViagensController extends AbstractController<Viagens> implements Serializable {
//generics:passing JPA Entity class, where the 'reason' in JSF is defined
public ViagensController() {
super(Viagens.class);
}
}
Need to override the save method passing the injected http session value :
#ManagedBean(name = "riscosController")
#ViewScoped
public class RiscosController extends AbstractController<Riscos> {
#EJB
private RiscosFacade ejbFacade;
#Inject
#SessionChave
private String iSessionChave;
private String sessionChave;
private UorPosController matriculaController;
private UorPosController informanteController;
public String getSessionChave(String chave) {
if (sessionChave.isEmpty()) {
sessionChave = iSessionChave;
}
return sessionChave;
}
public void setSessionChave(String sessionChave) {
this.sessionChave = sessionChave;
}
#PostConstruct
#Override
public void init() {
super.setFacade(ejbFacade);
FacesContext context = FacesContext.getCurrentInstance();
matriculaController = context.getApplication().evaluateExpressionGet(context, "#{uorPosController}", UorPosController.class);
informanteController = context.getApplication().evaluateExpressionGet(context, "#{uorPosController}", UorPosController.class);
sessionChave = "";
}
#Override
public void saveNew(ActionEvent event) {
this.getSelected().setObs(this.getSessionChave(sessionChave));
super.saveNew(event);
}
}