4ddceb3b5f015a709e508f73cbb91e4cc46e66e0
[controller.git] / opendaylight / md-sal / sal-common-impl / src / main / java / org / opendaylight / controller / md / sal / common / impl / routing / AbstractDataReadRouter.java
1 package org.opendaylight.controller.md.sal.common.impl.routing;
2
3 import java.util.Map.Entry;
4
5 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
6 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
7 import org.opendaylight.yangtools.concepts.Path;
8 import org.opendaylight.yangtools.concepts.Registration;
9
10 import com.google.common.base.Function;
11 import com.google.common.base.Predicate;
12 import com.google.common.collect.FluentIterable;
13 import com.google.common.collect.HashMultimap;
14 import com.google.common.collect.Multimap;
15 import com.google.common.collect.Multimaps;
16
17 /**
18  * Base abstract implementation of DataReadRouter, which performs
19  * a read operation on multiple data readers and then merges result.
20  * 
21  * @param <P>
22  * @param <D>
23  */
24 public abstract class AbstractDataReadRouter<P extends Path<P>, D> implements DataReader<P, D> {
25
26     Multimap<P, DataReaderRegistration<P, D>> configReaders = Multimaps.synchronizedSetMultimap(HashMultimap.<P, DataReaderRegistration<P, D>>create());
27     Multimap<P, DataReaderRegistration<P, D>> operationalReaders = Multimaps.synchronizedSetMultimap(HashMultimap.<P, DataReaderRegistration<P, D>>create());
28
29     @Override
30     public D readConfigurationData(P path) {
31         FluentIterable<D> dataBits = FluentIterable //
32                 .from(getReaders(configReaders, path)).transform(configurationRead(path));
33         return merge(path,dataBits);
34     }
35
36     @Override
37     public D readOperationalData(P path) {
38         FluentIterable<D> dataBits = FluentIterable //
39                 .from(getReaders(operationalReaders, path)).transform(operationalRead(path));
40         return merge(path,dataBits);
41
42     }
43
44     /**
45      * Merges data readed by reader instances from specified path
46      * 
47      * @param path Path on which read was performed
48      * @param data Data which was returned by read operation.
49      * @return Merged result.
50      */
51     protected abstract D merge(P path,Iterable<D> data);
52
53     /**
54      * Returns a function which performs configuration read for supplied path
55      * 
56      * @param path
57      * @return function which performs configuration read for supplied path
58      */
59     
60     private Function<DataReader<P, D>, D> configurationRead(final P path) {
61         return new Function<DataReader<P, D>, D>() {
62             @Override
63             public D apply(DataReader<P, D> input) {
64                 return input.readConfigurationData(path);
65             }
66         };
67     }
68
69     /**
70      * Returns a function which performs operational read for supplied path
71      * 
72      * @param path
73      * @return function which performs operational read for supplied path
74      */
75     private Function<DataReader<P, D>, D> operationalRead(final P path) {
76         return new Function<DataReader<P, D>, D>() {
77             @Override
78             public D apply(DataReader<P, D> input) {
79                 return input.readOperationalData(path);
80             }
81         };
82     }
83
84     // Registrations
85
86     /**
87      * Register's a reader for operational data.
88      * 
89      * @param path Path which is served by this reader
90      * @param reader Reader instance which is responsible for reading particular subpath.
91      * @return 
92      */
93     public Registration<DataReader<P, D>> registerOperationalReader(P path, DataReader<P, D> reader) {
94         OperationalDataReaderRegistration<P, D> ret = new OperationalDataReaderRegistration<>(path, reader);
95         operationalReaders.put(path, ret);
96         return ret;
97     }
98
99     public Registration<DataReader<P, D>> registerConfigurationReader(P path, DataReader<P, D> reader) {
100         ConfigurationDataReaderRegistration<P, D> ret = new ConfigurationDataReaderRegistration<>(path, reader);
101         configReaders.put(path, ret);
102         return ret;
103     }
104
105     Iterable<DataReader<P, D>> getOperationalReaders(P path) {
106         return getReaders(operationalReaders, path);
107     }
108
109     Iterable<DataReader<P, D>> getConfigurationReaders(P path) {
110         return getReaders(configReaders, path);
111     }
112
113     private Iterable<DataReader<P, D>> getReaders(Multimap<P, DataReaderRegistration<P, D>> readerMap, P path) {
114         return FluentIterable
115             .from(readerMap.entries()) //
116             .filter(affects(path)) //
117             .transform(retrieveInstance());
118     }
119
120     private void removeRegistration(OperationalDataReaderRegistration<?, ?> registration) {
121         operationalReaders.remove(registration.getKey(), registration);
122     }
123
124     private void removeRegistration(ConfigurationDataReaderRegistration<?, ?> registration) {
125         configReaders.remove(registration.getKey(), registration);
126     }
127
128     private Function<? super Entry<P, DataReaderRegistration<P, D>>, DataReader<P, D>> retrieveInstance() {
129         return new Function<Entry<P, DataReaderRegistration<P, D>>, DataReader<P,D>>() {
130             @Override
131             public DataReader<P, D> apply(Entry<P, DataReaderRegistration<P, D>> input) {
132                 return input.getValue().getInstance();
133             }
134         };
135     }
136
137     private Predicate<? super Entry<P, DataReaderRegistration<P, D>>> affects(final P path) {
138         
139         return new Predicate<Entry<P, DataReaderRegistration<P, D>>>() {
140             
141             @Override
142             public boolean apply(Entry<P, DataReaderRegistration<P, D>> input) {
143                 final P key = input.getKey();
144                 return key.contains(path) || ((P) path).contains(key);
145             }
146             
147         };
148     }
149
150     @SuppressWarnings("hiding")
151     private class ConfigurationDataReaderRegistration<P extends Path<P>, D> extends DataReaderRegistration<P, D> {
152
153         public ConfigurationDataReaderRegistration(P key, DataReader<P, D> instance) {
154             super(key, instance);
155         }
156
157         @Override
158         protected void removeRegistration() {
159             AbstractDataReadRouter.this.removeRegistration(this);
160         }
161     }
162
163     @SuppressWarnings("hiding")
164     private class OperationalDataReaderRegistration<P extends Path<P>, D> extends DataReaderRegistration<P, D> {
165
166         public OperationalDataReaderRegistration(P key, DataReader<P, D> instance) {
167             super(key, instance);
168         }
169
170         @Override
171         protected void removeRegistration() {
172             AbstractDataReadRouter.this.removeRegistration(this);
173         }
174     }
175
176     private abstract static class DataReaderRegistration<P extends Path<P>, D> extends
177             AbstractObjectRegistration<DataReader<P, D>> {
178
179         private final P key;
180
181         public P getKey() {
182             return this.key;
183         }
184
185         public DataReaderRegistration(P key, DataReader<P, D> instance) {
186             super(instance);
187             this.key = key;
188         }
189     }
190 }