de1ac39d3066af80ba84237acc1ff25e20e327dc
[hc2vpp.git] /
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.v3po.translate.impl.write;
18
19 import com.google.common.base.Function;
20 import com.google.common.base.Optional;
21 import com.google.common.collect.Maps;
22 import com.google.common.collect.Sets;
23 import io.fd.honeycomb.v3po.translate.impl.TraversalType;
24 import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
25 import io.fd.honeycomb.v3po.translate.util.RWUtils;
26 import io.fd.honeycomb.v3po.translate.write.ChildWriter;
27 import io.fd.honeycomb.v3po.translate.write.WriteContext;
28 import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Map;
32 import javax.annotation.Nonnull;
33 import org.opendaylight.yangtools.yang.binding.Augmentation;
34 import org.opendaylight.yangtools.yang.binding.ChildOf;
35 import org.opendaylight.yangtools.yang.binding.DataObject;
36 import org.opendaylight.yangtools.yang.binding.Identifiable;
37 import org.opendaylight.yangtools.yang.binding.Identifier;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39
40 public class CompositeListWriter<D extends DataObject & Identifiable<K>, K extends Identifier<D>> extends
41     AbstractCompositeWriter<D>
42     implements ChildWriter<D> {
43
44     private static final Function<DataObject, Object> INDEX_FUNCTION = input -> input instanceof Identifiable<?>
45         ? ((Identifiable<?>) input).getKey()
46         : input;
47
48
49     private final ListWriterCustomizer<D, K> customizer;
50
51     public CompositeListWriter(@Nonnull final Class<D> type,
52                                @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
53                                @Nonnull final List<ChildWriter<? extends Augmentation<D>>> augWriters,
54                                @Nonnull final ListWriterCustomizer<D, K> customizer) {
55         this(type, childWriters, augWriters, customizer, TraversalType.PREORDER);
56     }
57
58     public CompositeListWriter(@Nonnull final Class<D> type,
59                                @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
60                                @Nonnull final List<ChildWriter<? extends Augmentation<D>>> augWriters,
61                                @Nonnull final ListWriterCustomizer<D, K> customizer,
62                                @Nonnull final TraversalType traversalType) {
63         super(type, childWriters, augWriters, traversalType);
64         this.customizer = customizer;
65     }
66
67     public CompositeListWriter(@Nonnull final Class<D> type,
68                                @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
69                                @Nonnull final ListWriterCustomizer<D, K> customizer) {
70         this(type, childWriters, RWUtils.<D>emptyAugWriterList(), customizer);
71     }
72
73     public CompositeListWriter(@Nonnull final Class<D> type,
74                                @Nonnull final ListWriterCustomizer<D, K> customizer) {
75         this(type, RWUtils.<D>emptyChildWriterList(), RWUtils.<D>emptyAugWriterList(), customizer);
76
77     }
78
79     @Override
80     protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D data,
81                                           @Nonnull final WriteContext ctx) throws WriteFailedException {
82         customizer.writeCurrentAttributes(id, data, ctx);
83     }
84
85     @Override
86     protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D dataBefore,
87                                            @Nonnull final WriteContext ctx) throws WriteFailedException {
88         customizer.deleteCurrentAttributes(id, dataBefore, ctx);
89     }
90
91     @Override
92     protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D dataBefore,
93                                            @Nonnull final D dataAfter, @Nonnull final WriteContext ctx)
94         throws WriteFailedException {
95         customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx);
96     }
97
98     @Override
99     public void writeChild(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
100                            @Nonnull final DataObject parentData,
101                            @Nonnull final WriteContext ctx) throws WriteFailedException {
102         final InstanceIdentifier<D> currentId = RWUtils.appendTypeToId(parentId, getManagedDataObjectType());
103         final Optional<List<D>> currentData = customizer.extract(currentId, parentData);
104         if (currentData.isPresent()) {
105             for (D entry : currentData.get()) {
106                 writeCurrent(currentId, entry, ctx);
107             }
108         }
109     }
110
111     @Override
112     public void deleteChild(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
113                             @Nonnull final DataObject parentDataBefore,
114                             @Nonnull final WriteContext ctx) throws WriteFailedException {
115         final InstanceIdentifier<D> currentId = RWUtils.appendTypeToId(parentId, getManagedDataObjectType());
116         final Optional<List<D>> dataBefore = customizer.extract(currentId, parentDataBefore);
117         if (dataBefore.isPresent()) {
118             for (D entry : dataBefore.get()) {
119                 deleteCurrent(currentId, entry, ctx);
120             }
121         }
122     }
123
124     private Map<Object, D> listOfIdentifiableToMap(Optional<List<D>> list) {
125         if (list.isPresent()) {
126             return Maps.uniqueIndex(list.get(), INDEX_FUNCTION);
127         } else {
128             return Collections.emptyMap();
129         }
130
131     }
132
133     @Override
134     public void updateChild(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
135                             @Nonnull final DataObject parentDataBefore, @Nonnull final DataObject parentDataAfter,
136                             @Nonnull final WriteContext ctx) throws WriteFailedException {
137         final InstanceIdentifier<D> currentId = RWUtils.appendTypeToId(parentId, getManagedDataObjectType());
138         final Map<Object, D> dataBefore = listOfIdentifiableToMap(customizer.extract(currentId, parentDataBefore));
139         final Map<Object, D> dataAfter = listOfIdentifiableToMap(customizer.extract(currentId, parentDataAfter));
140
141         for (Map.Entry<Object, D> after : dataAfter.entrySet()) {
142             final D before = dataBefore.get(after.getKey());
143             if(before == null) {
144                 writeCurrent(currentId, after.getValue(), ctx);
145             } else {
146                 updateCurrent(currentId, before, after.getValue(), ctx);
147             }
148         }
149
150         // Delete the rest in dataBefore
151         for (Object deletedNodeKey : Sets.difference(dataBefore.keySet(), dataAfter.keySet())) {
152             final D deleted = dataBefore.get(deletedNodeKey);
153             deleteCurrent(currentId, deleted, ctx);
154         }
155
156     }
157
158     @Override
159     protected void writeCurrent(final InstanceIdentifier<D> id, final D data, final WriteContext ctx)
160         throws WriteFailedException {
161         // Make sure the key is present
162         if(isWildcarded(id)) {
163             super.writeCurrent(getSpecificId(id, data), data, ctx);
164         } else {
165             super.writeCurrent(id, data, ctx);
166         }
167     }
168
169     @Override
170     protected void updateCurrent(final InstanceIdentifier<D> id, final D dataBefore, final D dataAfter,
171                                  final WriteContext ctx) throws WriteFailedException {
172         // Make sure the key is present
173         if(isWildcarded(id)) {
174             super.updateCurrent(getSpecificId(id, dataBefore), dataBefore, dataAfter, ctx);
175         } else {
176             super.updateCurrent(id, dataBefore, dataAfter, ctx);
177         }
178     }
179
180     @Override
181     protected void deleteCurrent(final InstanceIdentifier<D> id, final D dataBefore, final WriteContext ctx)
182         throws WriteFailedException {
183         // Make sure the key is present
184         if(isWildcarded(id)) {
185             super.deleteCurrent(getSpecificId(id, dataBefore), dataBefore, ctx);
186         } else {
187             super.deleteCurrent(id, dataBefore, ctx);
188         }
189     }
190
191     private boolean isWildcarded(final InstanceIdentifier<D> id) {
192         return id.firstIdentifierOf(getManagedDataObjectType().getTargetType()).isWildcarded();
193     }
194
195     private InstanceIdentifier<D> getSpecificId(final InstanceIdentifier<D> currentId, final D current) {
196         return RWUtils.replaceLastInId(currentId,
197             new InstanceIdentifier.IdentifiableItem<>(currentId.getTargetType(), current.getKey()));
198     }
199 }