/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.yang.data.codec.gson; import com.google.common.annotations.Beta; import com.google.common.base.Preconditions; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.gson.stream.JsonWriter; import java.io.IOException; import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; import org.opendaylight.yangtools.yang.model.util.IdentityrefType; import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType; import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Factory for creating JSON equivalents of codecs. Each instance of this object is bound to * a particular {@link SchemaContext}, but can be reused by multiple {@link JSONNormalizedNodeStreamWriter}s. */ @Beta public final class JSONCodecFactory { private static final Logger LOG = LoggerFactory.getLogger(JSONCodecFactory.class); private static final JSONCodec NULL_CODEC = new JSONCodec() { @Override public Object deserialize(final String input) { return null; } @Override public String serialize(final Object input) { return null; } @Override public boolean needQuotes() { return false; } @Override public void serializeToWriter(JsonWriter writer, Object value) throws IOException { // NOOP since codec is unkwown. LOG.warn("Call of the serializeToWriter method on JSONCodecFactory.NULL_CODEC object. No operation performed."); } }; private final LoadingCache> codecs = CacheBuilder.newBuilder().softValues().build(new CacheLoader>() { @Override public JSONCodec load(final DataSchemaNode key) throws Exception { final TypeDefinition type; if (key instanceof LeafSchemaNode) { type = ((LeafSchemaNode) key).getType(); } else if (key instanceof LeafListSchemaNode) { type = ((LeafListSchemaNode) key).getType(); } else { throw new IllegalArgumentException("Not supported node type " + key.getClass().getName()); } return createCodec(key,type); } }); private final SchemaContext schemaContext; private final JSONCodec iidCodec; private final JSONCodec idrefCodec; private JSONCodecFactory(final SchemaContext context) { this.schemaContext = Preconditions.checkNotNull(context); iidCodec = new JSONStringInstanceIdentifierCodec(context); idrefCodec = new JSONStringIdentityrefCodec(context); } /** * Instantiate a new codec factory attached to a particular context. * * @param context SchemaContext to which the factory should be bound * @return A codec factory instance. */ public static JSONCodecFactory create(final SchemaContext context) { return new JSONCodecFactory(context); } private static TypeDefinition resolveBaseTypeFrom(final TypeDefinition type) { TypeDefinition superType = type; while (superType.getBaseType() != null) { superType = superType.getBaseType(); } return superType; } private JSONCodec createCodec(DataSchemaNode key, TypeDefinition type) { TypeDefinition baseType = resolveBaseTypeFrom(type); if (baseType instanceof LeafrefTypeDefinition) { return createReferencedTypeCodec(key, (LeafrefTypeDefinition) baseType); } return createFromSimpleType(type); } private JSONCodec createReferencedTypeCodec(DataSchemaNode schema, LeafrefTypeDefinition type) { // FIXME: Verify if this does indeed support leafref of leafref TypeDefinition referencedType = SchemaContextUtil.getBaseTypeForLeafRef(type, getSchemaContext(), schema); return createFromSimpleType(referencedType); } @SuppressWarnings("unchecked") private JSONCodec createFromSimpleType(TypeDefinition type) { final TypeDefinition baseType = resolveBaseTypeFrom(type); if (baseType instanceof InstanceIdentifierType) { return (JSONCodec) iidCodec; } if (baseType instanceof IdentityrefType) { return (JSONCodec) idrefCodec; } final TypeDefinitionAwareCodec codec = TypeDefinitionAwareCodec.from(type); if (codec == null) { LOG.debug("Codec for type \"{}\" is not implemented yet.", type.getQName() .getLocalName()); return NULL_CODEC; } return (JSONCodec) AbstractJSONCodec.create(codec); } SchemaContext getSchemaContext() { return schemaContext; } JSONCodec codecFor(DataSchemaNode schema) { return codecs.getUnchecked(schema); } }