]> source.dussan.org Git - sonarqube.git/commitdiff
[SONAR-1875] Improve CodeReaderFilter with channel capabilities
authorbellingard <bellingard@gmail.com>
Mon, 18 Oct 2010 15:25:51 +0000 (15:25 +0000)
committerbellingard <bellingard@gmail.com>
Mon, 18 Oct 2010 15:25:51 +0000 (15:25 +0000)
http://jira.codehaus.org/browse/SONAR-1875

sonar-channel/src/main/java/org/sonar/channel/ChannelCodeReaderFilter.java [new file with mode: 0644]
sonar-channel/src/main/java/org/sonar/channel/CodeBuffer.java
sonar-channel/src/main/java/org/sonar/channel/CodeReaderFilter.java
sonar-channel/src/test/java/org/sonar/channel/CodeBufferTest.java

diff --git a/sonar-channel/src/main/java/org/sonar/channel/ChannelCodeReaderFilter.java b/sonar-channel/src/main/java/org/sonar/channel/ChannelCodeReaderFilter.java
new file mode 100644 (file)
index 0000000..0834a52
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.channel;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * This class is a special CodeReaderFilter that uses Channels to filter the character stream before it is passed to the main channels
+ * declared for the CodeReader.
+ * 
+ */
+public final class ChannelCodeReaderFilter<OUTPUT> extends CodeReaderFilter {
+
+  @SuppressWarnings("unchecked")
+  private Channel<OUTPUT>[] channels = new Channel[0];
+
+  private CodeReader internalCodeReader;
+
+  private OUTPUT output;
+
+  /**
+   * Creates a CodeReaderFilter that will use the provided Channels to filter the character stream it gets from its reader. And optionaly,
+   * it can push token to the provided output object.
+   * 
+   * @param output
+   *          the object that may accept tokens
+   * @param channels
+   *          the different channels
+   */
+  public ChannelCodeReaderFilter(OUTPUT output, Channel<OUTPUT>... channels) {
+    super();
+    this.channels = channels;
+    this.output = output;
+  }
+
+  /**
+   * ${@inheritDoc}
+   */
+  @Override
+  public void setReader(Reader reader) {
+    super.setReader(reader);
+    internalCodeReader = new CodeReader(reader);
+  }
+
+  /**
+   * ${@inheritDoc}
+   */
+  @Override
+  public int read(char[] filteredBuffer, int offset, int lenght) throws IOException {
+    int initialOffset = offset;
+    while (offset < filteredBuffer.length) {
+      if (internalCodeReader.peek() == -1) {
+        break;
+      }
+      boolean consumed = false;
+      for (Channel<OUTPUT> channel : channels) {
+        if (channel.consume(internalCodeReader, output)) {
+          consumed = true;
+          break;
+        }
+      }
+      if ( !consumed) {
+        int charRead = internalCodeReader.pop();
+        filteredBuffer[offset++] = (char) charRead;
+      }
+    }
+    return offset - initialOffset;
+  }
+
+}
index b4288bad3ceeab84b00b3d093fef5e38c94321e7..fcddb8d827fab4ea0e467f144d3ac69f5ab14f2e 100644 (file)
@@ -253,6 +253,9 @@ public class CodeBuffer implements CharSequence {
     }
   }
 
+  /**
+   * Bridge class between CodeBuffer and CodeReaderFilter
+   */
   final class Filter extends FilterReader {
 
     private CodeReaderFilter codeReaderFilter;
@@ -260,6 +263,7 @@ public class CodeBuffer implements CharSequence {
     public Filter(Reader in, CodeReaderFilter codeReaderFilter) {
       super(in);
       this.codeReaderFilter = codeReaderFilter;
+      this.codeReaderFilter.setReader(in);
     }
 
     @Override
@@ -269,7 +273,7 @@ public class CodeBuffer implements CharSequence {
 
     @Override
     public int read(char[] cbuf, int off, int len) throws IOException {
-      return codeReaderFilter.read(in, cbuf, off, len);
+      return codeReaderFilter.read(cbuf, off, len);
     }
 
     @Override
index 4c63bcd9f9099f6e1390c1c70ef851ea0f6dacdc..da5a1dcb4f3b2144971f87877e29024a9d8843c5 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
 package org.sonar.channel;
 
 import java.io.IOException;
@@ -16,6 +35,27 @@ import java.io.Reader;
  */
 public abstract class CodeReaderFilter {
 
+  private Reader reader;
+
+  /**
+   * Returns the reader from which this class reads the character stream.
+   * 
+   * @return the reader
+   */
+  public Reader getReader() {
+    return reader;
+  }
+
+  /**
+   * Sets the reader from which this class will read the character stream.
+   * 
+   * @param reader
+   *          the reader
+   */
+  public void setReader(Reader reader) {
+    this.reader = reader;
+  }
+
   /**
    * This method implements the filtering logic, that is:
    * <ul>
@@ -27,8 +67,6 @@ public abstract class CodeReaderFilter {
    * and fill the given buffer to its full capacity with the filtered data.</li>
    * </ul>
    * 
-   * @param reader
-   *          the input character flow
    * @param filteredBuffer
    *          the output buffer that must contain the filtered data
    * @param offset
@@ -39,6 +77,6 @@ public abstract class CodeReaderFilter {
    * @throws IOException
    *           If an I/O error occurs
    */
-  public abstract int read(Reader reader, char[] filteredBuffer, int offset, int lenght) throws IOException;
+  public abstract int read(char[] filteredBuffer, int offset, int lenght) throws IOException;
 
 }
index 05ac7704804d5c81a202e3b2d94260c3161c0b8f..3807951eee0809ae290127fe251227026ae1a2e0 100644 (file)
@@ -24,7 +24,6 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 
 import java.io.IOException;
-import java.io.Reader;
 import java.util.regex.Pattern;
 
 import org.junit.Test;
@@ -175,14 +174,45 @@ public class CodeBufferTest {
     assertThat((char) code.pop(), is('-'));
   }
 
+  @Test
+  public void testChannelCodeReaderFilter() throws Exception {
+    // create a windowing channel that drops the 2 first characters, keeps 6 characters and drops the rest of the line
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    CodeBuffer code = new CodeBuffer("0123456789\nABCDEFGHIJ", new ChannelCodeReaderFilter(null, new WindowingChannel()));
+    // test #charAt
+    assertEquals('2', code.charAt(0));
+    assertEquals('7', code.charAt(5));
+    assertEquals('\n', code.charAt(6));
+    assertEquals('C', code.charAt(7));
+    assertEquals('H', code.charAt(12));
+    assertEquals( -1, code.intAt(13));
+    // test peek and pop
+    assertThat((char) code.peek(), is('2'));
+    assertThat((char) code.pop(), is('2'));
+    assertThat((char) code.pop(), is('3'));
+    assertThat((char) code.pop(), is('4'));
+    assertThat((char) code.pop(), is('5'));
+    assertThat((char) code.pop(), is('6'));
+    assertThat((char) code.pop(), is('7'));// and 8 shouldn't show up
+    assertThat((char) code.pop(), is('\n'));
+    assertThat((char) code.peek(), is('C'));
+    assertThat((char) code.pop(), is('C'));
+    assertThat((char) code.pop(), is('D'));
+    assertThat((char) code.pop(), is('E'));
+    assertThat((char) code.pop(), is('F'));
+    assertThat((char) code.pop(), is('G'));
+    assertThat((char) code.pop(), is('H'));
+    assertThat(code.pop(), is( -1));
+  }
+
   class ReplaceNumbersFilter extends CodeReaderFilter {
 
     private Pattern pattern = Pattern.compile("\\d");
     private String REPLACEMENT = "-";
 
-    public int read(Reader in, char[] cbuf, int off, int len) throws IOException {
+    public int read(char[] cbuf, int off, int len) throws IOException {
       char[] tempBuffer = new char[cbuf.length];
-      int charCount = in.read(tempBuffer, off, len);
+      int charCount = getReader().read(tempBuffer, off, len);
       if (charCount != -1) {
         String filteredString = pattern.matcher(new String(tempBuffer)).replaceAll(REPLACEMENT);
         System.arraycopy(filteredString.toCharArray(), 0, cbuf, 0, tempBuffer.length);
@@ -196,9 +226,9 @@ public class CodeBufferTest {
     private Pattern pattern = Pattern.compile("[a-zA-Z]");
     private String REPLACEMENT = "*";
 
-    public int read(Reader in, char[] cbuf, int off, int len) throws IOException {
+    public int read(char[] cbuf, int off, int len) throws IOException {
       char[] tempBuffer = new char[cbuf.length];
-      int charCount = in.read(tempBuffer, off, len);
+      int charCount = getReader().read(tempBuffer, off, len);
       if (charCount != -1) {
         String filteredString = pattern.matcher(new String(tempBuffer)).replaceAll(REPLACEMENT);
         System.arraycopy(filteredString.toCharArray(), 0, cbuf, 0, tempBuffer.length);
@@ -207,4 +237,21 @@ public class CodeBufferTest {
     }
   }
 
+  @SuppressWarnings("rawtypes")
+  class WindowingChannel extends Channel {
+
+    @Override
+    public boolean consume(CodeReader code, Object output) {
+      int columnPosition = code.getColumnPosition();
+      if (code.peek() == '\n') {
+        return false;
+      }
+      if (columnPosition < 2 || columnPosition > 7) {
+        code.pop();
+        return true;
+      }
+      return false;
+    }
+  }
+
 }