Pergunta

I am developing an application that dynamically load JAX resources in a OSGI enviroment. These resources are managed by Guice , in each Bundle and these are loaded into a JAX application that runs on a core bundle.

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

context.reload(cfg);

where context is a Jersey ServletContext managed by Guice.

All this works perfectly .         The problem occurs because we want manipulate the path when the resources are loaded. Then, we create our 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();
}

The error is that all dependencies injected into the resource can not be handled. By example: if resource has inject a Date (@Inject Date date) the error is the follow:

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]

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

I think the error is that the new instance (Resource r1) is handled by H2K and not by Guice and can not satisfy your dependencies.

We tried to use in OSGI enviroment the guice-bridge artifact, but this gives an error: not found an implementation of ServiceLocator.

But all dependencies are in the classpath:

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> 

So, any idea how to change the path of resource managed by guice, if the solution is to use guice-bridge, which is the best way to configure it?

I'm using jersey 2.4.

Thanks

Foi útil?

Solução

The solution I found (if not the best), is to define a CustomServletContext and use the guice-bridge artifact, following references issue HK2-121 in jersey issue tracker. The solution:

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

By example: My resources look like this:

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

The method:

     @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();
     }

Make changes in the path of the resource, recreates the instance and everything stays injected...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top