BUG-1768: expose JSONCodecFactory for sharing
[yangtools.git] / yang / yang-data-codec-gson / src / main / java / org / opendaylight / yangtools / yang / data / codec / gson / JSONCodecFactory.java
1 /*
2  * Copyright (c) 2014 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.codec.gson;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import com.google.common.cache.CacheBuilder;
13 import com.google.common.cache.CacheLoader;
14 import com.google.common.cache.LoadingCache;
15
16 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
17 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
18 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
19 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
20 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
21 import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * Factory for creating JSON equivalents of codecs. Each instance of this object is bound to
27  * a particular {@link SchemaContext}, but can be reused by multiple {@link JSONNormalizedNodeStreamWriter}s.
28  */
29 @Beta
30 public final class JSONCodecFactory {
31     private static final Logger LOG = LoggerFactory.getLogger(JSONCodecFactory.class);
32     private static final JSONCodec<Object> LEAFREF_DEFAULT_CODEC = new JSONLeafrefCodec();
33     private static final JSONCodec<Object> NULL_CODEC = new JSONCodec<Object>() {
34         @Override
35         public Object deserialize(final String input) {
36             return null;
37         }
38
39         @Override
40         public String serialize(final Object input) {
41             return null;
42         }
43
44         @Override
45         public boolean needQuotes() {
46             return false;
47         }
48     };
49
50     private static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
51         TypeDefinition<?> superType = type;
52         while (superType.getBaseType() != null) {
53             superType = superType.getBaseType();
54         }
55         return superType;
56     }
57
58     private final LoadingCache<TypeDefinition<?>, JSONCodec<Object>> codecs =
59             CacheBuilder.newBuilder().softValues().build(new CacheLoader<TypeDefinition<?>, JSONCodec<Object>>() {
60         @SuppressWarnings("unchecked")
61         @Override
62         public JSONCodec<Object> load(final TypeDefinition<?> key) throws Exception {
63             final TypeDefinition<?> type = resolveBaseTypeFrom(key);
64
65             if (type instanceof InstanceIdentifierType) {
66                 return (JSONCodec<Object>) iidCodec;
67             }
68             if (type instanceof IdentityrefType) {
69                 return (JSONCodec<Object>) idrefCodec;
70             }
71             if (type instanceof LeafrefTypeDefinition) {
72                 return LEAFREF_DEFAULT_CODEC;
73             }
74
75             final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codec = TypeDefinitionAwareCodec.from(type);
76             if (codec == null) {
77                 LOG.debug("Codec for type \"{}\" is not implemented yet.", type.getQName().getLocalName());
78                 return NULL_CODEC;
79             }
80
81             return AbstractJSONCodec.create(codec);
82         }
83     });
84
85     private final SchemaContext schemaContext;
86     private final JSONCodec<?> iidCodec;
87     private final JSONCodec<?> idrefCodec;
88
89     private JSONCodecFactory(final SchemaContext context) {
90         this.schemaContext = Preconditions.checkNotNull(context);
91         iidCodec = new JSONStringInstanceIdentifierCodec(context);
92         idrefCodec = new JSONStringIdentityrefCodec(context);
93     }
94
95     /**
96      * Instantiate a new codec factory attached to a particular context.
97      *
98      * @param context SchemaContext to which the factory should be bound
99      * @return A codec factory instance.
100      */
101     public static JSONCodecFactory create(final SchemaContext context) {
102         return new JSONCodecFactory(context);
103     }
104
105     SchemaContext getSchemaContext() {
106         return schemaContext;
107     }
108
109     JSONCodec<Object> codecFor(final TypeDefinition<?> typeDefinition) {
110         return codecs.getUnchecked(typeDefinition);
111     }
112 }