1   /*
2    * $Id: DynamicEntryPointDiscoveryTestCase.java 7963 2007-08-21 08:53:15Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.mule.model;
12  
13  import org.mule.config.MuleProperties;
14  import org.mule.impl.RequestContext;
15  import org.mule.impl.TooManySatisfiableMethodsException;
16  import org.mule.impl.endpoint.MuleEndpoint;
17  import org.mule.impl.model.resolvers.DynamicEntryPointResolver;
18  import org.mule.routing.inbound.InboundRouterCollection;
19  import org.mule.tck.model.AbstractEntryPointDiscoveryTestCase;
20  import org.mule.tck.testmodels.fruit.Apple;
21  import org.mule.tck.testmodels.fruit.Banana;
22  import org.mule.tck.testmodels.fruit.Fruit;
23  import org.mule.tck.testmodels.fruit.FruitBowl;
24  import org.mule.tck.testmodels.fruit.FruitCleaner;
25  import org.mule.tck.testmodels.fruit.FruitLover;
26  import org.mule.tck.testmodels.fruit.Kiwi;
27  import org.mule.tck.testmodels.fruit.ObjectToFruitLover;
28  import org.mule.tck.testmodels.fruit.WaterMelon;
29  import org.mule.umo.UMODescriptor;
30  import org.mule.umo.UMOEvent;
31  import org.mule.umo.endpoint.UMOEndpoint;
32  import org.mule.umo.model.UMOEntryPoint;
33  import org.mule.umo.model.UMOEntryPointResolver;
34  
35  import java.lang.reflect.InvocationHandler;
36  import java.lang.reflect.InvocationTargetException;
37  import java.util.Arrays;
38  import java.util.Collection;
39  import java.util.EventObject;
40  
41  public class DynamicEntryPointDiscoveryTestCase extends AbstractEntryPointDiscoveryTestCase
42  {
43      /**
44       * Name of the method override property on the event.
45       */
46      private static final String METHOD_PROPERTY_NAME = MuleProperties.MULE_METHOD_PROPERTY;
47  
48      /**
49       * Name of the non-existent method.
50       */
51      private static final String INVALID_METHOD_NAME = "nosuchmethod";
52  
53      public ComponentMethodMapping[] getComponentMappings()
54      {
55          ComponentMethodMapping[] mappings = new ComponentMethodMapping[6];
56          mappings[0] = new ComponentMethodMapping(WaterMelon.class, "myEventHandler", UMOEvent.class);
57          mappings[1] = new ComponentMethodMapping(FruitBowl.class, "consumeFruit", FruitLover.class);
58          // see testArrayArgumentResolution
59          mappings[2] = new ComponentMethodMapping(FruitBowl.class, "setFruit", Fruit[].class);
60          // see testListArgumentResolution
61          mappings[3] = new ComponentMethodMapping(FruitBowl.class, "setFruit", Collection.class);
62          mappings[4] = new ComponentMethodMapping(Banana.class, "peelEvent", EventObject.class);
63          // test proxy objects
64          mappings[5] = new ComponentMethodMapping(InvocationHandler.class, "invoke", FruitLover.class);
65          return mappings;
66      }
67  
68      // @Override
69      public UMODescriptor getDescriptorToResolve(String className) throws Exception
70      {
71          UMODescriptor descriptor = super.getDescriptorToResolve(className);
72          descriptor.setInboundRouter(new InboundRouterCollection());
73          UMOEndpoint endpoint = new MuleEndpoint("test://foo", true);
74  
75          if (className.equals(FruitBowl.class.getName()))
76          {
77              endpoint.setTransformer(new ObjectToFruitLover());
78              descriptor.getInboundRouter().addEndpoint(endpoint);
79          }
80          else if (className.equals(InvocationHandler.class.getName()))
81          {
82              endpoint.setTransformer(new ObjectToFruitLover());
83              descriptor.getInboundRouter().addEndpoint(endpoint);
84          }
85          return descriptor;
86      }
87  
88      public UMOEntryPointResolver getEntryPointResolver()
89      {
90          return new DynamicEntryPointResolver();
91      }
92  
93      /**
94       * Tests entrypoint discovery when there is more than one discoverable method
95       * with UMOEventContext parameter.
96       */
97      public void testFailEntryPointMultipleEventContextMatches() throws Exception
98      {
99          UMOEntryPointResolver epd = getEntryPointResolver();
100         UMODescriptor descriptor = getTestDescriptor("badContexts", MultipleEventContextsTestObject.class
101             .getName());
102 
103         UMOEntryPoint ep = epd.resolveEntryPoint(descriptor);
104         assertNotNull(ep);
105 
106         try
107         {
108             RequestContext.setEvent(getTestEvent("Hello"));
109             ep.invoke(new MultipleEventContextsTestObject(), RequestContext.getEventContext());
110             fail("Should have failed to find entrypoint.");
111         }
112         catch (InvocationTargetException itex)
113         {
114             final Throwable cause = itex.getCause();
115             if (cause instanceof TooManySatisfiableMethodsException)
116             {
117                 // expected
118             }
119             else
120             {
121                 throw itex;
122             }
123         }
124         finally
125         {
126             RequestContext.setEvent(null);
127         }
128 
129     }
130 
131     /**
132      * Tests entrypoint discovery when there is more than one discoverable method
133      * with UMOEventContext parameter.
134      */
135     public void testFailEntryPointMultiplePayloadMatches() throws Exception
136     {
137         UMOEntryPointResolver epd = getEntryPointResolver();
138         UMODescriptor descriptor = getTestDescriptor("badPayloads", MultiplePayloadsTestObject.class
139             .getName());
140 
141         UMOEntryPoint ep = epd.resolveEntryPoint(descriptor);
142         assertNotNull(ep);
143 
144         try
145         {
146             RequestContext.setEvent(getTestEvent("Hello"));
147             ep.invoke(new MultiplePayloadsTestObject(), RequestContext.getEventContext());
148             fail("Should have failed to find entrypoint.");
149         }
150         catch (TooManySatisfiableMethodsException itex)
151         {
152             // expected
153         }
154         finally
155         {
156             RequestContext.setEvent(null);
157         }
158     }
159 
160     /**
161      * If there was a method parameter specified to override the discovery mechanism
162      * and no such method exists, an exception should be thrown, and no fallback to
163      * the default discovery should take place.
164      */
165     public void testMethodOverrideDoesNotFallback() throws Exception
166     {
167         UMOEntryPointResolver epd = getEntryPointResolver();
168         UMODescriptor descriptor = getDescriptorToResolve(FruitBowl.class.getName());
169 
170         UMOEntryPoint ep = epd.resolveEntryPoint(descriptor);
171         assertNotNull(ep);
172 
173         try
174         {
175             RequestContext.setEvent(getTestEvent(new FruitLover("Yummy!")));
176 
177             // those are usually set on the endpoint and copied over to the message
178             final String methodName = "nosuchmethod";
179             final String propertyName = MuleProperties.MULE_METHOD_PROPERTY;
180             RequestContext.getEventContext().getMessage().setProperty(propertyName, methodName);
181 
182             ep.invoke(new FruitBowl(), RequestContext.getEventContext());
183             fail("Should have failed to find an entrypoint.");
184         }
185         catch (NoSuchMethodException itex)
186         {
187             // expected
188         }
189         finally
190         {
191             RequestContext.setEvent(null);
192         }
193     }
194 
195     /**
196      * If there was a method parameter specified to override the discovery mechanism
197      * and a Callable instance is serving the request, call the Callable, ignore the
198      * method override parameter.
199      */
200     public void testMethodOverrideIgnoredWithCallable() throws Exception
201     {
202         UMOEntryPointResolver epd = getEntryPointResolver();
203         UMODescriptor descriptor = getDescriptorToResolve(Apple.class.getName());
204 
205         UMOEntryPoint ep = epd.resolveEntryPoint(descriptor);
206         assertNotNull(ep);
207 
208         try
209         {
210             RequestContext.setEvent(getTestEvent(new FruitLover("Yummy!")));
211 
212             // those are usually set on the endpoint and copied over to the message
213             RequestContext.getEventContext().getMessage().setProperty(METHOD_PROPERTY_NAME,
214                 INVALID_METHOD_NAME);
215 
216             Apple apple = new Apple();
217             apple.setAppleCleaner(new FruitCleaner()
218             {
219                 public void wash(Fruit fruit)
220                 {
221                     // dummy
222                 }
223 
224                 public void polish(Fruit fruit)
225                 {
226                     // dummy
227                 }
228             });
229             ep.invoke(apple, RequestContext.getEventContext());
230         }
231         finally
232         {
233             RequestContext.setEvent(null);
234         }
235     }
236 
237     /**
238      * If there was a method parameter specified to override the discovery mechanism
239      * and a target instance has a method accepting UMOEventContext, proceed to call
240      * this method, ignore the method override parameter.
241      */
242     public void testMethodOverrideIgnoredWithEventContext() throws Exception
243     {
244         UMOEntryPointResolver epd = getEntryPointResolver();
245         UMODescriptor descriptor = getDescriptorToResolve(Kiwi.class.getName());
246 
247         UMOEntryPoint ep = epd.resolveEntryPoint(descriptor);
248         assertNotNull(ep);
249 
250         try
251         {
252             RequestContext.setEvent(getTestEvent(new FruitLover("Yummy!")));
253 
254             // those are usually set on the endpoint and copied over to the message
255             final String methodName = "nosuchmethod";
256             final String propertyName = MuleProperties.MULE_METHOD_PROPERTY;
257             RequestContext.getEventContext().getMessage().setProperty(propertyName, methodName);
258 
259             try
260             {
261                 ep.invoke(new Kiwi(), RequestContext.getEventContext());
262                 fail("no such method on component");
263             }
264             catch (NoSuchMethodException e)
265             {
266                 // expected
267             }
268         }
269         finally
270         {
271             RequestContext.setEvent(null);
272         }
273     }
274 
275     /**
276      * Test for proper resolution of a method that takes an array as argument.
277      */
278     // TODO MULE-1088: currently fails, therefore disabled
279     public void _testArrayArgumentResolution() throws Exception
280     {
281         UMOEntryPointResolver epd = this.getEntryPointResolver();
282         UMODescriptor descriptor = this.getDescriptorToResolve(FruitBowl.class.getName());
283 
284         UMOEntryPoint ep = epd.resolveEntryPoint(descriptor);
285         assertNotNull(ep);
286 
287         try
288         {
289             Object payload = new Fruit[]{new Apple(), new Banana()};
290             RequestContext.setEvent(getTestEvent(payload));
291 
292             FruitBowl bowl = new FruitBowl();
293             assertFalse(bowl.hasApple());
294             assertFalse(bowl.hasBanana());
295 
296             ep.invoke(bowl, RequestContext.getEventContext());
297 
298             assertTrue(bowl.hasApple());
299             assertTrue(bowl.hasBanana());
300         }
301         finally
302         {
303             RequestContext.setEvent(null);
304         }
305     }
306 
307     /**
308      * Test for proper resolution of a method that takes a List as argument.
309      */
310     public void testListArgumentResolution() throws Exception
311     {
312         UMOEntryPointResolver epd = this.getEntryPointResolver();
313         UMODescriptor descriptor = this.getDescriptorToResolve(FruitBowl.class.getName());
314 
315         UMOEntryPoint ep = epd.resolveEntryPoint(descriptor);
316         assertNotNull(ep);
317 
318         try
319         {
320             Object payload = Arrays.asList(new Fruit[]{new Apple(), new Banana()});
321             RequestContext.setEvent(getTestEvent(payload));
322 
323             FruitBowl bowl = new FruitBowl();
324             assertFalse(bowl.hasApple());
325             assertFalse(bowl.hasBanana());
326 
327             ep.invoke(bowl, RequestContext.getEventContext());
328 
329             assertTrue(bowl.hasApple());
330             assertTrue(bowl.hasBanana());
331         }
332         finally
333         {
334             RequestContext.setEvent(null);
335         }
336     }
337 
338     /**
339      * Test for proper resolution of an existing method specified as override
340      */
341     public void testExplicitOverride() throws Exception
342     {
343         UMOEntryPointResolver epd = this.getEntryPointResolver();
344         UMODescriptor descriptor = this.getDescriptorToResolve(FruitBowl.class.getName());
345 
346         UMOEntryPoint ep = epd.resolveEntryPoint(descriptor);
347         assertNotNull(ep);
348 
349         try
350         {
351             Object payload = Arrays.asList(new Fruit[]{new Apple(), new Banana()});
352             RequestContext.setEvent(getTestEvent(payload));
353 
354             final String methodName = "setFruit";
355             final String propertyName = MuleProperties.MULE_METHOD_PROPERTY;
356             RequestContext.getEventContext().getMessage().setProperty(propertyName, methodName);
357 
358             FruitBowl bowl = new FruitBowl();
359             assertFalse(bowl.hasApple());
360             assertFalse(bowl.hasBanana());
361 
362             ep.invoke(bowl, RequestContext.getEventContext());
363 
364             assertTrue(bowl.hasApple());
365             assertTrue(bowl.hasBanana());
366         }
367         finally
368         {
369             RequestContext.setEvent(null);
370         }
371     }
372 
373 }