/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2015 ForgeRock AS */ package org.opends.server.schema; import static org.mockito.Mockito.*; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NavigableMap; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.forgerock.opendj.ldap.Assertion; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.schema.MatchingRule; import org.forgerock.opendj.ldap.schema.Schema; import org.forgerock.opendj.ldap.spi.Indexer; import org.forgerock.opendj.ldap.spi.IndexingOptions; import org.opends.server.core.DirectoryServer; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.SearchFilter; class FakeEntryIndex { private AttributeType attrType; private MatchingRule matchingRule; private Indexer indexer; private final NavigableMap<ByteString, Set<Entry>> index = new TreeMap<>(); FakeEntryIndex(String attrName) throws DecodeException { attrType = DirectoryServer.getAttributeTypeOrNull(attrName); if (attrType == null) { throw new IllegalArgumentException("Cannot find attribute with name \"" + attrName + "\""); } matchingRule = attrType.getEqualityMatchingRule(); IndexingOptions options = mock(IndexingOptions.class); indexer = matchingRule.createIndexers(options).iterator().next(); } void addAll(List<Entry> entries) throws DecodeException { for (Entry entry : entries) { add(entry); } } void add(Entry entry) throws DecodeException { Attribute attribute = entry.getExactAttribute(attrType, Collections.<String>emptySet()); for (ByteString key : index(attribute)) { Set<Entry> entries = index.get(key); if (entries == null) { entries = new HashSet<>(); index.put(key, entries); } entries.add(entry); } } private Collection<ByteString> index(Attribute attribute) throws DecodeException { if (attribute == null) { return Collections.emptySet(); } Collection<ByteString> keys = new TreeSet<>(); for (ByteString attrValue : attribute) { indexer.createKeys(Schema.getDefaultSchema(), attrValue, keys); } return keys; } public Set<Entry> evaluateFilter(String filterString) throws DirectoryException, DecodeException { SearchFilter filter = SearchFilter.createFilterFromString(filterString); if (!attrType.equals(filter.getAttributeType())) { throw new IllegalArgumentException("The search filter \"" + filterString + "\" should target the same attribute type as this index \"" + attrType.getNameOrOID() + "\""); } Assertion assertion = getAssertion(filter); return assertion.createIndexQuery(new FakeIndexQueryFactory<Entry>(index)); } private Assertion getAssertion(SearchFilter filter) throws DecodeException { switch (filter.getFilterType()) { case EQUALITY: return matchingRule.getAssertion(filter.getAssertionValue()); case LESS_OR_EQUAL: return matchingRule.getLessOrEqualAssertion(filter.getAssertionValue()); case GREATER_OR_EQUAL: return matchingRule.getGreaterOrEqualAssertion(filter.getAssertionValue()); case EXTENSIBLE_MATCH: MatchingRule rule = DirectoryServer.getMatchingRule(filter.getMatchingRuleID()); return rule.getAssertion(filter.getAssertionValue()); default: throw new RuntimeException("Not implemented for search filter type " + filter.getFilterType()); } } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Map.Entry<ByteString, Set<Entry>> mapEntry : index.entrySet()) { String key = mapEntry.getKey().toHexString(); Set<Entry> value = mapEntry.getValue(); Iterator<Entry> it = value.iterator(); if (!it.hasNext()) { continue; } sb.append(key).append("\t").append(firstLine(it.next())).append("\n"); while (it.hasNext()) { sb.append(emptyString(key.length())).append("\t").append(firstLine(it.next())).append("\n"); } } return sb.toString(); } private String firstLine(Entry entry) { return entry.toString().split("\\n")[0] + " ..."; } private String emptyString(int length) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { sb.append(" "); } return sb.toString(); } }