Binding v2 runtime - adapters - spi 64/59164/2
authorJakub Toth <jakub.toth@pantheon.tech>
Wed, 14 Jun 2017 12:44:16 +0000 (14:44 +0200)
committerMartin Ciglan <martin.ciglan@pantheon.tech>
Mon, 19 Jun 2017 16:11:53 +0000 (16:11 +0000)
Change-Id: I824c5c29fd71ad288df0b3ef9fbeedbc760b98dc
Signed-off-by: Jakub Toth <jakub.toth@pantheon.tech>
(cherry picked from commit 45c59d14f8d8eef21f0a088c310f2e6975504704)

binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractForwardedDataBroker.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractForwardedTransaction.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractWriteTransaction.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/builder/AdapterBuilder.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/builder/BindingDOMAdapterBuilder.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/loader/AdapterLoader.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/loader/BindingDOMAdapterLoader.java [new file with mode: 0644]

diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractForwardedDataBroker.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractForwardedDataBroker.java
new file mode 100644 (file)
index 0000000..38166cd
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.adapter.spi;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This abstract class forwards DOM Data Broker and provides de-serialization of DOM data to Binding data.
+ */
+@Beta
+public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBroker>, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractForwardedDataBroker.class);
+
+    // The Broker to whom we do all forwarding
+    private final DOMDataBroker domDataBroker;
+
+    private final BindingToNormalizedNodeCodec codec;
+
+    protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker, final BindingToNormalizedNodeCodec codec) {
+        this.domDataBroker = domDataBroker;
+        this.codec = codec;
+    }
+
+    protected BindingToNormalizedNodeCodec getCodec() {
+        return codec;
+    }
+
+    @Override
+    public DOMDataBroker getDelegate() {
+        return domDataBroker;
+    }
+
+    protected Map<InstanceIdentifier<? extends TreeNode>, TreeNode> toBinding(
+            final InstanceIdentifier<? extends TreeNode> path,
+            final Map<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized) {
+        final Map<InstanceIdentifier<? extends TreeNode>, TreeNode> newMap = new HashMap<>();
+
+        for (final Map.Entry<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> entry : normalized.entrySet()) {
+            try {
+                final Optional<Entry<InstanceIdentifier<? extends TreeNode>, TreeNode>> potential =
+                        getCodec().toBinding(entry);
+                if (potential.isPresent()) {
+                    final Entry<InstanceIdentifier<? extends TreeNode>, TreeNode> binding = potential.get();
+                    newMap.put(binding.getKey(), binding.getValue());
+                }
+            } catch (final DeserializationException e) {
+                LOG.warn("Failed to transform {}, omitting it", entry, e);
+            }
+        }
+        return newMap;
+    }
+
+    protected Set<InstanceIdentifier<?>> toBinding(final InstanceIdentifier<?> path,
+            final Set<YangInstanceIdentifier> normalized) {
+        final Set<InstanceIdentifier<?>> hashSet = new HashSet<>();
+        for (final YangInstanceIdentifier normalizedPath : normalized) {
+            try {
+                final Optional<InstanceIdentifier<? extends TreeNode>> potential =
+                        getCodec().toBinding(normalizedPath);
+                if (potential.isPresent()) {
+                    final InstanceIdentifier<? extends TreeNode> binding = potential.get();
+                    hashSet.add(binding);
+                } else if (normalizedPath
+                        .getLastPathArgument() instanceof YangInstanceIdentifier.AugmentationIdentifier) {
+                    hashSet.add(path);
+                }
+            } catch (final DeserializationException e) {
+                LOG.warn("Failed to transform {}, omitting it", normalizedPath, e);
+            }
+        }
+        return hashSet;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected Optional<TreeNode> toBindingData(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> data) {
+        if (path.isWildcarded()) {
+            return Optional.absent();
+        }
+        return (Optional<TreeNode>) getCodec().deserializeFunction(path)
+                .apply(Optional.of(data));
+    }
+
+    @Override
+    public void close() {
+        // Intentional NOOP
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractForwardedTransaction.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractForwardedTransaction.java
new file mode 100644 (file)
index 0000000..46f36bf
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.adapter.spi;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.common.api.AsyncTransaction;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Abstract class for forwards transaction and codec for serialize/deserialize DOM and Binding data.
+ *
+ * @param <T>
+ *            - type of asynchronous transaction
+ */
+@Beta
+public abstract class AbstractForwardedTransaction<
+        T extends AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>>>
+        implements Delegator<T>, Identifiable<Object> {
+
+    private final T delegate;
+    private final BindingToNormalizedNodeCodec codec;
+
+    public AbstractForwardedTransaction(final T delegateTx, final BindingToNormalizedNodeCodec codec) {
+        this.delegate = Preconditions.checkNotNull(delegateTx, "Delegate must not be null");
+        this.codec = Preconditions.checkNotNull(codec, "Codec must not be null");
+    }
+
+    @Nonnull
+    @Override
+    public final Object getIdentifier() {
+        return delegate.getIdentifier();
+    }
+
+    @Override
+    public final T getDelegate() {
+        return delegate;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected final <S extends AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>>> S
+            getDelegateChecked(final Class<S> txType) {
+        Preconditions.checkState(txType.isInstance(delegate));
+        return (S) delegate;
+    }
+
+    protected final BindingToNormalizedNodeCodec getCodec() {
+        return codec;
+    }
+
+    protected final <D extends TreeNode> CheckedFuture<Optional<D>, ReadFailedException> doRead(
+            final DOMDataTreeReadTransaction readTx, final LogicalDatastoreType store,
+            final InstanceIdentifier<D> path) {
+        Preconditions.checkArgument(!path.isWildcarded(), "Invalid read of wildcarded path %s", path);
+
+        return MappingCheckedFuture
+                .create(Futures.transform(readTx.read(store, codec.toYangInstanceIdentifierBlocking(path)),
+                        codec.deserializeFunction(path)), ReadFailedException.MAPPER);
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractWriteTransaction.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractWriteTransaction.java
new file mode 100644 (file)
index 0000000..83491cd
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.adapter.spi;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.Map.Entry;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.mdsal.binding.javav2.spec.base.IdentifiableItem;
+import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Abstract Base Transaction for transactions which are backed by {@link DOMDataTreeWriteTransaction}.
+ */
+@Beta
+public abstract class AbstractWriteTransaction<T extends DOMDataTreeWriteTransaction>
+        extends AbstractForwardedTransaction<T> {
+
+    protected AbstractWriteTransaction(final T delegate, final BindingToNormalizedNodeCodec codec) {
+        super(delegate, codec);
+    }
+
+    /**
+     * Put Binding data to specific datastore via
+     * {@link DOMDataTreeWriteTransaction#put(LogicalDatastoreType, YangInstanceIdentifier, NormalizedNode)}.
+     *
+     * @param store
+     *            - specific {@link LogicalDatastoreType}
+     * @param path
+     *            - path to data
+     * @param data
+     *            - data to be written to specific path
+     * @param createParents
+     *            - option to create parent of data to be write
+     */
+    public final <U extends TreeNode> void put(final LogicalDatastoreType store, final InstanceIdentifier<U> path,
+            final U data, final boolean createParents) {
+        Preconditions.checkArgument(!path.isWildcarded(), "Cannot put data into wildcarded path %s", path);
+
+        final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = getCodec().toNormalizedNode(path, data);
+        if (createParents) {
+            ensureParentsByMerge(store, normalized.getKey(), path);
+        } else {
+            ensureListParentIfNeeded(store, path, normalized);
+        }
+
+        getDelegate().put(store, normalized.getKey(), normalized.getValue());
+    }
+
+    /**
+     * Merge Binding data with existing data on specific path via
+     * {@link DOMDataTreeWriteTransaction#merge(LogicalDatastoreType, YangInstanceIdentifier, NormalizedNode)}.
+     *
+     * @param store
+     *            - specific {@link LogicalDatastoreType}
+     * @param path
+     *            - path to data
+     * @param data
+     *            - data to be merged
+     * @param createParents
+     *            - option to create parent of data to be merged
+     */
+    public final <U extends TreeNode> void merge(final LogicalDatastoreType store, final InstanceIdentifier<U> path,
+            final U data, final boolean createParents) {
+        Preconditions.checkArgument(!path.isWildcarded(), "Cannot merge data into wildcarded path %s", path);
+
+        final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = getCodec().toNormalizedNode(path, data);
+        if (createParents) {
+            ensureParentsByMerge(store, normalized.getKey(), path);
+        } else {
+            ensureListParentIfNeeded(store, path, normalized);
+        }
+
+        getDelegate().merge(store, normalized.getKey(), normalized.getValue());
+    }
+
+    /**
+     * Ensures list parent if item is list, otherwise noop.
+     *
+     * <p>
+     * One of properties of binding specification is that it is impossible to represent list as a whole and
+     * thus it is impossible to write empty variation of MapNode without creating parent node, with empty
+     * list.
+     *
+     * <p>
+     * This actually makes writes such as
+     *
+     * <pre>
+     * put("Nodes", new NodesBuilder().build());
+     * put("Nodes/Node[key]", new NodeBuilder().setKey("key").build());
+     * </pre>
+     *
+     * <p>
+     * To result in three DOM operations:
+     *
+     * <pre>
+     * put("/nodes", domNodes);
+     * merge("/nodes/node", domNodeList);
+     * put("/nodes/node/node[key]", domNode);
+     * </pre>
+     *
+     * <p>
+     * In order to allow that to be inserted if necessary, if we know item is list item, we will try to merge
+     * empty MapNode or OrderedNodeMap to ensure list exists.
+     *
+     * @param store
+     *            - Data Store type
+     * @param path
+     *            - Path to data (Binding Aware)
+     * @param normalized
+     *            - Normalized version of data to be written
+     */
+    private void ensureListParentIfNeeded(final LogicalDatastoreType store, final InstanceIdentifier<?> path,
+            final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized) {
+        if (IdentifiableItem.class.isAssignableFrom(path.getTargetType())) {
+            final YangInstanceIdentifier parentMapPath = normalized.getKey().getParent();
+            Preconditions.checkArgument(parentMapPath != null, "Map path %s does not have a parent", path);
+
+            final NormalizedNode<?, ?> emptyParent = getCodec().getDefaultNodeFor(parentMapPath);
+            getDelegate().merge(store, parentMapPath, emptyParent);
+        }
+    }
+
+    /**
+     * Subclasses of this class are required to implement creation of parent nodes based on behavior of their
+     * underlying transaction.
+     *
+     * @param store
+     *            - an instance of LogicalDatastoreType
+     * @param domPath
+     *            - an instance of YangInstanceIdentifier
+     * @param path
+     *            - an instance of InstanceIdentifier
+     */
+    protected final void ensureParentsByMerge(final LogicalDatastoreType store, final YangInstanceIdentifier domPath,
+            final InstanceIdentifier<?> path) {
+        final YangInstanceIdentifier parentPath = domPath.getParent();
+        if (parentPath != null) {
+            final NormalizedNode<?, ?> parentNode = getCodec().instanceIdentifierToNode(parentPath);
+            getDelegate().merge(store, YangInstanceIdentifier.create(parentNode.getIdentifier()), parentNode);
+        }
+    }
+
+    protected final void doDelete(final LogicalDatastoreType store, final InstanceIdentifier<?> path) {
+        Preconditions.checkArgument(!path.isWildcarded(), "Cannot delete wildcarded path %s", path);
+
+        final YangInstanceIdentifier normalized = getCodec().toYangInstanceIdentifierBlocking(path);
+        getDelegate().delete(store, normalized);
+    }
+
+    protected final CheckedFuture<Void, TransactionCommitFailedException> doSubmit() {
+        return getDelegate().submit();
+    }
+
+    protected final boolean doCancel() {
+        return getDelegate().cancel();
+    }
+}
+
diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/builder/AdapterBuilder.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/builder/AdapterBuilder.java
new file mode 100644 (file)
index 0000000..cefc6c1
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.adapter.spi.builder;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import com.google.common.collect.MutableClassToInstanceMap;
+import java.util.Set;
+import org.opendaylight.yangtools.concepts.Builder;
+
+/**
+ * Class for building instances of delegates of specific type.
+ *
+ * @param <T>
+ *            - builded specific object type
+ * @param <D>
+ *            - delegates type
+ */
+@Beta
+public abstract class AdapterBuilder<T, D> implements Builder<T> {
+
+    private final ClassToInstanceMap<D> delegates = MutableClassToInstanceMap.create();
+
+    protected abstract T createInstance(ClassToInstanceMap<D> delegates);
+
+    /**
+     * Get required delegates.
+     *
+     * @return set of delegates
+     */
+    public abstract Set<? extends Class<? extends D>> getRequiredDelegates();
+
+    /**
+     * Add delegate to set of delegates.
+     *
+     * @param type
+     *            - type of delegate
+     * @param impl
+     *            - implementation of delegate
+     */
+    public final <V extends D> void addDelegate(final Class<V> type, final D impl) {
+        delegates.put(type, impl);
+    }
+
+    @Override
+    public final T build() {
+        checkAllRequiredServices();
+        return createInstance(ImmutableClassToInstanceMap.copyOf(delegates));
+    }
+
+    private void checkAllRequiredServices() {
+        for (final Class<? extends D> type : getRequiredDelegates()) {
+            Preconditions.checkState(delegates.get(type) != null, "Requires service %s is not defined.", type);
+        }
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/builder/BindingDOMAdapterBuilder.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/builder/BindingDOMAdapterBuilder.java
new file mode 100644 (file)
index 0000000..125fdcb
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.adapter.spi.builder;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ClassToInstanceMap;
+import org.opendaylight.mdsal.binding.javav2.api.BindingService;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.mdsal.dom.api.DOMService;
+
+/**
+ * Binding DOM adapter builder instance.
+ *
+ * @param <T>
+ *            - Binding Service type
+ */
+@Beta
+public abstract class BindingDOMAdapterBuilder<T extends BindingService> extends AdapterBuilder<T, DOMService> {
+
+    private BindingToNormalizedNodeCodec codec;
+
+    protected abstract T createInstance(BindingToNormalizedNodeCodec codec, ClassToInstanceMap<DOMService> delegates);
+
+    @Override
+    protected final T createInstance(final ClassToInstanceMap<DOMService> delegates) {
+        Preconditions.checkState(codec != null);
+        return createInstance(codec, delegates);
+    }
+
+    /**
+     * Set codec for builder.
+     *
+     * @param codec
+     *            - binding normalized node codec
+     */
+    public void setCodec(final BindingToNormalizedNodeCodec codec) {
+        this.codec = codec;
+    }
+
+    /**
+     * Factory for creating of new builder.
+     *
+     * @param <T>
+     *            - Binding Service type
+     */
+    public interface Factory<T extends BindingService> {
+
+        /**
+         * Prepare new builder for service.
+         *
+         * @return adapter builder
+         */
+        BindingDOMAdapterBuilder<T> newBuilder();
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/loader/AdapterLoader.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/loader/AdapterLoader.java
new file mode 100644 (file)
index 0000000..fcf693f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.adapter.spi.loader;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.cache.CacheLoader;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.mdsal.binding.javav2.dom.adapter.spi.builder.AdapterBuilder;
+
+/**
+ * Class for loading specific delegate type.
+ *
+ * @param <T>
+ *            - built specific object type
+ * @param <D>
+ *            - delegates type
+ */
+@Beta
+public abstract class AdapterLoader<T, D> extends CacheLoader<Class<? extends T>, Optional<T>> {
+
+    @Nullable
+    protected abstract D getDelegate(Class<? extends D> reqDeleg);
+
+    @Nonnull
+    protected abstract AdapterBuilder<? extends T, D> createBuilder(Class<? extends T> key);
+
+    @Nonnull
+    @Override
+    public Optional<T> load(@Nonnull final Class<? extends T> key) {
+
+        final AdapterBuilder<? extends T, D> builder = createBuilder(key);
+        for (final Class<? extends D> reqDeleg : builder.getRequiredDelegates()) {
+            final D deleg = getDelegate(reqDeleg);
+            if (deleg != null) {
+                builder.addDelegate(reqDeleg, deleg);
+            } else {
+                return Optional.absent();
+            }
+        }
+        return Optional.of(builder.build());
+    }
+}
\ No newline at end of file
diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/loader/BindingDOMAdapterLoader.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/loader/BindingDOMAdapterLoader.java
new file mode 100644 (file)
index 0000000..fd547cf
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.adapter.spi.loader;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.api.BindingService;
+import org.opendaylight.mdsal.binding.javav2.dom.adapter.spi.builder.AdapterBuilder;
+import org.opendaylight.mdsal.binding.javav2.dom.adapter.spi.builder.BindingDOMAdapterBuilder;
+import org.opendaylight.mdsal.binding.javav2.dom.adapter.spi.builder.BindingDOMAdapterBuilder.Factory;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.mdsal.dom.api.DOMService;
+
+/**
+ * Loader for factory of services.
+ */
+@Beta
+public abstract class BindingDOMAdapterLoader extends AdapterLoader<BindingService, DOMService> {
+
+    // TODO add all factory of services
+    @SuppressWarnings("checkstyle:GenericWhitespace")
+    private static final Map<Class<?>, BindingDOMAdapterBuilder.Factory<?>> FACTORIES =
+            ImmutableMap.<Class<?>, BindingDOMAdapterBuilder.Factory<?>> builder().build();
+
+    private final BindingToNormalizedNodeCodec codec;
+
+    public BindingDOMAdapterLoader(final BindingToNormalizedNodeCodec codec) {
+        this.codec = codec;
+    }
+
+    @Nonnull
+    @Override
+    protected final AdapterBuilder<? extends BindingService, DOMService>
+            createBuilder(final Class<? extends BindingService> key) {
+        final Factory<?> factory = FACTORIES.get(key);
+        Preconditions.checkArgument(factory != null, "Unsupported service type %s", key);
+        final BindingDOMAdapterBuilder<?> builder = factory.newBuilder();
+        builder.setCodec(codec);
+        return builder;
+    }
+}
\ No newline at end of file