Refactoring Module

Last modified by Anca Luca on 2021/10/12 19:31

wrench_orangeProvides APIs to refactor XWiki entities
TypeJAR
CategoryAPI
Developed by

XWiki Development Team

Rating
0 Votes
LicenseGNU Lesser General Public License 2.1
Bundled With

XWiki Standard

Compatibility

7.2M1+

Description

This module provides APIs to perform various refactoring operations, such as move, copy, rename, delete, that target XWiki Entities. Since most of these operations can take a long time (e.g. renaming a space with lots of documents in it) they have been implemented as jobs that run in background threads for which we can monitor the process.

You can trigger the refactoring jobs from a Java component using the Job Executor or from Velocity/Groovy using the script service. Note that some jobs (like move) are interactive and thus can ask questions (e.g. whether you want to overwrite an existing document or not).

This module is the one used for the page operations described in the page lifecycle documentation, so the behavior, options and limitations of this API are similar to those described in that documentation.

Script Service

For the sake of brevity in the following examples the HTTP request is blocked until the job is done by calling join(). In real life you should monitor the progress of the operation using the job status.

  • Copy a Space
    #set ($source = $services.model.resolveSpace('Path.To.Source'))
    #set ($destination = $services.model.resolveSpace('Path.To.New.Parent'))
    $services.refactoring.copy($source, $destination).join()
  • Copy a Space As
    #set ($source = $services.model.resolveSpace('Path.To.Source'))
    #set ($destination = $services.model.resolveSpace('Path.To.New.Name'))
    $services.refactoring.copyAs($source, $destination).join()
  • Copy a Document under a new name (copy as):
    #set ($source = $services.model.resolveDocument('Path.To.Source.WebHome'))
    #set ($destination = $services.model.resolveDocument('Path.To.New.WebHome'))
    $services.refactoring.copyAs($source, $destination).join()
  • Move a Space
    #set ($source = $services.model.resolveSpace('Path.To.Source'))
    #set ($destination = $services.model.resolveSpace('Path.To.New.Parent'))
    $services.refactoring.move($source, $destination).join()
  • Move a Document
    #set ($source = $services.model.resolveDocument('Path.To.Source.WebHome'))
    #set ($destination = $services.model.resolveSpace('Path.To.New.Parent'))
    $services.refactoring.move($source, $destination).join()
  • Rename a Space
    #set ($source = $services.model.resolveSpace('Path.To.Source'))
    $services.refactoring.rename($source, 'NewName').join()
  • Rename a Document and set up a redirect from the old location to the new location
    #set ($source = $services.model.resolveDocument('Path.To.Source.WebHome'))
    $services.refactoring.rename($source, 'NewName').join()
  • Rename a Document without setting up a redirect from the old location to the new location
    #set ($source = $services.model.resolveDocument('Path.To.Source.WebHome'))
    #set ($renameRequest = $services.refactoring.requestFactory.createRenameRequest($source, 'NewName'))
    #set ($discard = $renameRequest.setAutoRedirect(false))
    $services.refactoring.rename($renameRequest)).join()

    <10.11 The function to create requests was attached to the refactoring service itself. So to create the rename request before this version, you would write:
    #set ($renameRequest = $services.refactoring.createRenameRequest($source, 'NewName')) 

  • Copy page and keep links relative
    #set ($source = $services.model.resolveDocument('Path.To.Source.WebHome'))
    #set ($destination = $services.model.resolveDocument('Path.To.New.WebHome'))
    #set ($copyAsRequest = $services.refactoring.requestFactory.createCopyAsRequest($source, $destination))
    #set ($discard = $copyAsRequest.setAutoRedirect(false))
    $services.refactoring.copyAs($copyAsRequest).join()
  • Delete a Document
    #set ($source = $services.model.resolveDocument('Path.To.Source.WebHome'))
    $services.refactoring.delete($source).join()
  • Delete a Space
    #set ($source = $services.model.resolveSpace('Path.To.Source'))
    $services.refactoring.delete($source).join()
  • Convert a Terminal Document to a Nested Document
    #set ($source = $services.model.resolveDocument('Path.To.Page'))
    $services.refactoring.convertToNestedDocument($source).join()
  • Convert a Nested Document to a Terminal Document
    #set ($source = $services.model.resolveDocument('Path.To.Source.WebHome'))
    $services.refactoring.convertToTerminalDocument($source).join()
  • Restore a batch of deleted documents (since 10.10RC1)
    #set ($batchId = $deletedDocument.batchId)
    $services.refactoring.restore($batchId)
  • Permanently delete a batch of deleted documents (since 10.10RC1)
    #set ($batchId = $deletedDocument.batchId)
    $services.refactoring.permanentlyDelete($batchId)

Events

Checkout the Observation Module to see how to implement an event listener for one of the events listed below.

Copy

The following events are fired during a copy operation, in this order:

EventDescriptionCancelableSourceData
EntitiesCopyingEventFired when the copy job startstrueCopyJobCopyRequest
DocumentCopyingEventFired before copying a documenttrueCopyJobCopyRequest
DocumentCopiedEventFired after a document is copiedfalseCopyJobCopyRequest
EntitiesCopiedEventFired when the copy job endsfalseCopyJobCopyRequest

Rename/Move

The following events are fired during a rename/move operation, in this order:

EventDescriptionCancelableSourceData
EntitiesRenamingEventFired when the rename/move job startstrueRename/MoveJobMoveRequest
DocumentsDeletingEventFired before renaming/moving any documenttrueRename/MoveJobMap<EntityReference, EntitySelection>
DocumentRenamingEventFired before renaming/moving a documenttrueRename/MoveJobMoveRequest
DocumentRenamedEventFired after a document is renamed/movedfalseRename/MoveJobMoveRequest
EntitiesRenamedEventFired when the rename/move job endsfalseRename/MoveJobMoveRequest

Delete

The following events are fired during a delete operation, in this order:

EventDescriptionCancelableSourceData
DocumentsDeletingEventFired before renaming any documenttrueRename/MoveJobMap<EntityReference, EntitySelection>
DocumentDeletingEventFired before deleting a documenttrueXWikiDocumentXWikiContext
DocumentDeletedEventFired after a document is deletedfalseXWikiDocumentXWikiContext

Debugging

If some operation failed you can see what got executed by doing the following:

  • Find the id of the job by checking [Permanent directory]/jobs/status/refactoring/<operation>/
  • In a new page add the following snippet (and replace with your operation and job id):
    {{velocity}}
    #template('job_macros.vm')
    #set ($status = $services.job.getJobStatus(["refactoring", "move", "1502984592653-433"]))
    {{html}}
    #displayJobStatusLog($status, false)
    {{/html}}
    {{/velocity}}

    Example:

    debugging.png

Tags:
    

Get Connected