Commit 42f1194a authored by miloyip's avatar miloyip

Add remote reference

parent ed7e9bc9
......@@ -903,6 +903,7 @@ public:
friend class internal::Schema<GenericSchemaDocument>;
GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
document_(document),
remoteProvider_(remoteProvider),
root_(),
schemaMap_(allocator, kInitialSchemaMapSize),
......@@ -918,22 +919,8 @@ public:
SchemaEntry* refEntry = schemaRef_.template Pop<SchemaEntry>(1);
PointerType p = refEntry->pointer; // Due to re-entrance,
SchemaType* source = refEntry->schema; // backup the entry first,
refEntry->~SchemaEntry(); // and then destruct it.
bool resolved = false;
for (SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target <= schemaMap_.template Top<SchemaEntry>(); ++target)
if (p == target->pointer) {
source->ref_ = target->schema;
resolved = true;
break;
}
// If not reesolved to existing schemas, try to create schema from the pointer
if (!resolved) {
if (const ValueType* v = p.Get(document))
source->ref_ = CreateSchema(p, *v); // cause re-entrance (modifying schemaRef_)
}
refEntry->~SchemaEntry(); // and then destruct it.
source->ref_ = GetSchema(p);
}
}
......@@ -970,32 +957,41 @@ private:
while (i < len && s[i] != '#') // Find the first #
i++;
if (s[i] == '#') {
if (i > 0) { // Remote reference, resolve immediately
if (remoteProvider_) {
GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i);
GenericPointer<ValueType> pointer(s, len - i);
schema->ref_ = remoteDocument->GetSchema(pointer);
if (i > 0) { // Remote reference, resolve immediately
if (remoteProvider_) {
if (GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) {
printf("remote fragment: %*s\n", len - i, &s[i]);
GenericPointer<ValueType> pointer(&s[i], len - i);
if (pointer.IsValid())
schema->ref_ = remoteDocument->GetSchema(pointer);
}
}
else { // Local reference, defer resolution
GenericPointer<ValueType> pointer(v.GetString(), v.GetStringLength());
if (pointer.IsValid())
new (schemaRef_.template Push<SchemaEntry>()) SchemaEntry(pointer, schema);
}
}
else if (s[i] == '#') { // Local reference, defer resolution
printf("local fragment: %*s\n", len - i, &s[i]);
GenericPointer<ValueType> pointer(&s[i], len - i);
if (pointer.IsValid())
new (schemaRef_.template Push<SchemaEntry>()) SchemaEntry(pointer, schema);
}
}
}
}
const SchemaType* GetSchema(const GenericPointer<ValueType>& pointer) {
(void)pointer;
return 0;
for (SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target <= schemaMap_.template Top<SchemaEntry>(); ++target)
if (pointer == target->pointer)
return target->schema;
if (const ValueType* v = pointer.Get(document_))
return CreateSchema(pointer, *v);
else
return 0;
}
static const size_t kInitialSchemaMapSize = 1024;
static const size_t kInitialSchemaRefSize = 1024;
const ValueType& document_;
IRemoteSchemaDocumentProviderType* remoteProvider_;
const SchemaType* root_; //!< Root schema.
internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
......
......@@ -698,11 +698,11 @@ TEST(SchemaValidator, AllOf_Nested) {
static char* ReadFile(const char* filename, size_t& length) {
const char *paths[] = {
"jsonschema/tests/draft4/%s",
"bin/jsonschema/tests/draft4/%s",
"../bin/jsonschema/tests/draft4/%s",
"../../bin/jsonschema/tests/draft4/%s",
"../../../bin/jsonschema/tests/draft4/%s"
"%s",
"bin/%s",
"../bin/%s",
"../../bin/%s",
"../../../bin/%s"
};
char buffer[1024];
FILE *fp = 0;
......@@ -726,6 +726,62 @@ static char* ReadFile(const char* filename, size_t& length) {
return json;
}
class RemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
public:
RemoteSchemaDocumentProvider() {
const char* filenames[kCount] = {
"integer.json",
"subSchemas.json",
"folder/folderInteger.json"
};
for (size_t i = 0; i < kCount; i++) {
d_[i] = 0;
sd_[i] = 0;
char filename[FILENAME_MAX];
sprintf(filename, "jsonschema/remotes/%s", filenames[i]);
size_t length;
char* json = ReadFile(filename, length);
if (!json) {
printf("json remote file %s not found", filename);
ADD_FAILURE();
}
else {
d_[i] = new Document;
d_[i]->Parse(json);
sd_[i] = new SchemaDocument(*d_[i]);
free(json);
}
};
}
~RemoteSchemaDocumentProvider() {
for (size_t i = 0; i < kCount; i++) {
delete d_[i];
delete sd_[i];
}
}
virtual SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
const char* uris[kCount] = {
"http://localhost:1234/integer.json",
"http://localhost:1234/subSchemas.json",
"http://localhost:1234/folder/folderInteger.json"
};
for (size_t i = 0; i < kCount; i++) {
if (strncmp(uri, uris[i], length) == 0)
return sd_[i];
}
return 0;
}
private:
static const size_t kCount = 3;
Document* d_[kCount];
SchemaDocument* sd_[kCount];
};
TEST(SchemaValidator, TestSuite) {
const char* filenames[] = {
......@@ -765,8 +821,11 @@ TEST(SchemaValidator, TestSuite) {
unsigned testCount = 0;
unsigned passCount = 0;
RemoteSchemaDocumentProvider provider;
for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
const char* filename = filenames[i];
char filename[FILENAME_MAX];
sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]);
size_t length;
char* json = ReadFile(filename, length);
if (!json) {
......@@ -782,7 +841,7 @@ TEST(SchemaValidator, TestSuite) {
}
else {
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
SchemaDocument schema((*schemaItr)["schema"]);
SchemaDocument schema((*schemaItr)["schema"], &provider);
SchemaValidator validator(schema);
const char* description1 = (*schemaItr)["description"].GetString();
const Value& tests = (*schemaItr)["tests"];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment