+public class CompositeNodeDataWithSchema<T extends DataSchemaNode> extends AbstractNodeDataWithSchema<T> {
+ /**
+ * Policy on how child nodes should be treated when an attempt is made to add them multiple times.
+ */
+ @Beta
+ public enum ChildReusePolicy {
+ /**
+ * Do not consider any existing nodes at all, just perform a straight append. Multiple occurrences of a child
+ * will result in multiple children being emitted. This is almost certainly the wrong policy unless the caller
+ * prevents such a situation from arising via some different mechanism.
+ */
+ NOOP,
+ /**
+ * Do not allow duplicate definition of a child node. This would typically be used when a child cannot be
+ * encountered multiple times, but the caller does not make any provision to detect such a conflict. If a child
+ * node would end up being defined a second time, {@link DuplicateChildNodeRejectedException} is reported.
+ */
+ REJECT {
+ @Override
+ AbstractNodeDataWithSchema<?> appendChild(final Collection<AbstractNodeDataWithSchema<?>> view,
+ final AbstractNodeDataWithSchema<?> newChild) {
+ final DataSchemaNode childSchema = newChild.getSchema();
+ final AbstractNodeDataWithSchema<?> existing = findExistingChild(view, childSchema);
+ if (existing != null) {
+ throw new DuplicateChildNodeRejectedException("Duplicate child " + childSchema.getQName());
+ }
+ return super.appendChild(view, newChild);
+ }
+ },
+ /**
+ * Reuse previously-defined child node. This is most appropriate when a child may be visited multiple times
+ * and the intent is to append content of each visit. A typical usage is list elements with RFC7950 XML
+ * encoding, where there is no encapsulating element and hence list entries may be interleaved with other
+ * children.
+ */
+ REUSE {
+ @Override
+ AbstractNodeDataWithSchema<?> appendChild(final Collection<AbstractNodeDataWithSchema<?>> view,
+ final AbstractNodeDataWithSchema<?> newChild) {
+ final AbstractNodeDataWithSchema<?> existing = findExistingChild(view, newChild.getSchema());
+ return existing != null ? existing : super.appendChild(view, newChild);
+ }
+ };
+
+ AbstractNodeDataWithSchema<?> appendChild(final Collection<AbstractNodeDataWithSchema<?>> view,
+ final AbstractNodeDataWithSchema<?> newChild) {
+ view.add(newChild);
+ return newChild;
+ }
+
+ static @Nullable AbstractNodeDataWithSchema<?> findExistingChild(
+ final Collection<AbstractNodeDataWithSchema<?>> view, final DataSchemaNode childSchema) {
+ for (AbstractNodeDataWithSchema<?> existing : view) {
+ if (childSchema.equals(existing.getSchema())) {
+ return existing;
+ }
+ }
+ return null;
+ }
+ }