/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.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.runtime.core.registry; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import org.mule.runtime.api.lifecycle.Disposable; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.context.MuleContextAware; import org.mule.runtime.core.api.registry.RegistrationException; import org.mule.tck.junit4.AbstractMuleContextTestCase; import java.util.ArrayList; import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.junit.Test; import org.slf4j.Logger; public class TransientRegistryTestCase extends AbstractMuleContextTestCase { private static final String LIFECYCLE_PHASES = "[setMuleContext, initialise, start, stop, dispose]"; public static final String TEST_KEY = "test"; @Test public void testObjectLifecycle() throws Exception { muleContext.start(); InterfaceBasedTracker tracker = new InterfaceBasedTracker(); muleContext.getRegistry().registerObject(TEST_KEY, tracker); muleContext.dispose(); assertEquals(LIFECYCLE_PHASES, tracker.getTracker().toString()); } @Test public void testObjectLifecycleDoubleRegistration() throws Exception { muleContext.start(); InterfaceBasedTracker tracker1 = new InterfaceBasedTracker(); muleContext.getRegistry().registerObject(TEST_KEY, tracker1); InterfaceBasedTracker tracker2 = new InterfaceBasedTracker(); muleContext.getRegistry().registerObject(TEST_KEY, tracker2); InterfaceBasedTracker tracker3 = new InterfaceBasedTracker(); muleContext.getRegistry().registerObject(TEST_KEY, tracker3); muleContext.dispose(); assertEquals(LIFECYCLE_PHASES, tracker1.getTracker().toString()); assertEquals(LIFECYCLE_PHASES, tracker2.getTracker().toString()); assertEquals(LIFECYCLE_PHASES, tracker3.getTracker().toString()); } @Test public void doesNotTracksNonDisposableOverriddenObjects() throws Exception { final Logger log = mock(Logger.class); final TransientRegistry.RegistryMap registryMap = new TransientRegistry.RegistryMap(log); Object value1 = new Object(); Object value2 = new Object(); registryMap.putAndLogWarningIfDuplicate(TEST_KEY, value1); registryMap.putAndLogWarningIfDuplicate(TEST_KEY, value2); assertThat(registryMap.getLostObjects(), is(empty())); } @Test public void testJSR250ObjectLifecycle() throws Exception { muleContext.start(); JSR250ObjectLifecycleTracker tracker = new JSR250ObjectLifecycleTracker(); muleContext.getRegistry().registerObject(TEST_KEY, tracker); muleContext.dispose(); assertEquals("[setMuleContext, initialise, dispose]", tracker.getTracker().toString()); } @Test public void testObjectLifecycleStates() throws Exception { InterfaceBasedTracker tracker = new InterfaceBasedTracker(); muleContext.getRegistry().registerObject(TEST_KEY, tracker); assertEquals("[setMuleContext, initialise]", tracker.getTracker().toString()); try { muleContext.initialise(); fail("context already initialised"); } catch (IllegalStateException e) { // expected } muleContext.start(); assertEquals("[setMuleContext, initialise, start]", tracker.getTracker().toString()); try { muleContext.start(); fail("context already started"); } catch (IllegalStateException e) { // expected } muleContext.stop(); assertEquals("[setMuleContext, initialise, start, stop]", tracker.getTracker().toString()); try { muleContext.stop(); fail("context already stopped"); } catch (IllegalStateException e) { // expected } muleContext.dispose(); assertEquals(LIFECYCLE_PHASES, tracker.getTracker().toString()); try { muleContext.dispose(); fail("context already disposed"); } catch (IllegalStateException e) { // expected } } @Test public void testObjectLifecycleRestart() throws Exception { InterfaceBasedTracker tracker = new InterfaceBasedTracker(); muleContext.getRegistry().registerObject(TEST_KEY, tracker); muleContext.start(); assertEquals("[setMuleContext, initialise, start]", tracker.getTracker().toString()); muleContext.stop(); assertEquals("[setMuleContext, initialise, start, stop]", tracker.getTracker().toString()); muleContext.start(); assertEquals("[setMuleContext, initialise, start, stop, start]", tracker.getTracker().toString()); muleContext.dispose(); assertEquals("[setMuleContext, initialise, start, stop, start, stop, dispose]", tracker.getTracker().toString()); } @Test public void testLifecycleStateOutOfSequenceDisposeFirstWithTransientRegistryDirectly() throws Exception { TransientRegistry reg = new TransientRegistry(muleContext); reg.fireLifecycle(Disposable.PHASE_NAME); InterfaceBasedTracker tracker = new InterfaceBasedTracker(); try { reg.registerObject(TEST_KEY, tracker); fail("Cannot register objects on a disposed registry"); } catch (RegistrationException e) { // Expected } } @Test public void testLifecycleStateOutOfSequenceStartFirst() throws Exception { muleContext.start(); InterfaceBasedTracker tracker = new InterfaceBasedTracker(); muleContext.getRegistry().registerObject(TEST_KEY, tracker); // Initialise called implicitly because you cannot start a component without initialising it first assertEquals("[setMuleContext, initialise, start]", tracker.getTracker().toString()); muleContext.dispose(); // Stop called implicitly because you cannot dispose component without stopping it first assertEquals(LIFECYCLE_PHASES, tracker.getTracker().toString()); } @Test public void testLifecycleStateOutOfSequenceStopFirst() throws Exception { try { muleContext.stop(); fail("Cannot not stop the context if not started"); } catch (IllegalStateException e) { // expected } muleContext.start(); muleContext.stop(); InterfaceBasedTracker tracker = new InterfaceBasedTracker(); muleContext.getRegistry().registerObject(TEST_KEY, tracker); // Start is bypassed because the component was added when the registry was stopped, hence no need to start the component // Stop isn't called either because start was not called // Initialised is called because that pahse has completed in the registry assertEquals("[setMuleContext, initialise]", tracker.getTracker().toString()); muleContext.dispose(); assertEquals("[setMuleContext, initialise, dispose]", tracker.getTracker().toString()); } @Test public void testLifecycleStateOutOfSequenceDisposeFirst() throws Exception { muleContext.dispose(); InterfaceBasedTracker tracker = new InterfaceBasedTracker(); try { muleContext.getRegistry().registerObject(TEST_KEY, tracker); fail("cannot register objects on a disposed registry"); } catch (RegistrationException e) { // Expected } } public class InterfaceBasedTracker extends AbstractLifecycleTracker { // no custom methods } public class JSR250ObjectLifecycleTracker implements MuleContextAware { private final List<String> tracker = new ArrayList<String>(); public List<String> getTracker() { return tracker; } @Override public void setMuleContext(MuleContext context) { tracker.add("setMuleContext"); } @PostConstruct public void init() { tracker.add("initialise"); } @PreDestroy public void dispose() { tracker.add("dispose"); } } }