diff --git a/src/main/java/de/thm/arsnova/aop/RangeAspect.java b/src/main/java/de/thm/arsnova/aop/RangeAspect.java index 3ab757f6883c1fec3342338dabe0b147e29580a4..16d47ddd0550b4f1b3678b6b4c0eb56ad91a65b2 100644 --- a/src/main/java/de/thm/arsnova/aop/RangeAspect.java +++ b/src/main/java/de/thm/arsnova/aop/RangeAspect.java @@ -17,13 +17,16 @@ */ package de.thm.arsnova.aop; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -31,37 +34,62 @@ import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import de.thm.arsnova.controller.PaginationController; +import de.thm.arsnova.services.ResponseProviderService; @Component @Aspect @Profile("!test") public class RangeAspect { + @Autowired private HttpServletRequest request; + @Autowired + private ResponseProviderService responseProviderService; + private final Pattern rangePattern = Pattern.compile("^items=([0-9]+)-([0-9]+)?$"); private static final Logger logger = LoggerFactory.getLogger(RangeAspect.class); - /** Sets start and end parameters based on range header + /** Sets start and end parameters based on request's range header + * and sets content range header for the response * * @param controller + * @throws Throwable */ - @Before("execution(* de.thm.arsnova.controller.*.*(..)) && this(controller) && @annotation(de.thm.arsnova.web.Pagination)") - public void parsePaginationRange(final PaginationController controller) { + @Around("execution(java.util.List+ de.thm.arsnova.controller.*.*(..)) && this(controller) && @annotation(de.thm.arsnova.web.Pagination)") + public Object handlePaginationRange(ProceedingJoinPoint pjp, final PaginationController controller) throws Throwable { + logger.debug("handlePaginationRange"); String rangeHeader = request.getHeader("Range"); Matcher matcher = null; + int start = -1; + int end = -1; + if (rangeHeader != null) { matcher = rangePattern.matcher(rangeHeader); } if (matcher != null && matcher.matches()) { - int start = matcher.group(1) != null ? Integer.valueOf(matcher.group(1)) : -1; - int end = matcher.group(2) != null ? Integer.valueOf(matcher.group(2)) : -1; + start = matcher.group(1) != null ? Integer.valueOf(matcher.group(1)) : -1; + end = matcher.group(2) != null ? Integer.valueOf(matcher.group(2)) : -1; logger.debug("Pagination: {}-{}", start, end); - controller.setRange(start, end); - } else { - controller.setRange(-1, -1); } + controller.setRange(start, end); + + List<?> list = (List<?>) pjp.proceed(); + + if (matcher != null && matcher.matches()) { + /* Header format: "items <start>-<end>/<total>" + * + * The value for end is calculated since the result list + * could be shorter than requested. + * + * TODO: Set correct value for total */ + String rangeStr = String.format("items %d-%d/%d", start, start + list.size() - 1, -1); + HttpServletResponse response = responseProviderService.getResponse(); + response.addHeader("Content-Range", rangeStr); + } + + return list; } } diff --git a/src/main/java/de/thm/arsnova/services/ResponseProviderService.java b/src/main/java/de/thm/arsnova/services/ResponseProviderService.java new file mode 100644 index 0000000000000000000000000000000000000000..19b1713f7d2a9e6a475d49fa139cf83573fbcec7 --- /dev/null +++ b/src/main/java/de/thm/arsnova/services/ResponseProviderService.java @@ -0,0 +1,26 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.services; + +import javax.servlet.http.HttpServletResponse; + +public interface ResponseProviderService { + public void setResponse(HttpServletResponse response); + + public HttpServletResponse getResponse(); +} diff --git a/src/main/java/de/thm/arsnova/services/ResponseProviderServiceImpl.java b/src/main/java/de/thm/arsnova/services/ResponseProviderServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..d4791011599b9793ae82b8f32417690a49cc4ee8 --- /dev/null +++ b/src/main/java/de/thm/arsnova/services/ResponseProviderServiceImpl.java @@ -0,0 +1,42 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.services; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.stereotype.Service; + +@Service +@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) +public class ResponseProviderServiceImpl implements ResponseProviderService { + + HttpServletResponse response; + + @Override + public void setResponse(HttpServletResponse response) { + this.response = response; + } + + @Override + public HttpServletResponse getResponse() { + return response; + } + +} diff --git a/src/main/java/de/thm/arsnova/web/ResponseInterceptorHandler.java b/src/main/java/de/thm/arsnova/web/ResponseInterceptorHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..27f15d10e977de8d5ab4b75d0c1211ecf1c76fef --- /dev/null +++ b/src/main/java/de/thm/arsnova/web/ResponseInterceptorHandler.java @@ -0,0 +1,46 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.web; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import de.thm.arsnova.services.ResponseProviderService; + +@Component +public class ResponseInterceptorHandler extends HandlerInterceptorAdapter { + + @Autowired + ResponseProviderService responseProviderService; + + @Override + public boolean preHandle( + HttpServletRequest request, + HttpServletResponse response, + Object handler + ) throws Exception { + responseProviderService.setResponse(response); + + return true; + }; + +} diff --git a/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml b/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml index 5e4bf336a267447340603e6c341a7dbef753c32f..c9c760e7c93c970c2c33bc6e15566d1762bae87e 100644 --- a/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml +++ b/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml @@ -21,6 +21,7 @@ <mvc:interceptors> <bean class="de.thm.arsnova.web.CacheControlInterceptorHandler" /> <bean class="de.thm.arsnova.web.DeprecatedApiInterceptorHandler" /> + <bean class="de.thm.arsnova.web.ResponseInterceptorHandler" /> </mvc:interceptors> <aop:aspectj-autoproxy />