aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormontellese <montellese@xbmc.org>2011-06-11 16:14:38 +0200
committermontellese <montellese@xbmc.org>2011-06-11 16:15:03 +0200
commitf86d3a6d76d81a9790189dbfd2a5726b7781c1ad (patch)
treeda291b859ea9f69fbf3486440e80acabceeb0a0c
parent28c4d78e91b13b569352d250c05e24a758529e36 (diff)
parent787890946aec4cdf3a6ec839f175c360b5ba9fdd (diff)
jsonrpc: add "filter" parameter to JSONRPC.Introspect to allow the retrieval of method/namespace/type/notification-specific schema definitions
* montellese/jsonrpc_introspect_filtering: added parsing of "returns" to CJSONServiceDescription jsonrpc: add "filter" parameter to JSONRPC.Introspect to allow the retrieval of method/namespace/type/notification-specific schema definitions
-rw-r--r--xbmc/interfaces/json-rpc/JSONRPC.cpp10
-rw-r--r--xbmc/interfaces/json-rpc/JSONServiceDescription.cpp224
-rw-r--r--xbmc/interfaces/json-rpc/JSONServiceDescription.h11
-rw-r--r--xbmc/interfaces/json-rpc/ServiceDescription.h9
-rw-r--r--xbmc/interfaces/json-rpc/methods.json9
5 files changed, 212 insertions, 51 deletions
diff --git a/xbmc/interfaces/json-rpc/JSONRPC.cpp b/xbmc/interfaces/json-rpc/JSONRPC.cpp
index 259c803d0e..be1215de6e 100644
--- a/xbmc/interfaces/json-rpc/JSONRPC.cpp
+++ b/xbmc/interfaces/json-rpc/JSONRPC.cpp
@@ -59,13 +59,9 @@ void CJSONRPC::Initialize()
JSON_STATUS CJSONRPC::Introspect(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant& parameterObject, CVariant &result)
{
- bool getDescriptions = parameterObject["getdescriptions"].asBoolean();
- bool getMetadata = parameterObject["getmetadata"].asBoolean();
- bool filterByTransport = parameterObject["filterbytransport"].asBoolean();
-
- CJSONServiceDescription::Print(result, transport, client, getDescriptions, getMetadata, filterByTransport);
-
- return OK;
+ return CJSONServiceDescription::Print(result, transport, client,
+ parameterObject["getdescriptions"].asBoolean(), parameterObject["getmetadata"].asBoolean(), parameterObject["filterbytransport"].asBoolean(),
+ parameterObject["filter"]["id"].asString(), parameterObject["filter"]["type"].asString(), parameterObject["filter"]["getreferences"].asBoolean());
}
JSON_STATUS CJSONRPC::Version(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant& parameterObject, CVariant &result)
diff --git a/xbmc/interfaces/json-rpc/JSONServiceDescription.cpp b/xbmc/interfaces/json-rpc/JSONServiceDescription.cpp
index d632c277e9..1c4df3e19f 100644
--- a/xbmc/interfaces/json-rpc/JSONServiceDescription.cpp
+++ b/xbmc/interfaces/json-rpc/JSONServiceDescription.cpp
@@ -421,16 +421,114 @@ int CJSONServiceDescription::GetVersion()
return JSONRPC_SERVICE_VERSION;
}
-void CJSONServiceDescription::Print(CVariant &result, ITransportLayer *transport, IClient *client, bool printDescriptions, bool printMetadata, bool filterByTransport)
+JSON_STATUS CJSONServiceDescription::Print(CVariant &result, ITransportLayer *transport, IClient *client,
+ bool printDescriptions /* = true */, bool printMetadata /* = false */, bool filterByTransport /* = true */,
+ std::string filterByName /* = "" */, std::string filterByType /* = "" */, bool printReferences /* = true */)
{
+ std::map<std::string, JSONSchemaTypeDefinition> types;
+ CJsonRpcMethodMap methods;
+ std::map<std::string, CVariant> notifications;
+
+ int clientPermissions = client->GetPermissionFlags();
+ int transportCapabilities = transport->GetCapabilities();
+
+ if (filterByName.size() > 0)
+ {
+ CStdString name = filterByName;
+
+ if (filterByType == "method")
+ {
+ name = name.ToLower();
+
+ CJsonRpcMethodMap::JsonRpcMethodIterator methodIterator = m_actionMap.find(name);
+ if (methodIterator != m_actionMap.end() &&
+ (clientPermissions & methodIterator->second.permission) != 0 && ((transportCapabilities & methodIterator->second.transportneed) != 0 || !filterByTransport))
+ methods.add(methodIterator->second);
+ else
+ return InvalidParams;
+ }
+ else if (filterByType == "namespace")
+ {
+ // append a . delimiter to make sure we check for a namespace
+ name = name.ToLower().append(".");
+
+ CJsonRpcMethodMap::JsonRpcMethodIterator methodIterator;
+ CJsonRpcMethodMap::JsonRpcMethodIterator methodIteratorEnd = m_actionMap.end();
+ for (methodIterator = m_actionMap.begin(); methodIterator != methodIteratorEnd; methodIterator++)
+ {
+ // Check if the given name is at the very beginning of the method name
+ if (methodIterator->first.find(name) == 0 &&
+ (clientPermissions & methodIterator->second.permission) != 0 && ((transportCapabilities & methodIterator->second.transportneed) != 0 || !filterByTransport))
+ methods.add(methodIterator->second);
+ }
+
+ if (methods.begin() == methods.end())
+ return InvalidParams;
+ }
+ else if (filterByType == "type")
+ {
+ std::map<std::string, JSONSchemaTypeDefinition>::const_iterator typeIterator = m_types.find(name);
+ if (typeIterator != m_types.end())
+ types[typeIterator->first] = typeIterator->second;
+ else
+ return InvalidParams;
+ }
+ else if (filterByType == "notification")
+ {
+ std::map<std::string, CVariant>::const_iterator notificationIterator = m_notifications.find(name);
+ if (notificationIterator != m_notifications.end())
+ notifications[notificationIterator->first] = notificationIterator->second;
+ else
+ return InvalidParams;
+ }
+ else
+ return InvalidParams;
+
+ // If we need to print all referenced types we have to go through all parameters etc
+ if (printReferences)
+ {
+ std::vector<std::string> referencedTypes;
+
+ // Loop through all printed types to get all referenced types
+ std::map<std::string, JSONSchemaTypeDefinition>::const_iterator typeIterator;
+ std::map<std::string, JSONSchemaTypeDefinition>::const_iterator typeIteratorEnd = types.end();
+ for (typeIterator = types.begin(); typeIterator != typeIteratorEnd; typeIterator++)
+ getReferencedTypes(typeIterator->second, referencedTypes);
+
+ // Loop through all printed method's parameters and return value to get all referenced types
+ CJsonRpcMethodMap::JsonRpcMethodIterator methodIterator;
+ CJsonRpcMethodMap::JsonRpcMethodIterator methodIteratorEnd = methods.end();
+ for (methodIterator = methods.begin(); methodIterator != methodIteratorEnd; methodIterator++)
+ {
+ for (unsigned int index = 0; index < methodIterator->second.parameters.size(); index++)
+ getReferencedTypes(methodIterator->second.parameters.at(index), referencedTypes);
+
+ getReferencedTypes(methodIterator->second.returns, referencedTypes);
+ }
+
+ for (unsigned int index = 0; index < referencedTypes.size(); index++)
+ {
+ std::map<std::string, JSONSchemaTypeDefinition>::const_iterator typeIterator = m_types.find(referencedTypes.at(index));
+ if (typeIterator != m_types.end())
+ types[typeIterator->first] = typeIterator->second;
+ }
+ }
+ }
+ else
+ {
+ types = m_types;
+ methods = m_actionMap;
+ notifications = m_notifications;
+ }
+
// Print the header
result["id"] = JSONRPC_SERVICE_ID;
result["version"] = JSONRPC_SERVICE_VERSION;
result["description"] = JSONRPC_SERVICE_DESCRIPTION;
std::map<std::string, JSONSchemaTypeDefinition>::const_iterator typeIterator;
- std::map<std::string, JSONSchemaTypeDefinition>::const_iterator typeIteratorEnd = m_types.end();
- for (typeIterator = m_types.begin(); typeIterator != typeIteratorEnd; typeIterator++)
+ std::map<std::string, JSONSchemaTypeDefinition>::const_iterator typeIteratorEnd = types.end();
+ for (typeIterator = types.begin(); typeIterator != typeIteratorEnd; typeIterator++)
{
CVariant currentType = CVariant(CVariant::VariantTypeObject);
printType(typeIterator->second, false, true, true, printDescriptions, currentType);
@@ -439,12 +537,9 @@ void CJSONServiceDescription::Print(CVariant &result, ITransportLayer *transport
}
// Iterate through all json rpc methods
- int clientPermissions = client->GetPermissionFlags();
- int transportCapabilities = transport->GetCapabilities();
-
CJsonRpcMethodMap::JsonRpcMethodIterator methodIterator;
- CJsonRpcMethodMap::JsonRpcMethodIterator methodIteratorEnd = m_actionMap.end();
- for (methodIterator = m_actionMap.begin(); methodIterator != methodIteratorEnd; methodIterator++)
+ CJsonRpcMethodMap::JsonRpcMethodIterator methodIteratorEnd = methods.end();
+ for (methodIterator = methods.begin(); methodIterator != methodIteratorEnd; methodIterator++)
{
if ((clientPermissions & methodIterator->second.permission) == 0 || ((transportCapabilities & methodIterator->second.transportneed) == 0 && filterByTransport))
continue;
@@ -467,16 +562,18 @@ void CJSONServiceDescription::Print(CVariant &result, ITransportLayer *transport
currentMethod["params"].append(param);
}
- currentMethod["returns"] = methodIterator->second.returns;
+ printType(methodIterator->second.returns, false, false, false, printDescriptions, currentMethod["returns"]);
result["methods"][methodIterator->second.name] = currentMethod;
}
// Print notification description
std::map<std::string, CVariant>::const_iterator notificationIterator;
- std::map<std::string, CVariant>::const_iterator notificationIteratorEnd = m_notifications.end();
- for (notificationIterator = m_notifications.begin(); notificationIterator != notificationIteratorEnd; notificationIterator++)
+ std::map<std::string, CVariant>::const_iterator notificationIteratorEnd = notifications.end();
+ for (notificationIterator = notifications.begin(); notificationIterator != notificationIteratorEnd; notificationIterator++)
result["notifications"][notificationIterator->first] = notificationIterator->second;
+
+ return OK;
}
JSON_STATUS CJSONServiceDescription::CheckCall(const char* const method, const CVariant &requestParameters, IClient *client, bool notification, MethodCall &methodCall, CVariant &outputParameters)
@@ -1040,29 +1137,7 @@ bool CJSONServiceDescription::parseTypeDefinition(const CVariant &value, JSONSch
}
// Get the defined type of the parameter
- if (value["type"].isArray())
- {
- int parsedType = 0;
- // If the defined type is an array, we have
- // to handle a union type
- for (unsigned int typeIndex = 0; typeIndex < value["type"].size(); typeIndex++)
- {
- // If the type is a string try to parse it
- if (value["type"][typeIndex].isString())
- parsedType |= StringToSchemaValueType(value["type"][typeIndex].asString());
- else
- CLog::Log(LOGWARNING, "JSONRPC: Invalid type in union type definition of type %s", type.name.c_str());
- }
-
- type.type = (JSONSchemaType)parsedType;
-
- // If the type has not been set yet
- // set it to "any"
- if (type.type == 0)
- type.type = AnyValue;
- }
- else
- type.type = value["type"].isString() ? StringToSchemaValueType(value["type"].asString()) : AnyValue;
+ type.type = parseJSONSchemaType(value["type"]);
if (type.type == ObjectValue)
{
@@ -1254,11 +1329,49 @@ bool CJSONServiceDescription::parseTypeDefinition(const CVariant &value, JSONSch
return true;
}
-void CJSONServiceDescription::parseReturn(const CVariant &value, CVariant &returns)
+void CJSONServiceDescription::parseReturn(const CVariant &value, JSONSchemaTypeDefinition &returns)
{
// Only parse the "returns" definition if there is one
- if (value.isMember("returns"))
- returns = value["returns"];
+ if (!value.isMember("returns"))
+ {
+ returns.type = NullValue;
+ return;
+ }
+
+ // If the type of the return value is defined as a simple string we can parse it directly
+ if (value["returns"].isString())
+ {
+ returns.type = parseJSONSchemaType(value["returns"]);
+ }
+ // otherwise we have to parse the whole type definition
+ else
+ parseTypeDefinition(value["returns"], returns, false);
+}
+
+JSONSchemaType CJSONServiceDescription::parseJSONSchemaType(const CVariant &value)
+{
+ if (value.isArray())
+ {
+ int parsedType = 0;
+ // If the defined type is an array, we have
+ // to handle a union type
+ for (unsigned int typeIndex = 0; typeIndex < value.size(); typeIndex++)
+ {
+ // If the type is a string try to parse it
+ if (value[typeIndex].isString())
+ parsedType |= StringToSchemaValueType(value[typeIndex].asString());
+ else
+ CLog::Log(LOGWARNING, "JSONRPC: Invalid type in union type definition");
+ }
+
+ // If the type has not been set yet set it to "any"
+ if (parsedType == 0)
+ return AnyValue;
+
+ return (JSONSchemaType)parsedType;
+ }
+ else
+ return value.isString() ? StringToSchemaValueType(value.asString()) : AnyValue;
}
void CJSONServiceDescription::addReferenceTypeDefinition(JSONSchemaTypeDefinition &typeDefinition)
@@ -1276,12 +1389,47 @@ void CJSONServiceDescription::addReferenceTypeDefinition(JSONSchemaTypeDefinitio
m_types[typeDefinition.ID] = typeDefinition;
}
+void CJSONServiceDescription::getReferencedTypes(const JSONSchemaTypeDefinition &type, std::vector<std::string> &referencedTypes)
+{
+ // If the current type is a referenceable object, we can add it to the list
+ if (type.ID.size() > 0)
+ {
+ for (unsigned int index = 0; index < referencedTypes.size(); index++)
+ {
+ // The referenceable object has already been added to the list so we can just skip it
+ if (type.ID == referencedTypes.at(index))
+ return;
+ }
+
+ referencedTypes.push_back(type.ID);
+ }
+
+ // If the current type is an object we need to check its properties
+ if (HasType(type.type, ObjectValue))
+ {
+ JSONSchemaTypeDefinition::CJsonSchemaPropertiesMap::JSONSchemaPropertiesIterator iter;
+ JSONSchemaTypeDefinition::CJsonSchemaPropertiesMap::JSONSchemaPropertiesIterator iterEnd = type.properties.end();
+ for (iter = type.properties.begin(); iter != iterEnd; iter++)
+ getReferencedTypes(iter->second, referencedTypes);
+ }
+ // If the current type is an array we need to check its items
+ if (HasType(type.type, ArrayValue))
+ {
+ unsigned int index;
+ for (index = 0; index < type.items.size(); index++)
+ getReferencedTypes(type.items.at(index), referencedTypes);
+
+ for (index = 0; index < type.additionalItems.size(); index++)
+ getReferencedTypes(type.additionalItems.at(index), referencedTypes);
+ }
+}
+
CJSONServiceDescription::CJsonRpcMethodMap::CJsonRpcMethodMap()
{
m_actionmap = std::map<std::string, JsonRpcMethod>();
}
-void CJSONServiceDescription::CJsonRpcMethodMap::add(JsonRpcMethod &method)
+void CJSONServiceDescription::CJsonRpcMethodMap::add(const JsonRpcMethod &method)
{
CStdString name = method.name;
name = name.ToLower();
diff --git a/xbmc/interfaces/json-rpc/JSONServiceDescription.h b/xbmc/interfaces/json-rpc/JSONServiceDescription.h
index 9b42b60ccf..6b30eed190 100644
--- a/xbmc/interfaces/json-rpc/JSONServiceDescription.h
+++ b/xbmc/interfaces/json-rpc/JSONServiceDescription.h
@@ -205,7 +205,7 @@ namespace JSONRPC
/*!
\brief Definition of the return value
*/
- CVariant returns;
+ JSONSchemaTypeDefinition returns;
} JsonRpcMethod;
/*!
@@ -292,7 +292,7 @@ namespace JSONRPC
\param printMetadata Whether to print XBMC specific data or not
\param filterByTransport Whether to filter by transport or not
*/
- static void Print(CVariant &result, ITransportLayer *transport, IClient *client, bool printDescriptions, bool printMetadata, bool filterByTransport);
+ static JSON_STATUS Print(CVariant &result, ITransportLayer *transport, IClient *client, bool printDescriptions = true, bool printMetadata = false, bool filterByTransport = true, std::string filterByName = "", std::string filterByType = "", bool printReferences = true);
/*!
\brief Checks the given parameters from the request against the
@@ -322,15 +322,18 @@ namespace JSONRPC
static bool parseMethod(const CVariant &value, JsonRpcMethod &method);
static bool parseParameter(CVariant &value, JSONSchemaTypeDefinition &parameter);
static bool parseTypeDefinition(const CVariant &value, JSONSchemaTypeDefinition &type, bool isParameter);
- static void parseReturn(const CVariant &value, CVariant &returns);
+ static void parseReturn(const CVariant &value, JSONSchemaTypeDefinition &returns);
+ static JSONSchemaType parseJSONSchemaType(const CVariant &value);
static void addReferenceTypeDefinition(JSONSchemaTypeDefinition &typeDefinition);
+ static void getReferencedTypes(const JSONSchemaTypeDefinition &type, std::vector<std::string> &referencedTypes);
+
class CJsonRpcMethodMap
{
public:
CJsonRpcMethodMap();
- void add(JsonRpcMethod &method);
+ void add(const JsonRpcMethod &method);
typedef std::map<std::string, JsonRpcMethod>::const_iterator JsonRpcMethodIterator;
JsonRpcMethodIterator begin() const;
diff --git a/xbmc/interfaces/json-rpc/ServiceDescription.h b/xbmc/interfaces/json-rpc/ServiceDescription.h
index 4610199929..49a066065a 100644
--- a/xbmc/interfaces/json-rpc/ServiceDescription.h
+++ b/xbmc/interfaces/json-rpc/ServiceDescription.h
@@ -770,7 +770,14 @@ namespace JSONRPC
"\"params\": ["
"{ \"name\": \"getdescriptions\", \"type\": \"boolean\", \"default\": true },"
"{ \"name\": \"getmetadata\", \"type\": \"boolean\", \"default\": false },"
- "{ \"name\": \"filterbytransport\", \"type\": \"boolean\", \"default\": true }"
+ "{ \"name\": \"filterbytransport\", \"type\": \"boolean\", \"default\": true },"
+ "{ \"name\": \"filter\", \"type\": \"object\","
+ "\"properties\": {"
+ "\"id\": { \"type\": \"string\", \"required\": true, \"description\": \"Name of a namespace, method or type\" },"
+ "\"type\": { \"type\": \"string\", \"required\": true, \"enum\": [ \"method\", \"namespace\", \"type\", \"notification\" ], \"description\": \"Type of the given name\" },"
+ "\"getreferences\": { \"type\": \"boolean\", \"default\": true, \"description\": \"Whether or not to print the schema for referenced types\" }"
+ "}"
+ "}"
"],"
"\"returns\": \"object\""
"}",
diff --git a/xbmc/interfaces/json-rpc/methods.json b/xbmc/interfaces/json-rpc/methods.json
index 5b91ff77df..2e14d29898 100644
--- a/xbmc/interfaces/json-rpc/methods.json
+++ b/xbmc/interfaces/json-rpc/methods.json
@@ -7,7 +7,14 @@
"params": [
{ "name": "getdescriptions", "type": "boolean", "default": true },
{ "name": "getmetadata", "type": "boolean", "default": false },
- { "name": "filterbytransport", "type": "boolean", "default": true }
+ { "name": "filterbytransport", "type": "boolean", "default": true },
+ { "name": "filter", "type": "object",
+ "properties": {
+ "id": { "type": "string", "required": true, "description": "Name of a namespace, method or type" },
+ "type": { "type": "string", "required": true, "enum": [ "method", "namespace", "type", "notification" ], "description": "Type of the given name" },
+ "getreferences": { "type": "boolean", "default": true, "description": "Whether or not to print the schema for referenced types" }
+ }
+ }
],
"returns": "object"
},