@@ -12,19 +12,18 @@ All logic related to the proceccing of http requests.</Description>
1212<Default >1</Default >
1313</Parameter >
1414
15- <Method name =" DispatchRequest" >
16- <Description ><![CDATA[
17- Dispatch a REST request according to URL and Method.<br>
18- Add param Namespace to a request to execute MDX in desired namespace.]]> </Description >
19- <Internal >1</Internal >
15+ <Method name =" OnPreDispatch" >
16+ <Description >
17+ This method gets called prior to dispatch of the request. Put any common code here
18+ that you want to be executed for EVERY request. If pContinue is set to 0, the
19+ request will NOT be dispatched according to the UrlMap. In this case it's the
20+ responsibility of the user to return a response.</Description >
2021<ClassMethod >1</ClassMethod >
21- <FormalSpec >pUrl:%String,pMethod:%String</FormalSpec >
22+ <FormalSpec ><![CDATA[ pUrl:%String,pMethod:%String,&pContinue:%Boolean ]]> </FormalSpec >
2223<ReturnType >%Status</ReturnType >
2324<Implementation ><![CDATA[
24- #dim %response As %CSP.Response
25- #dim %request As %CSP.Request
26- #dim %session As %CSP.Session
27-
25+ Set pContinue = 1
26+ #dim request As %CSP.Request
2827 Do %response.SetHeader("Access-Control-Allow-Origin",..GetOrigins())
2928 Do %response.SetHeader("Access-Control-Allow-Credentials","true")
3029 Do %response.SetHeader("Access-Control-Allow-Methods","GET, PUT, POST, DELETE, OPTIONS")
@@ -36,141 +35,29 @@ Add param Namespace to a request to execute MDX in desired namespace.]]></Descri
3635
3736 Set %session.Language=$$MatchLanguage^%occMessages(%request.GetCgiEnv("HTTP_ACCEPT_LANGUAGE"),"%CSP","+s") // Localization support
3837 Set %response.Language=%session.Language
39-
40- #dim tSC As %Status = $$$OK
41- #dim e As %Exception.AbstractException
42-
43- #dim tMatcher As %Regex.Matcher
44-
45- #dim tArgs,tClass,tMatchUrl,tMapEntry,tRegEx,tTarget,tAccess As %String
46- #dim tI,tIndex As %Integer
47- #dim tResourceMatched As %Boolean
48- #dim tMethodMatched As %Boolean
49-
50- Try {
51-
52- Set st = ..ConvertRequestBody()
53- If $$$ISERR(st) Do ..Http500(st) Quit
54-
55- // Desired execusion namespace
56- Set Namespace = $get(%request.Data("Namespace",1))
57- Set st = ..CheckNamespace(.Namespace)
58- If $$$ISERR(st) Do ..Http500(st) Quit
59-
60- #; Check that the effective user ( could be unknown user ) can access this resource
61- Set tAccess=$SYSTEM.Security.Check($Piece($zu(90,21,$namespace),"^",4))
62- Set tAccess2=$SYSTEM.Security.Check($Piece($zu(90,21,$ZCVT($Namespace,"U")),"^",4))
63- If ((tAccess'["READ,WRITE") || (tAccess2'["READ,WRITE"))
64- {
65- #; Don't want the session token
66- Set %response.OutputSessionToken=0
67-
68- #; Set the Http Status
69- Set %response.Status="401 Unauthorized"
70-
71- #; Write out the header
72- Do %response.WriteHTTPHeader()
73-
74- #; Done
75- Quit
76- }
77-
78- Set (tResourceMatched,tMethodMatched)=0
79-
80- #; Walk the dispatch map in collation order of defintion
81- For tIndex=1:1 {
82-
83- #; Get the next map entry
84- Set tMapEntry=..DispatchMap(tIndex) If tMapEntry="" Quit
85-
86- #; Pick out the RegEx
87- Set tRegEx=$List(tMapEntry,1)
88-
89- #; Create a matcher
90- Set tMatcher=##class(%Regex.Matcher).%New(tRegEx)
91-
92- #; Extract the match url from the application name
93- Set tMatchUrl="/"_$Extract(pUrl,$Length(%request.Application)+1,*)
94-
95- #; Test each regular expression in turn, extracting the arguments,
96- #; dispatching to the named method
97- If tMatcher.Match(tMatchUrl) {
98-
99- #; We have matched the resource
100- Set tResourceMatched=1
101-
102- #; Now check method name
103- If pMethod'=$List(tMapEntry,2) Continue
104-
105- Set tTarget=$List(tMapEntry,3)
106-
107- #; We have matched a method
108- Set tMethodMatched=1
109-
110- #; Got a match, marshall the arguments
111- If tMatcher.GroupCount {
112- For tI=1:1:tMatcher.GroupCount Set tArgs(tI)=tMatcher.Group(tI)
113- Set tArgs=tI
114- } else {
115- Set tArgs=0
116- }
117-
118- #; Check for optional ClassName prefix
119- Set tClass=$classname()
120- If tTarget[":" Set tClass=$Piece(tTarget,":"),tTarget=$Piece(tTarget,":",2)
121-
122- #; Validate input
123- Set tBody = $List(tMapEntry,4)
124- Set tSC = ..ValidateRequest(pMethod,tBody)
125- If $$$ISERR(tSC) Do ..Http500(tSC) Quit
126-
127- #; Dispatch
128- If (Namespace'=$Namespace) {
129- Set oldNS = $Namespace
130- zn Namespace
131- Set tSC=$classmethod(tClass,tTarget,tArgs...)
132- zn oldNS
133- } Else {
134- Set tSC=$classmethod(tClass,tTarget,tArgs...)
135- }
136- If $$$ISERR(tSC) Do ..Http500(tSC)
137-
138- #; Don't want multiple matches
139- Quit
140- }
141- }
142-
143- #; Didn't have a match for the resource, report not found
144- If tResourceMatched=0 Set tSC=..Http404() Quit
145-
146- #; Had a match for resource but method not matched
147- If tMethodMatched=0 Set tSC=..Http405() Quit
148-
149- } Catch (ex) {
150-
151- #; Issue a '500'
152- Do ..Http500(ex.AsStatus())
38+
39+ Set st = ..ConvertRequestBody()
40+ If $$$ISERR(st) {
41+ Do ..Http500(st)
42+ Set pContinue = $$$NO
43+ Quit st
15344 }
154-
155- If ..#UseSession=0 Set %session.EndSession=1
156-
157- Quit tSC
158- ]]> </Implementation >
159- </Method >
160-
161- <Method name =" ValidateRequest" >
162- <Description >
163- Validates incoming request body against Body Route attribute.</Description >
164- <ClassMethod >1</ClassMethod >
165- <FormalSpec >pMethod:%String,pBody:%String=""</FormalSpec >
166- <ReturnType >%Status</ReturnType >
167- <Implementation ><![CDATA[
168- #dim %request As %CSP.Request
169-
170- return:(pMethod'="POST") $$$OK
171- return:(pBody="") $$$OK
172- return:'$d(%request.Content.%data(pBody)) $$$ERROR($$$PropertyRequired,pBody)
173- return $$$OK
45+
46+ // Desired execusion namespace
47+ Set Namespace = %request.Get("Namespace", $namespace)
48+ Set st = ..CheckNamespace(.Namespace)
49+ If $$$ISERR(st) {
50+ Do ..Http500(st)
51+ Set pContinue = $$$NO
52+ Quit
53+ }
54+
55+ #; Dispatch
56+ If (Namespace'=$Namespace) {
57+ zn Namespace
58+ }
59+
60+ Quit $$$OK
17461]]> </Implementation >
17562</Method >
17663
@@ -328,141 +215,6 @@ Returns OK if namespace both exists and contains MDX2JSON package.<br>
328215]]> </Implementation >
329216</Method >
330217
331- <Method name =" DispatchMap" >
332- <Description >
333- This project creates the DispatchMethod used to dispatch the Url and Method to the associated target method</Description >
334- <ClassMethod >1</ClassMethod >
335- <CodeMode >generator</CodeMode >
336- <FormalSpec >pIndex:%Integer</FormalSpec >
337- <ReturnType >%String</ReturnType >
338- <Implementation ><![CDATA[
339- #dim tSC As %Status = $$$OK
340- #dim e As %Exception.AbstractException
341-
342- #dim tStream As %Stream.TmpCharacter
343- #dim tHandler As %XML.ImportHandler
344- #dim tCompiledClass As %Dictionary.CompiledClass
345-
346- #dim tArgCount,tIndex,tI,tCounter As %Integer
347- #dim tArgs,tChild,tClassName,tDispatch,tError,tMap,tMethod,tPattern,tPiece,tType,tUrl As %String
348-
349- Try {
350-
351- Set tClassName=%classname
352-
353- #; Don't run on base class
354- If tClassName="MDX2JSON.AbstractREST" Quit
355-
356- #; Find named XDATA block
357- If ##class(%Dictionary.CompiledXData).%ExistsId(tClassName_"||UrlMap") {
358-
359- Set tCompiledClass=##class(%Dictionary.CompiledClass).%OpenId(tClassName,,.tSC)
360- If '$IsObject(tCompiledClass)||$$$ISERR(tSC) Quit
361-
362- Set tIndex = tCompiledClass.XDatas.FindObjectId(tClassName_"||UrlMap")
363- If tIndex="" Set tSC=$$$ERROR($$$XDataBlockMissing,tClassName,"UrlMap") Quit
364-
365- #; Get XDATA as stream
366- Set tStream = tCompiledClass.XDatas.GetAt(tIndex).Data
367- Do tStream.Rewind()
368-
369- #; Create an XML import handler ( use the internal handler )
370- Set tHandler=##class(%XML.ImportHandler).%New("CacheTemp",$$$IntHandler)
371-
372- #; Create the Entity Resolver
373- Set tResolver=##class(%XML.SAX.XDataEntityResolver).%New(tClassName)
374-
375- #; Parse the XML data in the specfied stream
376- Set tSC=##Class(%XML.SAX.Parser).ParseStream(tStream,tHandler,tResolver,,,"Schema")
377- If $$$ISERR(tSC) Quit
378-
379- #; Copy tree because handler will delete it's copy when it goes out of scope
380- Merge tMap=^CacheTemp(tHandler.Tree)
381-
382- If $Data(tMap("error"))||$Data(tMap("warning")) {
383-
384- Set tSC=$$$ERROR($$$InvalidDispatchMap)
385- For tType="error","warning" {
386- Set tIndex = "" For {
387- Set tIndex=$Order(tMap(tType,tIndex),1,tError) If tIndex="" Quit
388- Set tSC=$$$ADDSC(tSC,$$$ERROR($$$GeneralError,tError))
389- }
390- }
391- Quit
392- }
393-
394- #; Walk the xml and generate the routing map
395- Set tChild="",tCounter=0 For {
396- Set tChild=$Order(tMap(1,"c",tChild)) If tChild="" Quit
397- Set tPattern="",tArgCount=0,tUrl=tMap(tChild,"a","Url")
398- For tI=2:1:$Length(tUrl,"/") {
399- Set tPiece=$Piece(tUrl,"/",tI)
400- If $Extract(tPiece)=":" {
401- Set tPattern=tPattern_"/([^/]+)"
402- } else {
403- Set tPattern=tPattern_"/"_tPiece
404- }
405- }
406-
407- Set tCounter=$Increment(tCounter),tMethod=tMap(tChild,"a","Method"),tDispatch=tMap(tChild,"a","Call"),tBody=$g(tMap(tChild,"a","Body"))
408- $$$GENERATE(" If pIndex="_tCounter_" Quit $ListBuild("""_tPattern_""","""_tMethod_""","""_tDispatch_""","""_tBody_""")")
409- }
410- $$$GENERATE(" Quit """"")
411-
412- } Else {
413-
414- #; The specified class must have an XDATA Block named UrlMap
415- Set tSC=$$$ERROR($$$XDataBlockMissing,tClassName,"UrlMap")
416- }
417-
418- } Catch (e) {
419- Set tSC=e.AsStatus()
420- }
421-
422- Quit tSC
423- ]]> </Implementation >
424- </Method >
425-
426- <XData name =" Schema" >
427- <Description >
428- This is the Schema which defines the form of the dispatch map</Description >
429- <Internal >1</Internal >
430- <Data ><![CDATA[
431- <?xml version="1.0"?>
432- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" >
433-
434- <xs:element name="Routes">
435- <xs:complexType>
436- <xs:sequence>
437- <xs:element name="Route" minOccurs="0" maxOccurs="unbounded">
438- <xs:complexType>
439- <xs:attribute name="Url" type="string" use="required"/>
440- <xs:attribute name="Method" type="string" use="required"/>
441- <xs:attribute name="Call" type="call" use="required"/>
442- <xs:attribute name="Body" type="string" use="optional"/>
443- </xs:complexType>
444- </xs:element>
445- </xs:sequence>
446- </xs:complexType>
447- </xs:element>
448-
449- <xs:simpleType name="call">
450- <xs:restriction base="xs:string">
451- <xs:pattern value="([%]?[a-zA-Z][a-zA-Z0-9]*(\.[a-zA-Z][a-zA-Z0-9]*)*:)?[%]?[a-zA-Z][a-zA-Z0-9]*"/>
452- </xs:restriction>
453- </xs:simpleType>
454-
455- <xs:simpleType name="string">
456- <xs:restriction base="xs:string">
457- <xs:minLength value="1"/>
458- </xs:restriction>
459- </xs:simpleType>
460-
461-
462- </xs:schema>
463- ]]> </Data >
464- </XData >
465-
466218<Method name =" OutputToStr" >
467219<Description ><![CDATA[
468220Executes actions and returns device output <br>
0 commit comments