package com.constellio.model.services.schemas.builders; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.constellio.model.utils.ClassProvider; public class ClassListBuilder<T> { private static Map<String, Object> cache = new HashMap<>(); Class<?> implementedClass; Set<String> implementationsClassname = new HashSet<>(); private ClassProvider classProvider; public ClassListBuilder(ClassProvider classProvider, Class<?> implementedClass) { this.classProvider = classProvider; this.implementedClass = implementedClass; } public ClassListBuilder(ClassProvider classProvider, Class<?> implementedClass, Set<T> implementations) { this.implementedClass = implementedClass; this.classProvider = classProvider; for (T implementation : implementations) { this.implementationsClassname.add(implementation.getClass().getName()); } } public ClassListBuilder<T> add(String name) { this.implementationsClassname.add(name); return this; } public <I> ClassListBuilder<T> add(Class<I> implementationClass) { this.implementationsClassname.add(implementationClass.getName()); return this; } public Set<T> build() { return build(new HashSet<T>()); } @SuppressWarnings("unchecked") public Set<T> build(Set<T> otherIncludedImplementations) { Set<T> instanciatedImplementations = new HashSet<>(); Set<String> allClassNames = new HashSet<>(); for (T otherIncludedImplementation : otherIncludedImplementations) { allClassNames.add(otherIncludedImplementation.getClass().getName()); } allClassNames.addAll(implementationsClassname); for (String implementationClassname : allClassNames) { instanciatedImplementations.add(getObjectWithClassname(implementationClassname)); } return instanciatedImplementations; } private T getObjectWithClassname(String implementationClassname) { T object = (T) cache.get(implementationClassname); if (object == null) { object = createObjectWithClassname(implementationClassname); cache.put(implementationClassname, object); } return object; } private T createObjectWithClassname(String implementationClassname) { try { Class<T> implementationClass = classProvider.loadClass(implementationClassname); if (!implementedClass.isAssignableFrom(implementationClass)) { throw new ClassListBuilderRuntimeException.ClassDoesntImplementInterface(implementationClass.getName(), implementedClass); } return implementationClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new ClassListBuilderRuntimeException.CannotInstanciate(implementationClassname, e); } catch (ClassNotFoundException e) { throw new ClassListBuilderRuntimeException.ClassNotFound(implementationClassname, e); } } public <I> ClassListBuilder<T> remove(Class<I> implementationClass) { this.implementationsClassname.remove(implementationClass.getName()); return this; } public ClassListBuilder<T> remove(String name) { this.implementationsClassname.remove(name); return this; } public void set(List<String> validators) { this.implementationsClassname.clear(); this.implementationsClassname.addAll(validators); } public static <T> Set<T> combine(Set<T> set1, Set<T> set2) { Set<T> validators = new HashSet<>(); Set<String> validatorCodes = new HashSet<>(); for (T item1 : set1) { validatorCodes.add(item1.getClass().getName()); validators.add(item1); } for (T item2 : set2) { if (!validatorCodes.contains(item2.getClass().getName())) { validatorCodes.add(item2.getClass().getName()); validators.add(item2); } } return Collections.unmodifiableSet(validators); } public Set<String> getClassnames() { return implementationsClassname; } public static <T> boolean isSameValues(Set<T> values1, Set<T> values2) { Set<String> values1Classes = new HashSet<>(); for (T value : values1) { values1Classes.add(value.getClass().getName()); } Set<String> values2Classes = new HashSet<>(); for (T value : values2) { values2Classes.add(value.getClass().getName()); } return values1Classes.equals(values2Classes); } }