/*
 * $Id: ServerNotificationManagerTestCase.java 10489 2008-01-23 17:53:38Z dfeist $
 * --------------------------------------------------------------------------------------
 * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */

package org.mule.context.notification;

import org.mule.tck.AbstractMuleTestCase;

public class ServerNotificationManagerTestCase extends AbstractMuleTestCase
{

    protected Listener1 listener1;
    protected Listener2 listener2;
    protected ServerNotificationManager manager;

    protected void doSetUp() throws Exception
    {
        listener1 = new Listener1();
        listener2 = new Listener2();
        manager = new ServerNotificationManager();
    }

    protected void registerDefaultEvents() throws ClassNotFoundException
    {
        manager.addInterfaceToType(Listener1.class, SubEvent1.class);
        manager.addInterfaceToType(Listener2.class, Event2.class);
    }

    public void testNoListenersMeansNoEvents() throws ClassNotFoundException
    {
        registerDefaultEvents();
        assertNoEventsEnabled();
    }

    protected void assertNoEventsEnabled()
    {
        assertFalse(manager.isNotificationEnabled(Event1.class));
        assertFalse(manager.isNotificationEnabled(SubEvent1.class));
        assertFalse(manager.isNotificationEnabled(SubSubEvent1.class));
        assertFalse(manager.isNotificationEnabled(Event2.class));
        assertFalse(manager.isNotificationEnabled(SubEvent2.class));
        assertFalse(manager.isNotificationEnabled(Event3.class));
    }

    protected void registerDefaultListeners()
    {
        manager.addListenerSubscription(listener1, "id1");
        manager.addListener(listener2);
    }

    public void testAssociationOfInterfacesAndEvents() throws ClassNotFoundException
    {
        registerDefaultEvents();
        registerDefaultListeners();
        assertStandardEventsEnabled();
    }

    protected void assertStandardEventsEnabled()
    {
        assertTrue("via subclass", manager.isNotificationEnabled(Event1.class));
        assertTrue("direct", manager.isNotificationEnabled(SubEvent1.class));
        assertTrue("via superclass", manager.isNotificationEnabled(SubSubEvent1.class));
        assertTrue("direct", manager.isNotificationEnabled(Event2.class));
        assertTrue("via superclass", manager.isNotificationEnabled(SubEvent2.class));
        assertFalse("not specified at all", manager.isNotificationEnabled(Event3.class));
    }

    public void testDynamicResponseToDisablingEvents() throws ClassNotFoundException
    {
        registerDefaultEvents();
        registerDefaultListeners();
        assertStandardEventsEnabled();
        // now disable event 2
        manager.disableType(Event2.class);
        assertTrue("via subclass", manager.isNotificationEnabled(Event1.class));
        assertTrue("direct", manager.isNotificationEnabled(SubEvent1.class));
        assertFalse("disabled", manager.isNotificationEnabled(Event2.class));
        assertFalse("no listener", manager.isNotificationEnabled(SubEvent2.class));
        assertFalse("not specified at all", manager.isNotificationEnabled(Event3.class));
        // the subclass should be blocked too
        manager.addInterfaceToType(Listener2.class, SubEvent2.class);
        assertTrue("via subclass", manager.isNotificationEnabled(Event1.class));
        assertTrue("direct", manager.isNotificationEnabled(SubEvent1.class));
        assertFalse("disabled", manager.isNotificationEnabled(Event2.class));
        assertFalse("disabled", manager.isNotificationEnabled(SubEvent2.class));
        assertFalse("not specified at all", manager.isNotificationEnabled(Event3.class));
    }

    public void testDynamicResponseToDisablingInterfaces() throws ClassNotFoundException
    {
        registerDefaultEvents();
        registerDefaultListeners();
        assertStandardEventsEnabled();
        // now disable listener 1
        manager.disableInterface(Listener1.class);
        assertFalse("via subclass, but no listener", manager.isNotificationEnabled(Event1.class));
        assertFalse("disabled", manager.isNotificationEnabled(SubEvent1.class));
        assertFalse("via superclass, but no listener", manager.isNotificationEnabled(SubSubEvent1.class));
        assertTrue("direct", manager.isNotificationEnabled(Event2.class));
        assertTrue("via superclass", manager.isNotificationEnabled(SubEvent2.class));
        assertFalse("not specified at all", manager.isNotificationEnabled(Event3.class));
    }

    /**
     * A new policy should only be generated when the configuration changes
     */
    public void testPolicyCaching() throws ClassNotFoundException
    {
        registerDefaultEvents();
        registerDefaultListeners();
        Policy policy = manager.getPolicy();
        assertStandardEventsEnabled();
        assertSame(policy, manager.getPolicy());
        manager.disableType(Event2.class);
        assertNotSame(policy, manager.getPolicy());
    }

    public void testDynamicManagerDecisions() throws ClassNotFoundException
    {
        registerDefaultEvents();
        registerDefaultListeners();
        manager.setNotificationDynamic(true);
        OptimisedNotificationHandler decision = new OptimisedNotificationHandler(manager, Event2.class);
        assertTrue(decision.isNotificationEnabled(Event2.class));
        manager.disableType(Event2.class);
        assertFalse(decision.isNotificationEnabled(Event2.class));
    }

    /**
     * When the manager is not dynamic (the default), decisions should not change
     */
    public void testNonDynamicManagerDecisions() throws ClassNotFoundException
    {
        registerDefaultEvents();
        registerDefaultListeners();
        OptimisedNotificationHandler decision = new OptimisedNotificationHandler(manager, Event2.class);
        assertTrue(decision.isNotificationEnabled(Event2.class));
        manager.disableType(Event2.class);
        assertTrue(decision.isNotificationEnabled(Event2.class));
    }

    public void testNotification() throws ClassNotFoundException
    {
        registerDefaultEvents();
        registerDefaultListeners();
        assertNoListenersNotified();
        manager.notifyListeners(new Event1());
        assertNoListenersNotified();
        manager.notifyListeners(new SubEvent1());
        assertNoListenersNotified();
        manager.notifyListeners(new Event1("id1"));
        assertNoListenersNotified();
        manager.notifyListeners(new SubSubEvent1("id1"));
        assertTrue(listener1.isNotified());
        assertFalse(listener2.isNotified());
        manager.notifyListeners(new Event2());
        assertTrue(listener1.isNotified());
        assertTrue(listener2.isNotified());
    }

    protected void assertNoListenersNotified()
    {
        assertFalse(listener1.isNotified());
        assertFalse(listener2.isNotified());
    }

}
