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