/* * 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.md.sal.binding.compat; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; 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.DataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.util.ListenerRegistry; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Deprecated public class HydrogenDataBrokerAdapter implements DataProviderService, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(HydrogenDataBrokerAdapter.class); private final DataBroker delegate; public HydrogenDataBrokerAdapter(final DataBroker dataBroker) { delegate = dataBroker; LOG.info("ForwardedBackwardsCompatibleBroker started."); } @Override public DataModificationTransaction beginTransaction() { return new ForwardedBackwardsCompatibleTransacion(delegate.newReadWriteTransaction()); } @Override public DataObject readConfigurationData(final InstanceIdentifier path) { final DataModificationTransaction tx = beginTransaction(); return tx.readConfigurationData(path); } @Override public DataObject readOperationalData(final InstanceIdentifier path) { final DataModificationTransaction tx = beginTransaction(); return tx.readOperationalData(path); } @Override public ListenerRegistration registerDataChangeListener( final InstanceIdentifier path, final DataChangeListener listener) { final org.opendaylight.controller.md.sal.binding.api.DataChangeListener asyncOperListener = new BackwardsCompatibleOperationalDataChangeInvoker(listener); final org.opendaylight.controller.md.sal.binding.api.DataChangeListener asyncCfgListener = new BackwardsCompatibleConfigurationDataChangeInvoker(listener); final ListenerRegistration cfgReg = delegate.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, asyncCfgListener, DataChangeScope.SUBTREE); final ListenerRegistration operReg = delegate.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, path, asyncOperListener, DataChangeScope.SUBTREE); return new LegacyListenerRegistration(listener,cfgReg,operReg); } @Deprecated private class ForwardedBackwardsCompatibleTransacion implements DataModificationTransaction { private final ListenerRegistry listeners = ListenerRegistry.create(); private final Map, DataObject> updated = new HashMap<>(); private final Map, DataObject> created = new HashMap<>(); private final Set> removed = new HashSet<>(); private final Map, DataObject> original = new HashMap<>(); private TransactionStatus status = TransactionStatus.NEW; private final Set> posponedRemovedOperational = new HashSet<>(); private final Set> posponedRemovedConfiguration = new HashSet<>(); private final ReadWriteTransaction delegate; @Override public final TransactionStatus getStatus() { return status; } protected ForwardedBackwardsCompatibleTransacion(final ReadWriteTransaction delegate) { this.delegate = delegate; LOG.debug("Tx {} allocated.",getIdentifier()); } @Override public void putOperationalData(final InstanceIdentifier path, final DataObject data) { final boolean previouslyRemoved = posponedRemovedOperational.remove(path); @SuppressWarnings({ "rawtypes", "unchecked" }) final InstanceIdentifier castedPath = (InstanceIdentifier) path; if(previouslyRemoved) { delegate.put(LogicalDatastoreType.OPERATIONAL, castedPath, data,true); } else { delegate.merge(LogicalDatastoreType.OPERATIONAL, castedPath, data,true); } } @Override public void putConfigurationData(final InstanceIdentifier path, final DataObject data) { final boolean previouslyRemoved = posponedRemovedConfiguration.remove(path); final DataObject originalObj = readConfigurationData(path); if (originalObj != null) { original.put(path, originalObj); } else { created.put(path, data); } updated.put(path, data); @SuppressWarnings({"rawtypes","unchecked"}) final InstanceIdentifier castedPath = (InstanceIdentifier) path; if(previouslyRemoved) { delegate.put(LogicalDatastoreType.CONFIGURATION, castedPath, data,true); } else { delegate.merge(LogicalDatastoreType.CONFIGURATION, castedPath, data,true); } } @Override public void removeOperationalData(final InstanceIdentifier path) { posponedRemovedOperational.add(path); } @Override public void removeConfigurationData(final InstanceIdentifier path) { posponedRemovedConfiguration.add(path); } @Override public Map, DataObject> getCreatedOperationalData() { return Collections.emptyMap(); } @Override public Map, DataObject> getCreatedConfigurationData() { return created; } @Override public Map, DataObject> getUpdatedOperationalData() { return Collections.emptyMap(); } @Override public Map, DataObject> getUpdatedConfigurationData() { return updated; } @Override public Set> getRemovedConfigurationData() { return removed; } @Override public Set> getRemovedOperationalData() { return Collections.emptySet(); } @Override public Map, DataObject> getOriginalConfigurationData() { return original; } @Override public Map, DataObject> getOriginalOperationalData() { return Collections.emptyMap(); } @Override public DataObject readOperationalData(final InstanceIdentifier path) { try { return delegate.read(LogicalDatastoreType.OPERATIONAL, path).get().orNull(); } catch (InterruptedException | ExecutionException e) { LOG.error("Read of {} failed.", path,e); return null; } } @Override public DataObject readConfigurationData(final InstanceIdentifier path) { try { return delegate.read(LogicalDatastoreType.CONFIGURATION, path).get().orNull(); } catch (InterruptedException | ExecutionException e) { LOG.error("Read of {} failed.", path,e); return null; } } private void changeStatus(final TransactionStatus status) { LOG.trace("Transaction {} changed status to {}", getIdentifier(), status); this.status = status; for(final ListenerRegistration listener : listeners) { try { listener.getInstance().onStatusUpdated(this, status); } catch (final Exception e) { LOG.error("Error during invoking transaction listener {}",listener.getInstance(),e); } } } @Override public ListenableFuture> commit() { for(final InstanceIdentifier path : posponedRemovedConfiguration) { delegate.delete(LogicalDatastoreType.CONFIGURATION, path); } for(final InstanceIdentifier path : posponedRemovedOperational) { delegate.delete(LogicalDatastoreType.OPERATIONAL, path); } changeStatus(TransactionStatus.SUBMITED); final ListenableFuture> f = delegate.commit(); Futures.addCallback(f, new FutureCallback>() { @Override public void onSuccess(final RpcResult result) { changeStatus(result.getResult()); } @Override public void onFailure(final Throwable t) { LOG.error("Transaction {} failed to complete", getIdentifier(), t); changeStatus(TransactionStatus.FAILED); } }); return f; } @Override public ListenerRegistration registerListener(final DataTransactionListener listener) { return listeners.register(listener); } @Override public Object getIdentifier() { // TODO Auto-generated method stub return null; } } private static final class LegacyListenerRegistration implements ListenerRegistration { private final DataChangeListener instance; private final ListenerRegistration cfgReg; private final ListenerRegistration operReg; public LegacyListenerRegistration(final DataChangeListener listener, final ListenerRegistration cfgReg, final ListenerRegistration operReg) { this.instance = listener; this.cfgReg = cfgReg; this.operReg = operReg; } @Override public DataChangeListener getInstance() { return instance; } @Override public void close() { cfgReg.close(); operReg.close(); } } private static class BackwardsCompatibleOperationalDataChangeInvoker implements org.opendaylight.controller.md.sal.binding.api.DataChangeListener, Delegator { private final org.opendaylight.controller.md.sal.common.api.data.DataChangeListener delegate; public BackwardsCompatibleOperationalDataChangeInvoker(final DataChangeListener listener) { this.delegate = listener; } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { final DataChangeEvent legacyChange = HydrogenDataChangeEvent.createOperational(change); delegate.onDataChanged(legacyChange); } @Override public DataChangeListener getDelegate() { return (DataChangeListener) delegate; } } private static class BackwardsCompatibleConfigurationDataChangeInvoker implements org.opendaylight.controller.md.sal.binding.api.DataChangeListener, Delegator { private final org.opendaylight.controller.md.sal.common.api.data.DataChangeListener delegate; public BackwardsCompatibleConfigurationDataChangeInvoker(final DataChangeListener listener) { this.delegate = listener; } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { final DataChangeEvent legacyChange = HydrogenDataChangeEvent.createConfiguration(change); delegate.onDataChanged(legacyChange); } @Override public DataChangeListener getDelegate() { return (DataChangeListener) delegate; } } @Override public void close() throws Exception { // TODO Auto-generated method stub } }