//////////////////////////////////////////////////////////////////////////////// /// @brief input parsers /// /// @file /// /// DISCLAIMER /// /// Copyright 2010-2011 triagens GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler /// @author Copyright 2009-2011, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include "InputParser.h" #include #include #include #include #include #include #include #include #include #include #include "JsonParserX/JsonParserXDriver.h" using namespace std; using namespace triagens::basics; using namespace triagens::rest; // ----------------------------------------------------------------------------- // helper functions // ----------------------------------------------------------------------------- namespace triagens { namespace rest { enum ObjectDescriptionType { OD_BOOLEAN, OD_DOUBLE, OD_INTEGER, OD_STRING, OD_STRING_LIST, OD_VARIANT_ARRAY, OD_VARIANT_BOOLEAN, OD_VARIANT_DOUBLE, OD_VARIANT_INTEGER, OD_VARIANT_NULL, OD_VARIANT_STRING, OD_VARIANT_STRING_LIST, OD_VARIANT_VECTOR }; struct AttributeDescription { AttributeDescription () { } AttributeDescription (ObjectDescriptionType type, void* store, bool* hasAttribute) : type(type), store(store), hasAttribute(hasAttribute) { } ObjectDescriptionType type; void* store; bool* hasAttribute; }; } } namespace { void clearObject (ObjectDescriptionType type, void* store) { switch (type) { case OD_BOOLEAN: *reinterpret_cast(store) = false; break; case OD_DOUBLE: *reinterpret_cast(store) = false; break; case OD_INTEGER: *reinterpret_cast(store) = 0; break; case OD_STRING: *reinterpret_cast(store) = ""; break; case OD_VARIANT_ARRAY: case OD_VARIANT_BOOLEAN: case OD_VARIANT_DOUBLE: case OD_VARIANT_INTEGER: case OD_VARIANT_NULL: case OD_VARIANT_STRING: case OD_VARIANT_VECTOR: *reinterpret_cast(store) = 0; break; case OD_STRING_LIST: case OD_VARIANT_STRING_LIST: break; } } bool checkObjectType (string const& name, ObjectDescriptionType type, VariantObject* object, string& errorMessage) { char const* expecting; VariantObject::ObjectType otype; switch (type) { case OD_VARIANT_ARRAY: expecting = "ARRAY"; otype = VariantObject::VARIANT_ARRAY; break; case OD_BOOLEAN: case OD_VARIANT_BOOLEAN: expecting = "BOOLEAN"; otype = VariantObject::VARIANT_BOOLEAN; break; case OD_DOUBLE: case OD_VARIANT_DOUBLE: expecting = "DOUBLE"; otype = VariantObject::VARIANT_DOUBLE; break; case OD_INTEGER: case OD_VARIANT_INTEGER: expecting = "INTEGER"; otype = VariantObject::VARIANT_INT64; break; case OD_VARIANT_NULL: expecting = "NULL"; otype = VariantObject::VARIANT_NULL; break; case OD_STRING: case OD_VARIANT_STRING: expecting = "STRING"; otype = VariantObject::VARIANT_STRING; break; case OD_STRING_LIST: case OD_VARIANT_STRING_LIST: expecting = "VECTOR OF STRINGS"; otype = VariantObject::VARIANT_VECTOR; break; case OD_VARIANT_VECTOR: expecting = "VECTOR"; otype = VariantObject::VARIANT_VECTOR; break; default: THROW_INTERNAL_ERROR("wrong type"); } if (otype != object->type()) { errorMessage = "attribute '" + name + "' is of wrong type (expecting " + expecting + ", got " + VariantObject::NameObjectType(object->type()) + ")"; return false; } else { return true; } } template bool extractObjects (string const& name, VariantVector* list, ObjectDescriptionType type, vector< VT* >* store, string& errorMessage) { vector const& values = list->getValues(); for (vector::const_iterator i = values.begin(); i != values.end(); ++i) { VariantObject* object = *i; bool ok = checkObjectType(name, type, object, errorMessage); if (! ok) { return false; } VT* vt = object->as(); store->push_back(vt); } return true; } template bool extractObjects (string const& name, VariantVector* list, ObjectDescriptionType type, vector< T >* store, string& errorMessage) { vector const& values = list->getValues(); for (vector::const_iterator i = values.begin(); i != values.end(); ++i) { VariantObject* object = *i; bool ok = checkObjectType(name, type, object, errorMessage); if (! ok) { return false; } VT* vt = object->as(); store->push_back(vt->getValue()); } return true; } bool extractObject (string const& name, VariantObject* object, AttributeDescription const& desc, string& errorMessage) { switch (desc.type) { case OD_VARIANT_ARRAY: *reinterpret_cast(desc.store) = object->as(); return true; case OD_BOOLEAN: *reinterpret_cast(desc.store) = object->as()->getValue(); return true; case OD_VARIANT_BOOLEAN: *reinterpret_cast(desc.store) = object->as(); return true; case OD_DOUBLE: *reinterpret_cast(desc.store) = object->as()->getValue(); return true; case OD_VARIANT_DOUBLE: *reinterpret_cast(desc.store) = object->as(); return true; case OD_INTEGER: *reinterpret_cast(desc.store) = object->as()->getValue(); return true; case OD_VARIANT_INTEGER: *reinterpret_cast(desc.store) = object->as(); return true; case OD_VARIANT_NULL: *reinterpret_cast(desc.store) = object->as(); return true; case OD_STRING: *reinterpret_cast(desc.store) = object->as()->getValue(); return true; case OD_VARIANT_STRING: *reinterpret_cast(desc.store) = object->as(); return true; case OD_STRING_LIST: return extractObjects(name, object->as(), OD_VARIANT_STRING, reinterpret_cast< vector* >(desc.store), errorMessage); case OD_VARIANT_STRING_LIST: return extractObjects(name, object->as(), OD_VARIANT_STRING, reinterpret_cast< vector* >(desc.store), errorMessage); case OD_VARIANT_VECTOR: *reinterpret_cast(desc.store) = object->as(); return true; default: THROW_INTERNAL_ERROR("wrong type"); } } bool loadObject (VariantArray* array, string const& name, AttributeDescription const& desc, bool optional, string& errorMessage) { clearObject(desc.type, desc.store); if (desc.hasAttribute != 0) { *desc.hasAttribute = false; } VariantObject* object = array->lookup(name); if (object == 0) { if (optional) { return true; } else { errorMessage = "attribute '" + name + "' not found"; return false; } } if (object->is() && optional) { return true; } if (desc.hasAttribute != 0) { *desc.hasAttribute = true; } bool ok = checkObjectType(name, desc.type, object, errorMessage); if (! ok) { return false; } return extractObject(name, object, desc, errorMessage); } bool loadAlternatives (VariantArray* array, string const& name, vector const& alternatives, string& errorMessage) { for (vector::const_iterator i = alternatives.begin(); i != alternatives.end(); ++i) { clearObject(i->type, i->store); } VariantObject* object = array->lookup(name); if (object == 0) { return true; } for (vector::const_iterator i = alternatives.begin(); i != alternatives.end(); ++i) { AttributeDescription const& desc = *i; if (checkObjectType(name, desc.type, object, errorMessage)) { return extractObject(name, object, desc, errorMessage); } } errorMessage = "attribute '" + name + "' is of wrong type"; return false; } } namespace triagens { namespace rest { namespace InputParser { // ----------------------------------------------------------------------------- // object description implementation // ----------------------------------------------------------------------------- struct ObjectDescriptionImpl { map< string, AttributeDescription > attributes; map< string, AttributeDescription > optionals; map< string, vector > alternatives; string lastError; }; // ----------------------------------------------------------------------------- // object description // ----------------------------------------------------------------------------- ObjectDescription::ObjectDescription () { impl = new ObjectDescriptionImpl(); } ObjectDescription::~ObjectDescription () { delete impl; } string const& ObjectDescription::lastError () { return impl->lastError; } bool ObjectDescription::parse (VariantObject* object) { impl->lastError.clear(); // object must be a json array if (object == 0) { impl->lastError = "cannot parse object"; return false; } if (! object->is()) { impl->lastError = "not an object"; return false; } VariantArray* array = object->as(); // now find the attributes, optionals, and alternatives for (map::iterator i = impl->attributes.begin(); i != impl->attributes.end(); ++i) { string const& name = i->first; AttributeDescription& desc = i->second; bool ok = loadObject(array, name, desc, false, impl->lastError); if (! ok) { return false; } } for (map::iterator i = impl->optionals.begin(); i != impl->optionals.end(); ++i) { string const& name = i->first; AttributeDescription& desc = i->second; bool ok = loadObject(array, name, desc, true, impl->lastError); if (! ok) { return false; } } for (map< string, vector >::iterator i = impl->alternatives.begin(); i != impl->alternatives.end(); ++i) { string const& name = i->first; bool ok = loadAlternatives(array, name, i->second, impl->lastError); if (! ok) { return false; } } transform(); return true; } void ObjectDescription::transform () { } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // attribute // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ObjectDescription& ObjectDescription::attribute (string const& name, VariantArray*& store) { impl->attributes[name] = AttributeDescription(OD_VARIANT_ARRAY, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, VariantBoolean*& store) { impl->attributes[name] = AttributeDescription(OD_VARIANT_BOOLEAN, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, bool& store) { impl->attributes[name] = AttributeDescription(OD_BOOLEAN, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, VariantDouble*& store) { impl->attributes[name] = AttributeDescription(OD_VARIANT_DOUBLE, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, double& store) { impl->attributes[name] = AttributeDescription(OD_DOUBLE, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, VariantInt64*& store) { impl->attributes[name] = AttributeDescription(OD_VARIANT_INTEGER, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, int64_t& store) { impl->attributes[name] = AttributeDescription(OD_INTEGER, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, VariantNull*& store) { impl->attributes[name] = AttributeDescription(OD_VARIANT_NULL, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, VariantString*& store) { impl->attributes[name] = AttributeDescription(OD_VARIANT_STRING, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, string& store) { impl->attributes[name] = AttributeDescription(OD_STRING, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, vector& store) { impl->attributes[name] = AttributeDescription(OD_VARIANT_STRING_LIST, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, vector& store) { impl->attributes[name] = AttributeDescription(OD_STRING_LIST, reinterpret_cast(&store), 0); return *this; } ObjectDescription& ObjectDescription::attribute (string const& name, VariantVector*& store) { impl->attributes[name] = AttributeDescription(OD_VARIANT_VECTOR, reinterpret_cast(&store), 0); return *this; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // optional // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ObjectDescription& ObjectDescription::optional (string const& name, VariantArray*& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_VARIANT_ARRAY, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, VariantBoolean*& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_VARIANT_BOOLEAN, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, bool& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_BOOLEAN, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, VariantDouble*& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_VARIANT_DOUBLE, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, double& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_DOUBLE, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, VariantInt64*& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_VARIANT_INTEGER, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, int64_t& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_INTEGER, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, VariantNull*& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_VARIANT_NULL, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, VariantString*& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_VARIANT_STRING, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, string& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_STRING, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, vector& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_VARIANT_STRING_LIST, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, vector& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_STRING_LIST, reinterpret_cast(&store), hasAttribute); return *this; } ObjectDescription& ObjectDescription::optional (string const& name, VariantVector*& store, bool* hasAttribute) { impl->optionals[name] = AttributeDescription(OD_VARIANT_VECTOR, reinterpret_cast(&store), hasAttribute); return *this; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // alternative // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ObjectDescription& ObjectDescription::alternative (string const& name, VariantArray*& store) { impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_ARRAY, reinterpret_cast(&store), 0)); return *this; } ObjectDescription& ObjectDescription::alternative (string const& name, VariantBoolean*& store) { impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_BOOLEAN, reinterpret_cast(&store), 0)); return *this; } ObjectDescription& ObjectDescription::alternative (string const& name, VariantInt64*& store) { impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_INTEGER, reinterpret_cast(&store), 0)); return *this; } ObjectDescription& ObjectDescription::alternative (string const& name, VariantNull*& store) { impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_NULL, reinterpret_cast(&store), 0)); return *this; } ObjectDescription& ObjectDescription::alternative (string const& name, VariantString*& store) { impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_STRING, reinterpret_cast(&store), 0)); return *this; } ObjectDescription& ObjectDescription::alternative (string const& name, VariantVector*& store) { impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_VECTOR, reinterpret_cast(&store), 0)); return *this; } // ----------------------------------------------------------------------------- // public fucntions // ----------------------------------------------------------------------------- VariantObject* json (string const& input) { JsonParserXDriver parser; return parser.parse(input); } VariantObject* json (HttpRequest* request) { JsonParserXDriver parser; return parser.parse(request->body()); } VariantArray* jsonArray (string const& input) { JsonParserXDriver parser; VariantObject* object = parser.parse(input); if (object == 0) { return 0; } else if (object->type() == VariantObject::VARIANT_ARRAY) { return dynamic_cast(object); } else { delete object; return 0; } } VariantArray* jsonArray (HttpRequest* request) { JsonParserXDriver parser; VariantObject* object = parser.parse(request->body()); if (object == 0) { return 0; } else if (object->type() == VariantObject::VARIANT_ARRAY) { return dynamic_cast(object); } else { delete object; return 0; } } } } }