diff options
author | Maros Marsalek <mmarsale@cisco.com> | 2016-07-27 11:05:51 +0200 |
---|---|---|
committer | Maros Marsalek <mmarsale@cisco.com> | 2016-07-29 16:32:07 +0200 |
commit | 0578156b721fa01c8c645b8f9625ecebdb6449e4 (patch) | |
tree | 49d36f24e5d984a8c9f151b1440de88619f8b7de /infra/translate-api | |
parent | 007d4542388ca89be409ce1a4a4c7a36ddcb538f (diff) |
HONEYCOMB-130: Separate v3po plugin from HC infra
Creating folders:
- common/
- infra/
- v3po/
- vpp-common/
Change-Id: I2c39e1b17e39e7c0f0628f44aa5fe08563fa06e4
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'infra/translate-api')
28 files changed, 1630 insertions, 0 deletions
diff --git a/infra/translate-api/Readme.adoc b/infra/translate-api/Readme.adoc new file mode 100644 index 000000000..9e208744a --- /dev/null +++ b/infra/translate-api/Readme.adoc @@ -0,0 +1,9 @@ += Honeycomb translation layer API + +Extensible API for translation between Binding Aware data and actual device data. +Consists of readers and writers responsible for communication with the device. + +Provides registry of readers and writers for the data layer. +For every supported YANG model there should be at least one reader and writer registered. +Readers and writers form two tree structures matching corresponding YANG models. +Readers and writers can be attached to any non-leaf YANG node.
\ No newline at end of file diff --git a/infra/translate-api/pom.xml b/infra/translate-api/pom.xml new file mode 100644 index 000000000..45f00fe19 --- /dev/null +++ b/infra/translate-api/pom.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2015 Cisco and/or its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>io.fd.honeycomb.common</groupId> + <artifactId>impl-parent</artifactId> + <version>1.0.0-SNAPSHOT</version> + <relativePath>../../common/impl-parent</relativePath> + </parent> + + <modelVersion>4.0.0</modelVersion> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-api</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>bundle</packaging> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>mdsal-artifacts</artifactId> + <version>2.0.2-Beryllium-SR2</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>mdsal-binding-api</artifactId> + </dependency> + + <!-- Testing Dependencies --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <scope>test</scope> + </dependency> + + </dependencies> + +</project> diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java new file mode 100644 index 000000000..cff766e2a --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate; + +import com.google.common.base.Optional; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Mapping context is persisted storage where mapping matadata are stored. + * A snapshot is created for each transaction to provide consistent view over context data. + * After a transaction is successfully finished, objects added to this context are propagated to backing storage. + */ +public interface MappingContext extends AutoCloseable { + + /** + * Read any mapping context data + * + * @param currentId Id of an object to read + * + * @return Relevant mapping context data + */ + <T extends DataObject> Optional<T> read(@Nonnull final InstanceIdentifier<T> currentId); + + /** + * Delete the node at specified path. + * + * @param path Node path + */ + void delete(InstanceIdentifier<?> path); + + /** + * Merge the specified data with the currently-present data + * at specified path. + * + * @param path Node path + * @param data Data to be merged + */ + <T extends DataObject> void merge(InstanceIdentifier<T> path, T data); + + /** + * Replace the data at specified path with supplied data. + * + * @param path Node path + * @param data New node data + */ + <T extends DataObject> void put(InstanceIdentifier<T> path, T data); + + @Override + void close(); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java new file mode 100644 index 000000000..591a9e9bb --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate; + +import java.util.Collection; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Registry builder where {@link SubtreeManager}s can be added with or without relationships between them. + * The relationships express what the order of execution should be. + */ +public interface ModifiableSubtreeManagerRegistryBuilder<S extends SubtreeManager<? extends DataObject>> { + + /** + * Add a handler responsible for writing only a single complex node. + */ + ModifiableSubtreeManagerRegistryBuilder<S> add(@Nonnull S handler); + + /** + * Add a handler responsible for writing multiple complex nodes within a subtree its responsible for. Identifiers for + * subtree nodes handled by a single handler have to be relative from {@link DataObject} that represents subtree + * root. + */ + ModifiableSubtreeManagerRegistryBuilder<S> subtreeAdd(@Nonnull Set<InstanceIdentifier<?>> handledChildren, + @Nonnull S handler); + + /** + * Add a handler and make sure it will be executed before handler identifier by relatedType is executed. + */ + ModifiableSubtreeManagerRegistryBuilder<S> addBefore(@Nonnull S handler, + @Nonnull InstanceIdentifier<?> relatedType); + + ModifiableSubtreeManagerRegistryBuilder<S> addBefore(@Nonnull S handler, + @Nonnull Collection<InstanceIdentifier<?>> relatedTypes); + + ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddBefore(@Nonnull Set<InstanceIdentifier<?>> handledChildren, + @Nonnull S handler, + @Nonnull InstanceIdentifier<?> relatedType); + + ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddBefore(@Nonnull Set<InstanceIdentifier<?>> handledChildren, + @Nonnull S handler, + @Nonnull Collection<InstanceIdentifier<?>> relatedTypes); + + /** + * Add a handler and make sure it will be executed after handler identifier by relatedType is executed. + */ + ModifiableSubtreeManagerRegistryBuilder<S> addAfter(@Nonnull S handler, + @Nonnull InstanceIdentifier<?> relatedType); + + ModifiableSubtreeManagerRegistryBuilder<S> addAfter(@Nonnull S handler, + @Nonnull Collection<InstanceIdentifier<?>> relatedTypes); + + ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddAfter(@Nonnull Set<InstanceIdentifier<?>> handledChildren, + @Nonnull S handler, + @Nonnull InstanceIdentifier<?> relatedType); + + ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddAfter(@Nonnull Set<InstanceIdentifier<?>> handledChildren, + @Nonnull S handler, + @Nonnull Collection<InstanceIdentifier<?>> relatedTypes); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java new file mode 100644 index 000000000..cb2d4fde0 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate; + +import com.google.common.collect.Maps; +import java.util.HashMap; + +/** + * Simple context class that provides transient storage during one or more read/write operations + */ +public class ModificationCache implements AutoCloseable { + + protected final HashMap<Object, Object> map; + + public ModificationCache() { + map = Maps.newHashMap(); + } + + public Object get(final Object o) { + return map.get(o); + } + + public boolean containsKey(final Object o) { + return map.containsKey(o); + } + + public Object put(final Object o, final Object o2) { + return map.put(o, o2); + } + + @Override + public void close() { + map.clear(); + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java new file mode 100644 index 000000000..2c039aba0 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate; + +import javax.annotation.Nonnull; + +/** + * Common context for both writes and reads + */ +public interface ModificationContext extends AutoCloseable { + + /** + * Get key value transient storage for customizers. Is cleared for each new transaction. + * + * @return Context for customizers + */ + @Nonnull + ModificationCache getModificationCache(); + + /** + * Get persistent storage for mapping context. This context survives a modification. + * + * @return Mapping context accessor + */ + @Nonnull + MappingContext getMappingContext(); + + @Override + void close(); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java new file mode 100644 index 000000000..40842763d --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate; + +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Base identifiable subtree manager(reader, writer etc.) + * + * @param <D> Specific DataObject derived type, that is managed by this manager + */ +@Beta +public interface SubtreeManager<D extends DataObject> { + + /** + * Gets the type of node managed by this reader. + * + * @return Absolute instance identifier for managed type + */ + @Nonnull + InstanceIdentifier<D> getManagedDataObjectType(); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java new file mode 100644 index 000000000..2434deddb --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate; + +public interface SubtreeManagerRegistryBuilder<R> { + + R build(); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java new file mode 100644 index 000000000..ee0049977 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate; + +import com.google.common.annotations.Beta; + +/** + * Base exception for the translation layer + */ +@Beta +public class TranslationException extends Exception { + + public TranslationException(final String s) { + super(s); + } + + public TranslationException(final String s, final Throwable cause) { + super(s, cause); + } + + public TranslationException(final Throwable cause) { + super(cause); + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java new file mode 100644 index 000000000..13a7a55da --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.read; + +import com.google.common.annotations.Beta; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * List reader, allowing read of all the elements. + * + * @param <D> Specific DataObject derived type, that is handled by this reader + */ +@Beta +public interface ListReader + <D extends DataObject & Identifiable<K>, K extends Identifier<D>, B extends Builder<D>> extends Reader<D, B> { + + /** + * Read all elements in this list. + * + * @param id Wildcarded identifier of list managed by this reader + * @param ctx Read context + * + * @return List of all entries in this list + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + List<D> readList(@Nonnull final InstanceIdentifier<D> id, @Nonnull final ReadContext ctx) + throws ReadFailedException; + + /** + * Get IDs for all entries in the list. + */ + List<K> getAllIds(@Nonnull InstanceIdentifier<D> id, @Nonnull ReadContext ctx) + throws ReadFailedException; + + /** + * Merge read data into provided parent builder. + */ + void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<D> readData); + + @Override + default void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final D readValue) { + merge(parentBuilder, Collections.singletonList(readValue)); + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java new file mode 100644 index 000000000..e3ddd420c --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.read; + +import io.fd.honeycomb.v3po.translate.ModificationContext; + +/** + * Context providing information about current state of DataTree to readers + */ +public interface ReadContext extends ModificationContext { + +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java new file mode 100644 index 000000000..51d4fcb5a --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.read; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.v3po.translate.TranslationException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Thrown when a reader or customizer is not able to read data for the given id. + */ +public class ReadFailedException extends TranslationException { + + private final InstanceIdentifier<?> failedId; + + /** + * Constructs an ReadFailedException given data id and exception cause. + * + * @param failedId instance identifier of the data object that could not be read + * @param cause the cause of read failure + */ + public ReadFailedException(@Nonnull final InstanceIdentifier<?> failedId, final Throwable cause) { + super("Failed to read " + failedId, cause); + this.failedId = checkNotNull(failedId, "failedId should not be null"); + } + + /** + * Constructs an ReadFailedException given data id. + * + * @param failedId instance identifier of the data object that could not be read + */ + public ReadFailedException(@Nonnull final InstanceIdentifier<?> failedId) { + this(failedId, null); + } + + /** + * Returns id of the data object that could not be read. + * + * @return data object instance identifier + */ + @Nonnull + public InstanceIdentifier<?> getFailedId() { + return failedId; + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java new file mode 100644 index 000000000..d0bf0dea1 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.read; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.translate.SubtreeManager; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Base reader, responsible for translation between DataObjects and any other side. + * + * @param <D> Specific DataObject derived type, that is handled by this reader + */ +@Beta +public interface Reader<D extends DataObject, B extends Builder<D>> extends SubtreeManager<D> { + + // TODO make async + + /** + * Reads data identified by id + * + * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For + * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the + * right node or to delegate the read to a child reader. + * @param ctx Read context + * + * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + Optional<? extends DataObject> read(@Nonnull InstanceIdentifier<? extends DataObject> id, + @Nonnull ReadContext ctx) throws ReadFailedException; + + /** + * Fill in current node's attributes + * + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * @param builder Builder object for current node where the read attributes must be placed + * @param ctx Current read context + */ + void readCurrentAttributes(@Nonnull InstanceIdentifier<D> id, + @Nonnull B builder, + @Nonnull ReadContext ctx) throws ReadFailedException; + + /** + * Return new instance of a builder object for current node + * + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * @return Builder object for current node type + */ + @Nonnull + B getBuilder(InstanceIdentifier<D> id); + + /** + * Merge read data into provided parent builder. + */ + void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final D readValue); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java new file mode 100644 index 000000000..61472f8d2 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.read; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; +import javax.annotation.Nonnull; + +/** + * Factory producing readers for {@link ModifiableReaderRegistryBuilder}. + */ +@Beta +public interface ReaderFactory extends AutoCloseable { + + /** + * Initialize 1 or more readers and add them to provided registry. + */ + void init(@Nonnull ModifiableReaderRegistryBuilder registry); + + @Override + default void close() { + // NOOP TODO allow unregister + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java new file mode 100644 index 000000000..c2eba4f72 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.read.registry; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.translate.ModifiableSubtreeManagerRegistryBuilder; +import io.fd.honeycomb.v3po.translate.read.Reader; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Mutable registry that allows adding new readers. + */ +@Beta +public interface ModifiableReaderRegistryBuilder + extends ModifiableSubtreeManagerRegistryBuilder<Reader<? extends DataObject, ? extends Builder<?>>> { + + // TODO we should be able to add structural/reflexive readers automatically in the registry builder, we just need builder class + // We would need generated class loading strategy instance and then load builder classes relying on naming + package conventions of Binding spec + /** + * Add a structural reader that performs no read operation on its own, just fills in the hierarchy. + */ + <D extends DataObject> void addStructuralReader(@Nonnull InstanceIdentifier<D> id, + @Nonnull Class<? extends Builder<D>> builderType); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java new file mode 100644 index 000000000..308ec238d --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.read.registry; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import com.google.common.collect.Multimap; +import io.fd.honeycomb.v3po.translate.read.ReadContext; +import io.fd.honeycomb.v3po.translate.read.ReadFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Simple delegating reader suitable as a holder for all other root readers, providing readAll feature. + */ +@Beta +public interface ReaderRegistry { + + /** + * Performs read on all registered root readers and merges the results into a Multimap. Keys represent identifiers + * for root DataObjects from the data tree modeled by YANG. + * + * @param ctx Read context + * + * @return multimap that preserves deterministic iteration order across non-distinct key values + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll(@Nonnull final ReadContext ctx) + throws ReadFailedException; + + /** + * Reads data identified by id. + * + * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For + * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the + * right node or to delegate the read to a child reader. + * @param ctx Read context + * + * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + Optional<? extends DataObject> read(@Nonnull InstanceIdentifier<? extends DataObject> id, + @Nonnull ReadContext ctx) + throws ReadFailedException; +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java new file mode 100644 index 000000000..ff95d6248 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.read.registry; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.translate.SubtreeManagerRegistryBuilder; + +/** + * Builder for reader registries. + */ +@Beta +public interface ReaderRegistryBuilder extends SubtreeManagerRegistryBuilder<ReaderRegistry> { +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java new file mode 100644 index 000000000..0d891ecba --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Simple wrapper for BA id + data before and after state. Does not allow both before and after to be null. + */ +public class DataObjectUpdate { + + @Nonnull + private final InstanceIdentifier<?> id; + @Nullable + private final DataObject dataBefore; + @Nullable + private final DataObject dataAfter; + + private DataObjectUpdate(@Nonnull final InstanceIdentifier<?> id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter) { + this.id = checkNotNull(id); + this.dataAfter = dataAfter; + this.dataBefore = dataBefore; + } + + public DataObject getDataBefore() { + return dataBefore; + } + + public DataObject getDataAfter() { + return dataAfter; + } + + public InstanceIdentifier<?> getId() { + return id; + } + + public static DataObjectUpdate create(@Nonnull final InstanceIdentifier<?> id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter) { + checkArgument(!(dataBefore == null && dataAfter == null), "Both before and after data are null"); + if (dataBefore != null) { + checkArgument(id.getTargetType().isAssignableFrom(dataBefore.getClass())); + } + if (dataAfter != null) { + checkArgument(id.getTargetType().isAssignableFrom(dataAfter.getClass())); + } + + return dataAfter == null + ? new DataObjectDelete(id, dataBefore) + : new DataObjectUpdate(id, dataBefore, dataAfter); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final DataObjectUpdate that = (DataObjectUpdate) o; + + return id.equals(that.id); + + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String toString() { + return "DataObjectUpdate{" + "id=" + id + + ", dataBefore=" + dataBefore + + ", dataAfter=" + dataAfter + + '}'; + } + + public DataObjectUpdate reverse() { + return DataObjectUpdate.create(id, dataAfter, dataBefore); + } + + public static class DataObjectDelete extends DataObjectUpdate { + + private DataObjectDelete(@Nonnull final InstanceIdentifier<?> id, + @Nullable final DataObject dataBefore) { + super(id, dataBefore, null); + } + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java new file mode 100644 index 000000000..f29289d2d --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.write; + +import com.google.common.annotations.Beta; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; + +/** + * List writer, responsible for translation between a list of DataObjects and any other side. + * Handling all update operations(create, update, delete) + * + * @param <D> Specific DataObject derived type, that is handled by this writer + * @param <K> Identifier/key for D + */ +@Beta +public interface ListWriter<D extends DataObject & Identifiable<K>, K extends Identifier<D>> extends Writer<D> { +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java new file mode 100644 index 000000000..3433b3f34 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.write; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.translate.ModificationContext; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Context providing information about current state of DataTree to writers + */ +@Beta +public interface WriteContext extends ModificationContext { + + /** + * Read any config data object before current modification was applied + * + * @param currentId Id of an object to read + * + * @return Data before the modification was applied + */ + <T extends DataObject> Optional<T> readBefore(@Nonnull final InstanceIdentifier<T> currentId); + + /** + * Read any config data object from current modification + * + * @param currentId Id of an object to read + * + * @return Data from the modification + */ + <T extends DataObject> Optional<T> readAfter(@Nonnull final InstanceIdentifier<T> currentId); + +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java new file mode 100644 index 000000000..10a664fcf --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.v3po.translate.TranslationException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Thrown when a writer or customizer is not able to write/update/delete data . + */ +public class WriteFailedException extends TranslationException { + + private final InstanceIdentifier<?> failedId; + + /** + * Constructs an WriteFailedException given data id, exception detail message and exception cause. + * + * @param failedId instance identifier of the data object that could not be read + * @param cause the cause of read failure + * @param message the exception detail message + */ + public WriteFailedException(@Nonnull final InstanceIdentifier<?> failedId, + @Nonnull final String message, + @Nonnull final Throwable cause) { + super(message, cause); + this.failedId = checkNotNull(failedId, "failedId should not be null"); + } + + /** + * Constructs an WriteFailedException given data id. + * + * @param failedId instance identifier of the data object that could not be written + */ + public WriteFailedException(@Nonnull final InstanceIdentifier<?> failedId, + @Nonnull final String message) { + super(message); + this.failedId = checkNotNull(failedId, "failedId should not be null"); + } + + /** + * Constructs an WriteFailedException given data id and exception cause. + * + * @param failedId instance identifier of the data object that could not be read + * @param cause the cause of read failure + */ + public WriteFailedException(@Nonnull final InstanceIdentifier<?> failedId, + @Nonnull final Throwable cause) { + super(cause); + this.failedId = checkNotNull(failedId, "failedId should not be null"); + } + + /** + * Returns id of the data object that could not be written. + * + * @return data object instance identifier + */ + @Nonnull + public InstanceIdentifier<?> getFailedId() { + return failedId; + } + + + /** + * Delete specific write failed exception + */ + public static class DeleteFailedException extends WriteFailedException { + + public DeleteFailedException(@Nonnull final InstanceIdentifier<?> failedId, @Nonnull final Throwable cause) { + super(failedId, getMsg(failedId), cause); + } + + private static String getMsg(@Nonnull final InstanceIdentifier<?> failedId) { + return String.format("Failed to delete data at: %s", failedId); + } + + public DeleteFailedException(@Nonnull final InstanceIdentifier<?> failedId) { + super(failedId, getMsg(failedId)); + } + } + + /** + * Create specific write failed exception + */ + public static class CreateFailedException extends WriteFailedException { + + private final DataObject data; + + public CreateFailedException(@Nonnull final InstanceIdentifier<?> failedId, + @Nonnull final DataObject data, + @Nonnull final Throwable cause) { + super(failedId, getMsg(failedId, data), cause); + this.data = checkNotNull(data, "data"); + } + + private static String getMsg(final @Nonnull InstanceIdentifier<?> failedId, final DataObject data) { + return String.format("Failed to create data: %s at: %s", data, failedId); + } + + public CreateFailedException(@Nonnull final InstanceIdentifier<?> failedId, + @Nonnull final DataObject data) { + super(failedId, getMsg(failedId, data)); + this.data = checkNotNull(data, "data"); + } + + public DataObject getData() { + return data; + } + } + + /** + * Update specific write failed exception + */ + public static class UpdateFailedException extends WriteFailedException { + + private final DataObject dataBefore; + private final DataObject dataAfter; + + public UpdateFailedException(@Nonnull final InstanceIdentifier<?> failedId, + @Nonnull final DataObject dataBefore, + @Nonnull final DataObject dataAfter, + @Nonnull final Throwable cause) { + super(failedId, getMsg(failedId, dataBefore, dataAfter), cause); + this.dataBefore = checkNotNull(dataBefore, "dataBefore"); + this.dataAfter = checkNotNull(dataAfter, "dataAfter"); + } + + private static String getMsg(final @Nonnull InstanceIdentifier<?> failedId, final DataObject dataBefore, + final DataObject dataAfter) { + return String.format("Failed to update data from: %s to: %s, at: %s", dataBefore, dataAfter, failedId); + } + + public UpdateFailedException(@Nonnull final InstanceIdentifier<?> failedId, + @Nonnull final DataObject dataBefore, + @Nonnull final DataObject dataAfter) { + super(failedId, getMsg(failedId, dataBefore, dataAfter)); + this.dataBefore = checkNotNull(dataBefore, "dataBefore"); + this.dataAfter = checkNotNull(dataAfter, "dataAfter"); + } + + public DataObject getDataBefore() { + return dataBefore; + } + + public DataObject getDataAfter() { + return dataAfter; + } + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java new file mode 100644 index 000000000..77abe341c --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.write; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.translate.SubtreeManager; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Base writer, responsible for translation between DataObjects and any other side. Handling all update operations(create, + * update, delete) + * + * @param <D> Specific DataObject derived type, that is handled by this writer + */ +@Beta +public interface Writer<D extends DataObject> extends SubtreeManager<D> { + + /** + * Handle update operation. U from CRUD. + * + * @param id Identifier of data being written + * @param dataBefore Old data + * @param dataAfter New, updated data + * @param ctx Write context enabling writer to get information about candidate data as well as current data + * @throws WriteFailedException if update failed + */ + void update(@Nonnull final InstanceIdentifier<? extends DataObject> id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, + @Nonnull final WriteContext ctx) throws WriteFailedException; +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java new file mode 100644 index 000000000..ffc76a0e4 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.write; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder; +import javax.annotation.Nonnull; + +/** + * Factory producing writers for {@link ModifiableWriterRegistryBuilder}. + */ +@Beta +public interface WriterFactory extends AutoCloseable { + + /** + * Initialize 1 or more writers and add them to provided registry. + */ + void init(@Nonnull ModifiableWriterRegistryBuilder registry); + + @Override + default void close() { + // NOOP TODO allow unregister + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java new file mode 100644 index 000000000..8670a5059 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.write.registry; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.translate.ModifiableSubtreeManagerRegistryBuilder; +import io.fd.honeycomb.v3po.translate.write.Writer; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * Mutable registry that allows adding new writers. + */ +@Beta +public interface ModifiableWriterRegistryBuilder + extends ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> { + +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java new file mode 100644 index 000000000..439a85410 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.write.registry; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import io.fd.honeycomb.v3po.translate.TranslationException; +import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate; +import io.fd.honeycomb.v3po.translate.write.WriteContext; +import io.fd.honeycomb.v3po.translate.write.Writer; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Special {@link Writer} capable of performing bulk updates. + */ +@Beta +public interface WriterRegistry { + + /** + * Performs bulk update. + * + * @throws BulkUpdateException in case bulk update fails + * @throws TranslationException in case some other error occurs while processing update request + */ + void update(@Nonnull DataObjectUpdates updates, + @Nonnull WriteContext ctx) throws TranslationException; + + /** + * Simple DTO containing updates for {@link WriterRegistry}. Currently only deletes and updates (create + update) + * are distinguished. + */ + @Beta + final class DataObjectUpdates { + + private final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates; + private final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes; + + /** + * Create new instance. + * + * @param updates All updates indexed by their unkeyed {@link InstanceIdentifier} + * @param deletes All deletes indexed by their unkeyed {@link InstanceIdentifier} + */ + public DataObjectUpdates(@Nonnull final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates, + @Nonnull final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes) { + this.deletes = deletes; + this.updates = updates; + } + + public Multimap<InstanceIdentifier<?>, DataObjectUpdate> getUpdates() { + return updates; + } + + public Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> getDeletes() { + return deletes; + } + + public boolean isEmpty() { + return updates.isEmpty() && deletes.isEmpty(); + } + + @Override + public String toString() { + return "DataObjectUpdates{" + "updates=" + updates + ", deletes=" + deletes + '}'; + } + + /** + * Get a {@link Set} containing all update types from both updates as well as deletes. + */ + public Set<InstanceIdentifier<?>> getTypeIntersection() { + return Sets.union(deletes.keySet(), updates.keySet()); + } + + /** + * Check whether there is only a single type of data object to be updated. + * + * @return true if there is only a single type of updates (update + delete) + */ + public boolean containsOnlySingleType() { + return getTypeIntersection().size() == 1; + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + final DataObjectUpdates that = (DataObjectUpdates) other; + + if (!updates.equals(that.updates)) { + return false; + } + return deletes.equals(that.deletes); + + } + + @Override + public int hashCode() { + int result = updates.hashCode(); + result = 31 * result + deletes.hashCode(); + return result; + } + + } + + /** + * Thrown when bulk update failed. + */ + @Beta + class BulkUpdateException extends TranslationException { + + private final Reverter reverter; + private final Set<InstanceIdentifier<?>> failedIds; + + /** + * Constructs an BulkUpdateException. + * @param failedIds instance identifiers of the data objects that were not processed during bulk update. + * @param cause the cause of bulk update failure + */ + public BulkUpdateException(@Nonnull final Set<InstanceIdentifier<?>> failedIds, + @Nonnull final Reverter reverter, + @Nonnull final Throwable cause) { + super("Bulk update failed at: " + failedIds, cause); + this.failedIds = failedIds; + this.reverter = checkNotNull(reverter, "reverter should not be null"); + } + + /** + * Reverts changes that were successfully applied during bulk update before failure occurred. + * + * @throws Reverter.RevertFailedException if revert fails + */ + public void revertChanges() throws Reverter.RevertFailedException { + reverter.revert(); + } + + public Set<InstanceIdentifier<?>> getFailedIds() { + return failedIds; + } + } + + /** + * Abstraction over revert mechanism in case of a bulk update failure. + */ + @Beta + interface Reverter { + + /** + * Reverts changes that were successfully applied during bulk update before failure occurred. Changes are + * reverted in reverse order they were applied. + * + * @throws RevertFailedException if not all of applied changes were successfully reverted + */ + void revert() throws RevertFailedException; + + /** + * Thrown when some of the changes applied during bulk update were not reverted. + */ + @Beta + class RevertFailedException extends TranslationException { + + // TODO change to list of VppDataModifications to make debugging easier + private final Set<InstanceIdentifier<?>> notRevertedChanges; + + /** + * Constructs a RevertFailedException with the list of changes that were not reverted. + * + * @param notRevertedChanges list of changes that were not reverted + * @param cause the cause of revert failure + */ + public RevertFailedException(@Nonnull final Set<InstanceIdentifier<?>> notRevertedChanges, + final Throwable cause) { + super(cause); + checkNotNull(notRevertedChanges, "notRevertedChanges should not be null"); + this.notRevertedChanges = ImmutableSet.copyOf(notRevertedChanges); + } + + /** + * Returns the list of changes that were not reverted. + * + * @return list of changes that were not reverted + */ + @Nonnull + public Set<InstanceIdentifier<?>> getNotRevertedChanges() { + return notRevertedChanges; + } + } + } +}
\ No newline at end of file diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java new file mode 100644 index 000000000..3f0289ece --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.write.registry; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.translate.SubtreeManagerRegistryBuilder; + +/** + * Builder for writer registries. + */ +@Beta +public interface WriterRegistryBuilder extends SubtreeManagerRegistryBuilder<WriterRegistry> { +} diff --git a/infra/translate-api/src/main/yang/translate-api.yang b/infra/translate-api/src/main/yang/translate-api.yang new file mode 100644 index 000000000..796632dd2 --- /dev/null +++ b/infra/translate-api/src/main/yang/translate-api.yang @@ -0,0 +1,52 @@ +module translate-api { + yang-version 1; + namespace "urn:honeycomb:params:xml:ns:yang:translate:api"; + prefix "tapi"; + + import config { prefix config; revision-date 2013-04-05; } + + description + "This module contains the base YANG definitions for + readers/writers plugged into a honeycomb"; + + revision "2016-04-06" { + description + "Initial revision."; + } + + identity honeycomb-reader-factory { + base "config:service-type"; + config:java-class io.fd.honeycomb.v3po.translate.read.ReaderFactory; + } + + identity honeycomb-reader-registry { + base "config:service-type"; + config:java-class io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; + } + + identity honeycomb-reader-registry-builder { + base "config:service-type"; + config:java-class io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistryBuilder; + } + + identity honeycomb-writer-factory { + base "config:service-type"; + config:java-class io.fd.honeycomb.v3po.translate.write.WriterFactory; + } + + identity honeycomb-writer-registry { + base "config:service-type"; + config:java-class io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder; + } + + identity honeycomb-writer-registry-builder { + base "config:service-type"; + config:java-class io.fd.honeycomb.v3po.translate.write.registry.WriterRegistryBuilder; + } + + identity honeycomb-mapping-context { + base "config:service-type"; + config:java-class io.fd.honeycomb.v3po.translate.MappingContext; + } + +}
\ No newline at end of file diff --git a/infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java b/infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java new file mode 100644 index 000000000..71c0afbd3 --- /dev/null +++ b/infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate; + +import io.fd.honeycomb.v3po.translate.read.ReadFailedException; +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class ReadFailedExceptionTest { + + @Test + public void testInstantiation() { + final InstanceIdentifier<DataObject> id = InstanceIdentifier.create(DataObject.class); + ReadFailedException e = new ReadFailedException(id); + Assert.assertEquals(id, e.getFailedId()); + Assert.assertNull(e.getCause()); + Assert.assertTrue(e.getMessage().contains(id.toString())); + } + + @Test + public void testInstantiationWithCause() { + final InstanceIdentifier<DataObject> id = InstanceIdentifier.create(DataObject.class); + final RuntimeException cause = new RuntimeException(); + ReadFailedException e = new ReadFailedException(id, cause); + Assert.assertEquals(id, e.getFailedId()); + Assert.assertEquals(cause, e.getCause()); + Assert.assertTrue(e.getMessage().contains(id.toString())); + } + + @Test(expected = NullPointerException.class) + public void testInstantiationFailed() { + new ReadFailedException(null); + } +}
\ No newline at end of file |