001/*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019 */
020package org.sonar.channel;
021
022import java.io.IOException;
023import java.io.Reader;
024
025/**
026 * This class is a special CodeReaderFilter that uses Channels to filter the character stream before it is passed to the main channels
027 * declared for the CodeReader.
028 * 
029 */
030public final class ChannelCodeReaderFilter<OUTPUT> extends CodeReaderFilter<OUTPUT> {
031
032  @SuppressWarnings("unchecked")
033  private Channel<OUTPUT>[] channels = new Channel[0];
034
035  private CodeReader internalCodeReader;
036
037  /**
038   * Creates a CodeReaderFilter that will use the provided Channels to filter the character stream it gets from its reader.
039   * 
040   * @param channels
041   *          the different channels
042   */
043  public ChannelCodeReaderFilter(Channel<OUTPUT>... channels) {
044    super();
045    this.channels = channels;
046  }
047
048  /**
049   * Creates a CodeReaderFilter that will use the provided Channels to filter the character stream it gets from its reader. And optionally,
050   * it can push token to the provided output object.
051   * 
052   * @param output
053   *          the object that may accept tokens
054   * @param channels
055   *          the different channels
056   */
057  public ChannelCodeReaderFilter(OUTPUT output, Channel<OUTPUT>... channels) {
058    super(output);
059    this.channels = channels;
060  }
061
062  /**
063   * {@inheritDoc}
064   */
065  @Override
066  public void setReader(Reader reader) {
067    super.setReader(reader);
068    internalCodeReader = new CodeReader(reader, getConfiguration());
069  }
070
071  /**
072   * {@inheritDoc}
073   */
074  @Override
075  public int read(char[] filteredBuffer, int offset, int length) throws IOException {
076    if (internalCodeReader.peek() == -1) {
077      return -1;
078    }
079    int initialOffset = offset;
080    while (offset < filteredBuffer.length) {
081      if (internalCodeReader.peek() == -1) {
082        break;
083      }
084      boolean consumed = false;
085      for (Channel<OUTPUT> channel : channels) {
086        if (channel.consume(internalCodeReader, getOutput())) {
087          consumed = true;
088          break;
089        }
090      }
091      if ( !consumed) {
092        int charRead = internalCodeReader.pop();
093        filteredBuffer[offset++] = (char) charRead;
094      }
095    }
096    return offset - initialOffset;
097  }
098
099}