    001    /*****************************************************************************
    002     * Copyright (C) PicoContainer Organization. All rights reserved.            *
    003     * ------------------------------------------------------------------------- *
    004     * The software in this package is published under the terms of the BSD      *
    005     * style license a copy of which has been included with this distribution in *
    006     * the LICENSE.txt file.                                                     *
    007     *****************************************************************************/
    008    package org.picocontainer.lifecycle;
    009
    010    import static org.junit.Assert.assertFalse;
    011    import static org.picocontainer.tck.MockFactory.mockeryWithCountingNamingScheme;
    012
    013    import java.io.Serializable;
    014    import java.lang.reflect.Member;
    015    import java.lang.reflect.Method;
    016
    017    import org.hamcrest.BaseMatcher;
    018    import org.hamcrest.Description;
    019    import org.hamcrest.Matcher;
    020    import org.jmock.Expectations;
    021    import org.jmock.Mockery;
    022    import org.jmock.integration.junit4.JMock;
    023    import org.junit.Before;
    024    import org.junit.Test;
    025    import org.junit.runner.RunWith;
    026    import org.picocontainer.ComponentAdapter;
    027    import org.picocontainer.ComponentMonitor;
    028    import org.picocontainer.Disposable;
    029    import org.picocontainer.PicoContainer;
    030    import org.picocontainer.Startable;
    031
    032    /**
    033     * @author Paul Hammant
    034     * @author Mauro Talevi
    035     * @author J&ouml;rg Schaible
    036     */
    037    @RunWith(JMock.class)
    038    public class ReflectionLifecycleStrategyTestCase {
    039
    040            private Mockery mockery = mockeryWithCountingNamingScheme();
    041
    042            private ReflectionLifecycleStrategy strategy;
    043            private ComponentMonitor componentMonitor;
    044
    045            @Before
    046            public void setUp() {
    047                    componentMonitor = mockery.mock(ComponentMonitor.class);
    048                    strategy = new ReflectionLifecycleStrategy(componentMonitor);
    049            }
    050
    051             @Test
    052            public void testStartable() {
    053                    Object startable = mockComponent(true, false);
    054                    strategy.start(startable);
    055                    strategy.stop(startable);
    056                    strategy.dispose(startable);
    057            }
    058
    059            @Test
    060            public void testDisposable() {
    061                    Object disposable = mockComponent(false, true);
    062                    strategy.start(disposable);
    063                    strategy.stop(disposable);
    064                    strategy.dispose(disposable);
    065            }
    066
    067            @Test
    068            public void testNotStartableNorDisposable() {
    069                    Object serializable = mockery.mock(Serializable.class);
    070                    assertFalse(strategy.hasLifecycle(serializable.getClass()));
    071                    strategy.start(serializable);
    072                    strategy.stop(serializable);
    073                    strategy.dispose(serializable);
    074            }
    075
    076            @Test
    077            public void testMonitorChanges() {
    078                    final ComponentMonitor componentMonitor2 = mockery
    079                                    .mock(ComponentMonitor.class);
    080                    final Disposable disposable = mockery.mock(Disposable.class);
    081                    final Matcher<Member> isDisposeMember = new IsMember("dispose");
    082                    final Matcher<Method> isDisposeMethod = new IsMethod("dispose");
    083                    mockery.checking(new Expectations() {
    084                            {
    085                                    atLeast(1).of(disposable).dispose();
    086                                    one(componentMonitor).invoking(
    087                                                    with(aNull(PicoContainer.class)),
    088                                                    with(aNull(ComponentAdapter.class)),
    089                                                    with(isDisposeMember), with(same(disposable)), with(any(Object[].class)));
    090                                    one(componentMonitor).invoked(with(aNull(PicoContainer.class)),
    091                                                    with(aNull(ComponentAdapter.class)),
    092                                                    with(isDisposeMethod), with(same(disposable)),
    093                            with(any(Long.class)), with(any(Object[].class)), with(same(null)));
    094                                    one(componentMonitor2).invoking(
    095                                                    with(aNull(PicoContainer.class)),
    096                                                    with(aNull(ComponentAdapter.class)),
    097                                                    with(isDisposeMember), with(same(disposable)), with(any(Object[].class)));
    098                                    one(componentMonitor2).invoked(
    099                                                    with(aNull(PicoContainer.class)),
    100                                                    with(aNull(ComponentAdapter.class)),
    101                                                    with(isDisposeMethod), with(same(disposable)),
    102                            with(any(Long.class)), with(any(Object[].class)), with(same(null)));
    103                            }
    104                    });
    105                    strategy.dispose(disposable);
    106                    strategy.changeMonitor(componentMonitor2);
    107                    strategy.dispose(disposable);
    108            }
    109
    110            @Test
    111            public void testWithDifferentTypes() {
    112                    final MyLifecycle lifecycle = mockery.mock(MyLifecycle.class);
    113                    final Matcher<Member> isStartMember = new IsMember("start");
    114                    final Matcher<Method> isStartMethod = new IsMethod("start");
    115                    final Matcher<Member> isStopMember = new IsMember("stop");
    116                    final Matcher<Method> isStopMethod = new IsMethod("stop");
    117                    final Matcher<Member> isDisposeMember = new IsMember("dispose");
    118                    final Matcher<Method> isDisposeMethod = new IsMethod("dispose");
    119                    mockery.checking(new Expectations() {
    120                            {
    121                                    one(lifecycle).start();
    122                                    one(lifecycle).stop();
    123                                    one(lifecycle).dispose();
    124                                    one(componentMonitor).invoking(
    125                                                    with(aNull(PicoContainer.class)),
    126                                                    with(aNull(ComponentAdapter.class)),
    127                                                    with(isStartMember), with(same(lifecycle)), with(any(Object[].class)));
    128                                    one(componentMonitor).invoked(with(aNull(PicoContainer.class)),
    129                                                    with(aNull(ComponentAdapter.class)),
    130                                                    with(isStartMethod), with(same(lifecycle)),
    131                            with(any(Long.class)), with(any(Object[].class)), with(same(null)));
    132                                    one(componentMonitor).invoking(
    133                                                    with(aNull(PicoContainer.class)),
    134                                                    with(aNull(ComponentAdapter.class)),
    135                                                    with(isStopMember), with(same(lifecycle)), with(any(Object[].class)));
    136                                    one(componentMonitor).invoked(with(aNull(PicoContainer.class)),
    137                                                    with(aNull(ComponentAdapter.class)),
    138                                                    with(isStopMethod), with(same(lifecycle)),
    139                            with(any(Long.class)), with(any(Object[].class)), with(same(null)));
    140                                    one(componentMonitor).invoking(
    141                                                    with(aNull(PicoContainer.class)),
    142                                                    with(aNull(ComponentAdapter.class)),
    143                                                    with(isDisposeMember), with(same(lifecycle)), with(any(Object[].class)));
    144                                    one(componentMonitor).invoked(with(aNull(PicoContainer.class)),
    145                                                    with(aNull(ComponentAdapter.class)),
    146                                                    with(isDisposeMethod), with(same(lifecycle)),
    147                            with(any(Long.class)), with(any(Object[].class)), with(same(null)));
    148                            }
    149                    });
    150
    151                    Object startable = mockComponent(true, false);
    152                    strategy.start(startable);
    153                    strategy.stop(startable);
    154                    strategy.dispose(startable);
    155                    startable = lifecycle;
    156                    strategy.start(startable);
    157                    strategy.stop(startable);
    158                    strategy.dispose(startable);
    159            }
    160
    161            private Object mockComponent(boolean startable, boolean disposable) {
    162                    final Matcher<Member> isStartMember = new IsMember("start");
    163                    final Matcher<Method> isStartMethod = new IsMethod("start");
    164                    final Matcher<Member> isStopMember = new IsMember("stop");
    165                    final Matcher<Method> isStopMethod = new IsMethod("stop");
    166                    final Matcher<Member> isDisposeMember = new IsMember("dispose");
    167                    final Matcher<Method> isDisposeMethod = new IsMethod("dispose");
    168                    if (startable) {
    169                            final Startable mock = mockery.mock(Startable.class);
    170                            mockery.checking(new Expectations() {
    171                                    {
    172                                            atLeast(1).of(mock).start();
    173                                            atLeast(1).of(mock).stop();
    174                                            one(componentMonitor).invoking(
    175                                                            with(aNull(PicoContainer.class)),
    176                                                            with(aNull(ComponentAdapter.class)),
    177                                                            with(isStartMember), with(same(mock)), with(any(Object[].class)));
    178                                            one(componentMonitor)
    179                                                            .invoked(with(aNull(PicoContainer.class)),
    180                                                                            with(aNull(ComponentAdapter.class)),
    181                                                                            with(isStartMethod), with(same(mock)),
    182                                        with(any(Long.class)), with(any(Object[].class)), with(same(null)));
    183                                            one(componentMonitor).invoking(
    184                                                            with(aNull(PicoContainer.class)),
    185                                                            with(aNull(ComponentAdapter.class)),
    186                                                            with(isStopMember), with(same(mock)), with(any(Object[].class)));
    187                                            one(componentMonitor).invoked(
    188                                                            with(aNull(PicoContainer.class)),
    189                                                            with(aNull(ComponentAdapter.class)),
    190                                                            with(isStopMethod), with(same(mock)), with(any(Long.class)), with(any(Object[].class)), with(same(null)));
    191                                    }
    192                            });
    193                            return mock;
    194                    }
    195                    if (disposable) {
    196                            final Disposable mock = mockery.mock(Disposable.class);
    197                            mockery.checking(new Expectations() {
    198                                    {
    199                                            atLeast(1).of(mock).dispose();
    200                                            one(componentMonitor).invoking(
    201                                                            with(aNull(PicoContainer.class)),
    202                                                            with(aNull(ComponentAdapter.class)),
    203                                                            with(isDisposeMember), with(same(mock)), with(any(Object[].class)));
    204                                            one(componentMonitor)
    205                                                            .invoked(with(aNull(PicoContainer.class)),
    206                                                                            with(aNull(ComponentAdapter.class)),
    207                                                                            with(isDisposeMethod), with(same(mock)),
    208                                        with(any(Long.class)), with(any(Object[].class)), with(same(null)));
    209                                    }
    210                            });
    211                            return mock;
    212                    }
    213                    return mockery.mock(Serializable.class);
    214            }
    215
    216            public static interface MyLifecycle {
    217                    void start();
    218
    219                    void stop();
    220
    221                    void dispose();
    222            }
    223
    224            static class IsMember extends BaseMatcher<Member> {
    225                    private String name;
    226
    227                    public IsMember(String name) {
    228                            this.name = name;
    229                    }
    230
    231                    public boolean matches(Object item) {
    232                            return ((Member) item).getName().equals(name);
    233                    }
    234
    235                    public void describeTo(Description description) {
    236                            description.appendText("Should have been a member of name ");
    237                            description.appendText(name);
    238                    }
    239            };
    240
    241            static class IsMethod extends BaseMatcher<Method> {
    242                    private String name;
    243
    244                    public IsMethod(String name) {
    245                            this.name = name;
    246                    }
    247
    248                    public boolean matches(Object item) {
    249                            return ((Method) item).getName().equals(name);
    250                    }
    251
    252                    public void describeTo(Description description) {
    253                            description.appendText("Should have been a method of name ");
    254                            description.appendText(name);
    255                    }
    256            };
    257
    258    }