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

com.terapico.caf.ServletInvocationContextFactory Maven / Gradle / Ivy

package com.terapico.caf;

import org.springframework.context.ApplicationContext;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;

public class ServletInvocationContextFactory extends ReflectionTool implements InvocationContextFactory {
	private int start = 1;
	private String formBuilderBeanName = "formbuilder";
	private String formBuilderMethodName = "buildForm";

	private BeanFactory beanFactory = null;
	private ApplicationContext mApplicationContext;

	public ServletInvocationContextFactory(ApplicationContext pApplicationContext) {
		super();
		mApplicationContext = pApplicationContext;
	}

	public ServletInvocationContextFactory() {
		super();
	}

	protected int getStart() {
		return start;
	}

	public void setStart(int start) {
		this.start = start;
	}

	public synchronized BeanFactory getBeanFactory() {

		if (beanFactory == null) {
			beanFactory = new SpringBeanFactory(mApplicationContext);
		}
		return beanFactory;
	}

	public void setBeanFactory(BeanFactory beaFactory) {
		this.beanFactory = beaFactory;
	}

	public static final String OVERRIDE_URI = "__overrideURI";

	protected String getRequestPath(HttpServletRequest request) {
		String overrideURI = (String) request.getAttribute(OVERRIDE_URI);

		if (overrideURI != null) {
			return overrideURI;
		}
		String path = request.getRequestURI().substring(request.getContextPath().length());

		return path;

	}

	public InvocationContext create(Object input) throws InvocationException {

		if (input == null) {
			throw new IllegalArgumentException("Could not create the call, the input parameter is null");
		}

		if (!(input instanceof HttpServletRequest)) {
			throw new IllegalArgumentException("Could not create the call context since the type is: "
					+ input.getClass().getName() + ", Expected class: HttpServletRequest");
		}

		HttpServletRequest request = (HttpServletRequest) input;

		List urlElements = parse(request);

		if (urlElements.size() < start + 1) {
			throw new InvocationException("No sufficient parameter to call" + String.join(" and ", urlElements));
		}

		Object targetObject = getBean(request, urlElements);

		if (targetObject == null) {
			throw new InvocationException("Not able to find the target object to call: " + request.getRequestURI());
		}

		Method targetMethod = this.getMethod(request, targetObject, urlElements);

		if (targetMethod == null) {
			throw new InvocationException("Not able to find the target method to call: " + request.getRequestURI());
		}
		if (!hasRightNumberOfParameters(request, urlElements, targetMethod)) {
			Object[] parameters = this.getCandidateParameters(urlElements);
			return buildFormContext(getBeanName(urlElements), targetMethod, parameters);
		}

		Object[] parameters = this.getParameters(request, targetObject, urlElements, targetMethod);

		SimpleInvocationContext context = createNewInvocationContext();
		context.setTargetObject(targetObject);
		context.setTargetMethod(targetMethod);
		context.setParameters(parameters);
		return context;

	}

	protected List parse(HttpServletRequest request) throws InvocationException {
		if(isPostingJSONRequest(request)){
			return this.parsePut(request);
		}
		if (isPostRequest(request)) {
			return this.parsePost(request);
		}
		if (isPutRequest(request)) {
			return this.parsePut(request);
		}


		return this.parseGet(request);
	}

	protected SimpleInvocationContext createNewInvocationContext() {
		return new SimpleInvocationContext();
	}

	protected InvocationContext buildFormContext(String beanName, Method targetMethod, Object[] parameters)
			throws InvocationException {

		SimpleInvocationContext context = new SimpleInvocationContext();
		Object formBuilder = getBean(formBuilderBeanName);
		if (formBuilder == null) {
			throw new InvocationException("Form Builder can not be found with the name: " + formBuilderBeanName);
		}

		context.setTargetObject(formBuilder);
		Method method = findSingleMethod(formBuilder, formBuilderMethodName);
		if (method == null) {
			throw new InvocationException("Form Builder method can not be found with the name: " + formBuilderBeanName
					+ "." + formBuilderMethodName);
		}

		context.setTargetMethod(method);
		context.setParameters(new Object[] { beanName, targetMethod, parameters });
		return context;
	}

	protected int expectedCountOfParameters(HttpServletRequest request, List urlElements, Method targetMethod) {

		if(isPostingJSONRequest(request)){
			return 1;
		}
		if (isPutRequest(request)) {
			return 1;
		}
		int size = urlElements.size();
		return (size - start - 2);
	}

	protected boolean hasRightNumberOfParameters(HttpServletRequest request, List urlElements,
			Method targetMethod) {
		Type[] parameterTypes = targetMethod.getGenericParameterTypes();

		int expectedParameterCount = this.expectedCountOfParameters(request, urlElements, targetMethod);

		return expectedParameterCount == parameterTypes.length;

	}

	protected Object getBean(HttpServletRequest request, List urlElements) {

		String beanName = urlElements.get(start);
		return getBean(beanName);
	}

	protected String getBeanName(List urlElements) {

		return urlElements.get(start);

	}

	protected Object getBean(String beanName) {
		return this.getBeanFactory().getBean(beanName);
	}

	protected Object[] getCandidateParameters(List urlElements) {

		// Object [] parameters=new String[urlElements.size()-start-2];
		Object elements[] = urlElements.toArray();
		Object[] parameters = Arrays.copyOfRange(elements, start + 2, urlElements.size());

		return parameters;

	}

	protected Object[] getParameters(HttpServletRequest request, Object targetObject, List urlElements,
			Method method) {
		System.out.println(urlElements);
		Type[] parameterTypes = method.getGenericParameterTypes();
		if (parameterTypes.length == 0) {
			return new Object[] {};
		}
		// Object [] parameters=new String[urlElements.size()-start-2];
		Object elements[] = urlElements.toArray();
		Object[] parameters = Arrays.copyOfRange(elements, start + 2, urlElements.size());
		if (isPutRequest(request)) {
			return getPutParameters(parameterTypes, parameters, request);
		}
		if (isPostingJSONRequest(request)) {
			return getPutParameters(parameterTypes, parameters, request);
		}
		checkParametersLength(parameterTypes, parameters);

		if (isGetRequest(request)) {
			return getParameters(parameterTypes, parameters, request);
		}
		if (isPostRequest(request)) {
			return getPostParameters(parameterTypes, parameters, request);
		}

		return getParameters(parameterTypes, parameters, request);

	}

	protected void checkParametersLength(Type[] parameterTypes, Object[] parameters) {
		if (parameterTypes.length != parameters.length) {
			throw new IllegalArgumentException("The parameter length expect be:" + parameterTypes.length
					+ " but the actual length is:" + parameters.length);
		}
	}

	protected Object[] getParameters(Type[] types, Object[] parameters, HttpServletRequest request) {
		// TODO Auto-generated method stub
		return super.getParameters(types, parameters);
	}

	/*
	 * 处理PUT请求,只是允许两种情况 如果这个函数包括了userContext,那么允许两个参数
	 * 如果这个函数没有包括userContext,那么只是允许一个参数 没有UC的情况下,只是允许一个参数
	 * 
	 */
	protected Object[] getPutParameters(Type[] types, Object[] parameters, HttpServletRequest request) {
		int length = types.length;

		if (length == 0) {
			return new Object[] {};
			//
		}
		if (length > 1) {
			throw new IllegalArgumentException(
					"For put method without a userContext parameter, only one parameter allowed");
		}
		
		
		if(ReflectionTool.isFirstParameterByteArray(types)) {
			return new Object[] {this.readBodyAsBytes(request)};
		}
		// only one parameter allowed, the body should be a json object string

		String strExpr = this.readBodyAsString(request);
		Object object = ReflectionTool.convertOnlyOneParameter(types, strExpr);
		// return new Object[] {strExpr};
		return new Object[] { object };

	}

	/*
	 * 处理POST请求, 请求的路径的格式不变,不过路径里面的各个参数不是最终的值,而是要经过request.getParameter之后取得的值 比如
	 * POST /serviceMethod/param1/param2/
	 * 此时,对于serviceMethod而言,param1只是表示参数的名字,正确的表示是 POST
	 * /serviceMethod/param1Name/param2Name/ 而不是值,在调用serviceMethod之前,必须要通过 Object
	 * param1 = request.getParameter("param1Name") 来获得,一次类推 Object param2 =
	 * request.getParameter("param2Name") 但是,当目标类型是一个数组的时候,要取得的参数就是 Object[] param3
	 * = request.getParameterValues("param3");
	 */
	protected Object[] getPostParameters(Type[] types, Object[] parameters, HttpServletRequest request) {

		int length = parameters.length;
		if (length == 0) {
			return new Object[] {};
		}
		Object[] ret = new Object[length];

		for (int i = 0; i < length; i++) {
			ret[i] = convertExprToObject(types[i], parameters[i], request);
			// System.out.println(ret[i].getClass() + "" + ret[i]);
		}
		return ret;
	}

	private Object convertExprToObject(Type type, Object parameterName, HttpServletRequest request) {
		if (type == File.class) {
			throw new IllegalArgumentException(
					"The file type  for prameter '" + parameterName + "'is not supported yet!");
		}
		// 如果是基本类型,不是array,就直接调用上层
		String stringParameter = parameterName.toString();
		Class typeClazz = (Class) type;
		if (this.isPrimaryTypeOrOneStringConstructor(typeClazz)) {
			return convertExprToObject(type, request.getParameter(stringParameter));
		}
		// 如果是数组。不能使用父类提供的方法,而是要request.getParameterValues来转
		if (isArrayOfPrimaryType(type)) {
			String subParameters[] = request.getParameterValues(stringParameter);
			if (subParameters == null) {
				System.err.println("Found null valua for parameter: '" + stringParameter + "'");
				return null;
			}
			int length = subParameters.length;

			Class componentClazz = typeClazz.getComponentType();
			Object object = Array.newInstance(componentClazz, length);
			for (int index = 0; index < length; index++) {
				Array.set(object, index, convertExprToObject(typeClazz.getComponentType(), subParameters[index]));
			}
			return object;
		}

		throw new IllegalArgumentException(
				"The  type '" + type + "' for parameter '" + parameterName + "'is not supported yet!");
		
	}

	protected boolean isGetRequest(HttpServletRequest request) {
		return request.getMethod().equalsIgnoreCase("GET");
	}

	protected boolean isPutRequest(HttpServletRequest request) {
		return request.getMethod().equalsIgnoreCase("PUT");
	}

	protected boolean isPostRequest(HttpServletRequest request) {
		return request.getMethod().equalsIgnoreCase("POST");
	}
	protected boolean isContentTypeOfJSON(HttpServletRequest request) {
		String jsonMIMEType="application/json";
		
		return jsonMIMEType.equals(request.getContentType());
	}
	protected boolean isPostingJSONRequest(HttpServletRequest request) {

		System.out.println("--->>>"+ request.getMethod()+ "   ContentType: " +request.getContentType());

		return request.getMethod().equalsIgnoreCase("POST") && isContentTypeOfJSON(request);
	}

	protected Method getMethod(HttpServletRequest request, Object targetObject, List urlElements)
			throws InvocationException {
		if (urlElements.size() < start + 2) {

			throw new InvocationException("Not able to get method name, the method name is not specified by the URI!");

		}
		String methodName = urlElements.get(start + 1);

		return findSingleMethod(targetObject, methodName);

	}

	protected String readBodyAsString(HttpServletRequest request) {
		String str = null;
		StringBuilder resultString = new StringBuilder();
		try {
			BufferedReader reader = request.getReader();
			while (true) {
				if (!((str = reader.readLine()) != null)) break;
				resultString.append(str);
			}
			return resultString.toString();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return null;
		}
	}
	static final int MAX_ALLOWED_BYTES_LENGTH = 1024*128;
	protected byte[] readBodyAsBytes(HttpServletRequest request) {
		
		int length = request.getContentLength();
		
		if(length==0) {
			return new byte[] {};
		}
		if(length>1024*128) {
			throw new IllegalArgumentException("The length '"+length+"' is large than allowed size from MAX_ALLOWED_BYTES_LENGTH: "+ MAX_ALLOWED_BYTES_LENGTH);
			
		}
		byte [] buffer = new byte[1024];
		
		ByteBuffer resultString = ByteBuffer.allocate(request.getContentLength());
		try {
			int readLength = 0;
			ServletInputStream inputStream = request.getInputStream();
			while ((readLength = inputStream.read(buffer)) >0) {
				resultString.put(buffer, 0, readLength);
			}
			return resultString.array();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return null;
		}
	}
	

	protected List parsePut(HttpServletRequest request) throws InvocationException {

		List parameters = new ArrayList(10);
		String requestURI = this.getRequestPath(request);

		System.out.println("PUT : " + requestURI);

		String array[] = requestURI.split("/");
		// System.out.println("GET : "+requestURI);
		// Only method name should be parsed

		for (int i = 0; i < array.length; i++) {
			if (i > 2) {
				break;// ignore any parameter for put
			}
			try {
				String val = URLDecoder.decode(array[i], "UTF-8").trim();
				// System.out.println("array[" + i + "]:" + val);
				parameters.add(val);
			} catch (UnsupportedEncodingException e) {
				throw new InvocationException("Encoding UTF-8 is not supported");
			}
			// the last parameter sh
		}

		// String body = this.readBodyAsString(request);

		// parameters.add(body);

		/*
		 * try { while ((str = request.getReader().readLine()) != null) {
		 * resultString.append(str); } System.out.println("PUT data: "+resultString);
		 * parameters.add(resultString.toString()); } catch (IOException e) { // TODO
		 * Auto-generated catch block e.printStackTrace(); }
		 */
		// System.out.println(URLDecoder.decode(schema[2],"UTF-8"));
		return parameters;

	}

	protected List parsePost(HttpServletRequest request) throws InvocationException {

		List parameters = new ArrayList(10);
		String requestURI = this.getRequestPath(request);
		String array[] = requestURI.split("/");
		System.out.println("POST : " + requestURI);
		for (int i = 0; i < array.length; i++) {

			try {
				String name = URLDecoder.decode(array[i], "UTF-8").trim();
//				System.out
//						.println("array[" + i + "]:" + name + " = " + joinArray(",", request.getParameterValues(name)));
				parameters.add(name);
			} catch (UnsupportedEncodingException e) {
				throw new InvocationException("Encoding UTF-8 is not supported");
			}

		}
		// System.out.println(URLDecoder.decode(schema[2],"UTF-8"));
		return parameters;

	}

	protected String joinArray(String delimiter, String[] args) {
		if (args == null) {
			return null;
		}
		if (args.length < 1) {
			return "";
		}

		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < args.length; i++) {
			if (i > 0)
				stringBuilder.append(delimiter);
			stringBuilder.append(args[i]);
		}
		return stringBuilder.toString();

	}

	protected List parseGet(HttpServletRequest request) throws InvocationException {

		List parameters = new ArrayList(10);
		String requestURI = this.getRequestPath(request);
		String array[] = requestURI.split("/");
		System.out.println("GET : " + requestURI);
		for (int i = 0; i < array.length; i++) {

			try {
				String val = URLDecoder.decode(array[i], "UTF-8").trim();
				// System.out.println("array[" + i + "]:" + val);
				parameters.add(val);
			} catch (UnsupportedEncodingException e) {
				throw new InvocationException("Encoding UTF-8 is not supported");
			}

		}
		// System.out.println(URLDecoder.decode(schema[2],"UTF-8"));
		return parameters;

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy