/* * Copyright (c) 2016 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.groupbasedpolicy.neutron.vpp.mapper.processors; import java.io.Closeable; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType; import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Iterators; import com.google.common.collect.PeekingIterator; public class NeutronListener implements ClusteredDataTreeChangeListener<Neutron>, Closeable { private static final Logger LOG = LoggerFactory.getLogger(NeutronListener.class); private final Set<MappingProvider<? extends DataObject>> dataChangeProviders = new LinkedHashSet<>(); protected ListenerRegistration<NeutronListener> registeredListener; public NeutronListener(DataBroker dataBroker, NodeId routingNode) { LOG.info("Routing node chosen in ODL is {}", routingNode); registerHandlersAndListeners(dataBroker, routingNode); registeredListener = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>( LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(Neutron.class).build()), this); } private void registerHandlersAndListeners(DataBroker dataBroker, NodeId routingNode) { PortHandler portHandler = new PortHandler(dataBroker, routingNode); dataChangeProviders.add(new PortAware(portHandler, dataBroker)); dataChangeProviders.add(new NetworkAware(dataBroker)); dataChangeProviders.add(new SubnetAware(dataBroker)); } @Override public void onDataTreeChanged(Collection<DataTreeModification<Neutron>> changes) { for (DataTreeModification<Neutron> change : changes) { DataObjectModification<Neutron> rootNode = change.getRootNode(); for (MappingProvider<? extends DataObject> provider : dataChangeProviders) { for (DataObjectModification<? extends DataObject> modDto : findModifiedData(provider, rootNode)) { try { processChangedData(modDto, modDto.getModificationType(), provider); } catch (InterruptedException | ExecutionException e) { LOG.error("Failed to process {} modification of node: {}. {}", modDto.getModificationType(), modDto.getIdentifier(), e.getStackTrace()); } } } } } List<DataObjectModification<? extends DataObject>> findModifiedData(MappingProvider<? extends DataObject> provider, DataObjectModification<Neutron> rootNode) { List<DataObjectModification<? extends DataObject>> modDtos = new ArrayList<>(); PeekingIterator<PathArgument> pathArgs = Iterators.peekingIterator(provider.getNeutronDtoIid() .getPathArguments() .iterator()); DataObjectModification<? extends DataObject> modifDto = rootNode; while (pathArgs.hasNext()) { pathArgs.next(); for (DataObjectModification<? extends DataObject> childDto : modifDto.getModifiedChildren()) { if (pathArgs.hasNext() && childDto.getDataType().equals(pathArgs.peek().getType())) { if (childDto.getDataType().equals(provider.getNeutronDtoIid().getTargetType())) { modDtos.add(childDto); } else { modifDto = childDto; break; } } } } return modDtos; } @SuppressWarnings("unchecked") <T extends DataObject> void processChangedData(DataObjectModification<?> dto, ModificationType m, MappingProvider<T> processor) throws InterruptedException, ExecutionException { switch (m) { case WRITE: { if (dto.getDataBefore() != null) { processor.processUpdatedNeutronDto((T) dto.getDataBefore(), (T) dto.getDataAfter()); } else { processor.processCreatedNeutronDto((T) dto.getDataAfter()); } break; } case SUBTREE_MODIFIED: { processor.processUpdatedNeutronDto((T) dto.getDataBefore(), (T) dto.getDataAfter()); break; } case DELETE: { processor.processDeletedNeutronDto((T) dto.getDataBefore()); break; } } } @VisibleForTesting void clearDataChangeProviders() { dataChangeProviders.clear(); } @VisibleForTesting <T extends DataObject> void addDataChangeProvider(MappingProvider<T> t) { dataChangeProviders.add(t); } @Override public void close() { registeredListener.close(); } }