opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java
@@ -22,7 +22,7 @@ * * * Copyright 2009 Sun Microsystems, Inc. * Portions copyright 2011-2012 ForgeRock AS. * Portions copyright 2011-2013 ForgeRock AS. */ package org.forgerock.opendj.ldap.schema; @@ -165,10 +165,12 @@ * attribute will be the normalized attribute type name followed by the * suffix "-oid". * * @param schema * The parent schema. * @param name * The name of the place-holder attribute type. */ AttributeType(final String name) { AttributeType(final Schema schema, final String name) { final StringBuilder builder = new StringBuilder(name.length() + 4); StaticUtils.toLowerCase(name, builder); builder.append("-oid"); @@ -178,12 +180,12 @@ this.isObsolete = false; this.superiorTypeOID = null; this.superiorType = null; this.equalityMatchingRule = Schema.getDefaultMatchingRule(); this.equalityMatchingRule = schema.getDefaultMatchingRule(); this.equalityMatchingRuleOID = equalityMatchingRule.getOID(); this.orderingMatchingRuleOID = null; this.substringMatchingRuleOID = null; this.approximateMatchingRuleOID = null; this.syntax = Schema.getDefaultSyntax(); this.syntax = schema.getDefaultSyntax(); this.syntaxOID = syntax.getOID(); this.isSingleValue = false; this.isCollective = false; opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java
@@ -22,6 +22,7 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2013 ForgeRock AS. */ package org.forgerock.opendj.ldap.schema; @@ -347,10 +348,10 @@ } if (impl == null) { impl = Schema.getDefaultMatchingRule().impl; final LocalizableMessage message = WARN_MATCHING_RULE_NOT_IMPLEMENTED1.get(getNameOrOID(), Schema .getDefaultMatchingRule().getOID()); impl = schema.getDefaultMatchingRule().impl; final LocalizableMessage message = WARN_MATCHING_RULE_NOT_IMPLEMENTED1 .get(getNameOrOID(), schema.getDefaultMatchingRule() .getOID()); warnings.add(message); } opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -22,7 +22,7 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2011-2012 ForgeRock AS * Portions copyright 2011-2013 ForgeRock AS */ package org.forgerock.opendj.ldap.schema; @@ -95,13 +95,21 @@ return false; } public Syntax getDefaultSyntax() { return Schema.getCoreSchema().getDefaultSyntax(); } public MatchingRule getDefaultMatchingRule() { return Schema.getCoreSchema().getDefaultMatchingRule(); } @Override public AttributeType getAttributeType(final String name) { public AttributeType getAttributeType(final Schema schema, final String name) { if (isStrict) { throw new UnknownSchemaElementException(WARN_ATTR_TYPE_UNKNOWN.get(name)); } else { // Return a place-holder. return new AttributeType(name); return new AttributeType(schema, name); } } @@ -234,9 +242,9 @@ } @Override public Syntax getSyntax(final String numericOID) { public Syntax getSyntax(final Schema schema, final String numericOID) { // Fake up a syntax substituted by the default syntax. return new Syntax(numericOID); return new Syntax(schema, numericOID); } @Override @@ -308,7 +316,11 @@ boolean allowZeroLengthDirectoryStrings(); AttributeType getAttributeType(String name); MatchingRule getDefaultMatchingRule(); Syntax getDefaultSyntax(); AttributeType getAttributeType(Schema schema, String name); Collection<AttributeType> getAttributeTypes(); @@ -360,7 +372,7 @@ String getSchemaName(); Syntax getSyntax(String numericOID); Syntax getSyntax(Schema schema, String numericOID); Collection<Syntax> getSyntaxes(); @@ -408,10 +420,18 @@ return strictImpl.allowZeroLengthDirectoryStrings(); } public Syntax getDefaultSyntax() { return strictImpl.getDefaultSyntax(); } public MatchingRule getDefaultMatchingRule() { return strictImpl.getDefaultMatchingRule(); } @Override public AttributeType getAttributeType(final String name) { public AttributeType getAttributeType(final Schema schema, final String name) { final AttributeType type = strictImpl.getAttributeType0(name); return type != null ? type : new AttributeType(name); return type != null ? type : new AttributeType(schema, name); } @Override @@ -540,11 +560,11 @@ } @Override public Syntax getSyntax(final String numericOID) { public Syntax getSyntax(final Schema schema, final String numericOID) { if (!strictImpl.hasSyntax(numericOID)) { return new Syntax(numericOID); return new Syntax(schema, numericOID); } return strictImpl.getSyntax(numericOID); return strictImpl.getSyntax(schema, numericOID); } @Override @@ -609,55 +629,37 @@ private static final class StrictImpl implements Impl { private final Map<Integer, DITStructureRule> id2StructureRules; private final Map<String, List<AttributeType>> name2AttributeTypes; private final Map<String, List<DITContentRule>> name2ContentRules; private final Map<String, List<MatchingRule>> name2MatchingRules; private final Map<String, List<MatchingRuleUse>> name2MatchingRuleUses; private final Map<String, List<NameForm>> name2NameForms; private final Map<String, List<ObjectClass>> name2ObjectClasses; private final Map<String, List<DITStructureRule>> name2StructureRules; private final Map<String, List<DITStructureRule>> nameForm2StructureRules; private final Map<String, AttributeType> numericOID2AttributeTypes; private final Map<String, DITContentRule> numericOID2ContentRules; private final Map<String, MatchingRule> numericOID2MatchingRules; private final Map<String, MatchingRuleUse> numericOID2MatchingRuleUses; private final Map<String, NameForm> numericOID2NameForms; private final Map<String, ObjectClass> numericOID2ObjectClasses; private final Map<String, Syntax> numericOID2Syntaxes; private final Map<String, List<NameForm>> objectClass2NameForms; private final List<LocalizableMessage> warnings; private final String schemaName; private final boolean allowMalformedJPEGPhotos; private final boolean allowNonStandardTelephoneNumbers; private final boolean allowZeroLengthDirectoryStrings; private final boolean allowMalformedNamesAndOptions; private final Syntax defaultSyntax; private final MatchingRule defaultMatchingRule; StrictImpl(final String schemaName, final boolean allowMalformedNamesAndOptions, final boolean allowMalformedJPEGPhotos, final boolean allowNonStandardTelephoneNumbers, final boolean allowZeroLengthDirectoryStrings, final Syntax defaultSyntax, final MatchingRule defaultMatchingRule, final Map<String, Syntax> numericOID2Syntaxes, final Map<String, MatchingRule> numericOID2MatchingRules, final Map<String, MatchingRuleUse> numericOID2MatchingRuleUses, @@ -681,6 +683,8 @@ this.allowMalformedJPEGPhotos = allowMalformedJPEGPhotos; this.allowNonStandardTelephoneNumbers = allowNonStandardTelephoneNumbers; this.allowZeroLengthDirectoryStrings = allowZeroLengthDirectoryStrings; this.defaultSyntax = defaultSyntax; this.defaultMatchingRule = defaultMatchingRule; this.numericOID2Syntaxes = Collections.unmodifiableMap(numericOID2Syntaxes); this.numericOID2MatchingRules = Collections.unmodifiableMap(numericOID2MatchingRules); this.numericOID2MatchingRuleUses = @@ -718,8 +722,16 @@ return allowZeroLengthDirectoryStrings; } public Syntax getDefaultSyntax() { return defaultSyntax; } public MatchingRule getDefaultMatchingRule() { return defaultMatchingRule; } @Override public AttributeType getAttributeType(final String name) { public AttributeType getAttributeType(final Schema schema, final String name) { final AttributeType type = getAttributeType0(name); if (type != null) { return type; @@ -963,7 +975,7 @@ } @Override public Syntax getSyntax(final String numericOID) { public Syntax getSyntax(final Schema schema, final String numericOID) { final Syntax syntax = numericOID2Syntaxes.get(numericOID); if (syntax == null) { throw new UnknownSchemaElementException(WARN_SYNTAX_UNKNOWN.get(numericOID)); @@ -1317,20 +1329,14 @@ return new SchemaBuilder(entry).toSchema(); } static MatchingRule getDefaultMatchingRule() { return CoreSchema.getCaseIgnoreMatchingRule(); } static Syntax getDefaultSyntax() { return CoreSchema.getDirectoryStringSyntax(); } private final Impl impl; Schema(final String schemaName, final boolean allowMalformedNamesAndOptions, final boolean allowMalformedJPEGPhotos, final boolean allowNonStandardTelephoneNumbers, final boolean allowZeroLengthDirectoryStrings, final Syntax defaultSyntax, final MatchingRule defaultMatchingRule, final Map<String, Syntax> numericOID2Syntaxes, final Map<String, MatchingRule> numericOID2MatchingRules, final Map<String, MatchingRuleUse> numericOID2MatchingRuleUses, @@ -1350,9 +1356,9 @@ final Map<String, List<DITStructureRule>> nameForm2StructureRules, final List<LocalizableMessage> warnings) { impl = new StrictImpl(schemaName, allowMalformedNamesAndOptions, allowMalformedJPEGPhotos, allowNonStandardTelephoneNumbers, allowZeroLengthDirectoryStrings, numericOID2Syntaxes, new StrictImpl(schemaName, allowMalformedNamesAndOptions, allowMalformedJPEGPhotos, allowNonStandardTelephoneNumbers, allowZeroLengthDirectoryStrings, defaultSyntax, defaultMatchingRule, numericOID2Syntaxes, numericOID2MatchingRules, numericOID2MatchingRuleUses, numericOID2AttributeTypes, numericOID2ObjectClasses, numericOID2NameForms, numericOID2ContentRules, id2StructureRules, name2MatchingRules, @@ -1474,6 +1480,28 @@ } /** * Returns the default matching rule which will be used when parsing * unrecognized attributes. * * @return The default matching rule which will be used when parsing * unrecognized attributes. */ public MatchingRule getDefaultMatchingRule() { return impl.getDefaultMatchingRule(); } /** * Returns the default syntax which will be used when parsing unrecognized * attributes. * * @return The default syntax which will be used when parsing unrecognized * attributes. */ public Syntax getDefaultSyntax() { return impl.getDefaultSyntax(); } /** * Returns the attribute type with the specified name or numeric OID. * <p> * If the requested attribute type is not registered in this schema and this @@ -1492,7 +1520,7 @@ * @see AttributeType#isPlaceHolder() */ public AttributeType getAttributeType(final String name) { return impl.getAttributeType(name); return impl.getAttributeType(this, name); } /** @@ -1824,7 +1852,7 @@ * found or if the provided name is ambiguous. */ public Syntax getSyntax(final String numericOID) { return impl.getSyntax(numericOID); return impl.getSyntax(this, numericOID); } /** opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -153,6 +153,9 @@ private boolean allowMalformedNamesAndOptions; private boolean allowMalformedJPEGPhotos; private String defaultSyntaxOID; private String defaultMatchingRuleOID; // A schema which should be copied into this builder on any mutation. private Schema copyOnWriteSchema = null; @@ -1404,6 +1407,74 @@ } /** * Sets the default syntax which will be used when parsing unrecognized * attributes. * <p> * By default the {@link CoreSchema#getOctetStringSyntax() OctetString} * syntax will be used. * * @param syntax * The default syntax which will be used when parsing * unrecognized attributes. * @return A reference to this {@code SchemaBuilder}. */ public SchemaBuilder defaultSyntax(final Syntax syntax) { return defaultSyntax(syntax.getOID()); } /** * Sets the default matching rule which will be used when parsing * unrecognized attributes. * <p> * By default the {@link CoreSchema#getOctetStringMatchingRule() * OctetString} matching rule will be used. * * @param rule * The default matching rule which will be used when parsing * unrecognized attributes. * @return A reference to this {@code SchemaBuilder}. */ public SchemaBuilder defaultMatchingRule(final MatchingRule rule) { return defaultMatchingRule(rule.getOID()); } /** * Sets the default syntax which will be used when parsing unrecognized * attributes. * <p> * By default the {@link CoreSchema#getOctetStringSyntax() OctetString} * syntax will be used. * * @param syntaxOID * The default syntax which will be used when parsing * unrecognized attributes. * @return A reference to this {@code SchemaBuilder}. */ public SchemaBuilder defaultSyntax(final String syntaxOID) { lazyInitBuilder(); this.defaultSyntaxOID = syntaxOID; return this; } /** * Sets the default matching rule which will be used when parsing * unrecognized attributes. * <p> * By default the {@link CoreSchema#getOctetStringMatchingRule() * OctetString} matching rule will be used. * * @param ruleOID * The default matching rule which will be used when parsing * unrecognized attributes. * @return A reference to this {@code SchemaBuilder}. */ public SchemaBuilder defaultMatchingRule(final String ruleOID) { lazyInitBuilder(); this.defaultMatchingRuleOID = ruleOID; return this; } /** * Duplicates the name form. * * @param nameForm @@ -2461,17 +2532,26 @@ localSchemaName = String.format("Schema#%d", NEXT_SCHEMA_ID.getAndIncrement()); } Syntax defaultSyntax = numericOID2Syntaxes.get(defaultSyntaxOID); if (defaultSyntax == null) { defaultSyntax = Schema.getCoreSchema().getDefaultSyntax(); } MatchingRule defaultMatchingRule = numericOID2MatchingRules.get(defaultMatchingRuleOID); if (defaultMatchingRule == null) { defaultMatchingRule = Schema.getCoreSchema().getDefaultMatchingRule(); } final Schema schema = new Schema(localSchemaName, allowMalformedNamesAndOptions, allowMalformedJPEGPhotos, allowNonStandardTelephoneNumbers, allowZeroLengthDirectoryStrings, numericOID2Syntaxes, numericOID2MatchingRules, numericOID2MatchingRuleUses, allowZeroLengthDirectoryStrings, defaultSyntax, defaultMatchingRule, numericOID2Syntaxes, numericOID2MatchingRules, numericOID2MatchingRuleUses, numericOID2AttributeTypes, numericOID2ObjectClasses, numericOID2NameForms, numericOID2ContentRules, id2StructureRules, name2MatchingRules, name2MatchingRuleUses, name2AttributeTypes, name2ObjectClasses, name2NameForms, name2ContentRules, name2StructureRules, objectClass2NameForms, nameForm2StructureRules, warnings); validate(schema); // Re-init this builder so that it can continue to be used afterwards. @@ -2749,6 +2829,8 @@ allowMalformedJPEGPhotos = true; allowNonStandardTelephoneNumbers = true; allowZeroLengthDirectoryStrings = false; defaultSyntaxOID = SchemaConstants.SYNTAX_OCTET_STRING_OID; defaultMatchingRuleOID = SchemaConstants.EMR_OCTET_STRING_OID; numericOID2Syntaxes = new LinkedHashMap<String, Syntax>(); numericOID2MatchingRules = new LinkedHashMap<String, MatchingRule>(); @@ -2780,6 +2862,8 @@ allowMalformedJPEGPhotos = copyOnWriteSchema.allowMalformedJPEGPhotos(); allowNonStandardTelephoneNumbers = copyOnWriteSchema.allowNonStandardTelephoneNumbers(); allowZeroLengthDirectoryStrings = copyOnWriteSchema.allowZeroLengthDirectoryStrings(); defaultSyntaxOID = copyOnWriteSchema.getDefaultSyntax().getOID(); defaultMatchingRuleOID = copyOnWriteSchema.getDefaultMatchingRule().getOID(); copyOnWriteSchema = null; } @@ -2793,6 +2877,8 @@ this.allowMalformedJPEGPhotos = true; this.allowNonStandardTelephoneNumbers = true; this.allowZeroLengthDirectoryStrings = false; this.defaultSyntaxOID = null; this.defaultMatchingRuleOID = null; this.numericOID2Syntaxes = null; this.numericOID2MatchingRules = null; opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Syntax.java
@@ -22,6 +22,7 @@ * * * Copyright 2009 Sun Microsystems, Inc. * Portions copyright 2013 ForgeRock AS. */ package org.forgerock.opendj.ldap.schema; @@ -62,13 +63,24 @@ private Schema schema; private SyntaxImpl impl; Syntax(final String oid) { super("", Collections.singletonMap("X-SUBST", Collections.singletonList(Schema .getDefaultSyntax().getOID())), null); /** * Creates a syntax representing an unrecognized syntax and whose * implementation is substituted by the schema's default syntax. * * @param schema * The parent schema. * @param oid * The numeric OID of the unrecognized syntax. */ Syntax(final Schema schema, final String oid) { super("", Collections.singletonMap("X-SUBST", Collections.singletonList(schema.getDefaultSyntax().getOID())), null); Validator.ensureNotNull(oid); this.oid = oid; this.impl = Schema.getDefaultSyntax().impl; this.schema = schema; this.impl = schema.getDefaultSyntax().impl; } Syntax(final String oid, final String description, @@ -282,10 +294,10 @@ } if (impl == null) { impl = Schema.getDefaultSyntax().impl; final LocalizableMessage message = WARN_ATTR_SYNTAX_NOT_IMPLEMENTED1.get(getDescription(), oid, Schema .getDefaultSyntax().getOID()); impl = schema.getDefaultSyntax().impl; final LocalizableMessage message = WARN_ATTR_SYNTAX_NOT_IMPLEMENTED1 .get(getDescription(), oid, schema.getDefaultSyntax() .getOID()); warnings.add(message); } } opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleTest.java
@@ -22,6 +22,7 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2013 ForgeRock AS. */ package org.forgerock.opendj.ldap.schema; @@ -29,9 +30,6 @@ import static org.forgerock.opendj.ldap.schema.SchemaConstants.EMR_DN_OID; import static org.testng.Assert.assertEquals; import java.text.Normalizer; import java.text.Normalizer.Form; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.ConditionResult; import org.testng.annotations.DataProvider; @@ -112,7 +110,11 @@ { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107", ConditionResult.TRUE }, { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8,o=Airius", "ou=\u55b6\u696d\u90e8,o=airius", ConditionResult.TRUE }, { "photo=\\ john \\ ,dc=com", "photo=\\ john \\ ,dc=com", ConditionResult.TRUE }, { "cn=\\ john \\ ,dc=com", "cn=\\ john \\ ,dc=com", ConditionResult.TRUE }, { "caseexact=UPPER,dc=COM", "caseexact=UPPER,dc=com", ConditionResult.TRUE }, { "caseexact=upper,dc=COM", "caseexact=UPPER,dc=com", ConditionResult.FALSE }, { "caseexact=UPPER,dc=COM", "caseexact=upper,dc=com", ConditionResult.FALSE }, { "caseexact=lower,dc=COM", "caseexact=lower,dc=com", ConditionResult.TRUE }, { "AB-global=", "ab-global=", ConditionResult.TRUE }, { "OU= Sales + CN = J. Smith ,DC=example,DC=net", "cn=j. smith+ou=sales,dc=example,dc=net", ConditionResult.TRUE }, @@ -167,10 +169,12 @@ // Unicode codepoints from 0000-0008 are mapped to nothing. "cn=hi" }, { "1.1.1=", "1.1.1=" }, { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107" }, { "CN=Lu\\C4\\8Di\\C4\\87", "cn=luc\u030cic\u0301" }, { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8,o=Airius", "o=airius\u0000ou=\u55b6\u696d\u90e8" }, { "photo=\\ john \\ ,dc=com", "dc=com\u0000photo=john" }, { "cn=\\ john \\ ,dc=com", "dc=com\u0000cn=john" }, { "caseexact=UPPER,dc=COM", "dc=com\u0000caseexact=UPPER" }, { "caseexact=mIxEd,dc=COM", "dc=com\u0000caseexact=mIxEd" }, { "AB-global=", "ab-global=" }, { "OU= Sales + CN = J. Smith ,DC=example,DC=net", "dc=net\u0000dc=example\u0000cn=j. smith\u0001ou=sales" }, @@ -186,13 +190,11 @@ * Test the normalized values */ @Test(dataProvider = "testDNs") public void matchingRules(final String value1, final String value2) throws Exception { public void testNormalization(final String value1, final String value2) throws Exception { final MatchingRule rule = getRule(); final ByteString normalizedValue1 = rule.normalizeAttributeValue(ByteString.valueOf(value1)); final ByteString expectedValue = ByteString.valueOf(Normalizer.normalize(value2, Form.NFKD)); final ByteString expectedValue = ByteString.valueOf(value2); assertEquals(normalizedValue1, expectedValue); } } opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
@@ -21,7 +21,7 @@ * CDDL HEADER END * * * Portions copyright 2012 ForgeRock AS. * Portions copyright 2012-2013 ForgeRock AS. */ package org.forgerock.opendj.ldap.schema; @@ -210,6 +210,9 @@ assertThat(schema.getObjectClasses()).isEmpty(); assertThat(schema.getSyntaxes()).isEmpty(); assertThat(schema.getWarnings()).isEmpty(); assertThat(schema.getDefaultSyntax()).isEqualTo(CoreSchema.getOctetStringSyntax()); assertThat(schema.getDefaultMatchingRule()).isEqualTo( CoreSchema.getOctetStringMatchingRule()); // Could go on... } @@ -1960,7 +1963,46 @@ assertThat(sc.getNameForms()).isNotNull(); assertThat(sc.getNameForms()).isEmpty(); connection.close(); } @Test public void testDefaultSyntax() { final Schema schema = new SchemaBuilder(Schema.getCoreSchema()).toSchema().asNonStrictSchema(); assertThat(schema.getDefaultSyntax()).isEqualTo(CoreSchema.getOctetStringSyntax()); assertThat(schema.getAttributeType("dummy").getSyntax()).isEqualTo( CoreSchema.getOctetStringSyntax()); } @Test public void testOverrideDefaultSyntax() { final Schema schema = new SchemaBuilder(Schema.getCoreSchema()).defaultSyntax( CoreSchema.getDirectoryStringSyntax()).toSchema().asNonStrictSchema(); assertThat(schema.getDefaultSyntax()).isEqualTo(CoreSchema.getDirectoryStringSyntax()); assertThat(schema.getAttributeType("dummy").getSyntax()).isEqualTo( CoreSchema.getDirectoryStringSyntax()); } @Test public void testDefaultMatchingRule() { final Schema schema = new SchemaBuilder(Schema.getCoreSchema()).toSchema().asNonStrictSchema(); assertThat(schema.getDefaultMatchingRule()).isEqualTo( CoreSchema.getOctetStringMatchingRule()); assertThat(schema.getAttributeType("dummy").getEqualityMatchingRule()).isEqualTo( CoreSchema.getOctetStringMatchingRule()); } @Test public void testOverrideMatchingRule() { final Schema schema = new SchemaBuilder(Schema.getCoreSchema()).defaultMatchingRule( CoreSchema.getCaseIgnoreMatchingRule()).toSchema().asNonStrictSchema(); assertThat(schema.getDefaultMatchingRule()).isEqualTo(CoreSchema.getCaseIgnoreMatchingRule()); assertThat(schema.getAttributeType("dummy").getEqualityMatchingRule()).isEqualTo( CoreSchema.getCaseIgnoreMatchingRule()); } } opendj-core/src/test/java/org/forgerock/opendj/ldif/LDIFEntryReaderTestCase.java
@@ -1163,9 +1163,8 @@ * * @throws Exception */ @Test(enabled = false) @Test public void testLDIFEntryReaderMultiplesAttributeValuesDifferentLetterCase() throws Exception { // @formatter:off final String[] strEntry = { "dn: cn=Character Set,cn=Password Validators,cn=config", @@ -1185,7 +1184,6 @@ final String path = TestCaseUtils.createTempFile(strEntry); final FileInputStream in = new FileInputStream(path); final LDIFEntryReader reader = new LDIFEntryReader(in); try { assertThat(reader.hasNext()); final Entry entry = reader.readEntry();