Pull all interfaces into a single interface: Filter.
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Tue, 4 Jun 2013 18:36:51 +0000 (20:36 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Tue, 4 Jun 2013 18:36:51 +0000 (20:36 +0200)
29 files changed:
src/main/java/net/pterodactylus/sonitus/data/AbstractControlledComponent.java [deleted file]
src/main/java/net/pterodactylus/sonitus/data/AbstractFilter.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sonitus/data/ControlledComponent.java [deleted file]
src/main/java/net/pterodactylus/sonitus/data/Filter.java
src/main/java/net/pterodactylus/sonitus/data/MetadataListener.java
src/main/java/net/pterodactylus/sonitus/data/Pipeline.java
src/main/java/net/pterodactylus/sonitus/data/Sink.java [deleted file]
src/main/java/net/pterodactylus/sonitus/data/Source.java [deleted file]
src/main/java/net/pterodactylus/sonitus/data/event/SourceFinishedEvent.java [deleted file]
src/main/java/net/pterodactylus/sonitus/data/filter/AudioProcessingFilter.java
src/main/java/net/pterodactylus/sonitus/data/filter/BasicFilter.java [deleted file]
src/main/java/net/pterodactylus/sonitus/data/filter/ExternalFilter.java
src/main/java/net/pterodactylus/sonitus/data/filter/PredicateFilter.java
src/main/java/net/pterodactylus/sonitus/data/filter/RateLimitingFilter.java
src/main/java/net/pterodactylus/sonitus/data/filter/StereoSeparationFilter.java
src/main/java/net/pterodactylus/sonitus/data/filter/TimeCounterFilter.java
src/main/java/net/pterodactylus/sonitus/data/filter/VolumeFilter.java
src/main/java/net/pterodactylus/sonitus/data/sink/AudioSink.java
src/main/java/net/pterodactylus/sonitus/data/sink/FileSink.java
src/main/java/net/pterodactylus/sonitus/data/sink/Icecast2Sink.java
src/main/java/net/pterodactylus/sonitus/data/source/FileSource.java
src/main/java/net/pterodactylus/sonitus/data/source/MultiSource.java
src/main/java/net/pterodactylus/sonitus/data/source/SourceFinishedListener.java
src/main/java/net/pterodactylus/sonitus/data/source/StreamSource.java
src/main/java/net/pterodactylus/sonitus/gui/ComponentInfoPanel.java [deleted file]
src/main/java/net/pterodactylus/sonitus/gui/FilterInfoPanel.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sonitus/gui/MainWindow.java
src/main/java/net/pterodactylus/sonitus/gui/PipelinePanel.java
src/main/java/net/pterodactylus/sonitus/gui/SwitchPanel.java

diff --git a/src/main/java/net/pterodactylus/sonitus/data/AbstractControlledComponent.java b/src/main/java/net/pterodactylus/sonitus/data/AbstractControlledComponent.java
deleted file mode 100644 (file)
index fe338c1..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Sonitus - AbstractControlledComponent.java - Copyright © 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sonitus.data;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-
-import com.google.common.collect.Lists;
-
-/**
- * Abstract {@link ControlledComponent} implementation that takes care of
- * managing {@link MetadataListener}s.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public abstract class AbstractControlledComponent implements ControlledComponent {
-
-       /** The name of this filter. */
-       private final String name;
-
-       /** The list of metadata listeners. */
-       private final List<MetadataListener> metadataListeners = Lists.newCopyOnWriteArrayList();
-
-       /** The current metadata. */
-       private final AtomicReference<Metadata> metadata = new AtomicReference<Metadata>();
-
-       /**
-        * Creates a new abstract controlled component.
-        *
-        * @param name
-        *              The name of the component
-        */
-       protected AbstractControlledComponent(String name) {
-               this.name = name;
-       }
-
-       //
-       // LISTENER MANAGEMENT
-       //
-
-       @Override
-       public void addMetadataListener(MetadataListener metadataListener) {
-               metadataListeners.add(metadataListener);
-       }
-
-       @Override
-       public void removeMetadataListener(MetadataListener metadataListener) {
-               metadataListeners.remove(metadataListener);
-       }
-
-       //
-       // CONTROLLEDCOMPONENT METHODS
-       //
-
-       @Override
-       public String name() {
-               return name;
-       }
-
-       @Override
-       public Metadata metadata() {
-               return metadata.get();
-       }
-
-       @Override
-       public void metadataUpdated(Metadata metadata) {
-               if (metadata.equals(this.metadata.get())) {
-                       return;
-               }
-               this.metadata.set(metadata);
-               fireMetadataUpdated(metadata);
-       }
-
-       //
-       // EVENT METHODS
-       //
-
-       /**
-        * Notifies all registered metadata listeners that the metadata has changed.
-        *
-        * @param metadata
-        *              The new metadata
-        */
-       protected void fireMetadataUpdated(Metadata metadata) {
-               for (MetadataListener metadataListener : metadataListeners) {
-                       metadataListener.metadataUpdated(this, metadata);
-               }
-       }
-
-}
diff --git a/src/main/java/net/pterodactylus/sonitus/data/AbstractFilter.java b/src/main/java/net/pterodactylus/sonitus/data/AbstractFilter.java
new file mode 100644 (file)
index 0000000..6fa6511
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Sonitus - AbstractFilter.java - Copyright © 2013 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sonitus.data;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.google.common.collect.Lists;
+import com.google.common.io.Closeables;
+
+/**
+ * Abstract {@link Filter} implementation that takes care of managing {@link
+ * MetadataListener}s and pipes its input to its output.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public abstract class AbstractFilter implements Filter {
+
+       /** The name of this filter. */
+       private final String name;
+
+       /** The list of metadata listeners. */
+       private final List<MetadataListener> metadataListeners = Lists.newCopyOnWriteArrayList();
+
+       /** The current metadata. */
+       private final AtomicReference<Metadata> metadata = new AtomicReference<Metadata>();
+
+       /** The input stream from which to read. */
+       private InputStream inputStream;
+
+       /** The output stream to which to write. */
+       private OutputStream outputStream;
+
+       /**
+        * Creates a new abstract filter.
+        *
+        * @param name
+        *              The name of the filter
+        */
+       protected AbstractFilter(String name) {
+               this.name = name;
+       }
+
+       //
+       // LISTENER MANAGEMENT
+       //
+
+       @Override
+       public void addMetadataListener(MetadataListener metadataListener) {
+               metadataListeners.add(metadataListener);
+       }
+
+       @Override
+       public void removeMetadataListener(MetadataListener metadataListener) {
+               metadataListeners.remove(metadataListener);
+       }
+
+       //
+       // FILTER METHODS
+       //
+
+       @Override
+       public String name() {
+               return name;
+       }
+
+       @Override
+       public List<Controller<?>> controllers() {
+               return Collections.emptyList();
+       }
+
+       @Override
+       public Metadata metadata() {
+               return metadata.get();
+       }
+
+       @Override
+       public void metadataUpdated(Metadata metadata) {
+               if (metadata.equals(this.metadata.get())) {
+                       return;
+               }
+               this.metadata.set(metadata);
+               fireMetadataUpdated(metadata);
+       }
+
+       @Override
+       public void open(Metadata metadata) throws IOException {
+               metadataUpdated(metadata);
+               inputStream = createInputStream();
+               outputStream = createOutputStream();
+       }
+
+       @Override
+       public void close() {
+               try {
+                       Closeables.close(outputStream, true);
+                       Closeables.close(inputStream, true);
+               } catch (IOException e) {
+                       /* won’t throw. */
+               }
+       }
+
+       @Override
+       public void process(byte[] buffer) throws IOException {
+               outputStream.write(buffer);
+               outputStream.flush();
+       }
+
+       @Override
+       public byte[] get(int bufferSize) throws IOException {
+               byte[] buffer = new byte[bufferSize];
+               int read = inputStream.read(buffer);
+               if (read == -1) {
+                       throw new EOFException();
+               }
+               return Arrays.copyOf(buffer, read);
+       }
+
+       //
+       // EVENT METHODS
+       //
+
+       /**
+        * Notifies all registered metadata listeners that the metadata has changed.
+        *
+        * @param metadata
+        *              The new metadata
+        */
+       protected void fireMetadataUpdated(Metadata metadata) {
+               for (MetadataListener metadataListener : metadataListeners) {
+                       metadataListener.metadataUpdated(this, metadata);
+               }
+       }
+
+       //
+       // SUBCLASS METHODS
+       //
+
+       /**
+        * Creates the input stream from which {@link net.pterodactylus.sonitus.data.Pipeline}
+        * will read the audio data. If you override this, you have to override {@link
+        * #createOutputStream()}, too!
+        *
+        * @return The input stream to read from
+        * @throws IOException
+        *              if an I/O error occurs
+        */
+       protected InputStream createInputStream() throws IOException {
+               return new PipedInputStream();
+       }
+
+       /**
+        * Creates the output stream to which {@link net.pterodactylus.sonitus.data.Pipeline}
+        * will write the audio data. If you override this, you have to override {@link
+        * #createInputStream()}, too!
+        *
+        * @return The output stream to write to
+        * @throws IOException
+        *              if an I/O error occurs
+        */
+       protected OutputStream createOutputStream() throws IOException {
+               return new PipedOutputStream((PipedInputStream) inputStream);
+       }
+
+}
diff --git a/src/main/java/net/pterodactylus/sonitus/data/ControlledComponent.java b/src/main/java/net/pterodactylus/sonitus/data/ControlledComponent.java
deleted file mode 100644 (file)
index d3fde8e..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Sonitus - Controlled.java - Copyright © 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sonitus.data;
-
-import java.util.List;
-
-/**
- * Interface for components that can be controlled externally in some way.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface ControlledComponent {
-
-       /**
-        * Adds the given listener to the list of registered listeners.
-        *
-        * @param metadataListener
-        *              The metadata listener to add
-        */
-       void addMetadataListener(MetadataListener metadataListener);
-
-       /**
-        * Removes the given listener from the list of registered listeners.
-        *
-        * @param metadataListener
-        *              The metadata listener to remove
-        */
-       void removeMetadataListener(MetadataListener metadataListener);
-
-       /**
-        * Returns the name of this controlled component.
-        *
-        * @return The name of this controlled component
-        */
-       public String name();
-
-       /**
-        * Returns the current metadata of this component.
-        *
-        * @return The current metadata of this component
-        */
-       public Metadata metadata();
-
-       /**
-        * Returns the controllers offered by this component.
-        *
-        * @return The controllers of this component
-        */
-       public List<Controller<?>> controllers();
-
-       /**
-        * Notifies the sink that the metadata of the audio stream has changed. This
-        * method should return as fast as possible, i.e. every heavy lifting should be
-        * done from another thread.
-        *
-        * @param metadata
-        *              The new metadata
-        */
-       void metadataUpdated(Metadata metadata);
-
-}
index c251cfe..ec8fb94 100644 (file)
 
 package net.pterodactylus.sonitus.data;
 
+import java.io.IOException;
+import java.util.List;
+
 /**
- * A filter is both a {@link Source} and a {@link Sink}. It is used to process
+ * A filter is both a source and a sink for audio data. It is used to process
  * the audio date in whatever way seems appropriate.
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public interface Filter extends ControlledComponent, Source, Sink {
+public interface Filter {
+
+       /**
+        * Adds the given listener to the list of registered listeners.
+        *
+        * @param metadataListener
+        *              The metadata listener to add
+        */
+       void addMetadataListener(MetadataListener metadataListener);
+
+       /**
+        * Removes the given listener from the list of registered listeners.
+        *
+        * @param metadataListener
+        *              The metadata listener to remove
+        */
+       void removeMetadataListener(MetadataListener metadataListener);
+
+       /**
+        * Returns the name of this filter.
+        *
+        * @return The name of this filter
+        */
+       String name();
+
+       /**
+        * Returns the controllers offered by this filter.
+        *
+        * @return The controllers of this filter
+        */
+       List<Controller<?>> controllers();
+
+       /**
+        * Returns the metadata of the audio stream.
+        *
+        * @return The metadata of the audio stream
+        */
+       Metadata metadata();
+
+       /**
+        * Notifies the sink that the metadata of the audio stream has changed. This
+        * method should return as fast as possible, i.e. every heavy lifting should be
+        * done from another thread.
+        *
+        * @param metadata
+        *              The new metadata
+        */
+       void metadataUpdated(Metadata metadata);
+
+       /**
+        * Retrieves data from the audio stream.
+        *
+        * @param bufferSize
+        *              The maximum amount of bytes to retrieve from the audio stream
+        * @return A buffer filled with up to {@code bufferSize} bytes of data; the
+        *         returned buffer may contain less data than requested but will not
+        *         contain excess elements
+        * @throws IOException
+        *              if an I/O error occurs
+        */
+       byte[] get(int bufferSize) throws IOException;
+
+       /**
+        * Opens this sink using the format parameters of the given metadata.
+        *
+        * @param metadata
+        *              The metadata of the stream
+        * @throws IOException
+        *              if an I/O error occurs
+        */
+       void open(Metadata metadata) throws IOException;
+
+       /** Closes this sink. */
+       void close();
+
+       /**
+        * Processes the given buffer of data.
+        *
+        * @param buffer
+        *              The data to process
+        * @throws IOException
+        *              if an I/O error occurs
+        */
+       void process(byte[] buffer) throws IOException;
 
 }
index 01efe78..6b88ddf 100644 (file)
@@ -25,13 +25,13 @@ package net.pterodactylus.sonitus.data;
 public interface MetadataListener {
 
        /**
-        * Notifies a listener when the metadata of the given component was updated.
+        * Notifies a listener when the metadata of the given filter was updated.
         *
-        * @param component
-        *              The component whose metadata was updated
+        * @param filter
+        *              The filter whose metadata was updated
         * @param metadata
         *              The new metadata
         */
-       void metadataUpdated(ControlledComponent component, Metadata metadata);
+       void metadataUpdated(Filter filter, Metadata metadata);
 
 }
index ab6500e..5bbcd63 100644 (file)
@@ -36,26 +36,27 @@ import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.MoreExecutors;
 
 /**
- * A pipeline is responsible for streaming audio data from a {@link Source} to
- * an arbitrary number of connected {@link Filter}s and {@link Sink}s.
+ * A pipeline is responsible for streaming audio data from a {@link Filter} to
+ * an arbitrary number of connected {@link Filter}s.
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class Pipeline implements Iterable<ControlledComponent> {
+public class Pipeline implements Iterable<Filter> {
 
        /** The logger. */
        private static final Logger logger = Logger.getLogger(Pipeline.class.getName());
 
        /** The source of the audio stream. */
-       private final Source source;
+       private final Filter source;
 
-       /** The sinks for each source. */
-       private final Multimap<Source, Sink> sinks;
+       /** The filters for each source. */
+       private final ListMultimap<Filter, Filter> filters;
 
        /** All started connections. */
        private final List<Connection> connections = Lists.newArrayList();
@@ -65,23 +66,21 @@ public class Pipeline implements Iterable<ControlledComponent> {
         *
         * @param source
         *              The source of the audio stream
-        * @param sinks
-        *              The sinks for each source
+        * @param filters
+        *              The filters for each source
         */
-       private Pipeline(Source source, Multimap<Source, Sink> sinks) {
+       private Pipeline(Filter source, Multimap<Filter, Filter> filters) {
                this.source = Preconditions.checkNotNull(source, "source must not be null");
-               this.sinks = Preconditions.checkNotNull(sinks, "sinks must not be null");
-               for (ControlledComponent component : Lists.reverse(components())) {
-                       logger.finest(String.format("Adding Listener to %s.", component.name()));
-                       component.addMetadataListener(new MetadataListener() {
+               this.filters = ArrayListMultimap.create(Preconditions.checkNotNull(filters, "filters must not be null"));
+               for (Filter filter : Lists.reverse(filters())) {
+                       logger.finest(String.format("Adding Listener to %s.", filter.name()));
+                       filter.addMetadataListener(new MetadataListener() {
+
                                @Override
-                               public void metadataUpdated(ControlledComponent component, Metadata metadata) {
-                                       if (!(component instanceof Source)) {
-                                               return;
-                                       }
-                                       for (ControlledComponent controlledComponent : sinks((Source) component)) {
-                                               logger.fine(String.format("Updating Metadata from %s to %s as %s.", component.name(), controlledComponent.name(), metadata));
-                                               controlledComponent.metadataUpdated(metadata);
+                               public void metadataUpdated(Filter filter, Metadata metadata) {
+                                       for (Filter sinks : filters(filter)) {
+                                               logger.fine(String.format("Updating Metadata from %s to %s as %s.", filter.name(), sinks.name(), metadata));
+                                               sinks.metadataUpdated(metadata);
                                        }
                                }
                        });
@@ -97,38 +96,37 @@ public class Pipeline implements Iterable<ControlledComponent> {
         *
         * @return This pipeline’s source
         */
-       public Source source() {
+       public Filter source() {
                return source;
        }
 
        /**
-        * Returns all {@link Sink}s (or {@link Filter}s, really) that are connected to
-        * the given source.
+        * Returns all {@link Filter}s that are connected to the given filter.
         *
-        * @param source
-        *              The source to get the sinks for
-        * @return The sinks connected to the given source, or an empty list if the
-        *         source does not exist in this pipeline
+        * @param filter
+        *              The filter to get the connected filters for
+        * @return The filters connected to the given filter, or an empty list if the
+        *         filter does not exist in this pipeline, or is not connected to any filters
         */
-       public Collection<Sink> sinks(Source source) {
-               return sinks.get(source);
+       public List<Filter> filters(Filter filter) {
+               return filters.get(filter);
        }
 
        /**
-        * Returns the traffic counters of the given controlled component.
+        * Returns the traffic counters of the given filter.
         *
-        * @param controlledComponent
-        *              The controlled component to get the traffic counters for
-        * @return The traffic counters for the given controlled component
+        * @param filter
+        *              The filter to get the traffic counters for
+        * @return The traffic counters for the given filter
         */
-       public TrafficCounter trafficCounter(ControlledComponent controlledComponent) {
+       public TrafficCounter trafficCounter(Filter filter) {
                long input = -1;
                long output = -1;
                for (Connection connection : connections) {
                        /* the connection where the source matches knows the output. */
-                       if (connection.source.equals(controlledComponent)) {
+                       if (connection.source.equals(filter)) {
                                output = connection.counter();
-                       } else if (connection.sinks.contains(controlledComponent)) {
+                       } else if (connection.sinks.contains(filter)) {
                                input = connection.counter();
                        }
                }
@@ -143,7 +141,7 @@ public class Pipeline implements Iterable<ControlledComponent> {
         * Starts the pipeline.
         *
         * @throws IOException
-        *              if any of the sinks can not be opened
+        *              if any of the filters can not be opened
         * @throws IllegalStateException
         *              if the pipeline is already running
         */
@@ -151,26 +149,24 @@ public class Pipeline implements Iterable<ControlledComponent> {
                if (!connections.isEmpty()) {
                        throw new IllegalStateException("Pipeline is already running!");
                }
-               List<Source> sources = Lists.newArrayList();
-               sources.add(source);
+               List<Filter> filters = Lists.newArrayList();
+               filters.add(source);
                /* collect all source->sink pairs. */
-               while (!sources.isEmpty()) {
-                       Source source = sources.remove(0);
-                       Collection<Sink> sinks = this.sinks.get(source);
-                       connections.add(new Connection(source, sinks));
-                       for (Sink sink : sinks) {
+               while (!filters.isEmpty()) {
+                       Filter filter = filters.remove(0);
+                       Collection<Filter> sinks = this.filters.get(filter);
+                       connections.add(new Connection(filter, sinks));
+                       for (Filter sink : sinks) {
                                logger.info(String.format("Opening %s with %s...", sink.name(), source.metadata()));
-                               sink.open(source.metadata());
-                               if (sink instanceof Filter) {
-                                       sources.add((Source) sink);
-                               }
+                               sink.open(filter.metadata());
+                               filters.add(sink);
                        }
                }
                for (Connection connection : connections) {
-                       String threadName = String.format("%s → %s.", connection.source.name(), FluentIterable.from(connection.sinks).transform(new Function<Sink, String>() {
+                       String threadName = String.format("%s → %s.", connection.source.name(), FluentIterable.from(connection.sinks).transform(new Function<Filter, String>() {
 
                                @Override
-                               public String apply(Sink sink) {
+                               public String apply(Filter sink) {
                                        return sink.name();
                                }
                        }));
@@ -194,8 +190,8 @@ public class Pipeline implements Iterable<ControlledComponent> {
        //
 
        @Override
-       public Iterator<ControlledComponent> iterator() {
-               return components().iterator();
+       public Iterator<Filter> iterator() {
+               return filters().iterator();
        }
 
        //
@@ -203,26 +199,24 @@ public class Pipeline implements Iterable<ControlledComponent> {
        //
 
        /**
-        * Returns all components of this pipeline, listed breadth-first, starting with
+        * Returns all filters of this pipeline, listed breadth-first, starting with
         * the source.
         *
-        * @return All components of this pipeline
+        * @return All filters of this pipeline
         */
-       public List<ControlledComponent> components() {
-               ImmutableList.Builder<ControlledComponent> components = ImmutableList.builder();
-               List<ControlledComponent> currentComponents = Lists.newArrayList();
-               components.add(source);
-               currentComponents.add(source);
-               while (!currentComponents.isEmpty()) {
-                       Collection<Sink> sinks = this.sinks((Source) currentComponents.remove(0));
-                       for (Sink sink : sinks) {
-                               components.add(sink);
-                               if (sink instanceof Source) {
-                                       currentComponents.add(sink);
-                               }
+       public List<Filter> filters() {
+               ImmutableList.Builder<Filter> filters = ImmutableList.builder();
+               List<Filter> remainingFilters = Lists.newArrayList();
+               filters.add(source);
+               remainingFilters.add(source);
+               while (!remainingFilters.isEmpty()) {
+                       Collection<Filter> sinks = this.filters(remainingFilters.remove(0));
+                       for (Filter sink : sinks) {
+                               filters.add(sink);
+                               remainingFilters.add(sink);
                        }
                }
-               return components.build();
+               return filters.build();
        }
 
        //
@@ -236,7 +230,7 @@ public class Pipeline implements Iterable<ControlledComponent> {
         *              The source at which to start
         * @return A builder for a new pipeline
         */
-       public static Builder builder(Source source) {
+       public static Builder builder(Filter source) {
                return new Builder(source);
        }
 
@@ -248,13 +242,13 @@ public class Pipeline implements Iterable<ControlledComponent> {
        public static class Builder {
 
                /** The source of the pipeline. */
-               private final Source source;
+               private final Filter source;
 
-               /** The sinks to which each source streams. */
-               private Multimap<Source, Sink> nextSinks = ArrayListMultimap.create();
+               /** The filters to which each source streams. */
+               private Multimap<Filter, Filter> nextSinks = ArrayListMultimap.create();
 
                /** The last added source. */
-               private Source lastSource;
+               private Filter lastSource;
 
                /**
                 * Creates a new builder.
@@ -262,31 +256,27 @@ public class Pipeline implements Iterable<ControlledComponent> {
                 * @param source
                 *              The source that starts the pipeline
                 */
-               private Builder(Source source) {
+               private Builder(Filter source) {
                        this.source = source;
                        lastSource = source;
                }
 
                /**
-                * Adds a {@link Sink} (or {@link Filter} as a recipient for the last added
-                * {@link Source}.
+                * Adds a {@link Filter} as a recipient for the last added source.
                 *
                 * @param sink
                 *              The sink to add
                 * @return This builder
-                * @throws IllegalStateException
-                *              if the last added {@link Sink} was not also a {@link Source}
                 */
-               public Builder to(Sink sink) {
-                       Preconditions.checkState(lastSource != null, "last added Sink was not a Source");
+               public Builder to(Filter sink) {
                        nextSinks.put(lastSource, sink);
-                       lastSource = (sink instanceof Filter) ? (Source) sink : null;
+                       lastSource = sink;
                        return this;
                }
 
                /**
                 * Locates the given source and sets it as the last added node so that the
-                * next invocation of {@link #to(Sink)} can “fork” the pipeline.
+                * next invocation of {@link #to(Filter)} can “fork” the pipeline.
                 *
                 * @param source
                 *              The source to locate
@@ -294,7 +284,7 @@ public class Pipeline implements Iterable<ControlledComponent> {
                 * @throws IllegalStateException
                 *              if the given source was not previously added as a sink
                 */
-               public Builder find(Source source) {
+               public Builder find(Filter source) {
                        Preconditions.checkState(nextSinks.containsValue(source));
                        lastSource = source;
                        return this;
@@ -312,8 +302,8 @@ public class Pipeline implements Iterable<ControlledComponent> {
        }
 
        /**
-        * A connection is responsible for streaming audio from one {@link Source} to
-        * an arbitrary number of {@link Sink}s it is connected to. A connection is
+        * A connection is responsible for streaming audio from one {@link Filter} to
+        * an arbitrary number of {@link Filter}s it is connected to. A connection is
         * started by creating a {@link Thread} wrapping it and starting said thread.
         *
         * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
@@ -321,10 +311,10 @@ public class Pipeline implements Iterable<ControlledComponent> {
        public class Connection implements Runnable {
 
                /** The source. */
-               private final Source source;
+               private final Filter source;
 
-               /** The sinks. */
-               private final Collection<Sink> sinks;
+               /** The filters. */
+               private final Collection<Filter> sinks;
 
                /** Whether the feeder was stopped. */
                private final AtomicBoolean stopped = new AtomicBoolean(false);
@@ -344,9 +334,9 @@ public class Pipeline implements Iterable<ControlledComponent> {
                 * @param source
                 *              The source of the stream
                 * @param sinks
-                *              The sinks to which to stream
+                *              The filters to which to stream
                 */
-               public Connection(Source source, Collection<Sink> sinks) {
+               public Connection(Filter source, Collection<Filter> sinks) {
                        this.source = source;
                        this.sinks = sinks;
                        if (sinks.size() < 2) {
@@ -406,10 +396,10 @@ public class Pipeline implements Iterable<ControlledComponent> {
                                        } catch (IOException ioe1) {
                                                throw new IOException(String.format("I/O error while reading from %s.", source.name()), ioe1);
                                        }
-                                       List<Future<Void>> futures = executorService.invokeAll(FluentIterable.from(sinks).transform(new Function<Sink, Callable<Void>>() {
+                                       List<Future<Void>> futures = executorService.invokeAll(FluentIterable.from(sinks).transform(new Function<Filter, Callable<Void>>() {
 
                                                @Override
-                                               public Callable<Void> apply(final Sink sink) {
+                                               public Callable<Void> apply(final Filter sink) {
                                                        return new Callable<Void>() {
 
                                                                @Override
@@ -485,7 +475,7 @@ public class Pipeline implements Iterable<ControlledComponent> {
                 * Returns the number of input bytes.
                 *
                 * @return The number of input bytes, or {@link Optional#absent()} if the
-                *         component can not receive input
+                *         filter did not receive input
                 */
                public Optional<Long> input() {
                        return (input == -1) ? Optional.<Long>absent() : Optional.of(input);
@@ -495,7 +485,7 @@ public class Pipeline implements Iterable<ControlledComponent> {
                 * Returns the number of output bytes.
                 *
                 * @return The number of output bytes, or {@link Optional#absent()} if the
-                *         component can not send output
+                *         filter did not send output
                 */
                public Optional<Long> output() {
                        return (output == -1) ? Optional.<Long>absent() : Optional.of(output);
diff --git a/src/main/java/net/pterodactylus/sonitus/data/Sink.java b/src/main/java/net/pterodactylus/sonitus/data/Sink.java
deleted file mode 100644 (file)
index 937a4e5..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package net.pterodactylus.sonitus.data;
-
-import java.io.IOException;
-
-/**
- * A sink is a destination for audio data. It can be played on speakers, it can
- * be written to a file, or it can be sent to a remote streaming server.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface Sink extends ControlledComponent {
-
-       /**
-        * Opens this sink using the format parameters of the given metadata.
-        *
-        * @param metadata
-        *              The metadata of the stream
-        * @throws IOException
-        *              if an I/O error occurs
-        */
-       void open(Metadata metadata) throws IOException;
-
-       /** Closes this sink. */
-       void close();
-
-       /**
-        * Processes the given buffer of data.
-        *
-        * @param buffer
-        *              The data to process
-        * @throws IOException
-        *              if an I/O error occurs
-        */
-       void process(byte[] buffer) throws IOException;
-
-}
diff --git a/src/main/java/net/pterodactylus/sonitus/data/Source.java b/src/main/java/net/pterodactylus/sonitus/data/Source.java
deleted file mode 100644 (file)
index b12ec20..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-package net.pterodactylus.sonitus.data;
-
-import java.io.IOException;
-
-/**
- * A source produces an audio stream and accompanying metadata.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface Source extends ControlledComponent {
-
-       /**
-        * Returns the metadata of the audio stream.
-        *
-        * @return The metadata of the audio stream
-        */
-       Metadata metadata();
-
-       /**
-        * Retrieves data from the audio stream.
-        *
-        * @param bufferSize
-        *              The maximum amount of bytes to retrieve from the audio stream
-        * @return A buffer filled with up to {@code bufferSize} bytes of data; the
-        *         returned buffer may contain less data than requested but will not
-        *         contain excess elements
-        * @throws IOException
-        *              if an I/O error occurs
-        */
-       byte[] get(int bufferSize) throws IOException;
-
-}
diff --git a/src/main/java/net/pterodactylus/sonitus/data/event/SourceFinishedEvent.java b/src/main/java/net/pterodactylus/sonitus/data/event/SourceFinishedEvent.java
deleted file mode 100644 (file)
index 6161a16..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Sonitus - SourceFinishedEvent.java - Copyright © 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sonitus.data.event;
-
-import net.pterodactylus.sonitus.data.Source;
-
-/**
- * Event that is sent to an {@link com.google.common.eventbus.EventBus} when
- * a {@link Source} is no longer in use.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class SourceFinishedEvent {
-
-       /** The source that is no longer in use. */
-       private final Source source;
-
-       /**
-        * Creates a new source finished event.
-        *
-        * @param source
-        *              The source that is no longer in use
-        */
-       public SourceFinishedEvent(Source source) {
-               this.source = source;
-       }
-
-       /**
-        * Returns the source that is no longer in use
-        *
-        * @return The source that is no longer in use
-        */
-       public Source source() {
-               return source;
-       }
-
-}
index 7312f7f..933109e 100644 (file)
@@ -20,6 +20,7 @@ package net.pterodactylus.sonitus.data.filter;
 import java.io.IOException;
 import java.io.OutputStream;
 
+import net.pterodactylus.sonitus.data.AbstractFilter;
 import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.io.ProcessingOutputStream;
 
@@ -28,7 +29,7 @@ import net.pterodactylus.sonitus.io.ProcessingOutputStream;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public abstract class AudioProcessingFilter extends BasicFilter {
+public abstract class AudioProcessingFilter extends AbstractFilter implements Filter {
 
        /**
         * Creates a new audio processing filter with the given name.
@@ -41,7 +42,7 @@ public abstract class AudioProcessingFilter extends BasicFilter {
        }
 
        //
-       // BASICFILTER METHODS
+       // FILTER METHODS
        //
 
        @Override
diff --git a/src/main/java/net/pterodactylus/sonitus/data/filter/BasicFilter.java b/src/main/java/net/pterodactylus/sonitus/data/filter/BasicFilter.java
deleted file mode 100644 (file)
index 0f248d6..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Sonitus - AbstractFilter.java - Copyright © 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sonitus.data.filter;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import net.pterodactylus.sonitus.data.AbstractControlledComponent;
-import net.pterodactylus.sonitus.data.Controller;
-import net.pterodactylus.sonitus.data.Filter;
-import net.pterodactylus.sonitus.data.Metadata;
-
-import com.google.common.io.Closeables;
-
-/**
- * Basic {@link Filter} implementation that pipes its input to its output.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class BasicFilter extends AbstractControlledComponent implements Filter {
-
-       /** The input stream from which to read. */
-       private InputStream inputStream;
-
-       /** The output stream to which to write. */
-       private OutputStream outputStream;
-
-       /**
-        * Creates a new dummy filter with the given name.
-        *
-        * @param name
-        *              The name of the filter
-        */
-       public BasicFilter(String name) {
-               super(name);
-       }
-
-       //
-       // CONTROLLED METHODS
-       //
-
-       @Override
-       public List<Controller<?>> controllers() {
-               return Collections.emptyList();
-       }
-
-       //
-       // FILTER METHODS
-       //
-
-       @Override
-       public void open(Metadata metadata) throws IOException {
-               metadataUpdated(metadata);
-               inputStream = createInputStream();
-               outputStream = createOutputStream();
-       }
-
-       @Override
-       public void close() {
-               try {
-                       Closeables.close(outputStream, true);
-                       Closeables.close(inputStream, true);
-               } catch (IOException e) {
-                       /* won’t throw. */
-               }
-       }
-
-       @Override
-       public void process(byte[] buffer) throws IOException {
-               outputStream.write(buffer);
-               outputStream.flush();
-       }
-
-       @Override
-       public byte[] get(int bufferSize) throws IOException {
-               byte[] buffer = new byte[bufferSize];
-               int read = inputStream.read(buffer);
-               if (read == -1) {
-                       throw new EOFException();
-               }
-               return Arrays.copyOf(buffer, read);
-       }
-
-       //
-       // SUBCLASS METHODS
-       //
-
-       /**
-        * Creates the input stream from which {@link net.pterodactylus.sonitus.data.Pipeline}
-        * will read the audio data. If you override this, you have to override {@link
-        * #createOutputStream()}, too!
-        *
-        * @return The input stream to read from
-        * @throws IOException
-        *              if an I/O error occurs
-        */
-       protected InputStream createInputStream() throws IOException {
-               return new PipedInputStream();
-       }
-
-       /**
-        * Creates the output stream to which {@link net.pterodactylus.sonitus.data.Pipeline}
-        * will write the audio data. If you override this, you have to override {@link
-        * #createInputStream()}, too!
-        *
-        * @return The output stream to write to
-        * @throws IOException
-        *              if an I/O error occurs
-        */
-       protected OutputStream createOutputStream() throws IOException {
-               return new PipedOutputStream((PipedInputStream) inputStream);
-       }
-
-}
index 73338b5..a482cf6 100644 (file)
@@ -22,6 +22,8 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.logging.Logger;
 
+import net.pterodactylus.sonitus.data.AbstractFilter;
+import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.data.Metadata;
 import net.pterodactylus.sonitus.io.InputStreamDrainer;
 
@@ -34,7 +36,7 @@ import com.google.common.collect.Iterables;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public abstract class ExternalFilter extends BasicFilter {
+public abstract class ExternalFilter extends AbstractFilter implements Filter {
 
        /** The logger. */
        private final Logger logger = Logger.getLogger(getClass().getName());
@@ -69,10 +71,6 @@ public abstract class ExternalFilter extends BasicFilter {
                process.destroy();
        }
 
-       //
-       // BASICFILTER METHODS
-       //
-
        @Override
        protected InputStream createInputStream() throws IOException {
                return process.getInputStream();
index 8968596..20840a8 100644 (file)
@@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import net.pterodactylus.sonitus.data.AbstractFilter;
 import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.data.Metadata;
 
@@ -33,7 +34,7 @@ import com.google.common.base.Predicate;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class PredicateFilter extends BasicFilter {
+public class PredicateFilter extends AbstractFilter implements Filter {
 
        /** The predicate. */
        private final Predicate<Metadata> metadataPredicate;
index 881deeb..04ed2d1 100644 (file)
@@ -20,6 +20,8 @@ package net.pterodactylus.sonitus.data.filter;
 import java.io.IOException;
 import java.util.logging.Logger;
 
+import net.pterodactylus.sonitus.data.AbstractFilter;
+import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.data.Metadata;
 
 /**
@@ -29,7 +31,7 @@ import net.pterodactylus.sonitus.data.Metadata;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class RateLimitingFilter extends BasicFilter {
+public class RateLimitingFilter extends AbstractFilter implements Filter {
 
        /** The logger. */
        private static final Logger logger = Logger.getLogger(RateLimitingFilter.class.getName());
index 3993e11..6eef02c 100644 (file)
@@ -42,7 +42,7 @@ public class StereoSeparationFilter extends AudioProcessingFilter {
        }
 
        //
-       // CONTROLLED METHODS
+       // FILTER METHODS
        //
 
        @Override
@@ -50,10 +50,6 @@ public class StereoSeparationFilter extends AudioProcessingFilter {
                return Arrays.<Controller<?>>asList(separationKnob);
        }
 
-       //
-       // AUDIOPROCESSINGFILTER METHODS
-       //
-
        @Override
        protected int[] processSamples(int[] samples) {
                if (samples.length == 1) {
index cfa93af..ce08a61 100644 (file)
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
+import net.pterodactylus.sonitus.data.AbstractFilter;
 import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.data.Metadata;
 
@@ -31,7 +32,7 @@ import net.pterodactylus.sonitus.data.Metadata;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class TimeCounterFilter extends BasicFilter {
+public class TimeCounterFilter extends AbstractFilter implements Filter {
 
        /** The byte counter. */
        private final AtomicLong counter = new AtomicLong();
@@ -95,7 +96,7 @@ public class TimeCounterFilter extends BasicFilter {
        }
 
        //
-       // BASICFILTER METHODS
+       // FILTER METHODS
        //
 
        @Override
index 02570db..01d325f 100644 (file)
@@ -47,7 +47,7 @@ public class VolumeFilter extends AudioProcessingFilter {
        }
 
        //
-       // CONTROLLED METHODS
+       // FILTER METHODS
        //
 
        @Override
@@ -55,10 +55,6 @@ public class VolumeFilter extends AudioProcessingFilter {
                return Arrays.<Controller<?>>asList(volumeFader, muteSwitch);
        }
 
-       //
-       // AUDIOPROCESSINGFILTER METHODS
-       //
-
        @Override
        protected int[] processSamples(int[] samples) {
                int[] processedSamples = new int[samples.length];
index 07499ad..6cace62 100644 (file)
@@ -34,11 +34,10 @@ import javax.sound.sampled.FloatControl;
 import javax.sound.sampled.LineUnavailableException;
 import javax.sound.sampled.SourceDataLine;
 
-import net.pterodactylus.sonitus.data.AbstractControlledComponent;
+import net.pterodactylus.sonitus.data.AbstractFilter;
 import net.pterodactylus.sonitus.data.Controller;
+import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.data.Metadata;
-import net.pterodactylus.sonitus.data.Sink;
-import net.pterodactylus.sonitus.data.Source;
 import net.pterodactylus.sonitus.data.controller.Fader;
 import net.pterodactylus.sonitus.data.controller.Switch;
 import net.pterodactylus.sonitus.io.IntegralWriteOutputStream;
@@ -46,12 +45,12 @@ import net.pterodactylus.sonitus.io.IntegralWriteOutputStream;
 import com.google.common.base.Preconditions;
 
 /**
- * {@link Sink} implementation that uses the JDK’s {@link AudioSystem} to play
- * all {@link Source}s.
+ * {@link Filter} implementation that uses the JDK’s {@link AudioSystem} to play
+ * all the audio signal.
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class AudioSink extends AbstractControlledComponent implements Sink {
+public class AudioSink extends AbstractFilter {
 
        /** The logger. */
        private static final Logger logger = Logger.getLogger(AudioSink.class.getName());
@@ -135,7 +134,7 @@ public class AudioSink extends AbstractControlledComponent implements Sink {
        }
 
        //
-       // CONTROLLED METHODS
+       // FILTER METHODS
        //
 
        @Override
@@ -143,13 +142,10 @@ public class AudioSink extends AbstractControlledComponent implements Sink {
                return Arrays.<Controller<?>>asList(volumeFader, muteSwitch);
        }
 
-       //
-       // SINK METHODS
-       //
-
        @Override
        public void open(Metadata metadata) throws IOException {
                Preconditions.checkArgument(metadata.encoding().equalsIgnoreCase("PCM"), "source must be PCM-encoded");
+               super.open(metadata);
                AudioFormat audioFormat = new AudioFormat(metadata.frequency(), 16, metadata.channels(), true, false);
                try {
                        sourceDataLine = AudioSystem.getSourceDataLine(audioFormat);
@@ -178,6 +174,7 @@ public class AudioSink extends AbstractControlledComponent implements Sink {
        @Override
        public void process(byte[] buffer) throws IOException {
                sourceDataLineOutputStream.write(buffer);
+               super.process(buffer);
                logger.finest(String.format("AudioSink: Wrote %d Bytes.", buffer.length));
        }
 
index be934f3..5011321 100644 (file)
@@ -19,14 +19,10 @@ package net.pterodactylus.sonitus.data.sink;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
 import java.util.logging.Logger;
 
-import net.pterodactylus.sonitus.data.AbstractControlledComponent;
-import net.pterodactylus.sonitus.data.Controller;
+import net.pterodactylus.sonitus.data.AbstractFilter;
 import net.pterodactylus.sonitus.data.Metadata;
-import net.pterodactylus.sonitus.data.Sink;
 
 /**
  * {@link net.pterodactylus.sonitus.data.Sink} that writes all received data
@@ -34,7 +30,7 @@ import net.pterodactylus.sonitus.data.Sink;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class FileSink extends AbstractControlledComponent implements Sink {
+public class FileSink extends AbstractFilter {
 
        /** The logger. */
        private static final Logger logger = Logger.getLogger(FileSink.class.getName());
@@ -57,16 +53,7 @@ public class FileSink extends AbstractControlledComponent implements Sink {
        }
 
        //
-       // CONTROLLED METHODS
-       //
-
-       @Override
-       public List<Controller<?>> controllers() {
-               return Collections.emptyList();
-       }
-
-       //
-       // SINK METHODS
+       // FILTER METHODS
        //
 
        @Override
index 8e1c154..f98fba5 100644 (file)
@@ -28,10 +28,9 @@ import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import net.pterodactylus.sonitus.data.AbstractControlledComponent;
+import net.pterodactylus.sonitus.data.AbstractFilter;
 import net.pterodactylus.sonitus.data.Controller;
 import net.pterodactylus.sonitus.data.Metadata;
-import net.pterodactylus.sonitus.data.Sink;
 import net.pterodactylus.sonitus.io.InputStreamDrainer;
 
 import com.google.common.io.BaseEncoding;
@@ -43,7 +42,7 @@ import com.google.common.io.Closeables;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class Icecast2Sink extends AbstractControlledComponent implements Sink {
+public class Icecast2Sink extends AbstractFilter {
 
        /** The logger. */
        private static final Logger logger = Logger.getLogger(Icecast2Sink.class.getName());
@@ -111,7 +110,7 @@ public class Icecast2Sink extends AbstractControlledComponent implements Sink {
        }
 
        //
-       // CONTROLLED METHODS
+       // FILTER METHODS
        //
 
        @Override
@@ -119,10 +118,6 @@ public class Icecast2Sink extends AbstractControlledComponent implements Sink {
                return Collections.emptyList();
        }
 
-       //
-       // SINK METHODS
-       //
-
        @Override
        public void open(Metadata metadata) throws IOException {
                logger.info(String.format("Connecting to %s:%d...", server, port));
index 9aff8d4..7251f65 100644 (file)
@@ -27,21 +27,21 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-import net.pterodactylus.sonitus.data.AbstractControlledComponent;
+import net.pterodactylus.sonitus.data.AbstractFilter;
 import net.pterodactylus.sonitus.data.Controller;
+import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.data.Metadata;
-import net.pterodactylus.sonitus.data.Source;
 import net.pterodactylus.sonitus.io.IdentifyingInputStream;
 
 import com.google.common.base.Optional;
 
 /**
- * A {@link net.pterodactylus.sonitus.data.Source} that is read from the local
- * file system.
+ * A {@link Filter} that reads a file from the local file system and does not
+ * expect any input.
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class FileSource extends AbstractControlledComponent implements Source {
+public class FileSource extends AbstractFilter {
 
        /** The path of the file. */
        private final String path;
@@ -73,7 +73,7 @@ public class FileSource extends AbstractControlledComponent implements Source {
        }
 
        //
-       // CONTROLLED METHODS
+       // FILTER METHODS
        //
 
        @Override
@@ -81,10 +81,6 @@ public class FileSource extends AbstractControlledComponent implements Source {
                return Collections.emptyList();
        }
 
-       //
-       // SOURCE METHODS
-       //
-
        @Override
        public byte[] get(int bufferSize) throws IOException {
                byte[] buffer = new byte[bufferSize];
index 80c3f56..b8afd82 100644 (file)
@@ -27,21 +27,20 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.logging.Logger;
 import javax.swing.event.EventListenerList;
 
-import net.pterodactylus.sonitus.data.AbstractControlledComponent;
+import net.pterodactylus.sonitus.data.AbstractFilter;
 import net.pterodactylus.sonitus.data.Controller;
+import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.data.Metadata;
-import net.pterodactylus.sonitus.data.Source;
 
 import com.google.inject.Inject;
 
 /**
- * {@link Source} implementation that simply forwards another source and
- * supports changing the source without letting the {@link
- * net.pterodactylus.sonitus.data.Sink} know.
+ * {@link Filter} implementation that simply forwards data from another filter
+ * and supports changing the source without letting downstream filters know.
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class MultiSource extends AbstractControlledComponent implements Source {
+public class MultiSource extends AbstractFilter {
 
        /** The logger. */
        private static final Logger logger = Logger.getLogger(MultiSource.class.getName());
@@ -50,7 +49,7 @@ public class MultiSource extends AbstractControlledComponent implements Source {
        private final EventListenerList sourceFinishedListeners = new EventListenerList();
 
        /** The current source. */
-       private final AtomicReference<Source> source = new AtomicReference<Source>();
+       private final AtomicReference<Filter> source = new AtomicReference<Filter>();
 
        /** Whether the source was changed. */
        private boolean sourceChanged;
@@ -95,10 +94,10 @@ public class MultiSource extends AbstractControlledComponent implements Source {
         * @param source
         *              The new source to use
         */
-       public void setSource(Source source) {
+       public void setSource(Filter source) {
                checkNotNull(source, "source must not be null");
 
-               Source oldSource = this.source.getAndSet(source);
+               Filter oldSource = this.source.getAndSet(source);
                if (!source.equals(oldSource)) {
                        synchronized (this.source) {
                                sourceChanged = true;
@@ -115,7 +114,7 @@ public class MultiSource extends AbstractControlledComponent implements Source {
 
        /**
         * Notifies all registered listeners that the current source finished playing
-        * and that a new source should be {@link #setSource(Source) set}.
+        * and that a new source should be {@link #setSource(Filter) set}.
         *
         * @see SourceFinishedListener
         */
@@ -126,7 +125,7 @@ public class MultiSource extends AbstractControlledComponent implements Source {
        }
 
        //
-       // CONTROLLED METHODS
+       // FILTER METHODS
        //
 
        @Override
@@ -144,10 +143,6 @@ public class MultiSource extends AbstractControlledComponent implements Source {
                return super.metadata();
        }
 
-       //
-       // SOURCE METHODS
-       //
-
        @Override
        public byte[] get(int bufferSize) throws EOFException, IOException {
                while (true) {
@@ -167,7 +162,7 @@ public class MultiSource extends AbstractControlledComponent implements Source {
        // PRIVATE METHODS
        //
 
-       /** Waits for a new source to be {@link #setSource(Source) set}. */
+       /** Waits for a new source to be {@link #setSource(Filter) set}. */
        private void waitForNewSource() {
                fireSourceFinished();
                synchronized (source) {
index 35ad426..63c1eee 100644 (file)
@@ -19,8 +19,6 @@ package net.pterodactylus.sonitus.data.source;
 
 import java.util.EventListener;
 
-import net.pterodactylus.sonitus.data.Source;
-
 /**
  * Interface for {@link MultiSource} notifications if a source is finished
  * playing.
index dc6e4d0..a66fb7a 100644 (file)
@@ -27,12 +27,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.logging.Logger;
 
-import net.pterodactylus.sonitus.data.AbstractControlledComponent;
+import net.pterodactylus.sonitus.data.AbstractFilter;
 import net.pterodactylus.sonitus.data.ContentMetadata;
 import net.pterodactylus.sonitus.data.Controller;
 import net.pterodactylus.sonitus.data.FormatMetadata;
 import net.pterodactylus.sonitus.data.Metadata;
-import net.pterodactylus.sonitus.data.Source;
 import net.pterodactylus.sonitus.io.MetadataStream;
 
 import com.google.common.base.Optional;
@@ -47,7 +46,7 @@ import com.google.common.primitives.Ints;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class StreamSource extends AbstractControlledComponent implements Source {
+public class StreamSource extends AbstractFilter {
 
        /** The logger. */
        private static final Logger logger = Logger.getLogger(StreamSource.class.getName());
@@ -127,7 +126,7 @@ public class StreamSource extends AbstractControlledComponent implements Source
        }
 
        //
-       // CONTROLLED METHODS
+       // FILTER METHODS
        //
 
        @Override
@@ -140,10 +139,6 @@ public class StreamSource extends AbstractControlledComponent implements Source
                return Collections.emptyList();
        }
 
-       //
-       // SOURCE METHODS
-       //
-
        @Override
        public Metadata metadata() {
                Optional<ContentMetadata> streamMetadata = metadataStream.getContentMetadata();
diff --git a/src/main/java/net/pterodactylus/sonitus/gui/ComponentInfoPanel.java b/src/main/java/net/pterodactylus/sonitus/gui/ComponentInfoPanel.java
deleted file mode 100644 (file)
index 752ceef..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Sonitus - ComponentInfoPanel.java - Copyright © 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sonitus.gui;
-
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-
-import net.pterodactylus.sonitus.data.ControlledComponent;
-import net.pterodactylus.sonitus.data.Controller;
-import net.pterodactylus.sonitus.data.FormatMetadata;
-import net.pterodactylus.sonitus.data.controller.Fader;
-import net.pterodactylus.sonitus.data.controller.Knob;
-import net.pterodactylus.sonitus.data.controller.Switch;
-
-import com.google.common.base.Optional;
-
-/**
- * Panel that shows information about a {@link ControlledComponent}.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class ComponentInfoPanel extends JPanel {
-
-       /** The name of the component. */
-       private final JLabel headerLabel = new JLabel();
-
-       /** The number of received input bytes. */
-       private final JLabel inputLabel = new JLabel();
-
-       /** The number of sent output bytes. */
-       private final JLabel outputLabel = new JLabel();
-
-       /** The current format metadata. */
-       private final JLabel formatLabel = new JLabel();
-
-       /**
-        * Creates a new component info panel.
-        *
-        * @param controlledComponent
-        *              The component to display
-        */
-       public ComponentInfoPanel(ControlledComponent controlledComponent) {
-               super(new GridBagLayout());
-
-               setPreferredSize(new Dimension(300, 0));
-               createPanel(controlledComponent);
-       }
-
-       //
-       // ACTIONS
-       //
-
-       /**
-        * Sets the number of received input bytes.
-        *
-        * @param input
-        *              The number of received input bytes
-        * @return This panel
-        */
-       public ComponentInfoPanel input(Optional<Long> input) {
-               if (input.isPresent()) {
-                       inputLabel.setText(format(input.get()));
-               } else {
-                       inputLabel.setText("");
-               }
-               return this;
-       }
-
-       /**
-        * Sets the number of sent output bytes.
-        *
-        * @param output
-        *              The number of sent output input bytes
-        * @return This panel
-        */
-       public ComponentInfoPanel output(Optional<Long> output) {
-               if (output.isPresent()) {
-                       outputLabel.setText(format(output.get()));
-               } else {
-                       outputLabel.setText("");
-               }
-               return this;
-       }
-
-       /**
-        * Sets the current format metadata.
-        *
-        * @param metadata
-        *              The format metadata
-        * @return This panel
-        */
-       public ComponentInfoPanel format(Optional<FormatMetadata> metadata) {
-               if (metadata.isPresent()) {
-                       formatLabel.setText(metadata.get().toString());
-               } else {
-                       formatLabel.setText("");
-               }
-               return this;
-       }
-
-       //
-       // PRIVATE METHODS
-       //
-
-       /**
-        * Creates the panel for the given controlled component.
-        *
-        * @param controlledComponent
-        *              The controlled component
-        */
-       private void createPanel(ControlledComponent controlledComponent) {
-               setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
-
-               headerLabel.setText(controlledComponent.name());
-               headerLabel.setFont(headerLabel.getFont().deriveFont(Font.BOLD));
-
-               int line = 0;
-               add(headerLabel, new GridBagConstraints(0, line++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
-               add(new JLabel("Input"), new GridBagConstraints(0, line, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(18, 0, 0, 0), 0, 0));
-               add(inputLabel, new GridBagConstraints(1, line++, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(18, 6, 0, 0), 0, 0));
-               add(new JLabel("Output"), new GridBagConstraints(0, line, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
-               add(outputLabel, new GridBagConstraints(1, line++, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-               add(new JLabel("Format"), new GridBagConstraints(0, line, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
-               add(formatLabel, new GridBagConstraints(1, line++, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
-               /* add the controllers. */
-               for (Controller<?> controller : controlledComponent.controllers()) {
-                       add(new JLabel(controller.name()), new GridBagConstraints(0, line, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(6, 0, 0, 6), 0, 0));
-                       if (controller instanceof Fader) {
-                               add(new FaderPanel((Fader) controller), new GridBagConstraints(1, line++, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0));
-                       } else if (controller instanceof Switch) {
-                               add(new SwitchPanel((Switch) controller), new GridBagConstraints(1, line++, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0));
-                       } else if (controller instanceof Knob) {
-                               add(new KnobPanel((Knob) controller), new GridBagConstraints(1, line++, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0));
-                       }
-               }
-
-               add(Box.createVerticalGlue(), new GridBagConstraints(1, line++, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(6, 6, 0, 0), 0, 0));
-       }
-
-       /**
-        * Formats the number using SI prefixes so that a maximum of 3 digits are
-        * shown.
-        *
-        * @param number
-        *              The number to format
-        * @return The formatted number
-        */
-       private static String format(long number) {
-               String[] prefixes = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
-               double shortenedNumber = number;
-               for (String prefix : prefixes) {
-                       if (shortenedNumber < 1000) {
-                               return String.format("%.1f %sB", shortenedNumber, prefix);
-                       }
-                       shortenedNumber /= 1024;
-               }
-               return String.format("%.1e B", (double) number);
-       }
-
-}
diff --git a/src/main/java/net/pterodactylus/sonitus/gui/FilterInfoPanel.java b/src/main/java/net/pterodactylus/sonitus/gui/FilterInfoPanel.java
new file mode 100644 (file)
index 0000000..b26afe9
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Sonitus - FilterInfoPanel.java - Copyright © 2013 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sonitus.gui;
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import net.pterodactylus.sonitus.data.Controller;
+import net.pterodactylus.sonitus.data.Filter;
+import net.pterodactylus.sonitus.data.FormatMetadata;
+import net.pterodactylus.sonitus.data.controller.Fader;
+import net.pterodactylus.sonitus.data.controller.Knob;
+import net.pterodactylus.sonitus.data.controller.Switch;
+
+import com.google.common.base.Optional;
+
+/**
+ * Panel that shows information about a {@link Filter}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class FilterInfoPanel extends JPanel {
+
+       /** The name of the filter. */
+       private final JLabel headerLabel = new JLabel();
+
+       /** The number of received input bytes. */
+       private final JLabel inputLabel = new JLabel();
+
+       /** The number of sent output bytes. */
+       private final JLabel outputLabel = new JLabel();
+
+       /** The current format metadata. */
+       private final JLabel formatLabel = new JLabel();
+
+       /**
+        * Creates a new filter info panel.
+        *
+        * @param filter
+        *              The filter to display
+        */
+       public FilterInfoPanel(Filter filter) {
+               super(new GridBagLayout());
+
+               setPreferredSize(new Dimension(300, 0));
+               createPanel(filter);
+       }
+
+       //
+       // ACTIONS
+       //
+
+       /**
+        * Sets the number of received input bytes.
+        *
+        * @param input
+        *              The number of received input bytes
+        * @return This panel
+        */
+       public FilterInfoPanel input(Optional<Long> input) {
+               if (input.isPresent()) {
+                       inputLabel.setText(format(input.get()));
+               } else {
+                       inputLabel.setText("");
+               }
+               return this;
+       }
+
+       /**
+        * Sets the number of sent output bytes.
+        *
+        * @param output
+        *              The number of sent output input bytes
+        * @return This panel
+        */
+       public FilterInfoPanel output(Optional<Long> output) {
+               if (output.isPresent()) {
+                       outputLabel.setText(format(output.get()));
+               } else {
+                       outputLabel.setText("");
+               }
+               return this;
+       }
+
+       /**
+        * Sets the current format metadata.
+        *
+        * @param metadata
+        *              The format metadata
+        * @return This panel
+        */
+       public FilterInfoPanel format(Optional<FormatMetadata> metadata) {
+               if (metadata.isPresent()) {
+                       formatLabel.setText(metadata.get().toString());
+               } else {
+                       formatLabel.setText("");
+               }
+               return this;
+       }
+
+       //
+       // PRIVATE METHODS
+       //
+
+       /**
+        * Creates the panel for the given filter.
+        *
+        * @param filter
+        *              The filter to create a panel for
+        */
+       private void createPanel(Filter filter) {
+               setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
+
+               headerLabel.setText(filter.name());
+               headerLabel.setFont(headerLabel.getFont().deriveFont(Font.BOLD));
+
+               int line = 0;
+               add(headerLabel, new GridBagConstraints(0, line++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+               add(new JLabel("Input"), new GridBagConstraints(0, line, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(18, 0, 0, 0), 0, 0));
+               add(inputLabel, new GridBagConstraints(1, line++, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(18, 6, 0, 0), 0, 0));
+               add(new JLabel("Output"), new GridBagConstraints(0, line, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
+               add(outputLabel, new GridBagConstraints(1, line++, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+               add(new JLabel("Format"), new GridBagConstraints(0, line, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
+               add(formatLabel, new GridBagConstraints(1, line++, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+               /* add the controllers. */
+               for (Controller<?> controller : filter.controllers()) {
+                       add(new JLabel(controller.name()), new GridBagConstraints(0, line, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(6, 0, 0, 6), 0, 0));
+                       if (controller instanceof Fader) {
+                               add(new FaderPanel((Fader) controller), new GridBagConstraints(1, line++, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0));
+                       } else if (controller instanceof Switch) {
+                               add(new SwitchPanel((Switch) controller), new GridBagConstraints(1, line++, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0));
+                       } else if (controller instanceof Knob) {
+                               add(new KnobPanel((Knob) controller), new GridBagConstraints(1, line++, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0));
+                       }
+               }
+
+               add(Box.createVerticalGlue(), new GridBagConstraints(1, line++, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(6, 6, 0, 0), 0, 0));
+       }
+
+       /**
+        * Formats the number using SI prefixes so that a maximum of 3 digits are
+        * shown.
+        *
+        * @param number
+        *              The number to format
+        * @return The formatted number
+        */
+       private static String format(long number) {
+               String[] prefixes = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
+               double shortenedNumber = number;
+               for (String prefix : prefixes) {
+                       if (shortenedNumber < 1000) {
+                               return String.format("%.1f %sB", shortenedNumber, prefix);
+                       }
+                       shortenedNumber /= 1024;
+               }
+               return String.format("%.1e B", (double) number);
+       }
+
+}
index bb69578..85a49fb 100644 (file)
@@ -30,9 +30,9 @@ import javax.swing.JTabbedPane;
 import javax.swing.Timer;
 import javax.swing.WindowConstants;
 
-import net.pterodactylus.sonitus.data.ControlledComponent;
+import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.data.Pipeline;
-import net.pterodactylus.sonitus.gui.PipelinePanel.ComponentSelectionListener;
+import net.pterodactylus.sonitus.gui.PipelinePanel.FilterSelectionListener;
 import net.pterodactylus.sonitus.main.Version;
 
 import com.google.common.base.Optional;
@@ -48,7 +48,7 @@ public class MainWindow extends JFrame {
        /** The pipeline to display. */
        private final Pipeline pipeline;
 
-       /** The tabbed pane displaying all controlled components. */
+       /** The tabbed pane displaying all pipelines. */
        private final JTabbedPane tabbedPane = new JTabbedPane();
 
        /** The info panel card layout. */
@@ -57,8 +57,8 @@ public class MainWindow extends JFrame {
        /** The info panel. */
        private final JPanel infoPanel = new JPanel(infoPanelCardLayout);
 
-       /** The mapping from controlled components to info panels. */
-       private final Map<ControlledComponent, ComponentInfoPanel> controlledInfoPanels = Maps.newHashMap();
+       /** The mapping from filters to info panels. */
+       private final Map<Filter, FilterInfoPanel> filterInfoPanels = Maps.newHashMap();
 
        /**
         * Creates a new main window.
@@ -72,11 +72,11 @@ public class MainWindow extends JFrame {
                tabbedPane.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
                final JPanel pipelineInfoPanel = new JPanel(new BorderLayout(12, 12));
                PipelinePanel pipelinePanel = new PipelinePanel(pipeline);
-               pipelinePanel.addComponentHoverListener(new ComponentSelectionListener() {
+               pipelinePanel.addFilterSelectionListener(new FilterSelectionListener() {
 
                        @Override
-                       public void componentSelected(ControlledComponent controlledComponent) {
-                               infoPanelCardLayout.show(infoPanel, controlledComponent.name());
+                       public void filterSelected(Filter filter) {
+                               infoPanelCardLayout.show(infoPanel, filter.name());
                        }
                });
                pipelineInfoPanel.add(pipelinePanel, BorderLayout.CENTER);
@@ -85,11 +85,11 @@ public class MainWindow extends JFrame {
                getContentPane().add(tabbedPane, BorderLayout.CENTER);
                setSize(new Dimension(800, 450));
 
-               /* create info panels for all components. */
-               for (ControlledComponent controlledComponent : pipeline) {
-                       ComponentInfoPanel componentInfoPanel = new ComponentInfoPanel(controlledComponent);
-                       infoPanel.add(componentInfoPanel, controlledComponent.name());
-                       controlledInfoPanels.put(controlledComponent, componentInfoPanel);
+               /* create info panels for all filters. */
+               for (Filter fliter : pipeline) {
+                       FilterInfoPanel filterInfoPanel = new FilterInfoPanel(fliter);
+                       infoPanel.add(filterInfoPanel, fliter.name());
+                       filterInfoPanels.put(fliter, filterInfoPanel);
                }
 
                Timer timer = new Timer(250, new ActionListener() {
@@ -97,11 +97,11 @@ public class MainWindow extends JFrame {
                        @Override
                        public void actionPerformed(ActionEvent actionEvent) {
                                /* update all info panels. */
-                               for (ControlledComponent controlled : MainWindow.this.pipeline) {
-                                       ComponentInfoPanel componentInfoPanel = controlledInfoPanels.get(controlled);
-                                       componentInfoPanel.input(MainWindow.this.pipeline.trafficCounter(controlled).input());
-                                       componentInfoPanel.output(MainWindow.this.pipeline.trafficCounter(controlled).output());
-                                       componentInfoPanel.format(Optional.of(controlled.metadata().format()));
+                               for (Filter filter : MainWindow.this.pipeline) {
+                                       FilterInfoPanel filterInfoPanel = filterInfoPanels.get(filter);
+                                       filterInfoPanel.input(MainWindow.this.pipeline.trafficCounter(filter).input());
+                                       filterInfoPanel.output(MainWindow.this.pipeline.trafficCounter(filter).output());
+                                       filterInfoPanel.format(Optional.of(filter.metadata().format()));
                                }
                        }
                });
index d47003d..93189ef 100644 (file)
@@ -38,15 +38,13 @@ import javax.swing.JPanel;
 import javax.swing.UIManager;
 import javax.swing.event.EventListenerList;
 
-import net.pterodactylus.sonitus.data.ControlledComponent;
+import net.pterodactylus.sonitus.data.Filter;
 import net.pterodactylus.sonitus.data.Metadata;
 import net.pterodactylus.sonitus.data.MetadataListener;
 import net.pterodactylus.sonitus.data.Pipeline;
-import net.pterodactylus.sonitus.data.Sink;
-import net.pterodactylus.sonitus.data.Source;
 
 /**
- * {@link JPanel} that displays all components of a {@link Pipeline}.
+ * {@link JPanel} that displays all filters of a {@link Pipeline}.
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
@@ -58,11 +56,11 @@ public class PipelinePanel extends JPanel {
        /** The pipeline being displayed. */
        private final Pipeline pipeline;
 
-       /** The component hover listeners. */
-       private final EventListenerList componentSelectionListeners = new EventListenerList();
+       /** The filter selection listeners. */
+       private final EventListenerList filterSelectionListeners = new EventListenerList();
 
-       /** The currently selected component. */
-       private JComponent selectedComponent;
+       /** The currently selected filter. */
+       private JComponent selectedFilter;
 
        /**
         * Creates a new pipeline panel displaying the given pipeline.
@@ -81,13 +79,13 @@ public class PipelinePanel extends JPanel {
        //
 
        /**
-        * Adds the given component selection listener to this panel.
+        * Adds the given filter selection listener to this panel.
         *
-        * @param componentSelectionListener
-        *              The component selection listener to add
+        * @param filterSelectionListener
+        *              The filter selection listener to add
         */
-       public void addComponentHoverListener(ComponentSelectionListener componentSelectionListener) {
-               componentSelectionListeners.add(ComponentSelectionListener.class, componentSelectionListener);
+       public void addFilterSelectionListener(FilterSelectionListener filterSelectionListener) {
+               filterSelectionListeners.add(FilterSelectionListener.class, filterSelectionListener);
        }
 
        //
@@ -99,16 +97,11 @@ public class PipelinePanel extends JPanel {
                /* clear everything. */
                removeAll();
 
-               /* count all sinks. */
+               /* count all filters. */
                int sinkCount = 0;
-               for (ControlledComponent component : pipeline.components()) {
-                       if (!(component instanceof Source)) {
-                               logger.finest(String.format("%s is not a Source, skipping.", component.name()));
-                               sinkCount++;
-                               continue;
-                       }
-                       Collection<Sink> sinks = pipeline.sinks((Source) component);
-                       logger.finest(String.format("%s has %d sinks: %s", component.name(), sinks.size(), sinks));
+               for (Filter filter : pipeline.filters()) {
+                       Collection<Filter> sinks = pipeline.filters(filter);
+                       logger.finest(String.format("%s has %d filters: %s", filter.name(), sinks.size(), sinks));
                        if (sinks.isEmpty()) {
                                sinkCount++;
                        }
@@ -120,120 +113,119 @@ public class PipelinePanel extends JPanel {
                        gridCellCount *= n;
                }
 
-               /* paint all components recursively. */
-               addControlled(pipeline.source(), 0, 0, gridCellCount, null);
+               /* paint all filters recursively. */
+               addFilter(pipeline.source(), 0, 0, gridCellCount, null);
        }
 
        /**
-        * Displays the given component.
+        * Displays the given filter.
         *
-        * @param controlledComponent
-        *              The component to add this panel.
+        * @param filter
+        *              The filter to add this panel.
         * @param level
-        *              The level at which to show the component (the source is level {@code 0})
+        *              The level at which to show the filter (the source is level {@code 0})
         * @param position
-        *              The position at which to display the component
+        *              The position at which to display the filter
         * @param width
-        *              The width of the component in grid cells
+        *              The width of the filter in grid cells
         */
-       private void addControlled(final ControlledComponent controlledComponent, int level, int position, int width, ControlledComponent parentComponent) {
-               /* create a GUI component that displays the component. */
-               final JPanel componentPanel = createComponentPanel(controlledComponent, parentComponent);
-               componentPanel.addMouseListener(new MouseAdapter() {
+       private void addFilter(final Filter filter, int level, int position, int width, Filter parentFilter) {
+               /* create a GUI component that displays the filter. */
+               final JPanel filterPanel = createFilterPanel(filter, parentFilter);
+               filterPanel.addMouseListener(new MouseAdapter() {
 
                        @Override
                        public void mouseClicked(MouseEvent e) {
                                for (Component component : getComponents()) {
                                        component.setBackground(UIManager.getColor("Panel.background"));
                                }
-                               for (ComponentSelectionListener componentSelectionListener : componentSelectionListeners.getListeners(ComponentSelectionListener.class)) {
-                                       componentPanel.setBackground(Color.LIGHT_GRAY);
-                                       componentSelectionListener.componentSelected(controlledComponent);
+                               for (FilterSelectionListener filterSelectionListener : filterSelectionListeners.getListeners(FilterSelectionListener.class)) {
+                                       filterPanel.setBackground(Color.LIGHT_GRAY);
+                                       filterSelectionListener.filterSelected(filter);
                                }
-                               selectedComponent = componentPanel;
+                               selectedFilter = filterPanel;
                        }
 
                        @Override
                        public void mouseEntered(MouseEvent mouseEvent) {
-                               if (componentPanel != selectedComponent) {
-                                       componentPanel.setBackground(Color.white);
+                               if (filterPanel != selectedFilter) {
+                                       filterPanel.setBackground(Color.white);
                                }
                        }
 
                        @Override
                        public void mouseExited(MouseEvent mouseEvent) {
-                               if (componentPanel != selectedComponent) {
-                                       componentPanel.setBackground(UIManager.getColor("Panel.background"));
+                               if (filterPanel != selectedFilter) {
+                                       filterPanel.setBackground(UIManager.getColor("Panel.background"));
                                }
                        }
                });
 
-               /* show component. */
-               add(componentPanel, new GridBagConstraints(position, level, width, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
+               /* show filter. */
+               add(filterPanel, new GridBagConstraints(position, level, width, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
 
-               /* if the component does not have connected sinks, exit here. */
-               if (!(controlledComponent instanceof Source)) {
+               /* if the filter does not have connected filters, exit here. */
+               Collection<Filter> sinks = pipeline.filters(filter);
+               if (sinks.isEmpty()) {
                        add(new JPanel(), new GridBagConstraints(position, 999, width, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
                        return;
                }
 
-               /* iterate over the component’s sinks. */
-               Collection<Sink> sinks = pipeline.sinks((Source) controlledComponent);
+               /* iterate over the filter’s connected filters. */
                if (!sinks.isEmpty()) {
                        int sinkWidth = width / sinks.size();
                        int sinkIndex = 0;
-                       for (Sink connectedSink : sinks) {
-                               /* distribute all sinks evenly below this source. */
-                               addControlled(connectedSink, level + 1, position + sinkIndex * sinkWidth, sinkWidth, controlledComponent);
+                       for (Filter connectedSink : sinks) {
+                               /* distribute all filters evenly below this source. */
+                               addFilter(connectedSink, level + 1, position + sinkIndex * sinkWidth, sinkWidth, filter);
                                sinkIndex++;
                        }
                }
        }
 
        /**
-        * Creates a panel displaying a single component.
+        * Creates a panel displaying a single filter.
         *
-        * @param controlledComponent
-        *              The component to display
+        * @param filter
+        *              The filter to display
         * @return The created panel
         */
-       private static JPanel createComponentPanel(final ControlledComponent controlledComponent, final ControlledComponent parentComponent) {
-               JPanel componentPanel = new JPanel(new BorderLayout(12, 12));
-               componentPanel.setBorder(createCompoundBorder(createEtchedBorder(), createEmptyBorder(0, 4, 0, 3)));
-               componentPanel.add(new JLabel(controlledComponent.name()), BorderLayout.WEST);
-               final JLabel titleLabel = new JLabel(controlledComponent.metadata().fullTitle());
+       private static JPanel createFilterPanel(final Filter filter, final Filter parentFilter) {
+               JPanel filterPanel = new JPanel(new BorderLayout(12, 12));
+               filterPanel.setBorder(createCompoundBorder(createEtchedBorder(), createEmptyBorder(0, 4, 0, 3)));
+               filterPanel.add(new JLabel(filter.name()), BorderLayout.WEST);
+               final JLabel titleLabel = new JLabel(filter.metadata().fullTitle());
                titleLabel.setFont(titleLabel.getFont().deriveFont(titleLabel.getFont().getSize2D() * 0.8f));
-               componentPanel.add(titleLabel, BorderLayout.EAST);
-               if (parentComponent != null) {
-                       titleLabel.setVisible(!parentComponent.metadata().fullTitle().equals(controlledComponent.metadata().fullTitle()));
+               filterPanel.add(titleLabel, BorderLayout.EAST);
+               if (parentFilter != null) {
+                       titleLabel.setVisible(!parentFilter.metadata().fullTitle().equals(filter.metadata().fullTitle()));
                }
-               controlledComponent.addMetadataListener(new MetadataListener() {
+               filter.addMetadataListener(new MetadataListener() {
 
                        @Override
-                       public void metadataUpdated(ControlledComponent component, Metadata metadata) {
+                       public void metadataUpdated(Filter filter, Metadata metadata) {
                                titleLabel.setText(metadata.fullTitle());
-                               titleLabel.setVisible((parentComponent == null) || !parentComponent.metadata().fullTitle().equals(metadata.fullTitle()));
+                               titleLabel.setVisible((parentFilter == null) || !parentFilter.metadata().fullTitle().equals(metadata.fullTitle()));
                        }
                });
-               return componentPanel;
+               return filterPanel;
        }
 
        /**
         * Interface for objects that want to be notified if the user moves the mouse
-        * cursor over a controlled component.
+        * cursor over a filter.
         *
         * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
         */
-       public static interface ComponentSelectionListener extends EventListener {
+       public static interface FilterSelectionListener extends EventListener {
 
                /**
-                * Notifies the listener that the mouse is now over the given controlled
-                * component.
+                * Notifies the listener that the mouse is now over the given filter.
                 *
-                * @param controlledComponent
-                *              The controlled component now under the mouse
+                * @param filter
+                *              The filter now under the mouse
                 */
-               void componentSelected(ControlledComponent controlledComponent);
+               void filterSelected(Filter filter);
 
        }
 
index e3350a7..dba2f3c 100644 (file)
@@ -22,9 +22,7 @@ import java.awt.GridBagLayout;
 import java.awt.Insets;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import javax.swing.BorderFactory;
 import javax.swing.JCheckBox;
-import javax.swing.JLabel;
 import javax.swing.JPanel;
 
 import net.pterodactylus.sonitus.data.controller.Switch;
@@ -39,8 +37,8 @@ public class SwitchPanel extends JPanel {
        /**
         * Creates a new fader panel.
         *
-        * @param fader
-        *              The fader being controlled
+        * @param switchController
+        *              The switch being controlled
         */
        public SwitchPanel(final Switch switchController) {
                super(new GridBagLayout());