Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mm_createstp.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Create a type 1 Stored Process (9.2 compatible)
4 @details This macro creates a Type 1 stored process, and also the necessary
5 PromptGroup / File / TextStore objects. It requires the location (or uri)
6 for the App Server / Directory / Folder (Tree) objects.
7 To upgrade this macro to work with type 2 (which can embed SAS code
8 and is compabitible with SAS from 9.3 onwards) then the UsageVersion should
9 change to 2000000 and the TextStore object updated. The ComputeServer
10 reference will also be to ServerContext rather than LogicalServer.
11
12 This macro is idempotent - if you run it twice, it will only create an STP
13 once.
14
15 Usage (type 1 STP):
16
17 %mm_createstp(stpname=MyNewSTP
18 ,filename=mySpecialProgram.sas
19 ,directory=SASEnvironment/SASCode/STPs
20 ,tree=/User Folders/sasdemo
21 ,outds=work.uris)
22
23 If you wish to remove the new STP you can do so by running:
24
25 data _null_;
26 set work.uris;
27 rc1 = METADATA_DELOBJ(texturi);
28 rc2 = METADATA_DELOBJ(prompturi);
29 rc3 = METADATA_DELOBJ(fileuri);
30 rc4 = METADATA_DELOBJ(stpuri);
31 putlog (_all_)(=);
32 run;
33
34 Usage (type 2 STP):
35
36 %mm_createstp(stpname=MyNewType2STP
37 ,filename=mySpecialProgram.sas
38 ,directory=SASEnvironment/SASCode/STPs
39 ,tree=/User Folders/sasdemo
40 ,Server=SASApp
41 ,stptype=2)
42
43 @param [in] stpname= (SASjs Default STP) Stored Process name.
44 Avoid spaces - testing has shown that
45 the check to avoid creating multiple STPs in the same folder with the same
46 name does not work when the name contains spaces.
47 @param [in] stpdesc= Stored Process description (optional)
48 @param [in] filename= the name of the .sas program to run
49 @param [in] directory= (SASEnvironment/sascode)
50 The directory uri or the actual path to the sas program (no trailing slash).
51 If more than uri is found with that path, then the first one will be used.
52 @param [in] tree= The metadata folder uri, or the metadata path, in which to
53 create the STP.
54 @param [in] server= (SASApp) The server which will run the STP.
55 Server name or uri is fine.
56 @param [out] outds= (work.mm_createstp)
57 The two level name of the output dataset. Will contain all the meta uris.
58 @param [in] mDebug= set to 1 to show debug messages in the log
59 @param [in] stptype= Default is 1 (STP code saved on filesystem). Set to 2 if
60 source code is to be saved in metadata (9.3 and above feature).
61 @param [in] minify= set to YES to strip comments / blank lines etc
62 @param [in] frefin= (mm_in) fileref to use (enables change if there is
63 a conflict).
64 The filerefs are left open, to enable inspection after running the
65 macro (or importing into an xmlmap if needed).
66 @param [out] frefout= (mm_out) fileref to use (enables change if there is
67 a conflict)
68 @param [in] repo= ServerContext is tied to a repo, if you are not using the
69 foundation repo then select a different one here
70 @param [in] LogicalServerType= (Sps) Server Type to use. Valid options:
71 @li Any - Uses the default server.
72 @li Sps - Stored Process Server, best choice for web app development. Runs
73 under a system account identity (eg sassrv).
74 @li Wks - Workspace Server. Runs under the end user identity.
75
76 @returns outds dataset containing the following columns:
77 - stpuri
78 - prompturi
79 - fileuri
80 - texturi
81
82 <h4> SAS Macros </h4>
83 @li mf_nobs.sas
84 @li mf_verifymacvars.sas
85 @li mm_getdirectories.sas
86 @li mm_updatestpsourcecode.sas
87 @li mm_getservercontexts.sas
88 @li mp_abort.sas
89 @li mp_dropmembers.sas
90
91 <h4> Related Macros </h4>
92 @li mm_createwebservice.sas
93
94 @version 9.2
95 @author Allan Bowe
96
97**/
98
99%macro mm_createstp(
100 stpname=SASjs Default STP
101 ,stpdesc=This stp was created automatically by the mm_createstp macro
102 ,filename=mm_createstp.sas
103 ,directory=SASEnvironment/SASCode
104 ,tree=/User Folders/sasdemo
105 ,package=false
106 ,streaming=true
107 ,outds=work.mm_createstp
108 ,mDebug=0
109 ,server=SASApp
110 ,stptype=1
111 ,minify=NO
112 ,frefin=mm_in
113 ,frefout=mm_out
114 ,LogicalServerType=Sps
115)/*/STORE SOURCE*/;
116
117%local mD;
118%if &mDebug=1 %then %let mD=;
119%else %let mD=%str(*);
120%&mD.put Executing mm_CreateSTP.sas;
121%&mD.put _local_;
122
123%mp_abort(
124 iftrue=(%mf_verifymacvars(stpname filename directory tree)=0)
125 ,mac=&sysmacroname
126 ,msg=%str(Empty inputs: stpname filename directory tree)
127)
128
129%mp_dropmembers(%scan(&outds,2,.))
130
131/* check LogicalServerType validity */
132%mp_abort(
133 iftrue=(
134 &LogicalServerType ne Sps
135 and &LogicalServerType ne Wks
136 and &LogicalServerType ne Any
137 )
138 ,mac=&sysmacroname
139 ,msg=%str(Invalid value for LogicalServerType (&LogicalServerType))
140)
141
142/**
143 * check tree exists
144 */
145data _null_;
146 length type uri $256;
147 rc=metadata_pathobj("","&tree","Folder",type,uri);
148 call symputx('foldertype',type,'l');
149 call symputx('treeuri',uri,'l');
150run;
151%if &foldertype ne Tree %then %do;
152 %put %str(WARN)ING: Tree &tree does not exist!;
153 %return;
154%end;
155
156/**
157 * Check STP does not exist already
158 */
159%local cmtype;
160data _null_;
161 length type uri $256;
162 rc=metadata_pathobj("","&tree/&stpname",'StoredProcess',type,uri);
163 call symputx('cmtype',type,'l');
164 call symputx('stpuri',uri,'l');
165run;
166%if &cmtype = ClassifierMap %then %do;
167 %put %str(WARN)ING: Stored Process &stpname already exists in &tree!;
168 %return;
169%end;
170
171/**
172 * Check that the physical file exists
173 */
174%if %sysfunc(fileexist(&directory/&filename)) ne 1 %then %do;
175 %put %str(WARN)ING: FILE *&directory/&filename* NOT FOUND!;
176 %return;
177%end;
178
179%if &stptype=1 %then %do;
180 /* type 1 STP - where code is stored on filesystem */
181 %if %sysevalf(&sysver lt 9.2) %then %do;
182 %put %str(WARN)ING: Version 9.2 or later required;
183 %return;
184 %end;
185
186 /* check directory object (where 9.2 source code reference is stored) */
187 data _null_;
188 length id $20 dirtype $256;
189 rc=metadata_resolve("&directory",dirtype,id);
190 call symputx('checkdirtype',dirtype,'l');
191 run;
192
193 %if &checkdirtype ne Directory %then %do;
194 %mm_getdirectories(path=&directory,outds=&outds ,mDebug=&mDebug)
195 %if %mf_nobs(&outds)=0 or %sysfunc(exist(&outds))=0 %then %do;
196 %put %str(WARN)ING: The directory object does not exist for &directory;
197 %return;
198 %end;
199 %end;
200 %else %do;
201 data &outds;
202 directoryuri="&directory";
203 run;
204 %end;
205
206 data &outds (keep=stpuri prompturi fileuri texturi);
207 length stpuri prompturi fileuri texturi serveruri $256 ;
208 if _n_=1 then call missing (of _all_);
209 set &outds;
210
211 /* final checks on uris */
212 length id $20 type $256;
213 __rc=metadata_resolve("&treeuri",type,id);
214 if type ne 'Tree' then do;
215 putlog "%str(WARN)ING: Invalid tree URI: &treeuri";
216 stopme=1;
217 end;
218 __rc=metadata_resolve(directoryuri,type,id);
219 if type ne 'Directory' then do;
220 putlog "%str(WARN)ING: Invalid directory URI: " directoryuri;
221 stopme=1;
222 end;
223
224 /* get server info */
225 __rc=metadata_resolve("&server",type,serveruri);
226 if type ne 'LogicalServer' then do;
227 __rc=metadata_getnobj("omsobj:LogicalServer?@Name='&server'",1,serveruri);
228 if serveruri='' then do;
229 putlog "%str(WARN)ING: Invalid server: &server";
230 stopme=1;
231 end;
232 end;
233
234 if stopme=1 then do;
235 putlog (_all_)(=);
236 stop;
237 end;
238
239 /* create empty prompt */
240 rc1=METADATA_NEWOBJ('PromptGroup',prompturi,'Parameters');
241 rc2=METADATA_SETATTR(prompturi, 'UsageVersion', '1000000');
242 rc3=METADATA_SETATTR(prompturi, 'GroupType','2');
243 rc4=METADATA_SETATTR(prompturi, 'Name','Parameters');
244 rc5=METADATA_SETATTR(prompturi, 'PublicType','Embedded:PromptGroup');
245 GroupInfo=
246 "<PromptGroup promptId='PromptGroup_%sysfunc(datetime())_&sysprocessid'"
247 !!" version='1.0'><Label><Text xml:lang='en-GB'>Parameters</Text>"
248 !!"</Label></PromptGroup>";
249 rc6 = METADATA_SETATTR(prompturi, 'GroupInfo',groupinfo);
250
251 if sum(of rc1-rc6) ne 0 then do;
252 putlog "%str(WARN)ING: Issue creating prompt.";
253 if prompturi ne . then do;
254 putlog ' Removing orphan: ' prompturi;
255 rc = METADATA_DELOBJ(prompturi);
256 put rc=;
257 end;
258 stop;
259 end;
260
261 /* create a file uri */
262 rc7=METADATA_NEWOBJ('File',fileuri,'SP Source File');
263 rc8=METADATA_SETATTR(fileuri, 'FileName',"&filename");
264 rc9=METADATA_SETATTR(fileuri, 'IsARelativeName','1');
265 rc10=METADATA_SETASSN(fileuri, 'Directories','MODIFY',directoryuri);
266 if sum(of rc7-rc10) ne 0 then do;
267 putlog "%str(WARN)ING: Issue creating file.";
268 if fileuri ne . then do;
269 putlog ' Removing orphans:' prompturi fileuri;
270 rc = METADATA_DELOBJ(prompturi);
271 rc = METADATA_DELOBJ(fileuri);
272 put (_all_)(=);
273 end;
274 stop;
275 end;
276
277 /* create a TextStore object */
278 rc11= METADATA_NEWOBJ('TextStore',texturi,'Stored Process');
279 rc12= METADATA_SETATTR(texturi, 'TextRole','StoredProcessConfiguration');
280 rc13= METADATA_SETATTR(texturi, 'TextType','XML');
281 storedtext='<?xml version="1.0" encoding="UTF-8"?><StoredProcess>'
282 !!"<ResultCapabilities Package='&package' Streaming='&streaming'/>"
283 !!"<OutputParameters/></StoredProcess>";
284 rc14= METADATA_SETATTR(texturi, 'StoredText',storedtext);
285 if sum(of rc11-rc14) ne 0 then do;
286 putlog "%str(WARN)ING: Issue creating TextStore.";
287 if texturi ne . then do;
288 putlog ' Removing orphans: ' prompturi fileuri texturi;
289 rc = METADATA_DELOBJ(prompturi);
290 rc = METADATA_DELOBJ(fileuri);
291 rc = METADATA_DELOBJ(texturi);
292 put (_all_)(=);
293 end;
294 stop;
295 end;
296
297 /* create meta obj */
298 rc15= METADATA_NEWOBJ('ClassifierMap',stpuri,"&stpname");
299 rc16= METADATA_SETASSN(stpuri, 'Trees','MODIFY',treeuri);
300 rc17= METADATA_SETASSN(stpuri, 'ComputeLocations','MODIFY',serveruri);
301 rc18= METADATA_SETASSN(stpuri, 'SourceCode','MODIFY',fileuri);
302 rc19= METADATA_SETASSN(stpuri, 'Prompts','MODIFY',prompturi);
303 rc20= METADATA_SETASSN(stpuri, 'Notes','MODIFY',texturi);
304 rc21= METADATA_SETATTR(stpuri, 'PublicType', 'StoredProcess');
305 rc22= METADATA_SETATTR(stpuri, 'TransformRole', 'StoredProcess');
306 rc23= METADATA_SETATTR(stpuri, 'UsageVersion', '1000000');
307 rc24= METADATA_SETATTR(stpuri, 'Desc', "&stpdesc");
308
309 /* tidy up if err */
310 if sum(of rc15-rc24) ne 0 then do;
311 putlog "%str(WARN)ING: Issue creating STP.";
312 if stpuri ne . then do;
313 putlog ' Removing orphans: ' prompturi fileuri texturi stpuri;
314 rc = METADATA_DELOBJ(prompturi);
315 rc = METADATA_DELOBJ(fileuri);
316 rc = METADATA_DELOBJ(texturi);
317 rc = METADATA_DELOBJ(stpuri);
318 put (_all_)(=);
319 end;
320 end;
321 else do;
322 fullpath=cats('_program=',treepath,"/&stpname");
323 putlog "NOTE: Stored Process Created!";
324 putlog "NOTE- "; putlog "NOTE-"; putlog "NOTE-" fullpath;
325 putlog "NOTE- "; putlog "NOTE-";
326 end;
327 output;
328 stop;
329 run;
330%end;
331%else %if &stptype=2 %then %do;
332 /* type 2 stp - code is stored in metadata */
333 %if %sysevalf(&sysver lt 9.3) %then %do;
334 %put %str(WARN)ING: SAS version 9.3 or later required to create type2 STPs;
335 %return;
336 %end;
337 /* check we have the correct ServerContext */
338 %mm_getservercontexts(outds=contexts)
339 %local serveruri; %let serveruri=NOTFOUND;
340 data _null_;
341 set contexts;
342 where upcase(servername)="%upcase(&server)";
343 call symputx('serveruri',serveruri);
344 run;
345 %if &serveruri=NOTFOUND %then %do;
346 %put %str(WARN)ING: ServerContext *&server* not found!;
347 %return;
348 %end;
349
350 /**
351 * First, create a Hello World type 2 stored process
352 */
353 filename &frefin temp;
354 data _null_;
355 file &frefin;
356 treeuri=quote(symget('treeuri'));
357 serveruri=quote(symget('serveruri'));
358 stpdesc=quote(symget('stpdesc'));
359 stpname=quote(symget('stpname'));
360
361 put "<AddMetadata><Reposid>$METAREPOSITORY</Reposid><Metadata> "/
362 '<ClassifierMap UsageVersion="2000000" IsHidden="0" IsUserDefined="0" '/
363 ' IsActive="1" PublicType="StoredProcess" TransformRole="StoredProcess" '/
364 ' Name=' stpname ' Desc=' stpdesc '>'/
365 " <ComputeLocations>"/
366 " <ServerContext ObjRef=" serveruri "/>"/
367 " </ComputeLocations>"/
368 "<Notes> "/
369 ' <TextStore IsHidden="0" Name="SourceCode" UsageVersion="0" '/
370 ' TextRole="StoredProcessSourceCode" StoredText="%put hello world!;" />'/
371 ' <TextStore IsHidden="0" Name="Stored Process" UsageVersion="0" '/
372 ' TextRole="StoredProcessConfiguration" TextType="XML" '/
373 ' StoredText="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&qu'@@
374 'ot;?&gt;&lt;StoredProcess&gt;&lt;ServerContext LogicalServerType=&quot;'@@
375 "&LogicalServerType"@@
376 '&quot; OtherAllowed=&quot;false&quot;/&gt;&lt;ResultCapabilities Packa'@@
377 'ge=&quot;' @@ "&package" @@ '&quot; Streaming=&quot;' @@ "&streaming" @@
378 '&quot;/&gt;&lt;OutputParameters/&gt;&lt;/StoredProcess&gt;" />' /
379 " </Notes> "/
380 " <Prompts> "/
381 ' <PromptGroup Name="Parameters" GroupType="2" IsHidden="0" '/
382 ' PublicType="Embedded:PromptGroup" UsageVersion="1000000" '/
383 ' GroupInfo="&lt;PromptGroup promptId=&quot;PromptGroup_1502797359253'@@
384 '_802080&quot; version=&quot;1.0&quot;&gt;&lt;Label&gt;&lt;Text xml:lang='@@
385 '&quot;en-US&quot;&gt;Parameters&lt;/Text&gt;&lt;/Label&gt;&lt;/PromptGro'@@
386 'up&gt;" />'/
387 " </Prompts> "/
388 "<Trees><Tree ObjRef=" treeuri "/></Trees>"/
389 "</ClassifierMap></Metadata><NS>SAS</NS>"/
390 "<Flags>268435456</Flags></AddMetadata>";
391 run;
392
393 filename &frefout temp;
394
395 proc metadata in= &frefin out=&frefout ;
396 run;
397
398 %if &mdebug=1 %then %do;
399 /* write the response to the log for debugging */
400 data _null_;
401 infile &frefout lrecl=1048576;
402 input;
403 put _infile_;
404 run;
405 %end;
406
407 /**
408 * Next, add the source code
409 */
410 %mm_updatestpsourcecode(stp=&tree/&stpname
411 ,stpcode="&directory/&filename"
412 ,mdebug=&mdebug
413 ,minify=&minify)
414
415
416%end;
417%else %do;
418 %put %str(WARN)ING: STPTYPE=*&stptype* not recognised!;
419%end;
420
421%mend mm_createstp;