Liferay 7: How to access OSGi services from the JSF portlet
The objective is very clear from the title of the article, although in reality, this wants to be an addition to the official documentation of Liferay, which reports in the section JSF Portlets with Liferay Faces => Services in JSF, how to access OSGi-based services from a JSF portlet. The need for integration stems from the fact that the documentation omits how to deal with the necessary dependencies so that it is possible to use the OSGi services and correctly install the portlet.
When creating a JSF portlet on Liferay 7, via command line or via IDE, the dependencies are those indicated on the build.gradle file to follow (and in this particular case it was decided to use Primefaces).
apply plugin: 'war' repositories { mavenCentral() } dependencies { compile group: 'org.primefaces', name: 'primefaces', version:'6.1' compile group: 'com.liferay.faces', name: 'com.liferay.faces.bridge.ext', version:'5.0.1' compile group: 'com.liferay.faces', name: 'com.liferay.faces.bridge.impl', version:'4.1.0' compile group: 'log4j', name: 'log4j', version:'1.2.14' providedCompile group: 'javax.faces', name: 'javax.faces-api', version:'2.2' runtime group: 'org.glassfish', name: 'javax.faces', version:'2.2.14' }
When we need to access OSGi-based services from our JSF portlet, as explained in the Liferay documentation, we only need to use the ServiceTracker, which is part of the OSGi core framework. In order to use the ServiceTracker on our project, we must add an additional dependency to the build.gradle. The dependency that needs to be added is org.osgi.core.
apply plugin: 'war' repositories { mavenCentral() } dependencies { compile group: 'org.primefaces', name: 'primefaces', version:'6.1' compile group: 'com.liferay.faces', name: 'com.liferay.faces.bridge.ext', version:'5.0.1' compile group: 'com.liferay.faces', name: 'com.liferay.faces.bridge.impl', version:'4.1.0' compile group: 'log4j', name: 'log4j', version:'1.2.14' providedCompile group: "com.liferay.portal", name:"com.liferay.portal.kernel", version:"2.0.0" providedCompile group: "org.osgi", name:"org.osgi.core", version:"6.0.0" providedCompile group: 'javax.faces', name: 'javax.faces-api', version:'2.2' runtime group: 'org.glassfish', name: 'javax.faces', version:'2.2.14' }
When we use the Gradle war plugin, we have the ability to declare dependencies as providedCompile to instruct the compiler to include such dependencies in the compile classpath but not to be included in the packaged war artifact.
Declaring the org.osgi.core dependency as providedCompile is very important, otherwise the plugin deployment will fail. If you are careful, build.gradle also includes the com.liferay.portal.kernel dependency declared as providedCompile. These two dependencies are available on the system, so it is not necessary to include them in the war artifact of our plugin.
The build.gradle declares the com.liferay.portal.kernel dependency because it is required by the code example shown on the Liferay documentation using the UserLocalService service.
The build.gradle made in this way generates a proper war artifact that can be installed without any errors on your Liferay 7 instance.
For the happiness of You Readers, I have prepared a simple and complete project of a JSF + Primefaces portlet that accesses the OSGi UserLocaService service through the ServiceTracker in order to show the number of registered users on your Liferay system.
In Figure the example portlet that shows over the versions of the JSF framework also the number of users registered on their own instance of Liferay.
We referred to Gradle as a build system but the same is true for Maven, where the scope for the two dependencies in particular is provided.
We have reached the end of this article which I hope has been useful. At this point I can also reveal that the idea of the article was born from the specific question of a reader who could not make the example shown on the Liferay documentation work.