HONEYCOMB-359 - Wildcarded writers
[honeycomb.git] / infra / translate-utils / src / main / java / io / fd / honeycomb / translate / util / AbstractSubtreeManagerRegistryBuilderBuilder.java
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package io.fd.honeycomb.translate.util;
18
19 import com.google.common.base.Preconditions;
20 import com.google.common.collect.ImmutableMap;
21 import io.fd.honeycomb.translate.ModifiableSubtreeManagerRegistryBuilder;
22 import io.fd.honeycomb.translate.SubtreeManager;
23 import io.fd.honeycomb.translate.SubtreeManagerRegistryBuilder;
24 import org.opendaylight.yangtools.yang.binding.DataObject;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
26
27 import javax.annotation.Nonnull;
28 import java.util.Collection;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.Set;
32
33 public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends SubtreeManager<? extends DataObject>, R>
34         implements ModifiableSubtreeManagerRegistryBuilder<S>, SubtreeManagerRegistryBuilder<R> {
35
36     private final Map<InstanceIdentifier<?>, S> handlersMap = new HashMap<>();
37     private final YangDAG dag;
38
39     protected AbstractSubtreeManagerRegistryBuilderBuilder(@Nonnull final YangDAG yangDAG) {
40         this.dag = Preconditions.checkNotNull(yangDAG, "yangDAG should not be null");
41     }
42
43     /**
44      * Add handler without any special relationship to any other type.
45      */
46     @Override
47     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> add(@Nonnull final S handler) {
48         // Make IID wildcarded just in case
49         // + the way InstanceIdentifier.create + equals work for Identifiable items is unexpected, meaning updates would
50         // not be matched to writers in registry
51         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
52         checkWriterNotPresentYet(targetType);
53         dag.addVertex(targetType);
54         handlersMap.put(targetType, handler);
55         return this;
56     }
57
58     /**
59      * Add handler without any special relationship to any other type.
60      */
61     @Override
62     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAdd(@Nonnull final Set<InstanceIdentifier<?>> handledChildren,
63                                                                          @Nonnull final S handler) {
64         add(getSubtreeHandler(handledChildren, handler));
65         return this;
66     }
67
68     @Override
69     public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAdd(@Nonnull S handler) {
70         add(getWildcardedSubtreeHandler(handler));
71         return this;
72     }
73
74     private void checkWriterNotPresentYet(final InstanceIdentifier<?> targetType) {
75         Preconditions.checkArgument(!handlersMap.containsKey(targetType),
76                 "Writer for type: %s already present: %s", targetType, handlersMap.get(targetType));
77     }
78
79     /**
80      * Add handler with relationship: to be executed before handler handling relatedType.
81      */
82     @Override
83     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> addBefore(@Nonnull final S handler,
84                                                                         @Nonnull final InstanceIdentifier<?> relatedType) {
85         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
86         final InstanceIdentifier<?> wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType);
87         checkWriterNotPresentYet(targetType);
88         dag.addVertex(targetType);
89         dag.addVertex(wildcardedRelatedType);
90         dag.addEdge(targetType, wildcardedRelatedType);
91         handlersMap.put(targetType, handler);
92         return this;
93     }
94
95     @Override
96     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> addBefore(@Nonnull final S handler,
97                                                                         @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
98         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
99         checkWriterNotPresentYet(targetType);
100         dag.addVertex(targetType);
101         relatedTypes.stream()
102                 .map(RWUtils::makeIidWildcarded)
103                 .forEach(dag::addVertex);
104         relatedTypes.stream()
105                 .map(RWUtils::makeIidWildcarded)
106                 .forEach(type -> dag.addEdge(targetType, type));
107         handlersMap.put(targetType, handler);
108         return this;
109     }
110
111     @Override
112     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddBefore(
113             @Nonnull final Set<InstanceIdentifier<?>> handledChildren,
114             @Nonnull final S handler,
115             @Nonnull final InstanceIdentifier<?> relatedType) {
116         return addBefore(getSubtreeHandler(handledChildren, handler), relatedType);
117     }
118
119     @Override
120     public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddBefore(@Nonnull final S handler,
121                                                                                  @Nonnull final InstanceIdentifier<?> relatedType) {
122         return addBefore(getWildcardedSubtreeHandler(handler), relatedType);
123     }
124
125     @Override
126     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddBefore(
127             @Nonnull final Set<InstanceIdentifier<?>> handledChildren,
128             @Nonnull final S handler,
129             @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
130         return addBefore(getSubtreeHandler(handledChildren, handler), relatedTypes);
131     }
132
133     @Override
134     public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddBefore(@Nonnull final S handler,
135                                                                                  @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
136         return addBefore(getWildcardedSubtreeHandler(handler), relatedTypes);
137     }
138
139     protected abstract S getSubtreeHandler(@Nonnull final Set<InstanceIdentifier<?>> handledChildren,
140                                            @Nonnull final S handler);
141
142     protected abstract S getWildcardedSubtreeHandler(@Nonnull final S handler);
143
144     /**
145      * Add handler with relationship: to be executed after handler handling relatedType.
146      */
147     @Override
148     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> addAfter(@Nonnull final S handler,
149                                                                        @Nonnull final InstanceIdentifier<?> relatedType) {
150         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
151         final InstanceIdentifier<?> wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType);
152         checkWriterNotPresentYet(targetType);
153         dag.addVertex(targetType);
154         dag.addVertex(wildcardedRelatedType);
155         // set edge to indicate before relationship, just reversed
156         dag.addEdge(wildcardedRelatedType, targetType);
157         handlersMap.put(targetType, handler);
158         return this;
159     }
160
161     @Override
162     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> addAfter(@Nonnull final S handler,
163                                                                        @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
164         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
165         checkWriterNotPresentYet(targetType);
166         dag.addVertex(targetType);
167         relatedTypes.stream()
168                 .map(RWUtils::makeIidWildcarded)
169                 .forEach(dag::addVertex);
170         // set edge to indicate before relationship, just reversed
171         relatedTypes.stream()
172                 .map(RWUtils::makeIidWildcarded)
173                 .forEach(type -> dag.addEdge(type, targetType));
174         handlersMap.put(targetType, handler);
175         return this;
176     }
177
178     @Override
179     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddAfter(
180             @Nonnull final Set<InstanceIdentifier<?>> handledChildren,
181             @Nonnull final S handler,
182             @Nonnull final InstanceIdentifier<?> relatedType) {
183         return addAfter(getSubtreeHandler(handledChildren, handler), relatedType);
184     }
185
186     @Override
187     public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddAfter(@Nonnull final S handler,
188                                                                                 @Nonnull final InstanceIdentifier<?> relatedType) {
189         return addAfter(getWildcardedSubtreeHandler(handler), relatedType);
190     }
191
192     @Override
193     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddAfter(
194             @Nonnull final Set<InstanceIdentifier<?>> handledChildren,
195             @Nonnull final S handler,
196             @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
197         return addAfter(getSubtreeHandler(handledChildren, handler), relatedTypes);
198     }
199
200     @Override
201     public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddAfter(@Nonnull S handler, @Nonnull Collection<InstanceIdentifier<?>> relatedTypes) {
202         return addAfter(getWildcardedSubtreeHandler(handler), relatedTypes);
203     }
204
205     protected ImmutableMap<InstanceIdentifier<?>, S> getMappedHandlers() {
206         final ImmutableMap.Builder<InstanceIdentifier<?>, S> builder = ImmutableMap.builder();
207         // Iterate writer types according to their relationships from graph
208         dag.iterator().forEachRemaining(handlerType -> {
209                     // There might be types stored just for relationship sake, no real writer, ignoring those
210                     if (handlersMap.containsKey(handlerType)) {
211                         builder.put(handlerType, handlersMap.get(handlerType));
212                     }
213                 });
214
215         // TODO HONEYCOMB-171 we could optimize subtree handlers, if there is a dedicated handler for a node managed by a subtree
216         // handler, recreate the subtree handler with a subset of handled child nodes
217         // This way it is not necessary to change the configuration of subtree writer, just to add a dedicated child
218         // writer
219
220         return builder.build();
221     }
222 }