/** * Copyright © 2014 Instituto Superior Técnico * * This file is part of Bennu Spring. * * Bennu Spring is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Bennu Spring is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Bennu Spring. If not, see <http://www.gnu.org/licenses/>. */ package org.fenixedu.bennu.spring.portal; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.fenixedu.bennu.core.util.CoreConfiguration; import org.fenixedu.bennu.portal.model.Application; import org.fenixedu.bennu.portal.model.ApplicationRegistry; import org.fenixedu.bennu.portal.model.Functionality; import org.fenixedu.commons.i18n.LocalizedString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; public class PortalHandlerMapping extends RequestMappingHandlerMapping { private static final Logger logger = LoggerFactory.getLogger(PortalHandlerMapping.class); private static final String[] EMPTY_ARRAY = new String[0]; public static final String DELEGATE = "$DELEGATE_TO_PARENT$"; @Autowired private MessageSource messageSource; private final Map<Class<?>, Functionality> functionalities = new HashMap<>(); private final Map<Class<?>, Application> applicationClasses = new HashMap<>(); @Override protected void initHandlerMethods() { registerApplications(getApplicationContext().getBeansWithAnnotation(SpringApplication.class).values()); registerFunctionalities(getApplicationContext().getBeansWithAnnotation(SpringFunctionality.class).values()); registerLonelyControllers(getApplicationContext().getBeansWithAnnotation(BennuSpringController.class).values()); super.initHandlerMethods(); } private void registerLonelyControllers(Collection<Object> values) { for (Object bean : values) { Class<?> type = bean.getClass(); Class<?> functionalityType = AnnotationUtils.findAnnotation(type, BennuSpringController.class).value(); Functionality functionality = functionalities.get(functionalityType); if (functionality == null) { throw new Error("Controller " + type.getName() + " declares " + functionalityType.getName() + " as a functionality, but it is not one..."); } functionalities.put(type, functionality); } } private void registerApplications(Collection<Object> values) { for (Object bean : values) { Class<?> type = bean.getClass(); SpringApplication app = AnnotationUtils.findAnnotation(type, SpringApplication.class); LocalizedString title = getLocalized(app.title()); Application application = new Application(type.getName(), app.path(), app.group(), title, app.description().equals(DELEGATE) ? title : getLocalized(app.description()), app.hint()); applicationClasses.put(type, application); ApplicationRegistry.registerApplication(application); logger.debug("Registered application for type {}", type); } } private void registerFunctionalities(Collection<Object> values) { for (Object bean : values) { Class<?> type = bean.getClass(); SpringFunctionality model = AnnotationUtils.findAnnotation(type, SpringFunctionality.class); RequestMapping mapping = AnnotationUtils.findAnnotation(type, RequestMapping.class); if (mapping == null) { throw new Error("Functionality type " + type.getName() + " does not declare a @RequestMapping!"); } Application app = applicationClasses.get(model.app()); String path = extractPath(mapping, type); LocalizedString title = getLocalized(model.title()); Functionality functionality = new Functionality(SpringPortalBackend.BACKEND_KEY, "/" + path, path.replace('/', '-'), model.accessGroup() .equals(DELEGATE) ? app.getAccessGroup() : model.accessGroup(), title, model.description().equals( DELEGATE) ? title : getLocalized(model.description())); app.addFunctionality(functionality); functionalities.put(type, functionality); } } private String extractPath(RequestMapping mapping, Class<?> type) { if (ObjectUtils.isEmpty(mapping.value())) { throw new Error("Functionality type " + type.getName() + " does not declare any @RequestMapping mappings!"); } String path = mapping.value()[0]; return path.startsWith("/") ? path.substring(1) : path; } @Override protected HandlerMethod createHandlerMethod(Object handler, Method method) { HandlerMethod handlerMethod = super.createHandlerMethod(handler, method).createWithResolvedBean(); Functionality functionality = functionalities.get(handlerMethod.getBeanType()); return new PortalHandlerMethod(handlerMethod, functionality); } private LocalizedString getLocalized(String key) { LocalizedString.Builder builder = new LocalizedString.Builder(); for (Locale locale : CoreConfiguration.supportedLocales()) { builder.with(locale, messageSource.getMessage(key, EMPTY_ARRAY, "!!" + key + "!!", locale)); } return builder.build(); } }