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