package com.hwlcn.ldap.ldap.sdk.schema; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import com.hwlcn.ldap.asn1.ASN1OctetString; import com.hwlcn.ldap.ldap.matchingrules.MatchingRule; import com.hwlcn.ldap.ldap.sdk.Attribute; import com.hwlcn.ldap.ldap.sdk.Entry; import com.hwlcn.ldap.ldap.sdk.LDAPException; import com.hwlcn.ldap.ldap.sdk.RDN; import com.hwlcn.core.annotation.ThreadSafety; import com.hwlcn.ldap.util.ThreadSafetyLevel; import static com.hwlcn.ldap.ldap.sdk.schema.SchemaMessages.*; import static com.hwlcn.ldap.util.Debug.*; import static com.hwlcn.ldap.util.StaticUtils.*; import static com.hwlcn.ldap.util.Validator.*; @ThreadSafety(level=ThreadSafetyLevel.MOSTLY_THREADSAFE) public final class EntryValidator implements Serializable { private static final long serialVersionUID = -8945609557086398241L; private final AtomicLong entriesExamined; private final AtomicLong invalidEntries; private final AtomicLong malformedDNs; private final AtomicLong missingSuperiorClasses; private final AtomicLong multipleStructuralClasses; private final AtomicLong nameFormViolations; private final AtomicLong noObjectClasses; private final AtomicLong noStructuralClass; private boolean checkAttributeSyntax; private boolean checkMalformedDNs; private boolean checkMissingAttributes; private boolean checkMissingSuperiorObjectClasses; private boolean checkNameForms; private boolean checkProhibitedAttributes; private boolean checkProhibitedObjectClasses; private boolean checkSingleValuedAttributes; private boolean checkStructuralObjectClasses; private boolean checkUndefinedAttributes; private boolean checkUndefinedObjectClasses; private final ConcurrentHashMap<String,AtomicLong> attributesViolatingSyntax; private final ConcurrentHashMap<String,AtomicLong> missingAttributes; private final ConcurrentHashMap<String,AtomicLong> prohibitedAttributes; private final ConcurrentHashMap<String,AtomicLong> prohibitedObjectClasses; private final ConcurrentHashMap<String,AtomicLong> singleValueViolations; private final ConcurrentHashMap<String,AtomicLong> undefinedAttributes; private final ConcurrentHashMap<String,AtomicLong> undefinedObjectClasses; private final Schema schema; public EntryValidator(final Schema schema) { this.schema = schema; checkAttributeSyntax = true; checkMalformedDNs = true; checkMissingAttributes = true; checkMissingSuperiorObjectClasses = true; checkNameForms = true; checkProhibitedAttributes = true; checkProhibitedObjectClasses = true; checkSingleValuedAttributes = true; checkStructuralObjectClasses = true; checkUndefinedAttributes = true; checkUndefinedObjectClasses = true; entriesExamined = new AtomicLong(0L); invalidEntries = new AtomicLong(0L); malformedDNs = new AtomicLong(0L); missingSuperiorClasses = new AtomicLong(0L); multipleStructuralClasses = new AtomicLong(0L); nameFormViolations = new AtomicLong(0L); noObjectClasses = new AtomicLong(0L); noStructuralClass = new AtomicLong(0L); attributesViolatingSyntax = new ConcurrentHashMap<String,AtomicLong>(); missingAttributes = new ConcurrentHashMap<String,AtomicLong>(); prohibitedAttributes = new ConcurrentHashMap<String,AtomicLong>(); prohibitedObjectClasses = new ConcurrentHashMap<String,AtomicLong>(); singleValueViolations = new ConcurrentHashMap<String,AtomicLong>(); undefinedAttributes = new ConcurrentHashMap<String,AtomicLong>(); undefinedObjectClasses = new ConcurrentHashMap<String,AtomicLong>(); } public boolean checkMissingAttributes() { return checkMissingAttributes; } public void setCheckMissingAttributes(final boolean checkMissingAttributes) { this.checkMissingAttributes = checkMissingAttributes; } public boolean checkMissingSuperiorObjectClasses() { return checkMissingSuperiorObjectClasses; } public void setCheckMissingSuperiorObjectClasses( final boolean checkMissingSuperiorObjectClasses) { this.checkMissingSuperiorObjectClasses = checkMissingSuperiorObjectClasses; } public boolean checkMalformedDNs() { return checkMalformedDNs; } public void setCheckMalformedDNs(final boolean checkMalformedDNs) { this.checkMalformedDNs = checkMalformedDNs; } public boolean checkNameForms() { return checkNameForms; } public void setCheckNameForms(final boolean checkNameForms) { this.checkNameForms = checkNameForms; } public boolean checkProhibitedAttributes() { return checkProhibitedAttributes; } public void setCheckProhibitedAttributes( final boolean checkProhibitedAttributes) { this.checkProhibitedAttributes = checkProhibitedAttributes; } public boolean checkProhibitedObjectClasses() { return checkProhibitedObjectClasses; } public void setCheckProhibitedObjectClasses( final boolean checkProhibitedObjectClasses) { this.checkProhibitedObjectClasses = checkProhibitedObjectClasses; } public boolean checkSingleValuedAttributes() { return checkSingleValuedAttributes; } public void setCheckSingleValuedAttributes( final boolean checkSingleValuedAttributes) { this.checkSingleValuedAttributes = checkSingleValuedAttributes; } public boolean checkStructuralObjectClasses() { return checkStructuralObjectClasses; } public void setCheckStructuralObjectClasses( final boolean checkStructuralObjectClasses) { this.checkStructuralObjectClasses = checkStructuralObjectClasses; } public boolean checkAttributeSyntax() { return checkAttributeSyntax; } public void setCheckAttributeSyntax(final boolean checkAttributeSyntax) { this.checkAttributeSyntax = checkAttributeSyntax; } public boolean checkUndefinedAttributes() { return checkUndefinedAttributes; } public void setCheckUndefinedAttributes( final boolean checkUndefinedAttributes) { this.checkUndefinedAttributes = checkUndefinedAttributes; } public boolean checkUndefinedObjectClasses() { return checkUndefinedObjectClasses; } public void setCheckUndefinedObjectClasses( final boolean checkUndefinedObjectClasses) { this.checkUndefinedObjectClasses = checkUndefinedObjectClasses; } public boolean entryIsValid(final Entry entry, final List<String> invalidReasons) { ensureNotNull(entry); boolean entryValid = true; entriesExamined.incrementAndGet(); RDN rdn = null; try { rdn = entry.getParsedDN().getRDN(); } catch (LDAPException le) { debugException(le); if (checkMalformedDNs) { entryValid = false; malformedDNs.incrementAndGet(); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_MALFORMED_DN.get( getExceptionMessage(le))); } } } final HashSet<ObjectClassDefinition> ocSet = new HashSet<ObjectClassDefinition>(); final boolean missingOC = (! getObjectClasses(entry, ocSet, invalidReasons)); if (missingOC) { entryValid = false; } DITContentRuleDefinition ditContentRule = null; NameFormDefinition nameForm = null; if (! missingOC) { final AtomicReference<ObjectClassDefinition> ref = new AtomicReference<ObjectClassDefinition>(null); entryValid &= getStructuralClass(ocSet, ref, invalidReasons); final ObjectClassDefinition structuralClass = ref.get(); if (structuralClass != null) { ditContentRule = schema.getDITContentRule(structuralClass.getOID()); nameForm = schema.getNameFormByObjectClass(structuralClass.getNameOrOID()); } } HashSet<AttributeTypeDefinition> requiredAttrs = null; if (checkMissingAttributes || checkProhibitedAttributes) { requiredAttrs = getRequiredAttributes(ocSet, ditContentRule); if (checkMissingAttributes) { entryValid &= checkForMissingAttributes(entry, rdn, requiredAttrs, invalidReasons); } } HashSet<AttributeTypeDefinition> optionalAttrs = null; if (checkProhibitedAttributes) { optionalAttrs = getOptionalAttributes(ocSet, ditContentRule, requiredAttrs); } for (final Attribute a : entry.getAttributes()) { entryValid &= checkAttribute(a, requiredAttrs, optionalAttrs, invalidReasons); } if (checkProhibitedObjectClasses && (ditContentRule != null)) { entryValid &= checkAuxiliaryClasses(ocSet, ditContentRule, invalidReasons); } if (rdn != null) { entryValid &= checkRDN(rdn, requiredAttrs, optionalAttrs, nameForm, invalidReasons); } if (! entryValid) { invalidEntries.incrementAndGet(); } return entryValid; } private boolean getObjectClasses(final Entry entry, final HashSet<ObjectClassDefinition> ocSet, final List<String> invalidReasons) { final String[] ocValues = entry.getObjectClassValues(); if ((ocValues == null) || (ocValues.length == 0)) { noObjectClasses.incrementAndGet(); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_NO_OCS.get()); } return false; } boolean entryValid = true; final HashSet<String> missingOCs = new HashSet<String>(ocValues.length); for (final String ocName : entry.getObjectClassValues()) { final ObjectClassDefinition d = schema.getObjectClass(ocName); if (d == null) { if (checkUndefinedObjectClasses) { entryValid = false; missingOCs.add(toLowerCase(ocName)); updateCount(ocName, undefinedObjectClasses); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_UNDEFINED_OC.get(ocName)); } } } else { ocSet.add(d); } } for (final ObjectClassDefinition d : new HashSet<ObjectClassDefinition>(ocSet)) { entryValid &= addSuperiorClasses(d, ocSet, missingOCs, invalidReasons); } return entryValid; } private boolean addSuperiorClasses(final ObjectClassDefinition d, final HashSet<ObjectClassDefinition> ocSet, final HashSet<String> missingOCNames, final List<String> invalidReasons) { boolean entryValid = true; for (final String ocName : d.getSuperiorClasses()) { final ObjectClassDefinition supOC = schema.getObjectClass(ocName); if (supOC == null) { if (checkUndefinedObjectClasses) { entryValid = false; final String lowerName = toLowerCase(ocName); if (! missingOCNames.contains(lowerName)) { missingOCNames.add(lowerName); updateCount(ocName, undefinedObjectClasses); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_UNDEFINED_SUP_OC.get( d.getNameOrOID(), ocName)); } } } } else { if (! ocSet.contains(supOC)) { ocSet.add(supOC); if (checkMissingSuperiorObjectClasses) { entryValid = false; missingSuperiorClasses.incrementAndGet(); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_MISSING_SUP_OC.get( supOC.getNameOrOID(), d.getNameOrOID())); } } } entryValid &= addSuperiorClasses(supOC, ocSet, missingOCNames, invalidReasons); } } return entryValid; } private boolean getStructuralClass(final HashSet<ObjectClassDefinition> ocSet, final AtomicReference<ObjectClassDefinition> structuralClass, final List<String> invalidReasons) { final HashSet<ObjectClassDefinition> ocCopy = new HashSet<ObjectClassDefinition>(ocSet); for (final ObjectClassDefinition d : ocSet) { final ObjectClassType t = d.getObjectClassType(schema); if (t == ObjectClassType.STRUCTURAL) { ocCopy.removeAll(d.getSuperiorClasses(schema, true)); } else if (t == ObjectClassType.AUXILIARY) { ocCopy.remove(d); ocCopy.removeAll(d.getSuperiorClasses(schema, true)); } } boolean entryValid = true; Iterator<ObjectClassDefinition> iterator = ocCopy.iterator(); while (iterator.hasNext()) { final ObjectClassDefinition d = iterator.next(); if (d.getObjectClassType(schema) == ObjectClassType.ABSTRACT) { if (checkProhibitedObjectClasses) { entryValid = false; updateCount(d.getNameOrOID(), prohibitedObjectClasses); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_INVALID_ABSTRACT_CLASS.get( d.getNameOrOID())); } } iterator.remove(); } } switch (ocCopy.size()) { case 0: if (checkStructuralObjectClasses) { entryValid = false; noStructuralClass.incrementAndGet(); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_NO_STRUCTURAL_CLASS.get()); } } break; case 1: structuralClass.set(ocCopy.iterator().next()); break; default: if (checkStructuralObjectClasses) { entryValid = false; multipleStructuralClasses.incrementAndGet(); if (invalidReasons != null) { final StringBuilder ocList = new StringBuilder(); iterator = ocCopy.iterator(); while (iterator.hasNext()) { ocList.append(iterator.next().getNameOrOID()); if (iterator.hasNext()) { ocList.append(", "); } } invalidReasons.add( ERR_ENTRY_MULTIPLE_STRUCTURAL_CLASSES.get(ocList)); } } break; } return entryValid; } private HashSet<AttributeTypeDefinition> getRequiredAttributes( final HashSet<ObjectClassDefinition> ocSet, final DITContentRuleDefinition ditContentRule) { final HashSet<AttributeTypeDefinition> attrSet = new HashSet<AttributeTypeDefinition>(); for (final ObjectClassDefinition oc : ocSet) { attrSet.addAll(oc.getRequiredAttributes(schema, false)); } if (ditContentRule != null) { for (final String s : ditContentRule.getRequiredAttributes()) { final AttributeTypeDefinition d = schema.getAttributeType(s); if (d != null) { attrSet.add(d); } } } return attrSet; } private HashSet<AttributeTypeDefinition> getOptionalAttributes( final HashSet<ObjectClassDefinition> ocSet, final DITContentRuleDefinition ditContentRule, final HashSet<AttributeTypeDefinition> requiredAttrSet) { final HashSet<AttributeTypeDefinition> attrSet = new HashSet<AttributeTypeDefinition>(); for (final ObjectClassDefinition oc : ocSet) { if (oc.hasNameOrOID("extensibleObject") || oc.hasNameOrOID("1.3.6.1.4.1.1466.101.120.111")) { attrSet.addAll(schema.getUserAttributeTypes()); break; } for (final AttributeTypeDefinition d : oc.getOptionalAttributes(schema, false)) { if (! requiredAttrSet.contains(d)) { attrSet.add(d); } } } if (ditContentRule != null) { for (final String s : ditContentRule.getOptionalAttributes()) { final AttributeTypeDefinition d = schema.getAttributeType(s); if ((d != null) && (! requiredAttrSet.contains(d))) { attrSet.add(d); } } for (final String s : ditContentRule.getProhibitedAttributes()) { final AttributeTypeDefinition d = schema.getAttributeType(s); if (d != null) { attrSet.remove(d); } } } return attrSet; } private boolean checkForMissingAttributes(final Entry entry, final RDN rdn, final HashSet<AttributeTypeDefinition> requiredAttrs, final List<String> invalidReasons) { boolean entryValid = true; for (final AttributeTypeDefinition d : requiredAttrs) { boolean found = false; for (final String s : d.getNames()) { if (entry.hasAttribute(s) || ((rdn != null) && rdn.hasAttribute(s))) { found = true; break; } } if (! found) { if (! (entry.hasAttribute(d.getOID()) || ((rdn != null) && (rdn.hasAttribute(d.getOID()))))) { entryValid = false; updateCount(d.getNameOrOID(), missingAttributes); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_MISSING_REQUIRED_ATTR.get( d.getNameOrOID())); } } } } return entryValid; } private boolean checkAttribute(final Attribute attr, final HashSet<AttributeTypeDefinition> requiredAttrs, final HashSet<AttributeTypeDefinition> optionalAttrs, final List<String> invalidReasons) { boolean entryValid = true; final AttributeTypeDefinition d = schema.getAttributeType(attr.getBaseName()); if (d == null) { if (checkUndefinedAttributes) { entryValid = false; updateCount(attr.getBaseName(), undefinedAttributes); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_UNDEFINED_ATTR.get(attr.getBaseName())); } } return entryValid; } if (checkProhibitedAttributes && (! d.isOperational())) { if (! (requiredAttrs.contains(d) || optionalAttrs.contains(d))) { entryValid = false; updateCount(d.getNameOrOID(), prohibitedAttributes); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_ATTR_NOT_ALLOWED.get(d.getNameOrOID())); } } } final ASN1OctetString[] rawValues = attr.getRawValues(); if (checkSingleValuedAttributes && d.isSingleValued() && (rawValues.length > 1)) { entryValid = false; updateCount(d.getNameOrOID(), singleValueViolations); if (invalidReasons != null) { invalidReasons.add( ERR_ENTRY_ATTR_HAS_MULTIPLE_VALUES.get(d.getNameOrOID())); } } if (checkAttributeSyntax) { final MatchingRule r = MatchingRule.selectEqualityMatchingRule(d.getNameOrOID(), schema); for (final ASN1OctetString v : rawValues) { try { r.normalize(v); } catch (LDAPException le) { debugException(le); entryValid = false; updateCount(d.getNameOrOID(), attributesViolatingSyntax); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_ATTR_INVALID_SYNTAX.get( v.stringValue(), d.getNameOrOID(), getExceptionMessage(le))); } } } } return entryValid; } private boolean checkAuxiliaryClasses( final HashSet<ObjectClassDefinition> ocSet, final DITContentRuleDefinition ditContentRule, final List<String> invalidReasons) { final HashSet<ObjectClassDefinition> auxSet = new HashSet<ObjectClassDefinition>(); for (final String s : ditContentRule.getAuxiliaryClasses()) { final ObjectClassDefinition d = schema.getObjectClass(s); if (d != null) { auxSet.add(d); } } boolean entryValid = true; for (final ObjectClassDefinition d : ocSet) { final ObjectClassType t = d.getObjectClassType(schema); if ((t == ObjectClassType.AUXILIARY) && (! auxSet.contains(d))) { entryValid = false; updateCount(d.getNameOrOID(), prohibitedObjectClasses); if (invalidReasons != null) { invalidReasons.add( ERR_ENTRY_AUX_CLASS_NOT_ALLOWED.get(d.getNameOrOID())); } } } return entryValid; } private boolean checkRDN(final RDN rdn, final HashSet<AttributeTypeDefinition> requiredAttrs, final HashSet<AttributeTypeDefinition> optionalAttrs, final NameFormDefinition nameForm, final List<String> invalidReasons) { final HashSet<AttributeTypeDefinition> nfReqAttrs = new HashSet<AttributeTypeDefinition>(); final HashSet<AttributeTypeDefinition> nfAllowedAttrs = new HashSet<AttributeTypeDefinition>(); if (nameForm != null) { for (final String s : nameForm.getRequiredAttributes()) { final AttributeTypeDefinition d = schema.getAttributeType(s); if (d != null) { nfReqAttrs.add(d); } } nfAllowedAttrs.addAll(nfReqAttrs); for (final String s : nameForm.getOptionalAttributes()) { final AttributeTypeDefinition d = schema.getAttributeType(s); if (d != null) { nfAllowedAttrs.add(d); } } } boolean entryValid = true; for (final String s : rdn.getAttributeNames()) { final AttributeTypeDefinition d = schema.getAttributeType(s); if (d == null) { if (checkUndefinedAttributes) { entryValid = false; updateCount(s, undefinedAttributes); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_RDN_ATTR_NOT_DEFINED.get(s)); } } } else { if (checkProhibitedAttributes && (! (requiredAttrs.contains(d) || optionalAttrs.contains(d) || d.isOperational()))) { entryValid = false; updateCount(d.getNameOrOID(), prohibitedAttributes); if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_RDN_ATTR_NOT_ALLOWED_IN_ENTRY.get( d.getNameOrOID())); } } if (checkNameForms && (nameForm != null)) { if (! nfReqAttrs.remove(d)) { if (! nfAllowedAttrs.contains(d)) { if (entryValid) { entryValid = false; nameFormViolations.incrementAndGet(); } if (invalidReasons != null) { invalidReasons.add(ERR_ENTRY_RDN_ATTR_NOT_ALLOWED_BY_NF.get(s)); } } } } } } if (checkNameForms && (! nfReqAttrs.isEmpty())) { if (entryValid) { entryValid = false; nameFormViolations.incrementAndGet(); } if (invalidReasons != null) { for (final AttributeTypeDefinition d : nfReqAttrs) { invalidReasons.add(ERR_ENTRY_RDN_MISSING_REQUIRED_ATTR.get( d.getNameOrOID())); } } } return entryValid; } private static void updateCount(final String key, final ConcurrentHashMap<String,AtomicLong> map) { final String lowerKey = toLowerCase(key); AtomicLong l = map.get(lowerKey); if (l == null) { l = map.putIfAbsent(lowerKey, new AtomicLong(1L)); if (l == null) { return; } } l.incrementAndGet(); } public void resetCounts() { entriesExamined.set(0L); invalidEntries.set(0L); malformedDNs.set(0L); missingSuperiorClasses.set(0L); multipleStructuralClasses.set(0L); nameFormViolations.set(0L); noObjectClasses.set(0L); noStructuralClass.set(0L); attributesViolatingSyntax.clear(); missingAttributes.clear(); prohibitedAttributes.clear(); prohibitedObjectClasses.clear(); singleValueViolations.clear(); undefinedAttributes.clear(); undefinedObjectClasses.clear(); } public long getEntriesExamined() { return entriesExamined.get(); } public long getInvalidEntries() { return invalidEntries.get(); } public long getMalformedDNs() { return malformedDNs.get(); } public long getEntriesWithoutAnyObjectClasses() { return noObjectClasses.get(); } public long getEntriesMissingStructuralObjectClass() { return noStructuralClass.get(); } public long getEntriesWithMultipleStructuralObjectClasses() { return multipleStructuralClasses.get(); } public long getEntriesWithMissingSuperiorObjectClasses() { return missingSuperiorClasses.get(); } public long getNameFormViolations() { return nameFormViolations.get(); } public long getTotalUndefinedObjectClasses() { return getMapTotal(undefinedObjectClasses); } public Map<String,Long> getUndefinedObjectClasses() { return convertMap(undefinedObjectClasses); } public long getTotalUndefinedAttributes() { return getMapTotal(undefinedAttributes); } public Map<String,Long> getUndefinedAttributes() { return convertMap(undefinedAttributes); } public long getTotalProhibitedObjectClasses() { return getMapTotal(prohibitedObjectClasses); } public Map<String,Long> getProhibitedObjectClasses() { return convertMap(prohibitedObjectClasses); } public long getTotalProhibitedAttributes() { return getMapTotal(prohibitedAttributes); } public Map<String,Long> getProhibitedAttributes() { return convertMap(prohibitedAttributes); } public long getTotalMissingAttributes() { return getMapTotal(missingAttributes); } public Map<String,Long> getMissingAttributes() { return convertMap(missingAttributes); } public long getTotalAttributesViolatingSyntax() { return getMapTotal(attributesViolatingSyntax); } public Map<String,Long> getAttributesViolatingSyntax() { return convertMap(attributesViolatingSyntax); } public long getTotalSingleValueViolations() { return getMapTotal(singleValueViolations); } public Map<String,Long> getSingleValueViolations() { return convertMap(singleValueViolations); } private static long getMapTotal(final Map<String,AtomicLong> map) { long total = 0L; for (final AtomicLong l : map.values()) { total += l.longValue(); } return total; } private static Map<String,Long> convertMap(final Map<String,AtomicLong> map) { final TreeMap<String,Long> m = new TreeMap<String,Long>(); for (final Map.Entry<String,AtomicLong> e : map.entrySet()) { m.put(e.getKey(), e.getValue().longValue()); } return Collections.unmodifiableMap(m); } public List<String> getInvalidEntrySummary(final boolean detailedResults) { final long numInvalid = invalidEntries.get(); if (numInvalid == 0) { return Collections.emptyList(); } final ArrayList<String> messages = new ArrayList<String>(5); final long numEntries = entriesExamined.get(); long pct = 100 * numInvalid / numEntries; messages.add(INFO_ENTRY_INVALID_ENTRY_COUNT.get( numInvalid, numEntries, pct)); final long numBadDNs = malformedDNs.get(); if (numBadDNs > 0) { pct = 100 * numBadDNs / numEntries; messages.add(INFO_ENTRY_MALFORMED_DN_COUNT.get( numBadDNs, numEntries, pct)); } final long numNoOCs = noObjectClasses.get(); if (numNoOCs > 0) { pct = 100 * numNoOCs / numEntries; messages.add(INFO_ENTRY_NO_OC_COUNT.get(numNoOCs, numEntries, pct)); } final long numMissingStructural = noStructuralClass.get(); if (numMissingStructural > 0) { pct = 100 * numMissingStructural / numEntries; messages.add(INFO_ENTRY_NO_STRUCTURAL_OC_COUNT.get( numMissingStructural, numEntries, pct)); } final long numMultipleStructural = multipleStructuralClasses.get(); if (numMultipleStructural > 0) { pct = 100 * numMultipleStructural / numEntries; messages.add(INFO_ENTRY_MULTIPLE_STRUCTURAL_OCS_COUNT.get( numMultipleStructural, numEntries, pct)); } final long numNFViolations = nameFormViolations.get(); if (numNFViolations > 0) { pct = 100 * numNFViolations / numEntries; messages.add(INFO_ENTRY_NF_VIOLATION_COUNT.get( numNFViolations, numEntries, pct)); } final long numUndefinedOCs = getTotalUndefinedObjectClasses(); if (numUndefinedOCs > 0) { messages.add(INFO_ENTRY_UNDEFINED_OC_COUNT.get(numUndefinedOCs)); if (detailedResults) { for (final Map.Entry<String,AtomicLong> e : undefinedObjectClasses.entrySet()) { messages.add(INFO_ENTRY_UNDEFINED_OC_NAME_COUNT.get( e.getKey(), e.getValue().longValue())); } } } final long numProhibitedOCs = getTotalProhibitedObjectClasses(); if (numProhibitedOCs > 0) { messages.add(INFO_ENTRY_PROHIBITED_OC_COUNT.get(numProhibitedOCs)); if (detailedResults) { for (final Map.Entry<String,AtomicLong> e : prohibitedObjectClasses.entrySet()) { messages.add(INFO_ENTRY_PROHIBITED_OC_NAME_COUNT.get( e.getKey(), e.getValue().longValue())); } } } final long numMissingSuperior = getEntriesWithMissingSuperiorObjectClasses(); if (numMissingSuperior > 0) { messages.add( INFO_ENTRY_MISSING_SUPERIOR_OC_COUNT.get(numMissingSuperior)); } final long numUndefinedAttrs = getTotalUndefinedAttributes(); if (numUndefinedAttrs > 0) { messages.add(INFO_ENTRY_UNDEFINED_ATTR_COUNT.get(numUndefinedAttrs)); if (detailedResults) { for (final Map.Entry<String,AtomicLong> e : undefinedAttributes.entrySet()) { messages.add(INFO_ENTRY_UNDEFINED_ATTR_NAME_COUNT.get( e.getKey(), e.getValue().longValue())); } } } final long numMissingAttrs = getTotalMissingAttributes(); if (numMissingAttrs > 0) { messages.add(INFO_ENTRY_MISSING_ATTR_COUNT.get(numMissingAttrs)); if (detailedResults) { for (final Map.Entry<String,AtomicLong> e : missingAttributes.entrySet()) { messages.add(INFO_ENTRY_MISSING_ATTR_NAME_COUNT.get( e.getKey(), e.getValue().longValue())); } } } final long numProhibitedAttrs = getTotalProhibitedAttributes(); if (numProhibitedAttrs > 0) { messages.add(INFO_ENTRY_PROHIBITED_ATTR_COUNT.get(numProhibitedAttrs)); if (detailedResults) { for (final Map.Entry<String,AtomicLong> e : prohibitedAttributes.entrySet()) { messages.add(INFO_ENTRY_PROHIBITED_ATTR_NAME_COUNT.get( e.getKey(), e.getValue().longValue())); } } } final long numSingleValuedViolations = getTotalSingleValueViolations(); if (numSingleValuedViolations > 0) { messages.add(INFO_ENTRY_SINGLE_VALUE_VIOLATION_COUNT.get( numSingleValuedViolations)); if (detailedResults) { for (final Map.Entry<String,AtomicLong> e : singleValueViolations.entrySet()) { messages.add(INFO_ENTRY_SINGLE_VALUE_VIOLATION_NAME_COUNT.get( e.getKey(), e.getValue().longValue())); } } } final long numSyntaxViolations = getTotalAttributesViolatingSyntax(); if (numSyntaxViolations > 0) { messages.add(INFO_ENTRY_SYNTAX_VIOLATION_COUNT.get(numSyntaxViolations)); if (detailedResults) { for (final Map.Entry<String,AtomicLong> e : attributesViolatingSyntax.entrySet()) { messages.add(INFO_ENTRY_SYNTAX_VIOLATION_NAME_COUNT.get( e.getKey(), e.getValue().longValue())); } } } return Collections.unmodifiableList(messages); } }