/** * */ package org.gcube.informationsystem.discovery; 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.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.gcube.informationsystem.base.reference.Element; import org.gcube.informationsystem.base.reference.properties.PropertyElement; import org.gcube.informationsystem.types.annotations.ISProperty; import org.gcube.informationsystem.utils.ReflectionUtility; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) */ public class Discovery { public static Logger logger = LoggerFactory.getLogger(Discovery.class); protected final Class root; protected final Set packages; protected final List> discoveredElement; protected final List> discoveredElementActions; protected boolean discovered; public Discovery(Class root) throws Exception { this.root = root; this.packages = new HashSet<>(); this.discovered = false; this.discoveredElement = new ArrayList<>(); this.discoveredElementActions = new ArrayList<>(); add(root); } public List> getDiscoveredElement() { return discoveredElement; } @SuppressWarnings("unchecked") public synchronized void addDiscoveredElementActions(DiscoveredElementAction discoveredElementAction) throws Exception { discoveredElementActions.add(discoveredElementAction); if(discovered) { for(Class clz : discoveredElement) { discoveredElementAction.analizeElement((Class) clz); } } } public void addPackage(Package p) { packages.add(p); } public void addPackages(Collection packages) { for(Package p : packages) { addPackage(p); } } @SuppressWarnings("unchecked") protected void add(Class clz) throws Exception { if(!discoveredElement.contains(clz)) { discoveredElement.add(clz); for(DiscoveredElementAction discoveredElementAction : discoveredElementActions) { discoveredElementAction.analizeElement((Class) clz); } logger.info("+ Added {}.", clz); } } protected void analizeElement(Class clz) throws Exception { logger.trace("Analizyng {}", clz); if(!clz.isInterface()) { logger.trace("- Discarding {} because is not an interface", clz); return; } if(!root.isAssignableFrom(clz)) { logger.trace("- Discarding {} because is not a {}", clz, root.getSimpleName()); return; } if(discoveredElement.contains(clz)) { logger.trace("- Discarding {} because was already managed", clz); return; } Class[] interfaces = clz.getInterfaces(); for(Class interfaceClass : interfaces) { @SuppressWarnings("unchecked") Class parent = (Class) interfaceClass; analizeElement(parent); } if(root == PropertyElement.class) { for(Method m : clz.getDeclaredMethods()) { m.setAccessible(true); if(m.isAnnotationPresent(ISProperty.class)) { if(Map.class.isAssignableFrom(m.getReturnType()) || Set.class.isAssignableFrom(m.getReturnType()) || List.class.isAssignableFrom(m.getReturnType())) { Type[] typeArguments = ((ParameterizedType) m.getGenericReturnType()).getActualTypeArguments(); for(Type t : typeArguments) { @SuppressWarnings("unchecked") Class tClass = (Class) t; if(root.isAssignableFrom(tClass)) { @SuppressWarnings("unchecked") Class type = (Class) tClass; analizeElement(type); } } } else if(root.isAssignableFrom(m.getReturnType())) { @SuppressWarnings("unchecked") Class eClz = (Class) m.getReturnType(); analizeElement(eClz); } } } } add(clz); } public synchronized void discover() throws Exception { this.discovered = false; for(Package p : packages) { List> classes = ReflectionUtility.getClassesForPackage(p); for(Class clz : classes) { @SuppressWarnings("unchecked") Class eClz = (Class) clz; analizeElement(eClz); } } this.discovered = true; } }