001 package com.softwarementors.extjs.djn.scanner; 002 003 import java.lang.reflect.Method; 004 import java.util.HashMap; 005 import java.util.List; 006 import java.util.Map; 007 008 import org.apache.log4j.Logger; 009 010 import com.softwarementors.extjs.djn.ClassUtils; 011 import com.softwarementors.extjs.djn.api.RegisteredAction; 012 import com.softwarementors.extjs.djn.api.RegisteredApi; 013 import com.softwarementors.extjs.djn.api.RegisteredMethod; 014 import com.softwarementors.extjs.djn.api.RegisteredPollMethod; 015 import com.softwarementors.extjs.djn.api.Registry; 016 import com.softwarementors.extjs.djn.config.ApiConfiguration; 017 import com.softwarementors.extjs.djn.config.ApiConfigurationException; 018 import com.softwarementors.extjs.djn.config.annotations.DirectAction; 019 import com.softwarementors.extjs.djn.config.annotations.DirectFormPostMethod; 020 import com.softwarementors.extjs.djn.config.annotations.DirectMethod; 021 import com.softwarementors.extjs.djn.config.annotations.DirectPollMethod; 022 023 public class Scanner { 024 025 private static final Logger logger = Logger.getLogger( Scanner.class); 026 027 private Registry registry; 028 029 public Scanner() { 030 // Do nothing 031 } 032 033 public void scanAndRegisterApiConfigurations(Registry registry, List<ApiConfiguration> apiConfigurations) { 034 assert registry != null; 035 assert apiConfigurations != null; 036 037 this.registry = registry; 038 for( ApiConfiguration api: apiConfigurations ) { 039 scanAndRegisterApiConfiguration(api); 040 } 041 } 042 043 /* package */ void scanAndRegisterApiConfiguration(ApiConfiguration api) { 044 assert api != null; 045 046 if( this.registry.hasApi( api.getName() )) { 047 ApiConfigurationException ex = ApiConfigurationException.forApiAlreadyRegistered( api.getName()); 048 logger.fatal( ex.getMessage(), ex ); 049 throw ex; 050 } 051 052 RegisteredApi registeredApi = this.registry.addApi( api.getName(), api.getFullApiFileName(), api.getApiNamespace(), api.getActionsNamespace()); 053 054 List<Class<?>> actionClasses = api.getClasses(); 055 for( Class<?> cls : actionClasses ) { 056 assert cls != null; 057 scanAndRegisterActionClass(registeredApi, cls ); 058 } 059 } 060 061 private void scanAndRegisterActionClass( RegisteredApi api, Class<?> actionClass ) { 062 assert api != null; 063 assert actionClass != null; 064 065 Map<Class<?>, RegisteredAction> actionsByClass = new HashMap<Class<?>, RegisteredAction>(); 066 067 if( actionsByClass.containsKey( actionClass ) ) { 068 ApiConfigurationException ex = ApiConfigurationException.forClassAlreadyRegisteredAsAction(actionClass); 069 logger.fatal( ex.getMessage(), ex ); 070 throw ex; 071 } 072 073 if( logger.isDebugEnabled() ) { 074 logger.debug( "Scanning Java class: " + actionClass.getName() ); 075 } 076 077 RegisteredAction action = createActionFromJavaClass(api, actionClass); 078 079 scanAndRegisterAllKindsOfMethods(api, action); 080 actionsByClass.put( actionClass, action); 081 } 082 083 private RegisteredAction createActionFromJavaClass(RegisteredApi api, Class<?> actionClass) { 084 assert api != null; 085 assert actionClass != null; 086 087 DirectAction actionAnnotation = actionClass.getAnnotation(DirectAction.class); 088 String actionName = ""; 089 if( actionAnnotation != null ) { 090 actionName = actionAnnotation.action(); 091 } 092 093 if( actionName.equals("")) { 094 actionName = ClassUtils.getSimpleName(actionClass); 095 } 096 097 if( this.registry.hasAction( actionName ) ) { 098 RegisteredAction existingAction = this.registry.getAction( actionName ); 099 ApiConfigurationException ex = ApiConfigurationException.forActionAlreadyRegistered(actionName, actionClass, existingAction.getActionClass()); 100 logger.fatal( ex.getMessage(), ex ); 101 throw ex; 102 } 103 RegisteredAction action = api.addAction( actionClass, actionName ); 104 105 return action; 106 } 107 108 private static final String POLL_METHOD_NAME_PREFIX = "djnpoll_"; 109 private static final String FORM_POST_METHOD_NAME_PREFIX = "djnform_"; 110 private static final String STANDARD_METHOD_NAME_PREFIX = "djn_"; 111 112 private void scanAndRegisterAllKindsOfMethods(RegisteredApi api, RegisteredAction action) { 113 assert api != null; 114 assert action != null; 115 116 // *All* methods are candidates, including those in base classes, 117 // even if the base class does not have a DirectAction annotation! 118 Method[] methods = action.getActionClass().getDeclaredMethods(); // Get private, protected and other methods! 119 120 for( Method method : methods ) { 121 // Check if the kind of direct method -if any 122 DirectMethod methodAnnotation = method.getAnnotation(DirectMethod.class); 123 boolean isStandardMethod = methodAnnotation != null; 124 if( !isStandardMethod ) { 125 isStandardMethod = method.getName().startsWith(STANDARD_METHOD_NAME_PREFIX); 126 } 127 128 DirectFormPostMethod postMethodAnnotation = method.getAnnotation(DirectFormPostMethod.class); 129 boolean isFormPostMethod = postMethodAnnotation != null; 130 if( !isFormPostMethod ) { 131 isFormPostMethod = method.getName().startsWith(FORM_POST_METHOD_NAME_PREFIX); 132 } 133 134 DirectPollMethod pollMethodAnnotation = method.getAnnotation(DirectPollMethod.class); 135 boolean isPollMethod = pollMethodAnnotation != null; 136 if( !isPollMethod ) { 137 isPollMethod = method.getName().startsWith( POLL_METHOD_NAME_PREFIX ); 138 } 139 140 // Check that a method is just of only one kind of method 141 if( isStandardMethod && isFormPostMethod ) { 142 ApiConfigurationException ex = ApiConfigurationException.forMethodCantBeStandardAndFormPostMethodAtTheSameTime(action, method); 143 logger.fatal( ex.getMessage(), ex ); 144 throw ex; 145 } 146 if( (methodAnnotation != null || postMethodAnnotation != null) && isPollMethod) { 147 ApiConfigurationException ex = ApiConfigurationException.forPollMethodCantBeStandardOrFormPostMethodAtTheSameTime(action, method); 148 logger.fatal( ex.getMessage(), ex ); 149 throw ex; 150 } 151 152 // Process standard and form post methods together, as they are very similar 153 if( isStandardMethod || isFormPostMethod) { 154 155 String methodName = ""; 156 if( isStandardMethod ) { 157 methodName = getStandardMethodName(method, methodAnnotation); 158 } 159 else { 160 methodName = getFormPostMethodName( method, postMethodAnnotation); 161 } 162 if( action.hasMethod(methodName) ) { 163 ApiConfigurationException ex = ApiConfigurationException.forMethodAlreadyRegisteredInAction(methodName, action.getName()); 164 logger.fatal( ex.getMessage(), ex ); 165 throw ex; 166 } 167 168 if( isFormPostMethod && !RegisteredMethod.isValidFormHandlingMethod(method)) { 169 ApiConfigurationException ex = ApiConfigurationException.forMethodHasWrongParametersForAFormHandler( action.getName(), methodName ); 170 logger.fatal( ex.getMessage(), ex ); 171 throw ex; 172 } 173 174 175 action.addMethod( methodName, method, isFormPostMethod ); 176 } 177 178 // Process "poll" method 179 if( isPollMethod ) { 180 createPollMethod(api, method, pollMethodAnnotation); 181 } 182 } 183 } 184 185 private String getFormPostMethodName(Method method, DirectFormPostMethod postMethodAnnotation) { 186 String methodName = ""; 187 if( postMethodAnnotation != null ) { 188 methodName = postMethodAnnotation.method(); 189 } 190 if( methodName.equals("" )) { 191 methodName = method.getName(); 192 } 193 if( methodName.startsWith(FORM_POST_METHOD_NAME_PREFIX)) { 194 methodName = method.getName().substring(FORM_POST_METHOD_NAME_PREFIX.length()); 195 } 196 return methodName; 197 } 198 199 private String getStandardMethodName(Method method, DirectMethod methodAnnotation) { 200 String methodName = ""; 201 if( methodAnnotation != null ) { 202 methodName = methodAnnotation.method(); 203 } 204 if( methodName.equals("" )) { 205 methodName = method.getName(); 206 } 207 if( methodName.startsWith(STANDARD_METHOD_NAME_PREFIX)) { 208 methodName = method.getName().substring(STANDARD_METHOD_NAME_PREFIX.length()); 209 } 210 return methodName; 211 } 212 213 private RegisteredPollMethod createPollMethod(RegisteredApi api, Method method, DirectPollMethod pollMethodAnnotation) { 214 assert api != null; 215 assert method != null; 216 217 String eventName = getEventName(method, pollMethodAnnotation); 218 219 if( this.registry.hasPollMethod(eventName)) { 220 ApiConfigurationException ex = ApiConfigurationException.forPollEventAlreadyRegistered( eventName ); 221 logger.fatal( ex.getMessage(), ex ); 222 throw ex; 223 } 224 225 if( !RegisteredPollMethod.isValidPollMethod(method)) { 226 ApiConfigurationException ex = ApiConfigurationException.forMethodHasWrongParametersForAPollHandler( method ); 227 logger.fatal( ex.getMessage(), ex ); 228 throw ex; 229 } 230 231 RegisteredPollMethod poll = api.addPollMethod( eventName, method); 232 return poll; 233 } 234 235 private String getEventName(Method method, DirectPollMethod pollMethodAnnotation) { 236 assert method != null; 237 238 String eventName = ""; 239 if( pollMethodAnnotation != null ) { 240 eventName = pollMethodAnnotation.event(); 241 } 242 if( eventName.equals("")) { 243 eventName = method.getName(); 244 } 245 if( eventName.startsWith(POLL_METHOD_NAME_PREFIX)) { 246 eventName = method.getName().substring(POLL_METHOD_NAME_PREFIX.length()); 247 } 248 return eventName; 249 } 250 251 }