En algunas ocasiones necesitamos enviar notificaciones personalizadas a usuarios específicos para indicarles que ha ocurrido una opción o de manera automática actualizar algún componente tal como un tablero, por ejemplo.
Para utilizar WebSocket en nuestras aplicaciones Jakarta EE, seguimos los siguientes pasos:
- Configurar el archivo web.xml
<context-param>
<param-name>jakarta.faces.ENABLE_CDI_RESOLVER_CHAIN</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>jakarta.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name>
<param-value>true</param-value>
</context-param>
microprofile-config.properties
En el archivo micropofile-config.properties agregue la propìedad
#------------------------------------
#--WebSocket
#-------------------------------------
websocket.minimums.seconds.for.update=50
En la cual se especifica el tiempo mínimo en minutos en los cuales se debe actualizar el formulario actual , una vez que se invoque el Websocket. Se establece este tiempo para evitar actualizaciones demasiado frecuentes que pueden causar afectaciones en el desempeño.
Si el tiempo es menor que el tiempo establecido, se incrementara el contador de notificaciones pendientes que se mostrara al usuario para que luego pueda dar clic en el botón de notificaciones y se actualice el formulario actual.
Defina la interface
public interface WebSocketPlantilla {
public void sendMessageAll(String message, String scoped);
public void sendMessageProyecto(String message, User user);
public void sendMessageProyectoMultiple(String message, List<UserView> userViewList);
public void sendMessageSprint(String message, User user);
public void sendMessageSprintMultiple(String message, List<UserView> userViewList);
public void sendMessageTablero(String message, User user);
public void sendMessageTableroMultiple(String message, List<UserView> userViewList);
public void sendMessageBacklog(String message, User user);
public void sendMessageBacklogMultiple(String message, List<UserView> userViewList);
public void sendMessagePapeleraReciclaje(String message, User user);
public void sendMessagePapeleraReciclajeMultiple(String message, List<UserView> userViewList);
public void sendMessagePanelTrabajo(String message, User user);
public void sendMessagePanelTrabajoMultiple(String message, List<UserView> userViewList);
public Collection<Long> collectionOfUserList(List<UserView> userList);
}
Cree la clase
@ViewScoped
@Named
public class WebSocketController implements Serializable, WebSocketPlantilla {
@Inject
@Push
private PushContext proyectoChannel;
@Inject
@Push
private PushContext proyChannel;
@Inject
@Push
private PushContext sprintChannel;
@Inject
@Push
private PushContext tableroChannel;
@Inject
@Push
private PushContext backlogChannel;
@Inject
@Push
private PushContext panelTrabajoChannel;
@Inject
@Push
private PushContext papeleraReciclajeChannel;
@Inject
@Push
PushContext allChannel;
/**
*
* @param message
* @param user
*/
@Override
public void sendMessageProyecto(String message, User user) {
proyectoChannel.send(message, user.getIduser());
}
/**
* *
* Envia mensaje a muchos usuarios
*
* @param message
* @param userViewList
*/
@Override
public void sendMessageProyectoMultiple(String message, List<UserView> userViewList) {
proyectoChannel.send(message, collectionOfUserList(userViewList));
}
/**
*
* @param message
* @param user
*/
@Override
public void sendMessageSprint(String message, User user) {
sprintChannel.send(message, user.getIduser());
}
/**
* *
* Envia mensaje a muchos usuarios
*
* @param message
* @param userViewList
*/
@Override
public void sendMessageSprintMultiple(String message, List<UserView> userViewList) {
sprintChannel.send(message, collectionOfUserList(userViewList));
}
/**
*
* @param message
* @param user
*/
@Override
public void sendMessageTablero(String message, User user) {
tableroChannel.send(message, user.getIduser());
}
/**
* *
* Envia mensaje a muchos usuarios
*
* @param message
* @param userViewList
*/
@Override
public void sendMessageTableroMultiple(String message, List<UserView> userViewList) {
tableroChannel.send(message, collectionOfUserList(userViewList));
}
@Override
public void sendMessageAll(String message, String scoped) {
allChannel.send(message, "user");
}
@Override
public void sendMessageBacklog(String message, User user) {
backlogChannel.send(message, user.getIduser());
}
@Override
public void sendMessageBacklogMultiple(String message, List<UserView> userViewList) {
backlogChannel.send(message, collectionOfUserList(userViewList));
}
@Override
public void sendMessagePapeleraReciclaje(String message, User user) {
papeleraReciclajeChannel.send(message, user.getIduser());
}
@Override
public void sendMessagePapeleraReciclajeMultiple(String message, List<UserView> userViewList) {
papeleraReciclajeChannel.send(message, collectionOfUserList(userViewList));
}
@Override
public void sendMessagePanelTrabajo(String message, User user) {
panelTrabajoChannel.send(message, user.getIduser());
}
@Override
public void sendMessagePanelTrabajoMultiple(String message, List<UserView> userViewList) {
panelTrabajoChannel.send(message, collectionOfUserList(userViewList));
}
@Override
public Collection<Long> collectionOfUserList(List<UserView> userViewList) {
Collection<Long> result = new ArrayList<>();
try {
userViewList.forEach(u -> {
result.add(u.getIduser());
});
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
public Collection<Long> collectionOfProyectoList(List<Proyecto> proyectoList) {
Collection<Long> result = new ArrayList<>();
try {
proyectoList.forEach(u -> {
result.add(u.getIdproyecto());
});
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
}
Crear la interface FacesWebSocket
public interface FacesWebSocket {
public String refreshFromWebsocket();
public String updateForRemoteWebsocket();
public void sendMensajesWebsocket(MessageWebSocket messageWebSocket,Tarjeta tarjeta, Boolean exclude);
public void sendMensajesWebsocket(MessageWebSocket messageWebSocket);
public void onCompleteWebSocket();
/**
*
* @param userViewProjectoSelectedForWebSocketList
* @param tarjeta
* @return La lista de userView para ser usada en el envio de WebSocket.
* Verifica si es una tarjeta foranea y agrega el usuario.
*/
public default List<UserView> filterUserViewListForWebSocket(List<UserView> userViewProjectoSelectedForWebSocketList, Tarjeta tarjeta) {
List<UserView> result = new ArrayList<>();
try {
result.addAll(userViewProjectoSelectedForWebSocketList);
/**
* si es una tarjeta foranea agrega el usuario
*/
if (tarjeta.getForeaneo()) {
UserView uv = tarjeta.getUserView().get(0);
Optional<UserView> userViewOptional = result.stream().filter(x -> x.getIduser().equals(uv.getIduser())).findFirst();
if (!userViewOptional.isPresent()) {
result.add(uv);
}
}
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
// <editor-fold defaultstate="collapsed" desc="List<UserView> filterUserViewListForWebSocket(List<UserView> userViewProjectoSelectedForWebSocketList) {">
public default List<UserView> filterUserViewListForWebSocket(List<UserView> userViewProjectoSelectedForWebSocketList) {
List<UserView> result = new ArrayList<>();
try {
result.addAll(userViewProjectoSelectedForWebSocketList);
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="List<UserView> userViewFromProjectExclude(Proyecto proyectoSelected, Boolean exclude, User... excludeUser)">
/**
*
* @param proyectoSelected
* @return Obtiene la lista de userView del proyecto
*/
public default List<UserView> userViewFromProjectExclude(Proyecto proyectoSelected, Boolean exclude, User... excludeUser) {
List<UserView> result = new ArrayList<>();
try {
Long iduser = 0l;
if (excludeUser.length != 0) {
iduser = excludeUser[0].getIduser();
for (ProyectoMiembro pm : proyectoSelected.getProyectoMiembro()) {
if (exclude) {
if (iduser.equals(pm.getUserView().getIduser())) {
} else {
result.add(pm.getUserView());
}
} else {
result.add(pm.getUserView());
}
}
} else {
proyectoSelected.getProyectoMiembro().forEach(pm -> {
result.add(pm.getUserView());
});
}
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="List<UserView> userViewFromProjectExcludeIncludeOldUser(Proyecto proyectoSelected, List<ProyectoMiembro> proyectoMiembroOldList, Boolean exclude, User... excludeUser)">
/**
*
* @param proyectoSelected
* @return Obtiene la lista de userView del proyecto
*/
public default List<UserView> userViewFromProjectExcludeIncludeOldUser(Proyecto proyectoSelected, List<ProyectoMiembro> proyectoMiembroOldList, Boolean exclude, User... excludeUser) {
List<UserView> result = new ArrayList<>();
try {
List<ProyectoMiembro> proyectoMiembroList = new ArrayList<>();
proyectoMiembroList.addAll(proyectoSelected.getProyectoMiembro());
proyectoMiembroOldList.forEach(pm -> {
Optional<ProyectoMiembro> proyectoMiembroOptional = proyectoSelected.getProyectoMiembro().stream().filter(x -> x.getUserView().getIduser().equals(pm.getUserView().getIduser())).findFirst();
if (!proyectoMiembroOptional.isPresent()) {
proyectoMiembroList.add(pm);
}
});
/*
*/
Long iduser = 0l;
if (excludeUser.length != 0) {
iduser = excludeUser[0].getIduser();
for (ProyectoMiembro pm : proyectoMiembroList) {
if (exclude) {
if (iduser.equals(pm.getUserView().getIduser())) {
} else {
result.add(pm.getUserView());
}
} else {
result.add(pm.getUserView());
}
}
} else {
proyectoMiembroList.forEach(pm -> {
result.add(pm.getUserView());
});
}
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="List<UserView> userViewForWebSocketListFromProjectOfTarjeta(Tarjeta tarjeta, List<Proyecto> proyectoPorColaboradorList, User userLogged)">
public default List<UserView> userViewForWebSocketListFromProjectOfTarjeta(Tarjeta tarjeta, List<Proyecto> proyectoPorColaboradorList, User userLogged) {
List<UserView> result = new ArrayList<>();
try {
Proyecto proyectoWebSocket = new Proyecto();
Boolean found = Boolean.FALSE;
for (Proyecto p : proyectoPorColaboradorList) {
if (p.getIdproyecto().equals(tarjeta.getIdproyecto())) {
proyectoWebSocket = p;
found = Boolean.TRUE;
break;
}
}
if (found) {
result = userViewFromProjectExclude(proyectoWebSocket, Boolean.FALSE, userLogged);
}
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
// </editor-fold>
public default String validarEstadoIniciadoYFechaProyecto(Proyecto proyecto, JmoordbResourcesFiles rf) {
String result = "";
try {
if (!proyecto.getEstado().equals("iniciado")) {
result = rf.fromMessage("warning.proyectoestadonoiniciado");
}
if ((JmoordbCoreDateUtil.fechaIgual(JmoordbCoreDateUtil.getFechaHoraActual(), proyecto.getFechainicial())
|| JmoordbCoreDateUtil.fechaMayor(JmoordbCoreDateUtil.getFechaHoraActual(), proyecto.getFechainicial()))
&& (JmoordbCoreDateUtil.fechaIgual(JmoordbCoreDateUtil.getFechaHoraActual(), proyecto.getFechafinal())
|| JmoordbCoreDateUtil.fechaMenor(JmoordbCoreDateUtil.getFechaHoraActual(), proyecto.getFechafinal()))) {
} else {
result = rf.fromMessage("warning.fechasfuerarangoproyecto");
}
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
}
Edite el template.xhtml
Añada funciones Javascript para procesar las respuestas de los Websocket. Se invocaran remoteCommand pasandole los parámetros evento, channel,message.
Estos p:remoteCommand, se deben agregar en cada formulario donde se desea validar el evento.
<script>
function handleMessageAllChannel(message, channelName, event) {
var messageText = message.toString();
var eventText = event.toString();
var channelText = channelName.toString();
remoteCommandWebSocketAll(
[
{name: 'event', value: eventText},
{name: 'channel', value: channelText},
{name: 'message', value: messageText}
]);
}
function handleMessageProyectoChannel(message, channelName, event) {
var messageText = message.toString();
var eventText = event.toString();
var channelText = channelName.toString();
remoteCommandWebSocketProyecto(
[
{name: 'event', value: eventText},
{name: 'channel', value: channelText},
{name: 'message', value: messageText}
]);
}
function handleMessageTableroChannel(message, channelName, event) {
var messageText = message.toString();
var eventText = event.toString();
var channelText = channelName.toString();
remoteCommandWebSocketTablero(
[
{name: 'event', value: eventText},
{name: 'channel', value: channelText},
{name: 'message', value: messageText}
]
);
}
function handleMessageSprintChannel(message, channelName, event) {
var messageText = message.toString();
var eventText = event.toString();
var channelText = channelName.toString();
remoteCommandWebSocketSprint(
[
{name: 'event', value: eventText},
{name: 'channel', value: channelText},
{name: 'message', value: messageText}
]);
}
function handleMessageBacklogChannel(message, channelName, event) {
var messageText = message.toString();
var eventText = event.toString();
var channelText = channelName.toString();
remoteCommandWebSocketBacklog(
[
{name: 'event', value: eventText},
{name: 'channel', value: channelText},
{name: 'message', value: messageText}
]);
}
function handleMessagePapeleraReciclajeChannel(message, channelName, event) {
var messageText = message.toString();
var eventText = event.toString();
var channelText = channelName.toString();
remoteCommandWebSocketPapeleraReciclaje(
[
{name: 'event', value: eventText},
{name: 'channel', value: channelText},
{name: 'message', value: messageText}
]);
}
function handleMessagePanelTrabajoChannel(message, channelName, event) {
var messageText = message.toString();
var eventText = event.toString();
var channelText = channelName.toString();
remoteCommandWebSocketPanelTrabajo(
[
{name: 'event', value: eventText},
{name: 'channel', value: channelText},
{name: 'message', value: messageText}
]);
}
function errorListener(code, channel, event) {
if (code == 1001) {
// alert('error 1001 Server shutdwon');
} else if (code == 1006) {
//alert('error 1006 ');
} else {
// alert('otro ');
}
}
</script>
Añada componentes Websocket, dentro de un componente
<h:form>
<f:websocket channel="allChannel" user="user" onmessage="handleMessageAllChannel" />
<f:websocket channel="tableroChannel" scope="session" user="#{loginFaces.userLogged.iduser}" onmessage="handleMessageTableroChannel"
onerror="errorListener"/>
<f:websocket channel="sprintChannel" scope="session" user="#{loginFaces.userLogged.iduser}" onmessage="handleMessageSprintChannel"
onerror="errorListener"/>
<f:websocket channel="backlogChannel" scope="session" user="#{loginFaces.userLogged.iduser}" onmessage="handleMessageBacklogChannel"
onerror="errorListener"/>
<f:websocket channel="papeleraReciclajeChannel" scope="session" user="#{loginFaces.userLogged.iduser}" onmessage="handleMessagePapeleraReciclajeChannel"
onerror="errorListener"/>
<f:websocket channel="panelTrabajoChannel" scope="session" user="#{loginFaces.userLogged.iduser}" onmessage="handleMessagePanelTrabajoChannel"
onerror="errorListener"/>
<f:websocket channel="proyectoChannel" scope="session" user="#{loginFaces.userLogged.iduser}" onmessage="handleMessageProyectoChannel"
onerror="errorListener"/>
Añada un p:remoteCommnad para atrapar la acción a realizar con el WebSocket.
<p:remoteCommand name="remoteCommandWebSocketAll"
action="#{loginFaces.webSocketListenerMethod}"
update="template_growl_timesession"
onerror="errorListener"/>
Edite la Clase Dashboard.java
Agregue los atributos para manejar el WebSocket
// <editor-fold defaultstate="collapsed" desc="WebSocket">
@Inject
WebSocketController webSocketController;
private Boolean dialogVisibleWebSocket = Boolean.FALSE;
private Boolean dialogVisibleAddWebSocket = Boolean.FALSE;
private List<UserView> userViewForWebSocketList = new ArrayList<>();
private Integer contadorNotificacionesWebsocket = 0;
private Long jmoordbCronometerOld = 0L;
// </editor-fold>
- Leer la cantidad de segundos mínimos establecido en el archivo microprofile-config.properties.
// #Websocket
@Inject
@ConfigProperty(name = "websocket.minimums.seconds.for.update")
private Provider<Integer> websocketMinimumsSecondsForUpdate;
En el método init()
@PostConstruct
public void init() {
try {
JmoordbCronometer.startCronometer(FacesUtil.nameOfClassAndMethod());
/**
* WebSocket
*/
contadorNotificacionesWebsocket = 0;
jmoordbCronometerOld = 0L;
dialogVisibleWebSocket = Boolean.FALSE;
dialogVisibleAddWebSocket = Boolean.FALSE;
...
}
En los métodos prepare
Debe colocar a True el atributo dialogVisibleWebSocket, para que no se actualice si existe un dialogo abierto en que se esta trabajando.
Y Colocar en TRUE al atributo dialogVisibleAddWebSocket solo en el método prepareNew()
public String prepareNew() {
dialogVisibleWebSocket = Boolean.TRUE;
dialogVisibleAddWebSocket = Boolean.TRUE;
}
El los demás métodos prepare no se utiliza dialogVisibleAddWebSocket
public String prepareEditar(Proyecto proyecto) {
try {
dialogVisibleWebSocket = Boolean.TRUE;
}
}
Recuerde que en cada método que se invoque desde un dialogo debe asignar el valor a False, este proceso se puede simplificar agregándolo al método refresh() que es invocado por todos los métodos.
En el método refresh()
public String refresh() {
contadorNotificacionesWebsocket = 0;
dialogVisibleWebSocket = Boolean.FALSE;
dialogVisibleAddWebSocket = Boolean.FALSE;
}
En el método save()
Vamos a enviar notificaciones mediante Websocket a varios elementos tales como los canales de proyecto, tablero entre otros.
Creamos un objeto de tipo MessageWebSocket. Que esta incluido en la librería jmoordbcoreutilfaces.
public void save(Proyecto proyecto) {
/**
* WebSocket
*/
userViewForWebSocketList = userViewFromProjectExclude(proyecto, Boolean.FALSE, userLogged);
MessageWebSocket messageWebSocket = new MessageWebSocket.Builder()
.producer(FacesUtil.nameOfClass())
.action(FacesUtil.nameOfMethod())
.key("proyecto")
.value(proyecto.getIdproyecto().toString())
.message("Clonar proyecto")
.iduser(userLogged.getIduser())
.date(JmoordbCoreDateUtil.fechaHoraActual())
.build();
sendMensajesWebsocket(messageWebSocket);
}
Defina el método sendMensajesWebsocket(MessageWebSocket messageWebSocket)
En este caso se escribirán notificaciones a varios canales.
@Override
public void sendMensajesWebsocket(MessageWebSocket messageWebSocket) {
try {
List<UserView> result = filterUserViewListForWebSocket(userViewForWebSocketList);
webSocketController.sendMessageProyectoMultiple(messageWebSocket.toJSON(), result);
webSocketController.sendMessageTableroMultiple(messageWebSocket.toJSON(), result);
webSocketController.sendMessageSprintMultiple(messageWebSocket.toJSON(), result);
webSocketController.sendMessagePapeleraReciclajeMultiple(messageWebSocket.toJSON(), result);
webSocketController.sendMessageBacklogMultiple(messageWebSocket.toJSON(), result);
webSocketController.sendMessagePanelTrabajoMultiple(messageWebSocket.toJSON(), result);
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
}
Agregue los métodos para procesar los Websocket
@Override
public String refreshFromWebsocket() {
try {
/**
* Leer los datos del Websocket
*/
String event = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("event");
String channel = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("channel");
String message = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("message");
MessageWebSocket mws = new MessageWebSocket();
mws = mws.toMessageWebSocket(message);
if (jmoordbCronometerOld.equals(0L)) {
if (!dialogVisibleWebSocket) {
refresh();
PrimeFaces.current().ajax().update("form");
}
jmoordbCronometerOld = JmoordbCronometer.nanoSecondsNow();
} else {
Long dif = JmoordbCronometer.diference(jmoordbCronometerOld, JmoordbCronometer.nanoSecondsNow());
Long seconds = dif / 1000;
contadorNotificacionesWebsocket++;
if (seconds < websocketMinimumsSecondsForUpdate.get().longValue()) {
} else {
if (!dialogVisibleWebSocket) {
contadorNotificacionesWebsocket = 0;
refresh();
PrimeFaces.current().ajax().update("form");
}
}
jmoordbCronometerOld = JmoordbCronometer.nanoSecondsNow();
}
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return "";
}
@Override
public String updateForRemoteWebsocket() {
try {
if(dialogVisibleAddWebSocket){
closeOverlayPanel("PF('overlayPanelTarjetaAgregar').show()");
}
if (!dialogVisibleWebSocket) {
return ":form";
}
} catch (Exception e) { FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return "";
}
Defina el método onCompleteWebSocket()
public void onCompleteWebSocket() {
try {
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
}
Edite la pagina profile.xhtml correspondiente al dashboard
Agregue un badge que mostrara la cantidad de notificaciones se han realizado escuchando el WebSocket y no se ha actualizado.
<p:badge
value="#{dashboardFaces.contadorNotificacionesWebsocket}"
severity="danger">
<p:commandLink styleClass="ml-2"
action="#{dashboardFaces.refresh()}"
update=":form"
title="#{core['label.notificaciones']}"
>
<i class="pi pi-bell" style="font-size: 2rem"/>
</p:commandLink>
</p:badge>
Edite la pagina dashboard.xhtml, añada un remoteCommand de la siguiente manera.
<h:form id="form" prependId="false" >
<p:growl id="growl"/>
<p:remoteCommand name="remoteCommandWebSocketProyecto" action="#{dashboardFaces.refreshFromWebsocket()}"
update="#{dashboardFaces.updateForRemoteWebsocket()}"
oncomplete="#{dashboardFaces.onCompleteWebSocket()}"
/>
Escuchar Varios webSocket
En el siguiente ejemplo, tenemos una situación que en el formulario principal al actualizar un proyecto, se debe notificar a todos los usuarios que se encuentren en ese proyecto, y además a usuarios que se encuentren en otro formulario como por ejemplo tablero.
Tablero
El tablero recibe notificaciones desde otro tablero, pero también puede recibir notificaciones desde el Dashboard, que puede enviar un mensaje como por ejemplo el proyecto fue cerrado.
Edite el formulario tablero.xhtml
Añada un remoteCommand
<p:remoteCommand name="remoteCommandWebSocketTablero"
action="#{tableroFaces.refreshFromWebsocket()}"
oncomplete="#{tableroFaces.onCompleteWebSocket()}"
update="#{tableroFaces.updateForRemoteWebsocket()}"
/>
Edite el profile del tablero
Añada un p:badge para mostrar la notificación
<p:badge
value="#{tableroFaces.contadorNotificacionesWebsocket}"
severity="danger">
<p:commandLink styleClass="ml-2"
action="#{tableroFaces.refresh()}"
update=":form"
title="#{core['label.notificaciones']}" >
<i class="pi pi-bell" style="font-size: 2rem"/>
</p:commandLink>
</p:badge>
TableroFaces.java
En la clase TableroFaces añada los siguientes atributos
- Leer la cantidad de segundos mínimos establecido en el archivo microprofile-config.properties.
// #Websocket
@Inject
@ConfigProperty(name = "websocket.minimums.seconds.for.update")
private Provider<Integer> websocketMinimumsSecondsForUpdate;
Añada las propiedades
// <editor-fold defaultstate="collapsed" desc="WebSocket">
@Inject
WebSocketController webSocketController;
private Boolean dialogVisibleWebSocket = Boolean.FALSE;
private Boolean dialogVisibleAddWebSocket = Boolean.FALSE;
private List<UserView> userViewForWebSocketList = new ArrayList<>();
private Integer contadorNotificacionesWebsocket = 0;
private Long jmoordbCronometerOld = 0L;
// </editor-fold>
En el método init()
/*
WebSocket
*/
contadorNotificacionesWebsocket = 0;
jmoordbCronometerOld = 0L;
dialogVisibleWebSocket = Boolean.FALSE;
dialogVisibleAddWebSocket = Boolean.FALSE;
En el método refresh
public String refresh() {
try {
contadorNotificacionesWebsocket = 0;
dialogVisibleWebSocket = Boolean.FALSE;
dialogVisibleAddWebSocket = Boolean.FALSE;
...
}
}
En los métodos prepareNew añada dialogVisibleAddWebSocket
public String prepareNew() {
dialogVisibleWebSocket = Boolean.TRUE;
dialogVisibleAddWebSocket = Boolean.TRUE;
}
En los demás métodos prepare solo agregue dialogVisibleWebSocket
public String prepareEditar(Tarjeta tarjeta) {
try {
dialogVisibleWebSocket = Boolean.TRUE;
}
}
Agregue el método refreshFromWebsocket
Puede observar que este método contiene una verificación adicional para saber si fue invocado desde un tablero o si fue desde un Dashboard, en el caso que fue invocado desde un Dashboard, indica que el proyecto pudo haber cambiado y necesita obtener una actualización del proyecto de la base de datos.
@Override
public String refreshFromWebsocket() {
try {
/**
* Leer los datos del Websocket
*/
String event = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("event");
String channel = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("channel");
String message = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("message");
MessageWebSocket mws = new MessageWebSocket();
mws = mws.toMessageWebSocket(message);
if (jmoordbCronometerOld.equals(0L)) {
if (!dialogVisibleWebSocket) {
//Valida los datos del WebSocket
if (mws.getProducer().equals("DashboardFaces") && mws.getKey().equals("proyecto")
&& mws.getValue().equals(proyectoSelected.getIdproyecto().toString())) {
validateChangeInProject();
}
refresh();
PrimeFaces.current().ajax().update("form");
}
jmoordbCronometerOld = JmoordbCronometer.nanoSecondsNow();
} else {
Long dif = JmoordbCronometer.diference(jmoordbCronometerOld, JmoordbCronometer.nanoSecondsNow());
Long seconds = dif / 1000;
contadorNotificacionesWebsocket++;
if (seconds < websocketMinimumsSecondsForUpdate.get().longValue()) {
} else {
if (!dialogVisibleWebSocket) {
//Valida los datos del WebSocket
if (mws.getProducer().equals("DashboardFaces") && mws.getKey().equals("proyecto")
&& mws.getValue().equals(proyectoSelected.getIdproyecto().toString())) {
validateChangeInProject();
}
contadorNotificacionesWebsocket = 0;
refresh();
PrimeFaces.current().ajax().update("form");
}
}
jmoordbCronometerOld = JmoordbCronometer.nanoSecondsNow();
}
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return "";
}
Agregar el método updateForRemoteWebsocket()
public String updateForRemoteWebsocket() {
try {
if (dialogVisibleAddWebSocket) {
closeOverlayPanel("PF('overlayPanelTarjetaAgregar').show()");
}
if (!dialogVisible) {
return ":form";
}
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return "";
}
Añada el método onCompleteWebSocket()
public void onCompleteWebSocket() {
try {
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
}
Defina el método para validar cambios en el Proyecto
public String validateChangeInProject() {
try {
haveSprintOpen = Boolean.TRUE;
isSprintVencido = Boolean.FALSE;
Proyecto proyectoWebSocket = proyectoServices.findByIdproyecto(proyectoSelected.getIdproyecto());
if (proyectoSelected.equals(proyectoWebSocket)) {
} else {
JmoordbCoreUtil.copyBeans(proyectoSelected, proyectoWebSocket);
JmoordbCoreContext.put("DashboardFaces.proyectoSelected", proyectoSelected);
String result = validarEstadoIniciadoYFechaProyecto(proyectoSelected, rf);
if (!result.equals("")) {
haveSprintOpen = Boolean.FALSE;
isSprintVencido = Boolean.TRUE;
message = result;
FacesUtil.warningDialog(result);
PrimeFaces.current().ajax().update("form");
}
}
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return "";
}
En el método save, realice las operaciones y obtenga la lista de usuarios a los que se les debe enviar la notificación y utilice el método sendMessageTableroMultiple.
public void save(Tarjeta tarjeta) {
MessageWebSocket messageWebSocket = new MessageWebSocket.Builder()
.producer(FacesUtil.nameOfClass())
.action(FacesUtil.nameOfMethod())
.key("tarjeta")
.value(tarjeta.getIdtarjeta().toString())
.message("Crear tarjeta")
.iduser(userLogged.getIduser())
.date(JmoordbCoreDateUtil.fechaHoraActual())
.build();
sendMensajesWebsocket(messageWebSocket,tarjeta, Boolean.FALSE);
}
Añada el método
@Override
public void sendMensajesWebsocket(MessageWebSocket messageWebSocket,Tarjeta tarjeta, Boolean exclude) {
try {
List<UserView> result = filterUserViewListForWebSocket(userViewForWebSocketList, tarjeta);
webSocketController.sendMessageTableroMultiple(messageWebSocket.toJSON(), result);
webSocketController.sendMessageBacklogMultiple(messageWebSocket.toJSON(), result);
webSocketController.sendMessagePapeleraReciclajeMultiple(messageWebSocket.toJSON(), result);
webSocketController.sendMessagePanelTrabajoMultiple(messageWebSocket.toJSON(), result);
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
}
En el dialogo que usamos para agregar imágenes
Invocar los métodos
<p:commandButton value="#{core['button.save']}" icon="pi pi-save"
action="#{tableroFaces.save(tableroFaces.tarjetaSelected)}"
update=":form:growl"
process="#{cc.attrs.id}"
styleClass="w-6 ml-2"/>
<p:commandButton value="#{core['button.cancel']}" icon="pi pi-times" onclick="PF('overlayPanelTarjetaAgregar').hide()"
action="#{tableroFaces.refresh()}"
update=":form"
styleClass="ui-button-outlined w-6 mr-2"/>
Top comments (0)