492db5bdc4349176c2bd8782a56aded176ba98c8
[sonitus.git] / src / main / java / net / pterodactylus / sonitus / data / filter / PipelineFilter.java
1 /*
2  * Sonitus - PipelineFilter.java - Copyright © 2013 David Roden
3  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 package net.pterodactylus.sonitus.data.filter;
19
20 import java.io.IOException;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.List;
24
25 import net.pterodactylus.sonitus.data.AbstractFilter;
26 import net.pterodactylus.sonitus.data.DataPacket;
27 import net.pterodactylus.sonitus.data.Filter;
28 import net.pterodactylus.sonitus.data.Metadata;
29 import net.pterodactylus.sonitus.data.Pipeline.Connection;
30
31 import com.google.common.collect.Lists;
32
33 /**
34  * {@link Filter} that combines several filters into one.
35  *
36  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
37  */
38 public class PipelineFilter extends AbstractFilter implements Filter {
39
40         /** The first filter. */
41         private final Filter source;
42
43         /** All following filters. */
44         private final List<Filter> filters = Lists.newArrayList();
45
46         /** The last filter (for convenience). */
47         private final Filter lastFilter;
48
49         /**
50          * Creates a new pipeline filter.
51          *
52          * @param name
53          *              The name of the filter
54          * @param source
55          *              The first source of the filter
56          * @param filters
57          *              All other filters in correct order
58          */
59         private PipelineFilter(String name, Filter source, Collection<Filter> filters) {
60                 super(name);
61                 this.source = source;
62                 this.filters.addAll(filters);
63                 this.lastFilter = this.filters.get(filters.size() - 1);
64         }
65
66         //
67         // FILTER METHODS
68         //
69
70         @Override
71         public Metadata metadata() {
72                 return lastFilter.metadata();
73         }
74
75         @Override
76         public void open(Metadata metadata) throws IOException {
77                 /* open the source and all filters in the correct order. */
78                 source.open(metadata);
79                 Metadata currentMetadata = source.metadata();
80                 Filter currentSource = source;
81                 for (Filter filter : filters) {
82                         filter.open(currentMetadata);
83                         currentMetadata = filter.metadata();
84                         Connection connection = new Connection(currentSource, Arrays.asList(filter));
85                         String threadName = String.format("%s → %s", connection.source().name(), filter.name());
86                         new Thread(connection, threadName).start();
87                         currentSource = filter;
88                 }
89         }
90
91         @Override
92         public DataPacket get(int bufferSize) throws IOException {
93                 return lastFilter.get(bufferSize);
94         }
95
96         @Override
97         public void process(DataPacket dataPacket) throws IOException {
98                 source.process(dataPacket);
99         }
100
101         //
102         // STATIC METHODS
103         //
104
105         /**
106          * Returns a builder that can create pipeline filters.
107          *
108          * @param source
109          *              The source filter of the pipeline
110          * @return The pipeline filter builder
111          */
112         public static Builder builder(Filter source) {
113                 return new Builder(source);
114         }
115
116         /**
117          * Builder for a {@link PipelineFilter}.
118          *
119          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
120          */
121         public static class Builder {
122
123                 /** The source of the pipeline. */
124                 private final Filter source;
125
126                 /** All other filters of the pipeline. */
127                 private final List<Filter> filters = Lists.newArrayList();
128
129                 /**
130                  * Creates a new builder with the given source.
131                  *
132                  * @param source
133                  *              The source of the pipeline filter
134                  */
135                 private Builder(Filter source) {
136                         this.source = source;
137                 }
138
139                 /**
140                  * Connects the given filter at the end of the pipeline being build.
141                  *
142                  * @param filter
143                  *              The filter to add
144                  * @return This builder
145                  */
146                 public Builder to(Filter filter) {
147                         filters.add(filter);
148                         return this;
149                 }
150
151                 /**
152                  * Builds a filter using the given name. If no filters other than the source
153                  * have been added, only the source filter is being returned.
154                  *
155                  * @param name
156                  *              The name of the pipeline filter to build
157                  * @return The created filter, or the source filter
158                  */
159                 public Filter build(String name) {
160                         if (filters.isEmpty()) {
161                                 return source;
162                         }
163                         return new PipelineFilter(name, source, filters);
164                 }
165
166         }
167
168 }