From f877744f62d91eb3c9c7e589751cbf5200d61a54 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Tue, 1 Sep 2015 16:06:54 +0200 Subject: [PATCH] Bug 3875: Introduced transforming stream writer Introduced simple QName transforming stream writer which could be used to re-stream and rebuild YANG Data with replacement of QNames. QNameTransformingStreamWriter currently supports custom mapping, replacement of specified QNameModules and replacement of specified QNames Change-Id: I98b253a0f184e1996d78b99fa8cfb20a7d588b96 Signed-off-by: Tony Tkacik --- yang/pom.xml | 1 + yang/yang-data-transform/pom.xml | 34 +++ .../NormalizedNodeTransformations.java | 70 +++++++ .../QNameModuleReplacementFunction.java | 33 +++ .../transform/QNameReplacementFunction.java | 29 +++ .../QNameTransformingStreamWriter.java | 198 ++++++++++++++++++ 6 files changed, 365 insertions(+) create mode 100644 yang/yang-data-transform/pom.xml create mode 100644 yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/NormalizedNodeTransformations.java create mode 100644 yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameModuleReplacementFunction.java create mode 100644 yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameReplacementFunction.java create mode 100644 yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameTransformingStreamWriter.java diff --git a/yang/pom.xml b/yang/pom.xml index 5c19ea3049..1c1afcf2e1 100644 --- a/yang/pom.xml +++ b/yang/pom.xml @@ -26,6 +26,7 @@ yang-data-api yang-data-util yang-data-impl + yang-data-transform yang-data-operations yang-data-codec-gson yang-model-api diff --git a/yang/yang-data-transform/pom.xml b/yang/yang-data-transform/pom.xml new file mode 100644 index 0000000000..fe6247646e --- /dev/null +++ b/yang/yang-data-transform/pom.xml @@ -0,0 +1,34 @@ + + + + + + + org.opendaylight.yangtools + yangtools-parent + 0.8.0-SNAPSHOT + /../../common/parent/pom.xml + + + 4.0.0 + yang-data-transform + ${project.artifactId} + ${project.artifactId} + + + + ${project.groupId} + yang-data-api + + + ${project.groupId} + yang-data-impl + + + diff --git a/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/NormalizedNodeTransformations.java b/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/NormalizedNodeTransformations.java new file mode 100644 index 0000000000..766dd8b822 --- /dev/null +++ b/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/NormalizedNodeTransformations.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.transform; + +import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Throwables; +import java.io.IOException; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult; + +@Beta +public final class NormalizedNodeTransformations { + + private NormalizedNodeTransformations() { + throw new UnsupportedOperationException("Utility class."); + } + + public static NormalizedNode transformQNames(NormalizedNode original, Function mapping) { + NormalizedNodeResult result = new NormalizedNodeResult(); + NormalizedNodeStreamWriter nodeWriter = ImmutableNormalizedNodeStreamWriter.from(result); + NormalizedNodeStreamWriter transformWriter = QNameTransformingStreamWriter.fromFunction(nodeWriter, mapping); + try { + NormalizedNodeWriter.forStreamWriter(transformWriter).write(original); + return result.getResult(); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + /** + * + * Returns a {@link NormalizedNode} with QNames replaced by supplied mapping. + * + * @param original Original Normalized Node + * @param mapping Map of QNames to transform. Not listed QNames are preserved. + * @return Normalized Node with replaced QNames. + */ + public static NormalizedNode replaceQNames(@Nonnull NormalizedNode original, + @Nonnull Map mapping) { + return transformQNames(original, new QNameReplacementFunction(mapping)); + } + + /** + * + * Returns a {@link NormalizedNode} with QNameModules replaced by supplied mapping. + * + * @param original Original Normalized Node + * @param mapping Map of QNameModules to transform. Not listed QNameModules are preserved. + * @return Normalized Node with replaced QNameModules. + */ + + public static NormalizedNode replaceQNameModules(@Nonnull NormalizedNode original, + @Nonnull Map mapping) { + return transformQNames(original, new QNameModuleReplacementFunction(mapping)); + } + +} diff --git a/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameModuleReplacementFunction.java b/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameModuleReplacementFunction.java new file mode 100644 index 0000000000..6790fc004d --- /dev/null +++ b/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameModuleReplacementFunction.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.transform; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import java.util.Map; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; + +class QNameModuleReplacementFunction implements Function { + + private final Map mapping; + + QNameModuleReplacementFunction(Map mapping) { + this.mapping = Preconditions.checkNotNull(mapping); + } + + @Override + public QName apply(QName input) { + QNameModule potential = mapping.get(input.getModule()); + if (potential != null) { + return QName.cachedReference(QName.create(potential, input.getLocalName())); + } + return input; + } + +} diff --git a/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameReplacementFunction.java b/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameReplacementFunction.java new file mode 100644 index 0000000000..cba587c92b --- /dev/null +++ b/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameReplacementFunction.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.transform; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import java.util.Map; +import org.opendaylight.yangtools.yang.common.QName; + +class QNameReplacementFunction implements Function { + + private final Map mapping; + + QNameReplacementFunction(Map mapping) { + this.mapping = Preconditions.checkNotNull(mapping); + } + + @Override + public QName apply(QName input) { + QName potential = mapping.get(input); + return potential != null ? potential : input; + } + +} diff --git a/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameTransformingStreamWriter.java b/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameTransformingStreamWriter.java new file mode 100644 index 0000000000..70925f1693 --- /dev/null +++ b/yang/yang-data-transform/src/main/java/org/opendaylight/yangtools/transform/QNameTransformingStreamWriter.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.transform; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.ForwardingObject; +import com.google.common.collect.ImmutableSet; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; + +/** + * + * Stateless Normalized Node Stream Writer decorator, which performs QName translation. + * + * This class serves as base for Normalized Node Stream Writer decorators with option to transform + * QNames by user-implemented {@link #transform(QName)} function. + * + */ +public abstract class QNameTransformingStreamWriter extends ForwardingObject implements NormalizedNodeStreamWriter { + + // FIXME: Probably use loading cache to decrease memory + @Override + protected abstract NormalizedNodeStreamWriter delegate(); + + /** + * Returns decorator, which uses supplied function to transform QNames. + * + * @param delegate Underlying normalized node stream writer + * @param transformation Transformation function, function is required to return non-null + * values. + * @return decorator, which uses supplied function to transform QNames. + */ + public static NormalizedNodeStreamWriter fromFunction(final NormalizedNodeStreamWriter delegate, + final Function transformation) { + return new QNameTransformingStreamWriter() { + + @Override + protected NormalizedNodeStreamWriter delegate() { + return delegate; + } + + @Override + protected QName transform(QName key) { + return transformation.apply(key); + } + + }; + } + + /** + * Returns decorator, which uses supplied map to transform QNames. + * + * QNames not present in map are left unchanged. + * + * @param delegate Underlying normalized node stream writer + * @param mapping Immutable map which represent mapping from original to new values. + * @return decorator, which uses supplied mapping to transform QNames. + */ + public static NormalizedNodeStreamWriter createQNameReplacing(NormalizedNodeStreamWriter delegate, + final Map mapping) { + return fromFunction(delegate, new QNameReplacementFunction(mapping)); + } + + /** + * Returns decorator, which uses supplied map to transform QNameModules. + * + * QNameModules not present in map are left unchanged. + * + * @param delegate Underlying normalized node stream writer + * @param mapping Immutable map which represent mapping from original to new values. + * @return decorator, which uses supplied mapping to transform QNameModules. + */ + public static NormalizedNodeStreamWriter createQNameModuleReplacing(NormalizedNodeStreamWriter delegate, + final Map mapping) { + return fromFunction(delegate, new QNameModuleReplacementFunction(mapping)); + } + + /** + * Transforms a QName to new mapping. + * + * NOTE: If QName should be unchanged implemention needs to return original QName. + * + * @param key QName to transform. + * @return Returns new value of QName. + */ + protected abstract @Nonnull QName transform(@Nonnull QName key); + + @Override + public void leafNode(NodeIdentifier name, Object value) throws IOException, IllegalArgumentException { + delegate().leafNode(transform(name), value); + } + + @Override + public void startLeafSet(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException { + delegate().startLeafSet(transform(name), childSizeHint); + } + + @Override + public void leafSetEntryNode(Object value) throws IOException, IllegalArgumentException { + delegate().leafSetEntryNode(value); + } + + @Override + public void startContainerNode(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException { + delegate().startContainerNode(transform(name), childSizeHint); + } + + @Override + public void startUnkeyedList(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException { + delegate().startUnkeyedList(transform(name), childSizeHint); + } + + @Override + public void startUnkeyedListItem(NodeIdentifier name, int childSizeHint) throws IOException, IllegalStateException { + delegate().startUnkeyedListItem(transform(name), childSizeHint); + } + + @Override + public void startMapNode(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException { + delegate().startMapNode(transform(name), childSizeHint); + } + + @Override + public void startMapEntryNode(NodeIdentifierWithPredicates identifier, int childSizeHint) throws IOException, + IllegalArgumentException { + delegate().startMapEntryNode(transform(identifier), childSizeHint); + } + + @Override + public void startOrderedMapNode(NodeIdentifier name, int childSizeHint) throws IOException, + IllegalArgumentException { + delegate().startOrderedMapNode(transform(name), childSizeHint); + } + + @Override + public void startChoiceNode(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException { + delegate().startChoiceNode(transform(name), childSizeHint); + } + + @Override + public void startAugmentationNode(AugmentationIdentifier identifier) throws IOException, IllegalArgumentException { + delegate().startAugmentationNode(transform(identifier)); + } + + @Override + public void anyxmlNode(NodeIdentifier name, Object value) throws IOException, IllegalArgumentException { + delegate().anyxmlNode(transform(name), value); + } + + @Override + public void endNode() throws IOException, IllegalStateException { + delegate().endNode(); + } + + @Override + public void close() throws IOException { + delegate().close(); + } + + @Override + public void flush() throws IOException { + delegate().flush(); + } + + private NodeIdentifier transform(NodeIdentifier name) { + return new NodeIdentifier(transform(name.getNodeType())); + } + + private AugmentationIdentifier transform(AugmentationIdentifier identifier) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (QName original : identifier.getPossibleChildNames()) { + builder.add(transform(original)); + } + return new AugmentationIdentifier(builder.build()); + } + + private NodeIdentifierWithPredicates transform(NodeIdentifierWithPredicates identifier) { + Map keyValues = new HashMap<>(); + for (Map.Entry original : identifier.getKeyValues().entrySet()) { + keyValues.put(transform(original.getKey()), original.getValue()); + } + return new NodeIdentifierWithPredicates(transform(identifier.getNodeType()), keyValues); + } +} -- 2.36.6