Add schema-aware builders
[yangtools.git] / data / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / builder / impl / ImmutableUserMapNodeBuilder.java
1 /*
2  * Copyright (c) 2013 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.yangtools.yang.data.impl.schema.builder.impl;
9
10 import com.google.common.collect.Iterables;
11 import java.util.Collection;
12 import java.util.LinkedHashMap;
13 import java.util.Map;
14 import org.eclipse.jdt.annotation.NonNull;
15 import org.opendaylight.yangtools.util.UnmodifiableCollection;
16 import org.opendaylight.yangtools.util.UnmodifiableMap;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
20 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
24 import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeContainerBuilder;
25 import org.opendaylight.yangtools.yang.data.spi.node.AbstractNormalizedNode;
26 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
27
28 public class ImmutableUserMapNodeBuilder implements CollectionNodeBuilder<MapEntryNode, UserMapNode> {
29     private static final int DEFAULT_CAPACITY = 4;
30
31     private Map<NodeIdentifierWithPredicates, MapEntryNode> value;
32     private NodeIdentifier nodeIdentifier;
33     private boolean dirty;
34
35     ImmutableUserMapNodeBuilder() {
36         this.value = new LinkedHashMap<>(DEFAULT_CAPACITY);
37         this.dirty = false;
38     }
39
40     private ImmutableUserMapNodeBuilder(final int sizeHint) {
41         if (sizeHint >= 0) {
42             this.value = new LinkedHashMap<>(sizeHint + sizeHint / 3);
43         } else {
44             this.value = new LinkedHashMap<>(DEFAULT_CAPACITY);
45         }
46         this.dirty = false;
47     }
48
49     ImmutableUserMapNodeBuilder(final ImmutableUserMapNode node) {
50         this.nodeIdentifier = node.getIdentifier();
51         this.value = node.children;
52         this.dirty = true;
53     }
54
55     public static @NonNull CollectionNodeBuilder<MapEntryNode, UserMapNode> create() {
56         return new ImmutableUserMapNodeBuilder();
57     }
58
59     public static @NonNull CollectionNodeBuilder<MapEntryNode, UserMapNode> create(final int sizeHint) {
60         return new ImmutableUserMapNodeBuilder(sizeHint);
61     }
62
63     public static @NonNull CollectionNodeBuilder<MapEntryNode, UserMapNode> create(final UserMapNode node) {
64         if (!(node instanceof ImmutableUserMapNode)) {
65             throw new UnsupportedOperationException(String.format("Cannot initialize from class %s", node.getClass()));
66         }
67
68         return new ImmutableUserMapNodeBuilder((ImmutableUserMapNode) node);
69     }
70
71     @Deprecated(since = "6.0.7", forRemoval = true)
72     public static @NonNull CollectionNodeBuilder<MapEntryNode, UserMapNode> create(final ListSchemaNode schema) {
73         return new SchemaAwareImmutableOrderedMapNodeBuilder(schema);
74     }
75
76     @Deprecated(since = "6.0.7", forRemoval = true)
77     public static @NonNull CollectionNodeBuilder<MapEntryNode, UserMapNode> create(final ListSchemaNode schema,
78             final MapNode node) {
79         if (node instanceof ImmutableUserMapNode) {
80             return new SchemaAwareImmutableOrderedMapNodeBuilder(schema, (ImmutableUserMapNode) node);
81         }
82         throw new UnsupportedOperationException("Cannot initialize from class " + node.getClass());
83     }
84
85     private void checkDirty() {
86         if (dirty) {
87             value = new LinkedHashMap<>(value);
88             dirty = false;
89         }
90     }
91
92     @Override
93     public CollectionNodeBuilder<MapEntryNode, UserMapNode> withChild(final MapEntryNode child) {
94         checkDirty();
95         this.value.put(child.getIdentifier(), child);
96         return this;
97     }
98
99     @Override
100     public CollectionNodeBuilder<MapEntryNode, UserMapNode> withoutChild(final PathArgument key) {
101         checkDirty();
102         this.value.remove(key);
103         return this;
104     }
105
106     @Override
107     public CollectionNodeBuilder<MapEntryNode, UserMapNode> withValue(final Collection<MapEntryNode> withValue) {
108         // TODO replace or putAll ?
109         for (final MapEntryNode mapEntryNode : withValue) {
110             withChild(mapEntryNode);
111         }
112
113         return this;
114     }
115
116     @Override
117     public CollectionNodeBuilder<MapEntryNode, UserMapNode> withNodeIdentifier(
118             final NodeIdentifier withNodeIdentifier) {
119         this.nodeIdentifier = withNodeIdentifier;
120         return this;
121     }
122
123     @Override
124     public UserMapNode build() {
125         dirty = true;
126         return new ImmutableUserMapNode(nodeIdentifier, value);
127     }
128
129     @Override
130     public CollectionNodeBuilder<MapEntryNode, UserMapNode> addChild(
131             final MapEntryNode child) {
132         return withChild(child);
133     }
134
135
136     @Override
137     public NormalizedNodeContainerBuilder<NodeIdentifier, PathArgument, MapEntryNode, UserMapNode> removeChild(
138             final PathArgument key) {
139         return withoutChild(key);
140     }
141
142     protected static final class ImmutableUserMapNode
143             extends AbstractNormalizedNode<NodeIdentifier, UserMapNode> implements UserMapNode {
144         private final Map<NodeIdentifierWithPredicates, MapEntryNode> children;
145
146         ImmutableUserMapNode(final NodeIdentifier nodeIdentifier,
147                          final Map<NodeIdentifierWithPredicates, MapEntryNode> children) {
148             super(nodeIdentifier);
149             this.children = children;
150         }
151
152         @Override
153         public MapEntryNode childByArg(final NodeIdentifierWithPredicates child) {
154             return children.get(child);
155         }
156
157         @Override
158         public MapEntryNode childAt(final int position) {
159             return Iterables.get(children.values(), position);
160         }
161
162         @Override
163         public int size() {
164             return children.size();
165         }
166
167         @Override
168         public Collection<MapEntryNode> body() {
169             return UnmodifiableCollection.create(children.values());
170         }
171
172         @Override
173         public Map<NodeIdentifierWithPredicates, MapEntryNode> asMap() {
174             return UnmodifiableMap.of(children);
175         }
176
177         @Override
178         protected Class<UserMapNode> implementedType() {
179             return UserMapNode.class;
180         }
181
182         @Override
183         protected int valueHashCode() {
184             // Order is important
185             int hashCode = 1;
186             for (MapEntryNode child : children.values()) {
187                 hashCode = 31 * hashCode + child.hashCode();
188             }
189             return hashCode;
190         }
191
192         @Override
193         protected boolean valueEquals(final UserMapNode other) {
194             final Map<NodeIdentifierWithPredicates, MapEntryNode> otherChildren;
195             if (other instanceof ImmutableUserMapNode) {
196                 otherChildren = ((ImmutableUserMapNode) other).children;
197             } else {
198                 otherChildren = other.asMap();
199             }
200             return Iterables.elementsEqual(children.values(), otherChildren.values());
201         }
202     }
203 }