/**
 * This software program, Simple Data Access Layer (SDAL), is copyrighted by Object
 * Computing inc of St. Louis MO USA. It is provided under the open-source model
 * and is free of license fees. You are free to modify this code for your own use
 * but you may not claim copyright.
 *
 * Since SDAL is open source and free of licensing fees, you are free to use,
 * modify, and distribute the source code, as long as you include this copyright
 * statement.
 *
 * In particular, you can use SDAL to build proprietary software and are under no
 * obligation to redistribute any of your source code that is built using SDAL.
 * Note, however, that you may not do anything to the SDAL code, such as
 * copyrighting it yourself or claiming authorship of the SDAL code, that will
 * prevent SDAL from being distributed freely using an open source development
 * model.
 *
 * Warranty
 * LICENSED PRODUCT, SDAL, IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE,
 * NONINFRINGEMENT, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 *
 * Support
 * LICENSED PRODUCT, SDAL, IS PROVIDED WITH NO SUPPORT AND WITHOUT ANY OBLIGATION ON THE
 * PART OF OCI OR ANY OF ITS SUBSIDIARIES OR AFFILIATES TO ASSIST IN ITS USE,
 * CORRECTION, MODIFICATION OR ENHANCEMENT.
 *
 * Support may be available from OCI to users who have agreed to a support
 * contract.
 *
 * Liability
 * OCI OR ANY OF ITS SUBSIDIARIES OR AFFILIATES SHALL HAVE NO LIABILITY WITH
 * RESPECT TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY
 * LICENSED PRODUCT OR ANY PART THEREOF.
 *
 * IN NO EVENT WILL OCI OR ANY OF ITS SUBSIDIARIES OR AFFILIATES BE LIABLE FOR ANY
 * LOST REVENUE OR PROFITS OR OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL DAMAGES,
 * EVEN IF OCI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * Copyright OCI. St. Louis MO USA, 2004
 *
 */
package com.ociweb.service;

import junit.framework.TestCase;
import net.sf.hibernate.MockSession;
import net.sf.hibernate.MockTransaction;
import net.sf.hibernate.HibernateException;
import com.ociweb.domain.FooMgr;
import com.ociweb.bean.Foo;
import com.ociweb.service.ServiceLocatorException;
import com.ociweb.service.ServiceLocatorImpl;
import com.ociweb.service.ThreadSessionHolder;

import java.util.Collection;
import java.util.ArrayList;
import java.util.List;

public class ServiceLocatorTest extends TestCase {
    private MockSession session;
    private ServiceLocatorImpl locator;
    private MockTransaction transaction;
    private static final String HEYNOW = "heynow";

    protected void setUp() throws Exception {
        session = new MockSession();
        transaction = new MockTransaction();
        session.beginTransactionReturn = transaction;
        session.getNamedQueryReturn = new net.sf.hibernate.MockQuery();
        ThreadSessionHolder.set(session);

        locator = new ServiceLocatorImpl();
    }

    protected void tearDown() throws Exception {
        ThreadSessionHolder.set(null);
    }

    public void testGetManagerSuccess() throws Exception {
        GoodMgr goodMgr = (GoodMgr) locator.getDomainObjectManager(GoodMgr.class);
        assertNotNull(goodMgr);
    }

    public void testGetManagerFailureNotAnInterface() {
        try {
            locator.getDomainObjectManager(Object.class);
            fail("ServiceLocator should not allow non-interfaces to be passed in");
        } catch (ServiceLocatorException sle) {
        }
    }

    public void testGetManagerFailureDoesNotImplementCRUDlikeInterface() {
        try {
            locator.getDomainObjectManager(FooInterface.class);
            fail("ServiceLocator should not allow interfaces with non-crud-like APIs to be passed in");
        } catch (ServiceLocatorException sle) {
        }
    }

    public void testTargetFindByPrimaryKeySuccess() throws Exception {
        Object returnValue = new Object();
        session.load2Return = returnValue;
        GoodMgr clientMgr = (GoodMgr) locator.getDomainObjectManager(GoodMgr.class);
        assertFalse(session.beginTransactionCalled);
        assertFalse(session.saveCalled);
        Long id = new Long(1L);
        Object obj = clientMgr.findByPrimaryKey(id);
        assertEquals(returnValue, obj);
        assertFalse(session.beginTransactionCalled);
        assertTrue(session.load2Called);
        assertEquals(Object.class, session.load2TheClass);
        assertEquals(id, session.load2Id);
    }

    public void testTargetFindByPrimaryKeyFailure() throws ServiceLocatorException {
        session.load2Exception = new HibernateException("Foo");
        GoodMgr clientMgr = (GoodMgr) locator.getDomainObjectManager(GoodMgr.class);
        assertFalse(session.beginTransactionCalled);
        assertFalse(session.saveCalled);
        Long id = new Long(1L);
        try {
            Object obj = clientMgr.findByPrimaryKey(id);
            fail("The FindByPK should throw a LookupException when no record is found");
        } catch (com.ociweb.service.LookupException le) {
        }
    }

    public void testFindAll() throws Exception {
        List beans = new ArrayList();
        beans.add(new Foo());
        session.findReturn = beans;
        FooMgr fooMgr = (FooMgr) locator.getDomainObjectManager(FooMgr.class);
        assertFalse(session.beginTransactionCalled);
        assertFalse(session.saveCalled);
        Collection result = fooMgr.findAll();
        assertTrue(session.findCalled);
        assertEquals(beans, result);
        assertEquals("from Foo", session.findQuery);
    }

    public void testAddTargetRecord() throws Exception {
        GoodMgr clientMgr = (GoodMgr) locator.getDomainObjectManager(GoodMgr.class);
        assertFalse(session.beginTransactionCalled);
        assertFalse(session.saveCalled);
        Object target = new Object();
        clientMgr.add(target);
        assertTrue(session.beginTransactionCalled);
        assertTrue(session.saveCalled);
        assertTrue(transaction.commitCalled);
        assertEquals(target, session.saveObject);
    }

    public void testAddTargetRecordFailureNullTarget() throws Exception {
        GoodMgr clientMgr = (GoodMgr) locator.getDomainObjectManager(GoodMgr.class);
        assertFalse(session.beginTransactionCalled);
        assertFalse(session.saveCalled);
        try {
            clientMgr.add(null);
            fail("ServiceLocator should not all saving null targets");
        } catch (com.ociweb.service.PersistenceException pe) {
            assertFalse(session.beginTransactionCalled);
            assertFalse(session.saveCalled);
            assertFalse(transaction.commitCalled);
        }
    }

    public void testUpdateTargetRecord() throws Exception {
        GoodMgr clientMgr = (GoodMgr) locator.getDomainObjectManager(GoodMgr.class);
        assertFalse(session.beginTransactionCalled);
        assertFalse(session.saveCalled);
        Object target = new Object();
        clientMgr.update(target);
        assertTrue(session.beginTransactionCalled);
        assertTrue(session.updateCalled);
        assertTrue(transaction.commitCalled);
        assertEquals(target, session.updateObject);
    }

    public void testRemoveTargetRecord() throws Exception {
        GoodMgr clientMgr = (GoodMgr) locator.getDomainObjectManager(GoodMgr.class);
        assertFalse(session.beginTransactionCalled);
        assertFalse(session.saveCalled);
        Object target = new Object();
        clientMgr.remove(target);
        assertTrue(session.beginTransactionCalled);
        assertTrue(session.deleteCalled);
        assertTrue(transaction.commitCalled);
        assertEquals(target, session.deleteObject);
    }

    public void testArbitraryFinder() throws Exception {
        AnotherMgr anotherMgr = (AnotherMgr)locator.getDomainObjectManager(AnotherMgr.class);
        assertFalse(session.beginTransactionCalled);
        Collection result = anotherMgr.findBySomeString(HEYNOW);
        assertTrue(session.getNamedQueryCalled);
        assertEquals("com.ociweb.service.ServiceLocatorTest$AnotherMgr.findBySomeString",
                     session.getNamedQueryQueryName);
    }

    private static interface FooInterface {
        void bar();
    }

    private static interface GoodMgr {
        public void add(Object target) throws com.ociweb.service.PersistenceException;

        public void remove(Object target) throws com.ociweb.service.PersistenceException;

        public void update(Object target) throws com.ociweb.service.PersistenceException;

        public Object findByPrimaryKey(Long id) throws com.ociweb.service.LookupException;

        public Collection findAll() throws com.ociweb.service.LookupException;
    }

    private static interface AnotherMgr extends GoodMgr {
        public Collection findBySomeString(String value) throws com.ociweb.service.LookupException;
    }
}
