package org.exist.storage;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.exist.collections.triggers.TriggerException;
import org.exist.security.PermissionDeniedException;
import org.exist.util.LockException;
import org.junit.BeforeClass;
import org.exist.dom.persistent.BinaryDocument;
import org.exist.EXistException;
import org.exist.xmldb.XmldbURI;
import org.exist.test.TestConstants;
import org.exist.collections.Collection;
import org.exist.Database;
import org.exist.start.Main;
import org.exist.storage.txn.TransactionManager;
import org.exist.storage.txn.Txn;
import org.junit.Test;
import static org.junit.Assert.*;
import org.exist.util.ConfigurationHelper;

/**
 *
 * @author aretter
 */
public class StoreBinaryTest {

    @BeforeClass
    public static void ensureCleanDatabase() throws IOException {
        final File home = ConfigurationHelper.getExistHome();
        final File data = new File(home, "webapp/WEB-INF/data");

        final File dataFiles[] = data.listFiles(new FilenameFilter(){
            @Override
            public boolean accept(File file, String name) {
                return name.endsWith(".dbx") || name.endsWith(".journal") || name.endsWith(".log");
            }
        });

        for(final File dataFile : dataFiles){
            dataFile.delete();
        }

        for(final String subFolderName : new String[]{"journal", "fs", "sanity", "lucene"} ) {
            final File subFolder = new File(data, subFolderName);
            if(subFolder.exists()) {
                FileUtils.deleteDirectory(subFolder);
            }
        }
    }

    @Test
    public void check_MimeType_is_preserved() throws EXistException, InterruptedException, PermissionDeniedException, LockException, IOException, TriggerException {

        final String xqueryMimeType = "application/xquery";
        final String xqueryFilename = "script.xql";
        final String xquery = "current-dateTime()";

        Main database = startupDatabase();
        try {
            //store the xquery document
            BinaryDocument binaryDoc = storeBinary(xqueryFilename, xquery, xqueryMimeType);
            assertNotNull(binaryDoc);
            assertEquals(xqueryMimeType, binaryDoc.getMetadata().getMimeType());

            //make a note of the binary documents uri
            final XmldbURI binaryDocUri = binaryDoc.getFileURI();

            //restart the database
            stopDatabase(database);
            Thread.sleep(3000);
            database = startupDatabase();

            //retrieve the xquery document
            binaryDoc = getBinary(binaryDocUri);
            assertNotNull(binaryDoc);

            //check the mimetype has been preserved across database restarts
            assertEquals(xqueryMimeType, binaryDoc.getMetadata().getMimeType());

        } finally {
            stopDatabase(database);
        }
    }

    private Main startupDatabase() {
        Main database = new org.exist.start.Main("jetty");
        database.run(new String[]{"jetty"});
        return database;
    }

    private void stopDatabase(final Main database) {
        try {
            database.shutdown();
        } catch (Exception e) {
            // do not fail. exceptions may occur at this point.
            e.printStackTrace();
        }
    }

    private BinaryDocument getBinary(final XmldbURI uri) throws EXistException, PermissionDeniedException {
        BinaryDocument binaryDoc = null;
        final Database pool = BrokerPool.getInstance();

        try(final DBBroker broker = pool.get(pool.getSecurityManager().getSystemSubject());) {
            assertNotNull(broker);

            final Collection root = broker.getCollection(TestConstants.TEST_COLLECTION_URI);
            assertNotNull(root);

            binaryDoc = (BinaryDocument)root.getDocument(broker, uri);

        }

        return binaryDoc;
    }

    private BinaryDocument storeBinary(String name,  String data, String mimeType) throws EXistException, PermissionDeniedException, IOException, TriggerException, LockException {
        final Database pool = BrokerPool.getInstance();;
        final TransactionManager transact = pool.getTransactionManager();

        BinaryDocument binaryDoc = null;
        try(final DBBroker broker = pool.get(pool.getSecurityManager().getSystemSubject());
                final Txn transaction = transact.beginTransaction()) {

            final Collection root = broker.getOrCreateCollection(transaction, TestConstants.TEST_COLLECTION_URI);
    		broker.saveCollection(transaction, root);
            assertNotNull(root);

            binaryDoc = root.addBinaryResource(transaction, broker, XmldbURI.create(name), data.getBytes(), mimeType);

            transact.commit(transaction);
        }

        return binaryDoc;
    }
}

@@ -1032,32 +1032,34 @@
       final File
+%5B%5D
  dataFiles%5B%5D = d
@@ -1052,18 +1052,16 @@
 ataFiles
-%5B%5D
  = data.
@@ -1090,16 +1090,17 @@
 Filter()
+ 
 %7B%0A      
@@ -1153,18 +1153,29 @@
 ept(
-File file,
+final File dir, final
  Str
@@ -1213,82 +1213,91 @@
 urn 
+!(
 name.e
-ndsWith(%22.dbx%22) %7C%7C name.endsWith(%22.journal%22) %7C%7C name.endsWith(%22.log%22
+quals(%22RECOVERY%22) %7C%7C name.equals(%22README%22) %7C%7C name.equals(%22.DO_NOT_DELETE%22)
 );%0A 
@@ -1366,16 +1366,17 @@
 taFiles)
+ 
 %7B%0A      
@@ -1385,303 +1385,42 @@
     
-dataFile.delete();%0A        %7D%0A%0A        for(final String subFolderName : new String%5B%5D%7B%22journal%22, %22fs%22, %22sanity%22, %22lucene%22%7D ) %7B%0A            final File subFolder = new File(data, subFolderName);%0A            if(subFolder.exists()) %7B%0A                FileUtils.deleteDirectory(subFolder);%0A            %7D
+FileUtils.deleteQuietly(dataFile);
 %0A   

Make sure to correctly clean out the data folder, otherwise repeating test can show failure