Fortunamente non ho animali mitologici da gestire come Jader, tuttavia però... ho Jader :)
Oggi voglio parlare un pò di OSGi illustrandovi una soluzione molto elegante per risolvere un problema che potrebbe capitarvi.
Il requisito iniziale, a parole, è molto semplice: rimuovere il link Password dimenticata dalla portlet di login nativa di Liferay 7.1 ed aggiungere un link custom che punti ad una pagina in cui è presente una portlet custom.
In sostanza il risultato finale deve essere il seguente (sotto al pulsante Accedi):
Soddisfare il primo requisito (rimuovere il link Password dimenticata) è semplice perchè si tratta di una configurazione da fare sull'istanza di Liferay.
Invece per aggiungere un link custom la cosa è un pochino diversa; se fossimo sulla versione 6.2 avrei già iniziato a parlare di hook della JSP di portale e sinceramente il mio approccio iniziale era di fare qualcosa di analogo anche sulla 7.1. Così ho iniziato a cercare nei sorgenti di portale il punto in cui venivano gestiti i link ed ho scoperto che... non venivamo gestiti! Non esplicitamente almeno. Cioè?!
Il file in cui vengono gestiti i link a fondo pagina nella portlet di login è il seguente:
[SRC]\modules\apps\login\login-web\src\main\resources\META-INF\resources\navigation.jspf
Ma al suo interno non ci sono link da modificare ma solamente taglib del tipo:
<liferay-util:dynamic-include key="com.liferay.login.web#/navigation.jsp#post" />
In pratica, per farla breve, tutti i link presenti vengono inclusi dinamicamente a runtime (dynamic-include
per l'appunto); pertanto non bisogna modificare la portlet di login ma semplicemente realizzare un opportuno componente OSGi che venga caricato a runtime dalla taglib e si occupi di renderizzare il link custom.
Non mi soffermo oltre e vi mostro qualche riga di codice!
@Component(immediate = true, property = {
"login.web.navigation.position=post", "service.ranking:Integer=100"
}, service = PageInclude.class)
public class MyNavigationPostPageInclude implements PageInclude {
@Reference
private LayoutLocalService _layoutLocalService;
@Override
public void include(PageContext pageContext)
throws JspException {
try {
// La request serve sempre...
HttpServletRequest request =
(HttpServletRequest) pageContext.getRequest();
// Sito di riferimento
long groupId = PortalUtil.getScopeGroupId(request);
// Recupero la pagina a cui deve puntare il link custom
Layout layout = _layoutLocalService
.fetchLayoutByFriendlyURL(groupId, false, "/my-friendly-url");
if (layout != null) {
/*
* Se il testo del link non è una traduzione di portale, allora
* è necessario recuperarla esplicitamente dal vostro bundle
*/
Locale locale = PortalUtil.getLocale(request);
ResourceBundle resourceBundle =
ResourceBundleUtil.getBundle(locale, this.getClass());
String message = LanguageUtil.get(
resourceBundle, "link-text-label");
// Creazione della render URL da associare al link custom
LiferayPortletURL myURL =
PortletURLFactoryUtil.create(
request, PortletKeys.MY_CUSTOM_PORTLET, layout,
PortletRequest.RENDER_PHASE);
// Istanzio e configuro via codice la taglib aui:icon
IconTag iconTag = new IconTag();
iconTag.setCopyCurrentRenderParameters(false);
iconTag.setIconCssClass("icon-undo");
iconTag.setLocalizeMessage(false);
iconTag.setMessage(message);
iconTag.setUrl(myURL.toString());
iconTag.doTag(pageContext);
}
}
catch (PortalException e) {
throw new JspException(e);
}
}
}
Non so voi, ma io la trovo una soluzione estremamente elegante che evita di mettere mano ai sorgenti di portale.