Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Side by Side Diff: components/policy/core/common/schema.cc

Issue 23851022: Added new policy Schema classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: POLICY_EXPORT for Schema::Iterator Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/policy/core/common/schema.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "base/compiler_specific.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_vector.h"
13 #include "components/json_schema/json_schema_constants.h"
14 #include "components/json_schema/json_schema_validator.h"
15 #include "components/policy/core/common/schema_internal.h"
16
17 namespace policy {
18
19 namespace schema {
20
21 namespace {
22
23 const char kJSONSchemaVersion[] = "http://json-schema.org/draft-03/schema#";
24
25 class PolicySchemaImpl : public PolicySchema {
Mattias Nissler (ping if slow) 2013/09/13 12:56:48 If PolicySchema has only one implementation, why m
Joao da Silva 2013/09/13 14:02:54 Right. There were 2 implementations but in the end
26 public:
27 explicit PolicySchemaImpl(const internal::SchemaNode* root)
28 : root_(root) {}
29
30 virtual ~PolicySchemaImpl();
31
32 static scoped_ptr<PolicySchema> Parse(const std::string& schema,
33 std::string* error);
34
35 virtual Schema schema() const OVERRIDE {
36 return Schema(root_);
37 }
38
39 private:
40 PolicySchemaImpl() : root_(NULL) {}
41
42 const internal::SchemaNode* Parse(const base::DictionaryValue& schema,
43 std::string* error);
44 const internal::SchemaNode* ParseDictionary(
45 const base::DictionaryValue& schema,
46 std::string* error);
47 const internal::SchemaNode* ParseList(const base::DictionaryValue& schema,
48 std::string* error);
49
50 const internal::SchemaNode* root_;
51 ScopedVector<internal::SchemaNode> schema_nodes_;
52 // Note: |property_nodes_| contains PropertyNode[] and must be cleared
53 // manually to properly use delete[].
54 std::vector<internal::PropertyNode*> property_nodes_;
55 ScopedVector<internal::PropertiesNode> properties_nodes_;
56 ScopedVector<std::string> keys_;
57
58 DISALLOW_COPY_AND_ASSIGN(PolicySchemaImpl);
59 };
60
61 bool SchemaTypeToValueType(const std::string& type_string,
62 base::Value::Type* type) {
63 // Note: "any" is not an accepted type.
64 static const struct {
65 const char* schema_type;
66 base::Value::Type value_type;
67 } kSchemaToValueTypeMap[] = {
68 { json_schema_constants::kArray, base::Value::TYPE_LIST },
69 { json_schema_constants::kBoolean, base::Value::TYPE_BOOLEAN },
70 { json_schema_constants::kInteger, base::Value::TYPE_INTEGER },
71 { json_schema_constants::kNull, base::Value::TYPE_NULL },
72 { json_schema_constants::kNumber, base::Value::TYPE_DOUBLE },
73 { json_schema_constants::kObject, base::Value::TYPE_DICTIONARY },
74 { json_schema_constants::kString, base::Value::TYPE_STRING },
75 };
76 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) {
77 if (kSchemaToValueTypeMap[i].schema_type == type_string) {
78 *type = kSchemaToValueTypeMap[i].value_type;
79 return true;
80 }
81 }
82 return false;
83 }
84
85 PolicySchemaImpl::~PolicySchemaImpl() {
86 for (size_t i = 0; i < property_nodes_.size(); ++i)
87 delete[] property_nodes_[i];
88 }
89
90 // static
91 scoped_ptr<PolicySchema> PolicySchemaImpl::Parse(const std::string& content,
92 std::string* error) {
93 // Validate as a generic JSON schema.
94 scoped_ptr<base::DictionaryValue> dict =
95 JSONSchemaValidator::IsValidSchema(content, error);
96 if (!dict)
97 return scoped_ptr<PolicySchema>();
98
99 // Validate the schema version.
Mattias Nissler (ping if slow) 2013/09/13 12:56:48 That means we can never migrate to newer schema ve
Joao da Silva 2013/09/13 14:02:54 What can we possibly do for old builds? We'll hav
Mattias Nissler (ping if slow) 2013/09/13 14:55:17 I'm worried about the fact that extension authors
Joao da Silva 2013/09/13 15:15:47 I see where you're coming from. The latest draft i
100 std::string string_value;
101 if (!dict->GetString(json_schema_constants::kSchema, &string_value) ||
102 string_value != kJSONSchemaVersion) {
103 *error = "Must declare JSON Schema v3 version in \"$schema\".";
104 return scoped_ptr<PolicySchema>();
105 }
106
107 // Validate the main type.
108 if (!dict->GetString(json_schema_constants::kType, &string_value) ||
109 string_value != json_schema_constants::kObject) {
110 *error =
111 "The main schema must have a type attribute with \"object\" value.";
112 return scoped_ptr<PolicySchema>();
113 }
114
115 // Checks for invalid attributes at the top-level.
Mattias Nissler (ping if slow) 2013/09/13 12:56:48 Any good reason? They'd just be ignored.
Joao da Silva 2013/09/13 14:02:54 So that extension authors see the error. These co
Mattias Nissler (ping if slow) 2013/09/13 14:55:17 Right, makes sense. Let's leave the check in then.
116 if (dict->HasKey(json_schema_constants::kAdditionalProperties) ||
117 dict->HasKey(json_schema_constants::kPatternProperties)) {
118 *error = "\"additionalProperties\" and \"patternProperties\" are not "
119 "supported at the main schema.";
120 return scoped_ptr<PolicySchema>();
121 }
122
123 scoped_ptr<PolicySchemaImpl> impl(new PolicySchemaImpl());
124 impl->root_ = impl->Parse(*dict, error);
125 if (!impl->root_)
126 impl.reset();
127 return impl.PassAs<PolicySchema>();
128 }
129
130 const internal::SchemaNode* PolicySchemaImpl::Parse(
131 const base::DictionaryValue& schema,
132 std::string* error) {
133 std::string type_string;
134 if (!schema.GetString(json_schema_constants::kType, &type_string)) {
135 *error = "The schema type must be declared.";
136 return NULL;
137 }
138
139 base::Value::Type type = base::Value::TYPE_NULL;
140 if (!SchemaTypeToValueType(type_string, &type)) {
141 *error = "The \"any\" type can't be used.";
Mattias Nissler (ping if slow) 2013/09/13 12:56:48 I think you should just say "Type not supported: "
Joao da Silva 2013/09/13 14:02:54 Done. The "any" type was assumed because the JSONS
142 return NULL;
143 }
144
145 if (type == base::Value::TYPE_DICTIONARY)
146 return ParseDictionary(schema, error);
147 if (type == base::Value::TYPE_LIST)
148 return ParseList(schema, error);
149
150 internal::SchemaNode* node = new internal::SchemaNode;
151 node->type = type;
152 node->extra = NULL;
153 schema_nodes_.push_back(node);
154 return node;
155 }
156
157 const internal::SchemaNode* PolicySchemaImpl::ParseDictionary(
158 const base::DictionaryValue& schema,
159 std::string* error) {
160 internal::PropertiesNode* properties_node = new internal::PropertiesNode;
161 properties_node->begin = NULL;
162 properties_node->end = NULL;
163 properties_node->additional = NULL;
164 properties_nodes_.push_back(properties_node);
165
166 const base::DictionaryValue* dict = NULL;
167 const base::DictionaryValue* properties = NULL;
168 if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) {
169 internal::PropertyNode* property_nodes =
170 new internal::PropertyNode[properties->size()];
171 property_nodes_.push_back(property_nodes);
172
173 size_t index = 0;
174 for (base::DictionaryValue::Iterator it(*properties);
175 !it.IsAtEnd(); it.Advance(), ++index) {
176 // This should have been verified by the JSONSchemaValidator.
177 CHECK(it.value().GetAsDictionary(&dict));
178 const internal::SchemaNode* sub_schema = Parse(*dict, error);
179 if (!sub_schema)
180 return NULL;
181 std::string* key = new std::string(it.key());
182 keys_.push_back(key);
183 property_nodes[index].key = key->c_str();
184 property_nodes[index].schema = sub_schema;
185 }
186 CHECK_EQ(properties->size(), index);
187 properties_node->begin = property_nodes;
188 properties_node->end = property_nodes + index;
189 }
190
191 if (schema.GetDictionary(json_schema_constants::kAdditionalProperties,
192 &dict)) {
193 const internal::SchemaNode* sub_schema = Parse(*dict, error);
194 if (!sub_schema)
195 return NULL;
196 properties_node->additional = sub_schema;
197 }
198
199 internal::SchemaNode* schema_node = new internal::SchemaNode;
200 schema_node->type = base::Value::TYPE_DICTIONARY;
201 schema_node->extra = properties_node;
202 schema_nodes_.push_back(schema_node);
203 return schema_node;
204 }
205
206 const internal::SchemaNode* PolicySchemaImpl::ParseList(
207 const base::DictionaryValue& schema,
208 std::string* error) {
209 const base::DictionaryValue* dict = NULL;
210 if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) {
211 *error = "Arrays must declare a single schema for their items.";
212 return NULL;
213 }
214 const internal::SchemaNode* items_schema_node = Parse(*dict, error);
215 if (!items_schema_node)
216 return NULL;
217
218 internal::SchemaNode* schema_node = new internal::SchemaNode;
219 schema_node->type = base::Value::TYPE_LIST;
220 schema_node->extra = items_schema_node;
221 schema_nodes_.push_back(schema_node);
222 return schema_node;
223 }
224
225 } // namespace
226
227 Schema::Iterator::Iterator(const internal::PropertiesNode* properties)
228 : it_(properties->begin),
229 end_(properties->end) {}
230
231 Schema::Iterator::Iterator(const Iterator& iterator)
232 : it_(iterator.it_),
233 end_(iterator.end_) {}
234
235 Schema::Iterator::~Iterator() {}
236
237 Schema::Iterator& Schema::Iterator::operator=(const Iterator& iterator) {
238 it_ = iterator.it_;
239 end_ = iterator.end_;
240 return *this;
241 }
242
243 bool Schema::Iterator::IsAtEnd() const {
244 return it_ == end_;
245 }
246
247 void Schema::Iterator::Advance() {
248 ++it_;
249 }
250
251 const char* Schema::Iterator::key() const {
252 return it_->key;
253 }
254
255 Schema Schema::Iterator::schema() const {
256 return Schema(it_->schema);
257 }
258
259 Schema::Schema(const internal::SchemaNode* schema) : schema_(schema) {}
260
261 Schema::Schema(const Schema& schema) : schema_(schema.schema_) {}
262
263 Schema& Schema::operator=(const Schema& schema) {
264 schema_ = schema.schema_;
265 return *this;
266 }
267
268 base::Value::Type Schema::type() const {
269 CHECK(valid());
270 return schema_->type;
271 }
272
273 Schema::Iterator Schema::GetPropertiesIterator() const {
274 CHECK(valid());
275 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
276 return Iterator(
277 static_cast<const internal::PropertiesNode*>(schema_->extra));
278 }
279
280 namespace {
281
282 bool CompareKeys(const internal::PropertyNode& node, const std::string& key) {
283 return node.key < key;
284 }
285
286 } // namespace
287
288 Schema Schema::GetKnownProperty(const std::string& key) const {
289 CHECK(valid());
290 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
291 const internal::PropertiesNode* properties_node =
292 static_cast<const internal::PropertiesNode*>(schema_->extra);
293 const internal::PropertyNode* it = std::lower_bound(
294 properties_node->begin, properties_node->end, key, CompareKeys);
295 if (it != properties_node->end && it->key == key)
296 return Schema(it->schema);
297 return Schema(NULL);
298 }
299
300 Schema Schema::GetAdditionalProperties() const {
301 CHECK(valid());
302 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
303 return Schema(
304 static_cast<const internal::PropertiesNode*>(schema_->extra)->additional);
Mattias Nissler (ping if slow) 2013/09/13 12:56:48 Hm, casts. Maybe use a union? That's still easier
Joao da Silva 2013/09/13 14:02:54 I don't mind these casts *at all* :-) I did want
Mattias Nissler (ping if slow) 2013/09/13 14:55:17 Fine to go with the cast then.
305 }
306
307 Schema Schema::GetProperty(const std::string& key) const {
308 Schema schema = GetKnownProperty(key);
309 return schema.valid() ? schema : GetAdditionalProperties();
Mattias Nissler (ping if slow) 2013/09/13 12:56:48 Shouldn't this return Schema(NULL) for the error c
Joao da Silva 2013/09/13 14:02:54 GetAdditionalProperties returns Schema(NULL) if th
Mattias Nissler (ping if slow) 2013/09/13 14:55:17 Right, sorry, I was confused.
310 }
311
312 Schema Schema::GetItems() const {
313 CHECK(valid());
314 CHECK_EQ(base::Value::TYPE_LIST, type());
315 return Schema(static_cast<const internal::SchemaNode*>(schema_->extra));
316 }
317
318 // static
319 scoped_ptr<PolicySchema> PolicySchema::Wrap(
320 const internal::SchemaNode* schema) {
321 return scoped_ptr<PolicySchema>(new PolicySchemaImpl(schema));
322 }
323
324 // static
325 scoped_ptr<PolicySchema> PolicySchema::Parse(const std::string& schema,
326 std::string* error) {
327 return PolicySchemaImpl::Parse(schema, error);
328 }
329
330 } // namespace schema
331
332 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698