Refactoring Module
| Provides APIs to refactor XWiki entities |
| Type | JAR |
| Category | API |
| Developed by | |
| Rating | |
| License | GNU Lesser General Public License 2.1 |
| Bundled With | XWiki Standard |
| Compatibility | 7.2M1+ |
Table of contents
- Description
- Script Service
- Copy a Space
- Copy a Space As
- Copy a Document under a new name (copy as)
- Move a Space
- Move a Document
- Rename a Space
- Rename a Document and set up a redirect from the old location to the new location
- Rename a Document without setting up a HTTP redirect from the old location to the new location
- Move a page without the automatic correction of backlinks to target the new location
- Copy page and keep links relative
- Delete a Document
- Delete a Space
- Convert a Terminal Document to a Nested Document
- Convert a Nested Document to a Terminal Document
- Restore a batch of deleted documents (since )
- Permanently delete a batch of deleted documents (since )
- Controlling the parameters of the operation
- Events
- Debugging
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. Each such job is configured through a job request, that stores the parameters that configure the actual operations done during the job. While some APIs may "hide" away the request object and the job launched with that request, they are always created and finer grained options may be available from those APIs.
You can launch 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.
Refactoring jobs are grouped jobs, which ensures that jobs in the same group do not run in parallel. A group is identified by a group path. The group path is determined by the common ancestor of all the affected entities in the reference tree. This means that any refactoring job affecting pages within the same page tree (i.e., under the same common ancestor) will block other refactoring jobs on the same tree.
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 HTTP 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()Move a page without the automatic correction of backlinks to target the new location
#set ($source = $services.model.resolveDocument('Path.To.Source.WebHome'))
#set ($destination = $services.model.resolveDocument('Path.To.Destination.WebHome'))
#set ($moveRequest = $services.refactoring.requestFactory.createMoveRequest($source, $destination))
#set ($discard = $moveRequest.setUpdateLinks(false))
$services.refactoring.move($moveRequest)).join()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))
$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).join()Permanently delete a batch of deleted documents (since 10.10RC1)
#set ($batchId = $deletedDocument.batchId)
$services.refactoring.permanentlyDelete($batchId).join()Controlling the parameters of the operation
All the above operations may have parameters or options that you want to control. If such a control is needed, you can use the $services.refactoring.requestFactory API to create a request for the operation you need to do, then set up the various parameters on the operation request, and then, finally, launch the job providing the request as a parameter, using the dedicated APIs from $services.refactoring .
You can see the specific available functions and their parameters in the XWiki API Reference.
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:
| Event | Description | Cancelable | Source | Data |
|---|---|---|---|---|
| EntitiesCopyingEvent | Fired when the copy job starts | true | CopyJob | CopyRequest |
| DocumentCopyingEvent | Fired before copying a document | true | CopyJob | CopyRequest |
| DocumentCopiedEvent | Fired after a document is copied | false | CopyJob | CopyRequest |
| EntitiesCopiedEvent | Fired when the copy job ends | false | CopyJob | CopyRequest |
Rename/Move
The following events are fired during a rename/move operation, in this order:
| Event | Description | Cancelable | Source | Data |
|---|---|---|---|---|
| EntitiesRenamingEvent | Fired when the rename/move job starts | true | Rename/MoveJob | MoveRequest |
| DocumentsDeletingEvent | Fired before renaming/moving any document | true | Rename/MoveJob | Map<EntityReference, EntitySelection> |
| DocumentRenamingEvent | Fired before renaming/moving a document | true | Rename/MoveJob | MoveRequest |
| DocumentRenamedEvent | Fired after a document is renamed/moved | false | Rename/MoveJob | MoveRequest |
| EntitiesRenamedEvent | Fired when the rename/move job ends | false | Rename/MoveJob | MoveRequest |
Delete
The following events are fired during a delete operation, in this order:
| Event | Description | Cancelable | Source | Data |
|---|---|---|---|---|
| DocumentsDeletingEvent | Fired before renaming any document | true | Rename/MoveJob | Map<EntityReference, EntitySelection> |
| DocumentDeletingEvent | Fired before deleting a document | true | XWikiDocument | XWikiContext |
| DocumentDeletedEvent | Fired after a document is deleted | false | XWikiDocument | XWikiContext |
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:
