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