BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Jolie - a Service-Oriented Programming Language for Distributed Applications

Jolie - a Service-Oriented Programming Language for Distributed Applications

This item in japanese

Bookmarks

The Jolie programming language recently attracted the attention of developers on Hacker News. Jolie is a service-oriented language that encourages developers to model distributed software as composable services whose orchestration is described separately from communication protocols (SOAP, HTTP, XML-RPC) and deployment architecture. Jolie strives to reduce the distance between specification and implementation by reifying services as a first-class concept.

Prof. Fabrizio Montesi, head of section at the Department of Mathematics and Computer Science of the University of Southern Denmark, explained on Hacker News the rationale behind Jolie:

[I think the predominant question here is: why a language over, e.g., a framework?]

In a nutshell: because we want to minimize code <-> model distance. Other languages make you program in terms of functions, objects, etc., and make yourself model services by using these concepts. In Jolie, you write code that maps directly to the concepts that matter. What are the important concepts? APIs, Access Points, and Services (duh…) are examples.

Our (for now subjective) experience is that people who become familiar with Jolie are much faster at prototyping a service system, which makes it worth pursuing for us. Jolie code requires less boilerplate and state management for interesting scenarios.

[…] Another big reason for exploring languages is discipline. Languages discipline how you write code. […] The language enforces that if you ever decide that a component should become an external, independent service, you can do it by updating a few references (input/output ports, our access points). […] Jolie discipline also gives you the ability to reuse the same business logic under multiple access points with different protocols.

[…] In short: once you get to the implementation model [(after working out the domain model)] and if this is service-oriented, Jolie gives you a concise and executable syntax to write it.

A Jolie program is composed of two parts: behavior and deployment. The first part specifies the workflow the service will execute. The second part defines how to execute the behavior and how to interact with the rest of the system. In Jolie, a service is specified by its contracts, its endpoints (e.g., inputPort, outputPort, location, protocol, interfaces), its execution model (single | concurrent | sequential), and the computations associated with its input/output communications (behavior). Jolie’s documentation provides the implementation of a calculator to illustrate key language features (CalculatorInterface.ol):

type SumRequest: void {
    term[1,*]: int
}

type SubRequest: void {
    minuend: int 
    subtraend: int
}

type MulRequest: void {
    factor*: double
}

type DivRequest: void {
    dividend: double
    divisor: double
}

interface CalculatorInterface {
    RequestResponse:
        sum( SumRequest )( int ),
        sub( SubRequest )( int ),
        mul( MulRequest )( double ),
        div( DivRequest )( double ) 
}

The previous code describes the contracts for the calculator service: four arithmetic operations with the type of the required operands and computed results. RequestResponse indicates a synchronous exchange that involves a request message and a response message. The alternative OneWay (not used here) involves a request message without response.

The main code for the service is as follows:

from CalculatorInterfaceModule import CalculatorInterface

service CalculatorService {
  execution { single }
  
  inputPort CalculatorPort {
      location: "socket://localhost:8000"
      protocol: http { format = "json" }
      interfaces: CalculatorInterface
  }     

  main {

      [ sum( request )( response ) {
          for( t in request.term ) {
              response = response + t
          }
      }]

      [ sub( request )( response ) {
          response = request.minuend - request.subtraend
      }]

      [ mul( request )( response ) {
          response = 1
          for ( f in request.factor ) {
              response = response * f 
          }
      }]

      [ div( request )( response ) {
          response = request.dividend / request.divisor
      }]
  }

}

The previous code showcases the service listening endpoint (local socket on port 8000), the protocol to use to interact with the service, and the previously described service interface (CalculatorInterface.ol). The list of operations is specified using input choices (the square brackets inside of main), a control-flow construct.

The single execution modality used here means that the CalculatorService behavior should be run only once. It is usually used to run scripts — triggered by command rather than message reception. The sequential execution modality causes the program behavior to be made available again after the current instance has terminated, preventing concurrent execution. That modality can be used for modeling services that need to guarantee exclusive access to a resource. The concurrent modality allows a process to support multiple requests.

When defining the behavior of a service, developers may use standard control flow primitives (e.g., if, for), sequential composition (;), parallel composition ({ P } | { Q }), or input choice (analog to pattern matching on messages). The input choice feature uses a bracket syntax illustrated in the previous sample code.

Jolie strives to make it easy to change the distribution of applications without changing the logic of the services:

Deployment architecture

Jolie supports the definition of fault handlers for parallel fault handling. Developers can update the behavior of fault handlers at runtime with the install primitive:

scope ( scope_name ) {
 install (
 fault_name1 => handler code
 fault_name2 => handler code
 );throw ( fault_name )
 }

Jolie additionally facilitates composing services according to several architectural patterns: orchestration, aggregation, redirection, embedding. The embedding primitive allows specifying macro-services that coordinate a set of microservices within a single execution context:

Macroservices
(Source: Jolie’s documentation)

While Jolie originated from academia and has formal syntax and semantics, it is also used in production at for-profit companies.

Jolie shares some goals with Ballerina, another open-source programming language for writing network-distributed applications that promotes networking as a first-class concept into the language.

Jolie is an open-source general-purpose language that strives to facilitate the implementation of distributed applications by adopting services as a first-class concept. Jolie has dedicated primitives to handle common issues related to distributed applications: concurrency, communication between services, fault handling, heterogeneity, and system evolution. The Jolie acronym stands for Java Orchestration Language Interpreter Engine.

To get started with Jolie, developers may refer to its online documentation.

Rate this Article

Adoption
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT