I am missing something here. I am creating a new class and waht to have the resource resolver factory loaded using the @Reference annotation.
But it is not working and I am always getting an NPE when I use it.
Would someone help me to understand why? What am I missing?
Thanks.
@Component(metatype = false, immediate = true)
@Service(value = TestComponent.class)
@Properties({ @org.apache.felix.scr.annotations.Property(name = Constants.SERVICE_DESCRIPTION, value = "TestComponent"),
@org.apache.felix.scr.annotations.Property(name = Constants.SERVICE_VENDOR, value = GeneralConstants.VENDOR),
@org.apache.felix.scr.annotations.Property(name = "process.label", value = "TestComponent") })
public class TestComponentImpl implements TestComponent {
protected static final Logger LOG = LoggerFactory.getLogger( TestComponent.class);
@Reference( policy = ReferencePolicy.STATIC )
private ResourceResolverFactory resolverFactory;
Solved! Go to Solution.
Hi,
resourceResolver = new ReadServiceImpl().getResourceResolver();
That's the problem. You are constructing the ReadServiceImpl via Constructor, and in that way SCR cannot inject any references. You should make the ReadServiceImpl a service and let SCR manage its lifecycle.
Jörg
@Reference works - we have a lot of HELPX articles that show its use. See this one where we use it with Declarative Services annotations:
Adobe Experience Manager Help | Creating an Experience Manager 6.3 Page using the Page Manager API
For info on DS annotations - see: Official OSGi Declarative Services Annotations in AEM - Adobe Experience Manager | AEM/CQ | Apache S...
Views
Replies
Total Likes
I have personally never used the extra syntax you have:
( policy = ReferencePolicy.STATIC )
Views
Replies
Total Likes
I know it works. We have many instances where it is working. I just don't understand why it isn't in this case.
Views
Replies
Total Likes
Try same code on a fresh instance that will tell us if issue is with code or AEM instance.
Views
Replies
Total Likes
Does the reference show up at the OSGI console (/system/console/components) for this component?
Jörg
Views
Replies
Total Likes
Yes. The component status is active and the resource resolver factory is satisfied.
Reference resolverFactory | ["Satisfied","Service Name: org.apache.sling.api.resource.ResourceResolverFactory","Cardinality: 1..1","Policy: static","Policy Option: reluctant","Bound Service ID 981 (Apache Sling Resource Resolver Factory)"] |
Views
Replies
Total Likes
Ok, how does the code look you are using?
Jörg
Views
Replies
Total Likes
Please share logs
Views
Replies
Total Likes
ReferencePolicy.STATIC is the default policy for any referenced service
Views
Replies
Total Likes
Can you give me an idea of what you are looking for in the logs?
Views
Replies
Total Likes
Did you try running this code on a Fresh AEM DEV instance so we can rule out if its your code or the instance. Please do so and let us know the results.
Views
Replies
Total Likes
I started to, but there are dependencies that are not satisfied for our primary bundle. So at the moment I have suspended that approach.
Views
Replies
Total Likes
One curiosity I discovered, I added an activate method and logged the resource resolver in the activate and it appeared non-null.
In the same test, the value for the resource resolver in the main method was null. Not sure what to make of that.
Views
Replies
Total Likes
Can you hook a debugger to your application? Just to make sure that you're actually in the same object. It could be that once you start using that factory that for some reason, you're not in an osgi managed service anymore, but a new created object.
Views
Replies
Total Likes
In your example - you are using it within a method that belongs to TestComponentImpl -- correct?
Views
Replies
Total Likes
I have logging setup in all related classes. I know I am accessing the my class. No need for debugger in that regard.
Yes. I am utilizing the class from within a TestComponentImpl method.
Views
Replies
Total Likes
Hi,
can you please share the code of your component? "main method" sounds a bit strange.
Jörg
Views
Replies
Total Likes
I have taken the time to work the ReadServiceImpl code directly into the event listener for additional testing. Adding the ResourceResolverFactory injection successfully into the listener with that test.
FormSubmitEventListener Class which calls ReadServiceImpl
=====================================================================================
package org.oclc.cq.listeners;
import org.apache.felix.scr.annotations.*;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.jcr.api.SlingRepository;
import org.oclc.cq.config.EnvironmentConfig;
import org.oclc.cq.database.daoimpl.FormSubmittedDataDaoImpl;
import org.oclc.cq.database.util.DataSourceLookup;
import org.oclc.cq.database.valueobject.FormSubmittedData;
import org.oclc.cq.model.GeneralConstants;
import org.oclc.cq.service.ReadServiceImpl;
import org.oclc.cq.utils.ConvertResourceToJSON;
import org.osgi.framework.Constants;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.sql.DataSource;
import java.util.Calendar;
import java.util.Dictionary;
@Component( metatype = true, immediate = true, label = "Form Submit Event Listener", description = "Save form data to database" )
@Service( value = EventListener.class )
@Properties( {
@org.apache.felix.scr.annotations.Property( name = Constants.SERVICE_DESCRIPTION, value = "Form Submit Event Listener" ),
@org.apache.felix.scr.annotations.Property( name = Constants.SERVICE_VENDOR, value = GeneralConstants.VENDOR ) } )
public class FormSubmitEventListener implements EventListener {
protected static final Logger LOG = LoggerFactory.getLogger( FormSubmitEventListener.class);
private static final String FORMSUBMITTEDDATA_DATASOURCE_NAME = "MySQL_FormSubmittedData_DataSource";
@org.apache.felix.scr.annotations.Property( description = "Property to enable the event listener", boolValue = false )
public static final String IS_ENABLED = "org.oclc.cq.listeners.FormSubmitEventListener.isEnabled";
boolean isEnabled = false;
@Reference
private DataSourceLookup dataSourceLookup;
private Session readSession;
@Activate
public void activate( ComponentContext context ) throws Exception {
@SuppressWarnings( "unchecked" ) Dictionary<String, ?> props = context.getProperties();
isEnabled = PropertiesUtil.toBoolean( props.get( IS_ENABLED ), false );
// must be enabled and only allowed to run on author
if ( ! isEnabled || ( isEnabled && ! EnvironmentConfig.isAuthor()) ) {
LOG.info( "FormSubmitEventListener not enabled {} {}", isEnabled, EnvironmentConfig.isAuthor() );
return;
}
LOG.info( "FormSubmitEventListener activate" );
ResourceResolver resourceResolver = null;
try {
resourceResolver = new ReadServiceImpl().getResourceResolver(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Session readSession = resourceResolver.adaptTo( Session.class );
readSession.getWorkspace().getObservationManager().addEventListener( this, // handler
(Event.NODE_ADDED | Event.PROPERTY_CHANGED), // binary combination of event types
"/content/usergenerated/forms", // path
true, // is Deep?
null, // uuids filter
null, // nodetypes filter, allow all nodetypes
false );
} catch ( RepositoryException e ) {
LOG.error( "FormSubmitEventListener did not get registered", e );
throw new Exception( e );
}
finally {
try {
resourceResolver.close();
}
catch ( Exception e ) {
LOG.error( "****OCLC**** Error in finally attempting closes "+e.getMessage(), e );
}
}
}
@Deactivate
public void deactivate() {
if ( readSession != null ) {
readSession.logout();
}
}
@Override
public void onEvent( EventIterator events ) {
ResourceResolver resourceResolver = null;
FormSubmittedDataDaoImpl formSubmittedDataDaoImpl = null;
FormSubmittedData formSubmittedData = new FormSubmittedData();
try {
// THIS WORKS
DataSource dataSource = (DataSource) dataSourceLookup.getDataSource( FORMSUBMITTEDDATA_DATASOURCE_NAME );
LOG.info( "dataSourceLookup dataSource in FormSubmitEventListener {}", dataSource);
resourceResolver = new ReadServiceImpl().getResourceResolver();
ConvertResourceToJSON jsonConverter = new ConvertResourceToJSON();
formSubmittedDataDaoImpl = new FormSubmittedDataDaoImpl( dataSource );
formSubmittedDataDaoImpl.connect();
while ( events.hasNext() ) {
Event event = events.nextEvent();
LOG.info( "FormSubmitEventListener event.getPath : {}", event.getPath() );
LOG.info( "FormSubmitEventListener event.getType : {}", event.getType() );
String contentPath = event.getPath();
// this is temporary during testing, will only use NODE_ADDED
if ( event.getType() == Event.PROPERTY_CHANGED ) {
// need to clean up path, remove everything after nodename; example
// /content/usergenerated/forms/worldwide/en/oclc-rsc/1507296389824_195/jcr:content/participant.name becomes
// content/usergenerated/forms/worldwide/en/oclc-rsc/1507296389824_195
int x = contentPath.indexOf( "/jcr:content");
contentPath = contentPath.substring( 0, x );
}
Resource resource = resourceResolver.resolve(contentPath+"/jcr:content");
JSONObject jsonObject = jsonConverter.resourceToJSON(resource);
ValueMap properties = resource.adaptTo( ValueMap.class );
Calendar calendar = properties.get("jcr:created", null) ;
formSubmittedData.setNodeName( jsonObject.getString("jcr:title") );
formSubmittedData.setContentPath( contentPath );
formSubmittedData.setFormId( jsonObject.getString("formIdentifier") );
formSubmittedData.setFormTitle( jsonObject.getString("formTitle") );
formSubmittedData.setCreatedDate( new java.sql.Timestamp( calendar.getTimeInMillis() ) );
formSubmittedData.setJsonContent( jsonObject.toString() );
formSubmittedDataDaoImpl.addFormSubmittedData( formSubmittedData );
}
formSubmittedDataDaoImpl.close();
}
catch ( Exception e ) {
LOG.error( "Error while processing events "+e.getMessage(), e );
}
finally {
try {
formSubmittedDataDaoImpl.close();
resourceResolver.close();
}
catch ( Exception e ) {
LOG.error( "Error in finally attempting closes "+e.getMessage(), e );
}
}
}
}
=====================================================================================
ReadServiceImpl seems to never inject the ResourceResolverFactory
NPE on resolverFactory.getServiceResourceResolver(serviceParams)
=====================================================================================
package org.oclc.cq.service;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
@Component(metatype = false, immediate = true)
@Service(value = ReadService.class )
public class ReadServiceImpl implements ReadService {
protected static final Logger LOG = LoggerFactory.getLogger( ReadServiceImpl.class);
@Reference
private ResourceResolverFactory resolverFactory;
/**
*
* @return
*/
public ResourceResolver getResourceResolver() {
Map<String, Object> serviceParams = new HashMap<>();
serviceParams.put( ResourceResolverFactory.SUBSERVICE, "readService" );
ResourceResolver resolver = null;
try {
LOG.info("resolverFactory {}", resolverFactory);
resolver = resolverFactory.getServiceResourceResolver(serviceParams);
return resolver;
} catch (LoginException e) {
LOG.error("getServiceResoureResolver exception", e);
}
return null;
}
}
Views
Replies
Total Likes
Hi,
resourceResolver = new ReadServiceImpl().getResourceResolver();
That's the problem. You are constructing the ReadServiceImpl via Constructor, and in that way SCR cannot inject any references. You should make the ReadServiceImpl a service and let SCR manage its lifecycle.
Jörg
Great pick up Joerg!
Views
Replies
Total Likes