fd1bf502d90c70471a1d09683464570d209fa865
[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.base.Verify;
13 import com.google.gson.stream.JsonWriter;
14 import java.io.IOException;
15 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
16 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
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.TypedSchemaNode;
20 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
21 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
22 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Factory for creating JSON equivalents of codecs. Each instance of this object is bound to
31  * a particular {@link SchemaContext}, but can be reused by multiple {@link JSONNormalizedNodeStreamWriter}s.
32  */
33 @Beta
34 public abstract class JSONCodecFactory {
35     private static final Logger LOG = LoggerFactory.getLogger(JSONCodecFactory.class);
36     private static final JSONCodec<Object> NULL_CODEC = new JSONCodec<Object>() {
37         @Override
38         public Object deserialize(final String input) {
39             return null;
40         }
41
42         @Override
43         public String serialize(final Object input) {
44             return null;
45         }
46
47         @Override
48         public void serializeToWriter(final JsonWriter writer, final Object value) throws IOException {
49             // NOOP since codec is unkwown.
50             LOG.warn("Call of the serializeToWriter method on JSONCodecFactory.NULL_CODEC object. No operation performed.");
51         }
52     };
53
54     private final SchemaContext schemaContext;
55     private final JSONCodec<?> iidCodec;
56
57     JSONCodecFactory(final SchemaContext context) {
58         this.schemaContext = Preconditions.checkNotNull(context);
59         iidCodec = new JSONStringInstanceIdentifierCodec(context, this);
60     }
61
62     /**
63      * Instantiate a new codec factory attached to a particular context.
64      *
65      * @param context SchemaContext to which the factory should be bound
66      * @return A codec factory instance.
67      */
68     public static JSONCodecFactory create(final SchemaContext context) {
69         return SharedJSONCodecFactory.get(context);
70     }
71
72     final JSONCodec<?> createCodec(final DataSchemaNode key, final TypeDefinition<?> type) {
73         if (type instanceof LeafrefTypeDefinition) {
74             return createReferencedTypeCodec(key, (LeafrefTypeDefinition) type);
75         } else if (type instanceof IdentityrefTypeDefinition) {
76             return new JSONStringIdentityrefCodec(schemaContext, key.getQName().getModule());
77         } else if (type instanceof UnionTypeDefinition) {
78             return createUnionTypeCodec(key, (UnionTypeDefinition) type);
79         } else if (type instanceof InstanceIdentifierTypeDefinition) {
80             return iidCodec;
81         } else if (type instanceof EmptyTypeDefinition) {
82             return JSONEmptyCodec.INSTANCE;
83         }
84
85         final TypeDefinitionAwareCodec<Object, ?> codec = TypeDefinitionAwareCodec.from(type);
86         if (codec == null) {
87             // catches anyxml
88             LOG.debug("Codec for {} is not implemented yet", type);
89             return NULL_CODEC;
90         }
91         return AbstractJSONCodec.create(codec);
92     }
93
94     final SchemaContext getSchemaContext() {
95         return schemaContext;
96     }
97
98     JSONCodec<?> codecFor(final DataSchemaNode schema) {
99         Preconditions.checkArgument(schema instanceof TypedSchemaNode, "Unsupported node type %s", schema.getClass());
100         return codecFor((TypedSchemaNode) schema);
101     }
102
103     abstract JSONCodec<?> codecFor(final TypedSchemaNode schema);
104
105     final JSONCodec<?> codecFor(final DataSchemaNode schema, final TypeDefinition<?> unionSubType) {
106         return createCodec(schema, unionSubType);
107     }
108
109     private JSONCodec<?> createReferencedTypeCodec(final DataSchemaNode schema, final LeafrefTypeDefinition type) {
110         // FIXME: Verify if this does indeed support leafref of leafref
111         final TypeDefinition<?> referencedType = SchemaContextUtil.getBaseTypeForLeafRef(type, schemaContext, schema);
112         Verify.verifyNotNull(referencedType, "Unable to find base type for leafref node '%s'.", schema.getPath());
113         return createCodec(schema, referencedType);
114     }
115
116     private JSONCodec<Object> createUnionTypeCodec(final DataSchemaNode schema, final UnionTypeDefinition type) {
117         final JSONCodec<Object> jsonStringUnionCodec = new JSONStringUnionCodec(schema, type, this);
118         return jsonStringUnionCodec;
119     }
120 }