/*
* 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.base_endpoint;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import javax.annotation.Nullable;
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.data.LogicalDatastoreType;
import org.opendaylight.groupbasedpolicy.api.EndpointAugmentor;
import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
import org.opendaylight.groupbasedpolicy.util.EndpointUtils;
import org.opendaylight.groupbasedpolicy.util.IidFactory;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.BaseEndpointService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.RegisterEndpointInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.containment.endpoints.ContainmentEndpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.containment.endpoints.ContainmentEndpointBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.containment.endpoints.ContainmentEndpointKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpointBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpointKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.ParentEndpointChoice;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.containment.endpoint._case.ParentContainmentEndpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.containment.endpoint._case.ParentContainmentEndpointBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.containment.endpoint._case.ParentContainmentEndpointKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpointBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpointKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointReg;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.ContainmentEndpointReg;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.unregister.endpoint.input.AddressEndpointUnreg;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.unregister.endpoint.input.ContainmentEndpointUnreg;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
public class BaseEndpointServiceImpl implements BaseEndpointService, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(BaseEndpointServiceImpl.class);
private final DataBroker dataProvider;
private final EndpointAugmentorRegistryImpl epAugRegistry;
private static final Function<Void, RpcResult<Void>> TO_SUCCESS_RPC_RESULT = new Function<Void, RpcResult<Void>>() {
@Override
public RpcResult<Void> apply(Void input) {
return RpcResultBuilder.<Void>success().build();
}
};
public BaseEndpointServiceImpl(DataBroker dataProvider, EndpointAugmentorRegistryImpl epAugRegistry) {
this.epAugRegistry = Preconditions.checkNotNull(epAugRegistry);
this.dataProvider = Preconditions.checkNotNull(dataProvider);
}
/**
* Register a new endpoint into the registry. If there is already an existing
* endpoint with the same keys, they will be overwritten with the new information.
*
* @param input Endpoint to register
*/
@Override
public Future<RpcResult<Void>> registerEndpoint(RegisterEndpointInput input) {
long timestamp = System.currentTimeMillis();
ReadWriteTransaction t = dataProvider.newReadWriteTransaction();
ListenableFuture<RpcResult<Void>> failResult =
RegisterEndpointInputVerificator.verifyRegisterEndpointInput(input, t);
if (failResult != null) {
t.cancel();
return failResult;
}
List<ContainmentEndpointReg> endpoints = input.getContainmentEndpointReg();
for (ContainmentEndpointReg ce : nullToEmpty(endpoints)) {
long stamp = (ce.getTimestamp() == null || ce.getTimestamp() == 0) ? timestamp : ce.getTimestamp();
ContainmentEndpoint endpoint = buildContainmentEndpoint(ce).setTimestamp(stamp).build();
t.put(LogicalDatastoreType.OPERATIONAL, IidFactory.containmentEndpointIid(endpoint.getKey()), endpoint,
true);
addContainmentEndpointToChilds(t, endpoint);
}
List<AddressEndpointReg> addressEndpoints = input.getAddressEndpointReg();
for (AddressEndpointReg ae : nullToEmpty(addressEndpoints)) {
long stamp = (ae.getTimestamp() == null || ae.getTimestamp() == 0) ? timestamp : ae.getTimestamp();
AddressEndpoint endpoint = buildAddressEndpoint(ae).setTimestamp(stamp).build();
t.put(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(endpoint.getKey()), endpoint, true);
addAddressEndpointToChilds(t, endpoint);
addAddressEndpointToParents(t, endpoint);
}
return Futures.transform(t.submit(), TO_SUCCESS_RPC_RESULT);
}
private void addContainmentEndpointToChilds(ReadWriteTransaction t, ContainmentEndpoint endpoint) {
ParentContainmentEndpoint epAsParent = new ParentContainmentEndpointBuilder(endpoint).build();
for (ChildEndpoint child : nullToEmpty(endpoint.getChildEndpoint())) {
InstanceIdentifier<AddressEndpoint> childIid =
IidFactory.addressEndpointIid(EndpointUtils.createAddressEndpointKey(child));
Optional<AddressEndpoint> childAddrEpOptional =
DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, childIid, t);
if (childAddrEpOptional.isPresent()) {
KeyedInstanceIdentifier<ParentContainmentEndpoint, ParentContainmentEndpointKey> parentInChildIid =
childIid.child(ParentContainmentEndpoint.class, epAsParent.getKey());
t.put(LogicalDatastoreType.OPERATIONAL, parentInChildIid, epAsParent, true);
}
}
}
private void addAddressEndpointToChilds(ReadWriteTransaction t, AddressEndpoint endpoint) {
ParentEndpoint epAsParent = new ParentEndpointBuilder(endpoint).build();
for (ChildEndpoint child : nullToEmpty(endpoint.getChildEndpoint())) {
InstanceIdentifier<AddressEndpoint> childIid =
IidFactory.addressEndpointIid(EndpointUtils.createAddressEndpointKey(child));
Optional<AddressEndpoint> childAddrEpOptional =
DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, childIid, t);
if (childAddrEpOptional.isPresent()) {
KeyedInstanceIdentifier<ParentEndpoint, ParentEndpointKey> parentInChildIid =
childIid.child(ParentEndpoint.class, epAsParent.getKey());
t.put(LogicalDatastoreType.OPERATIONAL, parentInChildIid, epAsParent, true);
}
}
}
private void addAddressEndpointToParents(ReadWriteTransaction t, AddressEndpoint endpoint) {
ChildEndpoint epAsChild = new ChildEndpointBuilder(endpoint).build();
for (ParentEndpoint parent : EndpointUtils.getParentEndpoints(endpoint.getParentEndpointChoice())) {
InstanceIdentifier<AddressEndpoint> parentIid =
IidFactory.addressEndpointIid(EndpointUtils.createAddressEndpointKey(parent));
Optional<AddressEndpoint> parentAddrEpOptional =
DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, parentIid, t);
if (parentAddrEpOptional.isPresent()) {
KeyedInstanceIdentifier<ChildEndpoint, ChildEndpointKey> childInParentIid =
parentIid.child(ChildEndpoint.class, epAsChild.getKey());
t.put(LogicalDatastoreType.OPERATIONAL, childInParentIid, epAsChild, true);
}
}
for (ParentContainmentEndpoint parent : EndpointUtils.getParentContainmentEndpoints(endpoint.getParentEndpointChoice())) {
InstanceIdentifier<ContainmentEndpoint> parentIid = IidFactory
.containmentEndpointIid(new ContainmentEndpointKey(parent.getContextId(), parent.getContextType()));
Optional<ContainmentEndpoint> parentContEpOptional =
DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, parentIid, t);
if (parentContEpOptional.isPresent()) {
KeyedInstanceIdentifier<ChildEndpoint, ChildEndpointKey> childInParentIid =
parentIid.child(ChildEndpoint.class, epAsChild.getKey());
t.put(LogicalDatastoreType.OPERATIONAL, childInParentIid, epAsChild, true);
}
}
}
private ContainmentEndpointBuilder buildContainmentEndpoint(ContainmentEndpointReg input) {
ContainmentEndpointBuilder eb = new ContainmentEndpointBuilder().setChildEndpoint(input.getChildEndpoint())
.setCondition(input.getCondition())
.setContextType(input.getContextType())
.setContextId(input.getContextId())
.setEndpointGroup(input.getEndpointGroup())
.setKey(new ContainmentEndpointKey(input.getContextId(), input.getContextType()))
.setNetworkContainment(input.getNetworkContainment())
.setTenant(input.getTenant())
.setTimestamp(input.getTimestamp())
.setChildEndpoint(input.getChildEndpoint());
for (EndpointAugmentor epAugmentor : epAugRegistry.getEndpointAugmentors()) {
try {
Map.Entry<Class<? extends Augmentation<ContainmentEndpoint>>, Augmentation<ContainmentEndpoint>> augmentationEntry =
epAugmentor.buildContainmentEndpointAugmentation(input);
if (augmentationEntry != null) {
eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
}
} catch (Exception e) {
LOG.warn("AddressEndpoint Augmentation error while {} was processing {}",
epAugmentor.getClass().getSimpleName(), input, e);
}
}
return eb;
}
private AddressEndpointBuilder buildAddressEndpoint(AddressEndpointReg ae) {
AddressEndpointBuilder builder = new AddressEndpointBuilder().setTenant(ae.getTenant())
.setNetworkContainment(ae.getNetworkContainment())
.setEndpointGroup(ae.getEndpointGroup())
.setAddress(ae.getAddress())
.setAddressType(ae.getAddressType())
.setChildEndpoint(ae.getChildEndpoint())
.setCondition(ae.getCondition())
.setKey(new AddressEndpointKey(ae.getAddress(), ae.getAddressType(), ae.getContextId(),
ae.getContextType()))
.setParentEndpointChoice(ae.getParentEndpointChoice())
.setTimestamp(ae.getTimestamp())
.setContextId(ae.getContextId())
.setContextType(ae.getContextType())
.setTenant(ae.getTenant());
for (EndpointAugmentor epAugmentor : epAugRegistry.getEndpointAugmentors()) {
try {
Map.Entry<Class<? extends Augmentation<AddressEndpoint>>, Augmentation<AddressEndpoint>> augmentationEntry =
epAugmentor.buildAddressEndpointAugmentation(ae);
if (augmentationEntry != null) {
builder.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
}
} catch (Exception e) {
LOG.warn("AddressEndpoint Augmentation error while {} was processing {}",
epAugmentor.getClass().getSimpleName(), ae, e);
}
}
return builder;
}
/**
* Unregister an endpoint or endpoints from the registry.
*
* @param input Endpoint/endpoints to unregister
*/
@Override
public Future<RpcResult<Void>> unregisterEndpoint(UnregisterEndpointInput input) {
ReadWriteTransaction t = dataProvider.newReadWriteTransaction();
List<AddressEndpointUnreg> addrEndpoints = input.getAddressEndpointUnreg();
for (AddressEndpointUnreg aeUnreg : nullToEmpty(addrEndpoints)) {
AddressEndpointKey key = new AddressEndpointKey(aeUnreg.getAddress(), aeUnreg.getAddressType(),
aeUnreg.getContextId(), aeUnreg.getContextType());
Optional<AddressEndpoint> aeOptional = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
IidFactory.addressEndpointIid(key), t);
if (aeOptional.isPresent()) {
deleteAddressEndpointFromParents(t, aeOptional.get());
deleteAddressEndpointFromChilds(t, aeOptional.get());
}
}
List<ContainmentEndpointUnreg> contEndpoints = input.getContainmentEndpointUnreg();
for (ContainmentEndpointUnreg ceUnreg : nullToEmpty(contEndpoints)) {
ContainmentEndpointKey key = new ContainmentEndpointKey(ceUnreg.getContextId(), ceUnreg.getContextType());
Optional<ContainmentEndpoint> ceOptional = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
IidFactory.containmentEndpointIid(key), t);
if (ceOptional.isPresent()) {
deleteContainmentEndpointFromChilds(t, ceOptional.get());
}
}
ListenableFuture<Void> r = t.submit();
return Futures.transform(r, TO_SUCCESS_RPC_RESULT);
}
private void deleteAddressEndpointFromParents(ReadWriteTransaction t, AddressEndpoint endpoint) {
ParentEndpointChoice parentEndpointChoice = endpoint.getParentEndpointChoice();
for (ParentEndpoint parentEndpoint : EndpointUtils.getParentEndpoints(parentEndpointChoice)) {
KeyedInstanceIdentifier<ChildEndpoint, ChildEndpointKey> childEp =
IidFactory.addressEndpointIid(EndpointUtils.createAddressEndpointKey(parentEndpoint)).child(ChildEndpoint.class,
new ChildEndpointKey(endpoint.getAddress(), endpoint.getAddressType(),
endpoint.getContextId(), endpoint.getContextType()));
DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, childEp, t);
}
for (ParentContainmentEndpoint parentContEndpoint : EndpointUtils.getParentContainmentEndpoints(parentEndpointChoice)) {
KeyedInstanceIdentifier<ChildEndpoint, ChildEndpointKey> childEp = IidFactory
.containmentEndpointIid(new ContainmentEndpointKey(parentContEndpoint.getContextId(),
parentContEndpoint.getContextType()))
.child(ChildEndpoint.class, new ChildEndpointKey(endpoint.getAddress(), endpoint.getAddressType(),
endpoint.getContextId(), endpoint.getContextType()));
DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, childEp, t);
}
}
private void deleteAddressEndpointFromChilds(ReadWriteTransaction t, AddressEndpoint endpoint) {
for (ChildEndpoint childEndpoint : nullToEmpty(endpoint.getChildEndpoint())) {
KeyedInstanceIdentifier<ParentEndpoint, ParentEndpointKey> parentEp =
IidFactory.addressEndpointIid(EndpointUtils.createAddressEndpointKey(childEndpoint)).child(ParentEndpoint.class,
new ParentEndpointKey(endpoint.getAddress(), endpoint.getAddressType(),
endpoint.getContextId(), endpoint.getContextType()));
DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, parentEp, t);
}
}
private void deleteContainmentEndpointFromChilds(ReadWriteTransaction t, ContainmentEndpoint endpoint) {
for (ChildEndpoint child : nullToEmpty(endpoint.getChildEndpoint())) {
AddressEndpointKey aeKey = new AddressEndpointKey(child.getAddress(), child.getAddressType(),
child.getContextId(), child.getContextType());
KeyedInstanceIdentifier<ParentContainmentEndpoint, ParentContainmentEndpointKey> parentEp =
IidFactory.addressEndpointIid(aeKey).child(ParentContainmentEndpoint.class,
new ParentContainmentEndpointKey(endpoint.getContextId(), endpoint.getContextType()));
DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, parentEp, t);
}
}
@Override
public void close() {
}
private <T> List<T> nullToEmpty(@Nullable List<T> list) {
return list == null ? Collections.emptyList() : list;
}
}