ProxyReader.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.io.input;

  18. import static org.apache.commons.io.IOUtils.EOF;

  19. import java.io.FilterReader;
  20. import java.io.IOException;
  21. import java.io.Reader;
  22. import java.nio.CharBuffer;

  23. import org.apache.commons.io.IOUtils;

  24. /**
  25.  * A Proxy stream which acts as expected, that is it passes the method
  26.  * calls on to the proxied stream and doesn't change which methods are
  27.  * being called.
  28.  * <p>
  29.  * It is an alternative base class to FilterReader
  30.  * to increase reusability, because FilterReader changes the
  31.  * methods being called, such as read(char[]) to read(char[], int, int).
  32.  * </p>
  33.  */
  34. public abstract class ProxyReader extends FilterReader {

  35.     /**
  36.      * Constructs a new ProxyReader.
  37.      *
  38.      * @param delegate  the Reader to delegate to
  39.      */
  40.     public ProxyReader(final Reader delegate) {
  41.         // the delegate is stored in a protected superclass variable named 'in'
  42.         super(delegate);
  43.     }

  44.     /**
  45.      * Invoked by the read methods after the proxied call has returned
  46.      * successfully. The number of chars returned to the caller (or -1 if
  47.      * the end of stream was reached) is given as an argument.
  48.      * <p>
  49.      * Subclasses can override this method to add common post-processing
  50.      * functionality without having to override all the read methods.
  51.      * The default implementation does nothing.
  52.      * <p>
  53.      * Note this method is <em>not</em> called from {@link #skip(long)} or
  54.      * {@link #reset()}. You need to explicitly override those methods if
  55.      * you want to add post-processing steps also to them.
  56.      *
  57.      * @param n number of chars read, or -1 if the end of stream was reached
  58.      * @throws IOException if the post-processing fails
  59.      * @since 2.0
  60.      */
  61.     @SuppressWarnings("unused") // Possibly thrown from subclasses.
  62.     protected void afterRead(final int n) throws IOException {
  63.         // noop
  64.     }

  65.     /**
  66.      * Invoked by the read methods before the call is proxied. The number
  67.      * of chars that the caller wanted to read (1 for the {@link #read()}
  68.      * method, buffer length for {@link #read(char[])}, etc.) is given as
  69.      * an argument.
  70.      * <p>
  71.      * Subclasses can override this method to add common pre-processing
  72.      * functionality without having to override all the read methods.
  73.      * The default implementation does nothing.
  74.      * <p>
  75.      * Note this method is <em>not</em> called from {@link #skip(long)} or
  76.      * {@link #reset()}. You need to explicitly override those methods if
  77.      * you want to add pre-processing steps also to them.
  78.      *
  79.      * @param n number of chars that the caller asked to be read
  80.      * @throws IOException if the pre-processing fails
  81.      * @since 2.0
  82.      */
  83.     @SuppressWarnings("unused") // Possibly thrown from subclasses.
  84.     protected void beforeRead(final int n) throws IOException {
  85.         // noop
  86.     }

  87.     /**
  88.      * Invokes the delegate's {@code close()} method.
  89.      * @throws IOException if an I/O error occurs.
  90.      */
  91.     @Override
  92.     public void close() throws IOException {
  93.         try {
  94.             in.close();
  95.         } catch (final IOException e) {
  96.             handleIOException(e);
  97.         }
  98.     }

  99.     /**
  100.      * Handle any IOExceptions thrown.
  101.      * <p>
  102.      * This method provides a point to implement custom exception
  103.      * handling. The default behavior is to re-throw the exception.
  104.      * @param e The IOException thrown
  105.      * @throws IOException if an I/O error occurs.
  106.      * @since 2.0
  107.      */
  108.     protected void handleIOException(final IOException e) throws IOException {
  109.         throw e;
  110.     }

  111.     /**
  112.      * Invokes the delegate's {@code mark(int)} method.
  113.      * @param idx read ahead limit
  114.      * @throws IOException if an I/O error occurs.
  115.      */
  116.     @Override
  117.     public synchronized void mark(final int idx) throws IOException {
  118.         try {
  119.             in.mark(idx);
  120.         } catch (final IOException e) {
  121.             handleIOException(e);
  122.         }
  123.     }

  124.     /**
  125.      * Invokes the delegate's {@code markSupported()} method.
  126.      * @return true if mark is supported, otherwise false
  127.      */
  128.     @Override
  129.     public boolean markSupported() {
  130.         return in.markSupported();
  131.     }

  132.     /**
  133.      * Invokes the delegate's {@code read()} method.
  134.      * @return the character read or -1 if the end of stream
  135.      * @throws IOException if an I/O error occurs.
  136.      */
  137.     @Override
  138.     public int read() throws IOException {
  139.         try {
  140.             beforeRead(1);
  141.             final int c = in.read();
  142.             afterRead(c != EOF ? 1 : EOF);
  143.             return c;
  144.         } catch (final IOException e) {
  145.             handleIOException(e);
  146.             return EOF;
  147.         }
  148.     }

  149.     /**
  150.      * Invokes the delegate's {@code read(char[])} method.
  151.      * @param chr the buffer to read the characters into
  152.      * @return the number of characters read or -1 if the end of stream
  153.      * @throws IOException if an I/O error occurs.
  154.      */
  155.     @Override
  156.     public int read(final char[] chr) throws IOException {
  157.         try {
  158.             beforeRead(IOUtils.length(chr));
  159.             final int n = in.read(chr);
  160.             afterRead(n);
  161.             return n;
  162.         } catch (final IOException e) {
  163.             handleIOException(e);
  164.             return EOF;
  165.         }
  166.     }

  167.     /**
  168.      * Invokes the delegate's {@code read(char[], int, int)} method.
  169.      * @param chr the buffer to read the characters into
  170.      * @param st The start offset
  171.      * @param len The number of bytes to read
  172.      * @return the number of characters read or -1 if the end of stream
  173.      * @throws IOException if an I/O error occurs.
  174.      */
  175.     @Override
  176.     public int read(final char[] chr, final int st, final int len) throws IOException {
  177.         try {
  178.             beforeRead(len);
  179.             final int n = in.read(chr, st, len);
  180.             afterRead(n);
  181.             return n;
  182.         } catch (final IOException e) {
  183.             handleIOException(e);
  184.             return EOF;
  185.         }
  186.     }

  187.     /**
  188.      * Invokes the delegate's {@code read(CharBuffer)} method.
  189.      * @param target the char buffer to read the characters into
  190.      * @return the number of characters read or -1 if the end of stream
  191.      * @throws IOException if an I/O error occurs.
  192.      * @since 2.0
  193.      */
  194.     @Override
  195.     public int read(final CharBuffer target) throws IOException {
  196.         try {
  197.             beforeRead(IOUtils.length(target));
  198.             final int n = in.read(target);
  199.             afterRead(n);
  200.             return n;
  201.         } catch (final IOException e) {
  202.             handleIOException(e);
  203.             return EOF;
  204.         }
  205.     }

  206.     /**
  207.      * Invokes the delegate's {@code ready()} method.
  208.      * @return true if the stream is ready to be read
  209.      * @throws IOException if an I/O error occurs.
  210.      */
  211.     @Override
  212.     public boolean ready() throws IOException {
  213.         try {
  214.             return in.ready();
  215.         } catch (final IOException e) {
  216.             handleIOException(e);
  217.             return false;
  218.         }
  219.     }

  220.     /**
  221.      * Invokes the delegate's {@code reset()} method.
  222.      * @throws IOException if an I/O error occurs.
  223.      */
  224.     @Override
  225.     public synchronized void reset() throws IOException {
  226.         try {
  227.             in.reset();
  228.         } catch (final IOException e) {
  229.             handleIOException(e);
  230.         }
  231.     }

  232.     /**
  233.      * Invokes the delegate's {@code skip(long)} method.
  234.      * @param ln the number of bytes to skip
  235.      * @return the number of bytes to skipped or EOF if the end of stream
  236.      * @throws IOException if an I/O error occurs.
  237.      */
  238.     @Override
  239.     public long skip(final long ln) throws IOException {
  240.         try {
  241.             return in.skip(ln);
  242.         } catch (final IOException e) {
  243.             handleIOException(e);
  244.             return 0;
  245.         }
  246.     }

  247. }