go to post Yone Moreno · Aug 5, 2021 Thanks Julian Matthews for your reply because it is helpful and it let us try to understand a little bit what is happening How would you recommend or suggest to convert a hexadecimal to Ascii? Would you share an example or documentation with us, please? Thanks for your time, and it is a great tool to share with us what is happening behind scenes. If you could points us to some code or functions in ensemble to convert hexadecimal to ascii, it would be great.
go to post Yone Moreno · Jul 1, 2021 Hello Eduard thanks for your reply msg is a %GlobalCharacterStream it is defined before, here is the code: set msg=##class(%GlobalCharacterStream).%New() if ('tSC) || (response.error '= "")||(response.informacion.mensaje '= "") { do msg.Write("<br></br><H1>No existe el informe solicitado</H1>") } else { do ..Adapter.AssignOneSetting("Pdf","1","") Do msg.Write($SYSTEM.Encryption.Base64Decode(response.datos.pdf)) }
go to post Yone Moreno · Jun 30, 2021 Hello, thanks for your time reading our questions and doubts, We have studied how to use the following data types: %Stream.TmpCharacter and %Stream.TmpBinary We have used both as follows: set pOutput = ##class(%Stream.TmpBinary).%New() //set pOutput = msg while(msg.AtEnd=0){ do pOutput.Write(msg.Read()) } do msg.Clear() Quit $$$OK do pOutput.Clear() $$$LOGWARNING("Despues de borrar en el Servicio: pOutput.Clear()") However we still observing a .stream being created at: /opt/ensemble/ESBHCDSNS/stream How could we delete a .stream which represents a pdf being returned from a REST Service to POSTMAN? Thanks for your help 🙇♂️ and time reading our questions and code ⌚️ ➡️ We would need some help if you could explain to us how would you recommend to delete a .stream in a REST Service? , please. We have also read: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls... https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic.... https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic.... https://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?...
go to post Yone Moreno · Jun 8, 2021 Thanks Eduard Lebedyuk because you gave as a detailed explanation
go to post Yone Moreno · May 31, 2021 Thanks Jeffrey for your kind help, and thanks for your time. We have wrote your method in a class called "Util.FuncionesComunes" Namespace "ESBSSCC" We have wrote in the terminal: ESBSSCC 2e1>Set hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Producion.ESBSSCC","EnsLib.HTTP.InboundAdapter") We observe: SET hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Produccion.ESBSSCC",^"EnsLib.HTTP.InboundAdapter")<COMMAND>^Util.FuncionesComunes.1ESBSSCC 2e1> Production's name is: Producion.ESBSSCC How could we debug this to be able to execute the code and list all REST services in the current namespace? Thanks for your help, time and replies Jeffrey
go to post Yone Moreno · May 28, 2021 Thanks Jeffrey We have placed your function in a class called "Util.FuncionesComunes" We have tried to execute it as follows: Set hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Produccion.ESBSSCC","EnsLib.HTTP.InboundAdapter") It shows: SET hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Produccion.ESBSSCC",^"EnsLib.HTTP.InboundAdapter")<COMMAND>^Util.FuncionesComunes.1 When we write: "w $ZERROR" it outputs: SET hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Produccion.ESBSSCC",^"EnsLib.HTTP.InboundAdapter")<COMMAND>^Util.FuncionesComunes.1 How could we solve this?
go to post Yone Moreno · Apr 15, 2021 Hello Marc Mundt, ITB.HL7.BS.XMLService code is the following: /// HL7 XML services common class Class ITB.HL7.BS.XMLService Extends (Ens.BusinessService, ITB.HL7.XMLHost) { /// Location and Revision of this file in Perforce (Auto-updating) Parameter SrcVer = "$Id$"; Property UseAckCommitCodes As %Boolean [ InitialExpression = 1 ]; Property BadMessageHandler As %String(MAXLEN = 1000); /// Name of the element to send the incoming XML stream received by this Service if message is processed OK Property XMLInputHandler As %String(MAXLEN = 1000); /// Colon-separated LocalFacility:LocalApplication:MessageStructure codes representing this (receiving) facility, application, returning MessageStructure, AcceptAcknowledgmentType and ApplicationAcknowledgmentType<br/> /// These are used in constructing reply ACK message headers as SendingFacility, SendApplication and MessageStructure. <br/> /// The '@' symbol represents using the corresponding field from the incoming message. <br/> /// If your ID must contain a literal @ symbol, escape it with backslash: '\@' Property LocalFacilityApplication As %String [ InitialExpression = "ISC:EnsembleHL7:ACK:NE:NE" ]; /// Strip namespace in HL7 XML (ACK message). Property StripNamespace As %Boolean [ InitialExpression = 1 ]; /// Control of ACK handling; options: <br/> /// - Never : Do not send back any ACK <br/> /// - Immediate : Send back (commit) ACK reply message immediately upon receipt of the inbound message <br/> /// - Application : If message passes validation, wait for ACK from target config item and forward it back when it arrives <br/> Property AckMode As %String(DISPLAYLIST = ",Never,Immediate,Application", VALUELIST = ",Never,Immed,App") [ InitialExpression = "Immed", Required ]; /// Names the target(s) from which an ACK response should be forwarded back to the caller, if the AckMode="Application". Property ResponseFrom As %String(MAXLEN = 1000); Parameter SETTINGS = "StripNamespace,LocalFacilityApplication,AckMode,ResponseFrom::selector?context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},UseAckCommitCodes,TargetConfigNames:Basic:selector?multiSelect=1&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},BadMessageHandler:Basic:selector?context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},XMLInputHandler:Basic:selector?context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},SearchTableClass::selector?context={Ens.ContextSearch/SearchTableClasses?host=EnsLib.HL7.Service.Standard},MessageSchemaCategory:Basic:selector?context={Ens.ContextSearch/SchemaCategories?host=EnsLib.HL7.Service.Standard},AlertGracePeriod:Alerting"; /// HL7 XML (Stream) process input Method StreamProcessInput(pInput As %Stream.Object, Output pOutput As %Stream.Object, pSendAck As %Boolean = 0, pCallTargets As %Boolean = 1, Output pER7 As EnsLib.HL7.Message) As %Status { set ret = $$$OK try { // convert XML input to ER7 set tER7 = ##class(ITB.HL7.Util.Convert).XMLToER7(pInput,.tSC,..MessageSchemaCategory) if $$$ISERR(tSC) $$$ThrowStatus(tSC) set pER7 = tER7 // send ACK if pSendAck,..AckMode="Immed" { set tAckCode = $case(..UseAckCommitCodes, 1:"CA", 0:"AA") set tAckER7 = ..GetAck(tER7, tAckCode) set tAckXML = ##class(ITB.HL7.Util.Convert).ER7ToXML(tAckER7,.tSC,,,,..StripNamespace) if $$$ISERR(tSC) $$$ThrowStatus(tSC) set pOutput = tAckXML } // send EnsLib.HL7.Message to targets if pCallTargets { for i=1:1:$l(..TargetConfigNames, ",") { set tTarget=$zstrip($p(..TargetConfigNames,",",i),"<>W") if pSendAck,..AckMode="App",..ResponseFrom=tTarget { $$$THROWONERROR(tSC,..SendRequestSync(tTarget, tER7, .tAckER7)) set tAckXML = ##class(ITB.HL7.Util.Convert).ER7ToXML(tAckER7,.tSC,,,,..StripNamespace) if $$$ISERR(tSC) $$$ThrowStatus(tSC) set pOutput = tAckXML } else { $$$THROWONERROR(tSC,..SendRequestAsync(tTarget, tER7)) } } } // index HL7 in SearchTable if ..SearchTableClass'="" { set tSC = $zobjclassmethod(..SearchTableClass,"IndexDoc",tER7) if $$$ISERR(tSC) $$$LOGERROR("SearchTableClass Error: "_##class(%SYSTEM.Status).GetErrorText(tSC)) } // ok. send XML input to XMLInputHandler if any do:..XMLInputHandler'="" ..SendStreamToTarget(..XMLInputHandler,pInput) } catch ex { set ret = ex.AsStatus() $$$LOGERROR($$$StatusDisplayString(ret)) // error occured. send service input to BadMessageHandler if any do:..BadMessageHandler'="" ..SendStreamToTarget(..BadMessageHandler,pInput) // send alert when HL7 XML has not been processed correctly do:..AlertOnError ..SendAlert(##class(Ens.AlertRequest).%New($LB(..%ConfigName,$$$StatusDisplayString(ret)))) } quit ret } /// Get ACK message for a given HL7 message Method GetAck(pMsg As EnsLib.HL7.Message, pReplyCode As %String) As EnsLib.HL7.Message { // create ACK and copy the control id to the ack control id set tReply = pMsg.NewReplyDocument(,..LocalFacilityApplication) set tReply.Source = pMsg.%Id() do tReply.SetValueAt(pMsg.GetValueAt("1:10"),"1:10") do tReply.SetValueAt($p(..LocalFacilityApplication,":",3),"1:9.3") do tReply.SetValueAt($p(..LocalFacilityApplication,":",4),"1:15") do tReply.SetValueAt($p(..LocalFacilityApplication,":",5),"1:16") // MSA segment set tMSA=##class(EnsLib.HL7.Segment).%New($LB("",1)) set tMSA.Separators=tReply.Separators do tMSA.SetValueAt("MSA",0) do tMSA.SetValueAt(pReplyCode,1) do tMSA.SetValueAt(pMsg.GetValueAt("1:10"),2) do tReply.AppendSegment(tMSA) quit tReply } /// Send pInput stream to a production target Method SendStreamToTarget(pTarget As %String, pInput As %Stream.Object) As %Status { set tMsg = ##class(Ens.StreamContainer).%New(pInput) set tSC = ..SendRequestAsync(pTarget, tMsg) if $$$ISERR(tSC) $$$LOGERROR(##class(%SYSTEM.Status).GetOneErrorText((tSC))) quit tSC } /// Return an array of connections for drawing lines on the config diagram ClassMethod OnGetConnections(Output pArray As %String, pItem As Ens.Config.Item) { do ##super(.pArray,pItem) if pItem.GetModifiedSetting("TargetConfigNames",.tValue) { set:pItem.GetModifiedSetting("BadMessageHandler",.tBadMessageHandler) tValue=tValue_","_tBadMessageHandler set:pItem.GetModifiedSetting("XMLInputHandler",.tXMLInputHandler) tValue=tValue_","_tXMLInputHandler for i=1:1:$L(tValue,",") { set tOne=$zstrip($p(tValue,",",i),"<>W") continue:""=tOne set pArray(tOne)="" } } } } GetAck is a "Method" How should we call it using method syntax, Marc Mundt? Thanks for your replies
go to post Yone Moreno · Mar 9, 2021 Thanks Eduard for sharing this interesting piece of advice Why would be better or recommended to use %CSP.REST directly, instead of EnsLib.REST.Service? Are there any improvements if we use %CSP.REST? Thanks for your reply
go to post Yone Moreno · Mar 9, 2021 We are grateful Marc for your help, Thanks for explaining how did you find the cause which was preventing to get the response in POSTMAN
go to post Yone Moreno · Mar 8, 2021 Thanks Marc Mundt for your help You are right When we removed that line, the response is shown in POSTMAN: Thanks four your help Marc How did you know we should remove that line?
go to post Yone Moreno · Mar 8, 2021 Thanks Marc Mundt for your attention, and your helpful reply Our current code is: Class Servicios.REST.miSCS.Pruebas Extends EnsLib.REST.Service { Parameter ADAPTER = "EnsLib.HTTP.InboundAdapter"; Parameter EnsServicePrefix = "/aplicaciones/scs/test/miscs"; XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ] { <Routes> <Route Url="/:personType/:keyfield/:keyval/:getfield" Method="GET" Call="retrievePerson"/> <Route Url="/consultarImagen" Method="POST" Call="consultarImagen"/> </Routes> } /// Retrieve Method retrievePerson(pInput As %Library.AbstractStream, Output pOutput As %Stream.Object, pPersonType As %String, pKeyField As %String, pKeyVal As %String, pGetField As %String = "") As %Status { Set tType=$ZConvert(pPersonType,"L") Quit:$Case(tType,"employee":0, "person":0, :1) $$$ERROR($$$EnsErrGeneral,"Directory type "_..#EnsServicePrefix_"/"_tType_"/ not supported.") Set $E(tType)=$ZConvert($E(tType),"U") Set tKeyIn=pKeyField, tKey=$ZConvert(tKeyIn,"L") Quit:$Case(tKey,"name":0, "ssn":0, :1) $$$ERROR($$$EnsErrGeneral,"Directory key "_..#EnsServicePrefix_"/"_tType_"/"_tKey_" not supported.") Set tKeyVal=$Replace($ZConvert(pKeyVal,"I","URL"),"'","''") Set tField=pGetField Set:""=tField tField="*" Quit:tField["," $$$ERROR($$$EnsErrGeneral,"Commas not allowed in selection field; found: .../"_tField) Set tNS=$Namespace Set tKeyWild=$Translate(pKeyVal,"*?","%_") Do:tKeyWild'=pKeyVal pOutput.Write("[") ZNSpace "SAMPLES" try { Set tSel=$S("*"=tField:"ID",1:tField) Set tSQL="SELECT "_tSel_$S("*"=tField||(tKey=tSel):"", 1:","_tKey)_$Case("ID",tKey:"",tSel:"",:",ID")_" FROM Sample."_tType_" WHERE "_tKey_" LIKE '"_tKeyWild_"'" //$$$LOGINFO("tSQL: "_tSQL) Set tRS=##class(%ResultSet).%New() Set tSC=tRS.Prepare(tSQL) Quit:$$$ISERR(tSC) Set tSC=tRS.Execute() Quit:$$$ISERR(tSC) Set tFirst=1 Set tOut=##class(%IO.StringStream).%New() While tRS.Next(.tSC) && $$$ISOK(tSC) { #; first normalize the case of the key and sel property names If tFirst { Set k="" For { Set k=$O(tRS.Data(k)) Quit:""=k If $ZConvert(k,"L")=$Zconvert(tSel,"L") Set tSelN=k If $ZConvert(k,"L")=$Zconvert(tKey,"L") Set tKeyN=k } } If $Case(tSelN, "Company":1, "Notes":1, "Home":1, "Office":1, :0) { Set tVal=tRS.Data("ID") Set tObj=$classmethod("Sample."_tType,"%OpenId",tVal,,.tSC) Quit:$$$ISERR(tSC) Set tVal=$property(tObj,tSelN) Set tSelX = $Case(tSelN, "Home":"Addr", "Office":"Addr", :tSelN) Set tVal=$Case(tSelX, "Company":tVal.Name, "Notes":tVal.Read(), "Addr":tVal.Street_", "_tVal.City_" "_tVal.State_" "_tVal.Zip, :tVal) } Else { Set tVal=tRS.Data(tSelN) } If "*"=tField { Set tObj=$classmethod("Sample."_tType,"%OpenId",tVal,,.tSC) Quit:$$$ISERR(tSC) Set tProxyObj=..buildProxyObj(tObj) Do tOut.Write($S(tFirst:"",1:",")) Set tSC=..ObjectToJSONStream(tProxyObj,.tOut) } Else { Set:tKeyN'=tSelN tKeyFound=tRS.Data(tKeyN) Do tOut.Write($S(tFirst:"",1:",")_"{"_$S(tKeyN=tSelN:"",1:""""_tKeyIn_""":"""_tKeyFound_""", ")_""""_tSel_""":"""_tVal_"""}"_$C(13,10)) } Set tFirst=0 ZNSpace tNS Do tOut.Rewind() Set tSC1=pOutput.Write(tOut.Read()) Do tOut.Clear() Set:$$$ISOK(tSC) tSC=tSC1 Quit:$$$ISERR(tSC) ZNSpace "SAMPLES" } Quit:$$$ISERR(tSC) Do:tKeyWild'=tKeyVal pOutput.Write("]"_$C(13,10)) } catch { Kill tRS ZNSpace tNS Set tSC=$$$SystemError } Kill tRS ZNSpace tNS $$$LOGINFO("tSQL: "_tSQL) Do:$$$ISOK(tSC) pOutput.SetAttribute("Content-Type","application/json") while (pOutput.AtEnd = 0){ set respuestaFinal = pOutput.Read() } do pOutput.Rewind() $$$LOGINFO("respuestaFinal: "_respuestaFinal) Quit tSC } /// Normalize the Person or Employee info by copying its properties to a proxy object in a selective way ClassMethod buildProxyObj(pObj As %Persistent) [ Internal ] { Set tProxy = ##class(%ZEN.proxyObject).%New() Set tProxy.ID=pObj.%Id() Set tProxy.Name=pObj.Name Set tProxy.Age=pObj.Age Set tProxy.DOB=$ZDateTime(pObj.DOB,3) Set tProxy.SSN=pObj.SSN Set tProxy.FavoriteColors=pObj.FavoriteColors Set tProxy.Spouse=pObj.Spouse.Name Set tProxy.Home=..buildProxyAddr(pObj.Home) Set tProxy.Office=..buildProxyAddr(pObj.Office) If pObj.%IsA("Sample.Employee") { Set tProxy.Company=pObj.Company.Name Set tProxy.Notes=$S($IsObject(pObj.Notes):pObj.Notes.Read(),1:"") } Quit tProxy } ClassMethod buildProxyAddr(pObj As %SerialObject) [ Internal ] { Set tProxy = ##class(%ZEN.proxyObject).%New() Set tProxy.Street=pObj.Street Set tProxy.City=pObj.City Set tProxy.State=pObj.State Set tProxy.Zip=pObj.Zip Quit tProxy } /// Control the type and content of error returned to the REST caller ClassMethod OnErrorStream(pStatus As %Status) { Set tStream = ##class(%GlobalBinaryStream).%New() $$$ASSERT($IsObject(tStream)) Do tStream.Write($ZConvert($$$StatusDisplayString(pStatus)_$C(13,10),"O","UTF8")) Set tStream.Attributes("Content-Type")=" text/plain; charset=""UTF-8""" Set tStream.Attributes("ResponseCode")="500 Internal Server Error" Quit tStream } /// Obtener la imagen guardada en TSI 📥📥📥📥 Method consultarImagen(pInput As %Library.AbstractStream, Output pOutput As %Stream.Object) As %Status { Set pOutput=##class(%GlobalBinaryStream).%New() set claseAux = ##class(%ZEN.Auxiliary.jsonProvider).%New() //Convertir el body del JSON a objeto de Ensemble set body = pInput.Read() $$$LOGINFO("miSCS: body: "_body) do pInput.Rewind() //El mensaje esta en el body set tSC= claseAux.%ConvertJSONToObject(.body,"Mensajes.Request.miSCS.ConsultarImagen",.objetoEntrada,1) //Enviamos al Proceso set tSC = ..SendRequestSync("miSCS",objetoEntrada,.objetoSalida) //Convertimos el OBJETO devuelto por el Proceso en JSON //set tSC = claseAux.%WriteJSONStreamFromObject(.pOutput,.objetoSalida,,,,"aloqtuw") //Esta linea hace esta en el metodo de ejemplo "retrievePerson" y convierte el mensaje response en JSON Set tSC=..ObjectToJSONStream(objetoSalida,.pOutput) while (pOutput.AtEnd = 0){ set respuesta = pOutput.Read() } do pOutput.Rewind() $$$LOGINFO("respuesta: "_respuesta) $$$LOGINFO("tSC: "_tSC) $$$LOGINFO("$$$ISOK(tSC): "_$$$ISOK(tSC)) //Enviamos el JSON con cabeceras Do:$$$ISOK(tSC) pOutput.SetAttribute("Content-Type","application/json") do pOutput.SetAttribute("Access-Control-Allow-Origin","*") do pOutput.SetAttribute("Access-Control-Allow-Credentials","true") do pOutput.SetAttribute("Access-Control-Allow-Methods","GET") do pOutput.SetAttribute("Access-Control-Allow-Headers","request,Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers") while (pOutput.AtEnd = 0){ set respuestaFinal = pOutput.Read() } do pOutput.Rewind() $$$LOGINFO("respuestaFinal: "_respuestaFinal) Quit tSC } } When we dig deeper using Whireshark: First, we find that the method in the example that uses GET, the retrievePerson, does answers with a JSON to POSTMAN, so it works: GET request: GET response: In POSTMAN: However, Our custom method: consultarImagen which is a POST Shows nothing in POSTMAN Why? POST request: POST response: In POSTMAN: Could you help us? Thanks for your replies
go to post Yone Moreno · Mar 8, 2021 Thanks Marc Mundt for your reply Yes you are right, we should use POST We have changed it: <Route Url="/consultarImagen" Method="POST" Call="consultarImagen"/> However we do not see the response in POSTMAN: And the headers are: Content-Type: text/html Content-Length: 0 CACHE-CONTROL: no-cache PRAGAM: no-cache We send the POST to the following URL: http://localhost:19622/aplicaciones/scs/test/miscs/consultarImagen Besides we observe the response message being converted from Ensemble object to JSON in the service: We do see the Response Message from the Operation to the Service Why we do not see the JSON being replied from the Service in POSTMAN? How could we debug this behaviour? Thanks for your replies
go to post Yone Moreno · Jan 29, 2021 Thanks Marc Mundt for your help, We have tried to make objetoSalida.binario as %Binary Exactly we do the following: 1) We read the image as binary directly from the external system in the REST Operation: set linea="" if (tResponse.Data.AtEnd = 0) { set linea = tResponse.Data.Read() } set pResponse.binario = linea $$$LOGINFO("pResponse.binario: "_pResponse.binario) We observe the binary correctly written in the LOGINFO: 2) In the Service, we have a LOGINFO before writing it to JSON $$$LOGINFO("objetoSalida.binario: "_objetoSalida.binario) set tSC = claseAux.%WriteJSONStreamFromObject(.pOutput,.objetoSalida,,,,"aeloqtuw") We see it correctly: 3) However when we convert it to JSON we see that there are strange characters like "\x00" set tSC = claseAux.%WriteJSONStreamFromObject(.pOutput,.objetoSalida,,,,"aeloqtuw") $$$LOGINFO("pOutput.Read(): "_pOutput.Read()) How would you recommend us to continue? What documents or code examples would you study or write to handle this issue? Thanks for your help
go to post Yone Moreno · Jan 5, 2021 Hello, We have continued the development, The output system now replies to us However we do see that the 2nd MIME part, the image, is being sent from ENSEMBLE, different than the image sent with POSTMAN 1 Let's see what we send from Ensemble: 2 The following image show us what POSTMAN correctly sends: If we examine and compare both images, we observe that the image sent with Postam is being recognized as a JPEG, however the one sent with Ensemble is not being sent as a JPEG The code which we have written is: Class Operaciones.REST.miSCS.miSCS Extends EnsLib.REST.Operation { Parameter INVOCATION = "Queue"; /// 📤 Subir la imagen Method SubirImagen(pRequest As Mensajes.Request.miSCS.SubirImagen, pResponse As Mensajes.Response.miSCS.SubirImagen) As %Library.Status { //Crear Request y Response HTTP Set httpRequest=##class(%Net.HttpRequest).%New() set tResponse = ##class(%Net.HttpResponse).%New() // Create root MIMEPart, la parte que contiene al resto Set RootMIMEPart=##class(%Net.MIMEPart).%New() //Crear parte con el expediente Set ExpedienteMIMEPart=##class(%Net.MIMEPart).%New() Set contentdisp="form-data; name=""expediente""" Do ExpedienteMIMEPart.SetHeader("Content-Disposition",contentdisp) Set ExpedienteMIMEPart.Body=pRequest.expediente //Do ExpedienteMIMEPart.SetHeader("Content-Type","text/plain") // Crear parte con la imagen Set ImagenMIMEPart=##class(%Net.MIMEPart).%New() Set ImagenMIMEPart.Body=##class(%GlobalCharacterStream).%New() //Probamos a leer una imagen local Set stream=##class(%Stream.FileCharacter).%New() Set sc=stream.LinkToFile("C:\Users\ext-ymorjim\Pictures\miSCS.jpg") While 'stream.AtEnd { Set linea=stream.Read() } $$$LOGINFO("linea: "_linea) //Escribir la imagen en el mensaje MIME Do ImagenMIMEPart.Body.Write(linea) //Do ImagenMIMEPart.Body.Write(pRequest.imagen) // Cabeceras de la imagen Set ImagenMIMEPart.ContentType="image/jpeg" Set contentdisp="form-data; name=""imagen""; filename="""_stream.Filename_"" Do ImagenMIMEPart.SetHeader("Content-Disposition",contentdisp) // Insertar las partes en la raiz Do RootMIMEPart.Parts.Insert(ExpedienteMIMEPart) Do RootMIMEPart.Parts.Insert(ImagenMIMEPart) // create MIME writer; write root MIME message Set writer=##class(%Net.MIMEWriter).%New() // Prepare outputting to the HttpRequestStream Set httpRequest=##class(%Net.HttpRequest).%New() Set status=writer.OutputToStream(httpRequest.EntityBody) if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit} // Now write down the content Set status=writer.WriteMIMEBody(RootMIMEPart) if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit} // Creamos la URL set url = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","url") set path = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","path") set servicio = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","servicio") set recurso = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","subirImagen") set URL = "http://"_url_path_servicio_recurso $$$LOGINFO("URL: "_URL) //Escribimos el tipo de contenido que enviamos Set httpRequest.ContentType="multipart/form-data; boundary="_RootMIMEPart.Boundary $$$LOGINFO("> httpRequest.ContentType: "_httpRequest.ContentType) //Enviamos set tSC=httpRequest.Post(URL,0) $$$LOGINFO("tSC: "_tSC) if $$$ISERR(tSC){ $$$ThrowOnError(tSC) } if (tResponse.Data.AtEnd = 0) { $$$LOGINFO("En SubirImagen, tamaño de tResponse: "_tResponse.Data.Size) set linea = tResponse.Data.Read() $$$LOGINFO("Linea: "_linea) } set pResponse = ##class(Mensajes.Response.miSCS.SubirImagen).%New() set pResponse.resultado = 1 set pResponse.informacion = linea Quit pResponse } How could we continue‽ Could you point us to some example??, please We have read: https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI... Thanks in advance
go to post Yone Moreno · Jan 5, 2021 Hello, Thanks Marc Mundt for your help, 1 We have tried with the following code which reads a String which represents an image in pRequest.imagen and we send it into a MIME: Class Operaciones.REST.miSCS.miSCSSubirImagenJPGlocal Extends EnsLib.REST.Operation { Parameter INVOCATION = "Queue"; /// 📤 Subir la imagenSanitaria Method SubirImagen(pRequest As Mensajes.Request.miSCS.SubirImagen, pResponse As Mensajes.Response.miSCS.SubirImagen) As %Library.Status { Set httpRequest=##class(%Net.HttpRequest).%New() set tResponse = ##class(%Net.HttpResponse).%New() Set msg=##class(%Net.MIMEPart).%New() Set msg.Body=##class(%GlobalCharacterStream).%New() Do msg.Body.Write(pRequest.imagen) Set msg.ContentType="multipart/form-data" // create MIME writer; write root MIME message Set writer=##class(%Net.MIMEWriter).%New() // Prepare outputting to the HttpRequestStream Set status=writer.OutputToStream(httpRequest.EntityBody) if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit} // Now write down the content Set status=writer.WriteMIMEBody(msg) if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit} set url = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","url") set path = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","path") set servicio = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","servicio") set recurso = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","subirImagen") set URL = "http://"_url_path_servicio_recurso $$$LOGINFO("URL: "_URL) set tFormVarNames = "expediente,imagen" set tData("expediente") = pRequest.expediente set tData("imagen") = pRequest.imagen set tSC = ..Adapter.SendFormDataArray(.tResponse,"POST",httpRequest,.tFormVarNames,.tData,URL) $$$LOGINFO("tSC: "_tSC) if $$$ISERR(tSC){ $$$ThrowOnError(tSC) } if (tResponse.Data.AtEnd = 0) { $$$LOGINFO("En SubirImagen, tamaño de tResponse: "_tResponse.Data.Size) set linea = tResponse.Data.Read() $$$LOGINFO("Linea: "_linea) } set pResponse = ##class(Mensajes.Response.miSCS.SubirImagen).%New() do pResponse.return.Write(linea) Quit pResponse } However when we see it using Whireshark we observe that it is being sent as text/html 2 We have also used the following approach, to read a JPG directly and send it into the MIME: Class Operaciones.REST.miSCS.miSCSSubirImagenJPGlocal Extends EnsLib.REST.Operation { Parameter INVOCATION = "Queue"; /// 📤 Subir la imagenSanitaria Method SubirImagen(pRequest As Mensajes.Request.miSCS.SubirImagen, pResponse As Mensajes.Response.miSCS.SubirImagen) As %Library.Status { //Crear Request y Response HTTP Set httpRequest=##class(%Net.HttpRequest).%New() set tResponse = ##class(%Net.HttpResponse).%New() //Crear MIME Set msg=##class(%Net.MIMEPart).%New() Set msg.Body=##class(%GlobalCharacterStream).%New() //Probamos a leer una imagen local y a enviarla Set stream=##class(%Stream.FileCharacter).%New() Set sc=stream.LinkToFile("C:\Users\ext-ymorjim\Pictures\miSCS.jpg") While 'stream.AtEnd { Set linea=stream.Read() } $$$LOGINFO("linea: "_linea) //Escribir la imagen en el mensaje MIME Do msg.Body.Write(linea) //Do msg.Body.Write(pRequest.imagen) Set msg.ContentType="multipart/form-data" // create MIME writer; write root MIME message Set writer=##class(%Net.MIMEWriter).%New() // Prepare outputting to the HttpRequestStream Set status=writer.OutputToStream(httpRequest.EntityBody) if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit} // Now write down the content Set status=writer.WriteMIMEBody(msg) if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit} set url = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","url") set path = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","path") set servicio = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","servicio") set recurso = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","subirImagen") set URL = "http://"_url_path_servicio_recurso $$$LOGINFO("URL: "_URL) set tFormVarNames = "expediente,imagen" set tData("expediente") = pRequest.expediente set tData("imagen") = pRequest.imagen //set tData("imagen") = linea set tSC = ..Adapter.SendFormDataArray(.tResponse,"POST",httpRequest,.tFormVarNames,.tData,URL) $$$LOGINFO("tSC: "_tSC) if $$$ISERR(tSC){ $$$ThrowOnError(tSC) } if (tResponse.Data.AtEnd = 0) { $$$LOGINFO("En SubirImagen, tamaño de tResponse: "_tResponse.Data.Size) set linea = tResponse.Data.Read() $$$LOGINFO("Linea: "_linea) } set pResponse = ##class(Mensajes.Response.miSCS.SubirImagen).%New() do pResponse.return.Write(linea) Quit pResponse } With the previous code we see that a text/html is being sent too: In both cases, the external system gives us a HTTP code 400: ERROR <Ens>ErrException: <THROW>zSubirImagen+40^Operaciones.REST.miSCS.miSCS.1 *%Exception.StatusException ERROR <Ens>ErrHTTPStatus: Received non-OK status 400 from remote HTTP server: 'HTTP/1.1 400 ' -- logged as '-' number - @' Set sc=tSC Throw:('sc) ##class(%Exception.StatusException).ThrowIfInterrupt(sc)' How could we achieve to send it in the correct way? as it is being sent when we use POSTMAN: How could we send the image as multipart/form-data? > We have read: https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI... https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.c... How could we send the image as multipart/form-data as it is being sent by Postman? ➡️ Could you point us to same code examples, please?
go to post Yone Moreno · Aug 14, 2020 Hello Kevin, Yes you were right we did not include "/opt/contenedor/Java/AppSeguimientoAnadidaReferenciaJARSexternos.jar" We have just added it and the exception continues.
go to post Yone Moreno · Aug 14, 2020 Hello Kevin, We are using the following Java version: java version "1.8.0_65"Java(TM) SE Runtime Environment (build 1.8.0_65-b17)Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode) If we execute the command with our jar (which includes the Java program and its dependencies): jar -tf "AppSeguimientoAnadidaReferenciaJARSexternos.jar" We see: META-INF/MANIFEST.MForg/org/eclipse/org/eclipse/jdt/org/eclipse/jdt/internal/org/eclipse/jdt/internal/jarinjarloader/org/eclipse/jdt/internal/jarinjarloader/JIJConstants.classorg/eclipse/jdt/internal/jarinjarloader/JarRsrcLoader$ManifestInfo.classorg/eclipse/jdt/internal/jarinjarloader/JarRsrcLoader.classorg/eclipse/jdt/internal/jarinjarloader/RsrcURLConnection.classorg/eclipse/jdt/internal/jarinjarloader/RsrcURLStreamHandler.classorg/eclipse/jdt/internal/jarinjarloader/RsrcURLStreamHandlerFactory.classradarCovidcrearToken/radarCovidcrearToken/CCAATokenGeneratorTest.classgenerated_private_base64.pemaether-api-1.7.jaraether-impl-1.7.jaraether-spi-1.7.jaraether-util-1.7.jarasm-6.2.jarbcpkix-jdk15on-1.58.jarbcprov-jdk15on-1.58.jarclassworlds-1.1.jarcommons-cli-1.0.jarcommons-codec-1.14.jarcommons-io-2.5.jarjackson-annotations-2.10.3.jarjackson-core-2.10.3.jarjackson-databind-2.10.3.jarjava-jwt-3.10.3.jarjunit-3.8.1.jarplexus-build-api-0.0.4.jarplexus-cipher-1.4.jarplexus-classworlds-2.2.3.jarplexus-compiler-api-2.8.4.jarplexus-compiler-javac-2.8.4.jarplexus-compiler-manager-2.8.4.jarplexus-component-annotations-1.7.1.jarplexus-container-default-1.0-alpha-9-stable-1.jarplexus-interactivity-api-1.0-alpha-4.jarplexus-interpolation-1.13.jarplexus-interpolation-1.14.jarplexus-java-0.9.10.jarplexus-sec-dispatcher-1.3.jarplexus-utils-2.0.4.jarplexus-utils-2.0.5.jarqdox-2.0-M9.jarsisu-guice-2.1.7-noaop.jarsisu-inject-bean-1.4.2.jarsisu-inject-plexus-1.4.2.jarjava-jwt-3.10.3_2.jarjackson-databind-2.10.3_2.jarjackson-annotations-2.10.3_2.jarjackson-core-2.10.3_2.jarcommons-codec-1.14_2.jarbcpkix-jdk15on-1.58_2.jarbcprov-jdk15on-1.58_2.jar If we execute the command to locate the jar where is the class which generates the NoClassDefFoundError : jar -tf "bcprov-jdk15on-1.58.jar" We get: ... org/bouncycastle/util/io/pem/org/bouncycastle/util/io/pem/PemGenerationException.classorg/bouncycastle/util/io/pem/PemHeader.classorg/bouncycastle/util/io/pem/PemObject.classorg/bouncycastle/util/io/pem/PemObjectGenerator.classorg/bouncycastle/util/io/pem/PemObjectParser.classorg/bouncycastle/util/io/pem/PemReader.classorg/bouncycastle/util/io/pem/PemWriter.classorg/bouncycastle/util/test/ ... As you would notice it outputs the name of the missing class: org/bouncycastle/util/io/pem/PemReader.class What could we do?
go to post Yone Moreno · Aug 12, 2020 Hello Eduard We would need to be able to send a REST POST meesage with the following body: { "provider":"provider", "group": "group", "location": "location", "data": "data", "checkin": "checkin", "client": "client", "admin": "admin", "apiUrl": "apiUrl" } And get the previous body inside our Service. We have written as a Service: Class Servicios.REST.HistoriaClinica.Videoconsulta Extends Ens.BusinessService { Parameter ADAPTER = "EnsLib.HTTP.InboundAdapter"; Method OnProcessInput(pInput As %RegisteredObject, Output pOutput As %RegisteredObject) As %Status { do ..enviarCitaCrearSala(pInput,.pOutput) quit $$$OK } Method enviarCitaCrearSala(pInput As %Stream.Object, Output pOutput As %Stream.Object) As %Status { //TODO: Get body set tSC = ..SendRequestSync("Videoconsulta",body,.objetoSalida) set claseAux = ##class(%ZEN.Auxiliary.jsonProvider).%New() set tSC = claseAux.%WriteJSONStreamFromObject(.pOutput,.objetoSalida,,,,"aeloqtuw") Quit tSC }