fe2f1178f41e48ead680bd37128da0a8f3e4ce7f
[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 java.util.Collection;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Set;
28 import javax.annotation.Nonnull;
29 import org.opendaylight.yangtools.yang.binding.DataObject;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31
32 public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends SubtreeManager<? extends DataObject>, R>
33         implements ModifiableSubtreeManagerRegistryBuilder<S>, SubtreeManagerRegistryBuilder<R> {
34
35     private final Map<InstanceIdentifier<?>, S> handlersMap = new HashMap<>();
36     private final YangDAG dag;
37
38     protected AbstractSubtreeManagerRegistryBuilderBuilder(@Nonnull final YangDAG yangDAG) {
39         this.dag = Preconditions.checkNotNull(yangDAG, "yangDAG should not be null");
40     }
41
42     /**
43      * Add handler without any special relationship to any other type.
44      */
45     @Override
46     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> add(@Nonnull final S handler) {
47         // Make IID wildcarded just in case
48         // + the way InstanceIdentifier.create + equals work for Identifiable items is unexpected, meaning updates would
49         // not be matched to writers in registry
50         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
51         checkWriterNotPresentYet(targetType);
52         dag.addVertex(targetType);
53         handlersMap.put(targetType, handler);
54         return this;
55     }
56
57     /**
58      * Add handler without any special relationship to any other type.
59      */
60     @Override
61     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAdd(@Nonnull final Set<InstanceIdentifier<?>> handledChildren,
62                                                                          @Nonnull final S handler) {
63         add(getSubtreeHandler(handledChildren, handler));
64         return this;
65     }
66
67     private void checkWriterNotPresentYet(final InstanceIdentifier<?> targetType) {
68         Preconditions.checkArgument(!handlersMap.containsKey(targetType),
69                 "Writer for type: %s already present: %s", targetType, handlersMap.get(targetType));
70     }
71
72     /**
73      * Add handler with relationship: to be executed before handler handling relatedType.
74      */
75     @Override
76     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> addBefore(@Nonnull final S handler,
77                                                                         @Nonnull final InstanceIdentifier<?> relatedType) {
78         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
79         final InstanceIdentifier<?> wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType);
80         checkWriterNotPresentYet(targetType);
81         dag.addVertex(targetType);
82         dag.addVertex(wildcardedRelatedType);
83         dag.addEdge(targetType, wildcardedRelatedType);
84         handlersMap.put(targetType, handler);
85         return this;
86     }
87
88     @Override
89     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> addBefore(@Nonnull final S handler,
90                                                                         @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
91         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
92         checkWriterNotPresentYet(targetType);
93         dag.addVertex(targetType);
94         relatedTypes.stream()
95                 .map(RWUtils::makeIidWildcarded)
96                 .forEach(dag::addVertex);
97         relatedTypes.stream()
98                 .map(RWUtils::makeIidWildcarded)
99                 .forEach(type -> dag.addEdge(targetType, type));
100         handlersMap.put(targetType, handler);
101         return this;
102     }
103
104     @Override
105     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddBefore(
106             @Nonnull final Set<InstanceIdentifier<?>> handledChildren,
107             @Nonnull final S handler,
108             @Nonnull final InstanceIdentifier<?> relatedType) {
109         return addBefore(getSubtreeHandler(handledChildren, handler), relatedType);
110     }
111
112     @Override
113     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddBefore(
114             @Nonnull final Set<InstanceIdentifier<?>> handledChildren,
115             @Nonnull final S handler,
116             @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
117         return addBefore(getSubtreeHandler(handledChildren, handler), relatedTypes);
118     }
119
120     protected abstract S getSubtreeHandler(@Nonnull final Set<InstanceIdentifier<?>> handledChildren,
121                                            @Nonnull final S handler);
122
123     /**
124      * Add handler with relationship: to be executed after handler handling relatedType.
125      */
126     @Override
127     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> addAfter(@Nonnull final S handler,
128                                                                        @Nonnull final InstanceIdentifier<?> relatedType) {
129         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
130         final InstanceIdentifier<?> wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType);
131         checkWriterNotPresentYet(targetType);
132         dag.addVertex(targetType);
133         dag.addVertex(wildcardedRelatedType);
134         // set edge to indicate before relationship, just reversed
135         dag.addEdge(wildcardedRelatedType, targetType);
136         handlersMap.put(targetType, handler);
137         return this;
138     }
139
140     @Override
141     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> addAfter(@Nonnull final S handler,
142                                                                        @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
143         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
144         checkWriterNotPresentYet(targetType);
145         dag.addVertex(targetType);
146         relatedTypes.stream()
147                 .map(RWUtils::makeIidWildcarded)
148                 .forEach(dag::addVertex);
149         // set edge to indicate before relationship, just reversed
150         relatedTypes.stream()
151                 .map(RWUtils::makeIidWildcarded)
152                 .forEach(type -> dag.addEdge(type, targetType));
153         handlersMap.put(targetType, handler);
154         return this;
155     }
156
157     @Override
158     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddAfter(
159             @Nonnull final Set<InstanceIdentifier<?>> handledChildren,
160             @Nonnull final S handler,
161             @Nonnull final InstanceIdentifier<?> relatedType) {
162         return addAfter(getSubtreeHandler(handledChildren, handler), relatedType);
163     }
164
165     @Override
166     public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddAfter(
167             @Nonnull final Set<InstanceIdentifier<?>> handledChildren,
168             @Nonnull final S handler,
169             @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
170         return addAfter(getSubtreeHandler(handledChildren, handler), relatedTypes);
171     }
172
173     protected ImmutableMap<InstanceIdentifier<?>, S> getMappedHandlers() {
174         final ImmutableMap.Builder<InstanceIdentifier<?>, S> builder = ImmutableMap.builder();
175         // Iterate writer types according to their relationships from graph
176         dag.iterator().forEachRemaining(handlerType -> {
177                     // There might be types stored just for relationship sake, no real writer, ignoring those
178                     if (handlersMap.containsKey(handlerType)) {
179                         builder.put(handlerType, handlersMap.get(handlerType));
180                     }
181                 });
182
183         // TODO HONEYCOMB-171 we could optimize subtree handlers, if there is a dedicated handler for a node managed by a subtree
184         // handler, recreate the subtree handler with a subset of handled child nodes
185         // This way it is not necessary to change the configuration of subtree writer, just to add a dedicated child
186         // writer
187
188         return builder.build();
189     }
190 }