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

angularBeans.remote.InvocationHandler Maven / Gradle / Ivy

There is a newer version: 1.0.2-RELEASE
Show newest version
/*
 * AngularBeans, CDI-AngularJS bridge 
 *
 * Copyright (c) 2014, Bessem Hmidi. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program 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.
 *
 */

/**
 @author Bessem Hmidi
 */
package angularBeans.remote;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;

import angularBeans.api.NGPostConstruct;
import angularBeans.api.NGReturn;
import angularBeans.context.BeanLocator;
import angularBeans.context.NGSessionScopeContext;
import angularBeans.io.ByteArrayCache;
import angularBeans.io.LobWrapper;
import angularBeans.log.NGLogger;
import angularBeans.log.NGLogger.Level;
import angularBeans.util.AngularBeansUtils;
import angularBeans.util.CommonUtils;
import angularBeans.util.ModelQueryFactory;
import angularBeans.util.ModelQueryImpl;

/**
 * 
 * @author Bassem Hmidi This is the AngularBeans RPC main handler
 */

@SuppressWarnings("serial")
@ApplicationScoped
public class InvocationHandler implements Serializable {

	@Inject
	ByteArrayCache cache;

	@Inject
	NGLogger logger;

	@Inject
	AngularBeansUtils util;

	@Inject
	BeanLocator locator;

	@Inject
	ModelQueryFactory modelQueryFactory;

	static Map builtInMap = new HashMap();

	static Map arrayTypesMap = new HashMap<>();

	static {

		builtInMap.put("int", Integer.TYPE);
		builtInMap.put("long", Long.TYPE);
		builtInMap.put("double", Double.TYPE);
		builtInMap.put("float", Float.TYPE);
		builtInMap.put("boolean", Boolean.TYPE);
		builtInMap.put("char", Character.TYPE);
		builtInMap.put("byte", Byte.TYPE);

		builtInMap.put("short", Short.TYPE);

		arrayTypesMap.put("[I", int[].class);
		arrayTypesMap.put("[F", float[].class);
		arrayTypesMap.put("[D", double[].class);
		arrayTypesMap.put("[J", long[].class);
		arrayTypesMap.put("[S", short[].class);
		arrayTypesMap.put("[B", byte[].class);
		arrayTypesMap.put("[C", char[].class);
		arrayTypesMap.put("[Z", boolean[].class);

		arrayTypesMap.put("[Ljava.lang.Long;", Long[].class);
		arrayTypesMap.put("[Ljava.lang.Double;", Double[].class);
		arrayTypesMap.put("[Ljava.lang.Integer;", Integer[].class);
		arrayTypesMap.put("[Ljava.lang.Float;", Float[].class);
		arrayTypesMap.put("[Ljava.lang.Short;", Short[].class);
		arrayTypesMap.put("[Ljava.lang.Byte;", Byte[].class);
		arrayTypesMap.put("[Ljava.lang.Character;", Character[].class);
		arrayTypesMap.put("[Ljava.lang.Boolean;", Boolean[].class);
		arrayTypesMap.put("[Ljava.lang.String;", String[].class);
	}

	public void realTimeInvoke(Object ServiceToInvoque, String methodName, JsonObject params,
			RealTimeDataReceivedEvent event, long reqID, String UID) {

		NGSessionScopeContext.setCurrentContext(UID);

		Map returns = new HashMap();
		// Object mainReturn = null;

		returns.put("isRT", true);

		try {
			genericInvoke(ServiceToInvoque, methodName, params, returns, reqID, UID);

			if (returns.get("mainReturn") != null) {

				event.getConnection().write(util.getJson(returns), false);
			}
		} catch (SecurityException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException
				| InvocationTargetException | NoSuchMethodException e) {

			e.printStackTrace();
		}

	}

	public Object invoke(Object o, String method, JsonObject params, String UID) {

		NGSessionScopeContext.setCurrentContext(UID);

		Map returns = new HashMap();

		try {

			returns.put("isRT", false);
			genericInvoke(o, method, params, returns, 0, UID);

		} catch (Exception e) {
			// fire(e);
			e.printStackTrace();
		}

		return returns;
	}

	private void genericInvoke(Object service, String methodName, JsonObject params, Map returns,
			long reqID, String UID)

					throws SecurityException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException,
					InvocationTargetException, NoSuchMethodException {

		Object mainReturn = null;

		Method m = null;

		JsonElement argsElem = params.get("args");

		// returns.put("isRT", false);

		if (reqID > 0) {
			returns.put("reqId", reqID);
		}
		if (argsElem != null) {

			JsonArray args = params.get("args").getAsJsonArray();

			for (Method mt : service.getClass().getMethods()) {

				if (mt.getName().equals(methodName)) {

					Type[] parameters = mt.getParameterTypes();

					if (parameters.length == args.size()) {

						List argsValues = new ArrayList();

						for (int i = 0; i < parameters.length; i++) {

							Class typeClass = null;

							String typeString = ((parameters[i]).toString());

							if (typeString.startsWith("interface")) {
								typeString = typeString.substring(10);

								typeClass = Class.forName(typeString);

							} else {
								if (typeString.startsWith("class")) {
									typeString = typeString.substring(6);

									typeClass = Class.forName(typeString);

								}

								else {

									typeClass = builtInMap.get(typeString);
								}
							}

							JsonElement element = args.get(i);

							if (element.isJsonPrimitive()) {

								String val = element.getAsString();

								argsValues.add(CommonUtils.convertFromString(val, typeClass));

							} else if (element.isJsonArray()) {

								JsonArray arr = element.getAsJsonArray();

								argsValues.add(util.deserialise(arrayTypesMap.get(typeString), arr));

							} else {

								argsValues.add(util.deserialise(typeClass, element));

							}

						}

						m = mt;

						if (!CommonUtils.isGetter(m)) {
							// if(util.isSetter(m)){
							update(service, params);
							// }

						}

						String exceptionString = "";
						try {

							mainReturn = m.invoke(service, argsValues.toArray());

						} catch (Exception e) {
							handleException(m, e);

							e.printStackTrace();
						}

					}

				}

			}

		}
		// --------------------------------------------------

		else {

			m = service.getClass().getMethod(methodName);

			if (!CommonUtils.isGetter(m)) {
				// if(util.isSetter(m)){
				update(service, params);
				// }

			}

			try {

			} catch (Exception e) {
				handleException(m, e);
				e.printStackTrace();
			}
			mainReturn = m.invoke(service);

		}

		// 1

		// modelQueryFactory=(ModelQueryFactory)
		// locator.lookup("ModelQueryFactory",UID );

		ModelQueryImpl qImpl = (ModelQueryImpl) modelQueryFactory.get(service.getClass());

		Map scMap = new HashMap((qImpl).getData());

		returns.putAll(scMap);

		(qImpl).getData().clear();

		if (!modelQueryFactory.getRootScope().getRootScopeMap().isEmpty()) {
			returns.put("rootScope", new HashMap(modelQueryFactory.getRootScope().getRootScopeMap()));
			modelQueryFactory.getRootScope().getRootScopeMap().clear();
		}

		String[] updates = null;

		// if ((m.isAnnotationPresent(NGReturn.class))
		// || (m.isAnnotationPresent(NGPostConstruct.class))
		// ) {

		// if((returns.size()>0)&& (mainReturn==null))mainReturn="";

		if (m.isAnnotationPresent(NGReturn.class)) {

			if (mainReturn == null)
				mainReturn = "";

			NGReturn ngReturn = m.getAnnotation(NGReturn.class);
			updates = ngReturn.updates();

			if (ngReturn.model().length() > 0) {
				returns.put(ngReturn.model(), mainReturn);
				Map binding = new HashMap();

				binding.put("boundTo", ngReturn.model());

				mainReturn = binding;
			}
		}

		if (m.isAnnotationPresent(NGPostConstruct.class)) {
			NGPostConstruct ngPostConstruct = m.getAnnotation(NGPostConstruct.class);
			updates = ngPostConstruct.updates();

		}

		if (updates != null) {
			if ((updates.length == 1) && (updates[0].equals("*"))) {

				List upd = new ArrayList();
				for (Method met : service.getClass().getDeclaredMethods()) {

					if (CommonUtils.isGetter(met)) {

						String fieldName = (met.getName()).substring(3);
						String firstCar = fieldName.substring(0, 1);
						upd.add((firstCar.toLowerCase() + fieldName.substring(1)));

					}
				}

				updates = new String[upd.size()];

				for (int i = 0; i < upd.size(); i++) {
					updates[i] = upd.get(i);
				}

			}
		}

		if (updates != null) {
			for (String up : updates) {

				String getterName = "get" + up.substring(0, 1).toUpperCase() + up.substring(1);
				Method getter = null;
				try {
					getter = service.getClass().getMethod(getterName);
				} catch (NoSuchMethodException e) {
					getter = service.getClass().getMethod((getterName.replace("get", "is")));
				}

				Object result = getter.invoke(service);
				returns.put(up, result);

			}
		}

		// }

		// if (m.isAnnotationPresent(NGReturn.class)) {

		returns.put("mainReturn", mainReturn);

		if (!logger.getLogPool().isEmpty()) {
			returns.put("log", logger.getLogPool().toArray());
			logger.getLogPool().clear();
		}

		// }

	}

	private void handleException(Method m, Exception e) {
		Throwable cause = e.getCause();

		String exceptionString = m.getName() + " -->" + cause.getClass().getName();

		if (cause.getMessage() != null) {
			exceptionString += " " + cause.getMessage();
		}

		logger.log(Level.ERROR, exceptionString);

	}

	private void update(Object o, JsonObject params) {

		if (params != null) {

			// boolean firstIn = false;

			for (Map.Entry entry : params.entrySet()) {

				JsonElement value = entry.getValue();
				String name = entry.getKey();

				if ((name.equals("sessionUID")) || (name.equals("args"))) {
					continue;
				}

				if ((value.isJsonObject()) && (!value.isJsonNull())) {

					String getName;
					try {
						getName = CommonUtils.obtainGetter(o.getClass().getDeclaredField(name));

						Method getter = o.getClass().getMethod(getName);

						Object subObj = getter.invoke(o);

						// logger.log(Level.INFO, "#entring sub object "+name);
						update(subObj, value.getAsJsonObject());

					} catch (NoSuchFieldException | SecurityException | IllegalAccessException
							| IllegalArgumentException | InvocationTargetException | NoSuchMethodException e) {

						e.printStackTrace();
					}

				}
				// ------------------------------------
				if (value.isJsonArray()) {

					try {
						String getter = CommonUtils.obtainGetter(o.getClass().getDeclaredField(name));

						Method get = o.getClass().getDeclaredMethod(getter);

						Type type = get.getGenericReturnType();
						ParameterizedType pt = (ParameterizedType) type;
						Type actType = pt.getActualTypeArguments()[0];

						// Class collectionClazz = get.getReturnType();

						String className = actType.toString();

						className = className.substring(className.indexOf("class") + 6);
						Class clazz = Class.forName(className);

						JsonArray array = value.getAsJsonArray();

						Collection collection = (Collection) get.invoke(o);
						Object elem = null;
						for (JsonElement element : array) {
							if (element.isJsonPrimitive()) {
								JsonPrimitive primitive = element.getAsJsonPrimitive();

								elem = element;
								if (primitive.isBoolean())
									elem = primitive.getAsBoolean();
								if (primitive.isString()) {
									elem = primitive.getAsString();
								}
								if (primitive.isNumber())
									elem = primitive.isNumber();

							} else {

								elem = util.deserialise(clazz, element);

							}

							// if (collection instanceof AbstractCollection) {
							//
							// ArrayList list=new ArrayList();
							// list.addAll(collection);
							// collection=list;
							// }

							try {

								if (collection instanceof List) {

									if (collection.contains(elem))
										collection.remove(elem);
								}

								collection.add(elem);
							} catch (UnsupportedOperationException e) {
								Logger.getLogger("AngularBeans").log(java.util.logging.Level.WARNING,
										"trying to modify an immutable collection : " + name);
							}

						}

					} catch (Exception e) {
						e.printStackTrace();

					}

				}

				// ------------------------------------------
				if (value.isJsonPrimitive() && (!name.equals("setSessionUID"))) {
					try {

						if (!CommonUtils.hasSetter(o.getClass(), name)) {
							continue;
						}
						name = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);

						Class type = null;
						for (Method set : o.getClass().getDeclaredMethods()) {
							if (CommonUtils.isSetter(set)) {
								if (set.getName().equals(name)) {
									Class[] pType = set.getParameterTypes();

									type = pType[0];
									break;

								}
							}

						}

						if (type.equals(LobWrapper.class))
							continue;

						Object param = null;
						if ((params.entrySet().size() >= 1) && (type != null)) {

							param = CommonUtils.convertFromString(value.getAsString(), type);

						}

						o.getClass().getMethod(name, type).invoke(o, param);

					} catch (Exception e) {
						// fire(e);
						e.printStackTrace();

					}
				}

			}
		}

	}

}