BUG-7996: Split JSONCodec into multiple implementations
[yangtools.git] / yang / yang-data-codec-gson / src / main / java / org / opendaylight / yangtools / yang / data / codec / gson / EagerJSONCodecFactory.java
1 /*
2  * Copyright (c) 2017 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.base.Preconditions;
11 import com.google.common.cache.CacheBuilder;
12 import com.google.common.cache.CacheLoader;
13 import com.google.common.cache.LoadingCache;
14 import java.util.Map;
15 import javax.annotation.concurrent.ThreadSafe;
16 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
17 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
18 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
19 import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
20
21 /**
22  * Pre-computed JSONCodecFactory. All possible codecs are created upfront at instantiation time, after which they
23  * are available for the cost of a constant lookup.
24  *
25  * @author Robert Varga
26  */
27 @ThreadSafe
28 final class EagerJSONCodecFactory extends JSONCodecFactory {
29     // Weak keys to retire the entry when SchemaContext goes away
30     // Soft values to keep unreferenced factories around for a bit
31     private static final LoadingCache<SchemaContext, EagerJSONCodecFactory> CACHE = CacheBuilder.newBuilder()
32             .weakKeys().softValues().build(new CacheLoader<SchemaContext, EagerJSONCodecFactory>() {
33                 @Override
34                 public EagerJSONCodecFactory load(final SchemaContext key) {
35                     return new EagerJSONCodecFactory(key);
36                 }
37             });
38
39     private final Map<TypedSchemaNode, JSONCodec<?>> codecs;
40
41     EagerJSONCodecFactory(final SchemaContext context) {
42         super(context);
43         this.codecs = constructCodecs(context);
44     }
45
46     static EagerJSONCodecFactory getIfPresent(final SchemaContext context) {
47         return CACHE.getIfPresent(context);
48     }
49
50     static EagerJSONCodecFactory get(final SchemaContext context) {
51         return CACHE.getUnchecked(context);
52     }
53
54     @Override
55     JSONCodec<?> codecFor(final TypedSchemaNode schema) {
56         final JSONCodec<?> ret = codecs.get(schema);
57         Preconditions.checkArgument(ret != null, "No codec available for schema %s", schema);
58         return ret;
59     }
60
61     private static Map<TypedSchemaNode, JSONCodec<?>> constructCodecs(final SchemaContext context) {
62         final LazyJSONCodecFactory lazy = new LazyJSONCodecFactory(context);
63         requestCodecsForChildren(lazy, context);
64         return lazy.getCodecs();
65     }
66
67     private static void requestCodecsForChildren(final LazyJSONCodecFactory factory, final DataNodeContainer parent) {
68         for (DataSchemaNode child : parent.getChildNodes()) {
69             if (child instanceof TypedSchemaNode) {
70                 factory.codecFor(child);
71             } else if (child instanceof DataNodeContainer) {
72                 requestCodecsForChildren(factory, (DataNodeContainer)child);
73             }
74         }
75     }
76 }