2 * Copyright (c) 2016 Intel Corporation and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.data.codec.xml;
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.collect.ImmutableList;
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 import java.util.List;
17 import javax.xml.namespace.NamespaceContext;
18 import javax.xml.stream.XMLStreamException;
19 import javax.xml.stream.XMLStreamWriter;
20 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
24 abstract class UnionXmlCodec<T> implements XmlCodec<T> {
25 private static final class Diverse extends UnionXmlCodec<Object> {
26 Diverse(final List<XmlCodec<?>> codecs) {
31 public Class<Object> getDataType() {
36 private static final class SingleType<T> extends UnionXmlCodec<T> {
37 private final Class<T> dataClass;
39 SingleType(final Class<T> dataClass, final List<XmlCodec<?>> codecs) {
41 this.dataClass = requireNonNull(dataClass);
45 public Class<T> getDataType() {
50 private static final Logger LOG = LoggerFactory.getLogger(UnionXmlCodec.class);
52 private final ImmutableList<XmlCodec<?>> codecs;
54 UnionXmlCodec(final List<XmlCodec<?>> codecs) {
55 this.codecs = ImmutableList.copyOf(codecs);
58 static UnionXmlCodec<?> create(final UnionTypeDefinition type, final List<XmlCodec<?>> codecs) {
59 final Iterator<XmlCodec<?>> it = codecs.iterator();
60 verify(it.hasNext(), "Union %s has no subtypes", type);
62 Class<?> dataClass = it.next().getDataType();
63 while (it.hasNext()) {
64 final Class<?> next = it.next().getDataType();
65 if (!dataClass.equals(next)) {
66 LOG.debug("Type {} has diverse data classes: {} and {}", type, dataClass, next);
67 return new Diverse(codecs);
71 LOG.debug("Type {} has single data class {}", type, dataClass);
72 return new SingleType<>(dataClass, codecs);
76 @SuppressWarnings("checkstyle:illegalCatch")
77 public final T parseValue(final NamespaceContext ctx, final String str) {
78 final var suppressed = new ArrayList<RuntimeException>();
80 for (XmlCodec<?> codec : codecs) {
83 ret = codec.parseValue(ctx, str);
84 } catch (RuntimeException e) {
85 LOG.debug("Codec {} did not accept input '{}'", codec, str, e);
90 return getDataType().cast(ret);
93 final var ex = new IllegalArgumentException("Invalid value \"" + str + "\" for union type.");
94 suppressed.forEach(ex::addSuppressed);
99 @SuppressWarnings("checkstyle:illegalCatch")
100 public void writeValue(final XMLStreamWriter ctx, final Object value) throws XMLStreamException {
101 for (XmlCodec<?> codec : codecs) {
102 if (!codec.getDataType().isInstance(value)) {
103 LOG.debug("Codec {} cannot accept input {}, skipping it", codec, value);
107 @SuppressWarnings("unchecked")
108 final XmlCodec<Object> objCodec = (XmlCodec<Object>) codec;
110 objCodec.writeValue(ctx, value);
112 } catch (RuntimeException e) {
113 LOG.debug("Codec {} failed to serialize {}", codec, value, e);
117 throw new IllegalArgumentException("No codec would accept value \"" + value + "\"");