1.3 Middleware service

Middleware service acts as common access point for OBEDX to access Transformer’s APIs. It is required for accessing the jars generated by transformer over the network.

Middleware service is wrapper around transformer’s API. Since transformer may take some time for message transformation and enrichment, the middleware service must be designed in such a way that it should support asynchronous non-blocking communication.

  • Implementation team is required to build this service. Below are the expectations from the middleware service.
  • Must be restful webservice
  • Must support asynchronous and non-blocking API’s
  • Must have a rest endpoint to accept parsing requests from OBEDX with predefined request parameters
  • Must be able to identify and decide which transformer api operation to call based on incoming format identfier
  • Must be able to send acknolegement of parsing request
  • Must be able to send the parsed response in OBEDX format along with all the validations / exceptions details if any to below end point.
  • https://HOST_NAME:PORT_NUMBER/cmc-obrh-services/route/dispatch (OBRH_SERVICE_URL)
  • Service must provide a directory to place all the jars required for transformer api’s and jar generated by transformer.
  • Refer below screenshot for more details
  • After building the middleware service all the jars must be available in WEB-INF/lib folder for runtime access (refer line 26 from above screenshot).
  • Transformer GUI Toolkit application generates three properties project key, service name & operation name on console, while building the exposed service or in the service info file present in jar generated by transformer at /META-INF directory
  • These three properties must be configured in Parameters field present on integration preference screen UI as shown in below screenshot.
  • One should follow below sequence while configuring these properties
  • {project key}~{service name}~{operation name} (separator used is Tilde “~”)
  • OBEDX will provide format identifier along with transaction name in below format

    format name-transaction name as a parsing request parameter named “format id” ;

  • Along with properties configured in Parameters field on integration preferences UI as parsing request parameters named “parameters”.

Note that middleware service needs to be re-deployed every time new jar need to be added or modification done in existing mappings.

An example sudo code for middleware service written in java is provided below :

Note:

Code provided below is sample code for implementation partners to implement this service seamlessly. This code requires certain dependencies provided by transformer along with transformer’s runtime license jar.

Implementation team must retain the signature of submit() method, response headers, & response map keys as specified in the code below.

@RestControllerpublic class MiddlewareService{         @PostMapping("/submit")    public ResponseDtoWrapper submit(@RequestBody MultipartFile file, String fileRefId, String formatId,String
          parameters){             // perform technical validations such as not null check... etc                 // handleParsingRequest() must be asynch (execute in separate
          thread).        handleParsingRequest(incomingFile, fileRefId, originalFileName,
            formatId, parameters);                  // 
sendAcknowledgement() will return the ResponseDtoWrapper without waiting for
            handleParsingRequest() to finish        return sendAcknowledgement(originalFileName);     
}         @Async    public void handleParsingRequest(MultipartFile file, String fileRefId, String originalFileName,
            String formatId, String parameters) {                 String responseFromTrace = callTransformerApi(formatId, file,
            parameters);                  sendResponseToObrhService(responseFromTrace,
          fileRefId);    }         private String callTraceParserApi(String formatId, File file, String parameters)
          {        Object output;        try {                   // Project key, Service name, & Operation name will be generated by
          transformer         String [] parserParams =
          parameters.split(“~”);                   output =
            ServicePerformerExecutor.performServiceWithSimpleExceptions(ClasspathProjectManager.getInstance(),              parserParams[0],               parserParams[1],               parserParams[2],               Files.newInputStream(file.toPath()),              null,              OutputInstruction.asStringOutput());          String response = (String) output;          
return response;          }         
catch (Exception exception) {             // log or handle exception here and return String response           return TECHNICAL_ERROR_IN_PARSING;         }     }          private void sendResponseToObrhService(String responseFromTrace, String fileRefId)
          {        restTemplate.postForObject(OBRH_SERVICE_URL,                                    getObrhRequest(responseFromTrace,
                                             fileRefId),
                  ResponseDtoWrapper.class);} private HttpEntity<Map<String, Map<String, String>>> getObrhRequest(String responseFromTrace,
            String fileRefId) {        Map<String, Map<String, String>> responseMap =
            getResponseMap(responseFromTrace, fileRefId);                 HttpHeaders httpHeaders = new HttpHeaders();        httpHeaders.add("appId", "CMNCORE");        httpHeaders.add("userId", "EDXWORKFLOW");        httpHeaders.add("branchCode", "006");        httpHeaders.add("SERVICE-CONSUMER", SERVICE-CONSUMER); // SERVICE-CONSUMER must be replaced with name                                                                   of
            service consumer configured in OBRH        httpHeaders.add("entityId", "DEFAULTENTITY");        httpHeaders.add("SERVICE-CONSUMER-SERVICE", SERVICE-CONSUMER-SERVICE); // SERVICE-CONSUMER-SERVICE must                                             be
            replaced with name of service consumer service configured in OBRH        httpHeaders.setContentType(MediaType.APPLICATION_JSON);                 return new HttpEntity<>(responseMap, headers);    }         public Map<String, Map<String, String>> getResponseMap(String responseFromTrace, String
            fileRefId) {        Map<String, String> paramMap = new HashMap<>(2);        paramMap.put("input-file", fileRefId);        paramMap.put( "output-file", responseFromTrace);        Map<String, Map<String, String>> responseMap =
              new HashMap<>(1);        responseMap.put("external-parser-output", paramMap);                 // "input-file", "output-file" & "external-parser-output" are keys of response
            map and are must NOT be changed in any case.                 return responseMap;    }         private ResponseDtoWrapper sendAcknowledgement(String originalFilename) {        ResponseDtoWrapper responseDtoWrapper = new ResponseDtoWrapper();        ResponseDto responseDto = new ResponseDto();        responseDto.addToResponseList(new ResponseCode(ACCEPT_FOR_PARSE));       
 responseDto.addToResponseList(new ResponseCode(HttpStatus.ACCEPTED.toString()));        responseDto.setStatus("OK");        responseDto.setHttpStatusCode(HttpStatus.OK);        String requestId = String.format(" %s-%s ", UUID.randomUUID(), originalFilename);       
 responseDto.setRequestId(requestId);        responseDtoWrapper.setMessages(responseDto);        return responseDtoWrapper;    }}             

Middleware service’s api must return ResponseDtoWrapper object, structure of which is as shown below.

import org.springframework.stereotype.Component; 
@Componentpublic class ResponseDtoWrapper 
{    private ResponseDto messages;    private ResponseResourceSupport data;    
 public ResponseDtoWrapper() {    }     
public ResponseDto getMessages() {        
return this.messages;    }     public void setMessages(ResponseDto messages) 
{        this.messages = messages;    }     public ResponseResourceSupport getData() 
{        return this.data;    }     public void setData(ResponseResourceSupport data) 
{        this.data = data;    }}
import org.springframework.http.HttpStatus; import java.io.Serializable;import java.math.BigDecimal;
import java.util.ArrayList;import java.util.List; public class ResponseDto implements Serializable
 {    private static final long serialVersionUID = -8555557115768857726L;   
 private String keyId;    private String status;    private List<ResponseCode> codes = new ArrayList<>();  
  private String requestId;    private HttpStatus httpStatusCode;    private BigDecimal overrideAuthLevelsReqd;     
public ResponseDto() {    }     public HttpStatus getHttpStatusCode() {        return this.httpStatusCode;    }      
   public void setHttpStatusCode(HttpStatus httpStatusCode) 
{        this.httpStatusCode = httpStatusCode;    }     public String getKeyId() {        return this.keyId;    }  
   public void setKeyId(String keyId) 
{        this.keyId = keyId;    }   
  public void addToResponseList(ResponseCode respObj) {        this.codes.add(respObj);    }    
 public void removeFromResponseCodeList(ResponseCode respObj) {        this.codes.remove(respObj);    }    
 public void appendToResponseList(List<ResponseCode> respCodeListObj) 
{        this.codes.addAll(respCodeListObj);    }     
public String getStatus() {        return this.status;    }     public void setStatus(String status) 
{        this.status = status;    }   
  public List<ResponseCode> getCodes() 
{        return this.codes;    }     public void setCodes(List<ResponseCode> codes) {        
this.codes = codes;    }     public String getRequestId() {        return this.requestId;    }    
 public void setRequestId(String requestId) {        this.requestId = requestId;    }     
public BigDecimal getOverrideAuthLevelsReqd() {        return this.overrideAuthLevelsReqd;    }    
public void setOverrideAuthLevelsReqd(BigDecimal overrideAuthLevelsReqd) 
{        this.overrideAuthLevelsReqd = overrideAuthLevelsReqd;}}
import java.io.Serializable;import java.math.BigDecimal;import java.util.List; 
public class ResponseCode implements Serializable {   
 private String Code;    private String Desc;    
private String Type;    private String Language;   
 private List<Object> args;    private String arg;  
  private boolean information;    private boolean override;  
  private boolean error;    private BigDecimal overrideAuthLevelsReqd;    
 public List<Object> getArgs() {        return this.args;    }   
  public void setArgs(List<Object> args) {        this.args = args;    }   
  public ResponseCode() {    }     public ResponseCode(String code) 
{        this.Code = code;    }     public ResponseCode(String code, String msg)
 {        this.Code = code;        this.arg = msg;    }     public String getArg() 
{        return this.arg;    }     public void setArg(String arg)
 {        this.arg = arg;    }     public ResponseCode(String code, List<Object> msg)
 {        this.Code = code;        this.args = msg;    }     public String getCode()
 {        return this.Code;    }     public void setCode(String code)
 {        this.Code = code;    }          public String getDesc() 
{        return this.Desc;    }     public void setDesc(String desc) 
{        this.Desc = desc;    }     public String getType() 
{        return this.Type;    }     public void setType(String type) 
{        this.Type = type;    }     public String getLanguage()
 {        return this.Language;    }     public void setLanguage(String language)
 {        this.Language = language;    }     public boolean isError() 
{        return null != this.Type && this.Type.equalsIgnoreCase("E");    }     
public boolean isOverride() {        return null != this.Type && this.Type.equalsIgnoreCase("O");    }   
  public boolean isInformation() {        return null != this.Type && this.Type.equalsIgnoreCase("I");    }    
 public BigDecimal getOverrideAuthLevelsReqd() {        return this.overrideAuthLevelsReqd;    } 
public void setOverrideAuthLevelsReqd(BigDecimal overrideAuthLevelsReqd) 
{        this.overrideAuthLevelsReqd = overrideAuthLevelsReqd;}}
import org.springframework.hateoas.RepresentationModel; 
public class ResponseResourceSupport extends RepresentationModel 
{    public ResponseResourceSupport() {    }}