/* * Copyright (c) 2015 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.parser.rfc7950.stmt.list; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.ActionDefinition; import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode; import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; import org.opendaylight.yangtools.yang.model.api.UniqueConstraint; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.KeyEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ListEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ListStatement; import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; import org.opendaylight.yangtools.yang.model.api.stmt.compat.ActionNodeContainerCompat; import org.opendaylight.yangtools.yang.model.api.stmt.compat.NotificationNodeContainerCompat; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveMustConstraintAwareSimpleDataNodeContainer; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStmtUtils; import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; final class ListEffectiveStatementImpl extends AbstractEffectiveMustConstraintAwareSimpleDataNodeContainer implements ListEffectiveStatement, ListSchemaNode, DerivableSchemaNode, ActionNodeContainerCompat, NotificationNodeContainerCompat { private static final Logger LOG = LoggerFactory.getLogger(ListEffectiveStatementImpl.class); private static final String ORDER_BY_USER_KEYWORD = "user"; private final boolean userOrdered; private final ImmutableList keyDefinition; private final ListSchemaNode original; private final @NonNull ImmutableSet actions; private final @NonNull ImmutableSet notifications; private final @NonNull ImmutableList uniqueConstraints; private final ElementCountConstraint elementCountConstraint; ListEffectiveStatementImpl( final StmtContext> ctx) { super(ctx); this.original = (ListSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective).orElse(null); this.userOrdered = findFirstEffectiveSubstatementArgument(OrderedByEffectiveStatement.class) .map(ORDER_BY_USER_KEYWORD::equals).orElse(Boolean.FALSE).booleanValue(); // initKeyDefinition final Optional optKeyStmt = findFirstEffectiveSubstatement(KeyEffectiveStatement.class); if (optKeyStmt.isPresent()) { final KeyEffectiveStatement keyStmt = optKeyStmt.get(); final List keyDefinitionInit = new ArrayList<>(keyStmt.argument().size()); final Set possibleLeafQNamesForKey = new HashSet<>(); for (final EffectiveStatement effectiveStatement : effectiveSubstatements()) { if (effectiveStatement instanceof LeafSchemaNode) { possibleLeafQNamesForKey.add(((LeafSchemaNode) effectiveStatement).getQName()); } } for (final SchemaNodeIdentifier key : keyStmt.argument()) { final QName keyQName = key.getLastComponent(); if (!possibleLeafQNamesForKey.contains(keyQName)) { throw new InferenceException(ctx.getStatementSourceReference(), "Key '%s' misses node '%s' in list '%s'", keyStmt.getDeclared().rawArgument(), keyQName.getLocalName(), ctx.getStatementArgument()); } keyDefinitionInit.add(keyQName); } this.keyDefinition = ImmutableList.copyOf(keyDefinitionInit); } else { this.keyDefinition = ImmutableList.of(); } if (isConfiguration() && keyDefinition.isEmpty()) { LOG.info("Configuration list {} does not define any keys in violation of RFC7950 section 7.8.2. While " + " this is fine with OpenDaylight, it can cause interoperability issues with other systems " + "[at {}]", ctx.getStatementArgument(), ctx.getStatementSourceReference()); } this.uniqueConstraints = ImmutableList.copyOf(allSubstatementsOfType(UniqueConstraint.class)); final Builder actionsBuilder = ImmutableSet.builder(); final Builder notificationsBuilder = ImmutableSet.builder(); for (final EffectiveStatement effectiveStatement : effectiveSubstatements()) { if (effectiveStatement instanceof ActionDefinition) { actionsBuilder.add((ActionDefinition) effectiveStatement); } if (effectiveStatement instanceof NotificationDefinition) { notificationsBuilder.add((NotificationDefinition) effectiveStatement); } } this.actions = actionsBuilder.build(); this.notifications = notificationsBuilder.build(); elementCountConstraint = EffectiveStmtUtils.createElementCountConstraint(this).orElse(null); } @Override public Optional getOriginal() { return Optional.ofNullable(original); } @Override public List getKeyDefinition() { return keyDefinition; } @Override public Set getActions() { return actions; } @Override public Set getNotifications() { return notifications; } @Override public Collection getUniqueConstraints() { return uniqueConstraints; } @Override public boolean isUserOrdered() { return userOrdered; } @Override public Optional getElementCountConstraint() { return Optional.ofNullable(elementCountConstraint); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Objects.hashCode(getQName()); result = prime * result + Objects.hashCode(getPath()); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ListEffectiveStatementImpl other = (ListEffectiveStatementImpl) obj; return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath()); } @Override public String toString() { return "list " + getQName().getLocalName(); } }