Model Module

Last modified by Thomas Mortagne on 2023/06/16 09:28

shape_groupProvides an API for the XWiki Model (Wikis, Spaces, Documents, Objects, etc)
TypeJAR
Category
Developed by

XWiki Development Team

Rating
0 Votes
LicenseGNU Lesser General Public License 2.1
Bundled With

XWiki Standard

Description

The XWiki Model is made of Entities, such as:

  • A Wiki contains Spaces
  • A Space contains Documents
  • A Document contains Attachments and Objects (a.k.a XObjects), and can also contain one Class definition (XClass)
  • since 10.6 A Page is another way to represent Space/Document hierarchy
  • An Object contains Object Properties
  • A Class contain Class Properties

Entity Reference API

There are 3 concepts to understand:

  • The notion of EntityReference (or Reference for short).
    • A Reference points to an Entity from the Model (wiki, space, document, object, etc).
    • A Reference can have a parent Reference (e.g. a Document Reference's parent is a Space Reference)
    • A Reference can be absolute (i.e. all its parent references are defined till the wiki Reference) or relative.
    • To make it easy to construct References, a typed API exists. For example WikiReference, SpaceReference, DocumentReference, AttachmentReference, and more.
  • The notion of EntityReferenceResolver (Resolver for short). The goal of a Resolver is to take some input and convert it to an EntityReference instance. An example is an input defined as a String, such as wiki:space.document.
  • The notion of EntityReferenceSerializer (Serializer for short).  The goal of a Serializer is to convert an EntityReference instance into a given representation. For example a Serializer could convert a Reference into its string representation, e.g. xwiki:space.document.

Constructing an Entity Reference

Examples:

  // A Document Reference pointing to the wiki:space.document document
 DocumentReference reference = new DocumentReference("wiki", "space", "document");

 // A Page Reference pointing to the wiki:page1/page2 page
 PageReference reference = new PageReference("wiki", "page1", "page2");

 // A Document Reference pointing to the space.document document in an undefined wiki (i.e. without the wiki part)
 LocalDocumentReference reference = new LocalDocumentReference("space", "document");

 // A relative reference, specifying only a space
 EntityReference reference = new EntityReference("space", EntityType.SPACE);

 // A document reference, specified using the generic EntityReference API, defining parent references
 // The constructed reference is equivalent to: new DocumentReference("wiki", "space", "document").
 EntityReference reference = new EntityReference("document", EntityType.DOCUMENT,
     new EntityReference("space", EntityType.SPACE,
         new EntityReference("wiki", EntityType.WIKI)));

Resolving a Reference

There are 2 types of Resolvers:

  • Resolvers which take a String representing a Reference as input and convert it to an EntityReference (usually Absolute)
  • Resolvers which take an EntityReference as input and convert it to a EntityReference (usually Absolute). These Resolvers are often used to convert a relative Reference into an absolute Reference.

For both types of Resolvers, there are various Resolvers that exist:

  • default Resolver(String or EntityReference input): When some reference parts are missing from the input, default values are used (see the configuration example below for default values). These default values can be configured (using the Configuration Module) to use specific default values for missing Entity parts. This is achieved by editing the xwiki.properties file. For example:
    model.reference.default.wiki = mywiki (defaults to "xwiki")
    model.reference.default.space = myspace (defaults to "Main")
    model.reference.default.document = mydocument (defaults to "WebHome")
    model.reference.default.page = mypage (defaults to "Main")
    model.reference.default.attachment = myfilename (defaults to "filename")
    model.reference.default.object = myobject (defaults to "object")
    model.reference.default.object_property = myproperty (defaults to "property")
  • current Resolver(String or EntityReference input): Uses the current Entity Reference to fill missing parts from the input (i.e. current wiki, current space, current page, etc). If there's no current entity part then uses the default part values.
  • currentmixed Resolver(String or EntityReference input): Same as current but if the passed reference doesn't have a document name specified (or if it's empty) the value used is the default document name (instead of the document name of the current document's reference)
  • relative Resolver (String input only): Doesn't generate absolute references; simply transforms a String representation into an EntityReference instance without resolving any missing parts (space, wiki, page, etc).
  • withparameters Resolver (String input only): same as the default one but also support the standar entity reference parameters syntax for all types and not only for PAGE based reference

The API to call a Resolver is:

public interface EntityReferenceResolver<T>
{
   /**
     * @param entityReferenceRepresentation the representation of an entity reference (eg as a String)
     * @param type the type of the Entity (Document, Space, Attachment, Wiki, etc) to resolve out of the representation,
     *            since 14.8 it's possible to pass null if the resolver should extract the type from the representation
     *            itself
     * @param parameters optional parameters. Their meaning depends on the resolver implementation
     * @return the valid resolved reference as an Object
     */

    EntityReference resolve(T entityReferenceRepresentation, EntityType type, Object... parameters);
}

Note that all the Resolvers listed above will honor passing an EntityReference as parameters. If one is passed then it'll be used to resolve missing entity parts.

In addition to the Resolved listed above there's a special one:

  • explicit Resolver (String or EntityReference input): Must be called with an EntityReference parameter and this reference is used exclusively to resolve missing entity parts.

Some "typed" resolvers are also provided as helpers:

  • org.xwiki.model.reference.DocumentReferenceResolver (since 2.2M1)
  • org.xwiki.model.reference.AttachmentReferenceResolver (since 2.2M1)
  • org.xwiki.model.reference.ObjectReferenceResolver (since 2.3M1)
  • org.xwiki.model.reference.ObjectPropertyReferenceResolver (since 2.3M1)
  • org.xwiki.model.reference.SpaceReferenceResolver (since 7.2M1).
  • org.xwiki.model.reference.PageReferenceResolver (since 10.6RC1)
  • org.xwiki.model.reference.PageAttachmentReferenceResolver (since 10.6RC1)
  • org.xwiki.model.reference.PageObjectReferenceResolver (since 10.6RC1)
  • org.xwiki.model.reference.PageObjectPropertyReferenceResolver (since 10.6RC1)

Serializing a Reference

There are various Serializers that all take an EntityReference as input and generate a String representation of it:

  • default: Prints all parts of the passed EntityReference.
  • compact: Don't print parts that are the same as either the current entity in the Execution Context or as the passed entity reference (if any). Note that the terminal part is always kept (eg the document's name for a document reference or the attachment's filename for an attachment reference).
  • compactwiki: Don't print the wiki reference part if the passed reference matches the current wiki or as the wiki of the passed entity reference (if any). The space reference and document references are always printed.
  • local: Never print the wiki reference part.
  • uid: Fast unique String reference. It's not meant to be parsed but to get a unique String for a given reference as fast as possible. It's mostly used as cache and database identifiers. Since 8.3RC1 it also support serializing the Locale part of a reference.
  • withparameters: same as the default one but also serialize the parameters for all types and not only for PAGE based reference
  • withtype: same as the default one but prefix the reference with the entity type
  • withtype/withparameters: a combination of both withtype and withparameters specifications

The API to call a Serializer is:

public interface EntityReferenceSerializer<T>
{
   /**
     * Serialize an entity reference into a new representation of type <T>.
     *
     * @param reference the reference to serialize
     * @param parameters optional parameters. Their meaning depends on the serializer implementation
     * @return the new representation (eg as a String)
     */

    T serialize(EntityReference reference, Object... parameters);
}

Reference Set

Since XWiki 5.2 org.xwiki.model.reference.EntityReferenceSet can be used to create a matcher combining included and excluded references.

The following example matches all references in the wiki:space space except the wiki:space.document document:

  EntityReferenceSet set = new EntityReferenceSet();

  set.includes(new SpaceReference("space", new WikiReference("wiki")));
  set.excludes(new DocumentReference("wiki", "space", "document"));

Reference tree

Since XWiki 5.4 org.xwiki.model.reference.EntityReferenceTree can be used to create a navigable tree of entity references.

  EntityReferenceTree tree = new EntityReferenceTree(new DocumentReference("wiki", "space", "document"), new DocumentReference("wiki", "space", "document2"));

The various References types

Page References

Since 10.6 

General string syntax: wiki:page1/page2

Note that you don't specify WebHome for nested pages, compared to Entity Reference or Document Reference.

Examples of string representations:

  • Wiki:Page1/Page2
  • Page1/Page2 (wiki not specified, it's a relative reference)
  • My\/Page (page with a slash in the name which needs to be escaped as otherwise "My" would be considered as a parent page name)
  • .. (parent page)
  • ./ChildPage (page under current page)
  • Page;en_US (page with locale en_US)
  • Page;key=value;en_US (page with lcoale en_US and custom parametere "key" with value "value")

API examples:

  • Generate a PageReference using a "current" Resolver, filling wiki with the current wiki:
    @Inject
    @Named("current")
    private PageReferenceResolver<String> resolver;
    ...
    PageReference reference = resolver.resolve("Page");
  • Serialize a Page Reference into a String:
    @Inject
    private EntityReferenceSerializer<String> serializer;
    ...
    String serializer = serializer.serialize(reference);
  • Lookup the "current" Page Reference resolver (in case you can't have it injected):
    PageReferenceResolver<String> stringResolver = componentManager.getInstance(PageReferenceResolver.TYPE_STRING, "current");
    PageReferenceResolver<EntityReference> referenceResolver = componentManager.getInstance(PageReferenceResolver.TYPE_REFERENCE, "current");
  • Resolve the sandbox page reference and generate its string representation filling the missing wiki with the current wiki:
      PageReferenceResolver<String> stringResolver = componentManager.getInstance(PageReferenceResolver.TYPE_STRING, "current");
      EntityReferenceSerializer<String> stringSerializer = componentManager.getInstance(EntityReferenceSerializer.class);
      String sandboxName = "Sandbox.TestDocument1";

      PageReference sandboxRef = stringResolver.resolve(sandboxName);
     // sandboxRef.getName() will give the page name TestDocument1
     // sandboxRef.getParent().getName() will give the parent page name Sandbox
     // sandboxRef.getParent().getParent().getName() will give the current wiki

     // serialize the reference:
     String sandbox = stringSerializer.serialize(sandboxRef) // will give <current_wiki>:Sandbox.TestDocument1

Local Page References

Since 10.6 

Same as PageReference but without the wiki part.

There is no dedicated resolver, it's mostly used as a helper to create a local page reference.

LocalPageReference reference = new LocalPageReference("page1", "page2");

Page Attachment References

Since 10.6 

General string syntax: Wiki:Page1/Page2/filename

Examples of string representations:

  • Wiki:Page1/Page2/filename
  • Page1/Page2/filename (wiki not specified, it's a relative reference)
  • filename  (wiki and page not defined, it's a relative reference)
  • file\/name (attachment name with a slash in the name which needs to be escaped as otherwise "file" would be considered as a page name)

Page Object References

Since 10.6 

General string syntax: Wiki:Page1/Page2/Object

Examples of string representations:

  • Wiki:Page1/Page2/Object
  • Page1/Page2/Object (wiki not specified, it's a relative reference)
  • Object  (wiki, page not defined, it's a relative reference)
  • Ob\/ject (object name with a slash in the name which needs to be escaped as otherwise "Ob" would be considered as a page name)

Page Object Property References

Since 10.6 

General string Syntax: Wiki:Page1/Page2/Object/Property

Examples of string representations:

  • Wiki:Page1/Page2/Object/Property
  • Page1/Page2/Object/Property (wiki not specified, it's a relative reference)
  • Object/Property  (wiki and page not defined, it's a relative reference)
  • Property  (wiki, page and object not defined, it's a relative reference)
  • Pro\/perty (object name with a slash in the name which needs to be escaped as otherwise "Pro" would be considered as a page name)

Page Class Property References

Since 10.6 

General string Syntax: Wiki:Page1/Page2/ClassProperty

Document References

General string syntax: wiki:space.document

Examples of string representations:

  • Wiki:Space.Document
  • Space.Document (wiki not specified, it's a relative reference)
  • Document (wiki and space not specified, it's a relative reference)
  • My\.Document (document with a dot in the name which needs to be escaped as otherwise "My" would be considered as a space name)
  • Document;en_US (page with locale en_US)
  • Document;key=value;en_US (page with locale en_US and custom parametere "key" with value "value")

API examples:

  • Generate a DocumentReference using a "current" Resolver, filling wiki and space parts with the current wiki and space:
    @Inject
    @Named("current")
    private DocumentReferenceResolver<String> resolver;
    ...
    DocumentReference reference = resolver.resolve("Document");
  • Generate a DocumentReference using a "default" Resolver, filling the wiki part with the default wiki name ("xwiki" by default but can be configured):
    @Inject
    private DocumentReferenceResolver<String> resolver;
    ...
    DocumentReference reference = resolver.resolve("Space.Document");
  • Generate a DocumentReference using a "default" Resolver, filling the space part with the default space name ("Main" by default but can be configured), and forcing the wiki part to use a fixed value if not defined:
    @Inject
    private DocumentReferenceResolver<String> resolver;
    ...
    DocumentReference reference = resolver.resolve("Document", new WikiReference("mywiki"));
  • Serialize a Document Reference into a String:
    @Inject
    private EntityReferenceSerializer<String> serializer;
    ...
    String serializer = serializer.serialize(reference);
  • Lookup the "current" Document Reference resolver (in case you can't have it injected):

    Starting with XWiki 4.0:

    DocumentReferenceResolver<String> stringResolver = componentManager.getInstance(DocumentReferenceResolver.TYPE_STRING, "current");
    DocumentReferenceResolver<EntityReference> referenceResolver = componentManager.getInstance(DocumentReferenceResolver.TYPE_REFERENCE, "current");

    Before XWiki 4.0:

    DocumentReferenceResolver<String> stringResolver = componentManager.getInstance(DocumentReferenceResolver.class, "current");
    DocumentReferenceResolver<EntityReference> referenceResolver = componentManager.getInstance(DocumentReferenceResolver.class, "current/reference");
  • Resolve the sandbox document reference and generate its string representation filling the missing wiki with the current wiki (starting with 4.0):
      DocumentReferenceResolver<String> stringResolver = componentManager.getInstance(DocumentReferenceResolver.TYPE_STRING, "current");
      EntityReferenceSerializer<String> stringSerializer = componentManager.getInstance(EntityReferenceSerializer.class);
      String sandboxName = "Sandbox.TestDocument1";

      DocumentReference sandboxRef = stringResolver.resolve(sandboxName);
     // sandboxRef.getName() will give the document name TestDocument1
     // sandboxRef.getParent().getName() will give the space Sandbox
     // sandboxRef.getParent().getParent().getName() will give the current wiki

     // serialize the reference:
     String sandbox = stringSerializer.serialize(sandboxRef) // will give <current_wiki>:Sandbox.TestDocument1

14.8+ 

A DocumentVersionReference is now present in the model: this is a special kind of DocumentReference which sets a parameter named version with the given version, and allow to retrieve it through the API. 

DocumentReference reference = resolver.resolve("Space.Document");
DocumentVersionReference versionRef = new DocumentVersionReference(reference, "1.4");
String version = versionRef.getVersion();

Local Document References

Same as DocumentReference but without the wiki part.

There is no dedicated resolver, its mostly used as a helper to create a local document reference (often used for XWiki classes for example).

LocalDocumentReference reference = new LocalDocumentReference("Space", "document");

Attachment References

General string syntax: Wiki:Space.Document@Filename

Examples of string representations:

  • Wiki:Space.Document@Filename
  • Space.Pocument@Filename (wiki not specified, it's a relative reference)
  • Document@Filename (wiki and space not specified, it's a relative reference)
  • Filename  (wiki, space, document not defined, it's a relative reference)
  • File\@name (attachment name with a '@' symbol in the name which needs to be escaped as otherwise "File" would be considered as a document name)

Object References

General string syntax: Wiki:Space.Document^Object

Examples of string representations:

  • Wiki:Space.Document^Object
  • Space.Document^Object (wiki not specified, it's a relative reference)
  • Document^Object (wiki and space not specified, it's a relative reference)
  • Object  (wiki, space, document not defined, it's a relative reference)
  • Ob\^ject (object name with a '^' symbol in the name which needs to be escaped as otherwise "Ob" would be considered as a document name)

In XWiki the Object name is of the form <class reference>[number] with the number being optional, for example:

  • Wiki:Space.Document^MySpace.MyClass[0]
  • Wiki:Space.Document^MySpace.MyClass

Object Property References

General string Syntax: Wiki:Space.Document^Object.Property

Examples of string representations:

  • Wiki:Space.Document^Object.Property
  • Space.Document^Object.Property (wiki not specified, it's a relative reference)
  • Document^Object.Property (wiki and space not specified, it's a relative reference)
  • Object.Property  (wiki, space, document not defined, it's a relative reference)
  • Property  (wiki, space, document and object not defined, it's a relative reference)
  • Pro\.perty (object name with a dot in the name which needs to be escaped as otherwise "Pro" would be considered as an object name)

Class Property References

General string Syntax: Wiki:Space.Document^ClassProperty

Script Service API

Full API is available here.

Examples:

  • Create a Document Reference:
    #set ($reference = $services.model.createDocumentReference("wiki", ["space"], "document"))

    Note that prior to XWiki 7.2, the API was:

    #set ($reference = $services.model.createDocumentReference("wiki", "space", "document"))
  • Generate a string representation for the parent reference relative to the current document (example in Velocity):
    #set ($parentReference = $services.model.resolveDocument($doc.parent, 'currentmixed', $doc.documentReference))
    $services.model.serialize($parentReference)
  • Create a document reference for the Space1.Space2.WebHome document on the main wiki:
    #set ($workspaceManagerMainDocumentReference = $services.model.createDocumentReference($xcontext.mainWikiName, ['Space1', 'Space2'], 'WebHome'))
  • Create a document reference for the Space1.Space2.WebHome document on the current wiki (any param can be an empty string and in this case it'll be resolved using the current resolver):
    #set ($workspaceManagerMainDocumentReference = $services.model.createDocumentReference('', ['Space1', 'Space2'], 'WebHome'))
  • Create an Entity Reference for a document with a wiki parent specified but not space reference specified:
    #set ($ref = $services.model.createEntityReference('document', 'document', $services.model.createEntityReference('wiki', 'wiki')))
  • Since XWiki 5.4 Create an Entity Reference tree from a list of Entity References:
    #set ($ref = $services.model.toTree($references))
  • Create a reference to a sibling of the current document:
    // Solution 1 (simplest and best):
    #set ($ref = $services.model.resolveDocument('siblingdocument', $doc.documentReference))
    // Solution 2:
    #set ($ref = $services.model.createEntityReference('siblingdocument', 'DOCUMENT', $doc.documentReference.parent))
  • Resolve the current page's Space home page (without hardcoding WebHome which is a bad practice):
    $services.model.resolveDocument('', 'default', $doc.documentReference.lastSpaceReference)

    Some explanations:

    • The empty name means we're letting the resolver figure it out
    • The default string means we want to use the Default Resolver (if not specified, it's the current resolver that would be used, hence the Resolver would resolve to the current page name)
    • The 3rd parameter is an Entity Reference that will be used to fill the parts of the reference that we don't specify (namely the wiki reference and the space references)
  • Resolve a group name (XWikiAllGroup in the example), as a DocumentReference:
    #set ($groupReference = $services.model.resolveDocument('XWikiAllGroup', 'group'))
Tags: development
    

Get Connected