AEM 6.4.x / OSGI / Servlet: как получить доступ к сервису OSGI из сервлета? - PullRequest
0 голосов
/ 24 июня 2019

У меня есть сервлет (например, localhost: 4502 / bin / my-servlet-here), где мне нужно было бы получить доступ к службе OSGI.

Я пробовал несколько вещей, которые видел в Интернете, но не могу получить доступ / ссылку на службу OSGI из моего сервлета.

Есть идеи, как это можно сделать?

В приведенном ниже классе сервлета кода я отлаживал в своей среде IDE (IntelliJ), и он зависает / не отвечает в строке, начинающейся с «Ссылка на ServiceReference»

Спасибо


мой класс сервлетов

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 ]

2 голосов
/ 24 июня 2019

Если вы используете 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;

Мой класс обслуживания: 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 голосов
/ 24 июня 2019

Вы можете использовать @Reference аннотацию, и Феликс сделает это за вас -

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

Здесь является примером для справки.

0 голосов
/ 26 июня 2019

Поскольку вы работаете с AEM 6.4.x, я бы предложил использовать декларативные аннотации службы OSGi вместо аннотаций Felix SCR, как предлагали другие члены сообщества.

Чтобы использовать эти аннотации, я преобразовал ваш код в аннотации OSGi, заменив аннотации Felix SCR.

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;
    }

}

Мы читаем наши пользовательские свойства в методе активации активации сервиса.

Аннотации свойств SCR дают вам большую свободу. Вы можете комментировать их в верхней части класса (используя аннотацию @ Properties в качестве контейнера с вложенными аннотациями @ Property ), вы можете аннотировать отдельные постоянные значения в качестве свойств. Вы можете сделать их видимыми в веб-консоли OSGI (технически вы создаете для них метатип) или можете пометить их как частные (метатип не создается).

С аннотациями 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";
}

Теперь наконец-то приходит ваш сервлет -

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 здесь.

Вы можете проверить другой пример с помощью службы планировщика здесь - https://aem.redquark.org/2018/10/day-13-schedulers-in-aem.html

Надеюсь, это поможет решить вашу проблему. Удачного кодирования! Ура!

0 голосов
/ 25 июня 2019

Вы должны использовать @Reference, но не из Felix SCR.Вместо этого используйте собственные аннотации OSGi.

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


@Reference
private ResourceResolverFactory factory;

Аннотации Феликса теперь находятся в режиме обслуживания ... В идеале весь ваш проект будет работать без Felix SCR.См. http://www.nateyolles.com/blog/2017/05/osgi-declarative-services-annotations-in-aem для дальнейших объяснений.

...