AEM 6.4.x / OSGI / Servlet:如何从Servlet访问OSGI服务?

时间:2019-06-24 08:22:50

标签: osgi aem

II有一个servlet(例如,“ localhost:4502 / bin / my-servlet-here”),在这里我需要访问OSGI服务。

我已经尝试了一些在线上看到的东西,但是我无法从servlet获得对OSGI服务的访问/引用。

关于如何实现的任何想法?

在下面的代码servlet类中,我在IDE(IntelliJ)中进行调试,并且它在“ ServiceReference reference”开头的行中挂起/未响应。

谢谢


我的servlet类

package com.myhost.core.servlets;

import com.myhost.core.services.MyService;
import javax.annotation.Resource;
import javax.inject.Inject;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

@SlingServlet(paths = "/bin/myservlet", methods = "GET", metatype = true)
public class MyServlet extends SlingAllMethodsServlet {

    @Resource(name="BundleContext")
    private BundleContext context;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {

    ServiceReference reference = context.getServiceReference(MyService.class.getName());
    MyService service = (MyService)context.getService(reference);

    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/json;charset=UTF-8");

    // the code the populates the JSON variable has been taken out

    printWriter.write(jsonObject.toString());
}

我的服务等级

package com.myhost.core.services;

public interface MyService {
    String getPassword(String type);
}

我的服务类实现

package com.myhost.core.services.impl;

import com.myhost.core.services.MyService;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import java.util.Map;

@Service
@Component(metatype = true, label = "My Service Implementation")
public class MyServiceImpl implements MyService {    
    @Property(label = "property1")
    private static final String Property1 = "com.myhost.core.services.MyService.property1";
    private String property1;

    @Property(label = "property2")
    private static final String Property2 = "com.myhost.core.services.MyService.property2";
    private String property2;

    @Activate
    protected void activate(Map<String, Object> properties) {
        this.property1 = PropertiesUtil.toString(properties.get(Property1), null);
        this.property2 = PropertiesUtil.toString(properties.get(Property2), null);
    }

    @Override
    public String getProperty(int temp) {
        switch (temp) {
            case 1:
                return property1;
            case 2:
                return property2;
            default:
                return "";
        }
    }
}

4 个答案:

答案 0 :(得分:2)

您可以使用@Reference批注,felix会为您注入-

//MyServlet.class
.
.
@Reference
MyService service;
.
.

Here是供参考的示例。

答案 1 :(得分:2)

如果您使用的是AEM 6.3或更高版本,我建议您使用OSGI声明式服务。如果少于,则为SCR注释。 以下是使用声明性服务的代码段,我在6.3及更高版本中使用了

   //My sevlet Practice Servlet
@Component(service=Servlet.class,
property={
        Constants.SERVICE_DESCRIPTION + "=Practice Servlet",
        "sling.servlet.methods=" + HttpConstants.METHOD_GET,
        "sling.servlet.paths="+ "/bin/practice"
})


public class PracticeServlet extends SlingSafeMethodsServlet{

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Reference
    private PracticeService pracService;

我在上面的servlet中使用的服务类:PracticeService.java

public interface PracticeService {

    public void printLogs(String Name);
}

我的服务实现类:PracticeServiceImpl.java,它实现上述服务类。

import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import aemdemo.core.service.PracticeService;

    @Component(service=PracticeService.class)
    public class PracticeServiceImpl implements PracticeService{

        private Logger log = LoggerFactory.getLogger(this.getClass());

        @Override
        public void printLogs(String name) {

            log.debug("Inside service!!!!!"+name);

        }

    }

答案 2 :(得分:0)

您应该使用@Reference,但不能使用Felix SCR。改用本机OSGi注释。

import org.osgi.service.component.annotations.*;


@Reference
private ResourceResolverFactory factory;

felix注释现在处于维护模式...理想情况下,整个项目将在没有felix scr的情况下运行。 有关更多说明,请参见http://www.nateyolles.com/blog/2017/05/osgi-declarative-services-annotations-in-aem

答案 3 :(得分:0)

由于您使用的是AEM 6.4.x,因此建议您使用OSGi declarative service annotations而不是其他社区成员建议的Felix SCR注释。

要使用这些注释,我已经通过替换Felix SCR注释将您的代码转换为使用OSGi注释。

MyService.java

package org.redquark.aem.extensions.core.services;

public interface MyService {

    /**
     * This method returns the entered password into a hash equivalent with some
     * properties passed by the user
     * 
     * @param type
     * @return {@link String}
     */
    String getPassword(String type);
}

MyServiceImpl.java

package org.redquark.aem.extensions.core.services.impl;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.Designate;
import org.redquark.aem.extensions.core.config.MyConfiguration;
import org.redquark.aem.extensions.core.services.MyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(service = MyService.class, 
           property = {
                   "label=My Service Implementation"
                   }
        )
@Designate(ocd = MyConfiguration.class)
public class MyServiceImpl implements MyService {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    // Two properties to be read
    private String propertyOne;
    private String propertyTwo;

    @Activate
    protected void activate(MyConfiguration config) {
        // Reading properties from the configuration
        propertyOne = config.getPropertyOne();
        propertyTwo = config.getPropertyTwo();

    }

    @Override
    public String getPassword(String type) {

        // MD5 equivalent of password string
        String passwordHash = null;

        try {

            type = type + propertyOne + propertyTwo;

            log.info("Resulant password: " + type);

            // Convert string to bytes - this is for the sample implementation (for show casing)
            byte[] passwordByte = type.getBytes("UTF-8");

            // Getting instance of MessageDigest
            MessageDigest md = MessageDigest.getInstance("MD5");

            // Convert bytes array to hash using MD5 algorithm
            byte[] digest = md.digest(passwordByte);

            passwordHash = new String(digest);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return passwordHash;
    }

}

我们正在通过服务实现的Activate方法读取自定义属性。

SCR属性注释为您提供了很大的自由度。您可以在类顶部进行注释(使用 @Properties 注释作为带有嵌套的 @Property 注释的容器),也可以将各个常量值注释为属性。您可以在OSGI Web控制台中使它们可见(从技术上讲,您正在为它们创建一个元类型),也可以将它们标记为私有(未创建元类型)。

对于OSGI注释,这是不同的。

元类型属性在标记为 @ObjectClassDefinition 的专用配置类中处理。他们不能是私人的。 视为私有的属性将附加到 @Component 批注。它们无法再更改。

因此,要处理这些属性,我们将使用@ObjectClassDesfinition注释创建一个单独的接口,并且每个属性均使用@AttributeType注释进行注释。

MyConfiguration.java

package org.redquark.aem.extensions.core.config;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

@ObjectClassDefinition(name = "My Configuration", 
                       description = "This configuration will be used to read the value of properties.")
public @interface MyConfiguration {

    @AttributeDefinition(name = "Property One", description = "Read property one", type = AttributeType.STRING)
    public String getPropertyOne() default "Property One";

    @AttributeDefinition(name = "Property Two", description = "Read property two", type = AttributeType.STRING)
    public String getPropertyTwo() default "Property Two";
}

现在,终于有了您的servlet-

MyServlet.java

package org.redquark.aem.extensions.core.servlets;

import java.io.IOException;

import javax.servlet.Servlet;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.redquark.aem.extensions.core.services.MyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(service = Servlet.class, property = { "sling.servlet.methods=" + HttpConstants.METHOD_GET,
        "sling.servlet.paths=" + "/bin/myservlet" })
public class MyServlet extends SlingAllMethodsServlet {

    // Generated serialVersionUID
    private static final long serialVersionUID = -8720724011172847122L;

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    // Injecting reference of your service - No need to use BundleContext
    @Reference
    private MyService myService;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {

        try {

            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json;charset=UTF-8");

            // Calling the method implementation from your service
            String password = myService.getPassword("Sample Type");

            log.info("Writing password to the browser...");

            response.getWriter().write(password);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

出于演示目的,我自由创建了等效于密码的MD5哈希,该密码也取决于自定义属性(propertyOne和propertyTwo)。您可以在此处编写JSON实现。

您可以在此处使用Scheduler服务检查另一个示例-https://aem.redquark.org/2018/10/day-13-schedulers-in-aem.html

我希望这有助于解决您的问题。 编码愉快!干杯!