169 lines
4.7 KiB
Java
169 lines
4.7 KiB
Java
/**
|
|
*
|
|
*/
|
|
package org.gcube.informationsystem.discovery;
|
|
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.ParameterizedType;
|
|
import java.lang.reflect.Type;
|
|
import java.util.Collection;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
|
|
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<E extends Element> {
|
|
|
|
public static Logger logger = LoggerFactory.getLogger(Discovery.class);
|
|
|
|
protected final Class<E> root;
|
|
protected final Set<Package> packages;
|
|
protected final Set<Class<E>> discoveredElement;
|
|
protected final Set<DiscoveredElementAction<Element>> discoveredElementActions;
|
|
|
|
protected final boolean includeRootPackage;
|
|
|
|
protected boolean discovered;
|
|
|
|
public Discovery(Class<E> root) throws Exception {
|
|
this(root, true);
|
|
}
|
|
|
|
public Discovery(Class<E> root, boolean includeRootPackage) throws Exception {
|
|
this.root = root;
|
|
this.packages = new HashSet<>();
|
|
this.includeRootPackage = includeRootPackage;
|
|
if(includeRootPackage) {
|
|
addPackage(root.getPackage());
|
|
}
|
|
this.discovered = false;
|
|
this.discoveredElement = new TreeSet<>();
|
|
this.discoveredElementActions = new TreeSet<>();
|
|
add(root);
|
|
}
|
|
|
|
public Set<Class<E>> getDiscoveredElement() {
|
|
return discoveredElement;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public synchronized void addDiscoveredElementActions(DiscoveredElementAction<Element> discoveredElementAction) throws Exception {
|
|
discoveredElementActions.add(discoveredElementAction);
|
|
if(discovered) {
|
|
for(Class<E> clz : discoveredElement) {
|
|
discoveredElementAction.analizeElement((Class<Element>) clz);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void addPackage(Package p) {
|
|
if(!includeRootPackage && p==root.getPackage()) {
|
|
return;
|
|
}
|
|
packages.add(p);
|
|
}
|
|
|
|
public void addPackages(Collection<Package> packages) {
|
|
for(Package p : packages) {
|
|
addPackage(p);
|
|
}
|
|
}
|
|
|
|
public void addRegistrationProvider(RegistrationProvider registrationProvider) {
|
|
addPackages(registrationProvider.getPackagesToRegister());
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
protected void add(Class<E> clz) throws Exception {
|
|
if(!discoveredElement.contains(clz)) {
|
|
discoveredElement.add(clz);
|
|
for(DiscoveredElementAction<Element> discoveredElementAction : discoveredElementActions) {
|
|
discoveredElementAction.analizeElement((Class<Element>) clz);
|
|
}
|
|
logger.info("+ Added {}.", clz);
|
|
}
|
|
}
|
|
|
|
protected void analizeElement(Class<E> 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<E> parent = (Class<E>) 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<? extends PropertyElement> tClass = (Class<? extends PropertyElement>) t;
|
|
if(root.isAssignableFrom(tClass)) {
|
|
@SuppressWarnings("unchecked")
|
|
Class<E> type = (Class<E>) tClass;
|
|
analizeElement(type);
|
|
}
|
|
}
|
|
|
|
} else if(root.isAssignableFrom(m.getReturnType())) {
|
|
@SuppressWarnings("unchecked")
|
|
Class<E> eClz = (Class<E>) m.getReturnType();
|
|
analizeElement(eClz);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
add(clz);
|
|
}
|
|
|
|
public synchronized void discover() throws Exception {
|
|
this.discovered = false;
|
|
for(Package p : packages) {
|
|
List<Class<?>> classes = ReflectionUtility.getClassesForPackage(p);
|
|
for(Class<?> clz : classes) {
|
|
@SuppressWarnings("unchecked")
|
|
Class<E> eClz = (Class<E>) clz;
|
|
analizeElement(eClz);
|
|
}
|
|
}
|
|
this.discovered = true;
|
|
}
|
|
|
|
}
|