works well when accessed with the browser, in Groovy
import java.net.URL
String url = http://myhost:8080/xwiki/bin/export/Team/WebHome/?format=xar&name=Team.2018-12-04&pages=xwiki%3ATeam.%25&history=true&backup=true
new URL(url).getText()
results in
Caused by: java.io.FileNotFoundException: http://myhost:8080/xwiki/bin/export/Test/WebHome/?format=xar&name=Test.2018-12-04&pages=xwiki%3ATest.%25&history=true&backup=true
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
Going trough a URL from a script is usually asking for trouble. The best is generally to do what this service does behind the scene, here directly manipulate the Filter API to “convert” and instance into a XAR file.
INFO:Starting job of type [filter.converter] with identifier [[filter, converter, xwiki+instance, xwiki+xar/1.3]]
ERROR:Exception thrown during job execution
INFO:Finished job of type [filter.converter] with identifier [[filter, converter, xwiki+instance, xwiki+xar/1.3]]
I don’t think this does what you expect it to do: this is a reference to the page wiki:xwiki.Main\.WebHome.
If what you want is the reference of the wiki (like the Velocity example does) then it’s new WikiReference('xwiki'). The wiki: prefix in the Velocity example indicate the type of the reference (a wiki reference here and not a document reference). If what you want is only to export the home page then it’s new DocumentReference('xwiki', 'Main', 'WebHome').
target is actually a very generic parameter (could be an OutputStream, etc.) so when you pass a file path you need to make is explicit by prefixing the value with ‘file:’ like in the Velocity example does (which is the “target type”).
I’d still like do be also able to manual trigger a download on the client side. I could generate download links and fiddle with JavaScript to invoke them one after the other. I’ll see.
Here is the complete working example: The content of a page that allows to download or backup a user selection of top level spaces and lists download links for all top level spaces
{{groovy}}
import com.xpn.xwiki.api.Document
import com.xpn.xwiki.util.Util;
import com.xpn.xwiki.web.XWikiServletResponse
import org.xwiki.logging.LogLevel
import org.xwiki.job.Job
import java.text.DateFormat
import java.text.SimpleDateFormat
import org.xwiki.filter.instance.input.DocumentInstanceInputProperties
import org.xwiki.filter.output.DefaultOutputStreamOutputTarget;
import org.xwiki.filter.type.FilterStreamType
import org.xwiki.model.reference.EntityReferenceSet
import org.xwiki.model.reference.SpaceReference
import org.xwiki.model.reference.WikiReference
TimeZone tz = TimeZone.getTimeZone("UTC")
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss")
df.setTimeZone(tz)
String now = df.format(new Date())
ArrayList<String> exclude = ["Help", "Menu", "XWiki", "Sandbox", "ScriptingDocumentation"]
ArrayList<String> names = new ArrayList<>()
Document home = xwiki.getDocument("Main.WebHome")
for (name in home.getChildren()) {
name = name.tokenize(".")[0]
if (!exclude.contains(name)) {
names << name
}
}
names.sort()
String[] pages = request.getParameterValues("pages")
StringBuffer out = new StringBuffer()
out << """
(% class="row" %)
(((
(% class="col-md-4" %)
(((
{{html}}
<form action="" id="backup" method="post">
<div>
<table>
<tbody>
<tr>
<th>Pages</th>
<td>
<select name="pages" multiple size=${names.size()}>
"""
for (name in names) {
out << "<option"
if (pages == null || pages.contains(name)) {
out << " selected"
}
out << ">" << name << "</option>\n"
}
out << """
</select>
</td>
</tr>
<tr>
<th>Target</th>
<td>
<select name="target" size=1 onchange="setButtonText(this.value)">
"""
for (opt in ["Server", "Download"]) {
out << "<option"
if (request.target == opt) {
out << " selected"
}
out << ">" << opt << "</option>\n"
}
out << """
</select>
</td>
</tr>
</tbody>
</table>
<span class="buttonwrapper"><input id="btn1" type="submit" value="Backup Selected Pages" class="button"/></span>
</div>
</form>
<script type="text/javascript">
function setButtonText(val) {
if (val == "Server") {
document.getElementById("btn1").value="Backup Selected Pages"
} else {
document.getElementById("btn1").value="Download Selected Pages"
}
}
</script>
{{/html}}
)))
(% class="col-md-4" %)
(((
"""
String base = xcontext.URLFactory.getServerURL(xcontext.context)
for (name in names) {
String url = "${base}/xwiki/bin/export/${name}/WebHome/?format=xar&name=${name}.${now}&pages=xwiki%3A${name}.%25&history=true&backup=true"
out << "\n[[Download ${name}>>${url}]]"
}
out << """
)))
)))
"""
if (pages != null) {
EntityReferenceSet entities = new EntityReferenceSet()
for (page in pages) {
entities.includes(new SpaceReference(page, new WikiReference("xwiki")))
}
DocumentInstanceInputProperties iProps = new DocumentInstanceInputProperties()
iProps.setEntities(entities)
iProps.setVerbose(true)
iProps.setWithJRCSRevisions(true)
iProps.setWithRevisions(false)
Map oProps = [
packageBackupPack: Boolean.TRUE
]
String filename = "Backup.${now}.xar"
if (request.target == "Server") {
oProps["target"] = new File("/var/local/xwiki/${filename}")
} else {
filename = Util.encodeURI(filename, xcontext.getContext())
XWikiServletResponse response = xcontext.getResponse()
response.setContentType("application/zip")
response.setHeader("Content-disposition", "attachment; filename=${filename}")
oProps["target"] = response.getOutputStream()
}
Job job = services.filter.instance.startExport(FilterStreamType.XWIKI_XAR_CURRENT, oProps, iProps)
job.join()
for (event in job.getStatus().getLog().getLogsFrom(LogLevel.DEBUG)) {
out << "{{{$event}}}" << "\n"
}
}
print out.toString()
{{/groovy}}
A little remark: This version generates duplicate backup requests if the selected space contains subspaces.
Changing line 30 from “names.sort()” to “names.sort().unique()” helps.