001    /*
002     * Copyright 2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2016 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.util;
022    
023    
024    
025    import java.io.BufferedReader;
026    import java.io.Closeable;
027    import java.io.File;
028    import java.io.FileReader;
029    import java.io.IOException;
030    import java.util.concurrent.atomic.AtomicLong;
031    
032    import com.unboundid.ldap.sdk.Filter;
033    import com.unboundid.ldap.sdk.LDAPException;
034    import com.unboundid.ldap.sdk.ResultCode;
035    
036    import static com.unboundid.util.UtilityMessages.*;
037    
038    
039    
040    /**
041     * This class provides a mechanism for reading LDAP search filters from a file.
042     * The file is expected to have one filter per line.  Blank lines and lines
043     * beginning with the octothorpe (#) character will be ignored.
044     */
045    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
046    public final class FilterFileReader
047           implements Closeable
048    {
049      // A counter used to keep track of the line number for information read from
050      // the file.
051      private final AtomicLong lineNumberCounter;
052    
053      // The reader to use to read the filters.
054      private final BufferedReader reader;
055    
056      // The file from which the filters are being read.
057      private final File filterFile;
058    
059    
060    
061      /**
062       * Creates a new filter file reader that will read from the file with the
063       * specified path.
064       *
065       * @param  path  The path to the file to be read.  It must not be {@code null}
066       *               and the file must exist.
067       *
068       * @throws  IOException  If a problem is encountered while opening the file
069       *                       for reading.
070       */
071      public FilterFileReader(final String path)
072             throws IOException
073      {
074        this(new File(path));
075      }
076    
077    
078    
079      /**
080       * Creates a new filter file reader that will read from the specified file.
081       *
082       * @param  filterFile  The file to be read.  It must not be {@code null} and
083       *                     the file must exist.
084       *
085       * @throws  IOException  If a problem is encountered while opening the file
086       *                       for reading.
087       */
088      public FilterFileReader(final File filterFile)
089             throws IOException
090      {
091        this.filterFile = filterFile;
092    
093        reader = new BufferedReader(new FileReader(filterFile));
094        lineNumberCounter = new AtomicLong(0L);
095      }
096    
097    
098    
099      /**
100       * Reads the next filter from the file.
101       *
102       * @return  The filter read from the file, or {@code null} if there are no
103       *          more filters to be read.
104       *
105       * @throws  IOException  If a problem is encountered while trying to read from
106       *                       the file.
107       *
108       * @throws  LDAPException  If data read from the file can't be parsed as an
109       *                         LDAP search filter.
110       */
111      public Filter readFilter()
112             throws IOException, LDAPException
113      {
114        while (true)
115        {
116          final long lineNumber;
117          final String line;
118          synchronized (this)
119          {
120            line = reader.readLine();
121            lineNumber = lineNumberCounter.incrementAndGet();
122          }
123    
124          if (line == null)
125          {
126            return null;
127          }
128    
129          final String filterString = line.trim();
130          if ((filterString.length() == 0) || filterString.startsWith("#"))
131          {
132            continue;
133          }
134    
135          try
136          {
137            return Filter.create(filterString);
138          }
139          catch (final LDAPException le)
140          {
141            Debug.debugException(le);
142            throw new LDAPException(ResultCode.FILTER_ERROR,
143                 ERR_FILTER_FILE_READER_CANNOT_PARSE_FILTER.get(filterString,
144                      lineNumber, filterFile.getAbsolutePath(), le.getMessage()),
145                 le);
146          }
147        }
148      }
149    
150    
151    
152      /**
153       * Closes this filter file reader.
154       *
155       * @throws  IOException  If a problem is encountered while closing the reader.
156       */
157      public void close()
158             throws IOException
159      {
160        reader.close();
161      }
162    }