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