protected ValidationError CreateError(string message, ErrorType errorType, JSchema schema, object value, IList<ValidationError> childErrors, IJsonLineInfo lineInfo, string path) { if (_schemaDiscovery == null) { _schemaDiscovery = new JSchemaDiscovery(); _schemaDiscovery.Discover(Schema, null); } ValidationError error = new ValidationError(); error.Message = message; error.ErrorType = errorType; error.Path = path; if (lineInfo != null) { error.LineNumber = lineInfo.LineNumber; error.LinePosition = lineInfo.LinePosition; } error.Schema = schema; error.SchemaId = _schemaDiscovery.KnownSchemas.Single(s => s.Schema == schema).Id; error.SchemaBaseUri = schema.BaseUri; error.Value = value; error.ChildErrors = childErrors; return error; }
public void RaiseError(IFormattable message, ErrorType errorType, JSchema schema, object value, IList<ValidationError> childErrors) { ValidationError error = CreateError(message, errorType, schema, value, childErrors); // shared cache information that could be read/populated from multiple threads // lock to ensure that only one thread writes known schemas if (Schema.KnownSchemas.Count == 0) { lock (Schema.KnownSchemas) { if (Schema.KnownSchemas.Count == 0) { JSchemaDiscovery discovery = new JSchemaDiscovery(Schema.KnownSchemas, KnownSchemaState.External); discovery.Discover(Schema, null); } } } PopulateSchemaId(error); SchemaValidationEventHandler handler = ValidationEventHandler; if (handler != null) handler(_publicValidator, new SchemaValidationEventArgs(error)); else throw JSchemaValidationException.Create(error); }
protected ValidationError CreateError(string message, ErrorType errorType, JSchema schema, object value, IList<ValidationError> childErrors, IJsonLineInfo lineInfo, string path) { if (_schemaDiscovery == null) { _schemaDiscovery = new JSchemaDiscovery(); _schemaDiscovery.Discover(Schema, null); } Uri schemaId = _schemaDiscovery.KnownSchemas.Single(s => s.Schema == schema).Id; ValidationError error = ValidationError.CreateValidationError(message, errorType, schema, schemaId, value, childErrors, lineInfo, path); return error; }
public void SimpleTest() { JSchema prop = new JSchema(); JSchema root = new JSchema { Properties = { { "prop1", prop }, { "prop2", prop } } }; JSchemaDiscovery discovery = new JSchemaDiscovery(); discovery.Discover(root, null); Assert.AreEqual(2, discovery.KnownSchemas.Count); Assert.AreEqual(root, discovery.KnownSchemas[0].Schema); Assert.AreEqual(new Uri("#", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[0].Id); Assert.AreEqual(prop, discovery.KnownSchemas[1].Schema); Assert.AreEqual(new Uri("#/properties/prop1", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[1].Id); }
public static bool FindSchema(Action <JSchema> setSchema, JSchema schema, Uri rootSchemaId, Uri reference, JSchemaReader schemaReader, ref JSchemaDiscovery discovery) { // todo, better way to get parts from Uri string[] parts = reference.ToString().Split('/'); bool resolvedSchema; if (parts.Length > 0 && (parts[0] == "#" || parts[0] == rootSchemaId + "#")) { schemaReader._schemaStack.Push(schema); parts = parts.Skip(1).ToArray(); object current = schema; foreach (string part in parts) { string unescapedPart = UnescapeReference(part); if (current is JSchema) { JSchema s = current as JSchema; schemaReader._schemaStack.Push(s); switch (unescapedPart) { case Constants.PropertyNames.Properties: current = s._properties; break; case Constants.PropertyNames.Items: current = s._items; break; case Constants.PropertyNames.AdditionalProperties: current = s.AdditionalProperties; break; case Constants.PropertyNames.AdditionalItems: current = s.AdditionalItems; break; case Constants.PropertyNames.Not: current = s.Not; break; case Constants.PropertyNames.OneOf: current = s._oneOf; break; case Constants.PropertyNames.AllOf: current = s._allOf; break; case Constants.PropertyNames.AnyOf: current = s._anyOf; break; case Constants.PropertyNames.Enum: current = s._enum; break; case Constants.PropertyNames.PatternProperties: current = s._patternProperties; break; case Constants.PropertyNames.Dependencies: current = s._dependencies; break; default: JToken t; s.ExtensionData.TryGetValue(unescapedPart, out t); current = t; break; } } else if (current is JToken) { JToken resolvedToken; JToken t = (JToken)current; if (t is JObject) { resolvedToken = t[unescapedPart]; } else if (t is JArray || t is JConstructor) { int index; if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index)) { if (index > t.Count() || index < 0) { resolvedToken = null; } else { resolvedToken = t[index]; } } else { resolvedToken = null; } } else { resolvedToken = null; } if (resolvedToken != null) { JSchemaAnnotation annotation = resolvedToken.Annotation <JSchemaAnnotation>(); if (annotation != null) { current = annotation.Schema; } else { current = resolvedToken; } } else { current = null; } } else if (current is IDictionary) { IDictionary d = (IDictionary)current; current = d[unescapedPart]; } else if (current is IList) { IList l = (IList)current; int index; if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index)) { if (index > l.Count || index < 0) { current = null; } else { current = l[index]; } } else { current = null; } } else { break; } } if (current is JToken) { JToken t = (JToken)current; JSchemaAnnotation annotation = t.Annotation <JSchemaAnnotation>(); if (annotation != null) { setSchema(annotation.Schema); resolvedSchema = true; } else { JSchema inlineSchema = schemaReader.ReadInlineSchema(setSchema, t); string path = reference.OriginalString; if (path.StartsWith("#/", StringComparison.Ordinal)) { path = path.Substring(2, path.Length - 2); } discovery.Discover(inlineSchema, rootSchemaId, path); resolvedSchema = true; } } else { JSchema s = current as JSchema; if (s != null) { setSchema(s); resolvedSchema = true; // schema is a reference schema and needs to be resolved if (s.Reference != null) { schemaReader.AddDeferedSchema(setSchema, s); } } else { resolvedSchema = false; } } schemaReader._schemaStack.Clear(); } else { discovery.Discover(schema, null); Uri resolvedReference = ResolveSchemaId(rootSchemaId, reference); // default Uri comparison ignores fragments // use firstordefault to handle duplicates KnownSchema knownSchema = discovery.KnownSchemas.FirstOrDefault(s => s.Id.OriginalString.TrimEnd('#') == resolvedReference.OriginalString.TrimEnd('#')); if (knownSchema != null) { resolvedSchema = true; setSchema(knownSchema.Schema); } else { int hashIndex = resolvedReference.OriginalString.IndexOf('#'); if (hashIndex != -1) { Uri path = new Uri(resolvedReference.OriginalString.Substring(0, hashIndex), UriKind.RelativeOrAbsolute); Uri fragment = new Uri(resolvedReference.OriginalString.Substring(hashIndex), UriKind.RelativeOrAbsolute); // default Uri comparison ignores fragments // there could be duplicated ids. use FirstOrDefault to get first schema with an id knownSchema = discovery.KnownSchemas.FirstOrDefault(s => s.Id.OriginalString.TrimEnd('#') == path.OriginalString); if (knownSchema != null) { // don't attempt to find a schema in the same schema again // avoids stackoverflow if (knownSchema.Schema != schema || !UriComparer.Instance.Equals(rootSchemaId, path) || !UriComparer.Instance.Equals(reference, fragment)) { resolvedSchema = FindSchema(setSchema, knownSchema.Schema, path, fragment, schemaReader, ref discovery); } else { resolvedSchema = false; } } else { resolvedSchema = false; } } else { resolvedSchema = false; } } } return(resolvedSchema); }
public void RootId_NestedId() { JSchema prop1 = new JSchema { Id = new Uri("test.json/", UriKind.RelativeOrAbsolute), Items = { new JSchema(), new JSchema { Id = new Uri("#fragmentItem2", UriKind.RelativeOrAbsolute), Items = { new JSchema(), new JSchema { Id = new Uri("#fragmentItem2Item2", UriKind.RelativeOrAbsolute) }, new JSchema { Id = new Uri("file.json", UriKind.RelativeOrAbsolute) }, new JSchema { Id = new Uri("/file1.json", UriKind.RelativeOrAbsolute) } } } } }; JSchema prop2 = new JSchema { Id = new Uri("#fragment", UriKind.RelativeOrAbsolute), Not = new JSchema() }; JSchema root = new JSchema { Id = new Uri("http://localhost/", UriKind.RelativeOrAbsolute), Properties = { { "prop1", prop1 }, { "prop2", prop2 } }, ExtensionData = { { "definitions", new JObject { { "def1", new JSchema() }, { "def2", new JSchema { Id = new Uri("def2.json", UriKind.RelativeOrAbsolute) } }, { "defn", new JArray { new JValue(5), new JSchema() } } } } } }; JSchemaDiscovery discovery = new JSchemaDiscovery(); discovery.Discover(root, null); int i = 0; Assert.AreEqual(new Uri("http://localhost/#", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root, discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/#/definitions/def1", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual((JSchema)root.ExtensionData["definitions"]["def1"], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/def2.json", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual((JSchema)root.ExtensionData["definitions"]["def2"], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/#/definitions/defn/1", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual((JSchema)root.ExtensionData["definitions"]["defn"][1], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/test.json/", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root.Properties["prop1"], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/test.json/#/items/0", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root.Properties["prop1"].Items[0], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/test.json/#fragmentItem2", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root.Properties["prop1"].Items[1], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/test.json/#fragmentItem2/items/0", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root.Properties["prop1"].Items[1].Items[0], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/test.json/#fragmentItem2Item2", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root.Properties["prop1"].Items[1].Items[1], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/test.json/file.json", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root.Properties["prop1"].Items[1].Items[2], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/file1.json", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root.Properties["prop1"].Items[1].Items[3], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/#fragment", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root.Properties["prop2"], discovery.KnownSchemas[i++].Schema); Assert.AreEqual(new Uri("http://localhost/#fragment/not", UriKind.RelativeOrAbsolute), discovery.KnownSchemas[i].Id); Assert.AreEqual(root.Properties["prop2"].Not, discovery.KnownSchemas[i++].Schema); }
public void Draft4Example() { JSchema schema1 = new JSchema { Id = new Uri("#foo", UriKind.RelativeOrAbsolute), Title = "schema1" }; JSchema schema2 = new JSchema { Id = new Uri("otherschema.json", UriKind.RelativeOrAbsolute), Title = "schema2", ExtensionData = { { "nested", new JSchema { Title = "nested", Id = new Uri("#bar", UriKind.RelativeOrAbsolute) } }, { "alsonested", new JSchema { Title = "alsonested", Id = new Uri("t/inner.json#a", UriKind.RelativeOrAbsolute), ExtensionData = { { "nestedmore", new JSchema { Title = "nestedmore" } } } } } } }; JSchema schema3 = new JSchema { Title = "schema3", Id = new Uri("some://where.else/completely#", UriKind.RelativeOrAbsolute) }; JSchema root = new JSchema { Id = new Uri("http://x.y.z/rootschema.json#", UriKind.RelativeOrAbsolute), ExtensionData = { { "schema1", schema1 }, { "schema2", schema2 }, { "schema3", schema3 } } }; JSchemaDiscovery discovery = new JSchemaDiscovery(); discovery.Discover(root, null); Assert.AreEqual(7, discovery.KnownSchemas.Count); Assert.AreEqual("http://x.y.z/rootschema.json#", discovery.KnownSchemas[0].Id.ToString()); Assert.AreEqual("http://x.y.z/rootschema.json#foo", discovery.KnownSchemas[1].Id.ToString()); Assert.AreEqual("http://x.y.z/otherschema.json", discovery.KnownSchemas[2].Id.ToString()); Assert.AreEqual("http://x.y.z/otherschema.json#bar", discovery.KnownSchemas[3].Id.ToString()); Assert.AreEqual("http://x.y.z/t/inner.json#a", discovery.KnownSchemas[4].Id.ToString()); Assert.AreEqual("http://x.y.z/t/inner.json#/nestedmore", discovery.KnownSchemas[5].Id.ToString()); Assert.AreEqual("some://where.else/completely#", discovery.KnownSchemas[6].Id.ToString()); }
public static bool FindSchema(Action <JSchema> setSchema, JSchema schema, Uri rootSchemaId, Uri reference, JSchemaReader schemaReader) { // todo, better way to get parts from Uri string[] parts = reference.ToString().Split('/'); bool resolvedSchema; if (parts.Length > 0 && (parts[0] == "#" || parts[0] == rootSchemaId + "#")) { schemaReader._schemaStack.Push(schema); parts = parts.Skip(1).ToArray(); object current = schema; foreach (string part in parts) { string unescapedPart = UnescapeReference(part); if (current is JSchema) { JSchema s = current as JSchema; schemaReader._schemaStack.Push(s); switch (unescapedPart) { case Constants.PropertyNames.Properties: current = s._properties; break; case Constants.PropertyNames.Items: current = s._items; break; case Constants.PropertyNames.AdditionalProperties: current = s.AdditionalProperties; break; case Constants.PropertyNames.AdditionalItems: current = s.AdditionalItems; break; case Constants.PropertyNames.Not: current = s.Not; break; case Constants.PropertyNames.OneOf: current = s._oneOf; break; case Constants.PropertyNames.AllOf: current = s._allOf; break; case Constants.PropertyNames.AnyOf: current = s._anyOf; break; case Constants.PropertyNames.Enum: current = s._enum; break; case Constants.PropertyNames.PatternProperties: current = s._patternProperties; break; default: JToken t; s.ExtensionData.TryGetValue(unescapedPart, out t); current = t; break; } } else if (current is JToken) { JToken resolvedToken; JToken t = (JToken)current; if (t is JObject) { resolvedToken = t[unescapedPart]; } else if (t is JArray || t is JConstructor) { int index; if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index)) { if (index > t.Count() || index < 0) { resolvedToken = null; } else { resolvedToken = t[index]; } } else { resolvedToken = null; } } else { resolvedToken = null; } if (resolvedToken != null) { JSchemaAnnotation annotation = resolvedToken.Annotation <JSchemaAnnotation>(); if (annotation != null) { current = annotation.Schema; } else { current = resolvedToken; } } else { current = null; } } else if (current is IDictionary) { IDictionary d = (IDictionary)current; current = d[unescapedPart]; } else if (current is IList) { IList l = (IList)current; int index; if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index)) { if (index > l.Count || index < 0) { current = null; } else { current = l[index]; } } else { current = null; } } else { break; } } if (current is JToken) { JToken t = (JToken)current; JSchemaAnnotation annotation = t.Annotation <JSchemaAnnotation>(); if (annotation != null) { setSchema(annotation.Schema); resolvedSchema = true; } else { schemaReader.ReadInlineSchema(setSchema, t); resolvedSchema = true; } } else { var s = current as JSchema; if (s != null) { setSchema(s); resolvedSchema = true; } else { resolvedSchema = false; } } schemaReader._schemaStack.Clear(); } else { JSchemaDiscovery discovery = new JSchemaDiscovery(); discovery.Discover(schema, null); Uri resolvedReference = ResolveSchemaId(rootSchemaId, reference); // default Uri comparison ignores fragments KnownSchema knownSchema = discovery.KnownSchemas.SingleOrDefault(s => s.Id.OriginalString.TrimEnd('#') == resolvedReference.OriginalString.TrimEnd('#')); if (knownSchema != null) { resolvedSchema = true; setSchema(knownSchema.Schema); } else { int hashIndex = resolvedReference.OriginalString.IndexOf('#'); if (hashIndex != -1) { Uri path = new Uri(resolvedReference.OriginalString.Substring(0, hashIndex), UriKind.RelativeOrAbsolute); Uri fragment = new Uri(resolvedReference.OriginalString.Substring(hashIndex), UriKind.RelativeOrAbsolute); // default Uri comparison ignores fragments knownSchema = discovery.KnownSchemas.SingleOrDefault(s => s.Id.OriginalString.TrimEnd('#') == path.OriginalString); if (knownSchema != null) { resolvedSchema = FindSchema(setSchema, knownSchema.Schema, path, fragment, schemaReader); } else { resolvedSchema = false; } } else { resolvedSchema = false; } } } return(resolvedSchema); }
public static bool FindSchema(Action<JSchema> setSchema, JSchema schema, Uri rootSchemaId, Uri reference, JSchemaReader schemaReader) { // todo, better way to get parts from Uri string[] parts = reference.ToString().Split('/'); bool resolvedSchema; if (parts.Length > 0 && (parts[0] == "#" || parts[0] == rootSchemaId + "#")) { schemaReader._schemaStack.Push(schema); parts = parts.Skip(1).ToArray(); object current = schema; foreach (string part in parts) { string unescapedPart = UnescapeReference(part); if (current is JSchema) { JSchema s = current as JSchema; schemaReader._schemaStack.Push(s); switch (unescapedPart) { case Constants.PropertyNames.Properties: current = s._properties; break; case Constants.PropertyNames.Items: current = s._items; break; case Constants.PropertyNames.AdditionalProperties: current = s.AdditionalProperties; break; case Constants.PropertyNames.AdditionalItems: current = s.AdditionalItems; break; case Constants.PropertyNames.Not: current = s.Not; break; case Constants.PropertyNames.OneOf: current = s._oneOf; break; case Constants.PropertyNames.AllOf: current = s._allOf; break; case Constants.PropertyNames.AnyOf: current = s._anyOf; break; case Constants.PropertyNames.Enum: current = s._enum; break; case Constants.PropertyNames.PatternProperties: current = s._patternProperties; break; case Constants.PropertyNames.Dependencies: current = s._dependencies; break; default: JToken t; s.ExtensionData.TryGetValue(unescapedPart, out t); current = t; break; } } else if (current is JToken) { JToken resolvedToken; JToken t = (JToken)current; if (t is JObject) { resolvedToken = t[unescapedPart]; } else if (t is JArray || t is JConstructor) { int index; if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index)) { if (index > t.Count() || index < 0) resolvedToken = null; else resolvedToken = t[index]; } else { resolvedToken = null; } } else { resolvedToken = null; } if (resolvedToken != null) { JSchemaAnnotation annotation = resolvedToken.Annotation<JSchemaAnnotation>(); if (annotation != null) current = annotation.Schema; else current = resolvedToken; } else { current = null; } } else if (current is IDictionary) { IDictionary d = (IDictionary)current; current = d[unescapedPart]; } else if (current is IList) { IList l = (IList)current; int index; if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index)) { if (index > l.Count || index < 0) current = null; else current = l[index]; } else { current = null; } } else { break; } } if (current is JToken) { JToken t = (JToken)current; JSchemaAnnotation annotation = t.Annotation<JSchemaAnnotation>(); if (annotation != null) { setSchema(annotation.Schema); resolvedSchema = true; } else { schemaReader.ReadInlineSchema(setSchema, t); resolvedSchema = true; } } else { JSchema s = current as JSchema; if (s != null) { setSchema(s); resolvedSchema = true; // schema is a reference schema and needs to be resolved if (s.Reference != null) schemaReader.AddDeferedSchema(setSchema, s); } else { resolvedSchema = false; } } schemaReader._schemaStack.Clear(); } else { JSchemaDiscovery discovery = new JSchemaDiscovery(); discovery.Discover(schema, null); Uri resolvedReference = ResolveSchemaId(rootSchemaId, reference); // default Uri comparison ignores fragments KnownSchema knownSchema = discovery.KnownSchemas.SingleOrDefault(s => s.Id.OriginalString.TrimEnd('#') == resolvedReference.OriginalString.TrimEnd('#')); if (knownSchema != null) { resolvedSchema = true; setSchema(knownSchema.Schema); } else { int hashIndex = resolvedReference.OriginalString.IndexOf('#'); if (hashIndex != -1) { Uri path = new Uri(resolvedReference.OriginalString.Substring(0, hashIndex), UriKind.RelativeOrAbsolute); Uri fragment = new Uri(resolvedReference.OriginalString.Substring(hashIndex), UriKind.RelativeOrAbsolute); // default Uri comparison ignores fragments knownSchema = discovery.KnownSchemas.SingleOrDefault(s => s.Id.OriginalString.TrimEnd('#') == path.OriginalString); if (knownSchema != null) { // don't attempt to find a schema in the same schema again // avoids stackoverflow if (knownSchema.Schema != schema || !UriComparer.Instance.Equals(rootSchemaId, path) || !UriComparer.Instance.Equals(reference, fragment)) { resolvedSchema = FindSchema(setSchema, knownSchema.Schema, path, fragment, schemaReader); } else { resolvedSchema = false; } } else { resolvedSchema = false; } } else { resolvedSchema = false; } } } return resolvedSchema; }
public void DuplicateIds() { JSchema root = new JSchema { Properties = { { "prop1", new JSchema { Id = new Uri("duplicate", UriKind.RelativeOrAbsolute), Properties = { { "test", new JSchema() } } } }, { "prop2", new JSchema { Id = new Uri("duplicate", UriKind.RelativeOrAbsolute), Properties = { { "test", new JSchema() } } } } } }; JSchemaDiscovery discovery = new JSchemaDiscovery(); discovery.Discover(root, null); Assert.AreEqual("#", discovery.KnownSchemas[0].Id.OriginalString); Assert.AreEqual("duplicate", discovery.KnownSchemas[1].Id.OriginalString); Assert.AreEqual("duplicate#/properties/test", discovery.KnownSchemas[2].Id.OriginalString); Assert.AreEqual("duplicate", discovery.KnownSchemas[3].Id.OriginalString); Assert.AreEqual("duplicate#/properties/test", discovery.KnownSchemas[4].Id.OriginalString); }
public void MultipleNestedPaths() { string schemaJson = @"{ ""$schema"": ""http://json-schema.org/draft-04/schema#"", ""type"": ""object"", ""title"": ""Quotes Configurator Schema"", ""description"": ""Defines the constraints for an acceptable JSON object required to produce a package"", ""properties"": { ""working_directory"" : { ""$ref"": ""#/definitions/working_directory"" }, ""environment"" : { ""$ref"": ""#/definitions/environment"" }, ""timezone"" : { ""description"": ""Timezone in in which processes are scheduled, does control the timezone in which they run"", ""type"": ""string"" }, ""cleanup_directories"" : { ""description"": ""Directories (and corresponding file types) which will be cleaned twice daily"", ""type"": ""object"" }, ""holiday_key"" : { ""description"": ""Holiday key which your package will follow"", ""type"": ""string"" }, ""cpu_alerting_threshold"" : { ""description"": ""Alerting threshold for high CPU usage"", ""type"": ""integer"", ""minimum"": 75, ""maximum"" : 250, ""multipleOf"" : 1 }, ""processes"" : { ""$ref"": ""#/definitions/processes"" }, ""schedule"" : { ""$ref"": ""#/definitions/schedule"" } }, ""additionalProperties"": false, ""required"": [ ""working_directory"", ""timezone"", ""environment"", ""cleanup_directories"", ""processes"", ""schedule"" ], ""definitions"": { ""nonEmptyWord"" : { ""type"" : ""string"", ""pattern"" : ""(^\\S+$)"" }, ""nonEmptyString"" : { ""type"" : ""string"", ""pattern"": ""(^\\S+(\\S|\\s)+$)"" }, ""dayShorthand"" : { ""type"" : ""string"", ""enum"" : [ ""Sun"", ""Mon"", ""Tue"", ""Wed"", ""Thu"", ""Fri"", ""Sat"" ] }, ""twentyFourHourTime"" : { ""type"" : ""integer"", ""minimum"": 0, ""maximum"" : 235959, ""multipleOf"" : 1 }, ""environment"" : { ""description"": ""Global environment settings for each of the processes"", ""type"": ""object"" }, ""working_directory"" : { ""description"": ""Working directory for each process. Usually either root directory of your package or its etc/ directory"", ""type"": ""string"", ""pattern"": ""(^@\\w+@$)"" }, ""process"": { ""id"": ""process"", ""type"" : ""object"", ""properties"": { ""working_directory"" : { ""$ref"": ""../#/definitions/working_directory"" }, ""environment"" : { ""$ref"": ""../#/definitions/environment"" }, ""name"" : { ""$ref"": ""../#/definitions/nonEmptyWord"" }, ""description"" : { ""$ref"": ""../#/definitions/nonEmptyString"" }, ""ulimit"" : { ""type"" : ""integer"", ""multipleOf"": 256, ""minimum"" : 256 }, ""alert_on_downtime"" : { ""type"" : ""boolean"" }, ""starts_on_holiday"" : { ""type"" : ""boolean"" }, ""check_for_completion"" : { ""type"" : ""boolean"" }, ""arguments"" : { ""type"" : ""array"", ""items"" : { ""$ref"": ""../#/definitions/nonEmptyString"" }, ""minItems"": 1 }, ""stats_store_groups"" : { ""type"" : ""array"", ""items"" : { ""$ref"": ""../#/definitions/nonEmptyWord"" }, ""uniqueItems"" : true } }, ""patternProperties"": { ""(^binary$|^module$|^external$|^bash$|^python$|^perl$)"" : { ""$ref"": ""../#/definitions/nonEmptyWord"" }, }, ""additionalProperties"": false, ""minProperties"": 5, ""maxProperties"": 12, ""allOf"" : [ { ""required"": [ ""name"", ""ulimit"", ""alert_on_downtime"", ""starts_on_holiday"" ] }, { ""oneOf"": [ { ""required"" : [ ""binary"" ] }, { ""required"" : [ ""module"" ] }, { ""required"" : [ ""external"" ] }, { ""required"" : [ ""bash"" ] }, { ""required"" : [ ""python"" ] }, { ""required"" : [ ""perl"" ] } ] } ] }, ""processes"": { ""description"": ""All processes that are allowed to be run"", ""type"" : ""array"", ""items"" : { ""$ref"": ""#/definitions/process"" } }, ""task"": { ""id"" : ""task"", ""type"" : ""object"", ""properties"" : { ""task_name"" : { ""$ref"": ""../#/definitions/nonEmptyWord"" }, ""processes"" : { ""type"" : ""array"" }, ""runs_on"" : { ""type"" : ""array"", ""items"" : { ""$ref"": ""../#/definitions/dayShorthand"" }, ""uniqueItems"" : true } }, ""patternProperties"": { ""(^start_at$|^end_at$)"" : { ""$ref"": ""../#/definitions/twentyFourHourTime"" }, }, ""allOf"" : [ { ""required"": [ ""task_name"", ""processes"", ""runs_on"" ] }, { ""oneOf"" : [ { ""anyOf"": [ { ""required"" : [ ""start_at"" ] } ] }, { ""anyOf"": [ { ""required"" : [ ""end_at"" ] } ] } ] }, ], ""additionalProperties"": false }, ""schedule"": { ""description"": ""Separate tasks which consist of one or more processes and will run under your package"", ""type"" : ""array"", ""items"" : { ""$ref"": ""#/definitions/task"" } } } }"; JSchema schema = JSchema.Parse(schemaJson); JSchemaDiscovery discovery = new JSchemaDiscovery(); discovery.Discover(schema, null); //for (int i = 0; i < discovery.KnownSchemas.Count; i++) //{ // KnownSchema knownSchema = discovery.KnownSchemas[i]; // Console.WriteLine(string.Format(@"Assert.AreEqual(""{0}"", discovery.KnownSchemas[{1}].Id.OriginalString);", knownSchema.Id, i)); //} Assert.AreEqual("#", discovery.KnownSchemas[0].Id.OriginalString); Assert.AreEqual("#/definitions/nonEmptyWord", discovery.KnownSchemas[1].Id.OriginalString); Assert.AreEqual("#/definitions/nonEmptyString", discovery.KnownSchemas[2].Id.OriginalString); Assert.AreEqual("#/definitions/dayShorthand", discovery.KnownSchemas[3].Id.OriginalString); Assert.AreEqual("#/definitions/twentyFourHourTime", discovery.KnownSchemas[4].Id.OriginalString); Assert.AreEqual("#/definitions/environment", discovery.KnownSchemas[5].Id.OriginalString); Assert.AreEqual("#/definitions/working_directory", discovery.KnownSchemas[6].Id.OriginalString); Assert.AreEqual("process", discovery.KnownSchemas[7].Id.OriginalString); Assert.AreEqual("process#/properties/ulimit", discovery.KnownSchemas[8].Id.OriginalString); Assert.AreEqual("process#/properties/alert_on_downtime", discovery.KnownSchemas[9].Id.OriginalString); Assert.AreEqual("process#/properties/starts_on_holiday", discovery.KnownSchemas[10].Id.OriginalString); Assert.AreEqual("process#/properties/check_for_completion", discovery.KnownSchemas[11].Id.OriginalString); Assert.AreEqual("process#/properties/arguments", discovery.KnownSchemas[12].Id.OriginalString); Assert.AreEqual("process#/properties/stats_store_groups", discovery.KnownSchemas[13].Id.OriginalString); Assert.AreEqual("process#/allOf/0", discovery.KnownSchemas[14].Id.OriginalString); Assert.AreEqual("process#/allOf/1", discovery.KnownSchemas[15].Id.OriginalString); Assert.AreEqual("process#/allOf/1/oneOf/0", discovery.KnownSchemas[16].Id.OriginalString); Assert.AreEqual("process#/allOf/1/oneOf/1", discovery.KnownSchemas[17].Id.OriginalString); Assert.AreEqual("process#/allOf/1/oneOf/2", discovery.KnownSchemas[18].Id.OriginalString); Assert.AreEqual("process#/allOf/1/oneOf/3", discovery.KnownSchemas[19].Id.OriginalString); Assert.AreEqual("process#/allOf/1/oneOf/4", discovery.KnownSchemas[20].Id.OriginalString); Assert.AreEqual("process#/allOf/1/oneOf/5", discovery.KnownSchemas[21].Id.OriginalString); Assert.AreEqual("#/definitions/processes", discovery.KnownSchemas[22].Id.OriginalString); Assert.AreEqual("task", discovery.KnownSchemas[23].Id.OriginalString); Assert.AreEqual("task#/properties/processes", discovery.KnownSchemas[24].Id.OriginalString); Assert.AreEqual("task#/properties/runs_on", discovery.KnownSchemas[25].Id.OriginalString); Assert.AreEqual("task#/allOf/0", discovery.KnownSchemas[26].Id.OriginalString); Assert.AreEqual("task#/allOf/1", discovery.KnownSchemas[27].Id.OriginalString); Assert.AreEqual("task#/allOf/1/oneOf/0", discovery.KnownSchemas[28].Id.OriginalString); Assert.AreEqual("task#/allOf/1/oneOf/0/anyOf/0", discovery.KnownSchemas[29].Id.OriginalString); Assert.AreEqual("task#/allOf/1/oneOf/1", discovery.KnownSchemas[30].Id.OriginalString); Assert.AreEqual("task#/allOf/1/oneOf/1/anyOf/0", discovery.KnownSchemas[31].Id.OriginalString); Assert.AreEqual("#/definitions/schedule", discovery.KnownSchemas[32].Id.OriginalString); Assert.AreEqual("#/properties/timezone", discovery.KnownSchemas[33].Id.OriginalString); Assert.AreEqual("#/properties/cleanup_directories", discovery.KnownSchemas[34].Id.OriginalString); Assert.AreEqual("#/properties/holiday_key", discovery.KnownSchemas[35].Id.OriginalString); Assert.AreEqual("#/properties/cpu_alerting_threshold", discovery.KnownSchemas[36].Id.OriginalString); }
public void ComplexPath() { string path = TestHelpers.ResolveFilePath(@"resources\schemas\custom\validator1.json"); string schemaJson = File.ReadAllText(path); JSchema schema = JSchema.Parse(schemaJson); JSchemaDiscovery discovery = new JSchemaDiscovery(); discovery.Discover(schema, null); Console.WriteLine(discovery.KnownSchemas[3].Id.OriginalString); // ensure the path does not contain multiple #'s Assert.AreEqual("http://www.example.org/IntegralLifeProduct#/definitions/ProductType/allOf/0", discovery.KnownSchemas[3].Id.OriginalString); }
public static bool FindSchema(Action <JSchema> setSchema, JSchema schema, Uri rootSchemaId, Uri reference, JSchemaReader schemaReader, ref JSchemaDiscovery discovery) { // todo, better way to get parts from Uri string[] parts = reference.ToString().Split('/'); bool resolvedSchema; if (parts.Length > 0 && (parts[0] == "#" || parts[0] == rootSchemaId + "#")) { schemaReader._schemaStack.Add(schema); JSchema parent = schema; object current = schema; for (int i = 1; i != parts.Length; ++i) { string unescapedPart = UnescapeReference(parts[i]); JSchema s = current as JSchema; if (s != null) { schemaReader._schemaStack.Add(s); parent = s; current = GetCurrentFromSchema(s, unescapedPart); } else if (current is JToken) { current = GetCurrentFromToken((JToken)current, unescapedPart); } else if (current is IDictionary <string, JSchema> ) { IDictionary <string, JSchema> d = (IDictionary <string, JSchema>)current; JSchema temp; d.TryGetValue(unescapedPart, out temp); current = temp; } else if (current is IList <JSchema> ) { IList <JSchema> l = (IList <JSchema>)current; int index; // if the schema collection is items then implicitly get first item if there is no position validation if (ReferenceEquals(parent._items, l) && !parent.ItemsPositionValidation) { if (l.Count > 0) { current = GetCurrentFromSchema(l[0], unescapedPart); } else { current = null; } } else if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index)) { if (index > l.Count || index < 0) { current = null; } else { current = l[index]; } } else { current = null; } } else { break; } } JToken t = current as JToken; if (t != null) { JSchemaAnnotation annotation = t.Annotation <JSchemaAnnotation>(); if (annotation != null) { setSchema(annotation.Schema); resolvedSchema = true; } else { JSchema inlineSchema = schemaReader.ReadInlineSchema(setSchema, t); string path = reference.OriginalString; if (path.StartsWith("#/", StringComparison.Ordinal)) { path = path.Substring(2, path.Length - 2); } discovery.Discover(inlineSchema, rootSchemaId, path); resolvedSchema = true; } } else { JSchema s = current as JSchema; if (s != null) { setSchema(s); resolvedSchema = true; // schema is a reference schema and needs to be resolved if (s.Reference != null) { schemaReader.AddDeferedSchema(null, setSchema, s); } } else { resolvedSchema = false; } } schemaReader._schemaStack.Clear(); } else { discovery.Discover(schema, null); Uri resolvedReference = ResolveSchemaId(rootSchemaId, reference); // use firstordefault to handle duplicates KnownSchema knownSchema = discovery.KnownSchemas.FirstOrDefault(s => UriComparer.Instance.Equals(s.Id, resolvedReference)); if (knownSchema != null) { resolvedSchema = true; setSchema(knownSchema.Schema); } else { int hashIndex = resolvedReference.OriginalString.IndexOf('#'); if (hashIndex != -1) { Uri path = new Uri(resolvedReference.OriginalString.Substring(0, hashIndex), UriKind.RelativeOrAbsolute); Uri fragment = new Uri(resolvedReference.OriginalString.Substring(hashIndex), UriKind.RelativeOrAbsolute); // there could be duplicated ids. use FirstOrDefault to get first schema with an id knownSchema = discovery.KnownSchemas.FirstOrDefault(s => UriComparer.Instance.Equals(s.Id, path)); if (knownSchema != null) { // don't attempt to find a schema in the same schema again // avoids stackoverflow if (knownSchema.Schema != schema || !UriComparer.Instance.Equals(rootSchemaId, path) || !UriComparer.Instance.Equals(reference, fragment)) { resolvedSchema = FindSchema(setSchema, knownSchema.Schema, path, fragment, schemaReader, ref discovery); } else { resolvedSchema = false; } } else { resolvedSchema = false; } } else { // special case // look in the root schema's definitions for a definition with the same property name and id as reference JToken definitions; if (schema.ExtensionData.TryGetValue(Constants.PropertyNames.Definitions, out definitions)) { JObject definitionsObject = definitions as JObject; if (definitionsObject != null) { JProperty matchingProperty = definitionsObject.Properties().FirstOrDefault(p => TryCompare(p.Name, resolvedReference)); JObject o = matchingProperty?.Value as JObject; if (o != null && TryCompare((string)o["id"], resolvedReference)) { JSchema inlineSchema = schemaReader.ReadInlineSchema(setSchema, o); discovery.Discover(inlineSchema, rootSchemaId, Constants.PropertyNames.Definitions + "/" + resolvedReference.OriginalString); resolvedSchema = true; } else { resolvedSchema = false; } } else { resolvedSchema = false; } } else { resolvedSchema = false; } } } } return(resolvedSchema); }