1 package org.opendaylight.controller.md.sal.common.impl.routing;
3 import java.util.Map.Entry;
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;
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;
18 * Base abstract implementation of DataReadRouter, which performs
19 * a read operation on multiple data readers and then merges result.
24 public abstract class AbstractDataReadRouter<P extends Path<P>, D> implements DataReader<P, D> {
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());
30 public D readConfigurationData(P path) {
31 FluentIterable<D> dataBits = FluentIterable //
32 .from(getReaders(configReaders, path)).transform(configurationRead(path));
33 return merge(path,dataBits);
37 public D readOperationalData(P path) {
38 FluentIterable<D> dataBits = FluentIterable //
39 .from(getReaders(operationalReaders, path)).transform(operationalRead(path));
40 return merge(path,dataBits);
45 * Merges data readed by reader instances from specified path
47 * @param path Path on which read was performed
48 * @param data Data which was returned by read operation.
49 * @return Merged result.
51 protected abstract D merge(P path,Iterable<D> data);
54 * Returns a function which performs configuration read for supplied path
57 * @return function which performs configuration read for supplied path
60 private Function<DataReader<P, D>, D> configurationRead(final P path) {
61 return new Function<DataReader<P, D>, D>() {
63 public D apply(DataReader<P, D> input) {
64 return input.readConfigurationData(path);
70 * Returns a function which performs operational read for supplied path
73 * @return function which performs operational read for supplied path
75 private Function<DataReader<P, D>, D> operationalRead(final P path) {
76 return new Function<DataReader<P, D>, D>() {
78 public D apply(DataReader<P, D> input) {
79 return input.readOperationalData(path);
87 * Register's a reader for operational data.
89 * @param path Path which is served by this reader
90 * @param reader Reader instance which is responsible for reading particular subpath.
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);
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);
105 Iterable<DataReader<P, D>> getOperationalReaders(P path) {
106 return getReaders(operationalReaders, path);
109 Iterable<DataReader<P, D>> getConfigurationReaders(P path) {
110 return getReaders(configReaders, path);
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());
120 private void removeRegistration(OperationalDataReaderRegistration<?, ?> registration) {
121 operationalReaders.remove(registration.getKey(), registration);
124 private void removeRegistration(ConfigurationDataReaderRegistration<?, ?> registration) {
125 configReaders.remove(registration.getKey(), registration);
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>>() {
131 public DataReader<P, D> apply(Entry<P, DataReaderRegistration<P, D>> input) {
132 return input.getValue().getInstance();
137 private Predicate<? super Entry<P, DataReaderRegistration<P, D>>> affects(final P path) {
139 return new Predicate<Entry<P, DataReaderRegistration<P, D>>>() {
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);
150 @SuppressWarnings("hiding")
151 private class ConfigurationDataReaderRegistration<P extends Path<P>, D> extends DataReaderRegistration<P, D> {
153 public ConfigurationDataReaderRegistration(P key, DataReader<P, D> instance) {
154 super(key, instance);
158 protected void removeRegistration() {
159 AbstractDataReadRouter.this.removeRegistration(this);
163 @SuppressWarnings("hiding")
164 private class OperationalDataReaderRegistration<P extends Path<P>, D> extends DataReaderRegistration<P, D> {
166 public OperationalDataReaderRegistration(P key, DataReader<P, D> instance) {
167 super(key, instance);
171 protected void removeRegistration() {
172 AbstractDataReadRouter.this.removeRegistration(this);
176 private abstract static class DataReaderRegistration<P extends Path<P>, D> extends
177 AbstractObjectRegistration<DataReader<P, D>> {
185 public DataReaderRegistration(P key, DataReader<P, D> instance) {