2 * Copyright (c) 2014 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
8 package org.opendaylight.yangtools.yang.data.codec.gson;
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Verify;
13 import com.google.common.cache.CacheBuilder;
14 import com.google.common.cache.CacheLoader;
15 import com.google.common.cache.LoadingCache;
16 import com.google.gson.stream.JsonWriter;
17 import java.io.IOException;
18 import javax.annotation.Nonnull;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
21 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
23 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
35 * Factory for creating JSON equivalents of codecs. Each instance of this object is bound to
36 * a particular {@link SchemaContext}, but can be reused by multiple {@link JSONNormalizedNodeStreamWriter}s.
39 public final class JSONCodecFactory {
40 private static final Logger LOG = LoggerFactory.getLogger(JSONCodecFactory.class);
41 private static final JSONCodec<Object> NULL_CODEC = new JSONCodec<Object>() {
43 public Object deserialize(final String input) {
48 public String serialize(final Object input) {
53 public void serializeToWriter(final JsonWriter writer, final Object value) throws IOException {
54 // NOOP since codec is unkwown.
55 LOG.warn("Call of the serializeToWriter method on JSONCodecFactory.NULL_CODEC object. No operation performed.");
59 private final LoadingCache<TypedSchemaNode, JSONCodec<?>> codecs = CacheBuilder.newBuilder().softValues()
60 .build(new CacheLoader<TypedSchemaNode, JSONCodec<?>>() {
62 public JSONCodec<?> load(@Nonnull final TypedSchemaNode key) throws Exception {
63 final TypeDefinition<?> type = key.getType();
64 return createCodec(key, type);
68 private final SchemaContext schemaContext;
69 private final JSONCodec<?> iidCodec;
71 private JSONCodecFactory(final SchemaContext context) {
72 this.schemaContext = Preconditions.checkNotNull(context);
73 iidCodec = new JSONStringInstanceIdentifierCodec(context, this);
77 * Instantiate a new codec factory attached to a particular context.
79 * @param context SchemaContext to which the factory should be bound
80 * @return A codec factory instance.
82 public static JSONCodecFactory create(final SchemaContext context) {
83 return new JSONCodecFactory(context);
86 private JSONCodec<?> createCodec(final DataSchemaNode key, final TypeDefinition<?> type) {
87 if (type instanceof LeafrefTypeDefinition) {
88 return createReferencedTypeCodec(key, (LeafrefTypeDefinition) type);
89 } else if (type instanceof IdentityrefTypeDefinition) {
90 return createIdentityrefTypeCodec(key);
91 } else if (type instanceof UnionTypeDefinition) {
92 return createUnionTypeCodec(key, (UnionTypeDefinition) type);
94 return createFromSimpleType(key, type);
97 private JSONCodec<?> createReferencedTypeCodec(final DataSchemaNode schema,
98 final LeafrefTypeDefinition type) {
99 // FIXME: Verify if this does indeed support leafref of leafref
100 final TypeDefinition<?> referencedType =
101 SchemaContextUtil.getBaseTypeForLeafRef(type, getSchemaContext(), schema);
102 Verify.verifyNotNull(referencedType, "Unable to find base type for leafref node '%s'.", schema.getPath());
103 return createCodec(schema, referencedType);
106 private JSONCodec<QName> createIdentityrefTypeCodec(final DataSchemaNode schema) {
107 final JSONCodec<QName> jsonStringIdentityrefCodec =
108 new JSONStringIdentityrefCodec(schemaContext, schema.getQName().getModule());
109 return jsonStringIdentityrefCodec;
112 private JSONCodec<Object> createUnionTypeCodec(final DataSchemaNode schema, final UnionTypeDefinition type) {
113 final JSONCodec<Object> jsonStringUnionCodec = new JSONStringUnionCodec(schema, type, this);
114 return jsonStringUnionCodec;
117 private JSONCodec<?> createFromSimpleType(final DataSchemaNode schema, final TypeDefinition<?> type) {
118 if (type instanceof InstanceIdentifierTypeDefinition) {
121 if (type instanceof EmptyTypeDefinition) {
122 return JSONEmptyCodec.INSTANCE;
125 final TypeDefinitionAwareCodec<Object, ?> codec = TypeDefinitionAwareCodec.from(type);
127 LOG.debug("Codec for type \"{}\" is not implemented yet.", type.getQName()
131 return AbstractJSONCodec.create(codec);
134 SchemaContext getSchemaContext() {
135 return schemaContext;
138 JSONCodec<?> codecFor(final DataSchemaNode schema) {
139 Preconditions.checkArgument(schema instanceof TypedSchemaNode, "Unsupported node type %s", schema.getClass());
140 return codecs.getUnchecked((TypedSchemaNode) schema);
143 JSONCodec<?> codecFor(final DataSchemaNode schema, final TypeDefinition<?> unionSubType) {
144 return createCodec(schema, unionSubType);