/*
* 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.location.resolver;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
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.DataTreeIdentifier;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
import org.opendaylight.groupbasedpolicy.util.IidFactory;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.AddressEndpointLocation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.AddressEndpointLocationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.AddressEndpointLocationKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.ContainmentEndpointLocation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.ContainmentEndpointLocationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.ContainmentEndpointLocationKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.ExternalLocation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.InternalLocation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.LocationProviders;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderContainmentEndpointLocation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderContainmentEndpointLocationKey;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LocationResolver implements ClusteredDataTreeChangeListener<LocationProvider>, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(LocationResolver.class);
private Map<AddressEndpointLocationKey, Map<Long, AbsoluteLocation>> realLocations;
private DataBroker dataBroker;
private ListenerRegistration<LocationResolver> listenerRegistation;
public LocationResolver(DataBroker dataBroker) {
this.dataBroker = dataBroker;
this.realLocations = new HashMap<>();
this.listenerRegistation = dataBroker.registerDataTreeChangeListener(
new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
InstanceIdentifier.builder(LocationProviders.class).child(LocationProvider.class).build()),
this);
}
@Override
public synchronized void onDataTreeChanged(Collection<DataTreeModification<LocationProvider>> changes) {
for (DataTreeModification<LocationProvider> change : changes) {
WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
switch (change.getRootNode().getModificationType()) {
case DELETE: {
processRemovedLocationProviderData(change.getRootNode().getDataBefore(), wtx);
LOG.debug("Data from location provider {} has been removed",
change.getRootNode().getDataBefore().getProvider().getValue());
break;
}
case WRITE: {
if (change.getRootNode().getDataBefore() != null) {
processRemovedLocationProviderData(change.getRootNode().getDataBefore(), wtx);
}
processCreatedLocationProviderData(change.getRootNode().getDataAfter(), wtx);
LOG.debug("Data from location provider {} has been created",
change.getRootNode().getDataAfter().getProvider().getValue());
break;
}
case SUBTREE_MODIFIED: {
processRemovedLocationProviderData(change.getRootNode().getDataBefore(), wtx);
processCreatedLocationProviderData(change.getRootNode().getDataAfter(), wtx);
LOG.debug("Data from location provider {} has been changed",
change.getRootNode().getDataAfter().getProvider().getValue());
break;
}
}
LOG.debug("Writing endpoint location changes to DS");
DataStoreHelper.submitToDs(wtx);
}
}
private void processRemovedLocationProviderData(LocationProvider provider, WriteTransaction wtx) {
for (ProviderAddressEndpointLocation addressEndpointLocation : nullToEmpty(
provider.getProviderAddressEndpointLocation())) {
AddressEndpointLocationKey epKey = createAddressEndpointLocationKey(addressEndpointLocation.getKey());
long priority;
if (provider.getPriority() == null) {
priority = 0;
LOG.debug("{} provider doesn't provide priority. Using 0 as priority instead.",
provider.getProvider().getValue());
} else {
priority = provider.getPriority();
}
if (realLocations.get(epKey) != null) {
realLocations.get(epKey).remove(priority);
}
AbsoluteLocation newAbsoluteLocation = getBestAbsoluteLocation(epKey);
if (newAbsoluteLocation == null) {
InstanceIdentifier<AbsoluteLocation> iid = IidFactory.absoluteLocationIid(epKey);
wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
} else {
AddressEndpointLocationBuilder newEP =
new AddressEndpointLocationBuilder().setKey(epKey).setAbsoluteLocation(newAbsoluteLocation);
InstanceIdentifier<AddressEndpointLocation> iid = IidFactory.addressEndpointLocationIid(newEP.getKey());
wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, newEP.build(), true);
}
if (addressEndpointLocation.getRelativeLocations() != null) {
for (InternalLocation location : nullToEmpty(
addressEndpointLocation.getRelativeLocations().getInternalLocation())) {
InstanceIdentifier<InternalLocation> iid = IidFactory.internalLocationIid(epKey, location.getKey());
wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
}
for (ExternalLocation location : nullToEmpty(
addressEndpointLocation.getRelativeLocations().getExternalLocation())) {
InstanceIdentifier<ExternalLocation> iid = IidFactory.externalLocationIid(epKey, location.getKey());
wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
}
}
if (newAbsoluteLocation == null && addressEndpointLocation.getRelativeLocations() == null) {
InstanceIdentifier<AddressEndpointLocation> iid = IidFactory.addressEndpointLocationIid(epKey);
wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
}
}
for (ProviderContainmentEndpointLocation containmentEndpoint : nullToEmpty(
provider.getProviderContainmentEndpointLocation())) {
ContainmentEndpointLocationKey epKey = createContainmentEndpointLocationKey(containmentEndpoint.getKey());
if (containmentEndpoint.getRelativeLocations() != null) {
for (InternalLocation location : nullToEmpty(
containmentEndpoint.getRelativeLocations().getInternalLocation())) {
InstanceIdentifier<InternalLocation> iid = IidFactory.internalLocationIid(epKey, location.getKey());
wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
}
for (ExternalLocation location : nullToEmpty(
containmentEndpoint.getRelativeLocations().getExternalLocation())) {
InstanceIdentifier<ExternalLocation> iid = IidFactory.externalLocationIid(epKey, location.getKey());
wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
}
}
}
}
private void processCreatedLocationProviderData(LocationProvider provider, WriteTransaction wtx) {
for (ProviderAddressEndpointLocation addressEndpointLocation : nullToEmpty(
provider.getProviderAddressEndpointLocation())) {
AddressEndpointLocationKey epKey = createAddressEndpointLocationKey(addressEndpointLocation.getKey());
AddressEndpointLocationBuilder newEP = new AddressEndpointLocationBuilder().setKey(epKey);
if (addressEndpointLocation.getAbsoluteLocation() != null) {
if (realLocations.get(epKey) == null) {
realLocations.put(epKey, new HashMap<>());
}
long priority;
if (provider.getPriority() == null) {
priority = 0;
LOG.debug("{} provider doesnt provide priority. Using 0 as priority instead.",
provider.getProvider().getValue());
} else {
priority = provider.getPriority();
}
realLocations.get(epKey).put(priority, addressEndpointLocation.getAbsoluteLocation());
}
AbsoluteLocation bestLocation = getBestAbsoluteLocation(epKey);
if (bestLocation != null) {
newEP.setAbsoluteLocation(bestLocation);
}
if (addressEndpointLocation.getRelativeLocations() != null) {
newEP.setRelativeLocations(addressEndpointLocation.getRelativeLocations());
}
InstanceIdentifier<AddressEndpointLocation> iid = IidFactory.addressEndpointLocationIid(newEP.getKey());
wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, newEP.build(), true);
}
for (ProviderContainmentEndpointLocation containmentEndpointLocation : nullToEmpty(
provider.getProviderContainmentEndpointLocation())) {
if (containmentEndpointLocation.getRelativeLocations() != null) {
ContainmentEndpointLocationKey key =
createContainmentEndpointLocationKey(containmentEndpointLocation.getKey());
ContainmentEndpointLocationBuilder newEP = new ContainmentEndpointLocationBuilder().setKey(key);
newEP.setRelativeLocations(containmentEndpointLocation.getRelativeLocations());
InstanceIdentifier<ContainmentEndpointLocation> iid =
IidFactory.containmentEndpointLocationIid(newEP.getKey());
wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, newEP.build(), true);
}
}
}
private AbsoluteLocation getBestAbsoluteLocation(AddressEndpointLocationKey epKey) {
if (realLocations.get(epKey) == null) {
return null;
}
long bestPriority = -1;
for (long priority : realLocations.get(epKey).keySet()) {
bestPriority = bestPriority > priority ? bestPriority : priority;
};
if (bestPriority == -1) {
return null;
}
return (realLocations.get(epKey).get(new Long(bestPriority)));
}
private AddressEndpointLocationKey createAddressEndpointLocationKey(ProviderAddressEndpointLocationKey key) {
return new AddressEndpointLocationKey(key.getAddress(), key.getAddressType(), key.getContextId(),
key.getContextType());
}
private ContainmentEndpointLocationKey createContainmentEndpointLocationKey(
ProviderContainmentEndpointLocationKey key) {
return new ContainmentEndpointLocationKey(key.getContextId(), key.getContextType());
}
private <T> List<T> nullToEmpty(@Nullable List<T> list) {
return list == null ? Collections.emptyList() : list;
}
@Override
public void close() {
listenerRegistation.close();
}
}