Loading deck

Ocelotds.org

The way between java and javascript

@hhfrancois

Ocelotds.org

Francois Achache

Senior sofware engineer


Java EE Architect


Lead on ocelotds

 

@hhfrancois

Ocelotds.org

Abstract

  • What is ocelotds ?
  • Why ocelotds ?
    • How to concact backend from frontend ?
    • Without ocelotds
    • With ocelotds
  • How that's work
  • Additional features
    • Cache on frontend
    • Topic/channel
  • Extends Ocelotds  : SPI
  • Questions ?

Ocelotds.org

What is Ocelotds ?

A Java framework to facilitate communication between
java web apps and HTML/javascript frontend

It is especialy design for Java EE application.
It is mainly based on CDI and Websocket

Compatible with Java EE 7 Servers

Compatible with major recent browsers

Ocelotds.org

WEB 1.0 : HTML(JSP/Servlet)

Iframe hidden + XML/HTML <=> Servlets/Jsp

XMLHttpRequest + XML/HTML <=> Servlets

WEB 2.0 : AJAX + HTML + JS + DOM

AJAX + XML/HTML/Json <=> Servlets/Jsp

WEB 2.5 HTML5

XMLHttpRequest + Json <=> REST

WEB 3.0 Semantic Web

Web communications story

Ocelotds.org

How to contact the backend from the frontend ?

  • 1st, you write you business layer
  • 2nd, you have to write REST resources for expose services
  • 3rd, in your UI, you call REST services

Problems :

  • no business in REST services, boilerplate codes
  • call REST services from javascript is not devfriendly
  • these calls are not clever
  • it is unidirectional

Why Ocelotds ?

Ocelotds.org

Example 1/3

public class MyService { // EJB, CDI, Spring
   public Result getResult(String str, MyObject arg2) {
      ...
   }
}

Write business service

Ocelotds.org

Example 2/3

@Path("/myservice")
public class MyRestService { 
   @POST
   @Produces("text/json")
   @Consumes("application/x-www-form-urlencoded")
   @Path("/{str}")
   public Result method(@PathParam("str") String str, @FormParam("arg") MyObject arg2) {
      return myService.getResult(str, arg2); // normaly myService is avalable by injection
   }
}

Write the associate REST resource

One REST for at least CRUDL resource
Maybe for all methods

Ocelotds.org

Example 3/3

var req = new XMLHttpRequest();
req.onreadystatechange = function() {
   if (req.status == 200) {
      var result = JSON.parse(req.responseText);
      // do something
   } else {
      // Error handler
   }
}
req.open("POST", "/myservice/foo", true);
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send("{\"prop1\":\"foo\",\"prop2\":true}");

Call REST from UI

Not really clear
And really far from this

obj = {"prop1":"foo","prop2":true};
myService.getResult("foo", obj);

Ocelotds.org

Now with Ocelotds

@DataService(resolver = Constants.Resolver...) // use the correct resolver
public class MyService { // EJB, CDI, Spring
   public Result getResult(String str, MyObject arg2) {
      ...
   }
}

Write business method as before
and annotate it

// You wrote MyService in java, you use MyService in javascript, marvelous
myService.getResult("foo", {"prop1":"foo","prop2":true})
   .then(function(res) {
      // do something with res
   });

Use it in javascript

Ocelotds.org

How that's work

@DataService(resolver = Constants.Resolver...) // process classes annotated

Annotation process tools APT

// You wrote MyService in java, you use mMyService in javascript, marvelous
myService.getResult("foo", {"prop1":"foo","prop2":true}).then(function(res) {
   // do something with res
});

Use it in javascript

Generate javascript stub

<script src="ocelot/services.js" type="text/javascript"></script>
<script src="ocelot/core.min.js" type="text/javascript"></script>

  • REST endpoint receive request
  • CDI find the resolver, the class, the method and process request
  • Endpoint return response
  • And finally, javascript part call handlers

Ocelotds.org

Additional feature : cache

public class UserService {
   List<User> getUsersFromService(Service srv) {...}
   void addUserToService(Service srv, User user) {...} 
}

Cache features on frontend

Who is best placed to code these features ?
Backend developper
or
Frontend developper ?

Usecase : the users list

List not is updated often,
we may cache it on client.

Ocelotds.org

Additional feature : cache

@DataService(resolver = Constants.Resolver...)
public class UserService {
   /** 
    * This service will be cached during 2 minute on the client
    * Cache key considerate : UserService.getUsers(id) 
    */
   @JsCacheResult(minute=2, keys = {"srv.id"}) 
   List<User> getUsersFromService(Service srv) {...} 

   /** 
    * This service will remove the cache on all client
    */
   @JsCacheRemove(cls = UserService.class, methodName = "getUsers", keys = {"srvid"})
   String addUserToService(Long srvid, User user) {...}
}

Cache on frontend

but defined on backend

Ocelotds.org

Additional feature : Topic/channel

sub.unsubscribe();

Topic mechanism 1/5

Subscription

Unsubscription

var sub = new Subscriber("mytopic").message(function (msg) {
   doSomethingWithMsg(msg);
});

Special topic

var sub = new Subscriber("subscribers:mytopic").message(function (num) {
   updateNumberSubscribers(num); 
});

Ocelotds.org

Topic mechanism 2/5

@Inject
@JsTopicEvent("mytopic")
Event<Object> mytopicEvent;

public void publish(Payload payload) {
   ...
   mytopicEvent.fire(payload);
   ...
}

publish messages from backend

Ocelotds.org

Topic mechanism 3/5

@DataService(resolver = Constants.Resolver.CDI)
public class MessageServices {
    @JsTopic("TopicName")
    public String publish(String message) {
        return message;
    }
...

With dynamic topic

@JsTopic
public String publishToTopic(String message, @JsTopicName String topic) {
   return message;
}

publish message from frontend

Ocelotds.org

Topic mechanism 4/5

public class GlobalTopicAccessControl implements JsTopicAccessController {
   @Override
   public void checkAccess(UserContext ctx, String topic) throws IllegalAccessException {
      // if access not allowed, throw IllegalAccessException
   }
}

Secure specific Topic

@JsTopicControl(SPECIFIC_TOPIC)
public class GlobalTopicAccessControl implements JsTopicAccessController {
   @Override
   public void checkAccess(UserContext ctx, String topic) throws IllegalAccessException {
      // if access to SPECIFIC_TOPIC not allowed, throw IllegalAccessException
   }
}

Secure All Topics

Ocelotds.org

Topic mechanism 5/5

public class PayloadMessageControl implements JsTopicMessageController<Payload> {
   @Override
   public void checkRight(UserContext ctx, Payload payload) throws NotRecipientException {
      // if not allowed, throw NotRecipientException
   }
}

Secure Message

Ocelotds.org

And more with Ocelotds ans SPI

@DataServiceResolver("MyResolver")
@ApplicationScoped
public class MyResolver implements IDataServiceResolver {
   @Override
   public <T> T resolveDataService(Class<T> clazz) throws DataServiceException {
      ...
   }
   @Override
   public Scope getScope(Class clazz) {
      ...
   }
}

Your backend beans not supported by ocelot
Implement your own resolver

Ocelotds.org

collaborative drawing

Demo

Ocelotds.org

Questions ?

Welcome

https://github.com/ocelotds/ocelot