1 /*=============================================================================
2 
3   Library: XNAT/Core
4 
5   Copyright (c) University College London,
6     Centre for Medical Image Computing
7 
8   Licensed under the Apache License, Version 2.0 (the "License");
9   you may not use this file except in compliance with the License.
10   You may obtain a copy of the License at
11 
12     http://www.apache.org/licenses/LICENSE-2.0
13 
14   Unless required by applicable law or agreed to in writing, software
15   distributed under the License is distributed on an "AS IS" BASIS,
16   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   See the License for the specific language governing permissions and
18   limitations under the License.
19 
20 =============================================================================*/
21 
22 // ctkXnatAPI includes
23 #include "ctkXnatAPI_p.h"
24 
25 #include "ctkXnatResourceCatalogXmlParser.h"
26 
27 #include "qRestResult.h"
28 
29 #include <QNetworkReply>
30 #include <QRegExp>
31 #include <QUrl>
32 #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
33 #include <QUrlQuery>
34 #endif
35 
36 // --------------------------------------------------------------------------
37 // ctkXnatAPI methods
38 
39 // --------------------------------------------------------------------------
ctkXnatAPI(QObject * _parent)40 ctkXnatAPI::ctkXnatAPI(QObject* _parent)
41   : Superclass(_parent)
42 {
43 }
44 
45 // --------------------------------------------------------------------------
~ctkXnatAPI()46 ctkXnatAPI::~ctkXnatAPI()
47 {
48 }
49 
50 // --------------------------------------------------------------------------
get(const QString & resource,const Parameters & parameters,const qRestAPI::RawHeaders & rawHeaders)51 QUuid ctkXnatAPI::get(const QString& resource, const Parameters& parameters, const qRestAPI::RawHeaders& rawHeaders)
52 {
53   QUrl url = this->createUrl(resource, parameters);
54 #if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
55   url.addQueryItem("format", "json");
56 #else
57   QUrlQuery urlQuery(url);
58   urlQuery.addQueryItem("format", "json");
59   url.setQuery(urlQuery);
60 #endif
61   QNetworkReply* queryReply = this->sendRequest(QNetworkAccessManager::GetOperation, url, rawHeaders);
62   QUuid queryId = queryReply->property("uuid").toString();
63   return queryId;
64 }
65 
66 // --------------------------------------------------------------------------
parseResponse(qRestResult * restResult,const QByteArray & response)67 void ctkXnatAPI::parseResponse(qRestResult* restResult, const QByteArray& response)
68 {
69   static QRegExp identifierPattern("[a-zA-Z][a-zA-Z0-9_]*");
70 
71   QList<QVariantMap> result;
72 
73   if (response.isEmpty())
74     {
75     // Some operations do not return result. E.g. creating a project.
76     }
77   else if (response.startsWith("<html>"))
78     {
79     // Some operations return an XML description of an object.
80     // E.g. GET query for a specific subject.
81     restResult->setError(QString("Bad data: ") + response, qRestAPI::ResponseParseError);
82     }
83   else if (response.startsWith("<?xml "))
84     {
85     // Some operations return an XML description of an object.
86     // E.g. GET query for a specific subject.
87     result = this->parseXmlResponse(restResult, response);
88     }
89   else if (response[0] == '{')
90     {
91     // Other operations return a json description of an object.
92     // E.g. GET query of the list of subjects
93     result = this->parseJsonResponse(restResult, response);
94     }
95   else if (identifierPattern.exactMatch(response))
96     {
97     // Some operations return the identifier of the newly created object.
98     // E.g. creating a subject.
99     QVariantMap map;
100     map["ID"] = response;
101     map["content"] = response;
102     result.push_back(map);
103     }
104   else
105     {
106     QVariantMap map;
107     map["content"] = response;
108     result.push_back(map);
109     }
110 
111   restResult->setResult(result);
112 }
113 
114 // --------------------------------------------------------------------------
parseXmlResponse(qRestResult *,const QByteArray & response)115 QList<QVariantMap> ctkXnatAPI::parseXmlResponse(qRestResult* /*restResult*/, const QByteArray& response)
116 {
117   QList<QVariantMap> result;
118   // In this case a resource catalog xml was requested
119   if (response.contains("<cat:Catalog"))
120   {
121     ctkXnatResourceCatalogXmlParser parser;
122     parser.setData(response);
123     parser.parseXml(result);
124   }
125   return result;
126 }
127 
128 // --------------------------------------------------------------------------
parseJsonResponse(qRestResult * restResult,const QByteArray & response)129 QList<QVariantMap> ctkXnatAPI::parseJsonResponse(qRestResult* restResult, const QByteArray& response)
130 {
131   QScriptValue scriptValue = this->ScriptEngine.evaluate("(" + QString(response) + ")");
132 
133   QList<QVariantMap> result;
134 
135   // e.g. {"ResultSet":{"Result": [{"p1":"v1","p2":"v2",...}], "totalRecords":"13"}}
136   QScriptValue resultSet = scriptValue.property("ResultSet");
137   QScriptValue data = resultSet.property("Result");
138   if (!data.isObject())
139     {
140     if (!data.toString().isEmpty())
141       {
142       restResult->setError(QString("Bad data: ") + data.toString(), qRestAPI::ResponseParseError);
143       }
144     }
145   if (data.isArray())
146     {
147     quint32 length = data.property("length").toUInt32();
148     for(quint32 i = 0; i < length; ++i)
149       {
150       qRestAPI::appendScriptValueToVariantMapList(result, data.property(i));
151       }
152     }
153   else
154     {
155     qRestAPI::appendScriptValueToVariantMapList(result, data);
156     }
157 
158   return result;
159 }
160