Skip to content

Commit 7228c5b

Browse files
Eduard LebedyukEduard Lebedyuk
authored andcommitted
2022.2 support MDX2JSON v3
1 parent a8e0524 commit 7228c5b

4 files changed

Lines changed: 44 additions & 292 deletions

File tree

MDX2JSON/AbstractREST.cls.xml

Lines changed: 31 additions & 279 deletions
Original file line numberDiff line numberDiff line change
@@ -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[
468220
Executes actions and returns device output <br>

MDX2JSON/REST.cls.xml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,34 +49,34 @@ Example: send HTTP GET request to web application with Dispatch class <b>MDX2JSO
4949
5050
<Route Url="/MDX" Method="POST" Call="WriteJSONfromMDX"/>
5151
<Route Url="/CancelQuery/:CubeKey/:QueryKey" Method="GET" Call="%DeepSee.ResultSet:%CancelQuery"/>
52-
<Route Url="/MDX2JSONP" Method="POST" Call="WriteJSONPfromMDX" Body="MDX"/>
53-
<Route Url="/MDXDrillthrough" Method="POST" Call="WriteDrillthroughJSON" Body="MDX"/>
54-
<Route Url="/MDX2XMLA" Method="POST" Call="WriteXMLAfromMDX" Body="MDX"/>
52+
<Route Url="/MDX2JSONP" Method="POST" Call="WriteJSONPfromMDX"/>
53+
<Route Url="/MDXDrillthrough" Method="POST" Call="WriteDrillthroughJSON" />
54+
<Route Url="/MDX2XMLA" Method="POST" Call="WriteXMLAfromMDX" />
5555
5656
<!-- Get info about availible filters and their values -->
5757
<Route Url="/Filters" Method="POST" Call="WriteFiltersForDataSource"/>
5858
5959
<!-- Get info about widgets-->
6060
<Route Url="/Dashboards" Method="GET" Call="GetDashboardList"/>
61-
<Route Url="/Dashboards" Method="POST" Call="GetDashboardList" Body="Folder"/>
62-
<Route Url="/Dashboard" Method="POST" Call="GetDashboard" Body="Dashboard"/>
63-
<Route Url="/Widgets" Method="POST" Call="GetWidgetsList" Body="Dashboard"/>
61+
<Route Url="/Dashboards" Method="POST" Call="GetDashboardList" />
62+
<Route Url="/Dashboard" Method="POST" Call="GetDashboard" />
63+
<Route Url="/Widgets" Method="POST" Call="GetWidgetsList" />
6464
<Route Url="/Action/:Cube/:Action" Method="POST" Call="ExecuteAction"/>
6565
6666
<!-- Get info about system format and locale-->
6767
<Route Url="/Format" Method="GET" Call="GetFormat"/>
6868
6969
<!-- Get info about pivot-->
70-
<Route Url="/DataSource" Method="POST" Call="GetDataSource" Body="DataSource"/>
70+
<Route Url="/DataSource" Method="POST" Call="GetDataSource" />
7171
7272
<!-- Get info about pivot-->
73-
<Route Url="/TermList" Method="POST" Call="GetTermList" Body="TermList"/>
73+
<Route Url="/TermList" Method="POST" Call="GetTermList" />
7474
7575
<!-- Get info about pivot variables-->
7676
<Route Url="/PivotVariables/:Cube" Method="GET" Call="WritePivotVariablesForCube"/>
7777
7878
<!-- Get info about user config-->
79-
<Route Url="/Config" Method="POST" Call="SetConfig" Body="Application"/>
79+
<Route Url="/Config" Method="POST" Call="SetConfig"/>
8080
<Route Url="/Config/:Application" Method="GET" Call="GetConfig" />
8181
8282
<!-- Get info about user favorites-->

MDX2JSON/Tests.cls.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ Classes with support methods for testing MDX2JSON</Description>
88

99
<Parameter name="LastCommit">
1010
<Type>%String</Type>
11-
<Default>8086969408b00c9661ae3475a5b7c7d5ceba60d5</Default>
11+
<Default>a8e0524a0048583d0cf37ca782cbf35e89bf27af</Default>
1212
</Parameter>
1313

1414
<Parameter name="LastCommitTS">
1515
<Type>%TimeStamp</Type>
16-
<Default>2021-12-01 11:27:17.694</Default>
16+
<Default>2021-12-01 00:00:00.000</Default>
1717
</Parameter>
1818

1919
<Method name="ProjectLength">

0 commit comments

Comments
 (0)