Adding an input port with protocol SODEPS

Protocol sodeps uses binary protocol sodep already described in this example, over ssl. It can be useful when securing communication over sodep protocol.

In the following picture we show how to add an inputPort which provides a sodeps protocol in addition to those with http/json, http/soap, sodep, https and sodeps already discussed.

As it happened for the addition of sodep protocol input port, also in the case of a sodep protocol input port the behaviour of the service is always the same, and you don't need to modify it.

Adding the port

The first step is adding the inputPort to the code. In our example is:

inputPort AdvancedCalculatorPortSODEPS {
    location: "socket://localhost:8006"
    protocol: sodeps {
        ssl.keyStore = "keystore.jks",
        ssl.keyStorePassword = "jolie!"
    }
    interfaces: AdvancedCalculatorInterface
}

It is worth noting that, as we did for protocol https also in this case we need to specify the keystore and the related password. You can use tool keytool for generating it.

The complete example

The complete example follows and it may be consulted at this [link] (https://github.com/jolie/examples/tree/master/v1.10.x/tutorials/more_inputports_and_protocols/sodeps)

from .AdvancedCalculatorServiceInterfaceModule import AdvancedCalculatorInterface
from .CalculatorInterfaceModule import CalculatorInterface

interface ChuckNorrisIface {
    RequestResponse: random( undefined )( undefined )
}

service AdvancedCalculatorService {

    execution: concurrent

    outputPort Chuck {
        location: "socket://api.chucknorris.io:443/"
        protocol: https {
            .osc.random.method = "get";
            .osc.random.alias = "jokes/random"
        }
        interfaces: ChuckNorrisIface
    }

    outputPort Calculator {
        location: "socket://localhost:8000"
        protocol: http { format = "json" }
        interfaces: CalculatorInterface
    }

    inputPort AdvancedCalculatorPort {
        location: "socket://localhost:8001"
        protocol: http { format = "json" }
        interfaces: AdvancedCalculatorInterface
    }

    inputPort AdvancedCalculatorPortSOAP {
        location: "socket://localhost:8002"
        protocol: soap {
            wsdl = "AdvancedCalculator.wsdl",
            wsdl.port = "AdvancedCalculatorPortSOAPServicePort"
        }
        interfaces: AdvancedCalculatorInterface
    }

    inputPort AdvancedCalculatorPortSODEP {
        location: "socket://localhost:8003"
        protocol: sodep 
        interfaces: AdvancedCalculatorInterface
    }

    inputPort AdvancedCalculatorPortHTTPS {
        location: "socket://localhost:8004"
        protocol: https { 
            format = "json",
            ssl.keyStore = "keystore.jks",
            ssl.keyStorePassword = "jolie!"
        }
        interfaces: AdvancedCalculatorInterface
    }

    inputPort AdvancedCalculatorPortSOAPS {
        location: "socket://localhost:8005"
        protocol: soaps {
            wsdl = "AdvancedCalculatorSOAPS.wsdl",
            wsdl.port = "AdvancedCalculatorPortSOAPServicePort",
            ssl.keyStore = "keystore.jks",
            ssl.keyStorePassword = "jolie!"
        }
        interfaces: AdvancedCalculatorInterface
    }

    inputPort AdvancedCalculatorPortSODEPS {
        location: "socket://localhost:8006"
        protocol: sodeps {
            ssl.keyStore = "keystore.jks",
            ssl.keyStorePassword = "jolie!"
        }
        interfaces: AdvancedCalculatorInterface
    }

    main {
        [ factorial( request )( response ) {
            for( i = request.term, i > 0, i-- ) {
                req_mul.factor[ #req_mul.factor ] = i
            }
            mul@Calculator( req_mul )( response.factorial )    
            random@Chuck()( chuck_res )
            response.advertisement = chuck_res.value            
        }]

        [ average( request )( response ) {
            {
                sum@Calculator( request )( sum_res )
                div@Calculator( { dividend = double( sum_res ), divisor = double( #request.term ) })( response.average )
            }
            |
            {
                random@Chuck()( chuck_res )
                response.advertisement = chuck_res.value
            }
        }]

        [ percentage( request )( response ) {
            {
                div@Calculator( { dividend = request.term, divisor = 100.0 })( div_res )
                mul@Calculator( { factor[0] = div_res, factor[1] = request.percentage })( response_mul )
                response.result = response_mul
            }
            |
            {
                random@Chuck()( chuck_res )
                response.advertisement = chuck_res.value
            }
        }]
    }
}

Running the service and invoking it

Since we are extending the example Using more than one dependency, here we need to run two services in two separate shells:

jolie AdvancedCalculatorService.ol
jolie CalcularService.ol

In this case the client is another jolie script that must be run in a separate shell. As we did for the example where we use protocol sodep, here we modified the output port which points to the sodeps port of the service, in order to be compliant with protocol sodeps.

from AdvancedCalculatorServiceInterfaceModule import AdvancedCalculatorInterface
from console import *
from string_utils import StringUtils

service SodepsClient {
    outputPort AdvancedCalculatorService {
        location: "socket://localhost:8006"
        protocol: sodeps {
            ssl.trustStore = "truststore.jks",
            ssl.trustStorePassword = "jolie!"
        }
        interfaces: AdvancedCalculatorInterface
    }

    inputPort ConsoleInputPort {
        location: "local"
        interfaces: ConsoleInputInterface
    }

    embed Console as Console
    embed StringUtils as StringUtils

    init {
        registerForInput@Console()()
    }

    main {
        println@Console("Select the operation to call:")()
        println@Console("1- factorial")()
        println@Console("2- percentage")()
        println@Console("3- average")()
        print@Console("? ")()

        in( answer )
        if ( (answer != "1") && (answer != "2") && (answer != "3") ) {
            println@Console("Please, select 1, 2 or 3")()
            throw( Error )
        }

        if ( answer == "1" ) {
            println@Console( "Enter an integer")()
            in( term )
            factorial@AdvancedCalculatorService( { term = int( term ) } )( factorial_response )
            println@Console( "Result: " + factorial_response.factorial )()
            println@Console( factorial_response.advertisement )()
        }
        if ( answer == "2" ) {
            println@Console( "Enter a double")()
            in ( term )
            println@Console( "Enter a percentage to be calculated")()
            in ( percentage )
            percentage@AdvancedCalculatorService( { term = double( term ), percentage = double( percentage ) } )( percentage_response )
            println@Console( "Result: " + percentage_response.result )()
            println@Console( percentage_response.advertisement )()
        }
        if ( answer == "3" ) {
            println@Console("Enter a list of integers separated by commas")()
            in( terms )
            split@StringUtils( terms { regex = ","} )( splitted_terms )
            for( t in splitted_terms.result ) {
                req_average.term[ #req_average.term ] = int( t )
            }
            average@AdvancedCalculatorService( req_average )( average_response )
            println@Console( "Result: " + average_response.average )()
            println@Console( average_response.advertisement )()
        }
    }
}

Note that the outputPort requires two more parameters: ssl.trustStore and ssl.trustStorePassword which allows to the define the trust store where checking the validity of the server certificate. To this end, it is important to extract the certificate from the keystore of the service and add it to the trust store of the client. In the following we report how to run the client and how it appears its console:

jolie sodep_client.ol 


Select the operation to call:
1- factorial
2- percentage
3- average
? 1
Enter an integer
3
Result: 6
Chuck NOrris is an incredible sitar player.