+ private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedAugmented(
+ final InstanceIdentifier<?> augPath) {
+ org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed = toNormalizedImpl(augPath);
+ // If used instance identifier codec added supports for deserialization
+ // of last AugmentationIdentifier we will just reuse it
+ if (isAugmentationIdentifier(processed)) {
+ return processed;
+ }
+ Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> additionalSerialized;
+ additionalSerialized = toNormalizedAugmentedUsingChildContainers(augPath, processed);
+
+ if (additionalSerialized.isPresent()) {
+ return additionalSerialized.get();
+ }
+ additionalSerialized = toNormalizedAugmentedUsingChildLeafs(augPath, processed);
+ if (additionalSerialized.isPresent()) {
+ return additionalSerialized.get();
+ }
+ throw new IllegalStateException("Unabled to construct augmentation identfier for " + augPath);
+ }
+
+ /**
+ * Tries to find correct augmentation identifier using children leafs
+ *
+ * This method uses normalized Instance Identifier of parent node to fetch
+ * schema and {@link BindingReflections#getModuleInfo(Class)} to learn about
+ * augmentation namespace, specificly, in which module it was defined.
+ *
+ * Then it uses it to filter all available augmentations for parent by
+ * module. After that it walks augmentations in particular module and
+ * pick-up first which at least one leaf name matches supplied augmentation.
+ * We could do this safely since YANG explicitly states that no any existing
+ * augmentations must differ in leaf fully qualified names.
+ *
+ *
+ * @param augPath
+ * Binding Aware Path which ends with augment
+ * @param parentPath
+ * Processed path
+ * @return
+ */
+ private Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toNormalizedAugmentedUsingChildLeafs(
+ final InstanceIdentifier<?> augPath,
+ final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
+ try {
+ DataNormalizationOperation<?> parentOp = legacyToNormalized.getOperation(parentPath);
+ if(!parentOp.getDataSchemaNode().isPresent()) {
+ return Optional.absent();
+ }
+ DataSchemaNode parentSchema = parentOp.getDataSchemaNode().get();
+ if (parentSchema instanceof AugmentationTarget) {
+ Set<AugmentationSchema> augmentations = ((AugmentationTarget) parentSchema).getAvailableAugmentations();
+ LOG.info("Augmentations for {}, {}", augPath, augmentations);
+ Optional<AugmentationSchema> schema = findAugmentation(augPath.getTargetType(), augmentations);
+ if (schema.isPresent()) {
+ AugmentationIdentifier augmentationIdentifier = DataNormalizationOperation
+ .augmentationIdentifierFrom(schema.get());
+ return Optional.of(parentPath.node(augmentationIdentifier));
+ }
+ }
+ } catch (DataNormalizationException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Creates instance identifier for augmentation child, tries to serialize it
+ * Instance Identifier is then shortened to last augmentation.
+ *
+ * This is for situations, where underlying codec is implementing hydrogen
+ * style DOM APIs (which did not supported {@link AugmentationIdentifier}.)
+ *
+ * @param augPath
+ * @param parentPath
+ * Path to parent node
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ private Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toNormalizedAugmentedUsingChildContainers(
+ final InstanceIdentifier<?> augPath,
+ final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
+ for (Class augChild : BindingReflections.getChildrenClasses(augPath.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ InstanceIdentifier<?> childPath = augPath.child(augChild);
+ org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = toNormalizedImpl(childPath);
+ org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potentialDiscovered = shortenToLastAugmentation(
+ normalized, parentPath);
+ if (potentialDiscovered != null) {
+ return Optional.of(potentialDiscovered);
+ }
+ }
+ return Optional.absent();
+ }
+
+ private Optional<AugmentationSchema> findAugmentation(final Class<?> targetType,
+ final Set<AugmentationSchema> augmentations) {
+ YangModuleInfo moduleInfo;
+ try {
+ moduleInfo = BindingReflections.getModuleInfo(targetType);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ Iterable<AugmentationSchema> filtered = filteredByModuleInfo(augmentations,
+ BindingReflections.getModuleQName(moduleInfo).getModule());
+ filtered.toString();
+ Set<String> targetTypeGetters = getYangModeledGetters(targetType);
+ for (AugmentationSchema schema : filtered) {
+ for (DataSchemaNode child : schema.getChildNodes()) {
+ String getterName = "get" + BindingMapping.getClassName(child.getQName());
+ if (targetTypeGetters.contains(getterName)) {
+ return Optional.of(schema);
+ }
+ }
+ }
+ return Optional.absent();
+ }
+
+ private static Iterable<AugmentationSchema> filteredByModuleInfo(final Iterable<AugmentationSchema> augmentations,
+ final QNameModule module) {
+ return Iterables.filter(augmentations, new Predicate<AugmentationSchema>() {
+ @Override
+ public boolean apply(final AugmentationSchema schema) {
+ final Collection<DataSchemaNode> childNodes = schema.getChildNodes();
+ return !childNodes.isEmpty() && module.equals(Iterables.get(childNodes, 0).getQName().getModule());
+ }
+ });
+ }
+
+ public static final Set<String> getYangModeledGetters(final Class<?> targetType) {
+ HashSet<String> ret = new HashSet<String>();
+ for (Method method : targetType.getMethods()) {
+ if (isYangModeledGetter(method)) {
+ ret.add(method.getName());
+ }
+ }
+ return ret;
+ }
+
+ /**
+ *
+ * Returns true if supplied method represent getter for YANG modeled value
+ *
+ * @param method
+ * Method to be tested
+ * @return true if method represent getter for YANG Modeled value.
+ */
+ private static final boolean isYangModeledGetter(final Method method) {
+ return !method.getName().equals("getClass") && !method.getName().equals("getImplementedInterface")
+ && method.getName().startsWith("get") && method.getParameterTypes().length == 0;
+ }
+
+ private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier shortenToLastAugmentation(
+ final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized,
+ final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
+ int parentSize = Iterables.size(parentPath.getPathArguments());
+ int position = 0;
+ int foundPosition = -1;
+ for (PathArgument arg : normalized.getPathArguments()) {
+ position++;
+ if (arg instanceof AugmentationIdentifier) {
+ foundPosition = position;
+ }
+ }
+ if (foundPosition > 0 && foundPosition > parentSize) {
+ Iterable<PathArgument> shortened = Iterables.limit(normalized.getPathArguments(), foundPosition);
+ return org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.create(shortened);
+ }
+ return null;
+ }
+
+ private InstanceIdentifier<? extends DataObject> shortenToLastAugment(
+ final InstanceIdentifier<? extends DataObject> binding) {
+ int position = 0;
+ int foundPosition = -1;
+ for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : binding.getPathArguments()) {
+ position++;
+ if (isAugmentation(arg.getType())) {
+ foundPosition = position;
+ }
+ }
+ return InstanceIdentifier.create(Iterables.limit(binding.getPathArguments(), foundPosition));
+ }
+
+ private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedImpl(
+ final InstanceIdentifier<? extends DataObject> binding) {
+ final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier legacyPath = bindingToLegacy
+ .toDataDom(binding);
+ final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = legacyToNormalized
+ .toNormalized(legacyPath);
+ return normalized;
+ }
+
+ private static boolean isAugmentation(final Class<? extends DataObject> type) {
+ return Augmentation.class.isAssignableFrom(type);
+ }
+
+ private static boolean isAugmentationIdentifier(final InstanceIdentifier<?> potential) {
+ return Augmentation.class.isAssignableFrom(potential.getTargetType());
+ }
+
+ private boolean isAugmentationIdentifier(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed) {
+ return Iterables.getLast(processed.getPathArguments()) instanceof AugmentationIdentifier;
+ }
+
+ private static int getAugmentationCount(final InstanceIdentifier<?> potential) {
+ int count = 0;
+ for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) {
+ if (isAugmentation(arg.getType())) {
+ count++;
+ }
+
+ }
+ return count;
+ }
+
+ private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potential) {
+ int count = 0;
+ for (PathArgument arg : potential.getPathArguments()) {
+ if (arg instanceof AugmentationIdentifier) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })