Ho avuto la necessità di dover recuperare il numero delle notifiche non lette tramite un servizio rest per poterne fare il polling via Javascript. Liferay purtroppo non mette a disposizione un api rest per le notifiche, per cui ho deciso di implementarla utilizzando il template BLADE "rest" messo a disposizione da Liferay DXP.
Ho creato, da Eclipse, un nuovo progetto utilizzando il template "rest"
Per prima cosa verifichiamo che nel build.gradle ci siano le seguenti dipendenze:
compile group: "javax.ws.rs", name:"javax.ws.rs-api", version:"2.0.1"
compileOnly group: "org.apache.cxf", name: "cxf-core", version: "3.0.3"
compileOnly group: "org.apache.cxf", name: "cxf-rt-frontend-jaxrs", version: "3.0.0"
compileOnly group: "org.apache.cxf", name: "cxf-rt-rs-extension-providers", version: "3.0.3"
Ora creaimo nella cartella resources una cartella configuration e creiamo questi due files:
- com.liferay.portal.remote.cxf.common.configuration.CXFEndpointPublisherConfiguration-cxf.properties
- com.liferay.portal.remote.rest.extender.configuration.RestExtenderConfiguration-rest.properties
creaimo il CXFEndpointPublisherConfiguration-cxf.properties con queste property
contextPath=/api
extensions=
authVerifierProperties=auth.verifier.PortalSessionAuthVerifier.urls.includes\=*
e il RestExtenderConfiguration-rest con queste property
contextPaths=/api
jaxRsProviderFilterStrings=
jaxRsServiceFilterStrings=
jaxRsApplicationFilterStrings=
Inserendo queste configurazioni direttamente da property potremo pubblicare i nostri servizi (in questo esempio risponderranno sul path /api) senza dover configurare nulla in control panel, a patto di aggiungere al bnd.bnd le seguenti informazioni
Liferay-Configuration-Path: /configuration
Include-Resource:configuration=src/main/resources/configuration
A questo punto passiamo all'implementazione del codice vero e proprio
Il template blade avrà creato già un OSGI component con all'interno dei metodi di esempio.
Le annotation di JAX ci permettono di recuperare alcuni parametri direttamente dal contesto, ma purtroppo i parametri recuperabili di default non sono correlati a oggetti Liferay. Nel nostro specifico caso sarebbe utile poter recuperare l'utente direttamente dal contesto, senza che questo debba essere passato come parametro.
Cercando un pò in rete ho trovato questo articolo che spiega come creare dei custom provider:
https://web.liferay.com/it/web/user.26526/blog/-/blogs/rest-custom-context-providers
Di seguito il custom provider che ho creato per recuperare l'utente loggato
@Component(immediate = true, service = UserContextProvider.class)
@Provider
public class UserContextProvider implements ContextProvider<User> {
@Override
public User createContext(Message message) {
try {
return _portal.getUser(
(HttpServletRequest)message.getContextualProperty(
"HTTP.REQUEST"));
}
catch (PortalException pe) {
if (_log.isWarnEnabled()) {
_log.warn("Unable to get user", pe);
}
return null;
}
}
private static final Log _log = LogFactoryUtil.getLog(
UserContextProvider.class);
@Reference
private Portal _portal;
}
Implementata la seguente classe basterà referenziarla attraverso il metodo getSingletons() creato in automatico da blade
@Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
singletons.add(_userContextProvider);
singletons.add(this);
return singletons;
}
Ora non ci rimane che esporre il nostro metodo per effettuare il count delle notifiche
@GET
@Path("/notificationCount")
@Produces(MediaType.APPLICATION_JSON)
public String countNotifications(@Context User user) {
int notificationCount = _userNotificationEventLocalService.getArchivedUserNotificationEventsCount(user.getUserId(), false);
JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
jsonObject.put("notificationCount", notificationCount);
return jsonObject.toJSONString();
}
Invochiamo da browser l'url che risponde sul path /o/api/<rest-path>/notificationCount e il gioco è fatto.