2 Replies Latest reply on Mar 15, 2016 3:32 PM by mauriclaudio

    Exposing a specific interface implementation as RESTFul web service.

    mauriclaudio

      Enviroment: Wildfly 10 Final with JDK 1.8 upd 73

       

      I was able without any effort to expose an EJB local interface as a RESTFul web service, just for playing a while with REST:

       

      import javax.ejb.Local;
      import javax.ws.rs.GET;
      import javax.ws.rs.Path;
      import javax.ws.rs.core.MediaType;
      @Local
      @Path("/myrest")
      public interface ICommon {
        @GET
        @Path("/greeting")
        @javax.ws.rs.Produces(MediaType.APPLICATION_JSON)
        public String getGreetings();
      }
      
      

       

      Above interface is implemented by two different EJBs, namely FirstBean and SecondBean. Publishing of the RESTFul interface is done by "triggering" automatic discovery of RESTFul annotated class, simply creating a simple @Singleton EJB which in turn extends Application:

      @Singleton
      public class RESTActivator extends Application {
      
      }
      
      

       

      with no further configuration. Now, when I try to access to RESTFul URL, I can verify that Wildfly actually exposes ICommon as implemented by FirstBean. In my case, since I have different implementations, I wonder if there is a way to let the container know which specific implementation must be exposed.

      Is that possible ?

       

      Thanks a lot for your help.

        • 1. Re: Exposing a specific interface implementation as RESTFul web service.
          emag

          IMO, I think it's preferable delegating injected service classes to several JAX-RS endpoint itself implementations.

           

          import javax.inject.Inject;
          
          @Path("/some-api")
          public class SomeApi {
          
            @Inject
            private SomeBean someBean; // Via @javax.enterprise.inject.Produces
          
            @GET
            public String doSomething() {
              return someBean.doSomething();
            }
          
          }
          
          

           

          However, (though I'm not sure it's the best way), it works the following way. You can switch the specific implementation using System property at runtime.

           

          import javax.ws.rs.ApplicationPath;
          import javax.ws.rs.core.Application;
          import java.util.HashSet;
          import java.util.Set;
          
          @ApplicationPath("/")
          public class RESTActivator extends Application {
          
            private Set<Object> singletons = new HashSet<>();
            private Set<Class<?>> empty = new HashSet<>();
          
            public RESTActivator() {
              boolean useSecond = Boolean.parseBoolean(System.getProperty("use.second", "false"));
          
              if (useSecond) {
                singletons.add(new SecondBean());
              } else {
                singletons.add(new FirstBean());
              }
            }
          
            @Override
          
            public Set<Class<?>> getClasses() {
              return empty;
            }
          
            @Override
            public Set<Object> getSingletons() {
              return singletons;
            }
          
          }
          
          

           

          I created the sample repository.

           

          GitHub - emag/jboss-developer-268492: https://developer.jboss.org/thread/268492

          • 2. Re: Exposing a specific interface implementation as RESTFul web service.
            mauriclaudio

            Hi Yoshimasa,

             

            first of all, thanks really a lot for your time and the code you shared on GitHub. It works really well, but I'm afraid you missed a detail: my question was about EJBs, not POJOs . With EJBs as far as I experimented using  javax.ws.rs.core.Application getClasses() or getSingletons() methods to expose REST resource doesn't work. After reading in depth RestEasy documentation, eventually I found a way to achieve my goal - i.e, select which implementation to use when multiple implementations are available.

             

            The key of mine solution is to use REST sub resources locators. First, let's define a business interface implemented by two ejbs:

             

            package com.rest.test;
            
            import javax.ejb.Local;
            import javax.naming.InitialContext;
            import javax.ws.rs.GET;
            import javax.ws.rs.Path;
            
            @Local
            @Path("/commonrest")
            public interface CommonRestIntf {
            
              @Path("/processor")
              default public CommonRestIntf getProcessor() {
              try {
                   InitialContext ctx = new InitialContext();
                   String actualJNDIName = ...; // select here somehow which ejb to use
                   CommonRestIntf intf = (CommonRestIntf) ctx.lookup(actualJNDIName);
                   return intf;
              }
              catch(Exception e) {
                   return null;
                   }
              }
            
              @GET
              @Path("/greetings")
              public String getGreetings();
            }
            

             

            Please note that I define a default implementation of the method getProcessor() that is responsable for locating and initializing the actual ejb I want to use. This method is annoted with @Path but misses any @GET, @POST annotations - as far as I understand this is the way that lets you to define a subresource locator method.

             

            Hence, I defined two simple EJBs:

             

            @Stateless
            public class FirstBean implements CommonRestIntf {
              public AlfaBean() {
                  // TODO Auto-generated constructor stub
              }
              @Override
              public String getGreetings() {
              return "Returned by FirstBean";
              }
            }
            

            and

             

            @Stateless
            public class SecondBean implements CommonRestIntf {
              public SecondBean() {
                  // TODO Auto-generated constructor stub
              }
              @Override
              public String getGreetings() {
              return "Returned by SecondBean";
              }
            }
            

             

            As last step, I defined a Singleton EJB to initialize REST services:

             

            @Singleton
            @Startup
            @ApplicationPath("/ejbrest")
            public class StarterREST extends Application {
               /**
                 * Default constructor. 
                 */
                public StarterREST() {
                    // TODO Auto-generated constructor stub
                }
            }
            

             

            To access RESTFul webservice, you may type in a browser : http://localhost:port/WebAppCTX/ejbrest/commonrest/processor/greetings.

             

            Again, thanks so much for your help. I have really appreciated it.

            All the best !