Update: The below is not the recommended way of waiting for services in Liferay DXP. To do it the way it should be done, please check the following documentation: https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/waiting-on-lifecycle-events
---
Sometimes, when creating a module, we may run into a situation where the service we're trying to use has not been properly loaded and tracked by OSGi yet. In such cases, the result of our service call will be a NullPointerException coming from the *ServiceUtil class, for example:
java.lang.NullPointerException
at com.liferay.dynamic.data.mapping.service.DDMStructureLocalServiceUtil.getStructures(DDMStructureLocalServiceUtil.java:910)
Checking the line from where its thrown, we see that the only way for a NullPointerException to occur is if getService() returns null.
getService() calls the serviceTracker, which, according to its javadoc, returns null if its not tracking any service objects for that service.
Such a situation can arise if we're trying to call the service during the global.startup.events phase for example - Where OSGi is still working on registering all the services that are being loaded.
Thankfully, there's a way to resolve this issue - add a ServiceDependencyListener.
A ServiceDependencyListener, once added with one or more services, will be called once all of the services have been properly loaded and tracked.
To register a ServiceDependencyListener, just add the below:
ServiceDependencyManager serviceDependencyManager = new ServiceDependencyManager();
serviceDependencyManager.addServiceDependencyListener(new ServiceDependencyListener() {
@Override
public void dependenciesFulfilled() {
_log.info("Dependencies fulfilled.");
doWhatNeedsToBeDone();
}
@Override
public void destroy() {
// ignore
}
});
Registry registry = RegistryUtil.getRegistry();
Filter ddmFilter = registry.getFilter("(&(objectClass=" + DDMStructureService.class.getName() + "))");
serviceDependencyManager.registerDependencies(ddmFilter);
The above is quite straightforward: Create a ServiceDependencyManager, add a new Listener with its two required methods that will be called once the dependencies are fulfilled and once the listener is no longer needed, then get the registry, construct a filter and register it as a dependency.
Hope this helps,
Daniel


