4 Replies Latest reply on Jan 6, 2014 9:56 PM by chaluwa

    Client Not Getting CDI Event From Server

    chaluwa

      I am building a code structure that I think will simplify my app, but now some things stopped working. My client no longer seems to get CDI events from the server and I cannot tell if the problem is with the client or server setup.

      Server Setup ::

      
      public interface RESTService<T>{           // in shared package
      
        @POST
        @Path("/add")
        @Consumes("application/json")
        @Produces("application/json")
        public T add(T entity);
      
        @GET
        @Path("/delete/{id:[0-9][0-9]*}")
        @Produces("application/json")
        public Response delete(@PathParam("id") Long id);
      
        ....
      }
      
      
      @Dependent
      public class CRUD<T>{           // in server package
        @Inject
        private Logger log;
      
      
        @Inject
        protected EntityManager em;
      
      
        @Inject
        private UserTransaction tnx;
      
        protected Class<T> clz;
        protected String clzName;
      
        public CRUD() {
             super();
        }
      
        public CRUD(Class<T> clz) {
             this.clz = clz;
             this.clzName = this.clz.getSimpleName();
        }
      
        protected T createEntity(T entity){
             log.severe("call to create " + this.clzName);
             try {
                  tnx.begin();
                  entity = em.merge(entity);
                  tnx.commit();
             } catch (Exception ex) {
                  ex.printStackTrace();
             }
             log.severe("created - " + this.clzName + ", returning call ...");
             return entity;
        }
      
        protected boolean deleteEntity(Long id){
             log.severe("call to delete " + this.clzName + " @ " + id);
             boolean status = false;
             try {
                  tnx.begin();
                  T entity = em.find(this.clz, id);
                  if(entity != null){
                       log.severe("found " + this.clzName + ", deleting it ... ");
                       em.remove(entity);
                  }
                  tnx.commit();
                  status = true;
             } catch (Exception ex) {
                  ex.printStackTrace();
             }
      
             String str = (status == true ? "deleted - " : "cold not delete - ");
             log.severe( str + this.clzName + " @ " + id + ", returning call ...");
             return status;
        }
      
        ...
      }
      
      
      // the next @Dependent class abstracts the base / common code from all
      // classes that will implement the jax-rs interface to provide
      // server-side functionality. M is the entity type and D is a CDI event type, fired when entity of type M is deleted.
      // Watch the CDI events fired in add() and delete() methods, they are somehow missed by the client ???
      
      
      @Dependent
      public class BaseEndpoint<M, D extends DeleteEvent> extends CRUD<M> implements RESTService<M> {      // in server package
      
        @Inject
        protected Logger log;
      
        @Inject @New
        protected Event<M> entityAdded;           // fired when entity M is created and persisted
      
      
        @Inject
        protected Event<D> entityDeleted;           // fired when entity M is deleted;
      
      
        public BaseEndpoint() {
             super();
        }
      
        public BaseEndpoint(Class<M> clz) {
             super(clz);
        }
      
        protected D getDeleteEventObject(){
             return null;          // subclass to return instance of delete event type. need a better way.
        }
      
      
        @Override
        public M add(M entity) {                     // defined in RESTService<M>
             log.severe("lets add " + clzName + " - " + entity);
             entity = createEntity(entity);
             entityAdded.fire(entity); // not seen by client ???
             log.severe("added " + entity + " and fired CDI event, returning call");
             return entity;
        }
      
      
        @Override
        public Response delete(Long id) {           // defined in RESTService<M>
             log.severe("lets delete " + clzName + " @ " + id);
             boolean status = deleteEntity(id);
             log.severe("deleted " + clzName + " @ " + id);
             if(status){
                  D d = getDeleteEventObject();
                  if(d != null){
                       d.setEntityId(id);
                       entityDeleted.fire(d); // not seen by client ???
                       log.severe("fired delete CDI event for " + clzName + " @ " + id);
                  }
                  return Response.ok().build();
             }
             return Response.serverError().build();
        }
      
      
      }
      
      
      // jax-rs sub-interface for "domain" specific actions if any
      
      
      @Path("/putme/bundles")
      public interface PutmeSubjectBundlesService extends RESTService<PutmeSubjectBundle> {      // in shared package
      
      }
      
      
      // And now, the "server" implementation, similar in role to UserComplaintEndpointImpl from errai-tutorial demo
      // PutmeSubjectBundle is the entity type and BundleDelete is the @Portable CDI event object type that gets
      // fired when a PutmeSubjectBundle object is deleted. PutmeSubjectBundle is a simple default-constructable @Portable @Bindable @Entity
      // and BundleDelete is a default-constructable @Portable pojo. All very simple and clear ...
      
      
      @RequestScoped
      public class PutmeSubjectBundlesEndpoint extends BaseEndpoint<PutmeSubjectBundle, BundleDelete> implements PutmeSubjectBundlesService {
        public PutmeSubjectBundlesEndpoint() {
             super(PutmeSubjectBundle.class);
        }
      
      
        @Override
        protected BundleDelete getDeleteEventObject() { // give BaseEndpoint BundleDelete instance to fire
             return new BundleDelete();
        }
      }
      
      
      
      
      

      On the server, PutmeSubjectBundlesEndpoint can now effortless add and delete entities by extending BaseEndpoint. Only problem is that CDI events fired by the super-class BaseEndpoint, are "not getting" to the clients ?? Lets look at the client side code now.

       

      @ApplicationScoped
      @SuppressWarnings({"unused", "deprecation"})
      public class PutmeBundlesPresenter{
      
      
        public interface PutmeBundlesDisplay{
             ....
        }
           
        @Inject
        private Caller<PutmeSubjectBundlesService> endpoint; // recall PutmeSubjectBundlesService above ??
      
        @Inject
        private PutmeBundlesView display; // the @Template @Page UI
      
        public PutmeBundlesPresenter() {
             super();
        }
      
        ...
      
        private void onAdd(@Observes @New PutmeSubjectBundle added){
             LogUtil.log("added bundle"); // never gets called ???
        }
      
        private void onDelete(@Observes BundleDelete evt){
             LogUtil.log("deleted bundle"); // never gets called ???
        }
      
      }
      
      
        • 1. Re: Client Not Getting CDI Event From Server
          mbarkley

          Hi Charles,

           

          Can you check if the bus is subscribing to the correct event type? To do so, run your app with chrome's developer tools open. In the "Network" tab, look for a with CommandType: "RemoteSubscribe" and with BeanType matching the event type for the observer.

          • 2. Re: Client Not Getting CDI Event From Server
            chaluwa

            Max Barkley wrote:

             

            Hi Charles,

             

            Can you check if the bus is subscribing to the correct event type? To do so, run your app with chrome's developer tools open. In the "Network" tab, look for a with CommandType: "RemoteSubscribe" and with BeanType matching the event type for the observer.

            Thanks for this, but I have not been able to follow your instructions with the Network tab in chrome dev tools. I was able to see the request go out and the response come back, inspected the headers and saw something like EncodingType but no CommandType in the response string. Pls kindly clarify.

            • 3. Re: Re: Client Not Getting CDI Event From Server
              mbarkley

              Hey Charles,

               

              There will be several messages sent by the bus while it's connecting. What you should be looking for specifically is something like what I've outlined in the attached image. This message should be sent for a type when a client-side observer is created for that type. So with an @ApplicationScoped observer, it should be sent fairly early.

              • 4. Re: Client Not Getting CDI Event From Server
                chaluwa

                Thanks. I was able to confirm that the "bus is subscribing to the correct event type", as shown in the attached picture. However, the client still does not seem to receive any of the "subscribed" events which are BundleDelete (without qualifiers), PutmeSubjectBundle (qualified with New), and PutmeSubjectBundle (qualified with Edit).

                Screenshot from 2014-01-07 03:34:32.png