HONEYCOMB-130: Rename infra packages(remove vpp/v3po)
[honeycomb.git] / infra / translate-api / src / main / java / io / fd / honeycomb / translate / write / registry / WriterRegistry.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.write.registry;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20
21 import com.google.common.annotations.Beta;
22 import com.google.common.collect.ImmutableSet;
23 import com.google.common.collect.Multimap;
24 import com.google.common.collect.Sets;
25 import io.fd.honeycomb.translate.TranslationException;
26 import io.fd.honeycomb.translate.write.DataObjectUpdate;
27 import io.fd.honeycomb.translate.write.WriteContext;
28 import io.fd.honeycomb.translate.write.Writer;
29 import java.util.Set;
30 import javax.annotation.Nonnull;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
32
33 /**
34  * Special {@link Writer} capable of performing bulk updates.
35  */
36 @Beta
37 public interface WriterRegistry {
38
39     /**
40      * Performs bulk update.
41      *
42      * @throws BulkUpdateException in case bulk update fails
43      * @throws TranslationException in case some other error occurs while processing update request
44      */
45     void update(@Nonnull DataObjectUpdates updates,
46                 @Nonnull WriteContext ctx) throws TranslationException;
47
48     /**
49      * Simple DTO containing updates for {@link WriterRegistry}. Currently only deletes and updates (create + update)
50      * are distinguished.
51      */
52     @Beta
53     final class DataObjectUpdates {
54
55         private final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates;
56         private final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes;
57
58         /**
59          * Create new instance.
60          *
61          * @param updates All updates indexed by their unkeyed {@link InstanceIdentifier}
62          * @param deletes All deletes indexed by their unkeyed {@link InstanceIdentifier}
63          */
64         public DataObjectUpdates(@Nonnull final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates,
65                                  @Nonnull final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes) {
66             this.deletes = deletes;
67             this.updates = updates;
68         }
69
70         public Multimap<InstanceIdentifier<?>, DataObjectUpdate> getUpdates() {
71             return updates;
72         }
73
74         public Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> getDeletes() {
75             return deletes;
76         }
77
78         public boolean isEmpty() {
79             return updates.isEmpty() && deletes.isEmpty();
80         }
81
82         @Override
83         public String toString() {
84             return "DataObjectUpdates{" + "updates=" + updates + ", deletes=" + deletes + '}';
85         }
86
87         /**
88          * Get a {@link Set} containing all update types from both updates as well as deletes.
89          */
90         public Set<InstanceIdentifier<?>> getTypeIntersection() {
91             return Sets.union(deletes.keySet(), updates.keySet());
92         }
93
94         /**
95          * Check whether there is only a single type of data object to be updated.
96          *
97          * @return true if there is only a single type of updates (update + delete)
98          */
99         public boolean containsOnlySingleType() {
100             return getTypeIntersection().size() == 1;
101         }
102
103         @Override
104         public boolean equals(final Object other) {
105             if (this == other) {
106                 return true;
107             }
108             if (other == null || getClass() != other.getClass()) {
109                 return false;
110             }
111
112             final DataObjectUpdates that = (DataObjectUpdates) other;
113
114             if (!updates.equals(that.updates)) {
115                 return false;
116             }
117             return deletes.equals(that.deletes);
118
119         }
120
121         @Override
122         public int hashCode() {
123             int result = updates.hashCode();
124             result = 31 * result + deletes.hashCode();
125             return result;
126         }
127
128     }
129
130     /**
131      * Thrown when bulk update failed.
132      */
133     @Beta
134     class BulkUpdateException extends TranslationException {
135
136         private final Reverter reverter;
137         private final Set<InstanceIdentifier<?>> failedIds;
138
139         /**
140          * Constructs an BulkUpdateException.
141          * @param failedIds instance identifiers of the data objects that were not processed during bulk update.
142          * @param cause the cause of bulk update failure
143          */
144         public BulkUpdateException(@Nonnull final Set<InstanceIdentifier<?>> failedIds,
145                                    @Nonnull final Reverter reverter,
146                                    @Nonnull final Throwable cause) {
147             super("Bulk update failed at: " + failedIds, cause);
148             this.failedIds = failedIds;
149             this.reverter = checkNotNull(reverter, "reverter should not be null");
150         }
151
152         /**
153          * Reverts changes that were successfully applied during bulk update before failure occurred.
154          *
155          * @throws Reverter.RevertFailedException if revert fails
156          */
157         public void revertChanges() throws Reverter.RevertFailedException {
158             reverter.revert();
159         }
160
161         public Set<InstanceIdentifier<?>> getFailedIds() {
162             return failedIds;
163         }
164     }
165
166     /**
167      * Abstraction over revert mechanism in case of a bulk update failure.
168      */
169     @Beta
170     interface Reverter {
171
172         /**
173          * Reverts changes that were successfully applied during bulk update before failure occurred. Changes are
174          * reverted in reverse order they were applied.
175          *
176          * @throws RevertFailedException if not all of applied changes were successfully reverted
177          */
178         void revert() throws RevertFailedException;
179
180         /**
181          * Thrown when some of the changes applied during bulk update were not reverted.
182          */
183         @Beta
184         class RevertFailedException extends TranslationException {
185
186             // TODO change to list of VppDataModifications to make debugging easier
187             private final Set<InstanceIdentifier<?>> notRevertedChanges;
188
189             /**
190              * Constructs a RevertFailedException with the list of changes that were not reverted.
191              *
192              * @param notRevertedChanges list of changes that were not reverted
193              * @param cause              the cause of revert failure
194              */
195             public RevertFailedException(@Nonnull final Set<InstanceIdentifier<?>> notRevertedChanges,
196                                          final Throwable cause) {
197                 super(cause);
198                 checkNotNull(notRevertedChanges, "notRevertedChanges should not be null");
199                 this.notRevertedChanges = ImmutableSet.copyOf(notRevertedChanges);
200             }
201
202             /**
203              * Returns the list of changes that were not reverted.
204              *
205              * @return list of changes that were not reverted
206              */
207             @Nonnull
208             public Set<InstanceIdentifier<?>> getNotRevertedChanges() {
209                 return notRevertedChanges;
210             }
211         }
212     }
213 }