Skip to content

Commit b9db404

Browse files
committed
[bugfix] Make sure the resource type and media type when restoring a Backup are preserved
1 parent 38ffb7a commit b9db404

File tree

2 files changed

+82
-63
lines changed

2 files changed

+82
-63
lines changed

exist-core/src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -341,17 +341,12 @@ private DeferredPermission restoreResourceEntry(final Attributes attributes) thr
341341
}
342342
}
343343

344-
MimeType mimeType = null;
345-
if (xmlType) {
346-
mimeType = MimeType.XML_TYPE;
347-
} else if (mimeTypeStr != null) {
348-
mimeType = MimeTable.getInstance().getContentType(mimeTypeStr);
349-
if (mimeType == null) {
350-
mimeType = MimeType.BINARY_TYPE;
351-
} else if (mimeType.isXMLType() != xmlType) {
352-
listener.warn("Calculated mime type " + mimeType + " type differs from the one specified in the backup, adjusting it");
353-
mimeType = new MimeType(mimeType.getName(), xmlType ? MimeType.XML : MimeType.BINARY);
354-
}
344+
final MimeType mimeType;
345+
if (mimeTypeStr == null || mimeTypeStr.trim().isEmpty()) {
346+
mimeType = xmlType ? MimeType.XML_TYPE : MimeType.BINARY_TYPE;
347+
listener.warn("Missing mimetype attribute in the backup __contents__.xml file for: " + commonAttributes.name + ", assuming: " + mimeType);
348+
} else {
349+
mimeType = new MimeType(mimeTypeStr.trim(), xmlType ? MimeType.XML : MimeType.BINARY);
355350
}
356351

357352
Date dateCreated = null;

exist-core/src/test/java/org/exist/backup/XMLDBRestoreTest.java

Lines changed: 76 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,18 @@
2828
import org.exist.security.MessageDigester;
2929
import org.exist.security.SecurityManager;
3030
import org.exist.test.ExistWebServer;
31-
import org.exist.util.MimeTable;
31+
import org.exist.util.MimeType;
3232
import org.exist.xmldb.*;
3333
import org.junit.*;
3434
import org.junit.rules.TemporaryFolder;
3535
import org.junit.runner.RunWith;
3636
import org.junit.runners.Parameterized;
3737
import org.xmldb.api.DatabaseManager;
3838
import org.xmldb.api.base.Collection;
39+
import org.xmldb.api.base.Resource;
3940
import org.xmldb.api.base.XMLDBException;
41+
import org.xmldb.api.modules.BinaryResource;
42+
import org.xmldb.api.modules.XMLResource;
4043

4144
import javax.annotation.Nullable;
4245
import java.io.File;
@@ -62,6 +65,17 @@ public class XMLDBRestoreTest {
6265

6366
private static final String PORT_PLACEHOLDER = "${PORT}";
6467

68+
private static final String COLLECTION1_NAME = "col1";
69+
private static final DocInfo[] BACKUP_DOCS = {
70+
new DocInfo("doc1.xml", MimeType.XML, "application/xml", "<doc1/>"),
71+
new DocInfo("doc2.xml", MimeType.XML, "application/xml", "<doc2/>"),
72+
new DocInfo("doc3.svg", MimeType.XML, "image/svg+xml", "<svg height=\"100\" width=\"100\"><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" />Sorry, your browser does not support inline SVG.</svg>"),
73+
new DocInfo("doc4.html", MimeType.BINARY, "text/html", "<html><body><h1>BinaryResource</h1></body></html>"),
74+
new DocInfo("doc5.html", MimeType.XML, "text/html", "<html><body><h1>XMLResource</h1></body></html>"),
75+
new DocInfo("doc6.xml", MimeType.XML, "<doc6/>"),
76+
new DocInfo("doc7.bin", MimeType.BINARY, "1234567")
77+
};
78+
6579
@ClassRule
6680
public static final TemporaryFolder tempFolder = new TemporaryFolder();
6781

@@ -83,20 +97,6 @@ private String getBaseUri() {
8397
return baseUri.replace(PORT_PLACEHOLDER, Integer.toString(existWebServer.getPort()));
8498
}
8599

86-
@BeforeClass
87-
public static void prepare() throws IOException {
88-
Path mimeTypesDefinition = tempFolder.getRoot().toPath().resolve("mime-types.xml");
89-
String mimeTypesContent =
90-
"<mime-types default-mime-type=\"foo/bar\" default-resource-type=\"binary\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"schema/mime-types.xsd\">\n" +
91-
"<mime-type name=\"text/html\" type=\"xml\">\n" +
92-
"<description>HTML document</description>\n" +
93-
"<extensions>.html</extensions>\n" +
94-
"</mime-type>\n"+
95-
"</mime-types>";
96-
Files.write(mimeTypesDefinition, mimeTypesContent.getBytes(UTF_8));
97-
MimeTable.getInstance(mimeTypesDefinition);
98-
}
99-
100100
@Test
101101
public void restoreValidZipBackup() throws IOException, XMLDBException {
102102
final Path zipFile = createZipBackupWithValidContent();
@@ -105,9 +105,13 @@ public void restoreValidZipBackup() throws IOException, XMLDBException {
105105

106106
restoreBackup(rootUri, zipFile, null, listener);
107107

108-
assertEquals(7, listener.restored.size());
109-
assertEquals(1, listener.warnings.size());
108+
assertEquals(9, listener.restored.size());
109+
assertEquals(2, listener.warnings.size());
110110
assertEquals(0, listener.errors.size());
111+
112+
for (final DocInfo backupDocInfo : BACKUP_DOCS) {
113+
checkMediaType(XmldbURI.ROOT_COLLECTION_URI.append(COLLECTION1_NAME), backupDocInfo);
114+
}
111115
}
112116

113117
@Test
@@ -118,9 +122,13 @@ public void restoreValidDirBackup() throws IOException, XMLDBException {
118122

119123
restoreBackup(rootUri, contentsFile, null, listener);
120124

121-
assertEquals(7, listener.restored.size());
122-
assertEquals(1, listener.warnings.size());
125+
assertEquals(9, listener.restored.size());
126+
assertEquals(2, listener.warnings.size());
123127
assertEquals(0, listener.errors.size());
128+
129+
for (final DocInfo backupDocInfo : BACKUP_DOCS) {
130+
checkMediaType(XmldbURI.ROOT_COLLECTION_URI.append(COLLECTION1_NAME), backupDocInfo);
131+
}
124132
}
125133

126134
@Test
@@ -290,57 +298,55 @@ private static void restoreBackup(final XmldbURI uri, final Path backup, @Nullab
290298
restoreService.restore(backup.normalize().toAbsolutePath().toString(), backupPassword, listener, false);
291299
}
292300

301+
private void checkMediaType(final XmldbURI collectionUri, final DocInfo backupDocInfo) throws XMLDBException {
302+
final Collection collection = DatabaseManager.getCollection(XmldbURI.create(getBaseUri()).append(collectionUri).toString(), TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD);
303+
final Resource resource = collection.getResource(backupDocInfo.name);
304+
if (backupDocInfo.type == MimeType.XML) {
305+
assertTrue(resource instanceof XMLResource);
306+
} else {
307+
assertTrue(resource instanceof BinaryResource);
308+
}
309+
if (backupDocInfo.mediaType != null) {
310+
assertEquals(backupDocInfo.mediaType, ((EXistResource) resource).getMimeType());
311+
} else {
312+
assertEquals(backupDocInfo.type == MimeType.XML ? MimeType.XML_TYPE.getName() : MimeType.BINARY_TYPE.getName(), ((EXistResource) resource).getMimeType());
313+
}
314+
}
315+
293316
private static Path createZipBackupWithValidContent() throws IOException {
294317
final Path dbContentsFile = createBackupWithValidContent();
295318
final Path dbDir = dbContentsFile.getParent();
296319
return zipDirectory(dbDir);
297320
}
298321

299322
private static Path createBackupWithValidContent() throws IOException {
323+
300324
final Path backupDir = tempFolder.newFolder().toPath();
301325
final Path db = Files.createDirectories(backupDir.resolve("db"));
302-
final Path col1 = Files.createDirectories(db.resolve("col1"));
326+
final Path col1 = Files.createDirectories(db.resolve(COLLECTION1_NAME));
303327

304328
final String dbContents =
305329
"<collection xmlns=\"http://exist.sourceforge.net/NS/exist\" name=\"/db\" owner=\"SYSTEM\" group=\"dba\" mode=\"755\" created=\"2019-05-15T15:58:39.385+04:00\" version=\"1\">\n" +
306330
" <acl entries=\"0\" version=\"1\"/>\n" +
307-
" <subcollection name=\"col1\" filename=\"col1\"/>\n" +
331+
" <subcollection name=\"" + COLLECTION1_NAME + "\" filename=\"" + COLLECTION1_NAME + "\"/>\n" +
308332
"</collection>";
309333

310334

311-
final String col1Contents =
312-
"<collection xmlns=\"http://exist.sourceforge.net/NS/exist\" name=\"/db/col1\" owner=\"admin\" group=\"dba\" mode=\"755\" created=\"2019-05-15T15:58:39.385+04:00\" deduplicate-blobs=\"false\" version=\"2\">\n" +
313-
" <acl entries=\"0\" version=\"1\"/>\n" +
314-
" <resource type=\"XMLResource\" name=\"doc1.xml\" owner=\"admin\" group=\"dba\" mode=\"644\" created=\"2019-05-15T15:58:48.638+04:00\" modified=\"2019-05-15T15:58:48.638+04:00\" filename=\"doc1.xml\" mimetype=\"application/xml\">\n" +
315-
" <acl entries=\"0\" version=\"1\"/>\n" +
316-
" </resource>\n" +
317-
" <resource type=\"XMLResource\" name=\"doc2.xml\" owner=\"admin\" group=\"dba\" mode=\"644\" created=\"2019-05-15T15:58:48.638+04:00\" modified=\"2019-05-15T15:58:48.638+04:00\" filename=\"doc2.xml\" mimetype=\"application/xml\">\n" +
318-
" <acl entries=\"0\" version=\"1\"/>\n" +
319-
" </resource>\n" +
320-
" <resource type=\"XMLResource\" name=\"doc3.xml\" owner=\"admin\" group=\"dba\" mode=\"644\" created=\"2019-05-15T15:58:49.618+04:00\" modified=\"2019-05-15T15:58:49.618+04:00\" filename=\"doc3.xml\" mimetype=\"application/special-xml\">\n" +
321-
" <acl entries=\"0\" version=\"1\"/>\n" +
322-
" </resource>\n" +
323-
" <resource type=\"BinaryResource\" name=\"doc4.html\" owner=\"admin\" group=\"dba\" mode=\"644\" created=\"2019-05-15T15:58:49.618+04:00\" modified=\"2019-05-15T15:58:49.618+04:00\" filename=\"doc4.html\" mimetype=\"text/xhtml\">\n" +
324-
" <acl entries=\"0\" version=\"1\"/>\n" +
325-
" </resource>\n" +
326-
" <resource type=\"BinaryResource\" name=\"doc5.html\" owner=\"admin\" group=\"dba\" mode=\"644\" created=\"2019-05-15T15:58:49.618+04:00\" modified=\"2019-05-15T15:58:49.618+04:00\" filename=\"doc5.html\" mimetype=\"text/html\">\n" +
327-
" <acl entries=\"0\" version=\"1\"/>\n" +
328-
" </resource>\n" +
329-
"</collection>";
330-
331-
final String doc1 = "<doc1/>";
332-
final String doc2 = "<doc2/>";
333-
final String doc3 = "<doc3/>";
334-
final String doc4 = "<html><body><hr/></body></html>";
335-
final String doc5 = "<html><body><hr></body></html>";
335+
final StringBuilder col1Contents = new StringBuilder();
336+
col1Contents.append("<collection xmlns=\"http://exist.sourceforge.net/NS/exist\" name=\"/db/").append(COLLECTION1_NAME).append("\" owner=\"admin\" group=\"dba\" mode=\"755\" created=\"2019-05-15T15:58:39.385+04:00\" deduplicate-blobs=\"false\" version=\"2\">\n");
337+
col1Contents.append(" <acl entries=\"0\" version=\"1\"/>\n");
338+
for (final DocInfo backupDocInfo : BACKUP_DOCS) {
339+
col1Contents.append(" <resource type=\"").append(backupDocInfo.type == MimeType.XML ? "XMLResource" : "BinaryResource").append("\" name=\"").append(backupDocInfo.name).append("\" owner=\"admin\" group=\"dba\" mode=\"644\" created=\"2019-05-15T15:58:48.638+04:00\" modified=\"2019-05-15T15:58:48.638+04:00\" filename=\"").append(backupDocInfo.name).append(backupDocInfo.mediaType != null ? "\" mimetype=\"" + backupDocInfo.mediaType + "\">\n" : "\">\n");
340+
col1Contents.append(" <acl entries=\"0\" version=\"1\"/>\n");
341+
col1Contents.append(" </resource>\n");
342+
}
343+
col1Contents.append("</collection>");
336344

337345
final Path dbContentsFile = Files.write(db.resolve(BackupDescriptor.COLLECTION_DESCRIPTOR), dbContents.getBytes(UTF_8));
338-
final Path col1ContentsFile = Files.write(col1.resolve(BackupDescriptor.COLLECTION_DESCRIPTOR), col1Contents.getBytes(UTF_8));
339-
Files.write(col1.resolve("doc1.xml"), doc1.getBytes(UTF_8));
340-
Files.write(col1.resolve("doc2.xml"), doc2.getBytes(UTF_8));
341-
Files.write(col1.resolve("doc3.xml"), doc3.getBytes(UTF_8));
342-
Files.write(col1.resolve("doc4.html"), doc4.getBytes(UTF_8));
343-
Files.write(col1.resolve("doc5.html"), doc5.getBytes(UTF_8));
346+
final Path col1ContentsFile = Files.write(col1.resolve(BackupDescriptor.COLLECTION_DESCRIPTOR), col1Contents.toString().getBytes(UTF_8));
347+
for (final DocInfo backupDocInfo : BACKUP_DOCS) {
348+
Files.write(col1.resolve(backupDocInfo.name), backupDocInfo.content.getBytes(UTF_8));
349+
}
344350

345351
return dbContentsFile;
346352
}
@@ -633,4 +639,22 @@ public void error(final String message) {
633639
errors.add(message);
634640
}
635641
}
642+
643+
private static class DocInfo {
644+
final String name;
645+
final int type;
646+
@Nullable final String mediaType;
647+
final String content;
648+
649+
private DocInfo(final String name, final int type, final String content) {
650+
this(name, type, null, content);
651+
}
652+
653+
private DocInfo(final String name, final int type, final String mediaType, final String content) {
654+
this.name = name;
655+
this.type = type;
656+
this.mediaType = mediaType;
657+
this.content = content;
658+
}
659+
}
636660
}

0 commit comments

Comments
 (0)