/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* bstefanescu
*
* $Id$
*/
package org.eclipse.ecr.core.api.model.impl.osm;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
/**
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*
*/
// XXX AT: this is either too generic, or not generic enough because it makes it
// impossible to map classes to the same type (see ExternalBlob and Blob
// properties/adapters for instance)
public class TypeAnnotationRegistry<T> {
protected final Map<Class<?>, Annotation> registry = new HashMap<Class<?>, Annotation>();
@SuppressWarnings("unchecked")
public synchronized T get(Class<?> type) {
Annotation anno = lookup(type);
return (T) anno.data;
}
public synchronized void put(Class<?> type, T data) {
Annotation anno = registry.get(type);
if (anno != null) {
remove(type); // TODO find a better solution to update reg
}
registry.put(type, new Annotation(type, null, data));
}
public synchronized void remove(Class<?> type) {
Annotation anno = registry.remove(type);
if (anno == null) {
return;
}
Iterator<Annotation> it = registry.values().iterator();
while (it.hasNext()) {
if (it.next().provider == type) {
it.remove();
}
}
}
protected Annotation lookup(Class<?> type) {
Annotation anno = registry.get(type);
if (anno != null) {
return anno;
}
Class<?> superClass = type.getSuperclass();
if (superClass == null) { // process interfaces
for (Class<?> itf : type.getInterfaces()) {
anno = lookup(itf);
if (anno != null && anno.data != null) {
registry.put(type, anno);
return anno;
}
}
} else {
// descent into superclasses
LinkedList<Class<?>> queue = new LinkedList<Class<?>>();
queue.add(type);
anno = lookup(superClass, queue);
if (anno != null && anno.data != null) {
registry.put(type, new Annotation(type, anno.type, anno.data));
return anno;
}
// process interfaces of queued classes
Class<?> t = queue.poll();
while (t != null) {
for (Class<?> itf : t.getInterfaces()) {
anno = lookup(itf);
if (anno != null && anno.data != null) {
registry.put(t, new Annotation(t, anno.type, anno.data));
return anno;
}
}
t = queue.poll();
}
}
anno = new Annotation(type, null, null);
registry.put(type, anno);
return anno;
}
protected Annotation lookup(Class<?> type, Queue<Class<?>> queue) {
Annotation anno = registry.get(type);
if (anno != null) {
return anno;
}
queue.add(type);
Class<?> superClass = type.getSuperclass();
if (superClass != null) { //descent in super classes
anno = lookup(superClass, queue);
}
if (anno == null) {
anno = new Annotation(type, null, null);
}
registry.put(type, anno);
return anno;
}
public static class Annotation {
final Class<?> type;
final Class<?> provider;
final Object data;
public Annotation(Class<?> type, Class<?> provider, Object data) {
this.type = type;
this.provider = provider;
this.data = data;
}
}
}