2 * Sonitus - PipelineFilter.java - Copyright © 2013 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.sonitus.data.filter;
20 import java.io.IOException;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.List;
25 import java.util.logging.Logger;
27 import net.pterodactylus.sonitus.data.AbstractFilter;
28 import net.pterodactylus.sonitus.data.DataPacket;
29 import net.pterodactylus.sonitus.data.Filter;
30 import net.pterodactylus.sonitus.data.Metadata;
31 import net.pterodactylus.sonitus.data.Pipeline.Connection;
33 import com.google.common.collect.Lists;
34 import com.google.common.collect.Maps;
37 * {@link Filter} that combines several filters into one.
39 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
41 public class PipelineFilter extends AbstractFilter implements Filter {
44 private static final Logger logger = Logger.getLogger(PipelineFilter.class.getName());
46 /** The first filter. */
47 private final Filter source;
49 /** All following filters. */
50 private final List<Filter> filters = Lists.newArrayList();
52 /** The last filter (for convenience). */
53 private final Filter lastFilter;
55 /** The connections for each filter. */
56 private final Map<Filter, Connection> filterConnections = Maps.newHashMap();
59 * Creates a new pipeline filter.
62 * The name of the filter
64 * The first source of the filter
66 * All other filters in correct order
68 private PipelineFilter(String name, Filter source, Collection<Filter> filters) {
71 this.filters.addAll(filters);
72 this.lastFilter = this.filters.get(filters.size() - 1);
80 public Metadata metadata() {
81 return lastFilter.metadata();
85 public void open(Metadata metadata) throws IOException {
86 /* open the source and all filters in the correct order. */
87 source.open(metadata);
88 Metadata currentMetadata = source.metadata();
89 Filter currentSource = source;
90 for (Filter filter : filters) {
91 filter.open(currentMetadata);
92 currentMetadata = filter.metadata();
93 Connection connection = new Connection(currentSource, Arrays.asList(filter));
94 filterConnections.put(filter, connection);
95 String threadName = String.format("%s → %s", connection.source().name(), filter.name());
96 logger.info(String.format("Starting Thread: %s.", threadName));
97 new Thread(connection, threadName).start();
98 currentSource = filter;
100 metadataUpdated(currentMetadata);
104 public DataPacket get(int bufferSize) throws IOException {
105 if (filterConnections.get(lastFilter).ioException().isPresent()) {
106 logger.info(String.format("Rethrowing exception from %s: %s", lastFilter.name(), filterConnections.get(lastFilter).ioException().get().getMessage()));
107 throw filterConnections.get(lastFilter).ioException().get();
109 logger.info(String.format("Requesting %d bytes from %s...", bufferSize, lastFilter.name()));
110 return lastFilter.get(bufferSize);
114 public void process(DataPacket dataPacket) throws IOException {
115 source.process(dataPacket);
123 * Returns a builder that can create pipeline filters.
126 * The source filter of the pipeline
127 * @return The pipeline filter builder
129 public static Builder builder(Filter source) {
130 return new Builder(source);
134 * Builder for a {@link PipelineFilter}.
136 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
138 public static class Builder {
140 /** The source of the pipeline. */
141 private final Filter source;
143 /** All other filters of the pipeline. */
144 private final List<Filter> filters = Lists.newArrayList();
147 * Creates a new builder with the given source.
150 * The source of the pipeline filter
152 private Builder(Filter source) {
153 this.source = source;
157 * Connects the given filter at the end of the pipeline being build.
161 * @return This builder
163 public Builder to(Filter filter) {
169 * Builds a filter using the given name. If no filters other than the source
170 * have been added, only the source filter is being returned.
173 * The name of the pipeline filter to build
174 * @return The created filter, or the source filter
176 public Filter build(String name) {
177 if (filters.isEmpty()) {
180 return new PipelineFilter(name, source, filters);