package aop.example;

import aop.example.model.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

/**
 * Аутентификационный аспект
 * обеспечивает проверку того что все контроллеры
 * нуждающиеся в пользователе его получат :)
 * @author Zubairov Renat
 */
public aspect AuthenticationAspect {
	
	// pointcut определяющий метод где мы будем отлавливать исключение
	// если пользователь не аутентифицирован
	// в нашем случае это метод фильтра
	public pointcut doFilterMethod(ServletRequest srequest, ServletResponse sresponse, EntranceFilter filter) :
		execution(void aop.example.EntranceFilter.doFilter(ServletRequest, ServletResponse, FilterChain))
			&& args(srequest, sresponse, FilterChain) && this(filter);


	// pointcut определяющий методы для которых необходима аутентификация
	// в нашем случае это метод сервлета ViewServlet doGet
	// так же захватываем контекст а именно HttpServletRequest
	public pointcut authenticationNeeded(HttpServletRequest request) :
		execution(* aop.example.ViewServlet.doGet(HttpServletRequest, HttpServletResponse)) && args(request, HttpServletResponse);

	/**
	 * Advice запускающийся перед методами нуждающимися в аутентификации
	 * и если пользователь не найдён в сесси, то выбрасывающий исключение
	 */
	before(HttpServletRequest request) : authenticationNeeded(request) {
		// В нашем случае только тогда когда есть хоть один параметр
		// у сервлета, только тогда необходима аутентификация
		if (request.getParameterMap().size() > 0) {
			if (request.getSession().getAttribute(EntranceFilter.USER_KEY) == null) {
				throw new AuthenticationException("User not logged in");
			}
			if (!(request.getSession().getAttribute(EntranceFilter.USER_KEY) instanceof User)) {
				throw new AuthenticationException("Anonymous user access denided");
			}
		}
	}

	/**
	 * Around advice (окружает pointcut - метод фильтра doFilter) 
	 * ловящий исключение и отравляющий запрос пользователя
	 * на страницу с логином если исключение вылетело
	 */
	void around(ServletRequest srequest, ServletResponse sresponse, EntranceFilter filter) throws IOException, ServletException : doFilterMethod(srequest, sresponse, filter) {
		try {
			// Выолняем метод
			proceed(srequest, sresponse, filter);
		} catch (AuthenticationException e) {
			// Сообщение об ошибке если вдруг понадобиться
			srequest.setAttribute("error_message", e.getMessage());
			// Отправляем на страницу с логином
			filter.getConfig().getServletContext().getRequestDispatcher("login.vm").forward(srequest, sresponse);
		}
	}
	
}
