001    // Copyright 2004, 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.engine;
016    
017    import org.apache.hivemind.ApplicationRuntimeException;
018    import org.apache.hivemind.Location;
019    import org.apache.tapestry.*;
020    import org.apache.tapestry.event.BrowserEvent;
021    import org.apache.tapestry.services.LinkFactory;
022    import org.apache.tapestry.services.ResponseRenderer;
023    import org.apache.tapestry.services.ServiceConstants;
024    import org.apache.tapestry.web.WebRequest;
025    import org.apache.tapestry.web.WebSession;
026    import static org.easymock.EasyMock.*;
027    import org.testng.annotations.Test;
028    
029    import java.util.HashMap;
030    import java.util.Map;
031    
032    /**
033     * Tests for {@link org.apache.tapestry.engine.DirectService}.
034     * 
035     * @author Howard M. Lewis Ship
036     * @since 4.0
037     */
038    @Test
039    public class DirectEventServiceTest extends ServiceTestCase
040    {
041        private IDirectEvent newDirect()
042        {
043            return newMock(IDirectEvent.class);
044        }
045    
046        public void testGetLinkOnSamePage()
047        {
048            IPage page = newPage("ThePage");
049            IDirectEvent c = newDirect();
050            IRequestCycle cycle = newCycle();
051            WebRequest request = newWebRequest(false, null);
052            LinkFactory lf = newLinkFactory();
053            ILink link = newLink();
054    
055            trainGetPage(cycle, page);
056            trainGetPage(c, page);
057            trainGetIdPath(c, "fred.barney");
058    
059            Object[] serviceParameters = new Object[0];
060    
061            Map parameters = new HashMap();
062    
063            parameters.put(ServiceConstants.PAGE, "ThePage");
064            parameters.put(ServiceConstants.COMPONENT, "fred.barney");
065            parameters.put(ServiceConstants.CONTAINER, null);
066            parameters.put(ServiceConstants.SESSION, null);
067            parameters.put(ServiceConstants.PARAMETER, serviceParameters);
068    
069            DirectEventService ds = new DirectEventService();
070    
071            ds.setLinkFactory(lf);
072            ds.setRequest(request);
073            ds.setRequestCycle(cycle);
074    
075            trainConstructLink(lf, ds, false, parameters, true, link);
076    
077            replay();
078    
079            assertSame(link, ds.getLink(false, new DirectEventServiceParameter(c, serviceParameters)));
080    
081            verify();
082        }
083    
084        public void testGetLinkOnSamePageForPost()
085        {
086            IPage page = newPage("ThePage");
087            IDirectEvent c = newDirect();
088            IRequestCycle cycle = newCycle();
089            WebRequest request = newWebRequest(false, null);
090            LinkFactory lf = newLinkFactory();
091            ILink link = newLink();
092    
093            trainGetPage(cycle, page);
094            trainGetPage(c, page);
095            trainGetIdPath(c, "fred.barney");
096    
097            Object[] serviceParameters = new Object[0];
098    
099            Map parameters = new HashMap();
100    
101            parameters.put(ServiceConstants.PAGE, "ThePage");
102            parameters.put(ServiceConstants.COMPONENT, "fred.barney");
103            parameters.put(ServiceConstants.CONTAINER, null);
104            parameters.put(ServiceConstants.SESSION, null);
105            parameters.put(ServiceConstants.PARAMETER, serviceParameters);
106    
107            DirectEventService ds = new DirectEventService();
108    
109            ds.setLinkFactory(lf);
110            ds.setRequest(request);
111            ds.setRequestCycle(cycle);
112    
113            trainConstructLink(lf, ds, true, parameters, true, link);
114    
115            replay();
116    
117            assertSame(link, ds.getLink(true, new DirectEventServiceParameter(c, serviceParameters)));
118    
119            verify();
120        }
121    
122        public void testGetLinkOnSamePageStateful()
123        {
124            IPage page = newPage("ThePage");
125            IDirectEvent c = newDirect();
126            IRequestCycle cycle = newCycle();
127            WebSession session = newWebSession();
128            WebRequest request = newWebRequest(false, session);
129            LinkFactory lf = newLinkFactory();
130            ILink link = newLink();
131    
132            trainGetPage(cycle, page);
133            trainGetPage(c, page);
134            trainGetIdPath(c, "fred.barney");
135    
136            Object[] serviceParameters = new Object[0];
137    
138            Map parameters = new HashMap();
139    
140            parameters.put(ServiceConstants.PAGE, "ThePage");
141            parameters.put(ServiceConstants.COMPONENT, "fred.barney");
142            parameters.put(ServiceConstants.CONTAINER, null);
143            parameters.put(ServiceConstants.SESSION, "T");
144            parameters.put(ServiceConstants.PARAMETER, serviceParameters);
145    
146            DirectEventService ds = new DirectEventService();
147            ds.setLinkFactory(lf);
148            ds.setRequest(request);
149            ds.setRequestCycle(cycle);
150    
151            trainConstructLink(lf, ds, false, parameters, true, link);
152    
153            replay();
154    
155            assertSame(link, ds.getLink(false, new DirectEventServiceParameter(c, serviceParameters)));
156    
157            verify();
158        }
159    
160        public void testGetLinkOnDifferentPage()
161        {
162            IPage page = newPage("ActivePage");
163            IPage componentPage = newPage("ComponentPage");
164            IDirectEvent c = newDirect();
165            IRequestCycle cycle = newCycle();
166            WebRequest request = newWebRequest(false, null);
167            LinkFactory lf = newLinkFactory();
168            ILink link = newLink();
169    
170            trainGetPage(cycle, page);
171            trainGetPage(c, componentPage);
172            trainGetIdPath(c, "fred.barney");
173    
174            Object[] serviceParameters = new Object[0];
175    
176            Map parameters = new HashMap();
177    
178            parameters.put(ServiceConstants.PAGE, "ActivePage");
179            parameters.put(ServiceConstants.COMPONENT, "fred.barney");
180            parameters.put(ServiceConstants.CONTAINER, "ComponentPage");
181            parameters.put(ServiceConstants.SESSION, null);
182            parameters.put(ServiceConstants.PARAMETER, serviceParameters);
183    
184            DirectEventService ds = new DirectEventService();
185            ds.setLinkFactory(lf);
186            ds.setRequest(request);
187            ds.setRequestCycle(cycle);
188    
189            trainConstructLink(lf, ds, false, parameters, true, link);
190    
191            replay();
192    
193            assertSame(link, ds.getLink(false, new DirectEventServiceParameter(c, serviceParameters)));
194    
195            verify();
196        }
197    
198        public void testServiceSimple() throws Exception
199        {
200            Object[] parameters = new Object[0];
201            IRequestCycle cycle = newCycle();
202            IPage page = newPage();
203            IDirectEvent d = newDirect();
204            LinkFactory lf = newLinkFactory();
205            ResponseRenderer rr = newResponseRenderer();
206    
207            trainGetParameter(cycle, ServiceConstants.COMPONENT, "fred.barney");
208            trainGetParameter(cycle, ServiceConstants.CONTAINER, null);
209            trainGetParameter(cycle, ServiceConstants.PAGE, "ActivePage");
210            trainGetParameter(cycle, ServiceConstants.SESSION, null);
211    
212            trainGetPage(cycle, "ActivePage", page);
213            cycle.activate(page);
214    
215            trainGetNestedComponent(page, "fred.barney", d);
216    
217            trainExtractListenerParameters(lf, cycle, parameters);
218    
219            trainExtractBrowserEvent(cycle);
220            
221            cycle.setListenerParameters(isA(Object[].class));
222            
223            d.triggerEvent(eq(cycle), isA(BrowserEvent.class));
224            
225            rr.renderResponse(cycle);
226            
227            replay();
228    
229            DirectEventService ds = new DirectEventService();
230            ds.setLinkFactory(lf);
231            ds.setResponseRenderer(rr);
232    
233            ds.service(cycle);
234    
235            verify();
236        }
237    
238        /**
239         * The complex case is where the component is contained on a different page than the active (at
240         * the time of render) page.
241         */
242        public void testServiceComplex() throws Exception
243        {
244            Object[] parameters = new Object[0];
245            IRequestCycle cycle = newCycle();
246            IPage page = newPage();
247            IPage componentPage = newPage();
248            IDirectEvent d = newDirect();
249            LinkFactory lf = newLinkFactory();
250            ResponseRenderer rr = newResponseRenderer();
251    
252            trainGetParameter(cycle, ServiceConstants.COMPONENT, "fred.barney");
253            trainGetParameter(cycle, ServiceConstants.CONTAINER, "ComponentPage");
254            trainGetParameter(cycle, ServiceConstants.PAGE, "ActivePage");
255            trainGetParameter(cycle, ServiceConstants.SESSION, null);
256            
257            trainGetPage(cycle, "ActivePage", page);
258            cycle.activate(page);
259    
260            trainGetPage(cycle, "ComponentPage", componentPage);
261            trainGetNestedComponent(componentPage, "fred.barney", d);
262    
263            trainExtractListenerParameters(lf, cycle, parameters);
264            trainExtractBrowserEvent(cycle);
265            
266            cycle.setListenerParameters(isA(Object[].class));
267            
268            d.triggerEvent(eq(cycle), isA(BrowserEvent.class));
269    
270            rr.renderResponse(cycle);
271    
272            replay();
273    
274            DirectEventService ds = new DirectEventService();
275            ds.setLinkFactory(lf);
276            ds.setResponseRenderer(rr);
277    
278            ds.service(cycle);
279    
280            verify();
281        }
282    
283        public void testServiceNotDirect() throws Exception
284        {
285            IRequestCycle cycle = newCycle();
286            IPage page = newPage();
287            IComponent c = newComponent();
288            Location l = newLocation();
289    
290            trainGetParameter(cycle, ServiceConstants.COMPONENT, "fred.barney");
291            trainGetParameter(cycle, ServiceConstants.CONTAINER, null);
292            trainGetParameter(cycle, ServiceConstants.PAGE, "ActivePage");
293            trainGetParameter(cycle, ServiceConstants.SESSION, null);
294    
295            trainGetPage(cycle, "ActivePage", page);
296            cycle.activate(page);
297    
298            trainGetNestedComponent(page, "fred.barney", c);
299    
300            trainGetExtendedId(c, "ActivePage/fred.barney");
301            trainGetLocation(c, l);
302    
303            replay();
304    
305            DirectEventService ds = new DirectEventService();
306    
307            try
308            {
309                ds.service(cycle);
310                unreachable();
311            }
312            catch (ApplicationRuntimeException ex)
313            {
314                assertEquals(
315                        "Component ActivePage/fred.barney does not implement the org.apache.tapestry.IDirectEvent interface.",
316                        ex.getMessage());
317                assertSame(c, ex.getComponent());
318                assertSame(l, ex.getLocation());
319            }
320    
321            verify();
322        }
323    
324        public void testSessionActiveAndRequired() throws Exception
325        {
326            Object[] parameters = new Object[0];
327            IRequestCycle cycle = newCycle();
328            IPage page = newPage();
329            IDirectEvent d = newDirect();
330            
331            LinkFactory lf = newLinkFactory();
332            ResponseRenderer rr = newResponseRenderer();
333            
334            trainGetParameter(cycle, ServiceConstants.COMPONENT, "fred.barney");
335            trainGetParameter(cycle, ServiceConstants.CONTAINER, null);
336            trainGetParameter(cycle, ServiceConstants.PAGE, "ActivePage");
337            trainGetParameter(cycle, ServiceConstants.SESSION, "T");
338            
339            trainGetPage(cycle, "ActivePage", page);
340            cycle.activate(page);
341    
342            trainGetNestedComponent(page, "fred.barney", d);
343    
344            trainIsStateful(d, true);
345    
346            WebSession session = newWebSession(false);
347            WebRequest request = newWebRequest(session);
348            
349            trainExtractListenerParameters(lf, cycle, parameters);
350    
351            trainExtractBrowserEvent(cycle);
352            
353            cycle.setListenerParameters(isA(Object[].class));
354            
355            d.triggerEvent(eq(cycle), isA(BrowserEvent.class));
356    
357            rr.renderResponse(cycle);
358    
359            replay();
360    
361            DirectEventService ds = new DirectEventService();
362            ds.setLinkFactory(lf);
363            ds.setResponseRenderer(rr);
364            ds.setRequest(request);
365    
366            ds.service(cycle);
367    
368            verify();
369        }
370        
371        public void testStaleSession() throws Exception
372        {
373            IRequestCycle cycle = newCycle();
374            IPage page = newPage();
375            IDirectEvent d = newDirect();
376            
377            Location l = newLocation();
378    
379            trainGetParameter(cycle, ServiceConstants.COMPONENT, "fred.barney");
380            trainGetParameter(cycle, ServiceConstants.CONTAINER, null);
381            trainGetParameter(cycle, ServiceConstants.PAGE, "ActivePage");
382            trainGetParameter(cycle, ServiceConstants.SESSION, "T");
383    
384            trainGetPage(cycle, "ActivePage", page);
385            cycle.activate(page);
386    
387            trainGetNestedComponent(page, "fred.barney", d);
388    
389            trainIsStateful(d, true);
390    
391            WebRequest request = newWebRequest(null);
392            
393            trainGetExtendedId(d, "ActivePage/fred.barney");
394            trainGetLocation(page, l);
395            trainGetPageName(page, "ActivePage");
396    
397            replay();
398    
399            DirectEventService ds = new DirectEventService();
400            ds.setRequest(request);
401    
402            try
403            {
404                ds.service(cycle);
405                unreachable();
406            }
407            catch (StaleSessionException ex)
408            {
409                assertEquals(
410                        "Component ActivePage/fred.barney is stateful, but the HttpSession has expired (or has not yet been created).",
411                        ex.getMessage());
412                assertSame(page, ex.getComponent());
413                assertSame(l, ex.getLocation());
414                assertEquals("ActivePage", ex.getPageName());
415                assertSame(page, ex.getPage());
416            }
417    
418            verify();
419        }
420        
421        public void testNoBrowserEvent() throws Exception
422        {
423            Object[] parameters = new Object[0];
424            IRequestCycle cycle = newCycle();
425            IPage page = newPage();
426            IDirectEvent d = newDirect();
427            LinkFactory lf = newLinkFactory();
428            ResponseRenderer rr = newResponseRenderer();
429    
430            trainGetParameter(cycle, ServiceConstants.COMPONENT, "fred.barney");
431            trainGetParameter(cycle, ServiceConstants.CONTAINER, null);
432            trainGetParameter(cycle, ServiceConstants.PAGE, "ActivePage");
433            trainGetParameter(cycle, ServiceConstants.SESSION, null);
434    
435            trainGetPage(cycle, "ActivePage", page);
436            cycle.activate(page);
437    
438            trainGetNestedComponent(page, "fred.barney", d);
439    
440            trainExtractListenerParameters(lf, cycle, parameters);
441    
442            expect(cycle.getParameter(BrowserEvent.NAME)).andReturn(null);
443            
444            replay();
445            
446            DirectEventService ds = new DirectEventService();
447            ds.setLinkFactory(lf);
448            ds.setResponseRenderer(rr);
449            
450            try {
451                ds.service(cycle);
452                unreachable();
453            } catch (ApplicationRuntimeException e) {
454                assertExceptionSubstring(e, "no browser event was found");
455            }
456            
457            verify();
458        }
459        
460        private void trainIsStateful(IDirectEvent direct, boolean isStateful)
461        {
462            expect(direct.isStateful()).andReturn(isStateful);
463        }
464    }