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

com.almende.eve.protocol.jsonrpc.NamespaceUtil Maven / Gradle / Ivy

The newest version!
/*
 * Copyright: Almende B.V. (2014), Rotterdam, The Netherlands
 * License: The Apache Software License, Version 2.0
 */
package com.almende.eve.protocol.jsonrpc;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.almende.eve.protocol.jsonrpc.annotation.Namespace;
import com.almende.util.AnnotationUtil;
import com.almende.util.AnnotationUtil.AnnotatedClass;
import com.almende.util.AnnotationUtil.AnnotatedMethod;
import com.almende.util.jackson.JOM;
import com.fasterxml.jackson.core.JsonProcessingException;

/**
 * The Class NamespaceUtil.
 */
final class NamespaceUtil {

	private static final Map	CACHE		= new HashMap();
	private static final NamespaceUtil					INSTANCE	= new NamespaceUtil();
	private static final Pattern						PATTERN		= Pattern
																			.compile("\\.[^.]+$");

	/**
	 * Instantiates a new namespace util.
	 */
	private NamespaceUtil() {};

	/**
	 * Gets the.
	 * 
	 * @param destination
	 *            the destination
	 * @param path
	 *            the path
	 * @return the call tuple
	 * @throws IllegalAccessException
	 *             the illegal access exception
	 * @throws InvocationTargetException
	 *             the invocation target exception
	 * @throws NoSuchMethodException
	 *             the no such method exception
	 */
	public static CallTuple get(final Object destination, final String path)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {

		return INSTANCE._get(destination, path);
	}

	/**
	 * Populate cache.
	 * 
	 * @param destination
	 *            the destination
	 * @param steps
	 *            the steps
	 * @param methods
	 *            the methods
	 * @throws IllegalAccessException
	 *             the illegal access exception
	 * @throws InvocationTargetException
	 *             the invocation target exception
	 */
	private void populateCache(final Object destination, final String steps,
			final AnnotatedMethod[] methods) throws IllegalAccessException,
			InvocationTargetException {
		final AnnotatedClass clazz = AnnotationUtil.get(destination.getClass());
		for (final AnnotatedMethod method : clazz
				.getAnnotatedMethods(Namespace.class)) {
			String namespace = method.getAnnotation(Namespace.class).value();
			final Object newDest = method.getActualMethod().invoke(destination,
					(Object[]) null);
			if (namespace.equals("*")) {
				// divert namespace labeling to referred class.
				if (newDest != null) {
					final AnnotatedClass destClazz = AnnotationUtil.get(newDest
							.getClass());
					namespace = destClazz.getAnnotation(Namespace.class)
							.value();
				} else {
					return;
				}
			}
			final String path = steps + "." + namespace;
			methods[methods.length - 1] = method;
			CACHE.put(path, Arrays.copyOf(methods, methods.length));

			// recurse:
			if (newDest != null) {
				populateCache(newDest, path,
						Arrays.copyOf(methods, methods.length + 1));
			}
		}
	}

	/**
	 * _get.
	 * 
	 * @param destination
	 *            the destination
	 * @param path
	 *            the path
	 * @return the call tuple
	 * @throws IllegalAccessException
	 *             the illegal access exception
	 * @throws InvocationTargetException
	 *             the invocation target exception
	 * @throws NoSuchMethodException
	 *             the no such method exception
	 */
	private CallTuple _get(final Object destination, final String path)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		final CallTuple result = new CallTuple();
		String reducedPath = "";
		String reducedMethod = path;
		if (path.indexOf('.') >= 0) {
			reducedPath = destination.getClass().getName() + "." + path;
			final Matcher matcher = PATTERN.matcher(reducedPath);
			reducedPath = matcher.replaceFirst("");
			reducedMethod = matcher.group().substring(1);
		}
		if (!CACHE.containsKey(reducedPath)) {
			final AnnotatedMethod[] methods = new AnnotatedMethod[1];
			final String newSteps = destination.getClass().getName();
			CACHE.put("", new AnnotatedMethod[0]);
			populateCache(destination, newSteps, methods);
		}
		if (!CACHE.containsKey(reducedPath)) {
			try {
				throw new IllegalStateException("Non resolveable path given:'"
						+ path + "' \n checked:"
						+ JOM.getInstance().writeValueAsString(CACHE));
			} catch (final JsonProcessingException e) {
				throw new IllegalStateException("Non resolveable path given:'"
						+ path + "' \n checked:" + CACHE);
			}
		}
		final AnnotatedMethod[] methodPath = CACHE.get(reducedPath);
		Object newDestination = destination;
		for (final AnnotatedMethod method : methodPath) {
			if (method != null) {
				newDestination = method.getActualMethod().invoke(destination,
						(Object[]) null);
			}
		}
		if (newDestination == null) {
			// Oops, namespace getter returned null pointer!
			return result;
		}
		result.setDestination(newDestination);
		final AnnotatedClass newClazz = AnnotationUtil.get(newDestination
				.getClass());
		final List methods = newClazz
				.getMethods(reducedMethod);
		if (!methods.isEmpty()) {
			result.setMethod(methods.get(0));
		}
		return result;
	}

	/**
	 * The Class CallTuple.
	 */
	public class CallTuple {

		/** The destination. */
		private Object			destination;

		/** The method name. */
		private AnnotatedMethod	method;

		/**
		 * Gets the destination.
		 * 
		 * @return the destination
		 */
		public Object getDestination() {
			return destination;
		}

		/**
		 * Sets the destination.
		 * 
		 * @param destination
		 *            the new destination
		 */
		public void setDestination(final Object destination) {
			this.destination = destination;
		}

		/**
		 * Gets the method name.
		 * 
		 * @return the method name
		 */
		public AnnotatedMethod getMethod() {
			return method;
		}

		/**
		 * Sets the method name.
		 * 
		 * @param method
		 *            The method
		 */
		public void setMethod(final AnnotatedMethod method) {
			this.method = method;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy