From 28075b86c1e3f6623bcd8b78c1856c652e68f31e Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 27 Sep 2014 23:33:59 -0700 Subject: [PATCH] GUAC-868: Add GuacamoleFilter interface. Implemented corresponding FilteredGuacamoleReader and test. --- .../protocol/FilteredGuacamoleReader.java | 99 +++++++++++++++++++ .../guacamole/protocol/GuacamoleFilter.java | 51 ++++++++++ .../protocol/FilteredGuacamoleReaderTest.java | 95 ++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 guacamole-common/src/main/java/org/glyptodon/guacamole/protocol/FilteredGuacamoleReader.java create mode 100644 guacamole-common/src/main/java/org/glyptodon/guacamole/protocol/GuacamoleFilter.java create mode 100644 guacamole-common/src/test/java/org/glyptodon/guacamole/protocol/FilteredGuacamoleReaderTest.java diff --git a/guacamole-common/src/main/java/org/glyptodon/guacamole/protocol/FilteredGuacamoleReader.java b/guacamole-common/src/main/java/org/glyptodon/guacamole/protocol/FilteredGuacamoleReader.java new file mode 100644 index 000000000..2692e1865 --- /dev/null +++ b/guacamole-common/src/main/java/org/glyptodon/guacamole/protocol/FilteredGuacamoleReader.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.protocol; + +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.io.GuacamoleReader; + +/** + * GuacamoleReader which applies a given GuacamoleFilter to observe or alter all + * read instructions. Instructions may also be dropped or denied by the the + * filter. + * + * @author Michael Jumper + */ +public class FilteredGuacamoleReader implements GuacamoleReader { + + /** + * The wrapped GuacamoleReader. + */ + private final GuacamoleReader reader; + + /** + * The filter to apply when reading instructions. + */ + private final GuacamoleFilter filter; + + /** + * Wraps the given GuacamoleReader, applying the given filter to all read + * instructions. Future reads will return only instructions which pass + * the filter. + * + * @param reader The GuacamoleReader to wrap. + * @param filter The filter which dictates which instructions are read, and + * how. + */ + public FilteredGuacamoleReader(GuacamoleReader reader, GuacamoleFilter filter) { + this.reader = reader; + this.filter = filter; + } + + @Override + public boolean available() throws GuacamoleException { + return reader.available(); + } + + @Override + public char[] read() throws GuacamoleException { + + GuacamoleInstruction filteredInstruction = readInstruction(); + if (filteredInstruction == null) + return null; + + return filteredInstruction.toString().toCharArray(); + + } + + @Override + public GuacamoleInstruction readInstruction() throws GuacamoleException { + + GuacamoleInstruction filteredInstruction; + + // Read and filter instructions until no instructions are dropped + do { + + // Read next instruction + GuacamoleInstruction unfilteredInstruction = reader.readInstruction(); + if (unfilteredInstruction == null) + return null; + + // Apply filter + filteredInstruction = filter.filter(unfilteredInstruction); + + } while (filteredInstruction == null); + + return filteredInstruction; + + } + +} diff --git a/guacamole-common/src/main/java/org/glyptodon/guacamole/protocol/GuacamoleFilter.java b/guacamole-common/src/main/java/org/glyptodon/guacamole/protocol/GuacamoleFilter.java new file mode 100644 index 000000000..334e104c5 --- /dev/null +++ b/guacamole-common/src/main/java/org/glyptodon/guacamole/protocol/GuacamoleFilter.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.protocol; + +import org.glyptodon.guacamole.GuacamoleException; + +/** + * Interface which provides for the filtering of individual instructions. Each + * filtered instruction may be allowed through untouched, modified, replaced, + * dropped, or explicitly denied. + * + * @author Michael Jumper + */ +public interface GuacamoleFilter { + + /** + * Applies the filter to the given instruction, returning the original + * instruction, a modified version of the original, or null, depending + * on the implementation. + * + * @param instruction The instruction to filter. + * @return The original instruction, if the instruction is to be allowed, + * a modified version of the instruction, if the instruction is + * to be overridden, or null, if the instruction is to be dropped. + * @throws GuacamoleException If an error occurs filtering the instruction, + * or if the instruction must be explicitly + * denied. + */ + public GuacamoleInstruction filter(GuacamoleInstruction instruction) throws GuacamoleException; + +} diff --git a/guacamole-common/src/test/java/org/glyptodon/guacamole/protocol/FilteredGuacamoleReaderTest.java b/guacamole-common/src/test/java/org/glyptodon/guacamole/protocol/FilteredGuacamoleReaderTest.java new file mode 100644 index 000000000..a03b65e07 --- /dev/null +++ b/guacamole-common/src/test/java/org/glyptodon/guacamole/protocol/FilteredGuacamoleReaderTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.protocol; + +import java.io.StringReader; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.io.GuacamoleReader; +import org.glyptodon.guacamole.io.ReaderGuacamoleReader; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * Test which validates filtering of Guacamole instructions with + * FilteredGuacamoleReader. + * + * @author Michael Jumper + */ +public class FilteredGuacamoleReaderTest { + + /** + * Filter which allows through "yes" instructions but drops all others. + */ + private class TestFilter implements GuacamoleFilter { + + @Override + public GuacamoleInstruction filter(GuacamoleInstruction instruction) throws GuacamoleException { + + if (instruction.getOpcode().equals("yes")) + return instruction; + + return null; + + } + + } + + @Test + public void testFilter() throws Exception { + + // Test string + final String test = "3.yes,1.A;2.no,1.B;3.yes,1.C;3.yes,1.D;4.nope,1.E;"; + + GuacamoleReader reader = new FilteredGuacamoleReader(new ReaderGuacamoleReader(new StringReader(test)), + new TestFilter()); + + GuacamoleInstruction instruction; + + // Validate first instruction + instruction = reader.readInstruction(); + assertNotNull(instruction); + assertEquals("yes", instruction.getOpcode()); + assertEquals(1, instruction.getArgs().size()); + assertEquals("A", instruction.getArgs().get(0)); + + // Validate second instruction + instruction = reader.readInstruction(); + assertNotNull(instruction); + assertEquals("yes", instruction.getOpcode()); + assertEquals(1, instruction.getArgs().size()); + assertEquals("C", instruction.getArgs().get(0)); + + // Validate third instruction + instruction = reader.readInstruction(); + assertNotNull(instruction); + assertEquals("yes", instruction.getOpcode()); + assertEquals(1, instruction.getArgs().size()); + assertEquals("D", instruction.getArgs().get(0)); + + // Should be done now + instruction = reader.readInstruction(); + assertNull(instruction); + + } + +}