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