package fr.openwide.core.spring.property.model; import java.io.Serializable; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import com.google.common.base.MoreObjects; import com.google.common.collect.Sets; public abstract class AbstractPropertyIds { private static ConcurrentMap<String, PropertyRegistryKeyClassDeclaration> declarationsByDeclaringClassName = new ConcurrentHashMap<>(); protected AbstractPropertyIds() { } public static <T> ImmutablePropertyId<T> immutable(String key) { PropertyRegistryKeyClassDeclaration declaration = getDeclaration(); ImmutablePropertyId<T> id = new ImmutablePropertyId<T>(declaration, key); declaration.addKey(id); return id; } public static <T> MutablePropertyId<T> mutable(String key) { PropertyRegistryKeyClassDeclaration declaration = getDeclaration(); MutablePropertyId<T> id = new MutablePropertyId<T>(declaration, key); declaration.addKey(id); return id; } public static <T> ImmutablePropertyIdTemplate<T> immutableTemplate(String key) { PropertyRegistryKeyClassDeclaration declaration = getDeclaration(); ImmutablePropertyIdTemplate<T> template = new ImmutablePropertyIdTemplate<T>(declaration, key); declaration.addKey(template); return template; } public static <T> MutablePropertyIdTemplate<T> mutableTemplate(String key) { PropertyRegistryKeyClassDeclaration declaration = getDeclaration(); MutablePropertyIdTemplate<T> template = new MutablePropertyIdTemplate<T>(declaration, key); declaration.addKey(template); return template; } private static PropertyRegistryKeyClassDeclaration getDeclaration() { StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); String callingClassName = stackTraceElements[3].getClassName(); return getDeclaration(callingClassName); } private static PropertyRegistryKeyClassDeclaration getDeclaration(String declaringClassName) { PropertyRegistryKeyClassDeclaration declaration = new PropertyRegistryKeyClassDeclaration(declaringClassName); return MoreObjects.firstNonNull( declarationsByDeclaringClassName.putIfAbsent(declaringClassName, declaration), declaration ); } /* * No need to override equals: there is only one instance of this class for each declaringClassName, due to * how instantiation is done and to how serialization/deserialization are done. */ private static final class PropertyRegistryKeyClassDeclaration implements IPropertyRegistryKeyDeclaration { private static final long serialVersionUID = 1L; private final String declaringClassName; private final Set<IPropertyRegistryKey<?>> declaredKeys = Sets.newLinkedHashSet(); public PropertyRegistryKeyClassDeclaration(String declaringClass) { super(); this.declaringClassName = declaringClass; } @Override public String toString() { return "Properties declared in class " + declaringClassName; } @Override public Set<IPropertyRegistryKey<?>> getDeclaredKeys() { return Collections.unmodifiableSet(declaredKeys); } public void addKey(IPropertyRegistryKey<?> key) { synchronized(declaredKeys) { declaredKeys.add(key); } } protected Object writeReplace() { return new SerializedForm(this); } private static final class SerializedForm implements Serializable { private static final long serialVersionUID = 1L; private String declaringClassName; public SerializedForm(PropertyRegistryKeyClassDeclaration declaration) { super(); this.declaringClassName = declaration.declaringClassName; } protected Object readResolve() { return getDeclaration(declaringClassName); } } } }