/** * 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.sal.binding.generator.impl; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl; import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry; import org.opendaylight.yangtools.yang.data.impl.codec.IdentifierCodec; import org.opendaylight.yangtools.yang.data.impl.codec.InstanceIdentifierCodec; import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { private static final Logger LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class); private final CodecRegistry codecRegistry; private final Map,Set>> augmentationAdapted = new WeakHashMap<>(); private final Map, Map, Class>> classToPreviousAugment = Collections .synchronizedMap(new WeakHashMap, Map, Class>>()); public InstanceIdentifierCodecImpl(final CodecRegistry registry) { this.codecRegistry = registry; } @Override public InstanceIdentifier deserialize( final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input) { Class baType = null; List biArgs = input.getPath(); List scannedPath = new ArrayList<>(biArgs.size()); List baArgs = new ArrayList(biArgs.size()); for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument biArg : biArgs) { scannedPath.add(biArg.getNodeType()); org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument baArg = deserializePathArgument( biArg, scannedPath); if (baArg != null) { baType = baArg.getType(); } Map, Class> injectAugment = classToPreviousAugment.get(baType); if (injectAugment != null) { @SuppressWarnings("unchecked") Class augment = (Class) injectAugment.get(scannedPath); if (augment != null) { baArgs.add(new Item(augment)); } } baArgs.add(baArg); } InstanceIdentifier ret = InstanceIdentifier.create(baArgs); LOG.debug("DOM Instance Identifier {} deserialized to {}", input, ret); return ret; } @Override public InstanceIdentifier deserialize( final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input, final InstanceIdentifier bindingIdentifier) { return deserialize(input); } private InstanceIdentifier.PathArgument deserializeNodeIdentifier( final NodeIdentifier argument, final List processedPath) { @SuppressWarnings("rawtypes") final Class cls = codecRegistry.getClassForPath(processedPath); @SuppressWarnings("unchecked") Item item = new Item<>(cls); return item; } private InstanceIdentifier.PathArgument deserializeNodeIdentifierWithPrecicates( final NodeIdentifierWithPredicates argument, final List processedPath) { @SuppressWarnings("rawtypes") final Class type = codecRegistry.getClassForPath(processedPath); @SuppressWarnings({ "unchecked", "rawtypes" }) final IdentifierCodec codec = codecRegistry .> getIdentifierCodecForIdentifiable(type); CompositeNode _compositeNode = this.toCompositeNode(argument); @SuppressWarnings("unchecked") ValueWithQName deserialize = codec.deserialize(_compositeNode); Object value = null; if (deserialize != null) { value = deserialize.getValue(); } return CodecTypeUtils.newIdentifiableItem(type, value); } public CompositeNode toCompositeNode(final NodeIdentifierWithPredicates predicates) { Set> keyValues = predicates.getKeyValues().entrySet(); List> values = new ArrayList<>(keyValues.size()); for (Map.Entry keyValue : keyValues) { values.add(new SimpleNodeTOImpl(keyValue.getKey(), null, keyValue.getValue())); } return new CompositeNodeTOImpl(predicates.getNodeType(), null, values); } @Override public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier serialize(final InstanceIdentifier input) { Class previousAugmentation = null; Iterable pathArgs = input.getPathArguments(); QName previousQName = null; List components = new ArrayList<>(); List qnamePath = new ArrayList<>(); for (InstanceIdentifier.PathArgument baArg : pathArgs) { if (!Augmentation.class.isAssignableFrom(baArg.getType())) { PathArgument biArg = serializePathArgumentAndUpdateMapping(qnamePath, baArg, previousQName,previousAugmentation); components.add(biArg); qnamePath.add(biArg.getNodeType()); previousQName = biArg.getNodeType(); previousAugmentation = null; } else { previousQName = codecRegistry.getQNameForAugmentation(baArg.getType()); previousAugmentation = baArg.getType(); ensureAugmentation(qnamePath,previousQName,baArg.getType()); } } org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier ret = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.create(components); LOG.debug("Binding Instance Identifier {} serialized to DOM InstanceIdentifier {}", input, ret); return ret; } private synchronized void ensureAugmentation(final List augPath, final QName augQName, final Class type) { Set> augPotential = augmentationAdapted.get(type); if(augPotential == null) { augPotential = new HashSet<>(); augmentationAdapted.put(type, augPotential); } ImmutableList augTargetPath = ImmutableList.copyOf(augPath); if(augPotential.contains(augPath)) { return; } for(Class child : BindingReflections.getChildrenClasses(type)) { Item baArg = new Item<>(child); PathArgument biArg = serializePathArgumentAndUpdateMapping(augPath, baArg, augQName,type); } augPotential.add(augTargetPath); } public Class updateAugmentationInjection(final Class class1, final List list, final Class augmentation) { if (classToPreviousAugment.get(class1) == null) { classToPreviousAugment.put(class1, new ConcurrentHashMap, Class>()); } return classToPreviousAugment.get(class1).put(list, augmentation); } private PathArgument serializeItem(final Item argument, final QName previousQname) { Class type = argument.getType(); QName qname = BindingReflections.findQName(type); if (previousQname == null || (BindingReflections.isAugmentationChild(argument.getType()))) { return new NodeIdentifier(qname); } return new NodeIdentifier(QName.create(previousQname, qname.getLocalName())); } private PathArgument serializeIdentifiableItem(final IdentifiableItem argument, final QName previousQname) { Map predicates = new HashMap<>(); @SuppressWarnings("rawtypes") Class type = argument.getType(); @SuppressWarnings("unchecked") IdentifierCodec keyCodec = codecRegistry.getIdentifierCodecForIdentifiable(type); QName qname = BindingReflections.findQName(type); if (previousQname != null && !(BindingReflections.isAugmentationChild(argument.getType()))) { qname = QName.create(previousQname, qname.getLocalName()); } @SuppressWarnings({ "rawtypes", "unchecked" }) ValueWithQName combinedInput = new ValueWithQName(previousQname, argument.getKey()); @SuppressWarnings("unchecked") CompositeNode compositeOutput = keyCodec.serialize(combinedInput); for (Node outputValue : compositeOutput.getValue()) { predicates.put(outputValue.getNodeType(), outputValue.getValue()); } if (previousQname == null) { return new NodeIdentifierWithPredicates(qname, predicates); } return new NodeIdentifierWithPredicates(qname, predicates); } private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument( final PathArgument argument, final List processedPath) { if (argument instanceof NodeIdentifier) { return deserializeNodeIdentifier((NodeIdentifier) argument, processedPath); } else if (argument instanceof NodeIdentifierWithPredicates) { return deserializeNodeIdentifierWithPrecicates((NodeIdentifierWithPredicates) argument, processedPath); } else { throw new IllegalArgumentException("Unhandled parameter types: " + Arrays. asList(argument, processedPath).toString()); } } private PathArgument serializePathArgumentAndUpdateMapping(final List parentPath, final InstanceIdentifier.PathArgument baArg, final QName previousQName, final Class previousAugmentation) { org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument biArg = serializePathArgument(baArg, previousQName); List qnamePath = new ArrayList<>(parentPath); qnamePath.add(biArg.getNodeType()); ImmutableList currentPath = ImmutableList.copyOf(qnamePath); codecRegistry.putPathToClass(currentPath, baArg.getType()); if (previousAugmentation != null) { updateAugmentationInjection(baArg.getType(), currentPath, previousAugmentation); } return biArg; } private PathArgument serializePathArgument( final InstanceIdentifier.PathArgument argument, final QName previousQname) { if (argument instanceof IdentifiableItem) { return serializeIdentifiableItem((IdentifiableItem) argument, previousQname); } else if (argument instanceof Item) { return serializeItem((Item) argument, previousQname); } else { throw new IllegalArgumentException("Unhandled parameter types: " + Arrays. asList(argument, previousQname).toString()); } } }