22 Replies Latest reply on Feb 15, 2018 7:30 AM by Tom Fought

    @Reference annotation not working

    Tom Fought Level 1

      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. Re: @Reference annotation not working
          smacdonald2008 Adobe Employee

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

          • 2. Re: @Reference annotation not working
            smacdonald2008 Adobe Employee

            I have personally never used the extra syntax you have:

             

            ( policy = ReferencePolicy.STATIC )

            • 3. Re: @Reference annotation not working
              Tom Fought Level 1

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

              • 4. Re: @Reference annotation not working
                smacdonald2008 Adobe Employee

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

                • 5. Re: @Reference annotation not working
                  Jörg Hoh Adobe Employee

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

                   

                  Jörg

                  • 6. Re: @Reference annotation not working
                    Tom Fought Level 1

                    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)"]
                    • 7. Re: @Reference annotation not working
                      Jörg Hoh Adobe Employee

                      Ok, how does the code look you are using?

                       

                      Jörg

                      • 8. Re: @Reference annotation not working
                        Hemant arora Level 3

                        Please share logs

                        • 9. Re: @Reference annotation not working
                          dylanr46798176 Level 1

                          ReferencePolicy.STATIC is the default policy for any referenced service

                          • 10. Re: @Reference annotation not working
                            Tom Fought Level 1

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

                            • 11. Re: @Reference annotation not working
                              smacdonald2008 Adobe Employee

                              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.

                              • 12. Re: @Reference annotation not working
                                Tom Fought Level 1

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

                                • 13. Re: @Reference annotation not working
                                  Tom Fought Level 1

                                  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.

                                  • 14. Re: @Reference annotation not working
                                    dylanr46798176 Level 1

                                    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.

                                    • 15. Re: @Reference annotation not working
                                      smacdonald2008 Adobe Employee

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

                                      • 16. Re: @Reference annotation not working
                                        Tom Fought Level 1

                                        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.

                                        • 17. Re: @Reference annotation not working
                                          Jörg Hoh Adobe Employee

                                          Hi,

                                           

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

                                           

                                          Jörg

                                          • 18. Re: @Reference annotation not working
                                            Tom Fought Level 1

                                            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/particip ant.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;

                                              }

                                            }

                                            • 19. Re: @Reference annotation not working
                                              Jörg Hoh Adobe 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

                                              1 person found this helpful
                                              • 20. Re: @Reference annotation not working
                                                smacdonald2008 Adobe Employee

                                                Great pick up Joerg!

                                                • 21. Re: @Reference annotation not working
                                                  dylanr46798176 Level 1

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

                                                  • 22. Re: @Reference annotation not working
                                                    Tom Fought Level 1

                                                    Thanks for all your assistance. This has help significantly!