Джерси и ресурсы под управлением Guice

Я разрабатываю приложение, которое динамически загружает ресурсы JAX в среде OSGI. Этими ресурсами управляет Guice в каждом пакете, и они загружаются в приложение JAX, которое работает в основном пакете.

ResourceConfig cfg = new ResourceConfig(context.getConfiguration());
for (Provider<?> r : kb.getResources()) {
  if (!cfg.isRegistered(r.get())) {
    cfg.registerInstances(r.get());
  }
}

context.reload(cfg);

где контекст — это сервлетконтекст Джерси, которым управляет Guice.

Все это прекрасно работает. Проблема возникает из-за того, что мы хотим манипулировать путем при загрузке ресурсов. Затем мы создаем наш ModelProcesor.

@Override
public ResourceModel processResourceModel(ResourceModel resourceModel, Configuration configuration) {
    logger.info(actualKrundle.getName());
    ResourceModel.Builder newResourceModelBuilder = new ResourceModel.Builder(false);

    for (final Provider<?> r : actualKrundle.getResources()) {
        String name = r.get().getClass().getCanonicalName();
        List<Resource> resources = resourceModel.getResources();
        for (final Resource resource : resources) {
            if (resource.getName().endsWith(name)){
               final Resource.Builder resourceBuilder = Resource.builder(resource);
               //add the bundle name to resource path
               resourceBuilder.path(actualKrundle.getName()+"/"+resource.getPath());

               Resource r1 = resourceBuilder.build();
               newResourceModelBuilder.addResource(r1);
               break;
            }
        }
    }
    return newResourceModelBuilder.build();
}

Ошибка в том, что все зависимости, внедренные в ресурс, не могут быть обработаны. Например: если ресурс внедрил дату (@Inject Date date), ошибка будет следующей:

A MultiException has 1 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=Date,parent=ResourceFinder,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,23999364)

        at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)[261:org.glassfish.hk2.locator:2.2.0.b21]
        at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:803)[261:org.glassfish.hk2.locator:2.2.0.b21]
        at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:832)[261:org.glassfish.hk2.locator:2.2.0.b21]
        at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:822)[261:org.glassfish.hk2.locator:2.2.0.b21]

.... .... ....

Я думаю, что ошибка в том, что новый экземпляр (ресурс r1) обрабатывается H2K, а не Guice, и не может удовлетворить ваши зависимости.

Мы пытались использовать в среде OSGI артефакт guice-bridge, но это выдает ошибку: не найдена реализация ServiceLocator.

Но все зависимости находятся в пути к классам:

karaf@root> la | grep HK2
[ 260] [Active     ] [            ] [   30] HK2 API module (2.2.0.b21)
[ 262] [Active     ] [            ] [   30] HK2 Implementation Utilities (2.2.0.b21)
[ 283] [Active     ] [            ] [   30] HK2 Guice Bridge (2.1.96)
karaf@root> la | grep ServiceLo
[ 261] [Active     ] [            ] [   30] ServiceLocator Default Implementation (2.2.0.b21)
karaf@root> 

Итак, есть идеи, как изменить путь к ресурсу, управляемому guice, если решение состоит в использовании guice-bridge, как лучше всего его настроить?

Я использую майку 2.4.

Спасибо


person Cristian Rinaldi    schedule 08.11.2013    source источник


Ответы (1)


Решение, которое я нашел (если не лучшее), состоит в том, чтобы определить CustomServletContext и использовать артефакт guice-bridge, следуя проблемам ссылок HK2-121 в отслеживании выпусков джерси. Решение:

 public class KratosServletContainer extends ServletContainer {

     private Injector injector;

     @Inject
    KratosServletContainer(Injector injector, ResourceConfig configuration) {
         super(configuration);
         this.injector = injector;
     }

     @Override
     protected void init(WebConfig webConfig) throws ServletException {
         super.init(webConfig);

         ServiceLocator locator;
         try {
             Field webComponentField = getClass().getSuperclass()
                     .getDeclaredField("webComponent");

             webComponentField.setAccessible(true);
             WebComponent webComponent = (WebComponent) webComponentField.get(this);

             Field appHandlerField = webComponent.getClass().getDeclaredField("appHandler");
             appHandlerField.setAccessible(true);
             ApplicationHandler appHandler = (ApplicationHandler) appHandlerField.get(webComponent);
             locator = appHandler.getServiceLocator();

         } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | llegalAccessException e) {
             throw new RuntimeException(e);
         }

         GuiceBridge.getGuiceBridge().initializeGuiceBridge(
                 locator);

         GuiceIntoHK2Bridge guiceBridge = locator
                 .getService(GuiceIntoHK2Bridge.class);
         guiceBridge.bridgeGuiceInjector(injector);
     } 
}

Например: Мои ресурсы выглядят так:

@Path("resource") 
public class ResourceFinder {

     private static final Logger logger = Logger.getLogger(ResourceFinder.class.getName());

     private Date date;

     private final PersistenceManagerService pm;

     @Inject
     public ResourceFinder(Date date, PersistenceManagerService pm) {
         this.date = date;
         this.pm = pm;   
     }

     @GET
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/suma/{value1}/{value2}")
     @PermitAll
     public String getSuma(@PathParam("value1") int value1,
             @PathParam("value2") int value2) {

         User user = new User();

         user.setName("cacho" + value1);



         pm.get().makePersistent(user);

         pm.get().flush();

         //date was injected by guice
         //pm was injected by guice

         return String.valueOf(value1 + value2 + "   "+pm.get()+" "+date);
     } 
}

Метод:

     @Override
     public ResourceModel processResourceModel(ResourceModel resourceModel, Configuration configuration) {
         logger.info(actualKrundle.getName());
         ResourceModel.Builder newResourceModelBuilder = new ResourceModel.Builder(false);

         for (final Provider<?> r : actualKrundle.getResources()) {
             String name = r.get().getClass().getCanonicalName();
             List<Resource> resources = resourceModel.getResources();
             for (final Resource resource : resources) {
                 if (resource.getName().endsWith(name)){
                    final Resource.Builder resourceBuilder = Resource.builder(resource);
                    resourceBuilder.path(actualKrundle.getName()+"/"+resource.getPath());
                    Resource r1 = resourceBuilder.build();
                    newResourceModelBuilder.addResource(r1);
                    break;
                 }
             }
         }
         return newResourceModelBuilder.build();
     }

Внесите изменения в путь к ресурсу, воссоздайте экземпляр, и все останется вставленным...

person Cristian Rinaldi    schedule 08.11.2013