All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.khs.sherpa.servlet.request.DefaultSherpaRequest Maven / Gradle / Ivy

There is a newer version: 1.3.2
Show newest version
package com.khs.sherpa.servlet.request;

/*
 * Copyright 2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.security.DenyAll;
import javax.annotation.security.RolesAllowed;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.cglib.proxy.Enhancer;

import org.apache.commons.lang3.StringUtils;
import org.reflections.ReflectionUtils;
import org.reflections.Reflections;

import com.google.common.base.Predicates;
import com.khs.sherpa.annotation.Action;
import com.khs.sherpa.annotation.Endpoint;
import com.khs.sherpa.annotation.Param;
import com.khs.sherpa.context.ApplicationContext;
import com.khs.sherpa.context.ApplicationContextAware;
import com.khs.sherpa.events.RequestEvent;
import com.khs.sherpa.exception.NoSuchManagedBeanExcpetion;
import com.khs.sherpa.exception.SherpaActionNotFoundException;
import com.khs.sherpa.exception.SherpaPermissionExcpetion;
import com.khs.sherpa.exception.SherpaRuntimeException;
import com.khs.sherpa.json.service.Authentication;
import com.khs.sherpa.json.service.JsonProvider;
import com.khs.sherpa.json.service.SessionStatus;
import com.khs.sherpa.json.service.SessionToken;
import com.khs.sherpa.json.service.SessionTokenService;
import com.khs.sherpa.processor.DefaultRequestProcessor;
import com.khs.sherpa.processor.RequestProcessor;
import com.khs.sherpa.processor.RestfulRequestProcessor;
import com.khs.sherpa.servlet.RequestMapper;
import com.khs.sherpa.util.Constants;
import com.khs.sherpa.util.JsonUtil;
import com.khs.sherpa.util.MethodUtil;
import com.khs.sherpa.util.SherpaPredicates;
import com.khs.sherpa.util.Util;

public class DefaultSherpaRequest implements SherpaRequest {

	private static Logger logger = Logger.getLogger(DefaultSherpaRequest.class.getSimpleName());
	
	private Map attributes = new LinkedHashMap();
	private ApplicationContext applicationContext;
	private HttpServletRequest request;
	private HttpServletResponse response;
	private RequestProcessor requestProcessor;
	
	public Object getAttribute(String name) {
		return attributes.get(name);
	}

	public void setAttribute(String name, Object object) {
		attributes.put(name, object);
	}
	
	public void doService(HttpServletRequest request, HttpServletResponse response) {
		this.request = request;
		this.response = response;
		
		Collection events = applicationContext.getManagedBeans(RequestEvent.class);
		for(RequestEvent event: events) {
			event.before(applicationContext, request, response);
		}
		
		ServletOutputStream output = null;
		JsonProvider jsonProvider = null;
		try {
			output = response.getOutputStream();
			jsonProvider = applicationContext.getManagedBean(JsonProvider.class);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		
		String callback = null;
		if ((Boolean)applicationContext.getAttribute(ApplicationContext.SETTINGS_JSONP)) {
			callback = request.getParameter("callback");
		}
		
		// set the correct Content type
		response.setContentType("application/json");
		if(callback != null) {
			response.setContentType("text/javascript");
		}
		
		try {
			JsonUtil.map(this.proccess(), jsonProvider, output, callback);
		} catch (RuntimeException e) {
			e.printStackTrace();
			JsonUtil.error(e.getMessage(), jsonProvider, output, callback);
			throw e;
		}
		
		for(RequestEvent event: events) {
			event.after(applicationContext, request, response);
		}
	}
	
	@SuppressWarnings("unchecked")
	protected Object proccess() throws SherpaRuntimeException {
		if(!isRestful()) {
			requestProcessor = new DefaultRequestProcessor();
		} else {
			requestProcessor = new RestfulRequestProcessor(applicationContext);
		}
		
		String endpoint = requestProcessor.getEndpoint(request);
		String action = requestProcessor.getAction(request);
		String httpMethod = request.getMethod();
		
		if(StringUtils.isEmpty(endpoint)) {
			if(action.equals(Constants.AUTHENTICATE_ACTION)) {
				return this.processAuthenication();
			} else if(action.equals(Constants.VALID)) {
				return this.processValid();
			}
		}
		
		Object target = null;
		Set methods = null;
		
		try {
			String userid = request.getHeader("userid");
			if(userid == null) {
				userid = request.getParameter("userid");
			}
			String token = request.getHeader("token");
			if(token == null) {
				token = request.getParameter("token");
			}
			
			this.hasPermission(applicationContext.getType(endpoint), userid, token);
			
			target = applicationContext.getManagedBean(endpoint);
			
			if(ApplicationContextAware.class.isAssignableFrom(target.getClass())) {
				((ApplicationContextAware)target).setApplicationContext(applicationContext);
			}
			
			methods = Reflections.getAllMethods(applicationContext.getType(endpoint), 
						Predicates.and(
								Predicates.not(SherpaPredicates.withAssignableFrom(Object.class)),
								ReflectionUtils.withModifier(Modifier.PUBLIC),
								Predicates.not(ReflectionUtils.withModifier(Modifier.ABSTRACT)),
								Predicates.not(SherpaPredicates.withGeneric()),
								Predicates.and(SherpaPredicates.withAssignableFrom(Enhancer.isEnhanced(target.getClass())? target.getClass().getSuperclass(): target.getClass())),
								Predicates.or(
										ReflectionUtils.withName(action),
										Predicates.and(
												ReflectionUtils.withAnnotation(Action.class),
												SherpaPredicates.withActionAnnotationValueEqualTo(action)
											)
									))
						);
			
			if(methods.size() == 0) {
				throw new SherpaActionNotFoundException(action);
			}
			
		} catch (NoSuchManagedBeanExcpetion e) {
			throw new SherpaRuntimeException(e);
		}
		
		return this.processEndpoint(target, methods.toArray(new Method[] {}), httpMethod);
	}
	
	protected Object processEndpoint(Object target, Method[] methods, String httpMethod) {
		Method method = MethodUtil.validateHttpMethods(methods, httpMethod);
		String userid = request.getHeader("userid");
		if(userid == null) {
			userid = request.getParameter("userid");
		}
		String token = request.getHeader("token");
		if(token == null) {
			token = request.getParameter("token");
		}
		
		this.hasPermission(method, userid, token);
		Action annotation = method.getAnnotation(Action.class);
		if (annotation == null) {
			throw new SherpaRuntimeException("Error executing"+target+" @Action annotation required for not endpoint methods"  );
		}
		if(annotation.contentType() != null) {
			response.setContentType(method.getAnnotation(Action.class).contentType().type);
		}
		return this.invokeMethod(target, method);  
	}
	
	protected void hasPermission(Class target, String userid, String token) {
		SessionTokenService service = null;
		try {
			service = applicationContext.getManagedBean(SessionTokenService.class);
		} catch (NoSuchManagedBeanExcpetion e) {
			throw new SherpaRuntimeException(e);
		}
		
		// make sure Endpoint Authentication is turned on
		if((Boolean)applicationContext.getAttribute(ApplicationContext.SETTINGS_ENDPOINT_AUTH) == false) {
			return;
		}
		
		Endpoint endpoint = null;
		if(Enhancer.isEnhanced(target)) {
			endpoint = target.getSuperclass().getAnnotation(Endpoint.class);
		} else {
			endpoint = target.getAnnotation(Endpoint.class);
		}
		
		// make sure its authenicated
		if(endpoint.authenticated() && !service.isActive(userid, token).equals(SessionStatus.AUTHENTICATED)) {
			throw new SherpaPermissionExcpetion("User status [" + service.isActive(userid, token) + "]", service.isActive(userid, token).toString());
		}
	}
	
	protected void hasPermission(Method method, String userid, String token) {
		SessionTokenService service = null;
		try {
			service = applicationContext.getManagedBean(SessionTokenService.class);
		} catch (NoSuchManagedBeanExcpetion e) {
			throw new SherpaRuntimeException(e);
		}

		if(method.isAnnotationPresent(DenyAll.class)) {
			throw new SherpaPermissionExcpetion("method ["+method.getName()+"] in class ["+method.getDeclaringClass().getCanonicalName()+"] has `@DenyAll` annotation", "DENY_ALL");
		}
		
		if(method.isAnnotationPresent(RolesAllowed.class)) {
			boolean fail = true;
			for(String role: method.getAnnotation(RolesAllowed.class).value()) {
				if(service.hasRole(userid, token, role)) {
					fail = false;
				}
			}
			if(fail) {
				throw new SherpaPermissionExcpetion("method ["+method.getName()+"] in class ["+method.getDeclaringClass().getCanonicalName()+"] has `@RolesAllowed` annotation", "DENY_ROLE" );
			}
		}
	}
	
	protected Object processValid()  throws SherpaRuntimeException {
		String userid = request.getParameter("userid");
		String token = request.getParameter("token");
		
		SessionTokenService service = null;
		Map resp = new HashMap();
		try {
			service = applicationContext.getManagedBean(SessionTokenService.class);
		} catch (NoSuchManagedBeanExcpetion e) {
			throw new SherpaRuntimeException(e);
		}

		resp.put("userid", userid);
		resp.put("token", token);
		resp.put("status", service.isActive(userid, token));
		return resp;
		
	}
	
	protected Object processAuthenication() throws SherpaRuntimeException {
		String userid = request.getParameter("userid");
		String password = request.getParameter("password");
		try {
			Authentication authentication = new Authentication(applicationContext);
			SessionToken token = authentication.authenticate(userid, password, request, response);
			
			boolean hasAdminRole = applicationContext.getManagedBean(SessionTokenService.class)
				.hasRole(token.getUserid(), token.getToken(), (String) applicationContext.getAttribute(ApplicationContext.SETTINGS_ADMIN_USER));
			
			// load the sherpa admin user
			if(hasAdminRole) {
				String[] roles = token.getRoles();
				token.setRoles(Util.append(roles, "SHERPA_ADMIN"));
			}
			return token;
		} catch (NoSuchManagedBeanExcpetion e) {
			throw new SherpaRuntimeException(e);
		}
	}
	
	protected Object invokeMethod(Object target, Method method){
		try {
			Object obj = method.invoke(target, this.getParams(method));
			return obj;
		} catch (Exception e) {
	    	if(e.getCause() != null && e.getCause().getClass().isAssignableFrom(SherpaRuntimeException.class)) {
	    		logger.throwing(target.getClass().getName(), method.getName(), e.getCause());
	    		throw new SherpaRuntimeException(e.getCause().getMessage());
	    	}
	    	logger.throwing(target.getClass().getName(), method.getName(), e);
			throw new SherpaRuntimeException("unable to execute method ["+method.getName()+"] in class ["+target.getClass().getCanonicalName()+"]", e);
		} finally {
			
		}
	}
	
	private Object[] getParams(Method method) {
		RequestMapper map = new RequestMapper();
		map.setApplicationContext(applicationContext);
		map.setRequest(request);
		map.setResponse(response);
		map.setRequestProcessor(requestProcessor);
		Class[] types = method.getParameterTypes();
		Object[] params = null;
		// get parameters
		if(types.length > 0) {
			params = new Object[types.length];
		}
		
		Annotation[][] parameters = method.getParameterAnnotations();
		for(int i=0; i type = types[i];
			Annotation annotation = null;
			if(parameters[i].length > 0 ) {
				for(Annotation an: parameters[i]) {
					if(an.annotationType().isAssignableFrom(Param.class)) {
						annotation = an;
						break;
					}
				}
				
			}
			params[i] = map.map(method.getClass().getName(),method.getName(),type, annotation);	
		}
		return params;
	}
	
	private boolean isRestful() {
		String path = request.getContextPath();
		if(path.equals("/")) {
			path = request.getServletPath();
		} else {
			path += request.getServletPath();
		}
		return !path.equals(request.getRequestURI());
	}
	
	@Action(disabled = true)
	public void setApplicationContext(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy