o:socket in EJB class - I get a NPE in org.omnifaces.util.Messages - jsf

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?

Related

Why is my Primefaces.current() returning null

So, I have this page:
#Named("ManagementPage")
#ViewScoped
#Getter
#Setter
#Join(path = "/{appScope}/admin/management",
to = "/pages/scoped/managementOverview.xhtml")
#Page(
group = "kitchen",
icon = "mdi mdi-comment-text",
key = "management",
navigation = Page.Navigation.ADMIN_SCOPED,
outcome = "/pages/scoped/managementOverview.xhtml",
auth = #PageAuth(value = "MANAGER_ACCESS", scoped = true))
public class ManagementPage implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private ManagementModel model;
#PostConstruct
public void init() {
this.model.init();
}
}
It's ViewScoped. And the model for it is:
#Log4j
#Dependent
#Getter
#Setter
public class ManagementModel implements Serializable {
...
}
I want, whenever I receive an event, to refresh some UI on the frontend (I'm using JSF). For that, I've created this dispatcher:
#ApplicationScoped
public class OrderEventDispatcher {
private static final List<ManagementModel> subscriptions = new ArrayList<>();
public static void addSubscriber(ManagementModel subscriber) {
subscriptions.add(subscriber);
}
public static void removeSubscriber(ManagementModel subscriber) {
subscriptions.remove(subscriber);
}
public void observerOrderCreated(#Observes FrontendEvent frontendEvent) {
if(frontendEvent instanceof ContentItemCreatedEvent){
if(!"order".equals(((ContentItemCreatedEvent) frontendEvent).getTypeKey())){
return;
}
}
if(frontendEvent instanceof ContentItemChangedEvent){
if(!"order".equals(((ContentItemChangedEvent) frontendEvent).getTypeKey())){
return;
}
}
subscriptions.forEach(ManagementModel::orderInit);
}
}
(I have implemented a proper equals for this in my model)
For my dispatcher to work, I'm subcribing with my model to it (the methods are inside the model)
#PostConstruct
public void init() {
id = totalIds++;
OrderEventDispatcher.addSubscriber(this);
...
And then i unsubscribe before I destroy the model:
#PreDestroy
public void preDestroy() {
OrderEventDispatcher.removeSubscriber(this);
}
And finally, the methods I call from my dispatcher:
public void orderInit() {
loadMergedOrders();
initializeDonut();
PrimeFaces.current().executeScript("orderInit()");
}
I'm doing all this in order to refresh my page (even when multiple instance of the same page are open) in reaction to an event (some item is created/deleted/modified, of that the FrontendEvent takes care). Now the issue is that my PrimeFaces.current() is always returning null, I've added a breakpoint in the init() method and I tried using PrimeFaces.current() and it worked then, but then when I went through the Dispatcher and into the orderInit() with the debugger I've seen that PrimeFaces.current() now returns null. Does anyone have any idea what I'm doing wrong? If not how to fix this then maybe a different approach to solving this. Thanks for your time!

Omnifaces: Socket; have multiple events / different remoteCommand scripts?

I´m using o:socket for my chat application.
Currently I can send and receive messages, but now I would like to have different events.
Event1: sendMessage (send a message to channel)
Event2: a user is typing.
Currently my page is like that:
<h:form>
<o:socket channel="chatChannel"
user="#{loginChatController.chatUser.id}" scope="view"
onmessage="chatScript">
</o:socket>
<p:remoteCommand name="chatScript" immediate="true" update=":chatForm"
global="false" />
</h:form>
Here my WebSocket:
#Named
#ApplicationScoped
public class ChatWebsocket implements Serializable {
private static final long serialVersionUID = 7615791377170410627L;
#Inject
#Push(channel = "chatChannel")
private PushContext push;
/**
* Push Chat
*
* #param recipientUser
*/
public void pushUser(#Observes ChatPushEvent event) {
if (event.getChatUserList() == null)
return;
push.send("chatForm", event.getChatUserList());
}
}
And here my ChatPushEvent class:
public class ChatPushEvent {
private String message;
private ChatUser chatUser;
private List<Long> chatUserList;
////////////////////////////////////////////////////////
public ChatPushEvent(String message, ChatUser chatUser) {
super();
this.message = message;
this.chatUser = chatUser;
}
public ChatPushEvent(String message, List<Long> chatUserList) {
super();
this.message = message;
this.chatUserList = chatUserList;
}
public List<Long> getChatUserList() {
return chatUserList;
}
public void setChatUserList(List<Long> chatUserList) {
this.chatUserList = chatUserList;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public ChatUser getChatUser() {
return chatUser;
}
public void setChatUser(ChatUser chatUser) {
this.chatUser = chatUser;
}
}
The idea is now to add at the ChatPushEvent class another String like "eventType". This can be "NORMAL_MESSAGE" or "TYPING"...
In my JSF page I need now this to call p:remoteCommand1 or p:remoteCommand2:
How can I do this / get the ChatPushEvent in the JSF page?
So I need something like this
<h:form>
<o:socket channel="chatChannel"
user="#{loginChatController.chatUser.id}" scope="view"
onmessage="chatScript">
</o:socket>
<p:remoteCommand name="chatScript" immediate="true" update=":chatForm"
global="false" />
<p:remoteCommand name="chatScriptTyping" actionListener="doSomething" immediate="true" update=":chatForm"
global="false" />
</h:form>
How can I call chatScriptTyping or chatScript

How to access a Managed Bean from WebSocket class

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;
}

How to extend AjaxBehaviorEvent dispatched from #FacesComponent?

When I dispatch an ajax event from the Composite Component by using <cc:clientBehavior name="chartUpdated" event="change" targets="chartdata"/> I catch it in Facelet page by using <f:ajax event="chartUpdated" listener="#{bean.updateListener}">. And In backing bean I capture event of type AjaxBehaviorEvent.
public void updateListener(AjaxBehaviorEvent event){
...
}
I undertand that I can extend AjaxBehaviorEvent and pass within it object which has been changed. For example, Primefaces's Scheduler uses this approach:
<p:ajax event="eventMove" listener="#{scheduleView.onEventMove}" update="messages" />
And backing bean:
public void onEventMove(ScheduleEntryMoveEvent event) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Event moved", "Day delta:" + event.getDayDelta() + ", Minute delta:" + event.getMinuteDelta());
addMessage(message);
}
Is it possible to achieve the same functionality by using Composite Component together with the #FacesComponent ?
Thank you in advance!
Nice to meet you, again :)
continuing from your previous question:
Override queueEvent() to filter interesting events (changes from specific components) and postpone their enqueue to validation phase to be able to fetch converted & validated values:
#FacesComponent("rangeComponent")
public class RangeComponent extends UIInput implements NamingContainer
{
private final List<AjaxBehaviorEvent> customEvents = new ArrayList<>();
...
#Override
public void queueEvent(FacesEvent event)
{
FacesContext context = getFacesContext();
if(event instanceof AjaxBehaviorEvent)
{
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
String eventName = params.get("javax.faces.behavior.event");
Object eventSource = event.getSource();
if("change".equals(eventName) && (from.equals(eventSource) || to.equals(eventSource)))
{
customEvents.add((AjaxBehaviorEvent) event);
return;
}
}
super.queueEvent(event);
}
#Override
public void validate(FacesContext context)
{
super.validate(context);
if(from.isValid() && to.isValid())
{
for(AjaxBehaviorEvent event : customEvents)
{
SelectEvent selectEvent = new SelectEvent(this, event.getBehavior(), this.getValue());
if(event.getPhaseId().equals(PhaseId.APPLY_REQUEST_VALUES))
{
selectEvent.setPhaseId(PhaseId.PROCESS_VALIDATIONS);
}
else
{
selectEvent.setPhaseId(PhaseId.INVOKE_APPLICATION);
}
super.queueEvent(selectEvent);
}
}
}
...
}
then add the specific event listener to your managed bean:
#ManagedBean
#ViewScoped
public class RangeBean implements Serializable
{
private static final long serialVersionUID = 1L;
private String range = "01/01/2015-31/12/2015";
public void onSelect(SelectEvent event)
{
Messages.addGlobalInfo("[{0}] selected: [{1}]", event.getComponent().getId(), event.getObject());
}
public String getRange()
{
return range;
}
public void setRange(String range)
{
this.range = range;
}
}

JSF h:selectonemenu convertor Validation error value is not valid [duplicate]

This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 7 years ago.
I know this has been discussed a lot, and I also tried most of resolution, but I still got this error:
sourceId=comboNewTaskParent[severity=(ERROR 2), summary=(comboNewTaskParent: Validation Error: Value is not valid), detail=(comboNewTaskParent: Validation Error: Value is not valid)]
Here is the code for HTML:
<h:outputLabel value="Parent task" for="comboNewTaskParent" />
<div class="formRight">
<h:selectOneMenu id="comboNewTaskParent" value="#{taskController.parentTask}" converter="#{taskConverter}"
<f:selectItems value="#{comboTaskByProject}" var="task" itemValue="#{task}" itemLabel="#{task.taskName}" />
</h:selectOneMenu>
</div>
Here is the code of my entity bean:
package com.projectportal.entity;
import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
/**
* The persistent class for the Task database table.
*
*/
#Entity
#Table(name="Task")
public class Task implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(unique=true, nullable=false, length=36)
private String taskId;
#Column(length=1000)
private String taskDesc;
#Column(nullable=false)
private int taskDurationHour;
#Temporal(TemporalType.TIMESTAMP)
#Column(nullable=false)
private Date taskEstimated;
#Column(nullable=false, length=200)
private String taskName;
#Column(nullable=false)
private float taskPercentComplete;
#Temporal(TemporalType.TIMESTAMP)
#Column(nullable=false)
private Date taskStartDate;
//bi-directional many-to-one association to Priority
#ManyToOne
#JoinColumn(name="priorityId", nullable=false)
private Priority priority;
//bi-directional many-to-one association to Project
#ManyToOne
#JoinColumn(name="projectId")
private Project project;
//bi-directional many-to-one association to Status
#ManyToOne
#JoinColumn(name="statusId", nullable=false)
private Status status;
//bi-directional many-to-one association to Task
#ManyToOne
#JoinColumn(name="parentTaskId")
private Task parentTask;
//bi-directional many-to-one association to Task
#OneToMany(mappedBy="parentTask")
private List<Task> childTasks;
//bi-directional many-to-one association to Task
#ManyToOne
#JoinColumn(name="preTaskId")
private Task preTask;
//bi-directional many-to-one association to Task
#OneToMany(mappedBy="preTask")
private List<Task> dependentTasks;
//bi-directional many-to-one association to UserXTask
#OneToMany(mappedBy="task")
private List<UserXTask> userXtasks;
public Task() {
}
public String getTaskId() {
return this.taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getTaskDesc() {
return this.taskDesc;
}
public void setTaskDesc(String taskDesc) {
this.taskDesc = taskDesc;
}
public int getTaskDurationHour() {
return this.taskDurationHour;
}
public void setTaskDurationHour(int taskDurationHour) {
this.taskDurationHour = taskDurationHour;
}
public Date getTaskEstimated() {
return this.taskEstimated;
}
public void setTaskEstimated(Date taskEstimated) {
this.taskEstimated = taskEstimated;
}
public String getTaskName() {
return this.taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public float getTaskPercentComplete() {
return this.taskPercentComplete;
}
public void setTaskPercentComplete(float taskPercentComplete) {
this.taskPercentComplete = taskPercentComplete;
}
public Date getTaskStartDate() {
return this.taskStartDate;
}
public void setTaskStartDate(Date taskStartDate) {
this.taskStartDate = taskStartDate;
}
public Priority getPriority() {
return this.priority;
}
public void setPriority(Priority priority) {
this.priority = priority;
}
public Project getProject() {
return this.project;
}
public void setProject(Project project) {
this.project = project;
}
public Status getStatus() {
return this.status;
}
public void setStatus(Status status) {
this.status = status;
}
public Task getParentTask() {
return this.parentTask;
}
public void setParentTask(Task parentTask) {
this.parentTask = parentTask;
}
public List<Task> getChildTasks() {
return this.childTasks;
}
public void setChildTasks(List<Task> childTasks) {
this.childTasks = childTasks;
}
public Task getPreTask() {
return this.preTask;
}
public void setPreTask(Task preTask) {
this.preTask = preTask;
}
public List<Task> getDependentTasks() {
return this.dependentTasks;
}
public void setDependentTasks(List<Task> dependentTasks) {
this.dependentTasks = dependentTasks;
}
public List<UserXTask> getUserXtasks() {
return this.userXtasks;
}
public void setUserXtasks(List<UserXTask> userXtasks) {
this.userXtasks = userXtasks;
}
}
The controller:
public #Model class TaskController {
#Inject private EntityManager em;
#Inject Identity identity;
#Inject Logger log;
#Inject Event<Task> taskEventSrc;
#Named
#Produces
private List<Task> requestTaskList;
private Task parentTask;
private Task newTask;
#Produces
#Named
public Task getNewTask(){
return this.newTask;
}
/**
*
*/
public TaskController() {
// TODO Auto-generated constructor stub
}
#PostConstruct
public void loadSelfTasks(){
// Init
newTask = new Task();
// Get user from DB.
User user = em.find(User.class, identity.getUser().getId());
requestTaskList = new ArrayList<Task>();
// Loop user's tasks.
for(UserXTask userTask : user.getUserXtasks()){
requestTaskList.add(userTask.getTask());
}
log.info("Tasks for user: " + user.getFirstname() + " loaded.");
}
/**
* Create task.
* #throws Exception
*/
public void createTask() throws Exception{
log.info("Persistencing task: " + newTask.getParentTask().getTaskId());
em.persist(newTask);
taskEventSrc.fire(newTask);
newTask = new Task();
}
/**
* #return the parentTask
*/
public Task getParentTask() {
return parentTask;
}
/**
* #param parentTask the parentTask to set
*/
public void setParentTask(Task parentTask) {
this.parentTask = parentTask;
}
}
And of course the converter:
#Named
/**
* #author lastcow
*
*/
public class TaskConverter implements Converter {
#Inject EntityManager em;
#Inject Logger log;
/* (non-Javadoc)
* #see javax.faces.convert.Converter#getAsObject(javax.faces.context.FacesContext, javax.faces.component.UIComponent, java.lang.String)
*/
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
log.info("=========== Convert to Object " + value);
if(value.equals("0")){
return null;
}
Task t = em.find(Task.class, value);
log.info("======== Got : " + t.getTaskName());
return t;
}
/* (non-Javadoc)
* #see javax.faces.convert.Converter#getAsString(javax.faces.context.FacesContext, javax.faces.component.UIComponent, java.lang.Object)
*/
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
log.info("=========== Convert to String " + value);
return ((Task)value).getTaskId();
}
}
from what logged, the convert are working as it, but when I try to submit the form, always throw 'Validation Error: Value is not valid' ERROR, I have struck here for almost 2 days.
Anyone please give some suggestions.
BTW, I tried put equals and hashCode in Task.java, doesn't working either.
Thanks in advance.
Validation Error: Value is not valid
This error will be thrown when the equals() method of the selected item hasn't returned true for any of the available items in <f:selectItem(s)>. Thus, this can technically have only 2 causes:
The equals() method of your Task class is missing or broken.
The <f:selectItems value="#{comboTaskByProject}"> has incompatibly changed during the postback request of the form submit as compared to during the initial request of the form display.
To fix cause #1, make sure that you understand how to implement equals() properly. You can find kickoff examples here: Right way to implement equals contract
To fix cause #2, make sure that the #{comboTaskByProject} never canges during postback. Best is to put it in the view scope or broader, or to make sure that request based conditions for populating that list are preserved in the postback request by e.g. using <f:viewParam>.
See also:
Our selectOneMenu wiki page
Validation Error: Value is not valid
I am not sure which version of JSF you are using. As far as I know, the converter in HTML should be used like this converter="javax.faces.DateTime". Where this part javax.faces.DateTime is converter name defined in faces-config.xml or in converter class with #FacesConverter.

Resources