Enable Enterprise enrollment on desktop builds.
[chromium-blink-merge.git] / chrome / browser / extensions / api / declarative / declarative_rule.h
blobb06ae7004eca48dc190a61cafb20a18592d2b422
1 // Copyright (c) 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 // DeclarativeRule<>, DeclarativeConditionSet<>, and DeclarativeActionSet<>
6 // templates usable with multiple different declarativeFoo systems. These are
7 // templated on the Condition and Action types that define the behavior of a
8 // particular declarative event.
10 #ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DECLARATIVE_RULE_H__
11 #define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DECLARATIVE_RULE_H__
13 #include <limits>
14 #include <set>
15 #include <string>
16 #include <vector>
18 #include "base/callback.h"
19 #include "base/memory/linked_ptr.h"
20 #include "base/memory/scoped_vector.h"
21 #include "base/stl_util.h"
22 #include "base/time/time.h"
23 #include "chrome/common/extensions/api/events.h"
24 #include "components/url_matcher/url_matcher.h"
25 #include "extensions/common/extension.h"
27 namespace base {
28 class Time;
29 class Value;
32 namespace extensions {
34 // This class stores a set of conditions that may be part of a DeclarativeRule.
35 // If any condition is fulfilled, the Actions of the DeclarativeRule can be
36 // triggered.
38 // ConditionT should be immutable after creation. It must define the following
39 // members:
41 // // Arguments passed through from DeclarativeConditionSet::Create.
42 // static scoped_ptr<ConditionT> Create(
43 // const Extension* extension,
44 // URLMatcherConditionFactory* url_matcher_condition_factory,
45 // // Except this argument gets elements of the AnyVector.
46 // const base::Value& definition,
47 // std::string* error);
48 // // If the Condition needs to be filtered by some URLMatcherConditionSets,
49 // // append them to |condition_sets|.
50 // // DeclarativeConditionSet::GetURLMatcherConditionSets forwards here.
51 // void GetURLMatcherConditionSets(
52 // URLMatcherConditionSet::Vector* condition_sets);
53 // // |match_data| passed through from DeclarativeConditionSet::IsFulfilled.
54 // bool IsFulfilled(const ConditionT::MatchData& match_data);
55 template<typename ConditionT>
56 class DeclarativeConditionSet {
57 public:
58 typedef std::vector<linked_ptr<base::Value> > AnyVector;
59 typedef std::vector<linked_ptr<const ConditionT> > Conditions;
60 typedef typename Conditions::const_iterator const_iterator;
62 // Factory method that creates a DeclarativeConditionSet for |extension|
63 // according to the JSON array |conditions| passed by the extension API. Sets
64 // |error| and returns NULL in case of an error.
65 static scoped_ptr<DeclarativeConditionSet> Create(
66 const Extension* extension,
67 url_matcher::URLMatcherConditionFactory* url_matcher_condition_factory,
68 const AnyVector& conditions,
69 std::string* error);
71 const Conditions& conditions() const {
72 return conditions_;
75 const_iterator begin() const { return conditions_.begin(); }
76 const_iterator end() const { return conditions_.end(); }
78 // If |url_match_trigger| is not -1, this function looks for a condition
79 // with this URLMatcherConditionSet, and forwards to that condition's
80 // IsFulfilled(|match_data|). If there is no such condition, then false is
81 // returned. If |url_match_trigger| is -1, this function returns whether any
82 // of the conditions without URL attributes is satisfied.
83 bool IsFulfilled(url_matcher::URLMatcherConditionSet::ID url_match_trigger,
84 const typename ConditionT::MatchData& match_data) const;
86 // Appends the URLMatcherConditionSet from all conditions to |condition_sets|.
87 void GetURLMatcherConditionSets(
88 url_matcher::URLMatcherConditionSet::Vector* condition_sets) const;
90 // Returns whether there are some conditions without UrlFilter attributes.
91 bool HasConditionsWithoutUrls() const {
92 return !conditions_without_urls_.empty();
95 private:
96 typedef std::map<url_matcher::URLMatcherConditionSet::ID, const ConditionT*>
97 URLMatcherIdToCondition;
99 DeclarativeConditionSet(
100 const Conditions& conditions,
101 const URLMatcherIdToCondition& match_id_to_condition,
102 const std::vector<const ConditionT*>& conditions_without_urls);
104 const URLMatcherIdToCondition match_id_to_condition_;
105 const Conditions conditions_;
106 const std::vector<const ConditionT*> conditions_without_urls_;
108 DISALLOW_COPY_AND_ASSIGN(DeclarativeConditionSet);
111 // Immutable container for multiple actions.
113 // ActionT should be immutable after creation. It must define the following
114 // members:
116 // // Arguments passed through from ActionSet::Create.
117 // static scoped_ptr<ActionT> Create(
118 // const Extension* extension,
119 // // Except this argument gets elements of the AnyVector.
120 // const base::Value& definition,
121 // std::string* error, bool* bad_message);
122 // void Apply(const std::string& extension_id,
123 // const base::Time& extension_install_time,
124 // // Contains action-type-specific in/out parameters.
125 // typename ActionT::ApplyInfo* apply_info) const;
126 // // Only needed if the RulesRegistry calls DeclarativeActionSet::Revert().
127 // void Revert(const std::string& extension_id,
128 // const base::Time& extension_install_time,
129 // // Contains action-type-specific in/out parameters.
130 // typename ActionT::ApplyInfo* apply_info) const;
131 // // Return the minimum priority of rules that can be evaluated after this
132 // // action runs. A suitable default value is MIN_INT.
133 // int minimum_priority() const;
135 // TODO(battre): As DeclarativeActionSet can become the single owner of all
136 // actions, we can optimize here by making some of them singletons (e.g. Cancel
137 // actions).
138 template<typename ActionT>
139 class DeclarativeActionSet {
140 public:
141 typedef std::vector<linked_ptr<base::Value> > AnyVector;
142 typedef std::vector<scoped_refptr<const ActionT> > Actions;
144 explicit DeclarativeActionSet(const Actions& actions);
146 // Factory method that instantiates a DeclarativeActionSet for |extension|
147 // according to |actions| which represents the array of actions received from
148 // the extension API.
149 static scoped_ptr<DeclarativeActionSet> Create(const Extension* extension,
150 const AnyVector& actions,
151 std::string* error,
152 bool* bad_message);
154 // Rules call this method when their conditions are fulfilled.
155 void Apply(const std::string& extension_id,
156 const base::Time& extension_install_time,
157 typename ActionT::ApplyInfo* apply_info) const;
159 // Rules call this method when they have stateful conditions, and those
160 // conditions stop being fulfilled. Rules with event-based conditions (e.g. a
161 // network request happened) will never Revert() an action.
162 void Revert(const std::string& extension_id,
163 const base::Time& extension_install_time,
164 typename ActionT::ApplyInfo* apply_info) const;
166 // Returns the minimum priority of rules that may be evaluated after
167 // this rule. Defaults to MIN_INT.
168 int GetMinimumPriority() const;
170 const Actions& actions() const { return actions_; }
172 private:
173 const Actions actions_;
175 DISALLOW_COPY_AND_ASSIGN(DeclarativeActionSet);
178 // Representation of a rule of a declarative API:
179 // https://developer.chrome.com/beta/extensions/events.html#declarative.
180 // Generally a RulesRegistry will hold a collection of Rules for a given
181 // declarative API and contain the logic for matching and applying them.
183 // See DeclarativeConditionSet and DeclarativeActionSet for the requirements on
184 // ConditionT and ActionT.
185 template<typename ConditionT, typename ActionT>
186 class DeclarativeRule {
187 public:
188 typedef std::string ExtensionId;
189 typedef std::string RuleId;
190 typedef std::pair<ExtensionId, RuleId> GlobalRuleId;
191 typedef int Priority;
192 typedef DeclarativeConditionSet<ConditionT> ConditionSet;
193 typedef DeclarativeActionSet<ActionT> ActionSet;
194 typedef extensions::api::events::Rule JsonRule;
195 typedef std::vector<std::string> Tags;
197 // Checks whether the set of |conditions| and |actions| are consistent.
198 // Returns true in case of consistency and MUST set |error| otherwise.
199 typedef base::Callback<bool(const ConditionSet* conditions,
200 const ActionSet* actions,
201 std::string* error)> ConsistencyChecker;
203 DeclarativeRule(const GlobalRuleId& id,
204 const Tags& tags,
205 base::Time extension_installation_time,
206 scoped_ptr<ConditionSet> conditions,
207 scoped_ptr<ActionSet> actions,
208 Priority priority);
210 // Creates a DeclarativeRule for |extension| given a json definition. The
211 // format of each condition and action's json is up to the specific ConditionT
212 // and ActionT. |extension| may be NULL in tests.
214 // Before constructing the final rule, calls check_consistency(conditions,
215 // actions, error) and returns NULL if it fails. Pass NULL if no consistency
216 // check is needed. If |error| is empty, the translation was successful and
217 // the returned rule is internally consistent.
218 static scoped_ptr<DeclarativeRule> Create(
219 url_matcher::URLMatcherConditionFactory* url_matcher_condition_factory,
220 const Extension* extension,
221 base::Time extension_installation_time,
222 linked_ptr<JsonRule> rule,
223 ConsistencyChecker check_consistency,
224 std::string* error);
226 const GlobalRuleId& id() const { return id_; }
227 const Tags& tags() const { return tags_; }
228 const std::string& extension_id() const { return id_.first; }
229 const ConditionSet& conditions() const { return *conditions_; }
230 const ActionSet& actions() const { return *actions_; }
231 Priority priority() const { return priority_; }
233 // Calls actions().Apply(extension_id(), extension_installation_time_,
234 // apply_info). This function should only be called when the conditions_ are
235 // fulfilled (from a semantic point of view; no harm is done if this function
236 // is called at other times for testing purposes).
237 void Apply(typename ActionT::ApplyInfo* apply_info) const;
239 // Returns the minimum priority of rules that may be evaluated after
240 // this rule. Defaults to MIN_INT. Only valid if the conditions of this rule
241 // are fulfilled.
242 Priority GetMinimumPriority() const;
244 private:
245 GlobalRuleId id_;
246 Tags tags_;
247 base::Time extension_installation_time_; // For precedences of rules.
248 scoped_ptr<ConditionSet> conditions_;
249 scoped_ptr<ActionSet> actions_;
250 Priority priority_;
252 DISALLOW_COPY_AND_ASSIGN(DeclarativeRule);
255 // Implementation details below here.
258 // DeclarativeConditionSet
261 template<typename ConditionT>
262 bool DeclarativeConditionSet<ConditionT>::IsFulfilled(
263 url_matcher::URLMatcherConditionSet::ID url_match_trigger,
264 const typename ConditionT::MatchData& match_data) const {
265 if (url_match_trigger == -1) {
266 // Invalid trigger -- indication that we should only check conditions
267 // without URL attributes.
268 for (typename std::vector<const ConditionT*>::const_iterator it =
269 conditions_without_urls_.begin();
270 it != conditions_without_urls_.end(); ++it) {
271 if ((*it)->IsFulfilled(match_data))
272 return true;
274 return false;
277 typename URLMatcherIdToCondition::const_iterator triggered =
278 match_id_to_condition_.find(url_match_trigger);
279 return (triggered != match_id_to_condition_.end() &&
280 triggered->second->IsFulfilled(match_data));
283 template<typename ConditionT>
284 void DeclarativeConditionSet<ConditionT>::GetURLMatcherConditionSets(
285 url_matcher::URLMatcherConditionSet::Vector* condition_sets) const {
286 for (typename Conditions::const_iterator i = conditions_.begin();
287 i != conditions_.end(); ++i) {
288 (*i)->GetURLMatcherConditionSets(condition_sets);
292 // static
293 template<typename ConditionT>
294 scoped_ptr<DeclarativeConditionSet<ConditionT> >
295 DeclarativeConditionSet<ConditionT>::Create(
296 const Extension* extension,
297 url_matcher::URLMatcherConditionFactory* url_matcher_condition_factory,
298 const AnyVector& conditions,
299 std::string* error) {
300 Conditions result;
302 for (AnyVector::const_iterator i = conditions.begin();
303 i != conditions.end(); ++i) {
304 CHECK(i->get());
305 scoped_ptr<ConditionT> condition = ConditionT::Create(
306 extension, url_matcher_condition_factory, **i, error);
307 if (!error->empty())
308 return scoped_ptr<DeclarativeConditionSet>();
309 result.push_back(make_linked_ptr(condition.release()));
312 URLMatcherIdToCondition match_id_to_condition;
313 std::vector<const ConditionT*> conditions_without_urls;
314 url_matcher::URLMatcherConditionSet::Vector condition_sets;
316 for (typename Conditions::const_iterator i = result.begin();
317 i != result.end(); ++i) {
318 condition_sets.clear();
319 (*i)->GetURLMatcherConditionSets(&condition_sets);
320 if (condition_sets.empty()) {
321 conditions_without_urls.push_back(i->get());
322 } else {
323 for (url_matcher::URLMatcherConditionSet::Vector::const_iterator
324 match_set = condition_sets.begin();
325 match_set != condition_sets.end(); ++match_set)
326 match_id_to_condition[(*match_set)->id()] = i->get();
330 return make_scoped_ptr(new DeclarativeConditionSet(
331 result, match_id_to_condition, conditions_without_urls));
334 template<typename ConditionT>
335 DeclarativeConditionSet<ConditionT>::DeclarativeConditionSet(
336 const Conditions& conditions,
337 const URLMatcherIdToCondition& match_id_to_condition,
338 const std::vector<const ConditionT*>& conditions_without_urls)
339 : match_id_to_condition_(match_id_to_condition),
340 conditions_(conditions),
341 conditions_without_urls_(conditions_without_urls) {}
344 // DeclarativeActionSet
347 template<typename ActionT>
348 DeclarativeActionSet<ActionT>::DeclarativeActionSet(const Actions& actions)
349 : actions_(actions) {}
351 // static
352 template<typename ActionT>
353 scoped_ptr<DeclarativeActionSet<ActionT> >
354 DeclarativeActionSet<ActionT>::Create(
355 const Extension* extension,
356 const AnyVector& actions,
357 std::string* error,
358 bool* bad_message) {
359 *error = "";
360 *bad_message = false;
361 Actions result;
363 for (AnyVector::const_iterator i = actions.begin();
364 i != actions.end(); ++i) {
365 CHECK(i->get());
366 scoped_refptr<const ActionT> action =
367 ActionT::Create(extension, **i, error, bad_message);
368 if (!error->empty() || *bad_message)
369 return scoped_ptr<DeclarativeActionSet>();
370 result.push_back(action);
373 return scoped_ptr<DeclarativeActionSet>(new DeclarativeActionSet(result));
376 template<typename ActionT>
377 void DeclarativeActionSet<ActionT>::Apply(
378 const std::string& extension_id,
379 const base::Time& extension_install_time,
380 typename ActionT::ApplyInfo* apply_info) const {
381 for (typename Actions::const_iterator i = actions_.begin();
382 i != actions_.end(); ++i)
383 (*i)->Apply(extension_id, extension_install_time, apply_info);
386 template<typename ActionT>
387 void DeclarativeActionSet<ActionT>::Revert(
388 const std::string& extension_id,
389 const base::Time& extension_install_time,
390 typename ActionT::ApplyInfo* apply_info) const {
391 for (typename Actions::const_iterator i = actions_.begin();
392 i != actions_.end(); ++i)
393 (*i)->Revert(extension_id, extension_install_time, apply_info);
396 template<typename ActionT>
397 int DeclarativeActionSet<ActionT>::GetMinimumPriority() const {
398 int minimum_priority = std::numeric_limits<int>::min();
399 for (typename Actions::const_iterator i = actions_.begin();
400 i != actions_.end(); ++i) {
401 minimum_priority = std::max(minimum_priority, (*i)->minimum_priority());
403 return minimum_priority;
407 // DeclarativeRule
410 template<typename ConditionT, typename ActionT>
411 DeclarativeRule<ConditionT, ActionT>::DeclarativeRule(
412 const GlobalRuleId& id,
413 const Tags& tags,
414 base::Time extension_installation_time,
415 scoped_ptr<ConditionSet> conditions,
416 scoped_ptr<ActionSet> actions,
417 Priority priority)
418 : id_(id),
419 tags_(tags),
420 extension_installation_time_(extension_installation_time),
421 conditions_(conditions.release()),
422 actions_(actions.release()),
423 priority_(priority) {
424 CHECK(conditions_.get());
425 CHECK(actions_.get());
428 // static
429 template<typename ConditionT, typename ActionT>
430 scoped_ptr<DeclarativeRule<ConditionT, ActionT> >
431 DeclarativeRule<ConditionT, ActionT>::Create(
432 url_matcher::URLMatcherConditionFactory* url_matcher_condition_factory,
433 const Extension* extension,
434 base::Time extension_installation_time,
435 linked_ptr<JsonRule> rule,
436 ConsistencyChecker check_consistency,
437 std::string* error) {
438 scoped_ptr<DeclarativeRule> error_result;
440 scoped_ptr<ConditionSet> conditions = ConditionSet::Create(
441 extension, url_matcher_condition_factory, rule->conditions, error);
442 if (!error->empty())
443 return error_result.Pass();
444 CHECK(conditions.get());
446 bool bad_message = false;
447 scoped_ptr<ActionSet> actions =
448 ActionSet::Create(extension, rule->actions, error, &bad_message);
449 if (bad_message) {
450 // TODO(battre) Export concept of bad_message to caller, the extension
451 // should be killed in case it is true.
452 *error = "An action of a rule set had an invalid "
453 "structure that should have been caught by the JSON validator.";
454 return error_result.Pass();
456 if (!error->empty() || bad_message)
457 return error_result.Pass();
458 CHECK(actions.get());
460 if (!check_consistency.is_null() &&
461 !check_consistency.Run(conditions.get(), actions.get(), error)) {
462 DCHECK(!error->empty());
463 return error_result.Pass();
466 CHECK(rule->priority.get());
467 int priority = *(rule->priority);
469 GlobalRuleId rule_id(extension->id(), *(rule->id));
470 Tags tags = rule->tags ? *rule->tags : Tags();
471 return scoped_ptr<DeclarativeRule>(
472 new DeclarativeRule(rule_id, tags, extension_installation_time,
473 conditions.Pass(), actions.Pass(), priority));
476 template<typename ConditionT, typename ActionT>
477 void DeclarativeRule<ConditionT, ActionT>::Apply(
478 typename ActionT::ApplyInfo* apply_info) const {
479 return actions_->Apply(extension_id(),
480 extension_installation_time_,
481 apply_info);
484 template<typename ConditionT, typename ActionT>
485 int DeclarativeRule<ConditionT, ActionT>::GetMinimumPriority() const {
486 return actions_->GetMinimumPriority();
489 } // namespace extensions
491 #endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DECLARATIVE_RULE_H__