@Reference annotation not working | Community
Skip to main content
New Participant
February 13, 2018
Solved

@Reference annotation not working

  • February 13, 2018
  • 22 replies
  • 11318 views

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;

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by joerghoh

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

22 replies

New Participant
February 15, 2018

Thanks for all your assistance. This has help significantly!

New Participant
February 15, 2018

Seems like I was right with my suggestion! Hopefully you can resolve this issue now by actually referencing the ReadService you referenced the DataSourceLookup!

smacdonald2008
New Participant
February 14, 2018

Great pick up Joerg!

joerghoh
joerghohAccepted solution
Employee
February 14, 2018

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

New Participant
February 14, 2018

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;

  }

}

joerghoh
Employee
February 14, 2018

Hi,

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

Jörg

New Participant
February 14, 2018

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.

smacdonald2008
New Participant
February 14, 2018

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

New Participant
February 14, 2018

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.

New Participant
February 14, 2018

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.