All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scriptella.driver.ldap.ldif.LdifReader Maven / Gradle / Ivy

There is a newer version: 1.1
Show newest version
/*
 *   Copyright 2006 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */
package scriptella.driver.ldap.ldif;

import scriptella.expression.LineIterator;
import scriptella.util.StringUtils;

import javax.naming.directory.DirContext;
import javax.naming.ldap.BasicControl;
import javax.naming.ldap.Control;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 
 *  <ldif-file> ::= "version:" <fill> <number> <seps> <dn-spec> <sep> <ldif-content-change>
 * 

* <ldif-content-change> ::= * <number> <oid> <options-e> <value-spec> <sep> <attrval-specs-e> <ldif-attrval-record-e> | * <alpha> <chars-e> <options-e> <value-spec> <sep> <attrval-specs-e> <ldif-attrval-record-e> | * "control:" <fill> <number> <oid> <spaces-e> <criticality> <value-spec-e> <sep> <controls-e> * "changetype:" <fill> <changerecord-type> <ldif-change-record-e> | * "changetype:" <fill> <changerecord-type> <ldif-change-record-e> *

* <ldif-attrval-record-e> ::= <seps> <dn-spec> <sep> <attributeType> * <options-e> <value-spec> <sep> <attrval-specs-e> * <ldif-attrval-record-e> | e *

* <ldif-change-record-e> ::= <seps> <dn-spec> <sep> <controls-e> * "changetype:" <fill> <changerecord-type> <ldif-change-record-e> | e *

* <dn-spec> ::= "dn:" <fill> <safe-string> | "dn::" <fill> <base64-string> *

* <controls-e> ::= "control:" <fill> <number> <oid> <spaces-e> <criticality> * <value-spec-e> <sep> <controls-e> | e *

* <criticality> ::= "true" | "false" | e *

* <oid> ::= '.' <number> <oid> | e *

* <attrval-specs-e> ::= <number> <oid> <options-e> <value-spec> <sep> <attrval-specs-e> | * <alpha> <chars-e> <options-e> <value-spec> <sep> <attrval-specs-e> | e *

* <value-spec-e> ::= <value-spec> | e *

* <value-spec> ::= ':' <fill> <safe-string-e> | * "::" <fill> <base64-chars> | * ":<" <fill> <url> *

* <attributeType> ::= <number> <oid> | <alpha> <chars-e> *

* <options-e> ::= ';' <char> <chars-e> <options-e> |e *

* <chars-e> ::= <char> <chars-e> | e *

* <changerecord-type> ::= "add" <sep> <attributeType> <options-e> <value-spec> <sep> <attrval-specs-e> | * "delete" <sep> | * "modify" <sep> <mod-type> <fill> <attributeType> <options-e> <sep> <attrval-specs-e> <sep> '-' <sep> <mod-specs-e> | * "moddn" <sep> <newrdn> <sep> "deleteoldrdn:" <fill> <0-1> <sep> <newsuperior-e> <sep> | * "modrdn" <sep> <newrdn> <sep> "deleteoldrdn:" <fill> <0-1> <sep> <newsuperior-e> <sep> *

* <newrdn> ::= ':' <fill> <safe-string> | "::" <fill> <base64-chars> *

* <newsuperior-e> ::= "newsuperior" <newrdn> | e *

* <mod-specs-e> ::= <mod-type> <fill> <attributeType> <options-e> * <sep> <attrval-specs-e> <sep> '-' <sep> <mod-specs-e> | e *

* <mod-type> ::= "add:" | "delete:" | "replace:" *

* <url> ::= <a Uniform Resource Locator, as defined in [6]> *

*

*

* LEXICAL * ------- *

* <fill> ::= ' ' <fill> | e * <char> ::= <alpha> | <digit> | '-' * <number> ::= <digit> <digits> * <0-1> ::= '0' | '1' * <digits> ::= <digit> <digits> | e * <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' * <seps> ::= <sep> <seps-e> * <seps-e> ::= <sep> <seps-e> | e * <sep> ::= 0x0D 0x0A | 0x0A * <spaces> ::= ' ' <spaces-e> * <spaces-e> ::= ' ' <spaces-e> | e * <safe-string-e> ::= <safe-string> | e * <safe-string> ::= <safe-init-char> <safe-chars> * <safe-init-char> ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] | [0x21-0x39] | 0x3B | [0x3D-0x7F] * <safe-chars> ::= <safe-char> <safe-chars> | e * <safe-char> ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x7F] * <base64-string> ::= <base64-char> <base64-chars> * <base64-chars> ::= <base64-char> <base64-chars> | e * <base64-char> ::= 0x2B | 0x2F | [0x30-0x39] | 0x3D | [0x41-9x5A] | [0x61-0x7A] * <alpha> ::= [0x41-0x5A] | [0x61-0x7A] *

* COMMENTS * -------- * - The ldap-oid VN is not correct in the RFC-2849. It has been changed from 1*DIGIT 0*1("." 1*DIGIT) to * DIGIT+ ("." DIGIT+)* * - The mod-spec lacks a sep between *attrval-spec and "-". * - The BASE64-UTF8-STRING should be BASE64-CHAR BASE64-STRING * - The ValueSpec rule must accept multilines values. In this case, we have a LF followed by a * single space before the continued value. *

*/ public class LdifReader implements Iterator, Iterable { /** * A list of read lines */ private final List lines=new ArrayList(); /** * The ldif file version default value */ private static final int DEFAULT_VERSION = 1; /** * The ldif version */ private int version=DEFAULT_VERSION; /** * Type of element read */ private static final int ENTRY = 0; private static final int CHANGE = 1; private static final int UNKNOWN = 2; /** * Size limit for file contained values */ private final long sizeLimit; /** * The default size limit : 1Mo */ private static final long SIZE_LIMIT_DEFAULT = 1024000; /** * State values for the modify operation */ private static final int MOD_SPEC = 0; private static final int ATTRVAL_SPEC = 1; private static final int ATTRVAL_SPEC_OR_SEP = 2; /** * Iterator prefetched entry */ private Entry prefetched; /** * The ldif LineIterator */ private LineIterator in; /** * A flag set if the ldif contains entries */ private boolean containsEntries; /** * A flag set if the ldif contains changes */ private boolean containsChanges; /** * A constructor which takes a line iterator. * * @param in A Reader containing ldif formated input * @throws LdifParseException If the file cannot be processed or if the format is incorrect */ public LdifReader(LineIterator in) { this(in, SIZE_LIMIT_DEFAULT); } /** * * A constructor which takes a line iterator and a size limit. * * @param in A Reader containing ldif formated input * @param sizeLimit maximum file size that can be accepted for an attribute value */ public LdifReader(LineIterator in, long sizeLimit) { this.in = in; this.sizeLimit = sizeLimit; // First get the version - if any - version = parseVersion(); prefetched = parseEntry(); } /** * For testing purposes. */ public LdifReader(String string) { this(new LineIterator(new StringReader(string))); } /** * @return The ldif file version */ public int getVersion() { return version; } /** * @return The maximum size of a file which is used into an attribute value. */ public long getSizeLimit() { return sizeLimit; } /** * Parse the changeType * * @param line The line which contains the changeType * @return The operation. */ private int parseChangeType(String line) { int operation = Entry.ADD; String modOp = line.substring("changetype:".length() + 1).trim(); if ("add".equalsIgnoreCase(modOp)) { operation = Entry.ADD; } else if ("delete".equalsIgnoreCase(modOp)) { operation = Entry.DELETE; } else if ("modify".equalsIgnoreCase(modOp)) { operation = Entry.MODIFY; } else if ("moddn".equalsIgnoreCase(modOp)) { operation = Entry.MODDN; } else if ("modrdn".equalsIgnoreCase(modOp)) { operation = Entry.MODRDN; } return operation; } /** * Parse the DN of an entry * * @param line The line to parse * @return A DN */ private String parseDn(String line) { String dn = null; String lowerLine = line.toLowerCase(); if (lowerLine.startsWith("dn:") || lowerLine.startsWith("DN:")) { // Ok, we have a DN. Is it base 64 encoded ? int length = line.length(); if (length == 3) { // The DN is empty : error throw new LdifParseException("No DN for entry", line); } else if (line.charAt(3) == ':') { if (length > 4) { // This is a base 64 encoded DN. String trimmedLine = line.substring(4).trim(); try { dn = new String(Utils.base64Decode(trimmedLine.toCharArray()), "UTF-8"); } catch (UnsupportedEncodingException uee) { // The DN is not base 64 encoded throw new LdifParseException("Invalid base 64 encoded DN",line); } } else { // The DN is empty : error throw new LdifParseException("No DN for entry", line); } } else { dn = line.substring(3).trim(); } } else { throw new LdifParseException("No DN for entry", line); } return dn; } /** * Parse the value part. * * @param line The line which contains the value * @param pos The starting position in the line * @return A String or a byte[], depending of the kind of value we get * @throws LdifParseException If something went wrong */ private Object parseValue(String line, int pos) { if (line.length() > pos + 1) { char c = line.charAt(pos + 1); if (c == ':') { String value = line.substring(pos + 2).trim(); return Utils.base64Decode(value.toCharArray()); } else if (c == '<') { String urlName = line.substring(pos + 2).trim(); try { return Utils.toByteArray(getUriStream(urlName), sizeLimit); } catch (IOException e) { throw new LdifParseException("Failed to read \""+urlName+"\" file content",line,e); } } else { return line.substring(pos + 1).trim(); } } else { return null; } } /** * Resolves URI to URL and returns a content stream. * This method just creates a new URL, subclasses may chnange this behaviour. * @param uri URI to resolve. * @return resolved URL content stream. * @throws IOException if an I/O error occurs or URI is malformed. */ protected InputStream getUriStream(String uri) throws IOException { return new URL(uri).openStream(); } /** * Parse a control. The grammar is : ::= "control:" * ::= * | e ::= "true" | "false" ::= * | e ::= ":" | "::" * | ":<" *

* It can be read as : "control:" [ " "+ ( "true" | * "false") ] [ ":" | "::" | ":<" * ] * * @param line The line containing the control * @return A control */ private Control parseControl(String line) { String lowerLine = line.toLowerCase().trim(); char[] controlValue = line.trim().toCharArray(); int pos = 0; int length = controlValue.length; // Get the if (pos > length) { // No OID : error ! throw new LdifParseException("Bad control, no oid", line); } int initPos = pos; while (Utils.isCharASCII(controlValue, pos, '.') || Utils.isDigit(controlValue, pos)) { pos++; } if (pos == initPos) { // Not a valid OID ! throw new LdifParseException("Bad control, no oid", line); } String oid = lowerLine.substring(0, pos); boolean criticality=false; byte[] controlBytes = null; // Get the criticality, if any // Skip the while (Utils.isCharASCII(controlValue, pos, ' ')) { pos++; } // Check if we have a "true" or a "false" int criticalPos = lowerLine.indexOf(':'); int criticalLength = 0; if (criticalPos == -1) { criticalLength = length - pos; } else { criticalLength = criticalPos - pos; } if ((criticalLength == 4) && ("true".equalsIgnoreCase(lowerLine.substring(pos, pos + 4)))) { criticality=true; } else if ((criticalLength == 5) && ("false".equalsIgnoreCase(lowerLine.substring(pos, pos + 5)))) { criticality=false; } else if (criticalLength != 0) { // If we have a criticality, it should be either "true" or "false", // nothing else throw new LdifParseException("Bad control criticality", line); } if (criticalPos > 0) { // We have a value. It can be a normal value, a base64 encoded value // or a file contained value if (Utils.isCharASCII(controlValue, criticalPos + 1, ':')) { // Base 64 encoded value controlBytes = Utils.base64Decode(line.substring(criticalPos + 2).toCharArray()); } else if (Utils.isCharASCII(controlValue, criticalPos + 1, '<')) { // File contained value } else { // Standard value byte[] value = new byte[length - criticalPos - 1]; for (int i = 0; i < length - criticalPos - 1; i++) { value[i] = (byte) controlValue[i + criticalPos + 1]; } controlBytes=value; } } return new BasicControl(oid, criticality, controlBytes); } /** * Parse an AttributeType/AttributeValue * * @param entry The entry where to store the value * @param line The line to parse */ public void parseAttributeValue(Entry entry, String line) { int colonIndex = line.indexOf(':'); String attributeType = line.substring(0, colonIndex); // We should *not* have a DN twice if (attributeType.equalsIgnoreCase("dn")) { throw new LdifParseException("A ldif entry should not have two DN", line); } Object attributeValue = parseValue(line, colonIndex); // Update the entry entry.addAttribute(attributeType, attributeValue); } /** * Parse a ModRDN operation * * @param entry The entry to update * @param iter The lines iterator */ private void parseModRdn(Entry entry, Iterator iter) { // We must have two lines : one starting with "newrdn:" or "newrdn::", // and the second starting with "deleteoldrdn:" if (iter.hasNext()) { String line = (String) iter.next(); String lowerLine = line.toLowerCase(); if (lowerLine.startsWith("newrdn::") || lowerLine.startsWith("newrdn:")) { int colonIndex = line.indexOf(':'); Object attributeValue = parseValue(line, colonIndex); entry.setNewRdn(attributeValue instanceof String ? (String) attributeValue : Utils .utf8ToString((byte[]) attributeValue)); } else { throw new LdifParseException("Bad modrdn operation", line); } } else { throw new LdifParseException("Bad modrdn operation, no newrdn"); } if (iter.hasNext()) { String line = (String) iter.next(); String lowerLine = line.toLowerCase(); if (lowerLine.startsWith("deleteoldrdn:")) { int colonIndex = line.indexOf(':'); Object attributeValue = parseValue(line, colonIndex); entry.setDeleteOldRdn("1".equals(attributeValue)); } else { throw new LdifParseException("Bad modrdn operation, no deleteoldrdn", line); } } else { throw new LdifParseException("Bad modrdn operation, no deleteoldrdn"); } } /** * Parse a modify change type. *

* The grammar is : ::= "changetype:" FILL "modify" SEP * ::= "add:" | "delete:" * | "replace:" ::= * | e ::= FILL ATTRIBUTE-DESCRIPTION SEP * ATTRVAL-SPEC "-" SEP ::= FILL * ATTRIBUTE-DESCRIPTION SEP "-" SEP ::= * ATTRVAL-SPEC | e * * * @param entry The entry to feed * @param iter The lines */ private void parseModify(Entry entry, Iterator iter) { int state = MOD_SPEC; String modified = null; int modification = 0; // The following flag is used to deal with empty modifications boolean isEmptyValue = true; while (iter.hasNext()) { String line = (String) iter.next(); String lowerLine = line.toLowerCase(); if (lowerLine.startsWith("-")) { if (state != ATTRVAL_SPEC_OR_SEP) { throw new LdifParseException("Bad modify separator", line); } else { if (isEmptyValue) { // Update the entry entry.addModificationItem(modification, modified, null); } state = MOD_SPEC; isEmptyValue = true; continue; } } else if (lowerLine.startsWith("add:")) { if ((state != MOD_SPEC) && (state != ATTRVAL_SPEC)) { throw new LdifParseException("Bad modify state", line); } modified = line.substring("add:".length()).trim(); modification = DirContext.ADD_ATTRIBUTE; state = ATTRVAL_SPEC; } else if (lowerLine.startsWith("delete:")) { if ((state != MOD_SPEC) && (state != ATTRVAL_SPEC)) { throw new LdifParseException("Bad modify state", line); } modified = line.substring("delete:".length()).trim(); modification = DirContext.REMOVE_ATTRIBUTE; state = ATTRVAL_SPEC_OR_SEP; } else if (lowerLine.startsWith("replace:")) { if ((state != MOD_SPEC) && (state != ATTRVAL_SPEC)) { throw new LdifParseException("Bad modify state", line); } modified = line.substring("replace:".length()).trim(); modification = DirContext.REPLACE_ATTRIBUTE; state = ATTRVAL_SPEC_OR_SEP; } else { if ((state != ATTRVAL_SPEC) && (state != ATTRVAL_SPEC_OR_SEP)) { throw new LdifParseException("Bad modify state", line); } // A standard AttributeType/AttributeValue pair int colonIndex = line.indexOf(':'); String attributeType = line.substring(0, colonIndex); if (!attributeType.equals(modified)) { throw new LdifParseException("Bad modify attribute", line); } // We should *not* have a DN twice if (attributeType.equals("dn")) { throw new LdifParseException("A ldif entry should not have two DN", line); } Object attributeValue = parseValue(line, colonIndex); // Update the entry entry.addModificationItem(modification, attributeType, attributeValue); isEmptyValue = false; state = ATTRVAL_SPEC_OR_SEP; } } } /** * Parse a change operation. We have to handle different cases depending on * the operation. 1) Delete : there should *not* be any line after the * "changetype: delete" 2) Add : we must have a list of AttributeType : * AttributeValue elements 3) ModDN : we must have two following lines: a * "newrdn:" and a "deleteoldrdn:" 4) ModRDN : the very same, but a * "newsuperior:" line is expected 5) Modify : *

* The grammar is : ::= "changetype:" FILL "add" SEP * | "changetype:" FILL "delete" | * "changetype:" FILL "modrdn" SEP SEP SEP | // To * be checked "changetype:" FILL "moddn" SEP SEP SEP * SEP | "changetype:" FILL "modify" SEP * ::= "newrdn:" FILL RDN | "newrdn::" FILL * BASE64-RDN ::= "deleteoldrdn:" FILL "0" | "deleteoldrdn:" * FILL "1" ::= "newsuperior:" FILL DN | "newsuperior::" FILL * BASE64-DN ::= | e ::= * "add:" | "delete:" | "replace:" * ::= FILL ATTRIBUTE-DESCRIPTION SEP ATTRVAL-SPEC "-" SEP * ::= ATTRVAL-SPEC | e * * @param entry The entry to feed * @param iter The lines iterator * @param operation The change operation (add, modify, delete, moddn or modrdn) * @param control The associated control, if any */ private void parseChange(Entry entry, Iterator iter, int operation, Control control) { // The changetype and operation has already been parsed. entry.setChangeType(operation); switch (operation) { case Entry.DELETE: // The change type will tell that it's a delete operation, // the dn is used as a key. return; case Entry.ADD: // We will iterate through all attribute/value pairs while (iter.hasNext()) { String line = (String) iter.next(); parseAttributeValue(entry, line); } return; case Entry.MODIFY: parseModify(entry, iter); return; case Entry.MODRDN:// They are supposed to have the same syntax ??? case Entry.MODDN: // First, parse the modrdn part parseModRdn(entry, iter); // The next line should be the new superior if (iter.hasNext()) { String line = (String) iter.next(); String lowerLine = line.toLowerCase(); if (lowerLine.startsWith("newsuperior:")) { int colonIndex = line.indexOf(':'); Object attributeValue = parseValue(line, colonIndex); entry.setNewSuperior(attributeValue instanceof String ? (String) attributeValue : Utils .utf8ToString((byte[]) attributeValue)); } else { if (operation == Entry.MODDN) { throw new LdifParseException("Bad moddn operation, no newsuperior", line); } } } else { if (operation == Entry.MODDN) { throw new LdifParseException("Bad moddn operation, no newsuperior"); } } return; default: // This is an error throw new LdifParseException("Bad operation"); } } /** * Parse a ldif file. The following rules are processed : *

* ::= | * ::= * ::= * ::= "dn:" * | "dn::" * ::= "changetype:" */ private Entry parseEntry() { if ((lines == null) || (lines.size() == 0)) { return null; } // The entry must start with a dn: or a dn:: String line = lines.get(0); String dn = parseDn(line); // Ok, we have found a DN Entry entry = new Entry(); entry.setDn(dn); // We remove this dn from the lines lines.remove(0); // Now, let's iterate through the other lines Iterator iter = lines.iterator(); // This flag is used to distinguish between an entry and a change int type = UNKNOWN; // The following boolean is used to check that a control is *not* // found elswhere than just after the dn boolean controlSeen = false; // We use this boolean to check that we do not have AttributeValues // after a change operation boolean changeTypeSeen = false; int operation = Entry.ADD; String lowerLine = null; Control control = null; while (iter.hasNext()) { // Each line could start either with an OID, an attribute type, with // "control:" or with "changetype:" line = (String) iter.next(); lowerLine = line.toLowerCase(); // We have three cases : // 1) The first line after the DN is a "control:" // 2) The first line after the DN is a "changeType:" // 3) The first line after the DN is anything else if (lowerLine.startsWith("control:")) { if (containsEntries) { throw new LdifParseException("No changes withing entries", line); } containsChanges = true; if (controlSeen) { throw new LdifParseException("Control misplaced", line); } // Parse the control control = parseControl(line.substring("control:".length())); entry.setControl(control); } else if (lowerLine.startsWith("changetype:")) { if (containsEntries) { throw new LdifParseException("No changes withing entries", line); } containsChanges = true; if (changeTypeSeen) { throw new LdifParseException("ChangeType misplaced", line); } // A change request type = CHANGE; controlSeen = true; operation = parseChangeType(line); // Parse the change operation in a separate function parseChange(entry, iter, operation, control); changeTypeSeen = true; } else if (line.indexOf(':') > 0) { if (containsChanges) { throw new LdifParseException("No entries within changes", line); } containsEntries = true; if (controlSeen || changeTypeSeen) { throw new LdifParseException("AttributeType misplaced", line); } parseAttributeValue(entry, line); type = ENTRY; } else { // Invalid attribute Value throw new LdifParseException("Bad attribute", line); } } if (type == CHANGE) { entry.setChangeType(operation); } return entry; } /** * "version:" */ static final Pattern VERSION_PATTERN = Pattern.compile("[ ]*version\\:[ ]*(\\d+)[ ]*"); /** * "version:" * */ static final Pattern VERSION_PATTERN_LINE1 = Pattern.compile("[ ]*version\\:[ ]*"); static final Pattern VERSION_PATTERN_LINE2 = Pattern.compile("[ ]\\d+"); /** * Parse the version from the ldif input. * * @return A number representing the version (default to 1) */ private int parseVersion() { // First, read a list of lines readLines(); if (lines.size() == 0) { return DEFAULT_VERSION; } // get the first line String line = lines.get(0); Matcher versionMatcher = VERSION_PATTERN.matcher(line); String versionStr = null; if (versionMatcher.matches()) { versionStr=versionMatcher.group(1); // We have found the version, just discard the line from the list lines.remove(0); } else { versionMatcher = VERSION_PATTERN_LINE1.matcher(line); if (versionMatcher.matches()) { lines.remove(0); if (!lines.isEmpty()) { versionMatcher = VERSION_PATTERN_LINE2.matcher(lines.get(1)); if (versionMatcher.matches()) { versionStr=versionMatcher.group(1); } lines.remove(0); } } } if (versionStr!=null) { try { return Integer.parseInt(versionStr.trim()); } catch (NumberFormatException e) { throw new LdifParseException("Invalid LDIF version number "+versionStr, line); } } else { return DEFAULT_VERSION; } } /** * Reads an entry in a ldif buffer, and returns the resulting lines, without * comments, and unfolded. *

* The lines represent *one* entry. * */ private void readLines() { String line; boolean insideComment = true; boolean isFirstLine = true; lines.clear(); StringBuilder sb = new StringBuilder(128); while (in.hasNext()) { //while not EOF line = in.next(); if (StringUtils.isAsciiWhitespacesOnly(line)) { //if line is empty if (isFirstLine) { continue; } else { // The line is empty, we have read an entry insideComment = false; if (lines.isEmpty()) { //if block is empty, i.e. comments section - read the next entry continue; } else { //otherwise stop break; } } } isFirstLine = false; // We will read the first line which is not a comment switch (line.charAt(0)) { case '#': insideComment = true; break; case ' ': if (insideComment) { continue; } else if (sb.length() == 0) { throw new LdifParseException("Ldif Parsing error: Cannot have an empty continuation line"); } else { sb.append(line.substring(1)); } insideComment = false; break; default: // We have found a new entry // First, stores the previous one if any. if (sb.length() != 0) { lines.add(sb.toString()); } sb = new StringBuilder(line); insideComment = false; break; } } // Stores the current line if necessary. if (sb.length() != 0) { lines.add(sb.toString()); } } // ------------------------------------------------------------------------ // Iterator Methods // ------------------------------------------------------------------------ /** * Gets the next LDIF on the channel. * * @return the next LDIF as a String. */ public Entry next() { if (!hasNext()) { throw new NoSuchElementException("No LDIF entries to read. Use hasNext()."); } Entry res = prefetched; prefetched=null; return res; } /** * Tests to see if another LDIF is on the input channel. * * @return true if another LDIF is available false otherwise. */ public boolean hasNext() { if (prefetched==null) { readLines(); prefetched = parseEntry(); } return null != prefetched; } /** * Always throws UnsupportedOperationException! * * @see java.util.Iterator#remove() */ public void remove() { throw new UnsupportedOperationException(); } /** * @return An iterator on the file */ public Iterator iterator() { return this; } /** * Just a helper method */ List asList() { // Create a list that will contain the read entries List entries = new ArrayList(); // When done, get the entries one by one. while (hasNext()) { Entry entry = next(); entries.add(entry); } return entries; } /** * @return True if the ldif file contains entries, fals if it contains * changes */ public boolean containsEntries() { return containsEntries; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy