Source Code Cross Referenced for SurrogateManager.java in  » Testing » Surrogate » net » sf » surrogate » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Testing » Surrogate » net.sf.surrogate.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /* Copyright (c) 2005 Per S Hustad. All rights reserved.
002:         *
003:         * Redistribution and use in source and binary forms, with or without 
004:         * modification, are permitted provided that the following conditions are met:
005:         *
006:         *  o Redistributions of source code must retain the above copyright notice, 
007:         *    this list of conditions and the following disclaimer. 
008:         *    
009:         *  o Redistributions in binary form must reproduce the above copyright notice, 
010:         *    this list of conditions and the following disclaimer in the documentation 
011:         *    and/or other materials provided with the distribution. 
012:         *    
013:         *  o Neither the name of surrogate.sourceforge.net nor the names of 
014:         *    its contributors may be used to endorse or promote products derived 
015:         *    from this software without specific prior written permission. 
016:         *    
017:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
018:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
019:         * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
020:         * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
021:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
022:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
023:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
024:         * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
025:         * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
026:         * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
027:         * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028:         */
029:        package net.sf.surrogate.core;
030:
031:        import java.lang.reflect.Constructor;
032:        import java.lang.reflect.Method;
033:        import java.util.Enumeration;
034:        import java.util.Hashtable;
035:
036:        import org.aspectj.lang.JoinPoint;
037:        import org.aspectj.lang.Signature;
038:        import org.aspectj.lang.reflect.CodeSignature;
039:        import org.aspectj.lang.reflect.ConstructorSignature;
040:        import org.aspectj.lang.reflect.MethodSignature;
041:
042:        /**
043:         * The link between Mock/ Unit Test objects and AspectJ code.
044:         * <p> 
045:         * The SurrogateManager is the common controller for Junit tests manipulating
046:         * MockObjects and mock methods.
047:         * <h4>Test Case View</h4>
048:         * The SurrogateManager provides utility methods for test cases to control which
049:         * Mock objects should be active for a particular test case run. These methods
050:         * are normally:
051:         * <pre>
052:         *    {@link #getInstance()}
053:         *    {@link #reset()}
054:         *    {@link #addMock(Object)}
055:         *    {@link #addMockMethod(MockMethod)}
056:         *    {@link #removeMock(Object)}
057:         *    {@link #removeMockMethod(MockMethod)}
058:         * </pre>
059:         * <h4>Aspect View</h4>
060:         * Every time an aspect detects a "mock poincut", it will ask the
061:         * SurrogateManager if a mock object has been registered for the corresponding
062:         * joinpoint. If so, the mock executes instead of the "real" method. Otherwise,
063:         * the real object is allowed to execute. The methods used by the aspects are
064:         * normally:
065:         * <pre>
066:         *   {@link #getInstance()}
067:         *   {@link #getMockExecutor(JoinPoint)}
068:         * </pre>
069:         * <h4>Test Case responsibility</h4>
070:         * A test case should normally always call the {@link #reset}method before
071:         * starting to use the SurrogateManager to avoid independence from other
072:         * testcases which might have been run earlier from within the same VM.
073:         * 
074:         * <h4><a name="Debugging">Debugging </a></h4>
075:         * If the System property "surrogate.debug" is set to "true", e.g. with the java
076:         * <b>-Dsurrogate.debug=true </b> option, the SurrogateManager will report every
077:         * time it is asked to resolve a JoinPoint into a mock object or method. The
078:         * information is written to <code>System.out</code>. Each debug line is on
079:         * the following format:
080:         * <pre>
081:         *   surrogate:&lt;joinpoint id&gt;|added|removed=&lt;mock id&gt;
082:         *   
083:         *   Example:
084:         *   surrogate:added=public static native long java.lang.System.currentTimeMillis()
085:         *   surrogate:added=net.sf.surrogate.example.MockFileWriter@38e059
086:         *   surrogate:call(long java.lang.System.currentTimeMillis())=public static native long java.lang.System.currentTimeMillis()
087:         *   surrogate:call(java.io.FileWriter(String))=net.sf.surrogate.example.MockFileWriter@38e059
088:         *   surrogate:call(java.io.BufferedWriter(Writer))=null
089:         * </pre>
090:         * I.e. the unit test has added mocks for <code>currentTimeMillis</code> and
091:         * the <code>FileWriter</code>. As expected, mocks were returned for the
092:         * <code>currentTimeMillis</code> and <code>FileWriter</code>
093:         * mockJoinPoint's but no mock was found for the</code> BufferedWriter</code>
094:         * joinpoint (<code>null</code> was returned).
095:         * 
096:         * @see SurrogateCalls
097:         * @see MockMethod
098:         * @author Per S Hustad
099:         */
100:        public class SurrogateManager {
101:            private static final String ADDED_MOCK = "added";
102:
103:            private static final String REMOVED_MOCK = "removed";
104:
105:            private static final String SURROGATE_DEBUG = "surrogate.debug";
106:
107:            private static SurrogateManager theInstance = null;
108:
109:            private Hashtable allMocks = new Hashtable();
110:
111:            private Hashtable allMockRefs = new Hashtable();
112:
113:            private boolean isDebugEnabled = false;
114:
115:            /**
116:             * There should ony be one instance of this object in the VM!
117:             */
118:            private SurrogateManager() {
119:
120:                // Check if debug is enabled
121:                String debugOption = System.getProperty(SURROGATE_DEBUG);
122:                isDebugEnabled = Boolean.valueOf(debugOption).booleanValue();
123:            }
124:
125:            /**
126:             * Gets the manager singleton
127:             * 
128:             * @return the manager instance.
129:             * @see #reset
130:             */
131:            public static SurrogateManager getInstance() {
132:                if (theInstance == null) {
133:                    theInstance = createInstance();
134:                }
135:                return theInstance;
136:            }
137:
138:            /**
139:             * Created an instance of the manager. Override this method if you want to
140:             * create a subclass of the manager
141:             * 
142:             * @return a new instance of the manager
143:             */
144:            protected static SurrogateManager createInstance() {
145:                return new SurrogateManager();
146:            }
147:
148:            /**
149:             * Removes all Mock objects and methods from the list of active objects.
150:             * This method should be called by every TestCase method to ensure that
151:             * "old" Mocks created by other testcases are not hanging around in the
152:             * system ...
153:             */
154:            public void reset() {
155:                for (Enumeration e1 = allMocks.elements(); e1.hasMoreElements();) {
156:                    debug(REMOVED_MOCK, e1.nextElement());
157:                }
158:                allMocks.clear();
159:
160:                for (Enumeration e2 = allMockRefs.elements(); e2
161:                        .hasMoreElements();) {
162:                    debug(REMOVED_MOCK, e2.nextElement());
163:                }
164:                allMockRefs.clear();
165:            }
166:
167:            /**
168:             * Adds a Mock object to the manager for later lookup by Aspect code. 
169:             * <p>
170:             * Note that for objects to be substituted with their mock implementation,
171:             * there must have been defined a <code>pointcut</code> intercepting the
172:             * method call or method execution. Otherwise, the mock object will never be
173:             * substituted, even if it has been registered. See {@link SurrogateCalls}
174:             * for pointcut definition details.
175:             * <p>
176:             * Surrogate uses the <code>java.lang.Class.isAssignableFrom</code> to see
177:             * whether the registered mock can subsitute a "real" object. It does this
178:             * by looking up the declared return type signature of the method or the
179:             * class signature of the constructor call.
180:             * <p>
181:             * Example usage:
182:             * 
183:             * <pre>
184:             * 
185:             *       SurrogateManager mm = SurrogateManager.getInstance();
186:             *       mm.reset();
187:             *       MockCustomerService mock = new MockCustomerService();
188:             *       mm.addMock(mock);
189:             *       mock.setGetCustomerReturnValue(&quot;MockCustomer&quot;);
190:             *       ...
191:             *  
192:             * </pre>
193:             * 
194:             * @param o
195:             *            the Mock object to add. Must be non-null.
196:             * @return the Mock object given as argument
197:             * @see #addMockMethod(MockMethod)
198:             * @see #removeMock(Object)
199:             * @see SurrogateCalls
200:             */
201:            public Object addMock(Object o) {
202:                allMocks.put(o.getClass(), o);
203:                debug(ADDED_MOCK, o.toString());
204:                return o;
205:            }
206:
207:            /**
208:             * Adds a mock method to the manager for later lookup by Aspect code.
209:             * <p>
210:             * Note that for objects to be substituted with their mock implementation,
211:             * there must have been defined a <code>pointcut</code> intercepting the
212:             * method call or method execution. Otherwise, the mock object will never be
213:             * substituted, even if it has been registered. See {@link SurrogateCalls}
214:             * for pointcut definition details.
215:             * <p>
216:             * Example usage:
217:             * <pre>
218:             *       SurrogateManager mm = SurrogateManager.getInstance();
219:             *       mm.reset();
220:             *       MockMethod mockTime = 
221:             *            mm.addMockMethod(new MockMethod(System.class,&quot;currentTimeMillis&quot;));
222:             *       mockTime.addReturnValue(1000L);
223:             *       mockTime.addReturnValue(2000L);
224:             *       mockTime.setExpectedCalls(2);
225:             *       ... Call object using System.currentTimeMillis
226:             *       mockTime.verify(); 
227:             *       ...
228:             * </pre>
229:             * 
230:             * @param m
231:             *            the Mock object to add. Must be non-null.
232:             * @return the MockMethod as given on input
233:             * @see #addMock(Object)
234:             * @see #removeMockMethod(MockMethod)
235:             */
236:            public MockMethod addMockMethod(MockMethod m) {
237:                allMockRefs.put(m.getAccessibleObject(), m);
238:                debug(ADDED_MOCK, m.toString());
239:                return m;
240:            }
241:
242:            /**
243:             * Removes a mock from the manager. The object will hence no longer be
244:             * returned instead of a "real" object when the corresponding aspect advice
245:             * executes
246:             * 
247:             * @param o
248:             *            the object to remove.
249:             * @return the removed object or <code>null</code> if the object was not
250:             *         found
251:             * @see #addMock(Object)
252:             */
253:            public Object removeMock(Object o) {
254:                debug(REMOVED_MOCK, o.toString());
255:                return allMocks.remove(o.getClass());
256:            }
257:
258:            /**
259:             * Removes a mock method from the manager. The method will hence no longer
260:             * execute instead of the "real" method when the corresponding aspect advice
261:             * executes.
262:             * 
263:             * @param o
264:             *            the object to remove.
265:             * @return the removed method or <code>null</code> if the mock method was
266:             *         not found.
267:             * @see #addMockMethod(MockMethod)
268:             */
269:            public MockMethod removeMockMethod(MockMethod m) {
270:                debug(REMOVED_MOCK, m.toString());
271:                return (MockMethod) allMockRefs.remove(m.getAccessibleObject());
272:            }
273:
274:            /**
275:             * Locates and gets a Mock object for an interface or a class. This method
276:             * looks for a Mock object implementing the interface or the class
277:             * assignable from <code>myClassOrInterface</code> by searching in the
278:             * list of Mock objects for the first object which
279:             * <code>myClassOrInterface</code> is assignable from
280:             * 
281:             * @param myClassOrInterface
282:             *            the interface/class to find a mock object for
283:             * @return the Mock object for the interface/class or <code>null</code> if
284:             *         no such mock object has been registered via the
285:             *         <code>addMock</code> method.
286:             * @see #addMock(Object)
287:             * @see Class#isAssignableFrom(java.lang.Class)
288:             */
289:            Object getMockObject(Class myClassOrInterface) {
290:                for (Enumeration keys = allMocks.keys(); keys.hasMoreElements();) {
291:                    Class c = (Class) keys.nextElement();
292:                    if (myClassOrInterface.isAssignableFrom(c)) {
293:                        return allMocks.get(c);
294:                    }
295:                }
296:                return null;
297:            }
298:
299:            /**
300:             * Gets a registered <code>Mock method reference</code> for a method. This
301:             * method should normally only be called from the aspect code.
302:             * 
303:             * @param m
304:             *            the Method to check
305:             * @return the registered Mock method reference or <code>null</code> if no
306:             *         such reference exists for the method
307:             * @see #addMockMethod(MockMethod)
308:             */
309:            MockMethod getMockMethod(Method m) {
310:                return (MockMethod) allMockRefs.get(m);
311:            }
312:
313:            /**
314:             * Gets a registered <code>Mock method reference</code> for a constructor
315:             * 
316:             * @param c
317:             *            the constructor to check
318:             * @return the registered Mock method reference or <code>null</code> if no
319:             *         such reference exists for the method
320:             * @see #addMockMethod(MockMethod)
321:             */
322:            MockMethod getMockConstructor(Constructor c) {
323:                return (MockMethod) allMockRefs.get(c);
324:            }
325:
326:            /**
327:             * Checks if an AspectJ "mock" joinpoint has an assoicated mock object
328:             * registered by the manager.
329:             * 
330:             * @param p
331:             *            the join point
332:             * @return the corresponding mock object or <code>null</code> if no match
333:             *         is found
334:             */
335:            protected Object getReturnedClassMock(JoinPoint p)
336:                    throws IllegalArgumentException {
337:                Signature sig = p.getSignature();
338:                Class c = null;
339:                if (sig instanceof  MethodSignature) {
340:                    c = ((MethodSignature) sig).getReturnType();
341:                } else if (sig instanceof  ConstructorSignature) {
342:                    c = ((CodeSignature) sig).getDeclaringType();
343:                } else {
344:                    throw new IllegalArgumentException("Unhandled Signature: "
345:                            + sig.getClass().getName());
346:                }
347:                return getMockObject(c);
348:            }
349:
350:            /**
351:             * Checks if an AspectJ "mock" joinpoint has an assoicated mock method
352:             * registered by the manager.
353:             * 
354:             * @param p
355:             *            the join point
356:             * @return the corresponding mock method or <code>null</code> if no match
357:             *         is found
358:             * @throws IllegalArgumentException
359:             *             if the joinpoint signature is not a "method" or "constructor"
360:             *             signature
361:             */
362:            protected MockMethod getMockMethod(JoinPoint p)
363:                    throws IllegalArgumentException, NoSuchMethodException {
364:                MockMethod mockMethod;
365:                CodeSignature sig = (CodeSignature) p.getSignature();
366:                Class c = sig.getDeclaringType();
367:                if (sig instanceof  ConstructorSignature) {
368:                    Constructor constr = c.getDeclaredConstructor(sig
369:                            .getParameterTypes());
370:                    mockMethod = getMockConstructor(constr);
371:                } else if (sig instanceof  MethodSignature) {
372:                    Method m = c.getDeclaredMethod(sig.getName(), sig
373:                            .getParameterTypes());
374:                    mockMethod = getMockMethod(m);
375:                } else {
376:                    throw new IllegalArgumentException("Unhandled Signature: "
377:                            + sig.getClass().getName());
378:                }
379:                return mockMethod;
380:
381:            }
382:
383:            /**
384:             * Gets the mock object or mock method for a joinpoint. This method should
385:             * normally only be called from the corresponding
386:             * <code>SurrogateCalls</code> advice but can also be called from other
387:             * advices which might want to check if a mock matches the joinpoint.
388:             * <p>
389:             * The rules are as follows
390:             * <ul>
391:             * <li>If a <code>MockMethod</code> matches the joinpoint, this method is
392:             * returned.
393:             * <li>Otherwise, if a Mock object matches the joinpoint, this object is
394:             * returned, wrapped behind a <code>MockExecutor</code>
395:             * <li>Otherwise, <code>null</code> is returned.
396:             * </ul>
397:             * The advices should, if receiving a non-null <code>MockExecutor</code>
398:             * return value, call the <code>MockExecutor.execute</code> with the
399:             * <b>same </b> JoinPoint as used as arguments to
400:             * <code>getMockExecutor</code>. If the returned
401:             * <code>MockExecutor</code> is <code>null</code>, the advice should
402:             * return a sensible value, e.g. with <code>return proceed();</code>
403:             * 
404:             * @param p
405:             *            the <code>thisJoinPoint</code> on the advice executing
406:             * @return the corresponding mock executor or <code>null</code> if no
407:             *         match has been found with a registered mock object or mock method
408:             * 
409:             * @throws IllegalArgumentException
410:             *             if the joinpoint signature is not a "constructor" or "method"
411:             *             signature.
412:             * 
413:             * @throws NoSuchMethodException
414:             *             if the joinpoint is inconsistent. This should normally be
415:             *             considered as a bug.
416:             * @see SurrogateCalls
417:             * @see #addMock(Object)
418:             * @see #addMockMethod(MockMethod)
419:             */
420:            public MockExecutor getMockExecutor(JoinPoint p)
421:                    throws IllegalArgumentException, NoSuchMethodException {
422:                MockMethod m = getMockMethod(p);
423:                if (m != null) {
424:                    debug(p.toString(), m.toString());
425:                    return m;
426:                }
427:                Object o = getReturnedClassMock(p);
428:                if (o != null) {
429:                    debug(p.toString(), o.toString());
430:                    return new MockExecutorWrapper(o);
431:                }
432:                debug(p.toString(), null);
433:                return null;
434:
435:            }
436:
437:            /**
438:             * Prints debug information if debug is enabled.
439:             * 
440:             * @param pred
441:             *            the predicate
442:             * @param mockId
443:             *            the mock ID
444:             * @see #Debugging
445:             */
446:            private void debug(String pred, Object mockId) {
447:                if (isDebugEnabled) {
448:                    System.out.println("surrogate:" + pred + "="
449:                            + (mockId != null ? mockId : "null"));
450:                }
451:            }
452:
453:            /**
454:             * Defines, towards the AspectJ layer, the mock object or method to be
455:             * executed.
456:             * 
457:             * @author Per S Hustad
458:             */
459:            public static interface MockExecutor {
460:                /**
461:                 * If the manager returns a non-null MockExecutor, the calling advice
462:                 * should call "execute" and return the "execute" return value. The
463:                 * throwable can be cached and rethrown with the
464:                 * <code>ExceptionThrower</code> utility.
465:                 * 
466:                 * @param args
467:                 *            the arguments, always use
468:                 *            <code>thisJoinPoint.getArgs()<code>
469:                 *            Ignored if the underlying mock is a mock object but used
470:                 *            if it is a MockMethod.
471:                 * @return the return value of the underlying mock object. If the
472:                 *         underlying mock object is a <code>MockMethod</code>, the return value as
473:                 *         setup in the method is returned. If the underlying object is
474:                 *         a plain mock object, that object is returned
475:                 * @throws Throwable
476:                 *             if a <code>MockMethod</code> has been set up explicitly to throw an
477:                 *             exeption or there was a mismatch between the JoinPoint args and
478:                 *             the method args.
479:                 */
480:                public Object execute(Object[] args) throws Throwable;
481:            }
482:
483:            /**
484:             * Wrapper class to wrap a standard mock object as a MockExecutor. This
485:             * class exists in order to provide a uniform interface to the AspectJ
486:             * layer.
487:             * 
488:             * @author Per S Hustad
489:             */
490:            private static final class MockExecutorWrapper implements 
491:                    MockExecutor {
492:
493:                private Object mockObject;
494:
495:                public MockExecutorWrapper(Object o) {
496:                    mockObject = o;
497:                }
498:
499:                public Object execute(Object[] args) {
500:                    return mockObject;
501:                }
502:
503:            }
504:
505:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.