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