From c321462128612e6a81403ed7de399c009e5d051e Mon Sep 17 00:00:00 2001 From: Mayur Bari <53168252+mayuraudev@users.noreply.github.com> Date: Tue, 6 Aug 2019 12:18:33 +0200 Subject: [PATCH] Two header are added - "verbose" & "nometa" 1. Allow for an option to send more verbose response in JSon so that consuming application can have ease of development. 2. Call based toggle for suppressing the meta information in response data. To improve performance. Solution : Two header are proposed "verbose" to respect the new format response - true=New format, false/header absent=Old format "nometa" to toggle the meta included in response - true=meta info excluded, false/header absent=meta info included. If the Restful API returning single object { "status": "Ok" or "Error" "value":{ } "error":{ "errorNo":"ABX011110", -- if any error number is there "errorText":"The name value can be be empty to process data." -- error description or text } } If the Restful API returning multiple objects { "status": "Ok" or "Error" "value":[ ] "count": "error":{ } } --- RestBCAdapter.bbj | 1282 ++++++++++++++-------------- RestBridge.bbj | 2080 +++++++++++++++++++++++---------------------- 2 files changed, 1692 insertions(+), 1670 deletions(-) diff --git a/RestBCAdapter.bbj b/RestBCAdapter.bbj index bd02927..a67f3d4 100644 --- a/RestBCAdapter.bbj +++ b/RestBCAdapter.bbj @@ -1,641 +1,641 @@ -use java.util.HashMap -use com.basiscomponents.db.ResultSet -use com.basiscomponents.db.DataRow - -seterr execerr - -debug=0 -debug=num(stbl("DEBUG",err=*next),err=*next) - -if debug then System.out.println("REST: new remote session ") - -BBjAPI().getConfig().setOptionSetting("ERROR_UNWINDS", 1) - -ses$ = argv(1) -authtype$=argv(2) -auth$ = argv(3) - -if debug then System.out.println("REST: WORKDIR "+dir("")) -ses$=stbl("SESSIONID",ses$) - -servletParams! = new HashMap() -servletParams! = BBjAPI().getGlobalNamespace().getValue(ses$+"_SERVLET_PARAMETERS",err=*next) - -if debug then System.out.println("Got auth header: "+authtype$+" "+auth$) -authtype$=cvs(authtype$,4) - -if authtype$="BASIC" then - auth$=java.util.Base64.getDecoder().decode(auth$) - user$=auth$(1,pos(":"=auth$)-1) - password$=auth$(pos(":"=auth$)+1) -fi - -if authtype$="BEARER" then - jwt$=auth$ -fi - -authenticated=0 - -rem changing the string encoding to the server's encoding -user$ = new String(user$,"utf-8").getBytes(info(1,2)) -password$ = new String(password$,"utf-8").getBytes(info(1,2)) - -authpgm$="authenticate.bbj" -if servletParams!.get("REST_AUTHPGM") <> null() then - authpgm$ = servletParams!.get("REST_AUTHPGM").toString() -endif - -call authpgm$ - -requestSemaphore! = BBjAPI().getGlobalNamespace().getValue(ses$+"_REQUEST_SEM") -responseSemaphore! = BBjAPI().getGlobalNamespace().getValue(ses$+"_RESPONSE_SEM") - -done_login: - - -timeout=60 -if servletParams!.containsKey("REST_TIMEOUT") then - timeout=num(servletParams!.get("REST_TIMEOUT").toString(),err=*next) -endif - -main_loop: - - CLEAR EXCEPT user$, ses$, requestSemaphore!, responseSemaphore!, ses!, authenticated, timeout, usecount, debug, authpgm$, servletParams! - - - seterr execerr - - dummy$=STBL("!SESSIONINFO",ses$+" - idle "+str(usecount)) - - rem requestSemaphore!.acquire() - if !requestSemaphore!.tryAcquire(1,timeout,java.util.concurrent.TimeUnit.SECONDS) then - rem a timeout has occurred while trying to acquire the semaphore - - rem remove the sessions' namespace values - namespace! = BBjAPI().getGlobalNamespace() - namespace!.removeValue(ses$+"_REQUEST") - namespace!.removeValue(ses$+"_RESPONSE") - namespace!.removeValue(ses$+"_REQUEST_SEM") - namespace!.removeValue(ses$+"_RESPONSE_SEM") - namespace!.removeValue(ses$+"_SERVLET_PARAMETERS") - - rem Calling the ON_CLEANUP label to perform possible user defined cleanup operations - call authpgm$+"::ON_CLEANUP",err=*next - - release - fi - - request!=BBjAPI().getGlobalNamespace().getValue(ses$+"_REQUEST") - if (str(request!) = "PING") then - responseSemaphore!.release() - goto main_loop - fi - - call authpgm$+"::ON_REQUEST",err=*next - - if debug then System.out.println("REST: remote session running "+ses$) - dummy$=STBL("!SESSIONINFO",ses$+" - working "+str(request!)) - - response! = new HashMap() - params! = new HashMap() - - if request!.get("uri") = null() then - statuscode=404 - throw "Missing BC",12 - endif - - vec! = request!.get("preferredlocales") - if vec! <> null() and vec!.size() then - void$ = stbl("!LOCALE",vec!.getItem(0).getLanguage()) - endif - - uri$=request!.get("uri") - uri$=uri$(2) - if pos("/"=uri$)>0 - bc$=uri$(1,pos("/"=uri$)-1) - uri$=uri$(pos("/"=uri$)+1) - sel$=uri$ - else - bc$=uri$ - sel$="" - fi - - if cvs(bc$,3) = "" then - statuscode=404 - throw "Missing BC",12 - endif - - ns! = BBjAPI().getNamespace("RestBCAdapter_"+ses$,"BCList",1) - bcMap! = ns!.getValue("BCMAP",err=*next) - if bcMap! = null() then - bcMap! = new HashMap() - ns!.setValue("BCMAP",bcMap!) - endif - - if bc$="Token" then - rs! = new ResultSet() - token_rec! = new DataRow() - - rem token_rec! should be created in the customizable authpgm - call authpgm$+"::ISSUE_JWT" - - rs!.add(token_rec!) - response!.put("resultset",rs!) - response!.put("BC","Token") - response!.put("single",1) - goto send_response - fi - - - bc$=bc$+"BC" - if bcMap!.containsKey(bc$) then - bc! = bcMap!.get(bc$) - else - if servletParams!.containsKey("REST_PGM_PREFIX") then - prefix$ = servletParams!.get("REST_PGM_PREFIX") - void$ = stbl("REST_PGM_PREFIX", prefix$) - endif - - if servletParams!.containsKey("REST_PGM_SUFFIX") then - suffix$ = servletParams!.get("REST_PGM_SUFFIX") - void$ = stbl("REST_PGM_SUFFIX", suffix$) - endif - - bc! = null() - bc! = eval("new ::"+prefix$+bc$+suffix$+"::"+bc$+"()") - bcMap!.put(bc$,bc!) - endif - - rem Determine primary key field(s) - ar! = bc!.getAttributesRecord() - it! = ar!.getFieldNames().iterator() - while it!.hasNext() - f$=it!.next() - if ar!.getFieldAttribute(f$,"EDITABLE")="2" then - filterf$=filterf$+"/"+f$ - fi - wend - if filterf$ > "" then - filterf$ = filterf$(2) - endif - - - method$ = request!.get("method") - switch method$ - case "POST" - if request!.get("invoke") <> null() then - invoke$ = request!.get("invoke") - dr! = DataRow.fromJson(request!.get("body")) - if dr! <> null() and dr!.getColumnCount() > 0 then - variableNamePrefix! = new String(user$) - variableNamePrefix! = variableNamePrefix!.replaceAll("\W", "_") - - it! = dr!.getFieldNames().iterator() - while it!.hasNext() - f$ = it!.next() - execute variableNamePrefix!+f$ + "! = dr!.getFieldValue("""+f$+""")" - ex$ = ex$ + "," + variableNamePrefix! + f$ + "!" - wend - - ex$ = ex$(2) - endif - ex$ = "bc!."+invoke$+"("+ex$+")" - if request!.get("retvarname") <> null() then - retvar$ = request!.get("retvarname") - ex$ = "var! = " + ex$ - endif - execute ex$ - if retvar$ <> "" then - if var!.getClass().getName() = "com.basiscomponents.db.ResultSet" then - rs! = var! - else - rs! = new ResultSet() - if var!.getClass().getName() = "com.basiscomponents.db.DataRow" then - rs!.add(var!) - else - retdr! = new DataRow() - class$=var!.getClass().getName() - if class$ = "java.util.HashMap" then - retdr! = new DataRow(var!) - else - if class$ = "java.lang.String" or class$ = "java.lang.Boolean" or pos("BBjNumber"=class$) or pos("BBjVector"=class$) then - retdr!.setFieldValue(retvar$,var!) - endif - endif - rs!.add(retdr!) - endif - endif - - response!.put("resultset",rs!) - else - response!.put("resultset","") - response!.put("statuscode","204") - endif - response!.put("request",str(request!)) - response!.put("BC",bc$) - response!.put("sel",sel$) - response!.put("primarykey",filterf$) - else - errorOccurred=0 - rs! = new ResultSet() - b1$=request!.get("body") - System.out.println(b1$) - if b1$>"" and b1$(1,1)<>"[" then - b1$="["+b1$+"]" - fi - System.out.println(b1$) - res! = ResultSet.fromJson(b1$) - k! = java.util.Arrays.asList(new String(filterf$).split("/")) - v! = java.util.Arrays.asList(new String(sel$).split("/",-1)) - it! = res!.iterator() - while it!.hasNext() - dr! = it!.next() - for i=0 to min(k!.size(),v!.size())-1 - if !dr!.contains(k!.get(i)) then - dr!.setFieldValue(k!.get(i),v!.get(i)) - endif - next i - - ok=0; dr! = bc!.write(dr!,err=*next); ok=1 - if !ok then - errorOccurred=1 - response!.put("statuscode","409") - response!.put("errorcode",str(err)) - response!.put("errormsg",errmes(-1)) - rem throw errmes(-1),err - else - rs!.addItem(dr!) - created! = dr!.getAttribute("CREATED") - if !errorOccurred then - if created! <> null() and created!.equals("true") then - response!.put("statuscode","201") - else - response!.put("statuscode","200") - endif - endif - endif - wend - - response!.put("resultset",rs!) - response!.put("request",str(request!)) - response!.put("BC",bc$) - response!.put("sel",sel$) - response!.put("primarykey",filterf$) - response!.put("single",rs!.size()>1) - endif - break - - case "DELETE" - case "PUT" - if method$ = "PUT" and cvs(sel$,4) = "IGNOREKEYS" then - dr! = DataRow.fromJson(request!.get("body")) - else - if sel$ = "" or filterf$ = "" then - throw "Missing resource ID",999 - endif - dr! = DataRow.fromJson(request!.get("body")) - k! = java.util.Arrays.asList(new String(filterf$).split("/")) - v! = java.util.Arrays.asList(new String(sel$).split("/",-1)) - if v!.size() < k!.size() then - throw "Not enough parameters for "+method$,999 - endif - for i=0 to k!.size()-1 - if !dr!.contains(k!.get(i)) then - dr!.setFieldValue(k!.get(i),v!.get(i)) - else - if dr!.getFieldAsString(k!.get(i)) <> v!.get(i) then - throw "Different resource ID in URL path and request body!",999 - endif - endif - next i - endif - - rs! = new ResultSet() - if method$ = "PUT" then - dr! = bc!.write(dr!,err=*next); ok=1 - if !ok then - response!.put("statuscode","409") - throw errmes(-1),err - else - created! = dr!.getAttribute("CREATED") - if created! <> null() and created!.equals("true") then - response!.put("statuscode","201") - else - response!.put("statuscode","200") - endif - response!.put("single",1) - endif - rs!.addItem(dr!) - else - bc!.remove(dr!) - response!.put("statuscode","204") - endif - - response!.put("resultset",rs!) - response!.put("request",str(request!)) - response!.put("BC",bc$) - response!.put("sel",sel$) - response!.put("primarykey",filterf$) - break - - case default - params! = request!.get("params",err=*next) - - if sel$ = "_meta" then - rs! = new ResultSet() - rs!.add(bc!.getAttributesRecord()) - response!.put("resultset",rs!) - response!.put("BC",bc$) - response!.put("sel",sel$) - response!.put("single",1) - - goto send_response - endif - - filter! = new DataRow() - response!.put("single",0) - k! = java.util.Arrays.asList(new String(filterf$).split("/")) - v! = java.util.Arrays.asList(new String(sel$).split("/",-1)) - - rem Add fields from URI - if sel$ > "" then - if filterf$>"" then - filter! = new DataRow() - for i=0 to min(v!.size(),k!.size())-1 - filter!.setFieldValue(k!.get(i),v!.get(i)) - next i - response!.put("linkfield",filterf$) - if k!.size() = v!.size() then - response!.put("single",1) - endif - else - statuscode=500 - throw "BC has no filter",999 - fi - fi - - rem iterate params to fill in [[var]]=value into param=[[var]] - if params! <> null() and params!.size() >0 then - it! = params!.keySet().iterator() - while it!.hasNext() - p$=it!.next() - v$=params!.get(p$) - if len(v$)>4 and v$(1,2)="[[" then - x!=params!.get(v$,err=*next) - params!.put(p$,str(x!)) - fi - wend - fi - - rem Add parameters - if params! <> null() and params!.size() >0 then - if filter! = null() then - filter! = new DataRow() - endif - - af! = ar! - if servletParams!.containsKey("USE_GET_ALLOWED_FILTER") and servletParams!.get("USE_GET_ALLOWED_FILTER").toString().equals("true") then - af! = bc!.getAllowedFilter(err=*next) - endif - - REM check the field case insensitive - REM but pass them with the correct casing to the filter - afnames! = af!.getFieldNames() - afnames_uc! = new BBjVector() - it! = afnames!.iterator() - while it!.hasNext() - afnames_uc!.addItem(cvs(str(it!.next()),4)) - wend - - it! = params!.keySet().iterator() - while it!.hasNext() - p$=it!.next() - pv$=params!.get(p$) - if (p$="_FULLTEXT" OR P$="_SEARCH") - filter!.setFieldValue("%SEARCH",pv$) - else - if (p$(1,1)<>"_" and pv$>"" and (afnames_uc!.contains(p$) OR bc$="DataSourceDataBC")) OR P$(1,1)="%" then - rem todo: all BCs should accept filters with fields that are not part of the attributes record - rem and still honor all other fields in the filter correctly, instead of giving no result - filter!.setFieldValue(afnames!.getItem(afnames_uc!.indexOf(p$)),pv$) - fi - fi - wend - fi - - if filter! <> null() then - bc!.setFilter(filter!) - fi - - scope!=params!.get("_SCOPE") - fieldsel!=params!.get("_FIELDSEL",err=*next) - - if fieldsel! <> null() AND scope! <> null() then - ok=0 - vec! = new BBjVector(java.util.Arrays.asList(fieldsel!.split(","))) - bc!.setFieldSelection(scope!, vec!,err=*next); ok=1 - if !ok then - if pos("no match for method"=cvs(errmes(-1),8)) then - fs! = new DataRow() - it! = vec!.iterator() - while it!.hasNext() - fs!.setFieldValue(it!.next(),"") - wend - bc!.setFieldSelection(scope!, fs!) - else - throw errmes(-1),err() - fi - fi - else - if fieldsel! <> null() - ok=0 - vec! = new BBjVector(java.util.Arrays.asList(fieldsel!.split(","))) - bc!.setFieldSelection(vec!,err=*next); ok=1 - if !ok then - if pos("no match for method"=cvs(errmes(-1),8)) then - fs! = new DataRow() - it! = vec!.iterator() - while it!.hasNext() - fs!.setFieldValue(it!.next(),"") - wend - bc!.setFieldSelection(fs!) - else - throw errmes(-1),err() - fi - fi - fi - if scope! <> null() then - bc!.setScope(str(scope!)) - endif - fi - - first% = 0 - last% = 0 - limitSearch = 0 - - if params! <> null() then - if params!.containsKey("_PAGE") or params!.containsKey("_PER_PAGE") then - page = 1 - page = num(params!.get("_PAGE"),err=*next) - if page < 1 then - throw "Invalid value for _PAGE parameter: must be greater than 0",999 - endif - perPage = num(params!.get("_PER_PAGE"),err=*next) - if perPage < 1 then - throw "Invalid value for _PER_PAGE parameter: must be greater than 0",999 - endif - - first% = (int(page)-1)*int(perPage) - last% = first%+int(perPage)-1 - limitSearch = 1 - endif - - if params!.containsKey("_OFFSET") then - offset = num(params!.get("_OFFSET")) - if offset < 0 then - throw "Invalid parameter for _OFFSET parameter: must be greater than or equals 0",999 - endif - limit = 20 - if params!.containsKey("_LIMIT") then - limit = num(params!.get("_LIMIT")) - endif - if limit < 1 then - throw "Invalid parameter for _LIMIT parameter: must be greater than 0",999 - endif - - first% = int(offset) - last% = first% + int(limit)-1 - limitSearch = 1 - endif - endif - - if len(sel$)>8 and sel$(1,8) = "_lookup/" then - rs! = new ResultSet() - - if filter!<>null() then - rs!.add(filter!) - fi - - field$=sel$(9) - System.out.println(field$) - - rs! = bc!.retrieveLookup(field$,filter!) - - response!.put("resultset",rs!) - response!.put("BC",bc$) - response!.put("single",0) - - goto send_response - endif - - if limitSearch then - rs! = bc!.retrieve(first%,last%) - else - rs! = bc!.retrieve() - endif - - - if params!.containsKey("_ATTACHMENT") then - if rs!.size() =1 then - rec! = rs!.getItem(0) - attachfield$ = params!.get("_ATTACHMENT") - - rs! = new ResultSet() - dr! = new DataRow() - filename$=rec!.getFieldAsString(attachfield$) - dr!.setFieldValue("FILEDELIVERY",filename$) - rs!.addItem(dr!) - - response!.put("resultset",rs!) - response!.put("BC",bc$) - response!.put("single",1) - response!.put("file",filename$) - - goto send_response - else - throw "file / record not found",11 - endif - endif - - response!.put("resultset",rs!) - response!.put("request",str(request!)) - response!.put("BC",bc$) - response!.put("sel",sel$) - response!.put("primarykey",filterf$) - break - swend - - - - send_response: - usecount=usecount+1 - usecount=usecount+1 - BBjAPI().getGlobalNamespace().setValue(ses$+"_RESPONSE",response!) - responseSemaphore!.release() - if debug then System.out.println("REST: remote session done "+ses$) - goto main_loop - - - execerr: - errorcode = err - errormsg$ = errmes(-1) - sw! = new java.io.StringWriter() - pw! = new java.io.PrintWriter(sw!) - BBjAPI().getLastBBjException().printStackTrace(pw!) - stacktrace$ = sw!.toString() - sw!.close() - pw!.close() - - if debug then - ch=unt - open (ch,mode="O_CREATE,O_APPEND",err=notrace)"bridgeerrlog.txt" - print (ch,err=*next)date(0:"%Yl-%Mz-%Dz %Hz:%mz:%sz") - print (ch,err=*next)"!ERROR "+str(err)+" "+stacktrace$ - print (ch,err=*next)errmes(-1) - close (ch,err=*next) - endif - - notrace: - -REM if errormsg$(1,4)="java" then -REM errormsg$=errormsg$(pos(":"=errormsg$)+2) -REM endif - - - error_out: - if statuscode=0 - statuscode=500 - fi - - response! = new HashMap() - - if authenticated>0 then - response!.put("statuscode",str(statuscode)) - response!.put("errorcode",errorcode) - response!.put("errormsg",errormsg$) - rem consider: stack trace only with DEBUG flag in config? - response!.put("stacktrace",stacktrace$) - else - response!.put("statuscode","401") - response!.put("errorcode",errorcode) - response!.put("errormsg",errormsg$) - rem no stack trace for unauthenticated users - fi - - BBjAPI().getGlobalNamespace().setValue(ses$+"_RESPONSE",response!) - responseSemaphore! = BBjAPI().getGlobalNamespace().getValue(ses$+"_RESPONSE_SEM") - responseSemaphore!.release() - - wait 10; rem FIN_WAIT - - namespace! = BBjAPI().getGlobalNamespace() - namespace!.removeValue(ses$+"_REQUEST",err=*next) - namespace!.removeValue(ses$+"_RESPONSE",err=*next) - namespace!.removeValue(ses$+"_REQUEST_SEM",err=*next) - namespace!.removeValue(ses$+"_RESPONSE_SEM",err=*next) - namespace!.removeValue(ses$+"_SERVLET_PARAMETERS",err=*next) - - rem Calling the ON_CLEANUP label to perform possible user defined cleanup operations - call authpgm$+"::ON_CLEANUP",err=*next -release - +use java.util.HashMap +use com.basiscomponents.db.ResultSet +use com.basiscomponents.db.DataRow + +seterr execerr + +debug=0 +debug=num(stbl("DEBUG",err=*next),err=*next) + +if debug then System.out.println("REST: new remote session ") + +BBjAPI().getConfig().setOptionSetting("ERROR_UNWINDS", 1) + +ses$ = argv(1) +authtype$=argv(2) +auth$ = argv(3) + +if debug then System.out.println("REST: WORKDIR "+dir("")) +ses$=stbl("SESSIONID",ses$) + +servletParams! = new HashMap() +servletParams! = BBjAPI().getGlobalNamespace().getValue(ses$+"_SERVLET_PARAMETERS",err=*next) + +if debug then System.out.println("Got auth header: "+authtype$+" "+auth$) +authtype$=cvs(authtype$,4) + +if authtype$="BASIC" then + auth$=java.util.Base64.getDecoder().decode(auth$) + user$=auth$(1,pos(":"=auth$)-1) + password$=auth$(pos(":"=auth$)+1) +fi + +if authtype$="BEARER" then + jwt$=auth$ +fi + +authenticated=0 + +rem changing the string encoding to the server's encoding +user$ = new String(user$,"utf-8").getBytes(info(1,2)) +password$ = new String(password$,"utf-8").getBytes(info(1,2)) + +authpgm$="authenticate.bbj" +if servletParams!.get("REST_AUTHPGM") <> null() then + authpgm$ = servletParams!.get("REST_AUTHPGM").toString() +endif + +call authpgm$ + +requestSemaphore! = BBjAPI().getGlobalNamespace().getValue(ses$+"_REQUEST_SEM") +responseSemaphore! = BBjAPI().getGlobalNamespace().getValue(ses$+"_RESPONSE_SEM") + +done_login: + + +timeout=60 +if servletParams!.containsKey("REST_TIMEOUT") then + timeout=num(servletParams!.get("REST_TIMEOUT").toString(),err=*next) +endif + +main_loop: + + CLEAR EXCEPT user$, ses$, requestSemaphore!, responseSemaphore!, ses!, authenticated, timeout, usecount, debug, authpgm$, servletParams! + + + seterr execerr + + dummy$=STBL("!SESSIONINFO",ses$+" - idle "+str(usecount)) + + rem requestSemaphore!.acquire() + if !requestSemaphore!.tryAcquire(1,timeout,java.util.concurrent.TimeUnit.SECONDS) then + rem a timeout has occurred while trying to acquire the semaphore + + rem remove the sessions' namespace values + namespace! = BBjAPI().getGlobalNamespace() + namespace!.removeValue(ses$+"_REQUEST") + namespace!.removeValue(ses$+"_RESPONSE") + namespace!.removeValue(ses$+"_REQUEST_SEM") + namespace!.removeValue(ses$+"_RESPONSE_SEM") + namespace!.removeValue(ses$+"_SERVLET_PARAMETERS") + + rem Calling the ON_CLEANUP label to perform possible user defined cleanup operations + call authpgm$+"::ON_CLEANUP",err=*next + + release + fi + + request!=BBjAPI().getGlobalNamespace().getValue(ses$+"_REQUEST") + if (str(request!) = "PING") then + responseSemaphore!.release() + goto main_loop + fi + + call authpgm$+"::ON_REQUEST",err=*next + + if debug then System.out.println("REST: remote session running "+ses$) + dummy$=STBL("!SESSIONINFO",ses$+" - working "+str(request!)) + + response! = new HashMap() + params! = new HashMap() + + if request!.get("uri") = null() then + statuscode=404 + throw "Missing BC",12 + endif + + vec! = request!.get("preferredlocales") + if vec! <> null() and vec!.size() then + void$ = stbl("!LOCALE",vec!.getItem(0).getLanguage()) + endif + + uri$=request!.get("uri") + uri$=uri$(2) + if pos("/"=uri$)>0 + bc$=uri$(1,pos("/"=uri$)-1) + uri$=uri$(pos("/"=uri$)+1) + sel$=uri$ + else + bc$=uri$ + sel$="" + fi + + if cvs(bc$,3) = "" then + statuscode=404 + throw "Missing BC",12 + endif + + ns! = BBjAPI().getNamespace("RestBCAdapter_"+ses$,"BCList",1) + bcMap! = ns!.getValue("BCMAP",err=*next) + if bcMap! = null() then + bcMap! = new HashMap() + ns!.setValue("BCMAP",bcMap!) + endif + + if bc$="Token" then + rs! = new ResultSet() + token_rec! = new DataRow() + + rem token_rec! should be created in the customizable authpgm + call authpgm$+"::ISSUE_JWT" + + rs!.add(token_rec!) + response!.put("resultset",rs!) + response!.put("BC","Token") + response!.put("single",1) + goto send_response + fi + + + bc$=bc$+"BC" + if bcMap!.containsKey(bc$) then + bc! = bcMap!.get(bc$) + else + if servletParams!.containsKey("REST_PGM_PREFIX") then + prefix$ = servletParams!.get("REST_PGM_PREFIX") + void$ = stbl("REST_PGM_PREFIX", prefix$) + endif + + if servletParams!.containsKey("REST_PGM_SUFFIX") then + suffix$ = servletParams!.get("REST_PGM_SUFFIX") + void$ = stbl("REST_PGM_SUFFIX", suffix$) + endif + + bc! = null() + bc! = eval("new ::"+prefix$+bc$+suffix$+"::"+bc$+"()") + bcMap!.put(bc$,bc!) + endif + + rem Determine primary key field(s) + ar! = bc!.getAttributesRecord() + it! = ar!.getFieldNames().iterator() + while it!.hasNext() + f$=it!.next() + if ar!.getFieldAttribute(f$,"EDITABLE")="2" then + filterf$=filterf$+"/"+f$ + fi + wend + if filterf$ > "" then + filterf$ = filterf$(2) + endif + + + method$ = request!.get("method") + switch method$ + case "POST" + if request!.get("invoke") <> null() then + invoke$ = request!.get("invoke") + dr! = DataRow.fromJson(request!.get("body")) + if dr! <> null() and dr!.getColumnCount() > 0 then + variableNamePrefix! = new String(user$) + variableNamePrefix! = variableNamePrefix!.replaceAll("\W", "_") + + it! = dr!.getFieldNames().iterator() + while it!.hasNext() + f$ = it!.next() + execute variableNamePrefix!+f$ + "! = dr!.getFieldValue("""+f$+""")" + ex$ = ex$ + "," + variableNamePrefix! + f$ + "!" + wend + + ex$ = ex$(2) + endif + ex$ = "bc!."+invoke$+"("+ex$+")" + if request!.get("retvarname") <> null() then + retvar$ = request!.get("retvarname") + ex$ = "var! = " + ex$ + endif + execute ex$ + if retvar$ <> "" then + if var!.getClass().getName() = "com.basiscomponents.db.ResultSet" then + rs! = var! + else + rs! = new ResultSet() + if var!.getClass().getName() = "com.basiscomponents.db.DataRow" then + rs!.add(var!) + else + retdr! = new DataRow() + class$=var!.getClass().getName() + if class$ = "java.util.HashMap" then + retdr! = new DataRow(var!) + else + if class$ = "java.lang.String" or class$ = "java.lang.Boolean" or pos("BBjString"=class$) or pos("BBjNumber"=class$) or pos("BBjVector"=class$) then + retdr!.setFieldValue(retvar$,var!) + endif + endif + rs!.add(retdr!) + endif + endif + + response!.put("resultset",rs!) + else + response!.put("resultset","") + response!.put("statuscode","204") + endif + response!.put("request",str(request!)) + response!.put("BC",bc$) + response!.put("sel",sel$) + response!.put("primarykey",filterf$) + else + errorOccurred=0 + rs! = new ResultSet() + b1$=request!.get("body") + System.out.println(b1$) + if b1$>"" and b1$(1,1)<>"[" then + b1$="["+b1$+"]" + fi + System.out.println(b1$) + res! = ResultSet.fromJson(b1$) + k! = java.util.Arrays.asList(new String(filterf$).split("/")) + v! = java.util.Arrays.asList(new String(sel$).split("/",-1)) + it! = res!.iterator() + while it!.hasNext() + dr! = it!.next() + for i=0 to min(k!.size(),v!.size())-1 + if !dr!.contains(k!.get(i)) then + dr!.setFieldValue(k!.get(i),v!.get(i)) + endif + next i + + ok=0; dr! = bc!.write(dr!,err=*next); ok=1 + if !ok then + errorOccurred=1 + response!.put("statuscode","409") + response!.put("errorcode",str(err)) + response!.put("errormsg",errmes(-1)) + rem throw errmes(-1),err + else + rs!.addItem(dr!) + created! = dr!.getAttribute("CREATED") + if !errorOccurred then + if created! <> null() and created!.equals("true") then + response!.put("statuscode","201") + else + response!.put("statuscode","200") + endif + endif + endif + wend + + response!.put("resultset",rs!) + response!.put("request",str(request!)) + response!.put("BC",bc$) + response!.put("sel",sel$) + response!.put("primarykey",filterf$) + response!.put("single",rs!.size()>1) + endif + break + + case "DELETE" + case "PUT" + if method$ = "PUT" and cvs(sel$,4) = "IGNOREKEYS" then + dr! = DataRow.fromJson(request!.get("body")) + else + if sel$ = "" or filterf$ = "" then + throw "Missing resource ID",999 + endif + dr! = DataRow.fromJson(request!.get("body")) + k! = java.util.Arrays.asList(new String(filterf$).split("/")) + v! = java.util.Arrays.asList(new String(sel$).split("/",-1)) + if v!.size() < k!.size() then + throw "Not enough parameters for "+method$,999 + endif + for i=0 to k!.size()-1 + if !dr!.contains(k!.get(i)) then + dr!.setFieldValue(k!.get(i),v!.get(i)) + else + if dr!.getFieldAsString(k!.get(i)) <> v!.get(i) then + throw "Different resource ID in URL path and request body!",999 + endif + endif + next i + endif + + rs! = new ResultSet() + if method$ = "PUT" then + dr! = bc!.write(dr!,err=*next); ok=1 + if !ok then + response!.put("statuscode","409") + throw errmes(-1),err + else + created! = dr!.getAttribute("CREATED") + if created! <> null() and created!.equals("true") then + response!.put("statuscode","201") + else + response!.put("statuscode","200") + endif + response!.put("single",1) + endif + rs!.addItem(dr!) + else + bc!.remove(dr!) + response!.put("statuscode","204") + endif + + response!.put("resultset",rs!) + response!.put("request",str(request!)) + response!.put("BC",bc$) + response!.put("sel",sel$) + response!.put("primarykey",filterf$) + break + + case default + params! = request!.get("params",err=*next) + + if sel$ = "_meta" then + rs! = new ResultSet() + rs!.add(bc!.getAttributesRecord()) + response!.put("resultset",rs!) + response!.put("BC",bc$) + response!.put("sel",sel$) + response!.put("single",1) + + goto send_response + endif + + filter! = new DataRow() + response!.put("single",0) + k! = java.util.Arrays.asList(new String(filterf$).split("/")) + v! = java.util.Arrays.asList(new String(sel$).split("/",-1)) + + rem Add fields from URI + if sel$ > "" then + if filterf$>"" then + filter! = new DataRow() + for i=0 to min(v!.size(),k!.size())-1 + filter!.setFieldValue(k!.get(i),v!.get(i)) + next i + response!.put("linkfield",filterf$) + if k!.size() = v!.size() then + response!.put("single",1) + endif + else + statuscode=500 + throw "BC has no filter",999 + fi + fi + + rem iterate params to fill in [[var]]=value into param=[[var]] + if params! <> null() and params!.size() >0 then + it! = params!.keySet().iterator() + while it!.hasNext() + p$=it!.next() + v$=params!.get(p$) + if len(v$)>4 and v$(1,2)="[[" then + x!=params!.get(v$,err=*next) + params!.put(p$,str(x!)) + fi + wend + fi + + rem Add parameters + if params! <> null() and params!.size() >0 then + if filter! = null() then + filter! = new DataRow() + endif + + af! = ar! + if servletParams!.containsKey("USE_GET_ALLOWED_FILTER") and servletParams!.get("USE_GET_ALLOWED_FILTER").toString().equals("true") then + af! = bc!.getAllowedFilter(err=*next) + endif + + REM check the field case insensitive + REM but pass them with the correct casing to the filter + afnames! = af!.getFieldNames() + afnames_uc! = new BBjVector() + it! = afnames!.iterator() + while it!.hasNext() + afnames_uc!.addItem(cvs(str(it!.next()),4)) + wend + + it! = params!.keySet().iterator() + while it!.hasNext() + p$=it!.next() + pv$=params!.get(p$) + if (p$="_FULLTEXT" OR P$="_SEARCH") + filter!.setFieldValue("%SEARCH",pv$) + else + if (p$(1,1)<>"_" and pv$>"" and (afnames_uc!.contains(p$) OR bc$="DataSourceDataBC")) OR P$(1,1)="%" then + rem todo: all BCs should accept filters with fields that are not part of the attributes record + rem and still honor all other fields in the filter correctly, instead of giving no result + filter!.setFieldValue(afnames!.getItem(afnames_uc!.indexOf(p$)),pv$) + fi + fi + wend + fi + + if filter! <> null() then + bc!.setFilter(filter!) + fi + + scope!=params!.get("_SCOPE") + fieldsel!=params!.get("_FIELDSEL",err=*next) + + if fieldsel! <> null() AND scope! <> null() then + ok=0 + vec! = new BBjVector(java.util.Arrays.asList(fieldsel!.split(","))) + bc!.setFieldSelection(scope!, vec!,err=*next); ok=1 + if !ok then + if pos("no match for method"=cvs(errmes(-1),8)) then + fs! = new DataRow() + it! = vec!.iterator() + while it!.hasNext() + fs!.setFieldValue(it!.next(),"") + wend + bc!.setFieldSelection(scope!, fs!) + else + throw errmes(-1),err() + fi + fi + else + if fieldsel! <> null() + ok=0 + vec! = new BBjVector(java.util.Arrays.asList(fieldsel!.split(","))) + bc!.setFieldSelection(vec!,err=*next); ok=1 + if !ok then + if pos("no match for method"=cvs(errmes(-1),8)) then + fs! = new DataRow() + it! = vec!.iterator() + while it!.hasNext() + fs!.setFieldValue(it!.next(),"") + wend + bc!.setFieldSelection(fs!) + else + throw errmes(-1),err() + fi + fi + fi + if scope! <> null() then + bc!.setScope(str(scope!)) + endif + fi + + first% = 0 + last% = 0 + limitSearch = 0 + + if params! <> null() then + if params!.containsKey("_PAGE") or params!.containsKey("_PER_PAGE") then + page = 1 + page = num(params!.get("_PAGE"),err=*next) + if page < 1 then + throw "Invalid value for _PAGE parameter: must be greater than 0",999 + endif + perPage = num(params!.get("_PER_PAGE"),err=*next) + if perPage < 1 then + throw "Invalid value for _PER_PAGE parameter: must be greater than 0",999 + endif + + first% = (int(page)-1)*int(perPage) + last% = first%+int(perPage)-1 + limitSearch = 1 + endif + + if params!.containsKey("_OFFSET") then + offset = num(params!.get("_OFFSET")) + if offset < 0 then + throw "Invalid parameter for _OFFSET parameter: must be greater than or equals 0",999 + endif + limit = 20 + if params!.containsKey("_LIMIT") then + limit = num(params!.get("_LIMIT")) + endif + if limit < 1 then + throw "Invalid parameter for _LIMIT parameter: must be greater than 0",999 + endif + + first% = int(offset) + last% = first% + int(limit)-1 + limitSearch = 1 + endif + endif + + if len(sel$)>8 and sel$(1,8) = "_lookup/" then + rs! = new ResultSet() + + if filter!<>null() then + rs!.add(filter!) + fi + + field$=sel$(9) + System.out.println(field$) + + rs! = bc!.retrieveLookup(field$,filter!) + + response!.put("resultset",rs!) + response!.put("BC",bc$) + response!.put("single",0) + + goto send_response + endif + + if limitSearch then + rs! = bc!.retrieve(first%,last%) + else + rs! = bc!.retrieve() + endif + + + if params!.containsKey("_ATTACHMENT") then + if rs!.size() =1 then + rec! = rs!.getItem(0) + attachfield$ = params!.get("_ATTACHMENT") + + rs! = new ResultSet() + dr! = new DataRow() + filename$=rec!.getFieldAsString(attachfield$) + dr!.setFieldValue("FILEDELIVERY",filename$) + rs!.addItem(dr!) + + response!.put("resultset",rs!) + response!.put("BC",bc$) + response!.put("single",1) + response!.put("file",filename$) + + goto send_response + else + throw "file / record not found",11 + endif + endif + + response!.put("resultset",rs!) + response!.put("request",str(request!)) + response!.put("BC",bc$) + response!.put("sel",sel$) + response!.put("primarykey",filterf$) + break + swend + + + + send_response: + usecount=usecount+1 + usecount=usecount+1 + BBjAPI().getGlobalNamespace().setValue(ses$+"_RESPONSE",response!) + responseSemaphore!.release() + if debug then System.out.println("REST: remote session done "+ses$) + goto main_loop + + + execerr: + errorcode = err + errormsg$ = errmes(-1) + sw! = new java.io.StringWriter() + pw! = new java.io.PrintWriter(sw!) + BBjAPI().getLastBBjException().printStackTrace(pw!) + stacktrace$ = sw!.toString() + sw!.close() + pw!.close() + + if debug then + ch=unt + open (ch,mode="O_CREATE,O_APPEND",err=notrace)"bridgeerrlog.txt" + print (ch,err=*next)date(0:"%Yl-%Mz-%Dz %Hz:%mz:%sz") + print (ch,err=*next)"!ERROR "+str(err)+" "+stacktrace$ + print (ch,err=*next)errmes(-1) + close (ch,err=*next) + endif + + notrace: + +REM if errormsg$(1,4)="java" then +REM errormsg$=errormsg$(pos(":"=errormsg$)+2) +REM endif + + + error_out: + if statuscode=0 + statuscode=500 + fi + + response! = new HashMap() + + if authenticated>0 then + response!.put("statuscode",str(statuscode)) + response!.put("errorcode",errorcode) + response!.put("errormsg",errormsg$) + rem consider: stack trace only with DEBUG flag in config? + response!.put("stacktrace",stacktrace$) + else + response!.put("statuscode","401") + response!.put("errorcode",errorcode) + response!.put("errormsg",errormsg$) + rem no stack trace for unauthenticated users + fi + + BBjAPI().getGlobalNamespace().setValue(ses$+"_RESPONSE",response!) + responseSemaphore! = BBjAPI().getGlobalNamespace().getValue(ses$+"_RESPONSE_SEM") + responseSemaphore!.release() + + wait 10; rem FIN_WAIT + + namespace! = BBjAPI().getGlobalNamespace() + namespace!.removeValue(ses$+"_REQUEST",err=*next) + namespace!.removeValue(ses$+"_RESPONSE",err=*next) + namespace!.removeValue(ses$+"_REQUEST_SEM",err=*next) + namespace!.removeValue(ses$+"_RESPONSE_SEM",err=*next) + namespace!.removeValue(ses$+"_SERVLET_PARAMETERS",err=*next) + + rem Calling the ON_CLEANUP label to perform possible user defined cleanup operations + call authpgm$+"::ON_CLEANUP",err=*next +release + diff --git a/RestBridge.bbj b/RestBridge.bbj index 6b24931..e9d626d 100644 --- a/RestBridge.bbj +++ b/RestBridge.bbj @@ -1,1029 +1,1051 @@ -use java.util.HashMap -use com.basiscomponents.db.ResultSet - -class public RestBridge - - field public static BBjString LOGTPL$="ID:C(16*),METHOD:C(1*),START:N(1*),END:N(1*),DURATION:N(1*),ADDR:C(1*),URL:C(1*),URI:C(1*),QUERY:C(1*),HEADERS:C(1*),PARAMS:C(1*),STATUS:C(1*)" - - METHOD PUBLIC void service(BBjspServletContext context!) - - declare BBjspWebRequest request! - declare BBjspWebResponse response! - - request! = context!.getRequest() - response! = context!.getResponse() - - debug = num(stbl("DEBUG",err=*next),err=*next) - restbridge_opt_jsonmeta=1 - restbridge_opt_jsonmeta=int(num(stbl("RESTBRIDGE_OPT_JSONMETA",err=*next),err=*next)) - - restbridge_opt_enablegzip=1 - restbridge_opt_enablegzip=int(num(stbl("RESTBRIDGE_OPT_ENABLEGZIP",err=*next),err=*next)) - - if debug then - System.out.println("REST request --------------------------") - System.out.println("REST request METHOD "+request!.getMethod()) - System.out.println("REST request HEADER "+request!.getRequestURL()) - System.out.println("REST request end -----------------------") - fi - - param! = context!.getInitParameter("REST_REQUESTLOG") - if param! <> null() then - void$ = stbl("REST_REQUESTLOG",param!) - endif - - req_id$ = #logRequest(request!) - - if request!.getHeader("Origin") <> null() then - response!.setHeader("Access-Control-Allow-Origin",request!.getHeader("Origin")) - else - response!.setHeader("Access-Control-Allow-Origin","*") - endif - response!.setHeader("Access-Control-Allow-Credentials","true") - response!.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS") - response!.setHeader("Access-Control-Allow-Headers",request!.getHeader("Access-Control-Request-Headers")) - - - files! = request!.getFileUploads() - if (files! <> null()) then - sz = files!.size() - if sz then - declare BBjFileUpload uploadFile! - hm_resp! = new HashMap() - for i=0 to sz-1 - uploadFile! = cast(BBjFileUpload,files!.get(i)) - if (debug) then - System.out.println(str("Field:" + uploadFile!.getFieldName())) - System.out.println(str("- Name:"+ uploadFile!.getOriginalName())) - System.out.println(str("- Temp Name:"+ uploadFile!.getTempName())) - System.out.println(str("- Type:"+ uploadFile!.getContentType())) - System.out.println(str("- Size:")) - System.out.println(str(uploadFile!.getContentLength())) - System.out.println(str("------------------------")) - fi - - tmpname$= uploadFile!.getTempName() - newname!=tmpname$ - - oname$=str(uploadFile!.getOriginalName()) - if oname$<>"" And oname$<>"null" then - newname$ = newname!.replace("\","/") - newname$=newname$(1,pos("/"=newname$,1,pos("/"=newname$,1,0))) - newname$=newname$+str(System.currentTimeMillis())+"/" - mkdir newname$ - newname$=newname$+uploadFile!.getOriginalName() - rename tmpname$ TO newname$ - hm_resp!.put(uploadFile!.getFieldName(),newname$) - fi - next i - - resp$="" - it! = hm_resp!.keySet().iterator() - while it!.hasNext() - x$=it!.next() - x1$=hm_resp!.get(x$) - if resp$>"" then - resp$=resp$+"," - fi - resp$=resp$+""""+x$+""":"""+x1$+"""" - wend - - response!.getOutputStream().write("{"+resp$+"}") - response!.setStatus(200) - #logResponse(req_id$,response!) - methodret - fi - fi - - - req! = new HashMap() - - switch request!.getMethod() - case "GET" - method$ = "GET" - break - case "OPTIONS" - response!.setStatus(200) - response!.setHeader("Access-Control-Max-Age","600") - #logResponse(req_id$,response!) - methodret - break - case "DELETE" - case "PUT" - method$ = request!.getMethod() - rem Only JSON is supported for now - if request!.getContentType() <> null() AND cvs(request!.getContentType(),8) <> "application/json" then - s! = response!.getOutputStream() - response!.sendError(415,"Unsupported media type """+request!.getContentType()+"""") - endif - break - case "POST" - method$ = "POST" - if request!.getHeader("ExecuteBCMethod") <> null() then - req!.put("invoke",request!.getHeader("ExecuteBCMethod")) - if request!.getHeader("BCReturnVarName") <> null() then - req!.put("retvarname",request!.getHeader("BCReturnVarName")) - endif - endif - break - case default - response!.setContentType("text/plain") - s! = response!.getOutputStream() - response!.sendError(501,"Unsupported HTTP method """+request!.getMethod()+"""") - #logResponse(req_id$,response!) - methodret - break - swend - - - - token$=request!.getParameter("_TOKEN") - if token$>"" then - auth$="Basic "+token$ - else - auth$=str(request!.getHeader("authorization",err=*next)) - fi - - if cvs(request!.getParameter("grant_type"),4) = "PASSWORD" then - user$=request!.getParameter("username") - password$=request!.getParameter("password") - auth$="Basic "+java.util.Base64.getEncoder().encode(user$+":"+password$) - rem we're using the Basic authentication way to pass username and password to the Adapter - rem so that the "usual" login can be used to check the credentials - fi - - if auth$="null" or len(auth$)<8 OR (cvs(auth$(1,5),4)<>"BASIC" AND cvs(auth$(1,6),4)<>"BEARER")then - tmp$=str(request!.getHeader("X-REQUESTED-WITH",err=*next)) - if tmp$<> "XMLHttpRequest" then - response!.setHeader("WWW-Authenticate","Basic realm=""REST Web Service""") - fi - response!.sendError(401,"Authentication required") - #logResponse(req_id$,response!) - methodret - else - rem create uid$ as a unique representant of the user - rem this needs to contain the config file and the prefix! - uid$ = hta(java.security.MessageDigest.getInstance("MD5").digest(auth$+BBjAPI().getConfig().getCurrentCommandLineObject().getConfigFile()+pfx)) - fi - - - ses_list! = BBjAPI().getGlobalNamespace().getValue(uid$+"_list",err=*next) - if ses_list! = null() then - BBjAPI().getGlobalNamespace().setValue(uid$+"_list",new java.util.Stack()) - ses_list! = BBjAPI().getGlobalNamespace().getValue(uid$+"_list") - endif - - - while 1 - if (ses_list!.empty()) - servletParams! = #getServletParameters(context!) - if !servletParams!.containsKey("REST_WD") then - goto setup_err - endif - if !servletParams!.containsKey("REST_ADAPTERPGM") then - goto setup_err - endif - - ses$=#newSession(auth$,servletParams!) - break - else - ses$=ses_list!.pop() - if (#checkSession(ses$)) then - break - endif - endif - wend - - params! = new HashMap() - it! = request!.getParameterNames().iterator() - while it!.hasNext() - p$=it!.next() - params!.put(cvs(p$,4),request!.getParameter(p$)) - wend - - uri!=request!.getPathInfo() - if uri! <> null() and uri!.lastIndexOf("/_output_") <> -1 then - uri! = uri!.substring(0,uri!.lastIndexOf("/_output_")) - fi - - req!.put("method",method$) - req!.put("uri",uri!) - req!.put("params",params!) - req!.put("body",request!.getBody(err=*next)) - req!.put("preferredlocales",request!.getLocales()) - - if str(uri!)="/admin/requestlog" then - answer! = #getRequestLog(request!) - else - answer!=#invoke(ses$,req!) - fi - ses_list!.push(ses$) - - accept$=str(params!.get("_ACCEPT")) - if accept$="null" then - accept$=str(request!.getHeader("Accept")) - endif - if accept$="null" then - accept$=str(request!.getHeader("Content-Type")) - if accept$="null" then - accept$="text/html" - fi - fi - - accept_enc$=str(request!.getHeader("Accept-Encoding")) - if pos("gzip"=accept_enc$) > 0 then - do_gzip=1 - fi - - rem check for multi-value accept headers - atmp$=accept$ - alist!=new java.util.ArrayList() - alist!.addAll(java.util.Arrays.asList(new String(accept$).split(","))) - accept$ = "" - it! = alist!.iterator() - while it!.hasNext() - accept$ = it!.next() - if mask(accept$,"^debug|^text/html|^application/json|^text/csv|^text/plain|^application/xml|^*/*|^text/xml|^application/xls") then - if pos(";"=accept$) then - accept$=cvs(accept$(1,pos(";"=accept$)-1),3) - endif - break - endif - wend - - if accept$ = "" then - if debug then - System.out.println("REST: error 406 Unsupported content type requested in Accept header: "+atmp$) - fi - response!.sendError(406, "Unsupported content type requested in Accept header: "+atmp$) - #logResponse(req_id$,response!) - methodret - fi - - if debug then - System.out.println("REST Accept: "+accept$) - fi - - statuscode! = answer!.get("statuscode",err=*next) - errormsg! = answer!.get("errormsg",err=*next) - errorcode$ = str(answer!.get("errorcode")) - - blobdata$=str(params!.get("_BLOBDATA")) - System.out.println(params!) - System.out.println("BLOBDATA : "+blobdata$) - if blobdata$<>"null" then - rs! = answer!.get("resultset",err=*next) - if rs! = null() or rs!.size()<>1 or !rs!.getItem(0).getFieldNames().contains(blobdata$) then - goto blob_err - fi - - blobname$=str(params!.get("_BLOBNAME")) - if blobname$="null" then - blobname$="attachment.dat" - fi - if pos("."=blobname$)>0 then - ext$=blobname$(pos("."=blobname$,1,pos("."=blobname$,1,0))+1) - fi - d$=System.getProperty("basis.cacheDirectory")+"/_output_/" - mkdir d$,err=*next - - wr! = new java.io.StringWriter() - f! = java.io.File.createTempFile("output_", ext$, new java.io.File(d$)) - ch=unt - open (ch)str(f!.toPath()) - write (ch)rs!.getItem(0).getFieldAsString(blobdata$,err=blob_err) - close (ch) - - java.nio.file.Files.copy(f!.toPath(), response!.getOutputStream()) - f!.delete() - - response!.setContentType("application/"+ext$) - response!.setHeader("Content-Disposition","inline; filename="""+blobname$+"""") - - #logResponse(req_id$,response!) - methodret - - blob_err: - response!.getOutputStream().write("BLOB not found") - response!.setStatus(404) - #logResponse(req_id$,response!) - methodret - endif - - - if answer!.containsKey("file") then - file$ = answer!.get("file") - - tryagain: - - ch=unt - open (ch,err=filenotfund)file$ - close (ch) - System.out.println(file$) - fullPath$ = BBjAPI().getFileSystem().resolvePath(file$) - System.out.println(fullPath$) - - filename$=fullPath$ - if (pos("/"=filename$)>0) then - filename$=filename$(pos("/"=filename$,1,pos("/"=filename$,1,0))+1) - fi - if (pos("\"=filename$)>0) then - filename$=filename$(pos("\"=filename$,1,pos("\"=filename$,1,0))+1) - fi - - ext$="dat" - - if pos("."=filename$)>0 then - ext$=filename$(pos("."=filename$,1,pos("."=filename$,1,0))+1) - fi - - f! = new java.io.File(fullPath$) - java.nio.file.Files.copy(f!.toPath(), response!.getOutputStream()) - - response!.setContentType("application/"+ext$) - response!.setHeader("Content-Disposition","inline; filename="""+filename$+"""") - - goto done_file - - filenotfund: - System.out.println("not found") - - response!.getOutputStream().write("file not found!") - response!.setStatus(404) - - done_file: - #logResponse(req_id$,response!) - methodret - endif - - if answer!.containsKey("stacktrace") then - stacktrace$ = answer!.get("stacktrace") - endif - - if statuscode! <> null() and !mask(statuscode!,"20\d") then - rem System.out.println("REST: error "+str(statuscode!)+" - "+str(errormsg!)) - if pos("application/json"=accept$) > 0 then - response!.setStatus(num(statuscode!)) - response!.setContentType("application/json") - rs! = answer!.get("resultset",err=*next) - if method$ = "POST" and rs! <> null() and rs!.size() > 0 then - wr! = new java.io.StringWriter() - com.basiscomponents.db.ResultSetExporter.writeJSON(rs!,wr!,restbridge_opt_jsonmeta) - wr!.flush() - wr!.close() - response!.getOutputStream().write(wr!.toString()) - #logResponse(req_id$,response!) - else - e$ = "{""code"":"""+str(errorcode$)+""",""message"":"""+org.apache.commons.lang.StringEscapeUtils.escapeJavaScript(errormsg!)+"""," - if debug and statuscode! <> "401" then - e$ = e$ + """stacktrace"":"""+org.apache.commons.lang.StringEscapeUtils.escapeJavaScript(stacktrace$)+"""," - endif - e$ = e$ + """ses"":"""+ses$+"""}" - response!.getOutputStream().write(e$) - endif - else - response!.setContentType("text/html") - s! = response!.getOutputStream() - s!.write("
Problem accessing "+request!.getRequestURI()+". Reason:
!ERROR="+errorcode$+" "+str(errormsg!))
- if debug and statuscode! <> "401" then
- s!.write($0a$+stacktrace$)
- endif
- s!.write("| " - while it!.hasNext() - metaName$ = it!.next() - resp_str! = resp_str!+" | "+metaName$+" | " - wend - resp_str! = resp_str!+"|
| "+f$+" | " - it2! = attrSet!.iterator() - while it2!.hasNext() - metaName$ = it2!.next() - if metaMap!.containsKey(metaName$) then - resp_str! = resp_str!+""+str(metaMap!.get(metaName$))+" | " - else - resp_str! = resp_str!+"" - endif - wend - resp_str! = resp_str!+" |
| "+f$+" | "+rec!.getFieldAsString(f$)+" |
Problem accessing "+request!.getRequestURI()+". Reason:
!ERROR="+errorcode$+" "+str(errormsg!))
+ if debug and statuscode! <> "401" then
+ s!.write($0a$+stacktrace$)
+ endif
+ s!.write("| " + while it!.hasNext() + metaName$ = it!.next() + resp_str! = resp_str!+" | "+metaName$+" | " + wend + resp_str! = resp_str!+"|
| "+f$+" | " + it2! = attrSet!.iterator() + while it2!.hasNext() + metaName$ = it2!.next() + if metaMap!.containsKey(metaName$) then + resp_str! = resp_str!+""+str(metaMap!.get(metaName$))+" | " + else + resp_str! = resp_str!+"" + endif + wend + resp_str! = resp_str!+" |
| "+f$+" | "+rec!.getFieldAsString(f$)+" |