Building Block View

To understand where the proposed MDD approach has its importance, the components involved in the Unix Web Socket communication have to be presented. Fig. 2 presents these components.

@startuml

  interface "Unix Web Socket" as ws

  package "AGL" {
    component "AGL Applications Framework" as af
      interface "Application Framework API" as af_api
  }


  package "Service" {
    component "AGL Service" as service
    component "Service Class" as service_class

    interface "Service Class" as i_service_class

    service .up.> af_api : use
    service .down.> i_service_class : use

    af -down- af_api
    i_service_class -down- service_class
  }

  package "Application" {
    component "APP Class" as app_class
    component "Application" as app
    component "WebSocketApi" as wsapi
    interface "APP Class" as i_app_class

    app .down.> i_app_class : use
    app_class -up- i_app_class

    app_class -down-|> wsapi
  }

  service -right-> ws
  app_class .right. ws : use

@enduml

Fig. 2 Web Socket Communication Component Diagram

Since the AGL Application Framework and its API are already given in the AGL architecture, the rationale behind the design was to wrap the AGL Application Framework API and the Web Socket communication in an RPC-like approach. Moreover, the components were encapsulated applying functional decomposition. Table 3 shows the responsibilities for each of the components in Fig. 2.

Table 3 Top Block Components Responsibilities
Name Responsibility
AGL Application Framework Manage all AGL Services and their life cycle, Create Unix Web Socket for the RESTfull API to be served by the AGL Services, Forward RESTfull API verb calls to AGL Services verbs callbacks, Verbs authentication process handling.
AGL Service Initialize service resources, serve the RESTfull API, Forward the RESTfull API verbs to the corresponding Service Class method, Unmarshal JSON messages as to parse corresponding Service Class method parameters, Marshal output parameters of Service Class as JSON to reply through Unix Web Socket.
Service Class Implements the intended functionality at service side for each RESTfull API verb.
Application Use functionality exposed by the AGL Services to achieve a user-visible purpose.
APP Class Exposes all RESTfull API verbs as methods with input and output parameters, Marshal parameters as JSON to send requests to the Unix Web Socket, Unmarshal JSON replies to update output parameters.
WebSocketApi Handle Unix Web Socket connection, Form RESTfull API request, Wait for RESTfull API replies.

raml2agl features an automatic code generation tool developed. Fig. 3 shows the building blocks of the tool and its relations with the possible outputs.

@startuml
component "RAML Model" as model
interface "RAML" as raml

package "RAML2AGL" {
  component "RAML Parser" as parser
  component "raml2agl main" as main
  interface "JSON Model" as jmodel
  interface "Templates Engine" as jinja_tmp
  component "Jinja2 Environment" as jinja_env

  parser -left- raml
  parser -down- jmodel
  main .up.> jmodel : use
  main .down.> jinja_tmp : use
  jinja_env -up- jinja_tmp
}

package "Service" {
  component "AGL Service" as service
  component "Service Class" as service_class
}

package "Application" {
  component "APP Class" as app_class
}

model -right- raml
main -right-> service : <<generate>> 
main -right-> app_class : <<generate>>
main -right-> service_class : <<partially generate>>
@enduml

Fig. 3 RAML2AGL Block Diagram

As shown in Fig. 3, raml2agl generates code for the Service Class, App Class, and the AGL Service; the last two are fully generated. Note that the automatically generated components are the ones with more responsibilities, as shown in Table 3. This fact was also the rationale behind the definition of the components, to automate most of the process and reduce the overhead of creating a new Service and/or Application. Moreover, Table 4 shows the responsibilities of each of the raml2agl components.

Table 4 RAML2AGL Components Responsibilities
Name Responsibility
RAML Parser Read the RAML model and create a JSON model to be pass to the Jinja2 templates.
Jinja2 Environment Manage the templates, render the templates using the JSON model.
raml2agl main Read the RAML model from a file, Control the entire generation flow, reads input command line parameters, Calls the RAML Parser to generate JSON model, Calls the Jinja2 Environment to render the corresponding templates.

Service Class

Fig. 4 shows an example of the output of raml2agl using the following model;

#%RAML 1.0
title: Example
mediaType: application/json
version: v1
baseUri: localhost:8000/api?token=x
/method_1:
  post:
    body:
      properties:
        param_in_1:
          type: integer
  get:
    responses:
      200:
        body:
          properties:
            param_out_1:
              type: integer
/method_2:
  post:
    body:
      properties:
        param_in_1:
          type: string
  get:
    responses:
      200:
        body:
          properties:
            param_out_1:
              type: string

@startuml

  class WebSocketApi {
  }

  class "Example" <<APP Class>> {
    method_1(param_in_1: const int, param_out_1: int &): int
    method_2(param_in_1: const char *, param_out_1: const char *): int
  }

  class "ServiceExample" <<Service Class>> {
    method_1(param_in_1: const int, param_out_1: int &): int
    method_2(param_in_1: const char *, param_out_1: const char *): int
  }

  "Example" -up-|> WebSocketApi
  "Example" .. "ServiceExample": linked over unix web socket

  hide members
  show "Example" methods
  show "ServiceExample" methods

@enduml

Fig. 4 Generated Example

Note that Service Class isn’t fully automatic generated. Nevertheless, a skeleton of the entire class with all the methods definition is generated. Is the task of the Service developer to finish the implementation of the functionality. Moreover, each method represents a verb of the RESTfull API. Hence, /example/method_1 will shall be implemented in ServiceExample.method_1(...). Furthermore, the model title is the parsed to name the RESTfull API and both classes.

WebSocketApi

Fig. 5 class diagram shows the definition of the WebSocketApi class.

@startuml
  class WebSocketApi {
    -{static} wsj1_itf: struct afb_wsj1_itf
    -{static} wsj1: struct afb_wsj1 *
    -{static} exonrep: int
    -{static} callcount: int
    -{static} loop: sd_event *
    -{static} reply: bool
    -{static} curr_reply: json_object *
    -uri: const char *
    -api_name: const char *
    #connected: bool

    +WebSocketApi(uri: const char *, api_name: const char * )
    +~WebSocketApi()
    #emit(verb: const char *, object: const char *): json_object *
    -{static} dec_callcount(): void
    -{static} on_wsj1_hangup(closure: void *, wsj1: struct afb_wsj1 *): void
    -{static} on_wsj1_call(closure: void *, api: const char *, verb: const char *, msg: struct afb_wsj1_msg *): void
    -{static} on_wsj1_event(closure: void *, event: const char *, msg: struct afb_wsj1_msg *): void
    -{static} on_wsj1_reply(closure: void *, msg: struct afb_wsj1_msg *): void
    -{static} wsj1_call(api: const char *, verb: const char *, object: const char *): int
  }
@enduml

Fig. 5 Web Socket API Class Diagram

Moreover, below the description of each of the classes members.

class WebSocketApi

Handle Unix Web Socket connection and transmission

Public Functions

WebSocketApi(const char *uri, const char *api_name)

Constructor

Creates Unix Web Socket connection and initialize the wait loop

Parameters
  • uri: Base uri to the web socket
  • api_name: API name

~WebSocketApi()

Destructor

Releases the resources and disconnect from the Unix Web Socket

Protected Functions

json_object *emit(const char *verb, const char *object)

Send string to the specified API’s verb

Return
Reply JSON object
Parameters
  • verb: API’s verb
  • object: Marshaled JSON object

Protected Attributes

bool connected

Flags connection status

Private Members

const char *uri

Base URI of the API

const char *api_name

API name

Private Static Functions

static void dec_callcount()

Decrement the reference count of calls

static void on_wsj1_hangup(void *closure, struct afb_wsj1 *wsj1)

Hang up callback

Parameters
  • closure: Hangup’s closure
  • wsj1: Connection object

static void on_wsj1_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)

Receives a method invocation callback

Parameters
  • closure: Call’s closure
  • api: API Name
  • verb: API’s verb
  • msg: Message to be sent

static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg *msg)

Receive an event callback

Parameters
  • closure: Event’s closure
  • event: Issued event
  • msg: Received message

static void on_wsj1_reply(void *closure, struct afb_wsj1_msg *msg)

Receive a reply callback

Parameters
  • closure: Reply’s closure
  • msg: Replied message

static int wsj1_call(const char *api, const char *verb, const char *object)

Send a marshaled object to the specified API and API’s verb

Return
Return POSIX error codes
Parameters
  • api: API name
  • verb: API’s verb
  • object: Marshalled JSON object

Private Static Attributes

struct afb_wsj1_itf wsj1_itf

The Web Socket callback interface for wsj1

struct afb_wsj1 *wsj1

The Web Socket connection object

int exonrep

The Web Socket connection object

int callcount

Calls Reference counter

sd_event *loop

Wait loop event

bool reply

Flags the presens of a reply

json_object *curr_reply

Last received JSON object

APP Class

As shown in Fig. 4 the Example APP Class has symmetric methods with ServiceExample. Therefore, a call to Example.method_1 will call /example/method_1 RESTfull API through the Unix Web Socket. Note that every APP Class is completely automatically generated. Moreover, APP Class inherits WebSocketApi and implements the entire Unix Web Socket communication its methods.

AGL Service

An AGL service is basically the implementation of the Application Framework API shown in Fig. 6.

@startuml
  class afb_auth << (S,#FF7700) >> {
  }

  class afb_verb_v2 << (S,#FF7700) >> {
    verb: const char *
    (*callback)(req: struct afb_req): void
    auth: const struct afb_auth *
    info: const char *
    session: uint32_t
  }

  class afb_binding_v2 << (S,#FF7700) >> {
    api: const char *
    specification: const char *
    info: const char *
    verbs: const struct afb_verb_v2 *
    (*preinit)(): int
    (*init)(): int
    (*onevent)(event: const char *, object: struct json_object *): void
    noconcurrency: unsigned
  }

  afb_binding_v2 --* afb_verb_v2 : use
  afb_verb_v2 --* afb_auth : use
@enduml

Fig. 6 AGL Application Framework API [29]

Furthermore, to implement Fig. 4, for instance, a null-terminated list of verbs has to be defined as follows;

static const struct afb_verb_v2 verbs[] = {
      /*Without security*/
      {.verb = "method_1", .callback = method_1, .auth = NULL, .info = "method_1", .session = 0},
      {.verb = "method_2", .callback = method_2, .auth = NULL, .info = "method_2", .session = 0},
      {.verb = NULL, .callback = NULL, .auth = NULL, .info = NULL, .session = 0 }
};

Note that for an initial implementation the authentication mechanisms weren’t implemented. Nevertheless, it has been included in the raml2agl’s road map, see [22].

And finally, to register the entire API to the AGL Application Framework the afb_binding_v2 structure is automatically generated as follows.

const struct afb_binding_v2 afbBindingV2 = {
  .api = "example",
  .specification = "",
  .info = "Auto generated - Example",
      .verbs = verbs,
      .preinit = NULL,
  .init = init,
      .onevent = NULL,
  .noconcurrency = 1
};

RAML Parser

Fig. 7 presents the internals of the RAML Parser component. Furthermore, the responsibilities of each of the sub-components are stated in Table 5

@startuml

  interface RAML as raml
  interface JSON as json

  package "RAML Parser" {

    component "Root Attributes Parser" as root_parser
    component "Methods Parser" as method_parser

    package "Parameters Parser" {
      component "Input Parameters Parser" as input_params
      component "Output Parameters Parser" as output_params
      component "Types Parser" as type_parser

      input_params <-down-> type_parser : <<flow>> RAML, JSON
      output_params <-down-> type_parser : <<flow>> RAML, JSON

    }

    method_parser <-down-> input_params : <<flow>> RAML, JSON
    method_parser <-down-> output_params : <<flow>> RAML, JSON

    root_parser <-down-> method_parser : <<flow>> RAML, JSON
  }

  raml -right-> root_parser : <<flow>> RAML

  root_parser -right-> json : <<flow>> JSON

@enduml

Fig. 7 RAML Parser Block Diagram

Table 5 RAML2 Parser Sub-components Responsibilities
Name Responsibility
Root Attributes Parser Parse the RAML root attributes like; title and base URI.
Methods Parser Parse the RAML verbs as methods
Input Parameters Parser Parse the RAML verbs’ input parameters
Output Parameters Parser Parse the RAML verbs’ output parameters
Types Parser Parse the RAML verbs’ parameters’ types

raml2agl main

Fig. 8 presents the internals of the RAML2AGL main component. Furthermore, the responsibilities of each of the sub-components are stated in Table 6

@startuml

  interface "JSON model" as json
  interface "Template Engine" as tmpl
  interface "Command Line" as cmd
  interface "Filesystem" as fs

  package "raml2agl main" {

    component "Templates Filters" as filters
    component "Command Line Arguments Parser" as parser
    component "Files Generator" as gen

    parser --> gen : Configures

    cmd --> parser

    gen -down-> fs : Write files


  }

  json -right-> gen

  filters .right.> tmpl
  gen .right.> tmpl : use


@enduml

Fig. 8 RAML2AGL main Block Diagram

Table 6 RAML2AGL main Sub-components Responsibilities
Name Responsibility
Command Line Arguments Parser Parses the command line arguments to configure the File Generator.
Templates Filters Defines Jinja2 Template filters to convert data types from RAML format to C++.
Files Generator Passes the JSON model to render the templates to be built and write files to the selected output location.

[22]Pedro Cuadra. Raml to agl. URL: https://github.com/pjcuadra/raml2agl.
[29]Automotive Grade Linux. Bindings reference. URL: http://docs.automotivelinux.org/docs/apis_services/en/dev/reference/af-binder/afb-binding-references.html.