/** * 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.controller.sal.compatibility; import java.util.Collections; import java.util.Map; import java.util.Set; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.base.Preconditions; public abstract class AbstractDataChangeListener implements AutoCloseable,DataChangeListener{ private static final Logger LOG = LoggerFactory.getLogger(AbstractDataChangeListener.class); protected InventoryAndReadAdapter adapter; protected final Class clazz; protected ListenerRegistration listenerRegistration; public AbstractDataChangeListener(final InventoryAndReadAdapter adapter, DataBroker db, final Class clazz) { this.adapter = Preconditions.checkNotNull(adapter, "InventoryAndReadAdapter can not be null!"); this.clazz = Preconditions.checkNotNull(clazz, "Class can not be null!"); Preconditions.checkNotNull(db, "DataBroker can not be null!"); registrationListener(db, 5); } @Override public void onDataChanged(AsyncDataChangeEvent, DataObject> changeEvent) { Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!"); /* All DataObjects for create */ final Map, DataObject> createdData = changeEvent.getCreatedData() != null ? changeEvent.getCreatedData() : Collections., DataObject> emptyMap(); /* All DataObjects for remove */ final Set> removeData = changeEvent.getRemovedPaths() != null ? changeEvent.getRemovedPaths() : Collections.> emptySet(); /* All DataObjects for updates */ final Map, DataObject> updateData = changeEvent.getUpdatedData() != null ? changeEvent.getUpdatedData() : Collections., DataObject> emptyMap(); /* All Original DataObjects */ final Map, DataObject> originalData = changeEvent.getOriginalData() != null ? changeEvent.getOriginalData() : Collections., DataObject> emptyMap(); this.createData(createdData); this.updateData(updateData, originalData); this.removeData(removeData, originalData); } @SuppressWarnings("unchecked") private void createData(final Map, DataObject> createdData) { final Set> keys = createdData.keySet() != null ? createdData.keySet() : Collections.> emptySet(); for (InstanceIdentifier key : keys) { if (clazz.equals(key.getTargetType())) { InstanceIdentifier createKeyIdent = key.firstIdentifierOf(clazz); final Optional value = Optional.of(createdData.get(key)); if (value.isPresent()) { this.add(createKeyIdent, (T)value.get()); } } } } abstract protected void add(InstanceIdentifier createKeyIdent, T node); @SuppressWarnings("unchecked") private void updateData(final Map, DataObject> updateData, final Map, DataObject> originalData) { final Set> keys = updateData.keySet() != null ? updateData.keySet() : Collections.> emptySet(); for (InstanceIdentifier key : keys) { if (clazz.equals(key.getTargetType())) { InstanceIdentifier updateKeyIdent = key.firstIdentifierOf(clazz); final Optional value = Optional.of(updateData.get(key)); final Optional original = Optional.of(originalData.get(key)); if (value.isPresent() && original.isPresent()) { this.update(updateKeyIdent, (T)original.get(), (T)value.get()); } } } } abstract protected void update(InstanceIdentifier updateKeyIdent, T node, T node2); @SuppressWarnings("unchecked") private void removeData(final Set> removeData, final Map, DataObject> originalData) { for (InstanceIdentifier key : removeData) { if (clazz.equals(key.getTargetType())) { final InstanceIdentifier ident = key.firstIdentifierOf(clazz); final DataObject removeValue = originalData.get(key); this.remove(ident, (T)removeValue); } } } abstract protected void remove(InstanceIdentifier ident, T removeValue); protected void registrationListener(final DataBroker db, int i) { try { listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, getWildCardPath(), this, DataChangeScope.BASE); } catch (final Exception e) { if (i >= 1) { try { Thread.sleep(100); } catch (InterruptedException e1) { LOG.error("Thread interrupted '{}'", e1); Thread.currentThread().interrupt(); } registrationListener(db, --i); } else { LOG.error("AbstractDataChangeListener registration fail!", e); throw new IllegalStateException("AbstractDataChangeListener registration Listener fail! System needs restart.", e); } } } protected abstract InstanceIdentifier getWildCardPath(); @Override public void close() { if (listenerRegistration != null) { try { listenerRegistration.close(); } catch (final Exception e) { LOG.error("Error by stop AbstractDataChangeListener.", e); } listenerRegistration = null; } } }