Calculator server source

The source code for the server-side application included in the RESTful Web services calculator demo.

IMPORT com
IMPORT util 
IMPORT FGL WSHelper

TYPE TYP_status RECORD
        code INTEGER,
        desc STRING
    END RECORD

GLOBALS
  DEFINE 
    add_in RECORD
      a INTEGER,
      b INTEGER
    END RECORD,
    add_out RECORD
      status TYP_status,
      r INTEGER
    END RECORD

  DEFINE 
    subtract_in RECORD
      a INTEGER,
      b INTEGER
    END RECORD,
    subtract_out RECORD
      status TYP_status,
      r INTEGER
    END RECORD

  DEFINE 
    multiply_in RECORD
      a INTEGER,
      b INTEGER
    END RECORD,
    multiply_out RECORD
      status TYP_status,
      r INTEGER
    END RECORD

  DEFINE 
    divide_in RECORD
      a INTEGER,
      b INTEGER
    END RECORD,
    divide_out RECORD
      status TYP_status,
      quotient  INTEGER,
      remainder INTEGER
    END RECORD

  DEFINE
    err TYP_status
    
END GLOBALS

TYPE reqInfoTyp RECORD
    method      STRING,
    ctype       STRING,     # check the Content-Type
    informat    STRING,     # short word for Content Type 
    caccept     STRING,     # check which format the client accepts
    outformat   STRING,     # short word for Accept
    path        STRING,
    items       WSHelper.WSQueryType
END RECORD

DEFINE m_reqInfo reqInfoTyp

CONSTANT ERR_PARAM_A        = "Operand 'a' not found"
CONSTANT ERR_PARAM_B        = "Operand 'b' not found"
CONSTANT ERR_OPERATION      = "Operation not found"
CONSTANT ERR_METHOD         = "Method not supported"

MAIN
  DEFINE ret INTEGER
  DEFINE req com.HttpServiceRequest
  DEFINE method STRING
  DEFINE url STRING
  DEFINE acc STRING
  DEFINE idx INT
      
  DEFER INTERRUPT
    
  #
  # Start the server
  #
  DISPLAY "Starting server..."
  #
  # Starts the server on the port number specified by the FGLAPPSERVER environment variable
  #  (EX: FGLAPPSERVER=8090)
  # 
  CALL com.WebServiceEngine.Start()
  DISPLAY "The server is listening."

  # create the server
  WHILE TRUE
      TRY
          LET req = com.WebServiceEngine.GetHTTPServiceRequest(-1)
          CALL getReqInfo(req)
          # Get the type of method
          LET method = m_reqInfo.method
          # Get the request path
          LET url = m_reqInfo.path
          # Get the output format
          LET acc = m_reqInfo.outformat

          DISPLAY "Processing request... ", method, " ", url

          # parse the url, retrieve the operation and the operand
          CASE method
              WHEN "GET"
                IF url.getIndexOf("/add",1) > 0 THEN
                    LET idx = getParameterIndex("a") 
                    IF idx = 0 THEN
                        LET add_out.status.code = -1
                        LET add_out.status.desc = ERR_PARAM_A
                        CALL req.setResponseHeader("Content-Type","application/json")
                        CALL req.sendTextResponse(200, "OK", util.JSON.stringify(add_out))
                        EXIT CASE
                    ELSE
                        LET add_in.a = getParameterValue(idx)
                    END IF
                    LET idx = getParameterIndex("b")
                    IF idx = 0 THEN
                        LET add_out.status.code = -1
                        LET add_out.status.desc = ERR_PARAM_B
                        CALL req.setResponseHeader("Content-Type","application/json")
                        CALL req.sendTextResponse(200, "OK", util.JSON.stringify(add_out))
                        EXIT CASE
                    ELSE
                        LET add_in.b = getParameterValue(idx)
                    END IF
                    CALL add()
                    CALL req.setResponseHeader("Content-Type","application/json")
                    CALL req.sendTextResponse(200, "OK", util.JSON.stringify(add_out))

                ELSE IF url.getIndexOf("/subtract",1) > 0 THEN
                    LET idx = getParameterIndex("a") 
                    IF idx = 0 THEN
                        LET add_out.status.code = -1
                        LET add_out.status.desc = ERR_PARAM_A
                        CALL req.setResponseHeader("Content-Type","application/json")
                        CALL req.sendTextResponse(200, "OK", util.JSON.stringify(subtract_out))
                        EXIT CASE
                    ELSE
                        LET subtract_in.a = getParameterValue(idx)
                    END IF
                    LET idx = getParameterIndex("b")
                    IF idx = 0 THEN
                        LET add_out.status.code = -1
                        LET add_out.status.desc = ERR_PARAM_B
                        CALL req.setResponseHeader("Content-Type","application/json")
                        CALL req.sendTextResponse(200, "OK", util.JSON.stringify(subtract_out))
                        EXIT CASE
                    ELSE
                        LET subtract_in.b = getParameterValue(idx)
                    END IF
                    CALL subtract()
                    CALL req.setResponseHeader("Content-Type","application/json")
                    CALL req.sendTextResponse(200, "OK", util.JSON.stringify(subtract_out))
                    
                ELSE IF url.getIndexOf("/multiply",1) > 0 THEN
                    LET idx = getParameterIndex("a") 
                    IF idx = 0 THEN
                        LET add_out.status.code = -1
                        LET add_out.status.desc = ERR_PARAM_A
                        CALL req.setResponseHeader("Content-Type","application/json")
                        CALL req.sendTextResponse(200, "OK", util.JSON.stringify(multiply_out))
                        EXIT CASE
                    ELSE
                        LET multiply_in.a = getParameterValue(idx)
                    END IF
                    LET idx = getParameterIndex("b")
                    IF idx = 0 THEN
                        LET add_out.status.code = -1
                        LET add_out.status.desc = ERR_PARAM_B
                        CALL req.setResponseHeader("Content-Type","application/json")
                        CALL req.sendTextResponse(200, "OK", util.JSON.stringify(multiply_out))
                        EXIT CASE
                    ELSE
                        LET multiply_in.b = getParameterValue(idx)
                    END IF
                    CALL multiply()
                    CALL req.setResponseHeader("Content-Type","application/json")
                    CALL req.sendTextResponse(200, "OK", util.JSON.stringify(multiply_out))
                    
                ELSE IF url.getIndexOf("/divide",1) > 0 THEN
                    LET idx = getParameterIndex("a") 
                    IF idx = 0 THEN
                        LET add_out.status.code = -1
                        LET add_out.status.desc = ERR_PARAM_A
                        CALL req.setResponseHeader("Content-Type","application/json")
                        CALL req.sendTextResponse(200, "OK", util.JSON.stringify(divide_out))
                        EXIT CASE
                    ELSE
                        LET divide_in.a = getParameterValue(idx)
                    END IF
                    LET idx = getParameterIndex("b")
                    IF idx = 0 THEN
                        LET add_out.status.code = -1
                        LET add_out.status.desc = ERR_PARAM_B
                        CALL req.setResponseHeader("Content-Type","application/json")
                        CALL req.sendTextResponse(200, "OK", util.JSON.stringify(divide_out))
                        EXIT CASE
                    ELSE
                        LET divide_in.b = getParameterValue(idx)
                    END IF
                    CALL divide()
                    CALL req.setResponseHeader("Content-Type","application/json")
                    CALL req.sendTextResponse(200, "OK", util.JSON.stringify(divide_out))
                ELSE
                    CALL setError("Unknown request:\n" || url || "\n" || method)
                    LET err.code = -2
                    LET err.desc = ERR_OPERATION
                    CALL req.sendTextResponse(200,"OK",util.JSON.stringify(err))
                END IF
                END IF
                END IF
                END IF
              OTHERWISE
                CALL setError("Unknown request:\n" || url || "\n" || method)
                LET err.code = -3
                LET err.desc = ERR_METHOD
                CALL req.sendTextResponse(200,"OK",util.JSON.stringify(err))
          END CASE

        CATCH
            LET ret = status
            CASE ret
            WHEN -15565
                DISPLAY "Server process has been stopped by Ctrl-C"
            WHEN -15575
                 DISPLAY "Server process has been disconnected by the GAS"
            OTHERWISE
                DISPLAY "[ERROR] " || ret
                EXIT WHILE
            END CASE
            IF int_flag <> 0 THEN
                 LET int_flag = 0
                 EXIT WHILE
            END IF
        END TRY
    END WHILE
END MAIN

FUNCTION add()
  LET add_out.r = add_in.a + add_in.b
  LET add_out.status.code = 0
  LET add_out.status.desc = "OK"
END FUNCTION

FUNCTION subtract()
  LET subtract_out.r = subtract_in.a - subtract_in.b
  LET subtract_out.status.code = 0
  LET subtract_out.status.desc = "OK"
END FUNCTION

FUNCTION multiply()
  LET multiply_out.r = multiply_in.a * multiply_in.b
END FUNCTION

FUNCTION divide()
  IF divide_in.b != 0 THEN 
    LET divide_out.quotient  = divide_in.a / divide_in.b
    LET divide_out.remainder = divide_in.a MOD divide_in.b
    LET divide_out.status.code = 0
    LET divide_out.status.desc = "OK"
  ELSE
    LET divide_out.status.code = 0
    LET divide_out.status.desc = "Cannot divide by 0"
  END IF
END FUNCTION

FUNCTION getHeaderByName(areq,hname)
    DEFINE areq com.HttpServiceRequest
    DEFINE hname STRING

    DEFINE aname STRING
    DEFINE iname STRING
    DEFINE i INT
    DEFINE n INT

    LET aname = hname.toLowerCase()
    LET n = areq.getRequestHeaderCount()
    FOR i=1 TO n
        LET iname = areq.getRequestHeaderName(i)
        IF aname.equals(iname.toLowerCase()) THEN
            RETURN areq.getRequestHeaderValue(i)
        END IF
    END FOR

    RETURN NULL
END FUNCTION

FUNCTION getReqInfo(req)
    DEFINE req com.HttpServiceRequest
    
    INITIALIZE m_reqInfo TO NULL

    LET m_reqInfo.ctype = getHeaderByName(req,"Content-Type")
    IF m_reqInfo.ctype.getIndexOf("/xml",1) THEN
        LET m_reqInfo.informat = "XML"
    ELSE 
        LET m_reqInfo.informat = "JSON"
    END IF
    
    LET m_reqInfo.caccept = getHeaderByName(req,"Accept")
    IF m_reqInfo.caccept.getIndexOf("/xml",1) THEN
        LET m_reqInfo.outformat = "XML"
    ELSE 
        LET m_reqInfo.outformat = "JSON"
    END IF
    
    LET m_reqInfo.method = req.getMethod()
    
    LET m_reqInfo.path = req.getUrlPath()
    
    CALL req.getUrlQuery(m_reqInfo.items)
  
END FUNCTION

FUNCTION setError(s)
    DEFINE s STRING
    DISPLAY s
END FUNCTION

# returns 0 if element not found
FUNCTION getParameterIndex(s)
    DEFINE s STRING
    DEFINE i INT

    FOR i=1 TO m_reqInfo.items.getLength()
        IF s.equals(m_reqInfo.items[i].name) THEN 
            RETURN i 
        END IF
    END FOR

    RETURN 0
END FUNCTION

FUNCTION getParameterValue(i)
    DEFINE i INT

    RETURN m_reqInfo.items[i].value
END FUNCTION