| | |
| | | import java.util.HashMap; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | /** |
| | | * The set of attribute types having at least one subordinate type in a |
| | | * schema, cached per schema instance. Subtype-inclusive attribute lookups |
| | | * run for every entry read (compare assertions, search filters, password |
| | | * policy attributes, ...): when the requested type has no subordinates, |
| | | * walking every attribute of the entry degenerates to an exact map lookup, |
| | | * so cache which types actually need the walk. The schema and the set |
| | | * computed for it are held in one immutable holder swapped atomically, so |
| | | * a reader can never pair a set with the wrong schema. |
| | | */ |
| | | private static final class TypesWithSubordinates |
| | | { |
| | | private final Schema schema; |
| | | private final Set<AttributeType> types; |
| | | |
| | | private TypesWithSubordinates(Schema schema, Set<AttributeType> types) |
| | | { |
| | | this.schema = schema; |
| | | this.types = types; |
| | | } |
| | | } |
| | | |
| | | private static volatile TypesWithSubordinates typesWithSubordinates = |
| | | new TypesWithSubordinates(null, Collections.<AttributeType> emptySet()); |
| | | |
| | | private static boolean mayHaveSubordinateTypes(AttributeType attrType) |
| | | { |
| | | if (attrType.isPlaceHolder()) |
| | | { |
| | | // isSuperTypeOf() matches place-holder types against schema-defined |
| | | // types by name, which an exact map lookup cannot honor: keep the walk. |
| | | return true; |
| | | } |
| | | Schema schema; |
| | | try |
| | | { |
| | | schema = DirectoryServer.getInstance().getServerContext().getSchema(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | // No server schema available (offline tools, early startup): |
| | | // conservatively assume subtypes may exist. |
| | | return true; |
| | | } |
| | | if (schema == null) |
| | | { |
| | | return true; |
| | | } |
| | | TypesWithSubordinates cached = typesWithSubordinates; |
| | | if (cached.schema != schema) |
| | | { |
| | | Set<AttributeType> withSubordinates = new HashSet<>(); |
| | | for (AttributeType type : schema.getAttributeTypes()) |
| | | { |
| | | for (AttributeType superior = type.getSuperiorType(); superior != null; |
| | | superior = superior.getSuperiorType()) |
| | | { |
| | | withSubordinates.add(superior); |
| | | } |
| | | } |
| | | cached = new TypesWithSubordinates(schema, withSubordinates); |
| | | typesWithSubordinates = cached; |
| | | } |
| | | return cached.types.contains(attrType); |
| | | } |
| | | |
| | | private void addAttributeTypeOrSubTypeValue(Collection<Attribute> results, AttributeType attrType, |
| | | Map<AttributeType, List<Attribute>> attrsMap) |
| | | { |
| | | if (!mayHaveSubordinateTypes(attrType)) |
| | | { |
| | | // No type in the schema extends attrType: isSuperTypeOf() can only |
| | | // match the type itself, so use an exact lookup instead of walking |
| | | // every attribute of the entry. |
| | | List<Attribute> attributes = attrsMap.get(attrType); |
| | | if (attributes != null) |
| | | { |
| | | results.addAll(attributes); |
| | | } |
| | | return; |
| | | } |
| | | for (Map.Entry<AttributeType, List<Attribute>> mapEntry : attrsMap.entrySet()) |
| | | { |
| | | if (attrType.isSuperTypeOf(mapEntry.getKey())) |
| | |
| | | private void addAttributeTypeOrSubTypeValue(Collection<Attribute> results, AttributeDescription attrDesc, |
| | | Map<AttributeType, List<Attribute>> attrsMap) |
| | | { |
| | | if (!mayHaveSubordinateTypes(attrDesc.getAttributeType())) |
| | | { |
| | | List<Attribute> attributes = attrsMap.get(attrDesc.getAttributeType()); |
| | | if (attributes != null) |
| | | { |
| | | for (Attribute attribute : attributes) |
| | | { |
| | | if (attrDesc.isSuperTypeOf(attribute.getAttributeDescription())) |
| | | { |
| | | results.add(attribute); |
| | | } |
| | | } |
| | | } |
| | | return; |
| | | } |
| | | for (Map.Entry<AttributeType, List<Attribute>> mapEntry : attrsMap.entrySet()) |
| | | { |
| | | if (!attrDesc.getAttributeType().isSuperTypeOf(mapEntry.getKey())) |
| | |
| | | |
| | | private boolean hasAttributeOrSubType(AttributeDescription attrDesc, Map<AttributeType, List<Attribute>> attrsMap) |
| | | { |
| | | if (!mayHaveSubordinateTypes(attrDesc.getAttributeType())) |
| | | { |
| | | List<Attribute> attributes = attrsMap.get(attrDesc.getAttributeType()); |
| | | if (attributes != null) |
| | | { |
| | | for (Attribute attribute : attributes) |
| | | { |
| | | // It's possible that there could be an attribute without any values, |
| | | // which we should treat as not having the requested attribute. |
| | | if (!attribute.isEmpty() && attrDesc.isSuperTypeOf(attribute.getAttributeDescription())) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | for (Map.Entry<AttributeType, List<Attribute>> mapEntry : attrsMap.entrySet()) |
| | | { |
| | | if (!attrDesc.getAttributeType().isSuperTypeOf(mapEntry.getKey())) |