Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mm_createwebservice.sas
Go to the documentation of this file.
1/**
2 @file mm_createwebservice.sas
3 @brief Create a Web Ready Stored Process
4 @details This macro creates a Type 2 Stored Process with the mm_webout macro
5 (and dependencies) included as pre-code.
6
7Usage:
8
9 %* compile macros ;
10 filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
11 %inc mc;
12
13 %* parmcards lets us write to a text file from open code ;
14 filename ft15f001 temp;
15 parmcards4;
16 %webout(FETCH)
17 %* do some sas, any inputs are now already WORK tables;
18 data example1 example2;
19 set sashelp.class;
20 run;
21 %* send data back;
22 %webout(OPEN)
23 %webout(ARR,example1) * Array format, fast, suitable for large tables ;
24 %webout(OBJ,example2) * Object format, easier to work with ;
25 %webout(CLOSE)
26 ;;;;
27 %mm_createwebservice(path=/Public/app/common,name=appInit,code=ft15f001)
28
29 For more examples of using these web services with the SASjs Adapter, see:
30 https://github.com/sasjs/adapter#readme
31
32 @param [in] path= () The full path (in SAS Metadata) where the service
33 will be created
34 @param [in] name= Stored Process name. Avoid spaces - testing has shown that
35 the check to avoid creating multiple STPs in the same folder with the same
36 name does not work when the name contains spaces.
37 @param [in] desc= The description of the service (optional)
38 @param [in] precode= () Space separated list of filerefs, pointing to the
39 code that needs to be attached to the beginning of the service (optional)
40 @param [in] code= (ft15f001) Space seperated fileref(s) of the actual code
41 to be added
42 @param [in] server= (SASApp) The server which will run the STP. Server
43 name or uri is fine.
44 @param [in] mDebug= (0) set to 1 to show debug messages in the log
45 @param [in] replace= (YES) select NO to avoid replacing an existing service
46 in that location
47 @param [in] adapter= (sasjs) the macro uses the sasjs adapter by default.
48 To use another adapter, add a (different) fileref here.
49
50 <h4> SAS Macros </h4>
51 @li mm_createstp.sas
52 @li mf_getuser.sas
53 @li mm_createfolder.sas
54 @li mm_deletestp.sas
55
56 @version 9.2
57 @author Allan Bowe
58
59 @sasjslint {"maxLineLength": 93}
60**/
61
62%macro mm_createwebservice(path=
63 ,name=initService
64 ,precode=
65 ,code=ft15f001
66 ,desc=This stp was created automagically by the mm_createwebservice macro
67 ,mDebug=0
68 ,server=SASApp
69 ,replace=YES
70 ,adapter=sasjs
71)/*/STORE SOURCE*/;
72
73%if &syscc ge 4 %then %do;
74 %put &=syscc - &sysmacroname will not execute in this state;
75 %return;
76%end;
77
78%local mD;
79%if &mDebug=1 %then %let mD=;
80%else %let mD=%str(*);
81%&mD.put Executing mm_createwebservice.sas;
82%&mD.put _local_;
83
84/* remove any trailing slash */
85%if "%substr(&path,%length(&path),1)" = "/" %then
86 %let path=%substr(&path,1,%length(&path)-1);
87
88/**
89 * Add webout macro
90 * These put statements are auto generated - to change the macro, change the
91 * source (mm_webout) and run `build.py`
92 */
93filename sasjs temp;
94data _null_;
95 file sasjs lrecl=3000 ;
96 put "/* Created on %sysfunc(datetime(),datetime19.) by %mf_getuser() */";
97/* WEBOUT BEGIN */
98 put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y ';
99 put ' ,engine=DATASTEP ';
100 put ' ,missing=NULL ';
101 put ' ,showmeta=N ';
102 put ' ,maxobs=MAX ';
103 put ')/*/STORE SOURCE*/; ';
104 put '%local tempds colinfo fmtds i numcols numobs stmt_obs lastobs optval ';
105 put ' tmpds1 tmpds2 tmpds3 tmpds4; ';
106 put '%let numcols=0; ';
107 put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
108 put ' ';
109 put '%if &action=OPEN %then %do; ';
110 put ' options nobomfile; ';
111 put ' data _null_;file &jref encoding=''utf-8'' lrecl=200; ';
112 put ' put ''{"PROCESSED_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''"''; ';
113 put ' run; ';
114 put '%end; ';
115 put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
116 put ' /* force variable names to always be uppercase in the JSON */ ';
117 put ' options validvarname=upcase; ';
118 put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
119 put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
120 put ' filename _sjs1 temp lrecl=200 ; ';
121 put ' data _null_; file _sjs1 encoding=''utf-8''; ';
122 put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
123 put ' run; ';
124 put ' /* now write to _webout 1 char at a time */ ';
125 put ' data _null_; ';
126 put ' infile _sjs1 lrecl=1 recfm=n; ';
127 put ' file &jref mod lrecl=1 recfm=n; ';
128 put ' input sourcechar $char1. @@; ';
129 put ' format sourcechar hex2.; ';
130 put ' put sourcechar char1. @@; ';
131 put ' run; ';
132 put ' filename _sjs1 clear; ';
133 put ' ';
134 put ' /* grab col defs */ ';
135 put ' proc contents noprint data=&ds ';
136 put ' out=_data_(keep=name type length format formatl formatd varnum label); ';
137 put ' run; ';
138 put ' %let colinfo=%scan(&syslast,2,.); ';
139 put ' proc sort data=&colinfo; ';
140 put ' by varnum; ';
141 put ' run; ';
142 put ' /* move meta to mac vars */ ';
143 put ' data &colinfo; ';
144 put ' if _n_=1 then call symputx(''numcols'',nobs,''l''); ';
145 put ' set &colinfo end=last nobs=nobs; ';
146 put ' name=upcase(name); ';
147 put ' /* fix formats */ ';
148 put ' if type=2 or type=6 then do; ';
149 put ' typelong=''char''; ';
150 put ' length fmt $49.; ';
151 put ' if format='''' then fmt=cats(''$'',length,''.''); ';
152 put ' else if formatl=0 then fmt=cats(format,''.''); ';
153 put ' else fmt=cats(format,formatl,''.''); ';
154 put ' end; ';
155 put ' else do; ';
156 put ' typelong=''num''; ';
157 put ' if format='''' then fmt=''best.''; ';
158 put ' else if formatl=0 then fmt=cats(format,''.''); ';
159 put ' else if formatd=0 then fmt=cats(format,formatl,''.''); ';
160 put ' else fmt=cats(format,formatl,''.'',formatd); ';
161 put ' end; ';
162 put ' /* 32 char unique name */ ';
163 put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
164 put ' ';
165 put ' call symputx(cats(''name'',_n_),name,''l''); ';
166 put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
167 put ' call symputx(cats(''length'',_n_),length,''l''); ';
168 put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
169 put ' call symputx(cats(''type'',_n_),type,''l''); ';
170 put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
171 put ' call symputx(cats(''label'',_n_),coalescec(label,name),''l''); ';
172 put ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
173 put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); ';
174 put ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+10)*1.5)),''l''); ';
175 put ' run; ';
176 put ' ';
177 put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
178 put ' proc sql noprint; ';
179 put ' select count(*) into: lastobs from &ds; ';
180 put ' %if &maxobs ne MAX %then %let lastobs=%sysfunc(min(&lastobs,&maxobs)); ';
181 put ' ';
182 put ' %if &engine=PROCJSON %then %do; ';
183 put ' %if &missing=STRING %then %do; ';
184 put ' %put &sysmacroname: Special Missings not supported in proc json.; ';
185 put ' %put &sysmacroname: Switching to DATASTEP engine; ';
186 put ' %goto datastep; ';
187 put ' %end; ';
188 put ' data &tempds; ';
189 put ' set &ds; ';
190 put ' &stmt_obs; ';
191 put ' %if &fmt=N %then format _numeric_ best32.;; ';
192 put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
193 put ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
194 put ' proc json out=_sjs2 pretty ';
195 put ' %if &action=ARR %then nokeys ; ';
196 put ' ;export &tempds / nosastags fmtnumeric; ';
197 put ' run; ';
198 put ' /* send back to webout */ ';
199 put ' data _null_; ';
200 put ' infile _sjs2 lrecl=1 recfm=n; ';
201 put ' file &jref mod lrecl=1 recfm=n; ';
202 put ' input sourcechar $char1. @@; ';
203 put ' format sourcechar hex2.; ';
204 put ' put sourcechar char1. @@; ';
205 put ' run; ';
206 put ' filename _sjs2 clear; ';
207 put ' %end; ';
208 put ' %else %if &engine=DATASTEP %then %do; ';
209 put ' %datastep: ';
210 put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 ';
211 put ' %then %do; ';
212 put ' %put &sysmacroname: &ds NOT FOUND!!!; ';
213 put ' %return; ';
214 put ' %end; ';
215 put ' ';
216 put ' %if &fmt=Y %then %do; ';
217 put ' /** ';
218 put ' * Extract format definitions ';
219 put ' * First, by getting library locations from dictionary.formats ';
220 put ' * Then, by exporting the width using proc format ';
221 put ' * Cannot use maxw from sashelp.vformat as not always populated ';
222 put ' * Cannot use fmtinfo() as not supported in all flavours ';
223 put ' */ ';
224 put ' %let tmpds1=%substr(fmtsum%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
225 put ' %let tmpds2=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
226 put ' %let tmpds3=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
227 put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
228 put ' proc sql noprint; ';
229 put ' create table &tmpds1 as ';
230 put ' select cats(libname,''.'',memname) as FMTCAT, ';
231 put ' FMTNAME ';
232 put ' from dictionary.formats ';
233 put ' where fmttype=''F'' and libname is not null ';
234 put ' and fmtname in (select format from &colinfo where format is not null) ';
235 put ' order by 1; ';
236 put ' create table &tmpds2( ';
237 put ' FMTNAME char(32), ';
238 put ' LENGTH num ';
239 put ' ); ';
240 put ' %local catlist cat fmtlist i; ';
241 put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
242 put ' %do i=1 %to %sysfunc(countw(&catlist,%str( ))); ';
243 put ' %let cat=%scan(&catlist,&i,%str( )); ';
244 put ' proc sql; ';
245 put ' select distinct fmtname into: fmtlist separated by '' '' ';
246 put ' from &tmpds1 where fmtcat="&cat"; ';
247 put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
248 put ' select &fmtlist; ';
249 put ' run; ';
250 put ' proc sql; ';
251 put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
252 put ' %end; ';
253 put ' ';
254 put ' proc sql; ';
255 put ' create table &tmpds4 as ';
256 put ' select a.*, b.length as MAXW ';
257 put ' from &colinfo a ';
258 put ' left join &tmpds2 b ';
259 put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
260 put ' order by a.varnum; ';
261 put ' data _null_; ';
262 put ' set &tmpds4; ';
263 put ' if not missing(maxw); ';
264 put ' call symputx( ';
265 put ' cats(''fmtlen'',_n_), ';
266 put ' /* vars need extra padding due to JSON escaping of special chars */ ';
267 put ' min(32767,ceil((max(length,maxw)+10)*1.5)) ';
268 put ' ,''l'' ';
269 put ' ); ';
270 put ' run; ';
271 put ' ';
272 put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
273 put ' %let optval=%sysfunc(getoption(varlenchk)); ';
274 put ' options varlenchk=NOWARN; ';
275 put ' data _data_(compress=char); ';
276 put ' /* shorten the new vars */ ';
277 put ' length ';
278 put ' %do i=1 %to &numcols; ';
279 put ' &&name&i $&&fmtlen&i ';
280 put ' %end; ';
281 put ' ; ';
282 put ' /* rename on entry */ ';
283 put ' set &ds(rename=( ';
284 put ' %do i=1 %to &numcols; ';
285 put ' &&name&i=&&newname&i ';
286 put ' %end; ';
287 put ' )); ';
288 put ' &stmt_obs; ';
289 put ' ';
290 put ' drop ';
291 put ' %do i=1 %to &numcols; ';
292 put ' &&newname&i ';
293 put ' %end; ';
294 put ' ; ';
295 put ' %do i=1 %to &numcols; ';
296 put ' %if &&typelong&i=num %then %do; ';
297 put ' &&name&i=cats(put(&&newname&i,&&fmt&i)); ';
298 put ' %end; ';
299 put ' %else %do; ';
300 put ' &&name&i=put(&&newname&i,&&fmt&i); ';
301 put ' %end; ';
302 put ' %end; ';
303 put ' if _error_ then do; ';
304 put ' call symputx(''syscc'',1012); ';
305 put ' stop; ';
306 put ' end; ';
307 put ' run; ';
308 put ' %let fmtds=&syslast; ';
309 put ' options varlenchk=&optval; ';
310 put ' %end; ';
311 put ' ';
312 put ' proc format; /* credit yabwon for special null removal */ ';
313 put ' value bart (default=40) ';
314 put ' %if &missing=NULL %then %do; ';
315 put ' ._ - .z = null ';
316 put ' %end; ';
317 put ' %else %do; ';
318 put ' ._ = [quote()] ';
319 put ' . = null ';
320 put ' .a - .z = [quote()] ';
321 put ' %end; ';
322 put ' other = [best.]; ';
323 put ' ';
324 put ' data &tempds; ';
325 put ' attrib _all_ label=''''; ';
326 put ' %do i=1 %to &numcols; ';
327 put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
328 put ' length &&name&i $&&fmtlen&i...; ';
329 put ' format &&name&i $&&fmtlen&i...; ';
330 put ' %end; ';
331 put ' %end; ';
332 put ' %if &fmt=Y %then %do; ';
333 put ' set &fmtds; ';
334 put ' %end; ';
335 put ' %else %do; ';
336 put ' set &ds; ';
337 put ' %end; ';
338 put ' &stmt_obs; ';
339 put ' format _numeric_ bart.; ';
340 put ' %do i=1 %to &numcols; ';
341 put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
342 put ' if findc(&&name&i,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
343 put ' &&name&i=''"''!!trim( ';
344 put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
345 put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
346 put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
347 put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
348 put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
349 put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
350 put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
351 put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
352 put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
353 put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
354 put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
355 put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
356 put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
357 put ' )))))))))))))!!''"''; ';
358 put ' end; ';
359 put ' /* trim (not cats) so leading blanks are retained */ ';
360 put ' else &&name&i=''"''!!trim(&&name&i)!!''"''; ';
361 put ' %end; ';
362 put ' %end; ';
363 put ' run; ';
364 put ' ';
365 put ' filename _sjs3 temp lrecl=131068 ; ';
366 put ' data _null_; ';
367 put ' file _sjs3 encoding=''utf-8''; ';
368 put ' if _n_=1 then put "["; ';
369 put ' set &tempds; ';
370 put ' if _n_>1 then put "," @; put ';
371 put ' %if &action=ARR %then "[" ; %else "{" ; ';
372 put ' %do i=1 %to &numcols; ';
373 put ' %if &i>1 %then "," ; ';
374 put ' %if &action=OBJ %then """&&name&i"":" ; ';
375 put ' "&&name&i"n /* name literal for reserved variable names */ ';
376 put ' %end; ';
377 put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
378 put ' ';
379 put ' /* close out the table */ ';
380 put ' data _null_; ';
381 put ' file _sjs3 mod encoding=''utf-8''; ';
382 put ' put '']''; ';
383 put ' run; ';
384 put ' data _null_; ';
385 put ' infile _sjs3 lrecl=1 recfm=n; ';
386 put ' file &jref mod lrecl=1 recfm=n; ';
387 put ' input sourcechar $char1. @@; ';
388 put ' format sourcechar hex2.; ';
389 put ' put sourcechar char1. @@; ';
390 put ' run; ';
391 put ' filename _sjs3 clear; ';
392 put ' %end; ';
393 put ' ';
394 put ' proc sql; ';
395 put ' drop table &colinfo, &tempds; ';
396 put ' ';
397 put ' %if %substr(&showmeta,1,1)=Y %then %do; ';
398 put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
399 put ' data _null_; ';
400 put ' file _sjs4; ';
401 put ' length label $350; ';
402 put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
403 put ' do i=1 to &numcols; ';
404 put ' name=quote(trim(symget(cats(''name'',i)))); ';
405 put ' format=quote(trim(symget(cats(''fmt'',i)))); ';
406 put ' label=quote(prxchange(''s/\\/\\\\/'',-1,trim(symget(cats(''label'',i))))); ';
407 put ' length=quote(trim(symget(cats(''length'',i)))); ';
408 put ' type=quote(trim(symget(cats(''typelong'',i)))); ';
409 put ' if i>1 then put "," @@; ';
410 put ' put name '':{"format":'' format '',"label":'' label ';
411 put ' '',"length":'' length '',"type":'' type ''}''; ';
412 put ' end; ';
413 put ' put ''}}''; ';
414 put ' run; ';
415 put ' /* send back to webout */ ';
416 put ' data _null_; ';
417 put ' infile _sjs4 lrecl=1 recfm=n; ';
418 put ' file &jref mod lrecl=1 recfm=n; ';
419 put ' input sourcechar $char1. @@; ';
420 put ' format sourcechar hex2.; ';
421 put ' put sourcechar char1. @@; ';
422 put ' run; ';
423 put ' filename _sjs4 clear; ';
424 put ' %end; ';
425 put '%end; ';
426 put ' ';
427 put '%else %if &action=CLOSE %then %do; ';
428 put ' data _null_; file &jref encoding=''utf-8'' mod ; ';
429 put ' put "}"; ';
430 put ' run; ';
431 put '%end; ';
432 put '%mend mp_jsonout; ';
433 put ' ';
434 put '%macro mf_getuser( ';
435 put ')/*/STORE SOURCE*/; ';
436 put ' %local user; ';
437 put ' ';
438 put ' %if %symexist(_sasjs_username) %then %let user=&_sasjs_username; ';
439 put ' %else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do; ';
440 put ' %let user=&SYS_COMPUTE_SESSION_OWNER; ';
441 put ' %end; ';
442 put ' %else %if %symexist(_metaperson) %then %do; ';
443 put ' %if %length(&_metaperson)=0 %then %let user=&sysuserid; ';
444 put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
445 put ' /* but be sure to quote in case of usernames with commas */ ';
446 put ' %else %let user=%unquote(%scan(%quote(&_metaperson),1,@)); ';
447 put ' %end; ';
448 put ' %else %let user=&sysuserid; ';
449 put ' ';
450 put ' %quote(&user) ';
451 put ' ';
452 put '%mend mf_getuser; ';
453 put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=N,missing=NULL ';
454 put ' ,showmeta=N,maxobs=MAX,workobs=0 ';
455 put '); ';
456 put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
457 put ' sasjs_tables; ';
458 put '%local i tempds jsonengine; ';
459 put ' ';
460 put '/* see https://github.com/sasjs/core/issues/41 */ ';
461 put '%if "%upcase(&SYSENCODING)" ne "UTF-8" %then %let jsonengine=PROCJSON; ';
462 put '%else %let jsonengine=DATASTEP; ';
463 put ' ';
464 put ' ';
465 put '%if &action=FETCH %then %do; ';
466 put ' %if %str(&_debug) ge 131 %then %do; ';
467 put ' options mprint notes mprintnest; ';
468 put ' %end; ';
469 put ' %let _webin_file_count=%eval(&_webin_file_count+0); ';
470 put ' /* now read in the data */ ';
471 put ' %do i=1 %to &_webin_file_count; ';
472 put ' %if &_webin_file_count=1 %then %do; ';
473 put ' %let _webin_fileref1=&_webin_fileref; ';
474 put ' %let _webin_name1=&_webin_name; ';
475 put ' %end; ';
476 put ' data _null_; ';
477 put ' infile &&_webin_fileref&i termstr=crlf; ';
478 put ' input; ';
479 put ' /* a plain $ informat strips leading blanks - use $char instead */ ';
480 put ' call symputx(''input_statement'' ';
481 put ' ,prxchange(''s/:\$(?=[0-9 ])/:\$char/i'',-1,_infile_) ';
482 put ' ); ';
483 put ' putlog "&&_webin_name&i input statement: " _infile_; ';
484 put ' stop; ';
485 put ' data &&_webin_name&i; ';
486 put ' infile &&_webin_fileref&i firstobs=2 dsd termstr=crlf encoding=''utf-8''; ';
487 put ' input &input_statement; ';
488 put ' %if %str(&_debug) ge 131 %then %do; ';
489 put ' if _n_<20 then putlog _infile_; ';
490 put ' %end; ';
491 put ' run; ';
492 put ' %let sasjs_tables=&sasjs_tables &&_webin_name&i; ';
493 put ' %end; ';
494 put '%end; ';
495 put ' ';
496 put '%else %if &action=OPEN %then %do; ';
497 put ' /* fix encoding */ ';
498 put ' OPTIONS NOBOMFILE; ';
499 put ' ';
500 put ' /** ';
501 put ' * check xengine type to avoid the below err message: ';
502 put ' * > Function is only valid for filerefs using the CACHE access method. ';
503 put ' */ ';
504 put ' data _null_; ';
505 put ' set sashelp.vextfl(where=(fileref="_WEBOUT")); ';
506 put ' if xengine=''STREAM'' then do; ';
507 put ' rc=stpsrv_header(''Content-type'',"text/html; encoding=utf-8"); ';
508 put ' end; ';
509 put ' run; ';
510 put ' ';
511 put ' /* setup json */ ';
512 put ' data _null_;file &fref encoding=''utf-8''; ';
513 put ' %if %str(&_debug) ge 131 %then %do; ';
514 put ' put ''>>weboutBEGIN<<''; ';
515 put ' %end; ';
516 put ' put ''{"SYSDATE" : "'' "&SYSDATE" ''"''; ';
517 put ' put '',"SYSTIME" : "'' "&SYSTIME" ''"''; ';
518 put ' run; ';
519 put ' ';
520 put '%end; ';
521 put ' ';
522 put '%else %if &action=ARR or &action=OBJ %then %do; ';
523 put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
524 put ' ,engine=&jsonengine,missing=&missing,showmeta=&showmeta,maxobs=&maxobs ';
525 put ' ) ';
526 put '%end; ';
527 put '%else %if &action=CLOSE %then %do; ';
528 put ' /* To avoid issues with _webout on EBI we use a temporary file */ ';
529 put ' filename _sjsref temp lrecl=131068; ';
530 put ' %if %str(&workobs) > 0 %then %do; ';
531 put ' /* if debug mode, send back first XX records of each work table also */ ';
532 put ' data;run;%let tempds=%scan(&syslast,2,.); ';
533 put ' ods output Members=&tempds; ';
534 put ' proc datasets library=WORK memtype=data; ';
535 put ' %local wtcnt;%let wtcnt=0; ';
536 put ' data _null_; ';
537 put ' set &tempds; ';
538 put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
539 put ' i+1; ';
540 put ' call symputx(cats(''wt'',i),name,''l''); ';
541 put ' call symputx(''wtcnt'',i,''l''); ';
542 put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
543 put ' put ",""WORK"":{"; ';
544 put ' %do i=1 %to &wtcnt; ';
545 put ' %let wt=&&wt&i; ';
546 put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
547 put ' dsid=open("WORK.&wt",''is''); ';
548 put ' nlobs=attrn(dsid,''NLOBS''); ';
549 put ' nvars=attrn(dsid,''NVARS''); ';
550 put ' rc=close(dsid); ';
551 put ' if &i>1 then put '',''@; ';
552 put ' put " ""&wt"" : {"; ';
553 put ' put ''"nlobs":'' nlobs; ';
554 put ' put '',"nvars":'' nvars; ';
555 put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y ';
556 put ' ,maxobs=&workobs ';
557 put ' ) ';
558 put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
559 put ' put "}"; ';
560 put ' %end; ';
561 put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
562 put ' put "}"; ';
563 put ' run; ';
564 put ' %end; ';
565 put ' /* close off json */ ';
566 put ' data _null_;file _sjsref mod encoding=''utf-8''; ';
567 put ' length SYSPROCESSNAME syserrortext syswarningtext autoexec $512; ';
568 put ' put ",""_DEBUG"" : ""&_debug"" "; ';
569 put ' _METAUSER=quote(trim(symget(''_METAUSER''))); ';
570 put ' put ",""_METAUSER"": " _METAUSER; ';
571 put ' _METAPERSON=quote(trim(symget(''_METAPERSON''))); ';
572 put ' put '',"_METAPERSON": '' _METAPERSON; ';
573 put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
574 put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
575 put ' autoexec=quote(urlencode(trim(getoption(''autoexec'')))); ';
576 put ' put '',"AUTOEXEC" : '' autoexec; ';
577 put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
578 put ' put ",""SYSCC"" : ""&syscc"" "; ';
579 put ' put ",""SYSENCODING"" : ""&sysencoding"" "; ';
580 put ' syserrortext=cats(symget(''syserrortext'')); ';
581 put ' if findc(syserrortext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
582 put ' syserrortext=''"''!!trim( ';
583 put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
584 put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
585 put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
586 put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
587 put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
588 put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
589 put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
590 put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
591 put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
592 put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
593 put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
594 put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
595 put ' prxchange(''s/\\/\\\\/'',-1,syserrortext) ';
596 put ' )))))))))))))!!''"''; ';
597 put ' end; ';
598 put ' else syserrortext=cats(''"'',syserrortext,''"''); ';
599 put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
600 put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
601 put ' put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" "; ';
602 put ' put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" "; ';
603 put ' SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME))); ';
604 put ' put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME; ';
605 put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
606 put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
607 put ' put ",""SYSSITE"" : ""&syssite"" "; ';
608 put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
609 put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
610 put ' put '',"SYSVLONG" : '' sysvlong; ';
611 put ' syswarningtext=cats(symget(''syswarningtext'')); ';
612 put ' if findc(syswarningtext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
613 put ' syswarningtext=''"''!!trim( ';
614 put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
615 put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
616 put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
617 put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
618 put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
619 put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
620 put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
621 put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
622 put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
623 put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
624 put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
625 put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
626 put ' prxchange(''s/\\/\\\\/'',-1,syswarningtext) ';
627 put ' )))))))))))))!!''"''; ';
628 put ' end; ';
629 put ' else syswarningtext=cats(''"'',syswarningtext,''"''); ';
630 put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
631 put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
632 put ' length memsize $32; ';
633 put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; ';
634 put ' memsize=quote(cats(memsize)); ';
635 put ' put '',"MEMSIZE" : '' memsize; ';
636 put ' put "}" @; ';
637 put ' %if %str(&_debug) ge 131 %then %do; ';
638 put ' put ''>>weboutEND<<''; ';
639 put ' %end; ';
640 put ' run; ';
641 put ' /* now write to _webout 1 char at a time */ ';
642 put ' data _null_; ';
643 put ' infile _sjsref lrecl=1 recfm=n; ';
644 put ' file &fref mod lrecl=1 recfm=n; ';
645 put ' input sourcechar $char1. @@; ';
646 put ' format sourcechar hex2.; ';
647 put ' put sourcechar char1. @@; ';
648 put ' run; ';
649 put ' filename _sjsref clear; ';
650 put ' ';
651 put '%end; ';
652 put ' ';
653 put '%mend mm_webout; ';
654/* WEBOUT END */
655 put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO';
656 put ' ,maxobs=MAX';
657 put ');';
658 put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
659 put ' ,showmeta=&showmeta,maxobs=&maxobs';
660 put ' )';
661 put '%mend;';
662run;
663
664/* add precode and code */
665%local work tmpfile;
666%let work=%sysfunc(pathname(work));
667%let tmpfile=__mm_createwebservice.temp;
668%local x fref freflist mod;
669%let freflist= &adapter &precode &code ;
670%do x=1 %to %sysfunc(countw(&freflist));
671 %if &x>1 %then %let mod=mod;
672
673 %let fref=%scan(&freflist,&x);
674 %&mD.put &sysmacroname: adding &fref;
675 data _null_;
676 file "&work/&tmpfile" lrecl=3000 &mod;
677 infile &fref;
678 input;
679 put _infile_;
680 run;
681%end;
682
683/* create the metadata folder if not already there */
684%mm_createfolder(path=&path)
685%if &syscc ge 4 %then %return;
686
687%if %upcase(&replace)=YES %then %do;
688 %mm_deletestp(target=&path/&name)
689%end;
690
691/* create the web service */
692%mm_createstp(stpname=&name
693 ,filename=&tmpfile
694 ,directory=&work
695 ,tree=&path
696 ,stpdesc=&desc
697 ,mDebug=&mdebug
698 ,server=&server
699 ,stptype=2)
700
701/* find the web app url */
702%local url;
703%let url=localhost/SASStoredProcess;
704data _null_;
705 length url $128;
706 rc=METADATA_GETURI("Stored Process Web App",url);
707 if rc=0 then call symputx('url',url,'l');
708run;
709
710%put &sysmacroname: STP &name successfully created in &path;
711%put Check it out here:;
712%put ;%put ;%put ;
713%put &url?_PROGRAM=&path/&name;
714%put ;%put ;%put ;
715
716%mend mm_createwebservice;