/** * Internal method to load class methods annotated with {@link MethodMapping} */ private void loadAnnotatedMethods() { Method[] methods = getClass().getDeclaredMethods(); boolean isUsingAuthAnnot = false; for (int i = 0; i < methods.length; i++) { Method method = methods[i]; MethodMapping methodMapped = method.getAnnotation(MethodMapping.class); AuthorizeInvocation authorizeInvocation = method.getAnnotation(AuthorizeInvocation.class); isUsingAuthAnnot = isUsingAuthAnnot || authorizeInvocation != null; if (methodMapped != null) { HttpMethod httpMethod = methodMapped.httpMethod(); MethodMappingInfo urlMappingInfo = new MethodMappingInfo(method, getMimeTypeResolver(method)); if (!isMimeTypesSupported(urlMappingInfo.getMimeInputFormat()) || !isMimeTypesSupported(urlMappingInfo.getMimeOutputFormat())) throw new WicketRuntimeException( "Mapped methods use a MIME type not supported by obj serializer/deserializer!"); mappedMethods.addValue( urlMappingInfo.getSegmentsCount() + "_" + httpMethod.getMethod(), urlMappingInfo); } } // if AuthorizeInvocation has been found but no role-checker has been // configured, throw an exception if (isUsingAuthAnnot && roleCheckingStrategy == null) throw new WicketRuntimeException( "Annotation AuthorizeInvocation is used but no role-checking strategy has been set for the controller!"); }
/** * * Handles a REST request invoking one of the methods annotated with {@link MethodMapping}. If * the annotated method returns a value, this latter is automatically serialized to a given string * format (like JSON, XML, etc...) and written to the web response.<br> * If no method is found to serve the current request, a 400 HTTP code is returned to the client. * Similarly, a 401 HTTP code is return if the user doesn't own one of the roles required to * execute an annotated method (See {@link AuthorizeInvocation}). */ @Override public final void respond(Attributes attributes) { PageParameters pageParameters = attributes.getParameters(); WebResponse response = (WebResponse) attributes.getResponse(); HttpMethod httpMethod = HttpUtils.getHttpMethod((WebRequest) RequestCycle.get().getRequest()); int indexedParamCount = pageParameters.getIndexedCount(); // mapped method are stored concatenating the number of the segments of // their URL and their HTTP method (see annotation MethodMapping) List<MethodMappingInfo> mappedMethodsCandidates = mappedMethods.get(indexedParamCount + "_" + httpMethod.getMethod()); MethodMappingInfo mappedMethod = selectMostSuitedMethod(mappedMethodsCandidates, pageParameters); if (mappedMethod != null) { if (!hasAny(mappedMethod.getRoles())) { response.sendError(401, "User is not allowed to invoke method on server."); return; } onBeforeMethodInvoked(mappedMethod, attributes); Object result = invokeMappedMethod(mappedMethod, attributes); onAfterMethodInvoked(mappedMethod, attributes, result); // if the invoked method returns a value, it is written to response if (result != null) { serializeObjectToResponse(response, result, mappedMethod.getMimeOutputFormat()); } } else { response.sendError( 400, "No suitable method found for URL '" + extractUrlFromRequest() + "' and HTTP method " + httpMethod); } }
/** * Method invoked to select the most suited method to serve the current request. * * @param mappedMethods List of {@link MethodMappingInfo} containing the informations of mapped * methods. * @param pageParameters The PageParameters of the current request. * @return The "best" method found to serve the request. */ private MethodMappingInfo selectMostSuitedMethod( List<MethodMappingInfo> mappedMethods, PageParameters pageParameters) { int highestScore = 0; MultiMap<Integer, MethodMappingInfo> mappedMethodByScore = new MultiMap<Integer, MethodMappingInfo>(); // no method mapped if (mappedMethods == null || mappedMethods.size() == 0) return null; /** * To select the "best" method, a score is assigned to every mapped method. To calculate the * score method calculateScore is executed for every segment. */ for (MethodMappingInfo mappedMethod : mappedMethods) { List<AbstractURLSegment> segments = mappedMethod.getSegments(); int score = 0; for (AbstractURLSegment segment : segments) { int i = segments.indexOf(segment); String currentActualSegment = AbstractURLSegment.getActualSegment(pageParameters.get(i).toString()); int partialScore = segment.calculateScore(currentActualSegment); if (partialScore == 0) { score = -1; break; } score += partialScore; } if (score >= highestScore) { highestScore = score; mappedMethodByScore.addValue(score, mappedMethod); } } // if we have more than one method with the highest score, throw // ambiguous exception. if (mappedMethodByScore.get(highestScore) != null && mappedMethodByScore.get(highestScore).size() > 1) throwAmbiguousMethodsException(mappedMethodByScore.get(highestScore)); return mappedMethodByScore.getFirstValue(highestScore); }