Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 :
7 : #ifndef nsXULTemplateQueryProcessorRDF_h__
8 : #define nsXULTemplateQueryProcessorRDF_h__
9 :
10 : #include "nsIRDFContainer.h"
11 : #include "nsIRDFContainerUtils.h"
12 : #include "nsIRDFDataSource.h"
13 : #include "nsIRDFObserver.h"
14 : #include "nsIRDFService.h"
15 : #include "nsIXULTemplateBuilder.h"
16 : #include "nsIXULTemplateQueryProcessor.h"
17 : #include "nsCollationCID.h"
18 :
19 : #include "nsResourceSet.h"
20 : #include "nsRuleNetwork.h"
21 : #include "nsRDFQuery.h"
22 : #include "nsRDFBinding.h"
23 : #include "nsXULTemplateResultSetRDF.h"
24 : #include "nsCOMArray.h"
25 : #include "nsString.h"
26 : #include "nsClassHashtable.h"
27 : #include "nsRefPtrHashtable.h"
28 : #include "nsCycleCollectionParticipant.h"
29 : #include "mozilla/Attributes.h"
30 :
31 : #include "mozilla/Logging.h"
32 : extern mozilla::LazyLogModule gXULTemplateLog;
33 :
34 : class nsIContent;
35 : class nsXULTemplateResultRDF;
36 :
37 : /**
38 : * An object that generates results from a query on an RDF graph
39 : */
40 : class nsXULTemplateQueryProcessorRDF final : public nsIXULTemplateQueryProcessor,
41 : public nsIRDFObserver
42 : {
43 : public:
44 : typedef nsTArray<RefPtr<nsXULTemplateResultRDF> > ResultArray;
45 :
46 : nsXULTemplateQueryProcessorRDF();
47 :
48 : nsresult InitGlobals();
49 :
50 : // nsISupports interface
51 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
52 0 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateQueryProcessorRDF,
53 : nsIXULTemplateQueryProcessor)
54 :
55 : // nsIXULTemplateQueryProcessor interface
56 : NS_DECL_NSIXULTEMPLATEQUERYPROCESSOR
57 :
58 : // nsIRDFObserver interface
59 : NS_DECL_NSIRDFOBSERVER
60 :
61 : /*
62 : * Propagate all changes through the rule network when an assertion is
63 : * added to the graph, adding any new results.
64 : */
65 : nsresult
66 : Propagate(nsIRDFResource* aSource,
67 : nsIRDFResource* aProperty,
68 : nsIRDFNode* aTarget);
69 :
70 : /*
71 : * Retract all changes through the rule network when an assertion is
72 : * removed from the graph, removing any results that no longer match.
73 : */
74 : nsresult
75 : Retract(nsIRDFResource* aSource,
76 : nsIRDFResource* aProperty,
77 : nsIRDFNode* aTarget);
78 :
79 : /*
80 : * Synchronize results when the graph changes, updating their bindings.
81 : */
82 : nsresult
83 : SynchronizeAll(nsIRDFResource* aSource,
84 : nsIRDFResource* aProperty,
85 : nsIRDFNode* aOldTarget,
86 : nsIRDFNode* aNewTarget);
87 :
88 : /*
89 : * Return true if a resource is a container
90 : */
91 : nsresult
92 : CheckContainer(nsIRDFResource* aTargetResource,
93 : bool* aIsContainer);
94 :
95 : /*
96 : * Check if a resource does not have any children
97 : */
98 : nsresult
99 : CheckEmpty(nsIRDFResource* aTargetResource,
100 : bool* aIsEmpty);
101 :
102 : /**
103 : * Check if a resource is a separator
104 : */
105 : nsresult
106 : CheckIsSeparator(nsIRDFResource* aResource, bool* aIsSeparator);
107 :
108 : /*
109 : * Compute the containment properties which are additional arcs which
110 : * indicate that a node is a container, in additional to the RDF container
111 : * tests. The computed list is stored in mContainmentProperties
112 : */
113 : nsresult
114 : ComputeContainmentProperties(nsIDOMNode* aRootNode);
115 :
116 : /**
117 : * Compile a query that uses the extended template syntax. The last
118 : * compiled node of the query is returned as aLastNode. This node will
119 : * have been added to mAllTests which owns the node.
120 : */
121 : nsresult
122 : CompileExtendedQuery(nsRDFQuery* aQuery,
123 : nsIContent* aConditions,
124 : TestNode** aLastNode);
125 :
126 : /**
127 : * Compile a single query child and return the compiled node in aResult.
128 : * This node will have been added to mAllTests which owns the node and
129 : * set as a child of aParentNode.
130 : */
131 : virtual nsresult
132 : CompileQueryChild(nsIAtom* aTag,
133 : nsRDFQuery* aQuery,
134 : nsIContent* aConditions,
135 : TestNode* aParentNode,
136 : TestNode** aResult);
137 :
138 : /**
139 : * Parse the value of a property test assertion for a condition or a simple
140 : * rule based on the parseType attribute into the appropriate literal type.
141 : */
142 : nsresult ParseLiteral(const nsString& aParseType,
143 : const nsString& aValue,
144 : nsIRDFNode** aResult);
145 :
146 : /**
147 : * Compile a <triple> condition and return the compiled node in aResult.
148 : * This node will have been added to mAllTests which owns the node and
149 : * set as a child of aParentNode.
150 : */
151 : nsresult
152 : CompileTripleCondition(nsRDFQuery* aQuery,
153 : nsIContent* aCondition,
154 : TestNode* aParentNode,
155 : TestNode** aResult);
156 :
157 : /**
158 : * Compile a <member> condition and return the compiled node in aResult.
159 : * This node will have been added to mAllTests which owns the node and
160 : * set as a child of aParentNode.
161 : */
162 : nsresult
163 : CompileMemberCondition(nsRDFQuery* aQuery,
164 : nsIContent* aCondition,
165 : TestNode* aParentNode,
166 : TestNode** aResult);
167 :
168 : /**
169 : * Add the default rules shared by all simple queries. This creates
170 : * the content start node followed by a member test. The member TestNode
171 : * is returned in aChildNode. Both nodes will have been added to mAllTests
172 : * which owns the nodes.
173 : */
174 : nsresult
175 : AddDefaultSimpleRules(nsRDFQuery* aQuery,
176 : TestNode** aChildNode);
177 :
178 : /**
179 : * Compile a query that's specified using the simple template
180 : * syntax. Each TestNode is created in a chain, the last compiled node
181 : * is returned as aLastNode. All nodes will have been added to mAllTests
182 : * which owns the nodes.
183 : */
184 : nsresult
185 : CompileSimpleQuery(nsRDFQuery* aQuery,
186 : nsIContent* aQueryElement,
187 : TestNode** aLastNode);
188 :
189 : RDFBindingSet*
190 : GetBindingsForRule(nsIDOMNode* aRule);
191 :
192 : /*
193 : * Indicate that a result is dependant on a particular resource. When an
194 : * assertion is added to or removed from the graph involving that
195 : * resource, that result must be recalculated.
196 : */
197 : void
198 : AddBindingDependency(nsXULTemplateResultRDF* aResult,
199 : nsIRDFResource* aResource);
200 :
201 : /**
202 : * Remove a dependency a result has on a particular resource.
203 : */
204 : void
205 : RemoveBindingDependency(nsXULTemplateResultRDF* aResult,
206 : nsIRDFResource* aResource);
207 :
208 : /**
209 : * A memory element is a hash of an RDF triple. One exists for each triple
210 : * that was involved in generating a result. This function adds this to a
211 : * map, keyed by memory element, when the value is a list of results that
212 : * depend on that memory element. When an RDF triple is removed from the
213 : * datasource, RetractElement is called, and this map is examined to
214 : * determine which results are no longer valid.
215 : */
216 : nsresult
217 : AddMemoryElements(const Instantiation& aInst,
218 : nsXULTemplateResultRDF* aResult);
219 :
220 : /**
221 : * Remove the memory elements associated with a result when the result is
222 : * no longer being used.
223 : */
224 : nsresult
225 : RemoveMemoryElements(const Instantiation& aInst,
226 : nsXULTemplateResultRDF* aResult);
227 :
228 : /**
229 : * Remove the results associated with a memory element since the
230 : * RDF triple the memory element is a hash of has been removed.
231 : */
232 : void RetractElement(const MemoryElement& aMemoryElement);
233 :
234 : /**
235 : * Return the index of a result's resource in its RDF container
236 : */
237 : int32_t
238 : GetContainerIndexOf(nsIXULTemplateResult* aResult);
239 :
240 : /**
241 : * Given a result and a predicate to sort on, get the target value of
242 : * the triple to use for sorting. The sort predicate is the predicate
243 : * with '?sort=true' appended.
244 : */
245 : nsresult
246 : GetSortValue(nsIXULTemplateResult* aResult,
247 : nsIRDFResource* aPredicate,
248 : nsIRDFResource* aSortPredicate,
249 : nsISupports** aResultNode);
250 :
251 0 : nsIRDFDataSource* GetDataSource() { return mDB; }
252 :
253 0 : nsIXULTemplateBuilder* GetBuilder() { return mBuilder; }
254 :
255 0 : nsResourceSet& ContainmentProperties() { return mContainmentProperties; }
256 :
257 : nsresult
258 : Log(const char* aOperation,
259 : nsIRDFResource* aSource,
260 : nsIRDFResource* aProperty,
261 : nsIRDFNode* aTarget);
262 :
263 : #define LOG(_op, _src, _prop, _targ) \
264 : Log(_op, _src, _prop, _targ)
265 :
266 : protected:
267 : ~nsXULTemplateQueryProcessorRDF();
268 :
269 : // We are an observer of the composite datasource. The cycle is
270 : // broken when the document is destroyed.
271 : nsCOMPtr<nsIRDFDataSource> mDB;
272 :
273 : // weak reference to the builder, cleared when the document is destroyed
274 : nsIXULTemplateBuilder* mBuilder;
275 :
276 : // true if the query processor has been initialized
277 : bool mQueryProcessorRDFInited;
278 :
279 : // true if results have been generated. Once set, bindings can no longer
280 : // be added. If they were, the binding value arrays for results that have
281 : // already been generated would be the wrong size
282 : bool mGenerationStarted;
283 :
284 : // nesting level for RDF batch notifications
285 : int32_t mUpdateBatchNest;
286 :
287 : // containment properties that are checked to determine if a resource is
288 : // a container
289 : nsResourceSet mContainmentProperties;
290 :
291 : // the end node of the default simple node hierarchy
292 : TestNode* mSimpleRuleMemberTest;
293 :
294 : // the reference variable
295 : nsCOMPtr<nsIAtom> mRefVariable;
296 :
297 : // the last ref that was calculated, used for simple rules
298 : nsCOMPtr<nsIXULTemplateResult> mLastRef;
299 :
300 : /**
301 : * A map between nsIRDFNodes that form the left-hand side (the subject) of
302 : * a <binding> and an array of nsIXULTemplateResults. When a new assertion
303 : * is added to the graph involving a particular rdf node, it is looked up
304 : * in this binding map. If it exists, the corresponding results must then
305 : * be synchronized.
306 : */
307 : nsClassHashtable<nsISupportsHashKey, ResultArray> mBindingDependencies;
308 :
309 : /**
310 : * A map between memory elements and an array of nsIXULTemplateResults.
311 : * When a triple is unasserted from the graph, the corresponding results
312 : * no longer match so they must be removed.
313 : */
314 : nsClassHashtable<nsUint32HashKey,
315 : nsCOMArray<nsXULTemplateResultRDF> > mMemoryElementToResultMap;
316 :
317 : // map of the rules to the bindings for those rules.
318 : // XXXndeakin this might be better just as an array since there is usually
319 : // ten or fewer rules
320 : nsRefPtrHashtable<nsISupportsHashKey, RDFBindingSet> mRuleToBindingsMap;
321 :
322 : /**
323 : * The queries
324 : */
325 : nsTArray<nsCOMPtr<nsITemplateRDFQuery> > mQueries;
326 :
327 : /**
328 : * All of the RDF tests in the rule network, which are checked when a new
329 : * assertion is added to the graph. This is a subset of mAllTests, which
330 : * also includes non-RDF tests.
331 : */
332 : ReteNodeSet mRDFTests;
333 :
334 : /**
335 : * All of the tests in the rule network, owned by this list
336 : */
337 : ReteNodeSet mAllTests;
338 :
339 : // pseudo-constants
340 : static nsrefcnt gRefCnt;
341 :
342 : public:
343 : static nsIRDFService* gRDFService;
344 : static nsIRDFContainerUtils* gRDFContainerUtils;
345 : static nsIRDFResource* kNC_BookmarkSeparator;
346 : static nsIRDFResource* kRDF_type;
347 : };
348 :
349 : #endif // nsXULTemplateQueryProcessorRDF_h__
|