Your achievements

Level 1

0% to

Level 2

Tip /
Sign in

Sign in to Community

to gain points, level up, and earn exciting badges like the new
Bedrock Mission!

Learn more

View all

Sign in to view all badges

SOLVED

@Reference annotation not working

Tom_Fought
Level 4
Level 4

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;

1 Accepted Solution
Jörg_Hoh
Correct answer by
Employee
Employee

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

View solution in original post

22 Replies
smacdonald2008
Level 10
Level 10

@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...

smacdonald2008
Level 10
Level 10

I have personally never used the extra syntax you have:

( policy = ReferencePolicy.STATIC )

Tom_Fought
Level 4
Level 4

I know it works. We have many instances where it is working. I just don't understand why it isn't in this case.

smacdonald2008
Level 10
Level 10

Try same code on a fresh instance that will tell us if issue is with code or AEM instance.

Jörg_Hoh
Employee
Employee

Does the reference show up at the OSGI console (/system/console/components) for this component?

Jörg

Tom_Fought
Level 4
Level 4

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)"]
Jörg_Hoh
Employee
Employee

Ok, how does the code look you are using?

Jörg

dylanr46798176
Level 3
Level 3

ReferencePolicy.STATIC is the default policy for any referenced service

Tom_Fought
Level 4
Level 4

Can you give me an idea of what you are looking for in the logs?

smacdonald2008
Level 10
Level 10

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.

Tom_Fought
Level 4
Level 4

I started to, but there are dependencies that are not satisfied for our primary bundle. So at the moment I have suspended that approach.

Tom_Fought
Level 4
Level 4

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.

dylanr46798176
Level 3
Level 3

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.

smacdonald2008
Level 10
Level 10

In your example - you are using it within a method that belongs to TestComponentImpl -- correct?

Tom_Fought
Level 4
Level 4

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.

Jörg_Hoh
Employee
Employee

Hi,

can you please share the code of your component? "main method" sounds a bit strange.

Jörg

Tom_Fought
Level 4
Level 4

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;

  }

}

Jörg_Hoh
Correct answer by
Employee
Employee

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

View solution in original post