org.nuxeo.ecm.core.TestSQLRepositoryReadAcls.java Source code

Java tutorial

Introduction

Here is the source code for org.nuxeo.ecm.core.TestSQLRepositoryReadAcls.java

Source

/*
 * Copyright (c) 2014 Nuxeo SA (http://nuxeo.com/) and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Florent Guillaume
 */
package org.nuxeo.ecm.core;

import static org.junit.Assert.assertEquals;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Ignore;
import org.junit.Test;
import org.nuxeo.ecm.core.api.ClientException;
import org.nuxeo.ecm.core.api.CoreInstance;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.security.ACE;
import org.nuxeo.ecm.core.api.security.impl.ACLImpl;
import org.nuxeo.ecm.core.api.security.impl.ACPImpl;
import org.nuxeo.ecm.core.query.sql.NXQL;
import org.nuxeo.ecm.core.storage.sql.TXSQLRepositoryTestCase;
import org.nuxeo.runtime.transaction.TransactionHelper;

/**
 * Tests read ACLs behavior in a transactional setting.
 */
public class TestSQLRepositoryReadAcls extends TXSQLRepositoryTestCase {

    protected static final Log log = LogFactory.getLog(TestSQLRepositoryJTAJCA.class);

    @Test
    public void testParallelPrepareUserReadAcls() throws Throwable {
        doParallelPrepareUserReadAcls(0);
    }

    // fails on SQL Server sometimes (expected:<1> but was:<0>)
    @Ignore
    @Test
    public void testParallelPrepareUserReadAclsMany() throws Throwable {
        for (int i = 0; i < 100; i++) {
            log.debug("try " + i);
            doParallelPrepareUserReadAcls(i);
        }
    }

    protected void doParallelPrepareUserReadAcls(int i) throws Throwable {
        // set ACP on root
        ACPImpl acp = new ACPImpl();
        ACLImpl acl = new ACLImpl();
        String username = "user" + i;
        acl.add(new ACE("Administrator", "Everything", true));
        acl.add(new ACE(username, "Everything", true));
        acp.addACL(acl);
        String name = "doc" + i;
        DocumentModel doc = session.createDocumentModel("/", name, "File");
        doc = session.createDocument(doc);
        doc.setACP(acp, true);
        session.save();

        closeSession();
        TransactionHelper.commitOrRollbackTransaction();

        CyclicBarrier barrier = new CyclicBarrier(2);
        CountDownLatch firstReady = new CountDownLatch(1);
        PrepareUserReadAclsJob r1 = new PrepareUserReadAclsJob(name, username, database.repositoryName, firstReady,
                barrier);
        PrepareUserReadAclsJob r2 = new PrepareUserReadAclsJob(name, username, database.repositoryName, null,
                barrier);
        Thread t1 = null;
        Thread t2 = null;
        try {
            t1 = new Thread(r1, "t1");
            t2 = new Thread(r2, "t2");
            t1.start();
            if (firstReady.await(60, TimeUnit.SECONDS)) {
                t2.start();

                t1.join();
                t1 = null;
                t2.join();
                t2 = null;
                if (r1.throwable != null) {
                    throw r1.throwable;
                }
                if (r2.throwable != null) {
                    throw r2.throwable;
                }
            } // else timed out
        } finally {
            // error condition recovery
            if (t1 != null) {
                t1.interrupt();
            }
            if (t2 != null) {
                t2.interrupt();
            }
        }

        // after both threads have run, check that we don't see
        // duplicate documents
        TransactionHelper.startTransaction();
        session = openSessionAs(username);
        checkOneDoc(session, name); // failed for PostgreSQL
        closeSession();
        TransactionHelper.commitOrRollbackTransaction();

        TransactionHelper.startTransaction();
        openSession();
    }

    protected static void checkOneDoc(CoreSession session, String name) throws ClientException {
        String query = "SELECT * FROM File WHERE ecm:isProxy = 0 AND ecm:name = '" + name + "'";
        DocumentModelList res = session.query(query, NXQL.NXQL, null, 0, 0, false);
        assertEquals(1, res.size());
    }

    protected static class PrepareUserReadAclsJob implements Runnable {

        private String name;

        private String username;

        private String repositoryName;

        public CountDownLatch ready;

        public CyclicBarrier barrier;

        public Throwable throwable;

        public PrepareUserReadAclsJob(String name, String username, String repositoryName, CountDownLatch ready,
                CyclicBarrier barrier) {
            this.name = name;
            this.username = username;
            this.repositoryName = repositoryName;
            this.ready = ready;
            this.barrier = barrier;
        }

        @Override
        public void run() {
            TransactionHelper.startTransaction();
            try (CoreSession session = CoreInstance.openCoreSession(repositoryName, username)) {
                if (ready != null) {
                    ready.countDown();
                    ready = null;
                }
                barrier.await(30, TimeUnit.SECONDS); // (throws on timeout)
                barrier = null;
                checkOneDoc(session, name); // fails for Oracle
            } catch (Throwable t) {
                t.printStackTrace();
                throwable = t;
            } finally {
                TransactionHelper.commitOrRollbackTransaction();
                // error recovery
                // still count down as main thread is awaiting us
                if (ready != null) {
                    ready.countDown();
                }
                // break barrier for other thread
                if (barrier != null) {
                    barrier.reset(); // break barrier
                }
            }
        }
    }

}