RDF:Interfaces

From MozillaWiki
Jump to: navigation, search

To prevent namespace conflicts with the existing interfaces, these new interfaces use the rdfI* prefix, instead of nsI* They use interCaps naming, so that there is no confusion in JS between the old and new interfaces. They also use the subject/predicate/object terminology contained in the RDF specification, instead of source/property/target.

The RDF node and service implementations are only available on the main (UI) thread.

The enumeration methods are replaced almost entirely with visitors. A visitor uses synchronous callbacks to return results in a "snapshot" without expensive intermediate storage allocations.

Support for reading, enumerating, and manipulating rdf:_1/_2 arcs in an ordered way is added as an intrinsic part of a datasource. This has the potential to reduce codesize and increase performance dramatically throughout the tree.

rdfINode

The RDF implementations of these interfaces will support nsIClassInfo, so that JS will automatically flatten the interface. They will also support nsISecurityCheckedComponent (allowing all access, except for rdfIResourceInternal, which we may not need at all).

interface rdfINode : nsISupports
{
    boolean equals(rdfINode aOther);
    readonly unsigned long hashCode;
    /**
     * As a shortcut to QueryInterface, c++ may use these methods to obtain a weak pointer to the
     * resource or literal of this node.
     */
    [noscript, notxpcom] rdfIResource GetResource();
    [noscript, notxpcom] rdfILiteral  GetLiteral();
};

The noscript methods may be a premature optimization. The major drawback is that if we have noscript methods, COM can't proxy or remote this interface.

rdfIResource

Note: we are getting rid of resource factories, so nobody is allowed to implement RDF resources except the internal RDF service implementations.

interface rdfIResource : rdfINode
{
    readonly attribute AUTF8String value;
    readonly attribute boolean isAnonymous;
    /**
     * The numeric value of an RDF ordinal predicate (rdf:_1)
     * Throws NS_RDF_NO_VALUE if the resource is not an ordinal.
     */
    readonly attribute long ordinal;
};
/* This functionality was originally provided by resource factories, which
   are a security problem. However, I don't see why a hashtable mapping
   resources->whatever wouldn't be just as good. Can we just drop this 
   altogether?
   This will *not* be available from untrusted content. */
interface rdfIResourceInternal : rdfIResource
{
    getDelegate(in AUTF8String aKey, in nsIIDRef aIID,
                [iid_is(aIID),retval] out nsQIResult aResult);
    releaseDelegate(in AUTF8String aKey);
};

rdfIBlankNode

Blank nodes don't have URIs, but only a blank node identifier

interface rdfIResource : rdfINode
{
    readonly attribute AUTF8String identifier;
};

rdfILiteral

Literals are always obtained through the RDF service. Any script can obtain a literal.

interface rdfILiteral : rdfINode
{
    readonly attribute AString value;
    readonly attribute AUTF8String lang;
    readonly attribute rdfIResource datatype;
    boolean equalsLiteral(in rdfILiteral aOther);
};

Literals should probably expose their primitive value (dates, ints, strings) via nsIVariant. I would love to see XML literals hook up with e4x.

We need a generic mapping of more complex schema datatypes to js, probably, think about http://www.w3.org/2001/XMLSchema-datatypes#base64Binary. This should be somewhat sane for C++, too.

rdfITripleVisitor

/**
 * Interface used in RDF to enumerate triples.
 * Also used by rdfIDataSource::getAllSubjects, then aPredicate,
 * aObject and aTruthValue are ignored.
 *
 * @status PLASMA
 */
interface rdfITripleVisitor : nsISupports
{
    /**
     * Callback function for returning query results.
     *
     * @param aSubject, aPredicate, aObject describe the (sub-)arc,
     * that is, depending on the query, some of them may be null.
     *
     * @returnCode NS_RDF_STOP_VISIT to stop iterating over the query result.
     *             Any error code (exception) will also stop the iteration.
     */
    void visit(in nsIRDFNode aSubject, in nsIRDFResource aPredicate,
               in nsIRDFNode aObject, in boolean aTruthValue);
};

rdfIDataSource

For information and tips to implement this interface check out the RDF:rdfIDataSource tests.

interface rdfIDataSource : nsISupports
{
    /**
     * Visit all the subject resources in the datasource. The order is
     * intederminate and may change from one invocation to the next.
     * The subjects will be in the aSubject argument in calls into
     * aVisitor, aPredicate and aObject will be null.
     * @note Implementations may throw NS_ERROR_NOT_IMPLEMENTED for
     * this method, but in this case RDF serializations of this
     * datasource will not be possible.
     */
    void visitAllSubjects(in rdfITripleVisitor aVisitor);
    /**
     * Visit all the triples in the datasource. The order is
     * intederminate and may change from one invocation to the next.
     * @note Implementations may throw NS_ERROR_NOT_IMPLEMENTED for
     * this method, but in this case RDF serializations of this
     * datasource will not be possible.
     */
    void visitAllTriples(in rdfITripleVisitor aVisitor);
};

Methods not yet in the tree follow here. Note that rdfIDataSource contains only query methods. We may factor out modifications to rdfIDataTarget. Datasources are *not* named: untrusted script can implement a datasource, and we can't trust the name it gives.

interface rdfIDataSource : nsISupports
{
    /**
     * Check if a triple exists.
     */
    boolean hasTriple(in rdfIResource aSubject,
                      in rdfIResource aPredicate,
                      in rdfIResource aObject,
                      in bool aTruthValue);
    /**
     * Get all the objects from a particular subject->predicate arc.
     * The order is indeterminate and may change from one invocation to the
     * next.
     */
    void getObjects(in rdfIResource      aSubject,
                    in rdfIResource      aPredicate,
                    in rdfITripleVisitor aVisitor);
    /**
     * Get all the subjects from a particular predicate->object arc.
     * The order is indeterminate and may change from one invocation to the           
     * next.
     */
    void getSubjects(in rdfIResource      aPredicate,
                     in rdfIResource      aObject,
                     in rdfITripleVisitor aVisitor);
};

rdfIDataTarget

Modifications of datasources are implemented on rdfIDataTarget.

interface rdfIDataTarget : rdfIDataSource
{
    void addObserver(rdfIObserver aObserver);
    void removeObserver(rdfIObserver aObserver);
    void beginUpdate();
    void endUpdate();
    void set(rdfIResource aSubject,
             rdfIResource aPredicate,
             rdfINode     aObject);
    void unset(rdfIResource aSubject,
               rdfIResource aPredicate,
               rdfINode     aObject);
    void reset(rdfIResource aSubject,
               rdfIResource aOldPredicate,
               rdfIResource aNewPredicate,
               rdfINode     aObject);
    void change(rdfIResource aSubject,
                rdfIResource aPredicate,
                rdfINode     aOldObject,
                rdfINode     aNewObject);
    void move(rdfIResource aOldSubject,
              rdfIResource aNewSubject,
              rdfIResource aPredicate,
              rdfINode     aObject);
};

I'm not sure we need all of these. It really depends on which API we want in the rdfIObserver. As everything else doesn't need to be part of the core API.

rdfICompositeDataSource

It's an interesting question whether the composite ds should implement rdfIDataTarget or not. Usually, asserting into a composite ds is a fuzzy thing to do, and if we made accessing the child datasources easier, it may not be worth a whole lot. So I'd favor not to.

The composite data source implements nsIMutableArray, so that clients can insert and remove datasources in any order. This should be exposed to C++, js wants an array scriptable helper (which we have to implement ourselves, the DOM one works off of nsIDOMNodeList).

interface rdfICompositeDataSource : rdfIDataSource
{
    /**
     * When enumerating triples if two triples are exactly the same, don't 
     * enumerate both arcs.
     * @note The default value is "false". Setting this to "true" can 
     * negatively affect performance of queries.
     */
    attribute boolean ignoreDuplicateTriples;
    /**
     * Allow later datasources to override matching triples in earlier 
     * datasources: i.e. DS1 has triple subjx->arc->"foo" and DS2 has
     * subjx->arc->"bar". If this attribute is false (the default) both triples
     * will be reflected. If true, only the "bar" arc will be reflected.
     * Setting this to true may affect performance and old-style container
     * aggregation.
     */
    attribute boolean allowOverride;
};

Note: if allowOverride is supposed to replace allowNegativeAssertions, then the comment is wrong.

rdfISerializer

/**
 * Interface used to serialize RDF.
 *
 * @status PLASMA
 */

interface rdfISerializer : nsISupports
{
    /**
     * Synchronously serialize the given datasource to the outputstream.
     *
     * Implementations are not required to implement any buffering or
     * other stream-based optimizations.
     *
     * @param aDataSource The RDF data source to be serialized.
     * @param aOut The output stream to use.
     */
    void serialize(in rdfIDataSource aDataSource, in nsIOutputStream aOut);
};

RdfService

RdfLoadAndSave