package net.enilink.composition.mappers; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Set; import net.enilink.composition.exceptions.ConfigException; public class ComposedRoleMapper<T> implements Cloneable, RoleMapper<T> { /** * Iterates the graph of delegates while preventing cycles. */ class UniqueTransitiveIterator implements Iterator<RoleMapper<T>>, Iterable<RoleMapper<T>> { protected Queue<Iterator<RoleMapper<T>>> mapperQueue = new LinkedList<Iterator<RoleMapper<T>>>(); protected RoleMapper<T> next; protected Set<RoleMapper<T>> seen = new HashSet<RoleMapper<T>>(); public UniqueTransitiveIterator() { mapperQueue.add(getRoleMappers().iterator()); } @Override public boolean hasNext() { if (next != null) { return true; } Iterator<RoleMapper<T>> it; while ((it = mapperQueue.peek()) != null) { while (it.hasNext()) { RoleMapper<T> candidat = it.next(); if (!seen.contains(candidat)) { next = candidat; if (next instanceof ComposedRoleMapper) { mapperQueue.add(((ComposedRoleMapper<T>) next) .getRoleMappers().iterator()); } return true; } } mapperQueue.remove(); } return false; } @Override public Iterator<RoleMapper<T>> iterator() { return this; } @Override public RoleMapper<T> next() { try { seen.add(next); return next; } finally { next = null; } } @Override public void remove() { throw new UnsupportedOperationException( "This is a read-only iterator."); } } private RoleMapper<T> primary; private List<RoleMapper<T>> roleMappers; private TypeFactory<T> typeFactory; public ComposedRoleMapper(TypeFactory<T> typeFactory) { this.typeFactory = typeFactory; } @Override public void addAnnotation(Class<?> annotation) { getPrimary().addAnnotation(annotation); } @Override public void addAnnotation(Class<?> annotation, T uri) { getPrimary().addAnnotation(annotation, uri); } @Override public void addAnnotation(Method annotation, T uri) { getPrimary().addAnnotation(annotation, uri); } @Override public void addAnnotation(Method annotation) { getPrimary().addAnnotation(annotation); } @Override public void addBehaviour(Class<?> role) throws ConfigException { getPrimary().addBehaviour(role); } @Override public void addBehaviour(Class<?> role, T type) throws ConfigException { getPrimary().addBehaviour(role, type); } @Override public void addConcept(Class<?> role) throws ConfigException { getPrimary().addConcept(role); } @Override public void addConcept(Class<?> role, T type) throws ConfigException { getPrimary().addConcept(role, type); } /** * Registers a new role mapper that is used as a delegate. * * @param roleMapper * A {@link RoleMapper} that should be added. * @return <code>true</code> if <code>roleMapper</code> is not already * registered, else <code>false</code>. */ public boolean addRoleMapper(RoleMapper<T> roleMapper) { if (roleMappers == null) { roleMappers = new ArrayList<RoleMapper<T>>(); } if (!roleMappers.contains(roleMapper)) { return roleMappers.add(roleMapper); } return false; } @Override public ComposedRoleMapper<T> clone() { try { @SuppressWarnings("unchecked") ComposedRoleMapper<T> cloned = (ComposedRoleMapper<T>) super .clone(); cloned.primary = primary == null ? null : primary.clone(); if (roleMappers != null) { // do not deep-copy the delegates cloned.roleMappers = new ArrayList<RoleMapper<T>>(roleMappers); } return cloned; } catch (CloneNotSupportedException e) { throw new AssertionError(); } } @Override public T findAnnotation(Method m) { for (RoleMapper<T> delegate : iterator()) { T annotation = delegate.findAnnotation(m); if (annotation != null) { return annotation; } } return null; } @Override public Collection<Class<?>> findIndividualRoles(T instance, Collection<Class<?>> classes) { for (RoleMapper<T> delegate : iterator()) { delegate.findIndividualRoles(instance, classes); } return classes; } @Override public Class<?> findInterfaceConcept(T uri) { for (RoleMapper<T> delegate : iterator()) { Class<?> concept = delegate.findInterfaceConcept(uri); if (concept != null) { return concept; } } return null; } @Override public Collection<Class<?>> findRoles(Collection<T> types, Collection<Class<?>> roles) { for (RoleMapper<T> delegate : iterator()) { delegate.findRoles(types, roles); } return roles; } @Override public Collection<Class<?>> findRoles(T type, Collection<Class<?>> roles) { for (RoleMapper<T> delegate : iterator()) { delegate.findRoles(type, roles); } return roles; } @Override public Collection<T> findSubTypes(Class<?> role, Collection<T> rdfTypes) { for (RoleMapper<T> delegate : iterator()) { delegate.findSubTypes(role, rdfTypes); } return rdfTypes; } @Override public T findType(Class<?> concept) { for (RoleMapper<T> delegate : iterator()) { T type = delegate.findType(concept); if (type != null) { return type; } } return null; } /** * This returns the writable role mapper of this composed role mapper. * * @return The primary writable role mapper. */ private RoleMapper<T> getPrimary() { if (primary == null) { primary = new DefaultRoleMapper<T>(typeFactory); if (roleMappers == null) { roleMappers = new ArrayList<RoleMapper<T>>(); } roleMappers.add(0, primary); } return primary; } public Collection<RoleMapper<T>> getRoleMappers() { return roleMappers == null ? Collections.<RoleMapper<T>> emptyList() : roleMappers; } @Override public boolean isIndividualRolesPresent(T instance) { for (RoleMapper<T> delegate : iterator()) { if (delegate.isIndividualRolesPresent(instance)) { return true; } } return false; } @Override public boolean isRecordedConcept(T type) { for (RoleMapper<T> delegate : iterator()) { if (delegate.isRecordedConcept(type)) { return true; } } return false; } private UniqueTransitiveIterator iterator() { return new UniqueTransitiveIterator(); } /** * Unregisters a role mapper that was used as a delegate. * * @param roleMapper * A {@link RoleMapper} that should be removed. * @return <code>true</code> if <code>roleMapper</code> was registered, else * <code>false</code>. */ public boolean removeRoleMapper(RoleMapper<T> roleMapper) { return roleMappers.remove(roleMapper); } }