summaryrefslogtreecommitdiffstats
path: root/dom/xul/templates/nsXULTemplateQueryProcessorRDF.h
blob: 30ac34d237308802bf1b2361947f38ba98492ce2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef nsXULTemplateQueryProcessorRDF_h__
#define nsXULTemplateQueryProcessorRDF_h__

#include "nsIRDFContainer.h"
#include "nsIRDFContainerUtils.h"
#include "nsIRDFDataSource.h"
#include "nsIRDFObserver.h"
#include "nsIRDFService.h"
#include "nsIXULTemplateBuilder.h"
#include "nsIXULTemplateQueryProcessor.h"
#include "nsCollationCID.h"

#include "nsResourceSet.h"
#include "nsRuleNetwork.h"
#include "nsRDFQuery.h"
#include "nsRDFBinding.h"
#include "nsXULTemplateResultSetRDF.h"
#include "nsCOMArray.h"
#include "nsString.h"
#include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"

#include "mozilla/Logging.h"
extern mozilla::LazyLogModule gXULTemplateLog;

class nsIContent;
class nsXULTemplateResultRDF;

/**
 * An object that generates results from a query on an RDF graph
 */
class nsXULTemplateQueryProcessorRDF final : public nsIXULTemplateQueryProcessor,
                                             public nsIRDFObserver
{
public:
    typedef nsTArray<RefPtr<nsXULTemplateResultRDF> > ResultArray;

    nsXULTemplateQueryProcessorRDF();

    nsresult InitGlobals();

    // nsISupports interface
    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateQueryProcessorRDF,
                                             nsIXULTemplateQueryProcessor)

    // nsIXULTemplateQueryProcessor interface
    NS_DECL_NSIXULTEMPLATEQUERYPROCESSOR
   
    // nsIRDFObserver interface
    NS_DECL_NSIRDFOBSERVER

    /*
     * Propagate all changes through the rule network when an assertion is
     * added to the graph, adding any new results.
     */
    nsresult
    Propagate(nsIRDFResource* aSource,
              nsIRDFResource* aProperty,
              nsIRDFNode* aTarget);

    /*
     * Retract all changes through the rule network when an assertion is
     * removed from the graph, removing any results that no longer match.
     */
    nsresult
    Retract(nsIRDFResource* aSource,
            nsIRDFResource* aProperty,
            nsIRDFNode* aTarget);

    /*
     * Synchronize results when the graph changes, updating their bindings.
     */
    nsresult
    SynchronizeAll(nsIRDFResource* aSource,
                   nsIRDFResource* aProperty,
                   nsIRDFNode* aOldTarget,
                   nsIRDFNode* aNewTarget);

    /*
     * Return true if a resource is a container
     */
    nsresult
    CheckContainer(nsIRDFResource* aTargetResource,
                   bool* aIsContainer);

    /*
     * Check if a resource does not have any children
     */
    nsresult
    CheckEmpty(nsIRDFResource* aTargetResource,
               bool* aIsEmpty);

    /**
     * Check if a resource is a separator
     */
    nsresult
    CheckIsSeparator(nsIRDFResource* aResource, bool* aIsSeparator);

    /*
     * Compute the containment properties which are additional arcs which
     * indicate that a node is a container, in additional to the RDF container
     * tests. The computed list is stored in mContainmentProperties
     */
    nsresult
    ComputeContainmentProperties(nsIDOMNode* aRootNode);

    /**
     * Compile a query that uses the extended template syntax. The last
     * compiled node of the query is returned as aLastNode. This node will
     * have been added to mAllTests which owns the node.
     */
    nsresult
    CompileExtendedQuery(nsRDFQuery* aQuery,
                         nsIContent* aConditions,
                         TestNode** aLastNode);

    /**
     * Compile a single query child and return the compiled node in aResult.
     * This node will have been added to mAllTests which owns the node and
     * set as a child of aParentNode.
     */
    virtual nsresult
    CompileQueryChild(nsIAtom* aTag,
                      nsRDFQuery* aQuery,
                      nsIContent* aConditions,
                      TestNode* aParentNode,
                      TestNode** aResult);

    /**
     * Parse the value of a property test assertion for a condition or a simple
     * rule based on the parseType attribute into the appropriate literal type.
     */
    nsresult ParseLiteral(const nsString& aParseType, 
                          const nsString& aValue,
                          nsIRDFNode** aResult);

    /**
     * Compile a <triple> condition and return the compiled node in aResult.
     * This node will have been added to mAllTests which owns the node and
     * set as a child of aParentNode.
     */
    nsresult
    CompileTripleCondition(nsRDFQuery* aQuery,
                           nsIContent* aCondition,
                           TestNode* aParentNode,
                           TestNode** aResult);

    /**
     * Compile a <member> condition and return the compiled node in aResult.
     * This node will have been added to mAllTests which owns the node and
     * set as a child of aParentNode.
     */
    nsresult
    CompileMemberCondition(nsRDFQuery* aQuery,
                           nsIContent* aCondition,
                           TestNode* aParentNode,
                           TestNode** aResult);

    /**
     * Add the default rules shared by all simple queries. This creates
     * the content start node followed by a member test. The member TestNode
     * is returned in aChildNode. Both nodes will have been added to mAllTests
     * which owns the nodes.
     */
    nsresult
    AddDefaultSimpleRules(nsRDFQuery* aQuery,
                          TestNode** aChildNode);

    /**
     * Compile a query that's specified using the simple template
     * syntax. Each  TestNode is created in a chain, the last compiled node
     * is returned as aLastNode. All nodes will have been added to mAllTests
     * which owns the nodes.
     */
    nsresult
    CompileSimpleQuery(nsRDFQuery* aQuery,
                      nsIContent* aQueryElement,
                      TestNode** aLastNode);

    RDFBindingSet*
    GetBindingsForRule(nsIDOMNode* aRule);

    /*
     * Indicate that a result is dependant on a particular resource. When an
     * assertion is added to or removed from the graph involving that
     * resource, that result must be recalculated.
     */
    void
    AddBindingDependency(nsXULTemplateResultRDF* aResult,
                         nsIRDFResource* aResource);

    /**
     * Remove a dependency a result has on a particular resource.
     */
    void
    RemoveBindingDependency(nsXULTemplateResultRDF* aResult,
                            nsIRDFResource* aResource);

    /**
     * A memory element is a hash of an RDF triple. One exists for each triple
     * that was involved in generating a result. This function adds this to a
     * map, keyed by memory element, when the value is a list of results that
     * depend on that memory element. When an RDF triple is removed from the
     * datasource, RetractElement is called, and this map is examined to
     * determine which results are no longer valid.
     */
    nsresult
    AddMemoryElements(const Instantiation& aInst,
                      nsXULTemplateResultRDF* aResult);

    /**
     * Remove the memory elements associated with a result when the result is
     * no longer being used.
     */
    nsresult
    RemoveMemoryElements(const Instantiation& aInst,
                         nsXULTemplateResultRDF* aResult);

    /**
     * Remove the results associated with a memory element since the
     * RDF triple the memory element is a hash of has been removed.
     */
    void RetractElement(const MemoryElement& aMemoryElement);

    /**
     * Return the index of a result's resource in its RDF container
     */
    int32_t
    GetContainerIndexOf(nsIXULTemplateResult* aResult);

    /**
     * Given a result and a predicate to sort on, get the target value of
     * the triple to use for sorting. The sort predicate is the predicate
     * with '?sort=true' appended.
     */
    nsresult
    GetSortValue(nsIXULTemplateResult* aResult,
                 nsIRDFResource* aPredicate,
                 nsIRDFResource* aSortPredicate,
                 nsISupports** aResultNode);

    nsIRDFDataSource* GetDataSource() { return mDB; }

    nsIXULTemplateBuilder* GetBuilder() { return mBuilder; }

    nsResourceSet& ContainmentProperties() { return mContainmentProperties; }

    nsresult
    Log(const char* aOperation,
        nsIRDFResource* aSource,
        nsIRDFResource* aProperty,
        nsIRDFNode* aTarget);

#define LOG(_op, _src, _prop, _targ) \
    Log(_op, _src, _prop, _targ)

protected:
    ~nsXULTemplateQueryProcessorRDF();

    // We are an observer of the composite datasource. The cycle is
    // broken when the document is destroyed.
    nsCOMPtr<nsIRDFDataSource> mDB;

    // weak reference to the builder, cleared when the document is destroyed
    nsIXULTemplateBuilder* mBuilder;

    // true if the query processor has been initialized
    bool mQueryProcessorRDFInited;

    // true if results have been generated. Once set, bindings can no longer
    // be added. If they were, the binding value arrays for results that have
    // already been generated would be the wrong size
    bool mGenerationStarted;

    // nesting level for RDF batch notifications
    int32_t mUpdateBatchNest;

    // containment properties that are checked to determine if a resource is
    // a container
    nsResourceSet mContainmentProperties;

    // the end node of the default simple node hierarchy
    TestNode* mSimpleRuleMemberTest;

    // the reference variable
    nsCOMPtr<nsIAtom> mRefVariable;

    // the last ref that was calculated, used for simple rules
    nsCOMPtr<nsIXULTemplateResult> mLastRef;

    /**
     * A map between nsIRDFNodes that form the left-hand side (the subject) of
     * a <binding> and an array of nsIXULTemplateResults. When a new assertion
     * is added to the graph involving a particular rdf node, it is looked up
     * in this binding map. If it exists, the corresponding results must then
     * be synchronized.
     */
    nsClassHashtable<nsISupportsHashKey, ResultArray> mBindingDependencies;

    /**
     * A map between memory elements and an array of nsIXULTemplateResults.
     * When a triple is unasserted from the graph, the corresponding results
     * no longer match so they must be removed.
     */
    nsClassHashtable<nsUint32HashKey,
                     nsCOMArray<nsXULTemplateResultRDF> > mMemoryElementToResultMap;

    // map of the rules to the bindings for those rules.
    // XXXndeakin this might be better just as an array since there is usually
    //            ten or fewer rules
    nsRefPtrHashtable<nsISupportsHashKey, RDFBindingSet> mRuleToBindingsMap;

    /**
     * The queries
     */
    nsTArray<nsCOMPtr<nsITemplateRDFQuery> > mQueries;

    /**
     * All of the RDF tests in the rule network, which are checked when a new
     * assertion is added to the graph. This is a subset of mAllTests, which
     * also includes non-RDF tests.
     */
    ReteNodeSet mRDFTests;

    /**
     * All of the tests in the rule network, owned by this list
     */
    ReteNodeSet mAllTests;

    // pseudo-constants
    static nsrefcnt gRefCnt;

public:
    static nsIRDFService*            gRDFService;
    static nsIRDFContainerUtils*     gRDFContainerUtils;
    static nsIRDFResource*           kNC_BookmarkSeparator;
    static nsIRDFResource*           kRDF_type;
};

#endif // nsXULTemplateQueryProcessorRDF_h__