Bloggers recientes

Carlos Hernandez

Staff
2 Mensajes
24 de febrero de 2018

David H Nebinger

68 Mensajes
23 de febrero de 2018

Jonas Choi

Staff
3 Mensajes
23 de febrero de 2018

Jamie Sammons

Staff
11 Mensajes
19 de febrero de 2018

Iacopo Colonnelli

2 Mensajes
17 de febrero de 2018

Christian Klein

1 Mensajes
15 de febrero de 2018

Jose M. Navarro

Staff
8 Mensajes
14 de febrero de 2018

Maria Sanchez

Staff
18 Mensajes
13 de febrero de 2018

Sergio González

Staff
5 Mensajes
13 de febrero de 2018

Minhchau Dang

Staff
15 Mensajes
31 de enero de 2018
« Atrás

Blueprint and OSGi Fragments for granular module extension

Technical Blogs 2 de diciembre de 2017 Por Iacopo Colonnelli

Introduction

OSGi Fragments are a really powerful tool to extend the features of an existing bundle. Indeed, since fragments share classpath with their host bundle, they allow us to implement new functionalities avoiding unnecessary resource replications. Nevertheless, there are two main limitations that must be taken into account:

  • since fragments never reach the Active status, they are not able to neither register new services nor to override existing ones with an higher ranking
  • despite the classpath sharing feature, fragments cannot override host resources, because host context is searched before fragment context. Liferay JSP fragments are explicitly forced to behave differently by the JspFragmentTrackerCustomizer embedded into JspServlet, but this is not the default

So, what if we have to implement a new service that needs some existing resources located on a third-party bundle (i.e. a set of JSPs, a Soy template, language properties and so on)? Here comes the power of Blueprint framework. Indeed, if we declare our service via blueprint on our fragment, it will be injected into the host classpath when the fragment is attached and will be activated when the host bundle reaches it's Active state.

I will use the simple but practical example below in order to better clarify this concept.

Use case example

Few days ago, a friend of mine asked me how to extend a DDMFormFieldType component in order to make the indexable parameter configurable from UI. Therefore, such option is usually hidden by the visibilityExpression setting contained into DefaultDDMFormFieldTypeSettings implementation.

Obviously, in order to achieve our goal it's necessary to create a new DDMFormFieldTypeSettings class containing an indexType() method annotated with @DDMFormField(visibilityExpression = "TRUE") and tell our DDMFormFieldType component to refer to such settings file. The point here is: how can we do that best, by making the most of the OSGi paradigm modularity? Let's examine the possible (and not possible) solutions:

  • Create a new bundle that implements an higher ranked version of the DDMFormFieldType service. This is the most obvious solution, but with this implementation we are forced to duplicate also js resources and language properties. It should be our last choice, if we can't do anything better. But I'm sure we can ^_^
  • We don't want to replicate resources, so we should try with an OSGI Fragment and its wonderful classpath sharing feature. We could maybe create a fragment and override the settings file, like we did with Ext Plugin in previous versions of Liferay. This solution DOESN'T WORK, because the host context is searched before the fragment context, so original resources always take precedence
  • Therefore, we are forced to implement also our DDMFormFieldType service and inject the new settings file into it. It's no big deal after all. We can simply create our component and set an higher service ranking on it's properties, and Bob's your uncle. Again, this solution DOESN'T WORK, because since fragments do not reach the Active state, their services are not started
  • Well, our last solution is the good one and it's.....a combination of OSGi Fragments and Blueprint Framework. What an astonishing turn of events!!! With this strategy, we only need 3 files to achieve our goal:
    • Our custom DDMFormFieldTypeSettings class, with @DDMFormField(visibilityExpression = "TRUE") annotation on indexType() method
    • Our DDMFormFieldType class, without the component annotation, that refers to our settings file
    • An xml file, contained into the src/main/resources/OSGI-INF/blueprint folder, where we register our DDMFormFieldType implementation as a service with an higher ranking than the original. A simple tutorial on how to define services with blueprint framework syntax can be found here

An implementation of this simple example, realised for Liferay 7 CE ga5, can be found at https://github.com/GlassOfWhiskey/liferay-blueprint-fragment-example. In our case, we extended the ParagraphDDMFormFieldType service, but the same can be done for the other field types. Unfortunately, Liferay 7 CE ga5 doesn't come with an OOTB implementation of Blueprint, so we have to first install all required bundles in order to make it work. This process deserves a dedicated section: the next one.

Blueprint integration

Since Liferay has not an integrated implementation of the Blueprint Framework, we have to install a third-party library. Despite Eclipse Gemini Blueprint is the reference implementation for the OSGi Blueprint service, we chose to integrate Apache Aries Blueprint libraries for a couple of reasons:

  • As reported by LPS-56983, nobody is taking care of the Eclipse Gemini Blueprint project and it's not evolving at all. On the contrary, Apache Aries seems to have a more active community contributing to it
  • Apache Aries suite appears interesting also for other features, as the OSGi Subsystems described by David H Nebinger in this blog post

In order to install Apache Aries Blueprint suite in our Liferay environment, we only need to copy few bundles into the deploy folder:

Into the org-apache-aries-blueprint folder of the example repo there is the set of bundles that we used to enable Blueprint framework on our Liferay instance. Therefore, in order to run the example, you only have to:

  • Copy bundles from org-apache-aries-blueprint folder to your ${LIFERAY_HOME}/deploy folder
  • Deploy the fragment module on your Liferay instance

If the Fragment is correctly resolved, trying to add a new paragraph field to a form and clicking on Show More Options, you should see something like this

Conclusions

With this article, I'd like to bring your attention on how the combination of Blueprint Framework and OSGi Fragments can enhance even more the Liferay extensibility, giving to developers a powerful, versatile and easy-to-use tool to extend Liferay core, that is fully supported by the OSGi standard. Nevertheless, if you can find any drawbacks with this approach or if you have better ideas on how to handle such scenarios, please share them.
Happy Liferay coding!!!

 

Respuestas anidadas Autor Fecha
Fantastic post! Very useful. Have you tried... Christoph Rabel 3 de diciembre de 2017 0:04
Hi Christoph, thank you for your positive... Iacopo Colonnelli 4 de diciembre de 2017 12:23
Very useful post! I don't know yet if I'm going... Krzysztof Gołębiowski 21 de febrero de 2018 6:46

Fantastic post! Very useful.
Have you tried subsystems already? A colleague did and it works only till he restarts the server. Than it doesn't come up anymore (forgot the exact error/problem).
Publicado el día 3/12/17 0:04.
Hi Christoph,
thank you for your positive feedback.
Concerning the Subsystems issue, are you experiencing problems with David's example or with a different esa package? In the first case, I suggest your colleague to add a comment below David's blog post, with the used Liferay version and some details about the error. If you're experiencing a problem with a different subsystem usage, maybe it would be better to open a dedicated thread on Liferay forum. In any case, I need more details to help you
Publicado el día 4/12/17 12:23 en respuesta a Christoph Rabel.
Very useful post! I don't know yet if I'm going to use Blueprint (however this approach is quite interesting), but every new peek under the hood of new Liferay 7/DXP from a different perspective is worth a lot!
Publicado el día 21/02/18 6:46.