AEM 6.3 - ResourceResolverFactory在Service中为null,并在Sling Model类中抛出LoginException

时间:2017-10-19 04:14:19

标签: aem osgi-bundle sling

1)我试图在SlingModel类中注入ResourceResolverFactory,如下所示:

package com.aem.sites.models;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;

import org.apache.sling.api.resource.LoginException;
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.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aem.sites.services.WeatherService;


@Model(adaptables=Resource.class)
public class Banner {

    final static Logger logger = LoggerFactory.getLogger(Banner.class);

    @Inject
    private WeatherService weatherService;

    private String serviceEndpoint;

    private String apiKey;

    private String temperature;

    @Inject
    @Optional
    @Named("bannerText")
    private String bannerText;

    @Inject
    @Optional
    @Named("button1Text")
    private String button1Text;

    @Inject
    @Optional
    @Named("button2Text")
    private String button2Text;

     @Inject
    private ResourceResolverFactory resourceResolverFactory;

        @PostConstruct
        public void init() {
            serviceEndpoint = weatherService.getServiceEndpoint();
            apiKey = weatherService.getApiKey();
            temperature = weatherService.getTemperatureValue()+" "+weatherService.getUnit();
            checkTemperatureProperty();
        }


        public String getServiceEndpoint() {
            return serviceEndpoint;
        }

        public String getApiKey() {
            return apiKey;
        }


        public String getTemperature() {
            return temperature;
        }


        public String getBannerText() {
            return bannerText;
        }


        public String getButton1Text() {
            return button1Text;
        }


        public String getButton2Text() {
            return button2Text;
        }

        private void checkTemperatureProperty() {
            logger.info("**********************checkTemperatureProperty****************");
            Map<String, Object> param = new HashMap<String, Object>();
            param.put(ResourceResolverFactory.SUBSERVICE,"getResourceResolver");
            ResourceResolver resourceResolver = null;
            try {
                if(resourceResolverFactory == null) {
                    logger.info("***********************resourceResolverFactory is null******************************");
                }
                else {
                    resourceResolver = resourceResolverFactory.getServiceResourceResolver(param);
                    logger.info("**********************resource resolver id****************"+resourceResolver.getUserID());
                    //Resource resource = resourceResolver.getResource("/content/aemsite/en/jcr:content/root/responsivegrid/banner");
                    //ValueMap readMap = resource.getValueMap();
                    //logger.info(readMap.get("temperature", ""));
                }
            }
            catch (LoginException e) {
                logger.error("LoginException",e);
            } finally{
                if(resourceResolver != null && resourceResolver.isLive()){
                    resourceResolver.close();
                }
            }
        }

}

这里讨论的方法是checkTemperatureProperty()。我创建了如下所示的系统用户:

enter image description here

我还配置了Mapper服务修正案,如下所示:

enter image description here

捆绑包的符号名称如下所示:

enter image description here

ResourceResolverFactor注入在Sling Model类中抛出LoginException,这是错误:

com.aem.sites.models.Banner LoginException
org.apache.sling.api.resource.LoginException: Cannot derive user name for bundle org.apache.sling.models.impl [489] and sub service getResourceResolver
    at org.apache.sling.resourceresolver.impl.ResourceResolverFactoryImpl.getServiceResourceResolver(ResourceResolverFactoryImpl.java:86)

当我尝试使用@Reference在Service中使用ResourceResolverFactory时,它会抛出空指针异常。

下面给出了有问题的类,方法checkTemperatureProperty()第195行:

package com.aem.sites.services.impl;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Reference;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.metatype.annotations.Designate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aem.sites.interfaces.Configuration;
import com.aem.sites.pojos.CurrentConditions;
import com.aem.sites.services.WeatherService;
import com.google.gson.Gson;

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.api.resource.LoginException;


// TODO: Auto-generated Javadoc
/**
 * The Class WeatherServiceImpl.
 */
@Component(service = WeatherService.class,
immediate = true,
configurationPid = "com.aem.sites.services.impl.WeatherServiceImpl")
@Designate(ocd = Configuration.class)
public class WeatherServiceImpl implements WeatherService {

    /** The Constant logger. */
    final static Logger logger = LoggerFactory.getLogger(WeatherServiceImpl.class);

    /** The service endpoint. */
    private String serviceEndpoint;

    /** The api key. */
    private String apiKey;

    /** The response body. */
    private String responseBody;

    /** The temperature value. */
    private String temperatureValue;

    /** The unit. */
    private String unit;

    /** The resource resolver factory. */
    @Reference
    private ResourceResolverFactory resourceResolverFactory;

    /* (non-Javadoc)
     * @see com.aem.sites.services.WeatherService#getServiceEndpoint()
     */
    @Override
    public String getServiceEndpoint() {
        return serviceEndpoint;
    }

    /* (non-Javadoc)
     * @see com.aem.sites.services.WeatherService#getApiKey()
     */
    @Override
    public String getApiKey() {
        return apiKey;
    }

    /**
     * Activate.
     *
     * @param config the config
     */
    @Activate
    @Modified
    protected final void activate(Configuration config) {
        logger.info("**********************************************activate********************************************");
        serviceEndpoint = config.getServiceURL();
        apiKey = config.getApiKey();
        String serviceURL = createRequestURL();
        logger.info("**************************The serviceURL is*******************************************"+serviceURL);
        callWebService(serviceURL);
        String responseString = getResponseBody();
        logger.info("**************************The response body is*******************************************"+responseString);
        convertStringToPojos(responseString);
        checkTemperatureProperty();
        //saveTemperatureInTheNode();

    }

    /**
     * Creates the request URL.
     *
     * @return the string
     */
    private String createRequestURL() {
        StringBuilder sb = new StringBuilder(); ;
        if(!StringUtils.isEmpty(serviceEndpoint)) {
            sb.append(serviceEndpoint);
            sb.append("/currentconditions/v1/33785");
            sb.append("?apikey=");
            sb.append(apiKey);
        }
        return sb.toString();
    }

    /**
     * Call web service.
     *
     * @param serviceURL the service URL
     */
    private void callWebService(String serviceURL) {
        if(!StringUtils.isEmpty(serviceURL))  {
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpGet httpget = new HttpGet(serviceURL);
            CloseableHttpResponse response = null;
            try {
                response = httpclient.execute(httpget);
                HttpEntity entity = response.getEntity();
                int status = response.getStatusLine().getStatusCode();
                if (status >= 200 && status < 300) {
                    if (entity != null) {
                        String responseString = EntityUtils.toString(entity);
                        setResponseBody(responseString);
                    }
                }
                else {
                    logger.info("*********************Unexpected response status: " + status);
                }
            } catch (IOException | UnsupportedOperationException e) {
                // TODO Auto-generated catch block
                logger.info("***********************************inside catch block****************IOException"+e.getMessage());
            }
            finally {
                if(null != response){
                    try {
                        response.close();
                        httpclient.close();
                    } catch (IOException e) {
                        logger.info("***********************************inside finally block****************IOException"+e.getMessage());
                    }
                }
            }
        }
    }

    /**
     * Convert string to pojos.
     *
     * @param jsonString the json string
     */
    private void convertStringToPojos(String jsonString) {
        if(!StringUtils.isEmpty(jsonString))  {
            jsonString = jsonString.substring(1);
            if(!StringUtils.isEmpty(jsonString))  {
                int ind = jsonString.lastIndexOf("]");
                if(ind >= 0) {
                    jsonString = jsonString.substring(0,jsonString.length()-1);
                }
                Gson gson = new Gson();
                if(!StringUtils.isEmpty(jsonString))  {
                    CurrentConditions conditions = gson.fromJson(jsonString, CurrentConditions.class);
                    logger.info("***************current temperature is*****************"+conditions.getTemperature().getImperial().getValue());
                    temperatureValue = conditions.getTemperature().getImperial().getValue();
                    unit = conditions.getTemperature().getImperial().getUnit();
                }
            }
        }
    }


    /**
     * Save temperature in the node.
     */
    private void checkTemperatureProperty() {
        logger.info("**********************checkTemperatureProperty****************");
        Map<String, Object> param = new HashMap<String, Object>();
        param.put(ResourceResolverFactory.SUBSERVICE,"getResourceResolver");
        ResourceResolver resourceResolver = null;
        try {
            resourceResolver = resourceResolverFactory.getServiceResourceResolver(param);
            logger.info("**********************resource resolver id****************"+resourceResolver.getUserID());
            Resource resource = resourceResolver.getResource("/content/aemsite/en/jcr:content/root/responsivegrid/banner");
            ValueMap readMap = resource.getValueMap();
            logger.info(readMap.get("temperature", ""));
        }
        catch (LoginException e) {
            logger.error("LoginException",e);
        } finally{
            if(resourceResolver != null && resourceResolver.isLive()){
                resourceResolver.close();
            }
        }
    }

    private void saveTemperatureProperty() {

    }

    /**
     * Gets the response body.
     *
     * @return the response body
     */
    public String getResponseBody() {
        return responseBody;
    }

    /**
     * Sets the response body.
     *
     * @param responseBody the new response body
     */
    public void setResponseBody(String responseBody) {
        this.responseBody = responseBody;
    }

    /* (non-Javadoc)
     * @see com.aem.sites.services.WeatherService#getTemperatureValue()
     */
    @Override
    public String getTemperatureValue() {
        // TODO Auto-generated method stub
        return temperatureValue;
    }

    /* (non-Javadoc)
     * @see com.aem.sites.services.WeatherService#getUnit()
     */
    @Override
    public String getUnit() {
        // TODO Auto-generated method stub
        return unit;
    }

    /**
     * Deactivate.
     */
    @Deactivate
    protected void deactivate() {
    }
}

我首先尝试在服务类(第二类)中使用ResourceResolverFactory,然后在Banner.java(第一类)中使用。但它既没有效果。

我已经完成了各种教程以及在stackoverflow上提出的类似问题。其中一些人在这里:

ResourceResolverFactory getServiceResourceResolver throws Exception in AEM 6.1

ResourceResolverFactory and SlingRepository null in Service class

ResourceResolverFactory is NULL (Adobe Experience Manager AEM)

并完全遵循它但无法找到解决方案。任何帮助表示赞赏。

提前致谢。

1 个答案:

答案 0 :(得分:1)

  

我看到您正在使用OSGI声明性服务(DS)

一些事情:

  1. 如果您使用SCR注释,则应从POM中删除SCR依赖关系以消除混淆。
  2. 如果您仅使用OSGI DS,则必须具备以下条件:
    • 阅读Nate Yolles的优秀post
    • 您的maven-bundle-plugin依赖项必须是3.2.0或更高版本
    • 您必须在包org.osgi.service.component.annotations中使用注释,org.apache.felix.scr.annotations.Reference中的SCR注释
  3. 在你的气象服务中,我发现你使用的是SCR @Reference而不是OSGI的@Reference

    在吊索模型中 您应该使用OSGI服务注入器来获取服务:@OSGiService 尽管使用@Inject工作得很好,但是特定的注入器对于可读性和性能更好,尽管不显着,因为我们只使用特定的注射器

    以下是使用您的部分代码的服务示例:

    气象服务界面:

    package com.aem.sites.services;
    
    public interface WeatherService
    {
      public String checkApps();
    
    }
    

    天气服务impl:

    package com.aem.sites.services.impl;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.felix.scr.annotations.Reference;
    import org.osgi.service.component.annotations.Activate;
    import org.osgi.service.component.annotations.Component;
    import org.osgi.service.component.annotations.Deactivate;
    import org.osgi.service.component.annotations.Modified;
    import org.osgi.service.metatype.annotations.Designate;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.aem.sites.services.Configuration;
    import com.aem.sites.services.WeatherService;
    
    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.LoginException;
    
    
    
    /**
     * The Class WeatherServiceImpl.
     */
    @Component(service = WeatherService.class,
            immediate = true,
            configurationPid = "com.aem.sites.services.impl.WeatherServiceImpl")
    @Designate(ocd = Configuration.class)
    public class WeatherServiceImpl implements WeatherService {
    
      /** The Constant logger. */
      final static Logger logger = LoggerFactory.getLogger(WeatherServiceImpl.class);
    
    
      /** The resource resolver factory. */
      @Reference
      private ResourceResolverFactory resourceResolverFactory;
    
      private ResourceResolver resolver;
    
    
      /**
       * Activate.
       *
       * @param config the config
       */
      @Activate
      @Modified
      protected final void activate(Configuration config) {}
    
    
    
      /**
       * check if we can get /apps resource, print weather it's null or not
       */
      public String checkApps() {
        logger.info("*************** checkApps");
        Map<String, Object> param = new HashMap<String, Object>();
        param.put(ResourceResolverFactory.SUBSERVICE,"getResourceResolver");
        ResourceResolver resourceResolver = null;
        try
        {
          resourceResolver = resourceResolverFactory.getServiceResourceResolver(param);
          logger.info("*************** resource resolver user id: "+resourceResolver.getUserID());
          Resource appsResource = resourceResolver.getResource("/apps");
    
          // return appropriate msg
          return appsResource == null
                 ? "apps resource is null"
                 : "apps resource is NOT null";
    
        }
        catch (LoginException e)
        {
          logger.error("LoginException",e);
          return e.toString();
        }
        finally
        {
          if(resourceResolver != null && resourceResolver.isLive()){
            resourceResolver.close();
          }
        }
    
      }
      /**
       * Deactivate.
       */
      @Deactivate
      protected void deactivate() {
      }
    }
    

    横幅模型:

    package com.aem.sites.models;
    
    import javax.annotation.PostConstruct;
    
    import org.apache.sling.api.resource.Resource;
    import org.apache.sling.models.annotations.Model;
    import org.apache.sling.models.annotations.injectorspecific.OSGiService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.aem.sites.services.WeatherService;
    
    
    @Model(adaptables=Resource.class)
    public class Banner {
    
      final static Logger logger = LoggerFactory.getLogger(Banner.class);
    
      @OSGiService
      private WeatherService weatherService;
    
      private String msg;
    
      @PostConstruct
      public void init() {
        msg = weatherService.checkApps();
      }
    
      public String getMsg() {
        return msg;
      }
    
    }
    

    显示消息的简单组件:

    <h1 data-sly-use.banner="com.aem.sites.models.Banner">${banner.msg}</h1>

    更新:关于在吊索模型中使用resourceResolver:

      

    最好在单独的服务中保留不使用模型的resource / resourceResolver的逻辑。在您的代码中,Banner#checkTemperatureProperty应该在服务中而不在模型本身中。

    这是我个人的观点,这里没有对错:

    您始终可以通过注入资源或请求,然后从资源/请求中获取解析程序来获取sling模型中的resourceResolver。在任何一种情况下,您都将获得与请求用户具有相同权限的resourceResolver,这是组件的首选。例如,如果您需要从同一页面上的/或内容中的其他组件获取资源,这是可行的方法。

    如果您有需要执行操作的用例,请求用户或匿名用户没有足够的权限来执行操作,也不想授予他们权限,您可以通过具有足够权限的系统用户获取resourceResolver 。例如,你想从/ apps中读取一些属性,或者你想开始工作流......等等。在这种情况下,将这些代码保存在服务中而不是模型本身更有条理,并且可能会推广这样你就可以在其他模型中重复使用它。