001    // Copyright 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.bean;
016    
017    import static org.easymock.EasyMock.expect;
018    
019    import org.apache.hivemind.ApplicationRuntimeException;
020    import org.apache.hivemind.ClassResolver;
021    import org.apache.hivemind.Location;
022    import org.apache.hivemind.impl.DefaultClassResolver;
023    import org.apache.tapestry.BaseComponentTestCase;
024    import org.apache.tapestry.IBeanProvider;
025    import org.apache.tapestry.IComponent;
026    import org.apache.tapestry.INamespace;
027    import org.apache.tapestry.IPage;
028    import org.apache.tapestry.IRequestCycle;
029    import org.apache.tapestry.services.ClassFinder;
030    import org.apache.tapestry.services.Infrastructure;
031    import org.apache.tapestry.spec.BeanSpecification;
032    import org.apache.tapestry.spec.IBeanSpecification;
033    import org.testng.annotations.Test;
034    
035    /**
036     * Tests for {@link org.apache.tapestry.bean.BeanProvider} (mostly new features added in release
037     * 4.0).
038     * 
039     * @author Howard M. Lewis Ship
040     * @since 4.0
041     */
042    @Test
043    public class TestBeanProvider extends BaseComponentTestCase
044    {
045        public static class BeanInitializerFixture extends AbstractBeanInitializer
046        {
047            private final RuntimeException _exception;
048    
049            public BeanInitializerFixture(String propertyName, RuntimeException exception)
050            {
051                setPropertyName(propertyName);
052                _exception = exception;
053            }
054    
055            public void setBeanProperty(IBeanProvider provider, Object bean)
056            {
057                throw _exception;
058            }
059    
060        }
061    
062        protected IBeanSpecification newBeanSpec()
063        {
064            return newMock(IBeanSpecification.class);
065        }
066    
067        protected void trainGetClassName(IBeanSpecification spec, String className)
068        {
069            expect(spec.getClassName()).andReturn(className);
070        }
071    
072        public void testResolveClassFailure()
073        {
074            ClassResolver resolver = newResolver();
075            IPage page = newPage();
076            IComponent component = newComponent();
077            ClassFinder finder = newClassFinder();
078    
079            trainForConstructor(page, component, resolver, finder);
080    
081            replay();
082    
083            BeanProvider bp = new BeanProvider(component);
084    
085            verify();
086    
087            IBeanSpecification bs = newBeanSpec();
088    
089            trainGetClassName(bs, "org.foo.Bar");
090    
091            trainFindClass(finder, "org.foo.Bar", null);
092    
093            trainGetExtendedId(component, "Fred/barney");
094    
095            Location l = newLocation();
096    
097            trainGetLocation(bs, l);
098    
099            replay();
100    
101            try
102            {
103                bp.instantiateBean("wilma", bs);
104                unreachable();
105            }
106            catch (ApplicationRuntimeException ex)
107            {
108                assertEquals(
109                        "Unable to instantiate bean 'wilma' of component Fred/barney: Unable to find class org.foo.Bar within package list 'mypackage'.",
110                        ex.getMessage());
111                assertSame(component, ex.getComponent());
112                assertSame(l, ex.getLocation());
113            }
114    
115            verify();
116        }
117    
118        public void testInstantiateBeanFailure()
119        {
120            ClassResolver resolver = newResolver();
121            IPage page = newPage();
122            IComponent component = newComponent();
123            ClassFinder finder = newClassFinder();
124    
125            trainForConstructor(page, component, resolver, finder);
126    
127            replay();
128    
129            BeanProvider bp = new BeanProvider(component);
130    
131            verify();
132    
133            IBeanSpecification bs = newBeanSpec();
134    
135            trainGetClassName(bs, "org.foo.Bar");
136    
137            trainFindClass(finder, "org.foo.Bar", InstantiateFailureBean.class);
138    
139            trainGetExtendedId(component, "Fred/barney");
140    
141            Location l = newLocation();
142    
143            trainGetLocation(bs, l);
144    
145            replay();
146    
147            try
148            {
149                bp.instantiateBean("wilma", bs);
150                unreachable();
151            }
152            catch (ApplicationRuntimeException ex)
153            {
154                assertEquals(
155                        "Unable to instantiate bean 'wilma' (for component Fred/barney) as class org.apache.tapestry.bean.InstantiateFailureBean: Boom!",
156                        ex.getMessage());
157                assertSame(component, ex.getComponent());
158                assertSame(l, ex.getLocation());
159            }
160    
161            verify();
162        }
163    
164        private void trainForConstructor(IPage page, IComponent component, ClassResolver resolver,
165                ClassFinder classFinder)
166        {
167            IRequestCycle cycle = newCycle();
168            Infrastructure infrastructure = newMock(Infrastructure.class);
169            INamespace namespace = newMock(INamespace.class);
170    
171            trainGetPage(component, page);
172    
173            expect(page.getRequestCycle()).andReturn(cycle);
174    
175            expect(cycle.getInfrastructure()).andReturn(infrastructure);
176    
177            expect(infrastructure.getClassResolver()).andReturn(resolver);
178    
179            expect(component.getNamespace()).andReturn(namespace);
180    
181            expect(namespace.getPropertyValue("org.apache.tapestry.bean-class-packages"))
182            .andReturn("mypackage");
183    
184            expect(infrastructure.getClassFinder()).andReturn(classFinder);
185        }
186    
187        protected ClassFinder newClassFinder()
188        {
189            return newMock(ClassFinder.class);
190        }
191    
192        private ClassResolver newResolver()
193        {
194            return newMock(ClassResolver.class);
195        }
196    
197        public void testInitializeFailure()
198        {
199            ClassResolver resolver = new DefaultClassResolver();
200            IPage page = newPage();
201            IComponent component = newComponent();
202            ClassFinder finder = newClassFinder();
203    
204            trainForConstructor(page, component, resolver, finder);
205    
206            replay();
207    
208            BeanProvider bp = new BeanProvider(component);
209    
210            verify();
211    
212            String className = TargetBean.class.getName();
213    
214            trainFindClass(finder, className, TargetBean.class);
215    
216            IBeanSpecification spec = new BeanSpecification();
217            spec.setClassName(className);
218    
219            RuntimeException t = new RuntimeException("Blat!");
220    
221            Location l = newLocation();
222    
223            IBeanInitializer bi = new BeanInitializerFixture("foo", t);
224            bi.setLocation(l);
225    
226            spec.addInitializer(bi);
227    
228            trainGetExtendedId(component, "Fred/barney");
229    
230            replay();
231    
232            try
233            {
234                bp.instantiateBean("wilma", spec);
235                unreachable();
236            }
237            catch (ApplicationRuntimeException ex)
238            {
239                assertEquals(
240                        "Error initializing property foo of bean 'wilma' (of component Fred/barney): Blat!",
241                        ex.getMessage());
242                assertSame(TargetBean.class, ex.getComponent().getClass());
243                assertSame(l, ex.getLocation());
244                assertSame(t, ex.getRootCause());
245            }
246    
247        }
248    
249        private void trainFindClass(ClassFinder finder, String className, Class clazz)
250        {
251            expect(finder.findClass("mypackage", className)).andReturn(clazz);
252        }
253    }