2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.neutron.transcriber;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import java.lang.reflect.InvocationTargetException;
15 import java.lang.reflect.Method;
16 import java.lang.reflect.ParameterizedType;
17 import java.lang.reflect.Type;
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.List;
22 import java.util.concurrent.ExecutionException;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
25 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
26 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
27 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
30 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.neutron.spi.INeutronAdminAttributes;
33 import org.opendaylight.neutron.spi.INeutronBaseAttributes;
34 import org.opendaylight.neutron.spi.INeutronCRUD;
35 import org.opendaylight.neutron.spi.INeutronObject;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.attrs.rev150712.AdminAttributes;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.attrs.rev150712.BaseAttributes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
40 import org.opendaylight.yangtools.concepts.Builder;
41 import org.opendaylight.yangtools.yang.binding.Augmentable;
42 import org.opendaylight.yangtools.yang.binding.ChildOf;
43 import org.opendaylight.yangtools.yang.binding.DataObject;
44 import org.opendaylight.yangtools.yang.binding.Identifiable;
45 import org.opendaylight.yangtools.yang.binding.Identifier;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 public abstract class AbstractNeutronInterface<T extends DataObject & Identifiable<K> & ChildOf<? super U>,
51 U extends ChildOf<? super Neutron> & Augmentable<U>, K extends Identifier<T>, S extends INeutronObject<S>>
52 implements AutoCloseable, INeutronCRUD<S> {
53 // T extends DataObject & Identifiable<K> & ChildOf<? super U> as 0th type argument
54 private static final int MD_LIST_CLASS_TYPE_INDEX = 0;
55 // U extends ChildOf<? super Neutron> & Augmentable<U> as 1st type argument
56 private static final int MD_CONTAINER_CLASS_TYPE_INDEX = 1;
57 // S extends INeutronObject<S> as 3rd type argument
58 private static final int NEUTRON_OBJECT_TYPE_INDEX = 3;
60 private static final Logger LOGGER = LoggerFactory.getLogger(AbstractNeutronInterface.class);
61 private static final int DEDASHED_UUID_LENGTH = 32;
62 private static final int DEDASHED_UUID_START = 0;
63 private static final int DEDASHED_UUID_DIV1 = 8;
64 private static final int DEDASHED_UUID_DIV2 = 12;
65 private static final int DEDASHED_UUID_DIV3 = 16;
66 private static final int DEDASHED_UUID_DIV4 = 20;
68 private static final int RETRY_MAX = 2;
70 private final DataBroker db;
72 private final Class<U> mdContainerClass;
73 private final Class<T> mdListClass;
75 // Unfortunately odl yangtools doesn't model yang model "uses" as
76 // class/interface hierarchy. So we need to resort to use reflection
77 // to call setter method.
78 private final Class<? extends Builder<T>> builderClass;
79 private final Method setUuid;
80 private final Method setTenantId;
81 private final Method setProjectId;
82 private final Method setName;
83 private final Method setAdminStateUp;
84 private final Method setStatus;
85 private final Method setRevisionNumber;
87 AbstractNeutronInterface(Class<? extends Builder<T>> builderClass, DataBroker db) {
88 this.db = Preconditions.checkNotNull(db);
89 this.builderClass = builderClass;
91 ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
92 Type[] types = parameterizedType.getActualTypeArguments();
93 @SuppressWarnings("unchecked")
94 Class<T> localMdListClass = (Class<T>) types[MD_LIST_CLASS_TYPE_INDEX];
95 mdListClass = localMdListClass;
96 @SuppressWarnings("unchecked")
97 Class<U> localMdContainerClass = (Class<U>) types[MD_CONTAINER_CLASS_TYPE_INDEX];
98 mdContainerClass = localMdContainerClass;
99 @SuppressWarnings("unchecked")
100 Class<S> neutronObjectClass = (Class<S>) types[NEUTRON_OBJECT_TYPE_INDEX];
102 setUuid = builderClass.getDeclaredMethod("setUuid", Uuid.class);
103 setTenantId = builderClass.getDeclaredMethod("setTenantId", Uuid.class);
104 if (INeutronBaseAttributes.class.isAssignableFrom(neutronObjectClass)) {
105 setName = builderClass.getDeclaredMethod("setName", String.class);
106 setProjectId = builderClass.getDeclaredMethod("setProjectId", String.class);
107 setRevisionNumber = builderClass.getDeclaredMethod("setRevisionNumber", Long.class);
111 setRevisionNumber = null;
114 if (INeutronAdminAttributes.class.isAssignableFrom(neutronObjectClass)) {
115 setAdminStateUp = builderClass.getDeclaredMethod("setAdminStateUp", Boolean.class);
116 setStatus = builderClass.getDeclaredMethod("setStatus", String.class);
118 setAdminStateUp = null;
121 } catch (NoSuchMethodException e) {
122 throw new IllegalArgumentException(e);
126 public DataBroker getDataBroker() {
127 Preconditions.checkNotNull(db);
131 private InstanceIdentifier<T> createInstanceIdentifier(T item) {
132 return InstanceIdentifier.create(Neutron.class).child(mdContainerClass).child(mdListClass, item.getKey());
135 private InstanceIdentifier<U> createInstanceIdentifier() {
136 return InstanceIdentifier.create(Neutron.class).child(mdContainerClass);
139 protected <S1 extends INeutronBaseAttributes<S1>, M extends BaseAttributes, B extends Builder<M>>
140 void toMdIds(INeutronObject<S1> neutronObject, B builder) {
142 if (neutronObject.getID() != null) {
143 setUuid.invoke(builder, toUuid(neutronObject.getID()));
145 LOGGER.warn("Attempting to write neutron object {} without UUID", builderClass.getSimpleName());
147 if (neutronObject.getTenantID() != null && !neutronObject.getTenantID().isEmpty()) {
148 setTenantId.invoke(builder, toUuid(neutronObject.getTenantID()));
150 if (neutronObject.getProjectID() != null) {
151 setProjectId.invoke(builder, neutronObject.getTenantID());
153 } catch (IllegalAccessException | InvocationTargetException e) {
154 throw new IllegalArgumentException(e);
158 protected <S1 extends INeutronBaseAttributes<S1>>
159 void fromMdIds(BaseAttributes baseAttributes, INeutronObject<S1> answer) {
160 if (baseAttributes.getUuid() != null) {
161 answer.setID(baseAttributes.getUuid().getValue());
163 if (baseAttributes.getTenantId() != null) {
164 answer.setTenantID(baseAttributes.getTenantId());
166 if (baseAttributes.getProjectId() != null) {
167 answer.setProjectID(baseAttributes.getProjectId());
171 protected <S1 extends INeutronBaseAttributes<S1>, M extends BaseAttributes, B extends Builder<M>>
172 void toMdBaseAttributes(S1 neutronObject, B builder) {
173 toMdIds(neutronObject, builder);
175 if (neutronObject.getName() != null) {
176 setName.invoke(builder, neutronObject.getName());
178 if (neutronObject.getRevisionNumber() != null) {
179 setRevisionNumber.invoke(builder, neutronObject.getRevisionNumber());
181 } catch (IllegalAccessException | InvocationTargetException e) {
182 throw new IllegalArgumentException(e);
186 protected <S1 extends INeutronBaseAttributes<S1>>
187 void fromMdBaseAttributes(BaseAttributes baseAttributes, S1 answer) {
188 fromMdIds(baseAttributes, answer);
189 if (baseAttributes.getName() != null) {
190 answer.setName(baseAttributes.getName());
192 if (baseAttributes.getRevisionNumber() != null) {
193 answer.setRevisionNumber(baseAttributes.getRevisionNumber());
197 protected <S1 extends INeutronAdminAttributes<S1>, M extends BaseAttributes & AdminAttributes, B extends Builder<M>>
198 void toMdAdminAttributes(S1 neutronObject, B builder) {
199 toMdBaseAttributes(neutronObject, builder);
201 if (neutronObject.getAdminStateUp() != null) {
202 setAdminStateUp.invoke(builder, neutronObject.getAdminStateUp());
204 if (neutronObject.getStatus() != null) {
205 setStatus.invoke(builder, neutronObject.getStatus());
207 } catch (IllegalAccessException | InvocationTargetException e) {
208 throw new IllegalArgumentException(e);
212 protected <M extends BaseAttributes & AdminAttributes, S1 extends INeutronAdminAttributes<S1>>
213 void fromMdAdminAttributes(M attr, S1 answer) {
214 fromMdBaseAttributes(attr, answer);
215 if (attr.isAdminStateUp() != null) {
216 answer.setAdminStateUp(attr.isAdminStateUp());
218 if (attr.getStatus() != null) {
219 answer.setStatus(attr.getStatus());
223 protected abstract T toMd(S neutronObject);
225 protected T toMd(String uuid) {
228 builder = builderClass.newInstance();
229 setUuid.invoke(builder, toUuid(uuid));
230 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
231 // should not happen.
232 throw new IllegalArgumentException(e);
234 return builder.build();
237 protected abstract S fromMd(T dataObject);
239 private <T extends DataObject> T readMd(InstanceIdentifier<T> path, ReadTransaction tx) {
240 Preconditions.checkNotNull(tx);
242 final CheckedFuture<Optional<T>,
243 ReadFailedException> future = tx.read(LogicalDatastoreType.CONFIGURATION, path);
244 if (future != null) {
245 Optional<T> optional;
247 optional = future.checkedGet();
248 if (optional.isPresent()) {
249 result = optional.get();
251 } catch (final ReadFailedException e) {
252 LOGGER.warn("Failed to read {}", path, e);
258 protected <T extends DataObject> T readMd(InstanceIdentifier<T> path) {
259 try (ReadOnlyTransaction tx = getDataBroker().newReadOnlyTransaction()) {
260 return readMd(path, tx);
264 private void addMd(S neutronObject, WriteTransaction tx) throws InterruptedException, ExecutionException {
265 // TODO think about adding existence logic
266 updateMd(neutronObject, tx);
269 protected boolean addMd(S neutronObject) {
271 final WriteTransaction tx = getDataBroker().newWriteOnlyTransaction();
272 addMd(neutronObject, tx);
274 } catch (InterruptedException | ExecutionException e) {
275 LOGGER.warn("Transaction failed", e);
280 private void updateMd(S neutronObject, WriteTransaction tx) throws InterruptedException, ExecutionException {
281 Preconditions.checkNotNull(tx);
283 final T item = toMd(neutronObject);
284 final InstanceIdentifier<T> iid = createInstanceIdentifier(item);
285 tx.put(LogicalDatastoreType.CONFIGURATION, iid, item, true);
286 final CheckedFuture<Void, TransactionCommitFailedException> future = tx.submit();
287 // Check if it's successfuly committed, otherwise exception will be thrown.
291 protected boolean updateMd(S neutronObject) {
292 int retries = RETRY_MAX;
293 while (retries-- >= 0) {
295 final WriteTransaction tx = getDataBroker().newWriteOnlyTransaction();
296 updateMd(neutronObject, tx);
298 } catch (InterruptedException | ExecutionException e) {
299 if (e.getCause() instanceof OptimisticLockFailedException) {
300 LOGGER.warn("Got OptimisticLockFailedException - {} {}", neutronObject, retries);
303 // TODO: rethrow exception. don't mask exception
304 LOGGER.error("Transaction failed", e);
311 private void removeMd(T item, WriteTransaction tx) throws InterruptedException, ExecutionException {
312 Preconditions.checkNotNull(tx);
313 final InstanceIdentifier<T> iid = createInstanceIdentifier(item);
314 tx.delete(LogicalDatastoreType.CONFIGURATION, iid);
315 final CheckedFuture<Void, TransactionCommitFailedException> future = tx.submit();
316 // Check if it's successfuly committed, otherwise exception will be thrown.
320 protected boolean removeMd(T item) {
321 final ReadWriteTransaction tx = getDataBroker().newReadWriteTransaction();
325 } catch (InterruptedException | ExecutionException e) {
326 LOGGER.warn("Transaction failed", e);
331 protected Uuid toUuid(String uuid) {
332 Preconditions.checkNotNull(uuid);
335 result = new Uuid(uuid);
336 } catch (final IllegalArgumentException e) {
337 // OK... someone didn't follow RFC 4122... lets try this the hard way
338 final String dedashed = uuid.replace("-", "");
339 if (dedashed.length() == DEDASHED_UUID_LENGTH) {
340 final String redashed = dedashed.substring(DEDASHED_UUID_START, DEDASHED_UUID_DIV1) + "-"
341 + dedashed.substring(DEDASHED_UUID_DIV1, DEDASHED_UUID_DIV2) + "-"
342 + dedashed.substring(DEDASHED_UUID_DIV2, DEDASHED_UUID_DIV3) + "-"
343 + dedashed.substring(DEDASHED_UUID_DIV3, DEDASHED_UUID_DIV4) + "-"
344 + dedashed.substring(DEDASHED_UUID_DIV4, DEDASHED_UUID_LENGTH);
345 result = new Uuid(redashed);
354 public void close() throws Exception {
355 // TODO Auto-generated method stub
359 private boolean exists(String uuid, ReadTransaction tx) {
360 Preconditions.checkNotNull(tx);
361 final T dataObject = readMd(createInstanceIdentifier(toMd(uuid)), tx);
362 return dataObject != null;
366 public boolean exists(String uuid) {
367 try (ReadOnlyTransaction tx = getDataBroker().newReadOnlyTransaction()) {
368 return exists(uuid, tx);
372 private S get(String uuid, ReadTransaction tx) {
373 Preconditions.checkNotNull(tx);
374 final T dataObject = readMd(createInstanceIdentifier(toMd(uuid)), tx);
375 if (dataObject == null) {
378 return fromMd(dataObject);
382 public S get(String uuid) {
383 try (ReadOnlyTransaction tx = getDataBroker().newReadOnlyTransaction()) {
384 return get(uuid, tx);
388 protected abstract List<T> getDataObjectList(U dataObjects);
390 private List<S> getAll(ReadTransaction tx) {
391 Preconditions.checkNotNull(tx);
392 final Set<S> allNeutronObjects = new HashSet<>();
393 final U dataObjects = readMd(createInstanceIdentifier(), tx);
394 if (dataObjects != null) {
395 for (final T dataObject : getDataObjectList(dataObjects)) {
396 allNeutronObjects.add(fromMd(dataObject));
399 LOGGER.debug("Exiting _getAll, Found {} OpenStackFirewall", allNeutronObjects.size());
400 final List<S> ans = new ArrayList<>();
401 ans.addAll(allNeutronObjects);
406 public List<S> getAll() {
407 try (ReadOnlyTransaction tx = getDataBroker().newReadOnlyTransaction()) {
412 private boolean add(S input, ReadWriteTransaction tx) throws InterruptedException, ExecutionException {
413 Preconditions.checkNotNull(tx);
414 if (exists(input.getID(), tx)) {
423 public boolean add(S input) {
424 int retries = RETRY_MAX;
425 while (retries-- >= 0) {
426 final ReadWriteTransaction tx = getDataBroker().newReadWriteTransaction();
428 return add(input, tx);
429 } catch (InterruptedException | ExecutionException e) {
430 if (e.getCause() instanceof OptimisticLockFailedException) {
431 LOGGER.warn("Got OptimisticLockFailedException - {} {}", input, retries);
434 // TODO: rethrow exception. don't mask exception
435 LOGGER.error("Transaction failed", e);
442 private boolean remove(String uuid, ReadWriteTransaction tx) throws InterruptedException, ExecutionException {
443 Preconditions.checkNotNull(tx);
444 if (!exists(uuid, tx)) {
448 removeMd(toMd(uuid), tx);
453 public boolean remove(String uuid) {
454 int retries = RETRY_MAX;
455 while (retries-- >= 0) {
456 final ReadWriteTransaction tx = getDataBroker().newReadWriteTransaction();
458 return remove(uuid, tx);
459 } catch (InterruptedException | ExecutionException e) {
460 if (e.getCause() instanceof OptimisticLockFailedException) {
461 LOGGER.warn("Got OptimisticLockFailedException - {} {}", uuid, retries);
464 // TODO: rethrow exception. don't mask exception
465 LOGGER.error("Transaction failed", e);
472 private boolean update(String uuid, S delta, ReadWriteTransaction tx)
473 throws InterruptedException, ExecutionException {
474 Preconditions.checkNotNull(tx);
475 if (!exists(uuid, tx)) {
484 public boolean update(String uuid, S delta) {
485 int retries = RETRY_MAX;
486 while (retries-- >= 0) {
487 final ReadWriteTransaction tx = getDataBroker().newReadWriteTransaction();
489 return update(uuid, delta, tx);
490 } catch (InterruptedException | ExecutionException e) {
491 if (e.getCause() instanceof OptimisticLockFailedException) {
492 LOGGER.warn("Got OptimisticLockFailedException - {} {} {}", uuid, delta, retries);
495 // TODO: rethrow exception. don't mask exception
496 LOGGER.error("Transaction failed", e);