View Javadoc

1   package org.apache.onami.test.handler;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.lang.reflect.Field;
23  import java.lang.reflect.Method;
24  import java.lang.reflect.Modifier;
25  import java.util.HashMap;
26  import java.util.Map.Entry;
27  import java.util.logging.Level;
28  import java.util.logging.Logger;
29  
30  import org.apache.onami.test.annotation.Mock;
31  import org.apache.onami.test.mock.MockEngine;
32  import org.apache.onami.test.reflection.FieldHandler;
33  import org.apache.onami.test.reflection.HandleException;
34  
35  /**
36   * Handler class to handle all {@link Mock} annotations.
37   *
38   * @see org.apache.onami.test.reflection.ClassVisitor
39   * @see Mock
40   */
41  public final class MockHandler
42      implements FieldHandler<Mock>
43  {
44  
45      private static final Logger LOGGER = Logger.getLogger( MockHandler.class.getName() );
46  
47      private final HashMap<Field, Object> mockedObjects = new HashMap<Field, Object>( 1 );
48  
49      /**
50       * Return the mocked objects.
51       * 
52       * @param engine the {@link MockEngine}
53       * @return the map of mocked objects
54       */
55      public HashMap<Field, Object> getMockedObject( MockEngine engine )
56      {
57          createMockedObjectBymockFramekork( engine );
58          return mockedObjects;
59      }
60  
61      private void createMockedObjectBymockFramekork( MockEngine engine )
62      {
63          for ( Entry<Field, Object> entry : mockedObjects.entrySet() )
64          {
65              if ( entry.getValue() instanceof Class<?> )
66              {
67                  Field field = entry.getKey();
68                  Mock mock = field.getAnnotation( Mock.class );
69                  mockedObjects.put( entry.getKey(), engine.createMock( (Class<?>) entry.getValue(), mock.type() ) );
70              }
71          }
72      }
73  
74      
75      /**
76       * Invoked when the visitor founds an element with a {@link Mock} annotation.
77       * @param annotation The {@link Mock} annotation type
78       * @param element the {@link Mock} annotated fiels 
79       * @throws HandleException when an error occurs.    
80       */
81      @SuppressWarnings( "unchecked" )
82      public void handle( final Mock annotation, final Field element )
83          throws HandleException
84      {
85          final Class<? super Object> type = (Class<? super Object>) element.getDeclaringClass();
86  
87          if ( LOGGER.isLoggable( Level.FINER ) )
88          {
89              LOGGER.finer( "      Found annotated field: " + element );
90          }
91          if ( annotation.providedBy().length() > 0 )
92          {
93              Class<?> providedClass = type;
94              if ( annotation.providerClass() != Object.class )
95              {
96                  providedClass = annotation.providerClass();
97              }
98              try
99              {
100                 Method method = providedClass.getMethod( annotation.providedBy() );
101 
102                 if ( !element.getType().isAssignableFrom( method.getReturnType() ) )
103                 {
104                     throw new HandleException( "Impossible to mock %s due to compatibility type, method provider %s#%s returns %s",
105                                                element.getDeclaringClass().getName(),
106                                                providedClass.getName(),
107                                                annotation.providedBy(),
108                                                method.getReturnType().getName() );
109                 }
110                 try
111                 {
112                     Object mocked = getMockProviderForType( element.getType(), method, type );
113                     mockedObjects.put( element, mocked );
114                 }
115                 catch ( Throwable t )
116                 {
117                     throw new HandleException( "Impossible to mock %s, method provider %s#%s raised an error: %s",
118                                                element.getDeclaringClass().getName(),
119                                                providedClass.getName(),
120                                                annotation.providedBy(),
121                                                t );
122                 }
123             }
124             catch ( SecurityException e )
125             {
126                 throw new HandleException( "Impossible to mock %s, impossible to access to method provider %s#%s: %s",
127                                            element.getDeclaringClass().getName(),
128                                            providedClass.getName(),
129                                            annotation.providedBy(),
130                                            e );
131             }
132             catch ( NoSuchMethodException e )
133             {
134                 throw new HandleException( "Impossible to mock %s, the method provider %s#%s doesn't exist.",
135                                            element.getDeclaringClass().getName(),
136                                            providedClass.getName(),
137                                            annotation.providedBy() );
138             }
139         }
140         else
141         {
142             mockedObjects.put( element, element.getType() );
143         }
144     }
145 
146     @SuppressWarnings( "unchecked" )
147     private <T> T getMockProviderForType( T t, Method method, Class<?> cls )
148         throws HandleException
149     {
150         if ( method.getReturnType() == t )
151         {
152             try
153             {
154                 if ( LOGGER.isLoggable( Level.FINER ) )
155                 {
156                     LOGGER.finer( "        ...invoke Provider method for Mock: " + method.getName() );
157                 }
158                 if ( !Modifier.isPublic( method.getModifiers() ) || !Modifier.isStatic( method.getModifiers() ) )
159                 {
160                     throw new HandleException( "Impossible to invoke method %s#%s. The method shuld be 'static public %s %s()",
161                                                cls.getName(),
162                                                method.getName(),
163                                                method.getReturnType().getName(),
164                                                method.getName() );
165                 }
166 
167                 return (T) method.invoke( cls );
168             }
169             catch ( Exception e )
170             {
171                 throw new RuntimeException( e );
172             }
173         }
174         throw new HandleException( "The method: %s should return type %s", method, t );
175     }
176 
177 }