2 * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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.util.codec;
10 import com.google.common.base.Preconditions;
11 import com.google.common.base.Verify;
12 import java.util.ArrayList;
13 import java.util.List;
14 import javax.annotation.concurrent.ThreadSafe;
15 import org.opendaylight.yangtools.yang.common.QNameModule;
16 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
17 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
18 import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
19 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
20 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
21 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
22 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
31 import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
33 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 * A type-to-codec factory base class with logic to efficiently lookup and cache codec instances,
39 * also dealing with union type composition.
41 * @author Robert Varga
43 * @param <T> Codec type
46 public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>> {
47 private static final Logger LOG = LoggerFactory.getLogger(AbstractCodecFactory.class);
49 private final CodecCache<T> cache;
51 private final SchemaContext schemaContext;
53 protected AbstractCodecFactory(final SchemaContext schemaContext, final CodecCache<T> cache) {
54 this.schemaContext = Preconditions.checkNotNull(schemaContext);
55 this.cache = Preconditions.checkNotNull(cache);
58 public final SchemaContext getSchemaContext() {
62 public final T codecFor(final TypedSchemaNode schema) {
64 * There are many trade-offs to be made here. We need the common case being as fast as possible while reusing
65 * codecs as much as possible.
67 * This gives us essentially four classes of codecs:
68 * - simple codecs, which are based on the type definition only
69 * - complex codecs, which depend on both type definition and the leaf
70 * - null codec, which does not depend on anything
71 * - instance identifier codec, which is based on namespace mapping
73 * We assume prevalence is in above order and that caching is effective. We therefore
75 final TypeDefinition<?> type = schema.getType();
76 T ret = cache.lookupSimple(type);
78 LOG.trace("Type {} hit simple {}", type, ret);
81 ret = cache.lookupComplex(schema);
83 LOG.trace("Type {} hit complex {}", type, ret);
87 // Dealing with simple types first...
88 ret = getSimpleCodecFor(type);
90 LOG.trace("Type {} miss simple {}", type, ret);
94 // ... and complex types afterwards
95 ret = createComplexCodecFor(schema, type);
96 LOG.trace("Type {} miss complex {}", type, ret);
97 return cache.getComplex(schema, ret);
100 protected abstract T binaryCodec(BinaryTypeDefinition type);
101 protected abstract T booleanCodec(BooleanTypeDefinition type);
102 protected abstract T bitsCodec(BitsTypeDefinition type);
103 protected abstract T emptyCodec(EmptyTypeDefinition type);
104 protected abstract T enumCodec(EnumTypeDefinition type);
105 protected abstract T identityRefCodec(IdentityrefTypeDefinition type, QNameModule module);
106 protected abstract T instanceIdentifierCodec(InstanceIdentifierTypeDefinition type);
107 protected abstract T intCodec(IntegerTypeDefinition type);
108 protected abstract T decimalCodec(DecimalTypeDefinition type);
109 protected abstract T stringCodec(StringTypeDefinition type);
110 protected abstract T uintCodec(UnsignedIntegerTypeDefinition type);
111 protected abstract T unionCodec(UnionTypeDefinition type, List<T> codecs);
112 protected abstract T unknownCodec(UnknownTypeDefinition type);
114 private T getSimpleCodecFor(final TypeDefinition<?> type) {
115 // These types are expected to be fully-shared
116 if (type instanceof EmptyTypeDefinition) {
117 return emptyCodec((EmptyTypeDefinition) type);
118 } else if (type instanceof UnknownTypeDefinition) {
119 return unknownCodec((UnknownTypeDefinition) type);
122 // Now deal with simple types. Note we consider union composed of purely simple types a simple type itself.
123 // The checks here are optimized for common types.
125 if (type instanceof StringTypeDefinition) {
126 ret = stringCodec((StringTypeDefinition) type);
127 } else if (type instanceof IntegerTypeDefinition) {
128 ret = intCodec((IntegerTypeDefinition) type);
129 } else if (type instanceof UnsignedIntegerTypeDefinition) {
130 ret = uintCodec((UnsignedIntegerTypeDefinition) type);
131 } else if (type instanceof BooleanTypeDefinition) {
132 ret = booleanCodec((BooleanTypeDefinition) type);
133 } else if (type instanceof DecimalTypeDefinition) {
134 ret = decimalCodec((DecimalTypeDefinition) type);
135 } else if (type instanceof EnumTypeDefinition) {
136 ret = enumCodec((EnumTypeDefinition) type);
137 } else if (type instanceof BitsTypeDefinition) {
138 ret = bitsCodec((BitsTypeDefinition) type);
139 } else if (type instanceof UnionTypeDefinition) {
140 final UnionTypeDefinition union = (UnionTypeDefinition) type;
141 if (!isSimpleUnion(union)) {
144 ret = createSimpleUnion(union);
145 } else if (type instanceof BinaryTypeDefinition) {
146 ret = binaryCodec((BinaryTypeDefinition) type);
147 } else if (type instanceof InstanceIdentifierTypeDefinition) {
148 return instanceIdentifierCodec((InstanceIdentifierTypeDefinition) type);
153 return cache.getSimple(type, Verify.verifyNotNull(ret));
156 private static boolean isSimpleUnion(final UnionTypeDefinition union) {
157 for (TypeDefinition<?> t : union.getTypes()) {
158 if (t instanceof IdentityrefTypeDefinition || t instanceof LeafrefTypeDefinition
159 || (t instanceof UnionTypeDefinition && !isSimpleUnion((UnionTypeDefinition) t))) {
160 LOG.debug("Type {} has non-simple subtype", t);
165 LOG.debug("Type {} is simple", union);
169 private T createComplexCodecFor(final TypedSchemaNode schema, final TypeDefinition<?> type) {
170 if (type instanceof UnionTypeDefinition) {
171 return createComplexUnion(schema, (UnionTypeDefinition) type);
172 } else if (type instanceof LeafrefTypeDefinition) {
173 final TypeDefinition<?> target = SchemaContextUtil.getBaseTypeForLeafRef((LeafrefTypeDefinition) type,
174 schemaContext, schema);
175 Verify.verifyNotNull(target, "Unable to find base type for leafref node %s type %s.", schema.getPath(),
178 final T ret = getSimpleCodecFor(target);
179 return ret != null ? ret : createComplexCodecFor(schema, target);
180 } else if (type instanceof IdentityrefTypeDefinition) {
181 return identityRefCodec((IdentityrefTypeDefinition) type, schema.getQName().getModule());
183 throw new IllegalArgumentException("Unsupported type " + type);
187 private T createSimpleUnion(final UnionTypeDefinition union) {
188 final List<TypeDefinition<?>> types = union.getTypes();
189 final List<T> codecs = new ArrayList<>(types.size());
191 for (TypeDefinition<?> type : types) {
192 T codec = cache.lookupSimple(type);
194 codec = Verify.verifyNotNull(getSimpleCodecFor(type), "Type %s did not resolve to a simple codec",
201 return unionCodec(union, codecs);
204 private T createComplexUnion(final TypedSchemaNode schema, final UnionTypeDefinition union) {
205 final List<TypeDefinition<?>> types = union.getTypes();
206 final List<T> codecs = new ArrayList<>(types.size());
208 for (TypeDefinition<?> type : types) {
209 T codec = cache.lookupSimple(type);
211 codec = getSimpleCodecFor(type);
213 codec = createComplexCodecFor(schema, type);
217 codecs.add(Verify.verifyNotNull(codec, "Schema %s subtype %s has no codec", schema, type));
220 return unionCodec(union, codecs);