Merge "Complete implementation of DataChangeListenerProxy"
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / sal / dom / broker / impl / DataReaderRouter.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.sal.dom.broker.impl;
9
10 import static com.google.common.base.Preconditions.checkState;
11
12 import com.google.common.collect.Iterables;
13
14 import java.net.URI;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Map.Entry;
23 import java.util.Set;
24
25 import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
28 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
30 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
31 import org.opendaylight.yangtools.yang.data.api.Node;
32 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
33 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 public class DataReaderRouter extends
38 AbstractDataReadRouter<InstanceIdentifier, CompositeNode> {
39     private final static Logger LOG = LoggerFactory
40             .getLogger(DataReaderRouter.class);
41     private final static URI NETCONF_NAMESPACE = URI
42             .create("urn:ietf:params:xml:ns:netconf:base:1.0");
43     private final static QName NETCONF_DATA = new QName(NETCONF_NAMESPACE,
44             "data");
45
46     @Override
47     protected CompositeNodeTOImpl merge(final InstanceIdentifier path,
48             final Iterable<CompositeNode> data) {
49         PathArgument pathArgument = Iterables.getLast(path.getPathArguments(), null);
50         boolean empty = true;
51         QName name = (pathArgument == null ? null : pathArgument.getNodeType());
52         final ArrayList<Node<?>> nodes = new ArrayList<Node<?>>();
53         final HashMap<QName, SimpleNode<?>> keyNodes = new HashMap<QName, SimpleNode<?>>();
54         for (final CompositeNode dataBit : data) {
55             try {
56                 if (pathArgument != null && dataBit != null) {
57                     empty = false;
58                     final Map<QName, SimpleNode<?>> keyNodesLocal = getKeyNodes(
59                             pathArgument, dataBit);
60                     nodes.addAll(this.childrenWithout(dataBit,
61                             keyNodesLocal.entrySet()));
62                 } else if (dataBit != null) {
63                     empty = false;
64                     nodes.addAll(dataBit.getValue());
65                 }
66             } catch (IllegalStateException e) {
67                 LOG.error("BUG: Readed data for path {} was invalid", path, e);
68             }
69         }
70         if (empty) {
71             return null;
72         }
73         /**
74          * Reading from Root
75          *
76          */
77         if (pathArgument == null) {
78             return new CompositeNodeTOImpl(NETCONF_DATA, null, nodes);
79         }
80         final ArrayList<Node<?>> finalNodes = new ArrayList<Node<?>>(
81                 nodes.size() + keyNodes.size());
82         finalNodes.addAll(keyNodes.values());
83         finalNodes.addAll(nodes);
84         return new CompositeNodeTOImpl(name, null, finalNodes);
85     }
86
87     protected Map<QName, SimpleNode<?>> _getKeyNodes(
88             final PathArgument argument, final CompositeNode node) {
89         return Collections.emptyMap();
90     }
91
92     protected Map<QName, SimpleNode<?>> _getKeyNodes(
93             final NodeIdentifierWithPredicates argument,
94             final CompositeNode node) {
95         final HashMap<QName, SimpleNode<?>> ret = new HashMap<QName, SimpleNode<?>>();
96         for (final Entry<QName, Object> keyValue : argument.getKeyValues()
97                 .entrySet()) {
98             final List<SimpleNode<?>> simpleNode = node
99                     .getSimpleNodesByName(keyValue.getKey());
100             if (simpleNode != null && !simpleNode.isEmpty()) {
101                 checkState(
102                         simpleNode.size() <= 1,
103                         "Only one simple node for key $s is allowed in node $s",
104                         keyValue.getKey(), node);
105                 checkState(
106                         simpleNode.get(0).getValue().equals(keyValue.getValue()),
107                         "Key node must equal to instance identifier value in node $s",
108                         node);
109                 ret.put(keyValue.getKey(), simpleNode.get(0));
110             }
111             final List<CompositeNode> compositeNode = node
112                     .getCompositesByName(keyValue.getKey());
113             checkState(compositeNode == null || compositeNode.isEmpty(),
114                     "Key node must be Simple Node, not composite node.");
115         }
116         return ret;
117     }
118
119     public Map<QName, SimpleNode<?>> getKeyNodes(
120             final InstanceIdentifier.PathArgument argument,
121             final CompositeNode node) {
122         if (argument instanceof InstanceIdentifier.NodeIdentifierWithPredicates) {
123             return _getKeyNodes(
124                     (InstanceIdentifier.NodeIdentifierWithPredicates) argument,
125                     node);
126         } else if (argument != null) {
127             return _getKeyNodes(argument, node);
128         } else {
129             throw new IllegalArgumentException("Unhandled parameter types: "
130                     + Arrays.<Object> asList(argument, node).toString());
131         }
132     }
133
134     private Collection<? extends Node<?>> childrenWithout(
135             final CompositeNode node,
136             final Set<Entry<QName, SimpleNode<?>>> entries) {
137         if (entries.isEmpty()) {
138             return node.getValue();
139         }
140         final List<Node<?>> filteredNodes = new ArrayList<Node<?>>();
141         for (final Node<?> scannedNode : node.getValue()) {
142             if (!entries.contains(scannedNode.getNodeType())) {
143                 filteredNodes.add(scannedNode);
144             }
145         }
146         return filteredNodes;
147     }
148
149 }