Package org.apache.openjpa.persistence.cache.jpa

Source Code of org.apache.openjpa.persistence.cache.jpa.AbstractCacheModeTestCase$Action

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.   
*/
package org.apache.openjpa.persistence.cache.jpa;

import java.util.List;

import javax.persistence.Cache;
import javax.persistence.CacheRetrieveMode;
import javax.persistence.CacheStoreMode;
import javax.persistence.EntityManager;

import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.lib.jdbc.AbstractJDBCListener;
import org.apache.openjpa.lib.jdbc.JDBCEvent;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.cache.jpa.model.CacheEntity;
import org.apache.openjpa.persistence.cache.jpa.model.CacheableEntity;
import org.apache.openjpa.persistence.cache.jpa.model.NegatedCachableEntity;
import org.apache.openjpa.persistence.cache.jpa.model.NegatedUncacheableEntity;
import org.apache.openjpa.persistence.cache.jpa.model.UncacheableEntity;
import org.apache.openjpa.persistence.cache.jpa.model.UnspecifiedEntity;
import org.apache.openjpa.persistence.cache.jpa.model.XmlCacheableEntity;
import org.apache.openjpa.persistence.cache.jpa.model.XmlUncacheableEntity;

public abstract class AbstractCacheModeTestCase extends AbstractCacheTestCase {
    public abstract OpenJPAEntityManagerFactorySPI getEntityManagerFactory();

    public abstract List<String> getSql();

    protected abstract Class<?>[] getExpectedNotInCache();

    protected abstract Class<?>[] getExpectedInCache();

    // =======================================================================
    // Asserts
    // =======================================================================
    /**
     * Assert whether the cache contains the expected results.
     *
     * @param cache
     *            The JPA Cache to verify
     * @param expectCacheables
     *            Whether entities with @Cacheable(true) should be in the cache
     *            (almost always true)
     * @param expectUncacheables
     *            Whether entities with @Cacheable(false) should be in the cache
     *            (almost always false)
     * @param expectUnspecified
     *            Whether entities with no @Cacheable annotation should be in
     *            the cache (varies per config).
     */
    protected void assertCacheContents(Cache cache, boolean expectCacheables, boolean expectUncacheables,
        boolean expectUnspecified) {
        assertCacheables(cache, expectCacheables);
        assertUncacheables(cache, expectUncacheables);
        assertUnspecified(cache, expectUnspecified);
    }

    /**
     * Assert whether the cacheable types are in the cache. This method exits on
     * the first cache 'miss'.
     *
     * @param cache
     *            JPA Cache to verify
     * @param expected
     *            If true the cacheable types should be in the cache, if false
     *            they should not be.
     */
    protected void assertCacheables(Cache cache, boolean expected) {
        assertCached(cache, CacheableEntity.class, 1, expected);
        assertCached(cache, NegatedUncacheableEntity.class, 1, expected);
        assertCached(cache, XmlCacheableEntity.class, 1, expected);
    }

    /**
     * Assert whether the uncacheable types are in the cache. This method exits
     * on the first cache 'miss'.
     *
     * @param cache
     *            JPA Cache to verify
     * @param expected
     *            If true the uncacheable types should be in the cache, if false
     *            they should not be.
     */
    protected void assertUncacheables(Cache cache, boolean expected) {
        assertCached(cache, UncacheableEntity.class, 1, expected);
        assertCached(cache, XmlUncacheableEntity.class, 1, expected);
        assertCached(cache, NegatedCachableEntity.class, 1, expected);
    }

    /**
     * Assert whether the unspecified types are in the cache. This method exits
     * on the first cache 'miss'.
     *
     * @param cache
     *            JPA Cache to verify
     * @param expected
     *            If true the unspecified types should be in the cache, if false
     *            they should not be.
     */
    protected void assertUnspecified(Cache cache, boolean expected) {
        assertCached(cache, UnspecifiedEntity.class, 1, expected);
    }

    /**
     * Assert that no sql is executed when running the supplied Action.
     *
     * @param act
     *            Action to execute.
     */
    public void assertNoSql(Action act) {
        assertSqlInc(act, 0);
    }

    /**
     * Assert that <literal>expectedSqls</literal> SQL statements are executed
     * when running <literal>act</literal>
     *
     * @param act
     *            Action to run.
     * @param expectedSqls
     *            Number of SQL statements that should be executed.
     */
    public void assertSqlInc(Action act, int expectedSqls) {
        int before = getSql().size();
        act.run();
        assertEquals(before + expectedSqls, getSql().size());
    }

    // =======================================================================
    // Utility classes
    // =======================================================================
    /**
     * Basic 'runnable' interface used to run a set of commands, then analyze
     * the number of SQL statements that result.
     */
    public interface Action {
        public void run();
    }

    /**
     * Simple JDBCListener which stores the executed sql in a List. The List is
     * provided by the getSql() method so that subclasses may use separate
     * lists.
     */
    public class Listener extends AbstractJDBCListener {
        @Override
        public void beforeExecuteStatement(JDBCEvent event) {
            if (event.getSQL() != null && getSql() != null) {
                getSql().add(event.getSQL());
            }
        }
    }

    // =======================================================================
    // Test utilities
    // =======================================================================
    public boolean getCacheEnabled() {
        return true;
    }

    // =======================================================================
    // Common test methods.
    // =======================================================================
    /**
     * Ensure that each call the em.find generates an SQL statement when
     * CacheRetrieveMode.BYPASS is used.
     */
    public void testReadModeByass() {
        assertSqlInc(new Action() {
            public void run() {
                EntityManager em = getEntityManagerFactory().createEntityManager();
                em.setProperty(RETRIEVE_MODE_PROP, CacheRetrieveMode.BYPASS);
                for (Class<?> cls : persistentTypes) {
                    em.find(cls, 1);
                }
                em.close();
            }
        }, persistentTypes.length);
    }

    /**
     * <p>
     * Ensure that each entity in getExpectedInCache():
     * <ul>
     * <li>is in the cache</li>
     * <li>does not go to the database for a find operation</li>
     * <li>is not null</li>
     * </ul>
     * </p>
     * <p>
     * and
     * </p>
     * <p>
     * Ensure that each entity in getExpectedNotInCache() :
     * <ul>
     * <li>is not in the cache</li>
     * <li>results in a single SQL statement when em.find() is called</li>
     * <li>is not null</li>
     * </ul>
     * </p>
     *
     */
    public void testRetrieveModeUse() {
        assertNoSql(new Action() {
            public void run() {
                EntityManager em = getEntityManagerFactory().createEntityManager();
                em.setProperty(RETRIEVE_MODE_PROP, CacheRetrieveMode.USE);
                for (Class<?> cls : getExpectedInCache()) {
                    assertCached(getEntityManagerFactory().getCache(), cls, 1, true);
                    assertNotNull(em.find(cls, 1));
                }
                em.close();
            }
        });
        assertSqlInc(new Action() {
            public void run() {
                EntityManager em = getEntityManagerFactory().createEntityManager();
                em.setProperty(RETRIEVE_MODE_PROP, CacheRetrieveMode.USE);
                for (Class<?> cls : getExpectedNotInCache()) {
                    assertCached(getEntityManagerFactory().getCache(), cls, 1, false);
                    assertNotNull(em.find(cls, 1));
                }
                em.close();
            }
        }, getExpectedNotInCache().length);
    }

    public void updateAndFind(Class<? extends CacheEntity> classToUpdate, int idToUpdate,
            Class<? extends CacheEntity> classToFind, int idToFind,
            CacheStoreMode storeMode, CacheRetrieveMode retrieveMode) {
        EntityManager em = getEntityManagerFactory().createEntityManager();

        if (storeMode != null) {
            em.setProperty(STORE_MODE_PROP, storeMode);
        }
        if (retrieveMode != null) {
            em.setProperty(RETRIEVE_MODE_PROP, retrieveMode);
        }

        em.getTransaction().begin();
        CacheEntity ce1 = em.find(classToUpdate, idToUpdate);
        CacheEntity ce2 = em.find(classToFind, idToFind);
        assertNotNull(ce1);
        assertNotNull(ce2);
        ce1.setName(ce1.getName() + "UPD");
        em.getTransaction().commit();
        em.close();
    }

    /**
     * <p>
     * Test logic to validate different CacheStoreModes. It should behave
     * identically for all shared-cache-modes except NONE which never caches
     * anything.
     * </p>
     * <p>
     * This method only tests setting the store mode on the EntityManager
     * itself.
     * </p>
     * <p>
     * The first transaction updates CacheableEntity::1 with CacheStoreMode
     * tran1StoreMode, calls find for CacheableEntity::1 and
     * XmlCacheableEntity::1. This will never trigger a cache refresh since the
     * data is up to date - but it could trigger additional SQL
     * </p>
     * <p>
     * The second transaction updates XmlCacheableEntity::1 with CacheStoreMode
     * tran2StoreMode, calls find for CacheableEntity::1 and
     * XmlCacheableEntity::1. In this case if tran2StoreMode ==
     * CacheStoreMode.REFRESH we may update the cache with the state of
     * CacheableEntity::1.
     * </p>
     *
     * @param tran1StoreMode
     *            CacheStoreMode to use in transaction 1.
     * @param tran2StoreMode
     *            cacheStoreMode to use in transaction 2.
     * @param cacheUpdatedForTran1
     *            Whether the cache will contain an updated version of
     *            CacheableEntity::1
     * @param cacheUpdatedForTran2
     *            Whether the cache will contain an updated version of
     *            XmlCacheableEntity::1
     * @param version
     *            Expected starting version of for both entities
     */
    public void entityManagerStoreModeTest(CacheStoreMode tran1StoreMode, CacheStoreMode tran2StoreMode,
        boolean cacheUpdatedForTran1, boolean cacheUpdatedForTran2, int version) {
        updateAndFind(CacheableEntity.class, 1, XmlCacheableEntity.class, 1, tran1StoreMode, null);
        updateAndFind(XmlCacheableEntity.class, 1, CacheableEntity.class, 1, tran2StoreMode, null);

        // get entities from the cache and ensure their versions are as
        // expected.
        EntityManager em = getEntityManagerFactory().createEntityManager();
        em = getEntityManagerFactory().createEntityManager();
        CacheableEntity ceFromEM = em.find(CacheableEntity.class, 1);
        XmlCacheableEntity xceFromEM = em.find(XmlCacheableEntity.class, 1);
        em.close();
        assertEquals(cacheUpdatedForTran1 ? version + 1 : version, ceFromEM.getVersion());
        assertEquals(cacheUpdatedForTran2 ? version + 1 : version, xceFromEM.getVersion());

        // get the data from the database. Version should always have been
        // updated in this case.
        em = getEntityManagerFactory().createEntityManager();
        em.setProperty(RETRIEVE_MODE_PROP, CacheRetrieveMode.BYPASS);
        CacheableEntity ceFromDB =
            (CacheableEntity) em.createNativeQuery("Select * from CacheableEntity where id = 1", CacheableEntity.class)
                .getSingleResult();

        XmlCacheableEntity xceFromDB =
            (XmlCacheableEntity) em.createNativeQuery("Select * from XmlCacheableEntity where id = 1",
                XmlCacheableEntity.class).getSingleResult();

        assertEquals(version + 1, ceFromDB.getVersion());
        assertEquals(version + 1, xceFromDB.getVersion());
        em.close();
    }

    /**
     * Execute the defaultStoreModeTest with
     */
    public void testStoreModeUseBypass() throws Exception {
        if (getCacheEnabled()) {
            entityManagerStoreModeTest(CacheStoreMode.USE, CacheStoreMode.BYPASS, true, false, 1);
        }
    }

    public void testStoreModeUseUse() {
        if (getCacheEnabled()) {
            entityManagerStoreModeTest(CacheStoreMode.USE, CacheStoreMode.USE, true, true, 1);
        }
    }

    public void testStoreModeUseRefresh() {
        if (getCacheEnabled()) {
            entityManagerStoreModeTest(CacheStoreMode.USE, CacheStoreMode.REFRESH, true, true, 1);
        }
    }

    public void entityManagerStoreModeTest() {
        if (getCacheEnabled()) {
            entityManagerStoreModeTest(CacheStoreMode.BYPASS, CacheStoreMode.BYPASS, false, false, 1);
        }
    }

    public void testStoreModeBypassUse() {
        if (getCacheEnabled()) {
            entityManagerStoreModeTest(CacheStoreMode.BYPASS, CacheStoreMode.USE, false, true, 1);
        }
    }

    public void testStoreModeBypassRefresh() {
        if (getCacheEnabled()) {
            // REFRESH picks up the changes from the database, even though the
            // first update was done with BYPASS
            entityManagerStoreModeTest(CacheStoreMode.BYPASS, CacheStoreMode.REFRESH, true, true, 1);
        }
    }

    public void testStoreModeRefreshUse() {
        if (getCacheEnabled()) {
            entityManagerStoreModeTest(CacheStoreMode.REFRESH, CacheStoreMode.USE, true, true, 1);
        }
    }

    public void testStoreModeRefreshBypass() {
        if (getCacheEnabled()) {
            entityManagerStoreModeTest(CacheStoreMode.REFRESH, CacheStoreMode.BYPASS, true, false, 1);
        }
    }

    public void testStoreModeRefreshRefresh() {
        if (getCacheEnabled()) {
            entityManagerStoreModeTest(CacheStoreMode.REFRESH, CacheStoreMode.REFRESH, true, true, 1);
        }
    }
   
    public void testResultsFromQueryAreInCache() {
        // clear cache
        getEntityManagerFactory().getStoreCache().evictAll();
        getEntityManagerFactory().getQueryResultCache().evictAll();

        EntityManager em = getEntityManagerFactory().createEntityManager();
        String query;
        for(Class<?> cls : persistentTypes) {
            query = "Select e from " + getAlias(cls) + " e";
            List<?> res = em.createQuery(query).getResultList();
            assertNotNull(String.format("Expected to find some results when running query %s",query), res);
            assertTrue(String.format("Expected more than 0 results running query %s",query),res.size() != 0 ) ;
        }
        for(Class<?> cls : getExpectedInCache()) {
            assertCached(getEntityManagerFactory().getCache(), cls, 1, true);
        }
       
        for(Class<?> cls : getExpectedNotInCache()) {
            assertCached(getEntityManagerFactory().getCache(), cls, 1, false);
        }
        em.close();
    }
   
    public void testResultsFromFindAreInCache() {
        // clear cache
        getEntityManagerFactory().getStoreCache().evictAll();
        getEntityManagerFactory().getQueryResultCache().evictAll();

        EntityManager em = getEntityManagerFactory().createEntityManager();
        for(Class<?> cls : persistentTypes) {
            assertNotNull(String.format("Expected to find %s::%d from database or from cache", cls, 1),em.find(cls, 1));
        }
        for(Class<?> cls : getExpectedInCache()) {
            assertCached(getEntityManagerFactory().getCache(), cls, 1, true);
        }
       
        for(Class<?> cls : getExpectedNotInCache()) {
            assertCached(getEntityManagerFactory().getCache(), cls, 1, false);
        }
        em.close();
    }
   
    private String getAlias(Class<?> cls) {
        ClassMapping mapping =
            (ClassMapping) getEntityManagerFactory().getConfiguration().getMetaDataRepositoryInstance().getMetaData(
                cls, null, true);
        return mapping.getTypeAlias();
    }
}
TOP

Related Classes of org.apache.openjpa.persistence.cache.jpa.AbstractCacheModeTestCase$Action

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.