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

jadex.extension.rs.publish.DefaultRestMethodGenerator Maven / Gradle / Ivy

There is a newer version: 4.0.267
Show newest version
package jadex.extension.rs.publish;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import jadex.bridge.service.IServiceIdentifier;
import jadex.commons.MethodInfo;
import jadex.commons.SReflect;
import jadex.extension.rs.invoke.RSJAXAnnotationHelper;
import jadex.extension.rs.publish.annotation.MethodMapper;
import jadex.extension.rs.publish.annotation.ParametersMapper;
import jadex.extension.rs.publish.annotation.ResultMapper;

/**
 *  The default rest method generator. Analyses
 *  the Jadex service interface and possible the
 *  baseclass (which can be a concrete or abstract class or
 *  an interface).
 */
public class DefaultRestMethodGenerator implements IRestMethodGenerator
{
	/**
	 *  Generate the rest method infos.
	 *  @param service The Jadex service. 
	 *  @param classloader The classloader.
	 *  @param baseclass The (abstract or concrete) baseclass or interface.
	 *  @param mapprops Additional mapping properties.
	 *  @return The method infos.
	 *  @throws Exception
	 */
	public List generateRestMethodInfos(IServiceIdentifier serviceid, ClassLoader classloader, 
		Class baseclass, Map mapprops) throws Exception
	{
		List ret = new ArrayList();
		
		boolean gen = mapprops.get(AbstractRestServicePublishService.GENERATE)!=null? 
			((Boolean)mapprops.get(AbstractRestServicePublishService.GENERATE)).booleanValue(): true;
		boolean geninfo = mapprops.get(AbstractRestServicePublishService.GENERATE_INFO)!=null? 
			((Boolean)mapprops.get(AbstractRestServicePublishService.GENERATE_INFO)).booleanValue(): true;
		Class iface = serviceid.getServiceType().getType(classloader);
		
		MediaType[] formats = AbstractRestServicePublishService.DEFAULT_FORMATS;
		Object tmp = mapprops.get(AbstractRestServicePublishService.FORMATS);
		if(tmp instanceof String[])
		{
			String[] fms = (String[])tmp;
			formats = new MediaType[fms.length];
			for(int i=0; i paths = new HashSet();
		
		Set methods = new LinkedHashSet();
			
		if(baseclass!=null)
		{
			// Add all methods if is specific interface
			if(baseclass.isInterface())
			{
				Method[] ims = baseclass.getMethods();
				for(int i=0; i clazz = baseclass;
				while(!clazz.equals(Object.class))
				{
					Method[] bms = baseclass.getMethods();
					for(int i=0; i it = methods.iterator(); it.hasNext(); )
		{
			MethodWrapper mw = it.next();
			Method method = mw.getMethod();
			List consumed = new ArrayList();
			List produced = new ArrayList();
			
			// Determine rest method type.
			Class resttype = RSJAXAnnotationHelper.getDeclaredRestType(method);
			// User defined method, use as is
			if(resttype!=null)
			{
				if(method.isAnnotationPresent(Consumes.class))
				{
					String[] cons = method.getAnnotation(Consumes.class).value();
					if(cons!=null)
					{
						for(int i=0; i clazz = pm.value().clazz();
						if(clazz!=null && !Object.class.equals(clazz))
						{
							parametermapper = new Value(clazz);
						}
						else
						{
							parametermapper = new Value(pm.value().value());
						}
					}
					automapping = pm.automapping();
				}
				
				Value resultmapper = null;
				if(method.isAnnotationPresent(ResultMapper.class))
				{
					ResultMapper pm = (ResultMapper)method.getAnnotation(ResultMapper.class);
					Class clazz = pm.value().clazz();
					if(clazz!=null && !Object.class.equals(clazz))
						resultmapper = new Value(clazz);
					else
						resultmapper = new Value(pm.value().value());
				}
				
				String path = "";
				if(method.isAnnotationPresent(Path.class))
				{
					path = ((Path)method.getAnnotation(Path.class)).value();
				}
				else
				{
					path = mw.getName();
				}
				
				ret.add(new RestMethodInfo(method, mw.getName(), getPathName(path, paths), resttype, consumed, produced, 
					methodmapper, parametermapper, automapping, resultmapper,
					AbstractRestServicePublishService.class, "invoke"));
			}
			// Guess how method should be restified
			else
			{
				resttype = guessRestType(method);
				
				// Determine how many and which rest methods have to be created for the set of consumed media types.
				if(!GET.class.equals(resttype))
				{
					for(int j=0; j consumed = new ArrayList();
			List produced = new ArrayList();
			produced.add(MediaType.TEXT_HTML_TYPE);
			ret.add(new RestMethodInfo(new Class[0], String.class, new Class[0], "getServiceInfo", getPathName("", paths), GET.class, 
				consumed, produced, null, null, false, null, 
				AbstractRestServicePublishService.class, "getServiceInfo"));
		}
		
//		System.out.println("paths: "+paths);
		
		return ret;
	}
	
	/**
	 *  Guess the http type (GET, POST, PUT, DELETE, ...) of a method.
	 *  @param method The method.
	 *  @return  The rs annotation of the method type to use 
	 */
	public Class guessRestType(Method method)
	{
	    // Retrieve = GET (hasparams && hasret)
	    // Update = POST (hasparams && hasret)
	    // Create = PUT  return is pointer to new resource (hasparams? && hasret)
	    // Delete = DELETE (hasparams? && hasret?)

		Class ret = GET.class;
		
		Class rettype = SReflect.unwrapGenericType(method.getGenericReturnType());
		Class[] paramtypes = method.getParameterTypes();
		
		boolean hasparams = paramtypes.length>0;
		boolean hasret = rettype!=null && !rettype.equals(Void.class) && !rettype.equals(void.class);
		
		// GET or POST if has both
		if(hasret)
		{
			if(hasparams)
			{
				if(hasStringConvertableParameters(method, rettype, paramtypes))
				{
					ret = GET.class;
				}
				else
				{
					ret = POST.class;
				}
			}
		}
		
		// todo: other types?
		
//		System.out.println("rest-type: "+ret.getName()+" "+method.getName()+" "+hasparams+" "+hasret);
		
		return ret;
//		return GET.class;
	}
	
	/**
	 *  A a method wrapper.
	 *  @param mw The method mapper.
	 *  @param methods The set of method wrapper.
	 */
	protected static void addMethodWrapper(MethodWrapper mw, Set methods)
	{
		if(methods.contains(mw))
		{
			String basename = mw.getName();
			for(int j=0; methods.contains(mw); j++)
			{
				mw.setName(basename+j);
			}
		}
		methods.add(mw);
	}
	
	/**
	 *  Get a path name based on a start name.
	 *  @param path The path name.
	 *  @param paths The already taken paths.
	 *  @return The available path.
	 */
	protected static String getPathName(String path, Set paths)
	{
		if(paths.contains(path))
		{
			String basename = path;
			for(int i=0; paths.contains(path); i++)
			{
				path = basename+i;
			}
		}
		addPath(path, paths);
		return path;
	}
	
	/**
	 *  Add a path to the set of paths.
	 *  Add the path plus the path with trailing slash.
	 *  @param path The path.
	 *  @param paths The paths.
	 */
	protected static void addPath(String path, Set paths)
	{
		String p = path;
		if(path.endsWith("/"))
			p = path.substring(0, path.length()-1);
		else
			p = path + "/";
		paths.add(path);
		paths.add(p);
	}
	
	/**
	 *  Test if a method has parameters that are all convertible from string.
	 *  @param method The method.
	 *  @param rettype The return types (possibly unwrapped from future type).
	 *  @param paramtypes The parameter types.
	 *  @return True, if is convertible.
	 */
	public boolean hasStringConvertableParameters(Method method, Class rettype, Class[] paramtypes)
	{
		boolean ret = true;
		
		for(int i=0; i type)
	{
		boolean ret = true;
		if(!SReflect.isStringConvertableType(type))
		{
			try
			{
				Method m = type.getMethod("fromString", new Class[]{String.class});
			}
			catch(Exception e)
			{
				try
				{
					Method m = type.getMethod("valueOf", new Class[]{String.class});
				}
				catch(Exception e2)
				{
					ret = false;
				}
			}
		}
		return ret;
	}
	

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy