2 * Copyright (c) 2016 Cisco Systems, Inc. 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
9 package org.opendaylight.yangtools.yang.data.codec.xml;
11 import com.google.common.annotations.Beta;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Verify;
14 import com.google.common.cache.CacheBuilder;
15 import com.google.common.cache.CacheLoader;
16 import com.google.common.cache.LoadingCache;
17 import java.util.AbstractMap.SimpleImmutableEntry;
18 import java.util.Map.Entry;
19 import javax.annotation.Nonnull;
20 import javax.annotation.concurrent.ThreadSafe;
21 import javax.xml.namespace.NamespaceContext;
22 import javax.xml.stream.XMLStreamException;
23 import javax.xml.stream.XMLStreamWriter;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
27 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
30 import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
33 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
34 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
35 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
36 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
42 public final class XmlCodecFactory {
44 private static final Logger LOG = LoggerFactory.getLogger(XmlCodecFactory.class);
45 private static final XmlCodec<Object> NULL_CODEC = new XmlCodec<Object>() {
47 public Object deserialize(final String input) {
52 public String serialize(final Object input) {
57 public void serializeToWriter(final XMLStreamWriter writer, final Object value) throws XMLStreamException {
58 // NOOP since codec is unkwown.
59 LOG.warn("Call of the serializeToWriter method on XmlCodecFactory.NULL_CODEC object. No operation " +
64 private final LoadingCache<Entry<TypedSchemaNode, NamespaceContext>, XmlCodec<?>> codecs = CacheBuilder.newBuilder()
65 .softValues().build(new CacheLoader<Entry<TypedSchemaNode, NamespaceContext>, XmlCodec<?>>() {
67 public XmlCodec<?> load(@Nonnull final Entry<TypedSchemaNode, NamespaceContext> pair) {
68 final TypedSchemaNode schemaNode = pair.getKey();
69 final TypeDefinition<?> type = schemaNode.getType();
70 return createCodec(schemaNode, type, pair.getValue());
74 private final SchemaContext schemaContext;
76 private XmlCodecFactory(final SchemaContext context) {
77 this.schemaContext = Preconditions.checkNotNull(context);
81 * Instantiate a new codec factory attached to a particular context.
83 * @param context SchemaContext to which the factory should be bound
84 * @return A codec factory instance.
86 public static XmlCodecFactory create(final SchemaContext context) {
87 return new XmlCodecFactory(context);
90 private XmlCodec<?> createCodec(final DataSchemaNode key, final TypeDefinition<?> type,
91 final NamespaceContext namespaceContext) {
92 if (type instanceof LeafrefTypeDefinition) {
93 return createReferencedTypeCodec(key, (LeafrefTypeDefinition) type, namespaceContext);
94 } else if (type instanceof IdentityrefTypeDefinition) {
95 return createIdentityrefTypeCodec(key, namespaceContext);
96 } else if (type instanceof UnionTypeDefinition) {
97 return createUnionTypeCodec(key, (UnionTypeDefinition)type, namespaceContext);
99 return createFromSimpleType(key, type, namespaceContext);
102 private XmlCodec<?> createReferencedTypeCodec(final DataSchemaNode schema, final LeafrefTypeDefinition type,
103 final NamespaceContext namespaceContext) {
104 // FIXME: Verify if this does indeed support leafref of leafref
105 final TypeDefinition<?> referencedType =
106 SchemaContextUtil.getBaseTypeForLeafRef(type, getSchemaContext(), schema);
107 Verify.verifyNotNull(referencedType, "Unable to find base type for leafref node '%s'.", schema.getPath());
108 return createCodec(schema, referencedType, namespaceContext);
111 public XmlCodec<QName> createIdentityrefTypeCodec(final DataSchemaNode schema,
112 final NamespaceContext namespaceContext) {
113 final XmlCodec<QName> xmlStringIdentityrefCodec =
114 new XmlStringIdentityrefCodec(getSchemaContext(), schema.getQName().getModule(), namespaceContext);
115 return xmlStringIdentityrefCodec;
118 private XmlCodec<Object> createUnionTypeCodec(final DataSchemaNode schema, final UnionTypeDefinition type,
119 final NamespaceContext namespaceContext) {
120 final XmlCodec<Object> xmlStringUnionCodec = new XmlStringUnionCodec(schema, type, this, namespaceContext);
121 return xmlStringUnionCodec;
124 private XmlCodec<?> createFromSimpleType(
125 final DataSchemaNode schema, final TypeDefinition<?> type,
126 final NamespaceContext namespaceContext) {
127 if (type instanceof InstanceIdentifierTypeDefinition) {
128 final XmlCodec<YangInstanceIdentifier> iidCodec = new XmlStringInstanceIdentifierCodec(schemaContext, this,
132 if (type instanceof EmptyTypeDefinition) {
133 return XmlEmptyCodec.INSTANCE;
136 final TypeDefinitionAwareCodec<Object, ?> codec = TypeDefinitionAwareCodec.from(type);
138 LOG.debug("Codec for type \"{}\" is not implemented yet.", type.getQName().getLocalName());
141 return AbstractXmlCodec.create(codec);
144 SchemaContext getSchemaContext() {
145 return schemaContext;
148 XmlCodec<?> codecFor(final DataSchemaNode schema, final NamespaceContext namespaceContext) {
149 Preconditions.checkArgument(schema instanceof TypedSchemaNode, "Unsupported node type %s", schema.getClass());
150 return codecs.getUnchecked(new SimpleImmutableEntry<>((TypedSchemaNode)schema, namespaceContext));
153 XmlCodec<?> codecFor(final DataSchemaNode schema, final TypeDefinition<?> unionSubType,
154 final NamespaceContext namespaceContext) {
155 return createCodec(schema, unionSubType, namespaceContext);