go to post Julius Kavay · Apr 1, 2020 Sorry, but it's not clear to me what you want to achieve. If you want to provide data if somebody connected to your server, then use the DC.Upload class (see below). If somebody has data for you and you want to programatically download this data, use the DC.Download class (see below). The examples below does not handle the case, where the (Cache/IRIS)Server needs an user authentication (my IRIS System > Security Management > Web Applications is set to "Unauthenticated") Server side (Upload) /// Upload (i.e. provide) data to a remote party Class DC.Upload Extends %CSP.Page { ClassMethod OnPage() As %Status { if %request.Data("myData")]"" { do %request.Data("myData").OutputToDevice() do %request.Data("myData").%Close() } else { write "<html><head></head><body>",! write "Please provide a correct Password and ReportId<br>",! write "</body></html>",! } quit $$$OK } ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ] { if ..chkPsw(), ..chkRpt(.file) { set data=##class(%FileBinaryStream).%New() set size=##class(%File).GetFileSize(file) set name=##class(%File).GetFilename(file) do data.LinkToFile(file) set %response.ContentType="application/pdf" do %response.SetHeader("Content-Disposition","attachment;filename="_name) do %response.SetHeader("Content-Length",size) set time=$h-1 set %response.Expires=$zd(time,11)_", "_$zd(time,2)_" 00:00:00 GMT" set %request.Data("myData")=data } else { set %request.Data("myData")="" } quit $$$OK } ClassMethod chkPsw() { set psw=$g(%request.Data("pswd",1)) if psw]"" quit 1 quit 0 } ClassMethod chkRpt(name) { set rpt=$g(%request.Data("rpt",1)) if rpt]"" { set name="/tmp/outfiles/74LS13.pdf" quit 1 } quit 0 } } Client side (download) /// Download (i.e. get) data from remote server /// Class DC.Download Extends %RegisteredObject { ClassMethod GetFile(psw, rpt, saveTo = "/tmp/inpfiles/") { set http=##class(%Net.HttpRequest).%New() set http.Server="localhost" set http.Port=52773 do http.SetParam("pswd",psw) do http.SetParam("rpt",rpt) if http.Get("/csp/user/DC.Upload.cls") { set file=$piece($g(http.HttpResponse.Headers("CONTENT-DISPOSITION")),"=",2) set del=$select($zversion(1)=2:"\", 1:"/") set file=saveTo_$s($e(saveTo,*)=del:"",1:del)_$s(file="":"noname.dat",1:file) open file:"nwu":0 if $t { use file do http.HttpResponse.Data.OutputToDevice() close file quit 1 } else { quit "0,Can't open "_file } } else { quit "0,"_http.HttpResponse.StatusLine } } }
go to post Julius Kavay · Apr 1, 2020 Create a temp table with all properties you need, store it in a Cachte/IRIS-Temp unde $J of the running job (it could be, your applcation runs in several instances at the same time) an use it in your INSERT / UPDATE. This is your Table Class My.Table1 Extends %Persistent { Property Name As %String; Property Age As %Numeric; ClassMethod Test() { d ##class(My.Temp).%DeleteId($j) s tmp=##class(My.Temp).%New() s tmp.TempID=$j, tmp.Name="Paul", tmp.Age=69 d tmp.%Save() // or popolate the My.Temp via INSERT... &sql(INSERT INTO My.Table1 (Name,Age) SELECT Name,Age FROM My.Temp WHERE TempID=$j ) } } and this is the Temporary Table Class My.Temp Extends %Persistent { Parameter DEFAULTGLOBAL = "^CacheTemp.TempTable"; Property TempID As %Integer; Property Name As %String; Property Age As %Numeric; Index main On TempID [ IdKey ]; }
go to post Julius Kavay · Mar 30, 2020 Do I understand you right, you want to get the Value of a VALUELIST as a return value of a method? If yes, then the answer is yes. Class Some.Class { Property Status As %String (VALUELIST = ",1,2,3,4"); Property Rating As %String(VALUELIST = ",Bad,Good,Excellent"); /// For the Status property only ClassMethod StatusValues() As %String [ CodeMode = objectgenerator ] { for i=%class.Properties.Count():-1:0 if i,%class.Properties.GetAt(i).Name="Status" quit set val=$select(i:%class.Properties.GetAt(i).Parameters.GetAt("VALUELIST"), 1:"") do %code.WriteLine($c(9)_"quit """_val_"""") } /// For all properties with a VALUELIST parameter ClassMethod Values(prop) [ CodeMode = objectgenerator ] { set sel="" for i=1:1:%class.Properties.Count() { set val=%class.Properties.GetAt(i).Parameters.GetAt("VALUELIST") set:val]"" sel=sel_""""_%class.Properties.GetAt(i).Name_""":"""_val_""", " } do %code.WriteLine($c(9)_"quit $case(prop,"_sel_":"""")") } } And a few examples... Write ##class(Some.Class).StatusValues() ==> ,1,2,3 Write ##class(Some.Class).Values("Status") ==> ,1,2,3 Write ##class(Some.Class).Values("Rating") ==> Bad,Good,Excellent Write ##class(Some.Class).Values("OtherProperty") ==>
go to post Julius Kavay · Mar 30, 2020 not a built-in, but you can easily create one ClassMethod ParamList() [ CodeMode = objectgenerator ] As %List { set params="" for i=1:1:%class.Parameters.Count() set params=params_$lb(%class.Parameters.GetAt(i).Name) do %code.WriteLine($c(9)_"quit """_params_"""") } ClassMethod ParamString() As %String { quit $listtostring(..ParamList()) }
go to post Julius Kavay · Mar 29, 2020 as far as I know (subject to verification) you source code will be compiled into a p-code (pseudo- or portable-code). This means, Cache and IRIS behave (regarding program execution) as virtual machines, like the JVM (Java Virtual Machine).
go to post Julius Kavay · Mar 23, 2020 $listbuild() and all other functions, like $length(), $char() etc. are (I call them) basic functions of COS and have nothing to do with objects. The language of Cache (and of course IRIS ) handles data as raw (basic) data and not as objects, like some other (but not all) languages. For example, in JavaScript you can do var text="Some text"; alert("'" + text + "' has "+text.length + " characters"); alert("'Some text' has " + "Some text".length + " characters"); because both, a (text)variable and a (text)string have an (object)property name 'length'. Beside the raw data type COS also has object data type and most of the standard COS functions will accept an object property as argument, for example: Class Test.Class Extends %RegisteredObject { Property Data as %String; } set text="Some text" set obj = ##class(Test.Class).%New() set obj.Data = "Some text"; write $length(text),! write $length(obj.Data),!
go to post Julius Kavay · Mar 19, 2020 JavaScript, as your code shows, is compiled and executed on client side (in the browser). The part of the code #()# you use is CSP (CacheServerPages), which is compiled and prepared by the server for execution by client. Hence, you can't use the #()# syntax in a pure JavaScript code.
go to post Julius Kavay · Mar 17, 2020 $lb(data1, data2, data3, ... dataN) is built as a string of item1 item2 item3 ... itemN itemN:= <len> <type> <dataN> assuming, you are on a little-endian CPU and l1 = $length(data) l2 = l1 + 1 // for type byte l3 = l2 + 1 // for the length itself then the length is as follows if l1<=253 then len: <l3> elseif l1<=65534 len:= <0> <l2-lowbyte> <l2-highbyte> else len:= <0> <0> <0> <l2-lowbyte-loworderword> ... <l2-highbyte-highorderword> And don't forget,$lb(123) is not the same as $lb(1230/10), hence we have a $ls() function!
go to post Julius Kavay · Mar 15, 2020 I have no idea how you did your endless loop, but the above code can't do that.
go to post Julius Kavay · Mar 14, 2020 the functions $order() and $query() are your best friends ;-)) Write, for example, a method like this: ClassMethod(ref) { if $data(@ref)#10 write ref,"=",@ref,! // do something with this node set i="" for set i=$order(@ref@(i)) quit:i="" do ..Show($name(@ref@(i))) } So, for testdata like set tmp(1,2,3)="Joe" set tmp(1,2,3,4,1)="Paul" set tmp(1,2,3,4,2)="Paula" set tmp(1,2,3,5,6)="Tom" start some testing do ##class(yourclass).Show($na(tmp)) // shows all entries do ##class(yourclass).Show($na(tmp(1,2))) // also shows all entries do ##class(yourclass).Show($na(tmp(1,2,3))) // shows Joe do ##class(yourclass).Show($na(tmp(1,2,3,4)) // shows Paul and Paula do ##class(yourclass).Show($na(1,2,3,5))) // shows Tom do ##class(yourclass).Show($na(tmp(1,2,3,5,6))) // shows Tom do ##class(yourclass).Show($na(tmp(2,3))) // shows nothing Now, I hope, you can figure out how to get out your desired data
go to post Julius Kavay · Mar 14, 2020 set x="1.2.3", y=$name(tmp) for i=1:1:$length(x,".") { set y=$name(@y@($piece(x,".",i))) } set @y="" kill x,y,i You can put al the above in one line, if you are in terminal. Or put it in a method ClassMethod setTemp(x) [ PublicList = tmp] { set y=$name(tmp) for i=1:1:$length(x,".") { set y=$name(@y@($piece(x,".",i))) } set @y="" } Or you take the shorthand set x="1.2.3", @("tmp("_$tr(x,".",",")_")=""""") But this works only as long as x contains number_period_numeber_period_...No leading zeros, no alphabetics...
go to post Julius Kavay · Jan 15, 2020 Ok, I started my Studio (2018.1.1) --> New Class --> ABC.Try --> Finish. Then removed the Extends... and I left over with Class ABC.Try { } Then saved (but no compile) and my test in a terminal: USER>s aa=##class(%Dictionary.PackageDefinition).GetPackageList() USER>w aa.Find("ABC") 523 USER>
go to post Julius Kavay · Jan 15, 2020 In the class definition one can create persistent-, serial-, registered-, abstract- and data-classes. All of the above classes are contained in ##class(%Dictionary.PackageDefinition).GetPackageList(). Do you have a example for an class, which is not contained in the above method? Or there is just a misunderstanding?
go to post Julius Kavay · Jan 15, 2020 The simple (and documented) answer is something like this: set name="Test.Package" if ##class(%Dictionary.PackageDefinition).GetPackageList().Find($zconvert(name,"u")) { w "Yes" } else { w "No" } @Timothy using ^oddDEF and/or ^oddCOM works today, we hope, it will work tomorrow too, but there is no garantie
go to post Julius Kavay · Jan 12, 2020 A warning about long time open transactions will be placed in cconsole.log and alerts.log (both files in $system.Util.InstallDirectory()_"mgr" directory) - at least this is the case what I see on a customers system. The entries look like this: 04/05/19-02:31:34:470 (21012) 1 [SYSTEM MONITOR] TransOpenSecs Warning: One or more transactions open longer than 10 minutes. Process id 18624 22208 (only top 5 shown) 08/29/19-14:31:03:802 (18576) 1 [SYSTEM MONITOR] TransOpenSecs Warning: One or more transactions open longer than 10 minutes. Process id 4128 (only top 5 shown) 09/04/19-17:16:19:090 (21344) 1 [SYSTEM MONITOR] TransOpenSecs Warning: One or more transactions open longer than 10 minutes. Process id 25872 (only top 5 shown) So it should be as easy as monitoring those two logfiles. But how it looks like on an ECP server, don't ask me.
go to post Julius Kavay · Dec 21, 2019 You could try this way (I assume, your image is in *.jpg, *.png, *.gif, *.ico or *.bmp format and you use a Windows OS): - save the stream to a temp file - do $zf(-1,"pathToIrfanView.exe pathToInpFile /resize=(100,100) /aspectratio /convert=pathToOutFile") - read the output into a stream and proceed as needed Don't forget, if one of the above path contains a space char, you have to put in quotes the whole path. /resize=(100,100) /aspectration means, the picture will be resized to a max width/height of 100 by maintaning the aspect ratio. Example: input=2000x3000 out =67x100, input=3000x2000 out=100x67 For Unix exists similar tools to use with $zf(-1,...), for example "identify" to get the dimensions of the picture and "convert" or "imagemagick" for resizing.
go to post Julius Kavay · Dec 21, 2019 As I wrote above, Java is not my case, sorry. Maybe the link below gives you some clue https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_javagateway
go to post Julius Kavay · Dec 21, 2019 I'm not that java guy, so just a hint only. There should be a public static java.lang.String PetNameLogicalToDisplay(...) method, so use/call this method to display your pets.
go to post Julius Kavay · Sep 22, 2019 If your routine works in a terminal session (by issuing a DO ^Routinname command) but does not work, when the same routine is started via the Job commannd (JOB ^Routinname) then you lack something in background, what you have in the foreground. Put an errortrap in your routine and simple report a possible error (and if you wich, additionally the execution progress of your routine). rvExt2012 ; Test set $zt="bgErr" // ... // ... do signal("checkpoint 1") // this is optional // ... // ... do signal("checkpoint 2") // this is optional // ... // ... do signal("Done") quit bgErr do signal("Error: "_$ze) quit signal(msg) do $system.Event.Signal($zp, $username_", "_$roles_", "_msg) quit Now, in the terminal session enter following line job ^rvExt2012 do { set $lb(s,m)=$system.Event.WaitMsg("",1) write m,! } while s
go to post Julius Kavay · Sep 14, 2019 By the way, he above works for unicode chars too, unless your pattern match table is outdated ;-))Another solution is to use an loop and RegEx: set str="abcd(123)/,op(56)*&^%$987ABC", i=0 set remove="[:punct:]|[:symbol:]" set keep = "()" while $locate(str,remove,i,i,c) { set:keep'[c $e(str,i-1)=" " }