/*
* Copyright (c) 2015 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.openflowplugin.applications.bulk.o.matic;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.JdkFutureAdapters;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.AddFlowsDsInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.AddFlowsRpcInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.BulkFlowBaseContentGrouping;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.FlowRpcAddMultipleInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.FlowRpcAddTestInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.FlowTestInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.ReadFlowTestInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.RemoveFlowsDsInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.RemoveFlowsRpcInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.SalBulkFlowService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.TableTestInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.TableTestInput.Operation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.bulk.flow.service.rev150608.bulk.flow.ds.list.grouping.BulkFlowDsItem;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple implementation providing bulk flows operations.
*/
public class SalBulkFlowServiceImpl implements SalBulkFlowService {
private static final Logger LOG = LoggerFactory.getLogger(SalBulkFlowServiceImpl.class);
private final SalFlowService flowService;
private final DataBroker dataBroker;
private final FlowCounter flowCounterBeanImpl = new FlowCounter();
private final ExecutorService fjService = new ForkJoinPool();
public SalBulkFlowServiceImpl(SalFlowService flowService, DataBroker dataBroker) {
this.flowService = Preconditions.checkNotNull(flowService);
this.dataBroker = Preconditions.checkNotNull(dataBroker);
register();
}
@Override
public Future<RpcResult<Void>> addFlowsDs(AddFlowsDsInput input) {
WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
boolean createParentsNextTime = MoreObjects.firstNonNull(input.isAlwaysCreateParents(), Boolean.FALSE);
boolean createParents = true;
for (BulkFlowDsItem bulkFlow : input.getBulkFlowDsItem()) {
FlowBuilder flowBuilder = new FlowBuilder(bulkFlow);
flowBuilder.setTableId(bulkFlow.getTableId());
flowBuilder.setId(new FlowId(bulkFlow.getFlowId()));
writeTransaction.put(LogicalDatastoreType.CONFIGURATION, getFlowInstanceIdentifier(bulkFlow),
flowBuilder.build(), createParents);
createParents = createParentsNextTime;
}
CheckedFuture<Void, TransactionCommitFailedException> submitFuture = writeTransaction.submit();
return handleResultFuture(submitFuture);
}
private InstanceIdentifier<Flow> getFlowInstanceIdentifier(BulkFlowDsItem bulkFlow) {
final NodeRef nodeRef = bulkFlow.getNode();
return ((InstanceIdentifier<Node>) nodeRef.getValue())
.augmentation(FlowCapableNode.class)
.child(Table.class, new TableKey(bulkFlow.getTableId()))
.child(Flow.class,
new FlowKey(new FlowId(bulkFlow.getFlowId())));
}
@Override
public Future<RpcResult<Void>> removeFlowsDs(RemoveFlowsDsInput input) {
WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
for (BulkFlowDsItem bulkFlow : input.getBulkFlowDsItem()) {
writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, getFlowInstanceIdentifier(bulkFlow));
}
CheckedFuture<Void, TransactionCommitFailedException> submitFuture = writeTransaction.submit();
return handleResultFuture(submitFuture);
}
private ListenableFuture<RpcResult<Void>> handleResultFuture(CheckedFuture<Void,
TransactionCommitFailedException> submitFuture) {
final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
Futures.addCallback(submitFuture, new FutureCallback<Void>() {
@Override
public void onSuccess(Void result) {
rpcResult.set(RpcResultBuilder.success(result).build());
}
@Override
public void onFailure(Throwable t) {
RpcResultBuilder<Void> rpcResultBld = RpcResultBuilder.<Void>failed()
.withRpcErrors(Collections.singleton(
RpcResultBuilder.newError(RpcError.ErrorType.APPLICATION, null, t.getMessage())
));
rpcResult.set(rpcResultBld.build());
}
});
return rpcResult;
}
private <T> ListenableFuture<RpcResult<Void>> handleResultFuture(ListenableFuture<List<T>> submitFuture) {
final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
Futures.addCallback(submitFuture, new FutureCallback<List<T>>() {
@Override
public void onSuccess(List<T> result) {
rpcResult.set(RpcResultBuilder.success((Void) null).build());
}
@Override
public void onFailure(Throwable t) {
RpcResultBuilder<Void> rpcResultBld = RpcResultBuilder.<Void>failed()
.withRpcErrors(Collections.singleton(
RpcResultBuilder.newError(RpcError.ErrorType.APPLICATION, null, t.getMessage())
));
rpcResult.set(rpcResultBld.build());
}
});
return rpcResult;
}
@Override
public Future<RpcResult<Void>> addFlowsRpc(AddFlowsRpcInput input) {
List<ListenableFuture<RpcResult<AddFlowOutput>>> bulkResults = new ArrayList<>();
for (BulkFlowBaseContentGrouping bulkFlow : input.getBulkFlowItem()) {
AddFlowInputBuilder flowInputBuilder = new AddFlowInputBuilder((org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow) bulkFlow);
final NodeRef nodeRef = bulkFlow.getNode();
flowInputBuilder.setNode(nodeRef);
flowInputBuilder.setTableId(bulkFlow.getTableId());
Future<RpcResult<AddFlowOutput>> rpcAddFlowResult = flowService.addFlow(flowInputBuilder.build());
bulkResults.add(JdkFutureAdapters.listenInPoolThread(rpcAddFlowResult));
}
return handleResultFuture(Futures.allAsList(bulkResults));
}
@Override
public Future<RpcResult<Void>> readFlowTest(ReadFlowTestInput input) {
FlowReader flowReader = FlowReader.getNewInstance(dataBroker,
input.getDpnCount().intValue(),
input.getFlowsPerDpn().intValue(), input.isVerbose(),
input.isIsConfigDs(),input.getStartTableId().shortValue(),
input.getEndTableId().shortValue());
flowCounterBeanImpl.setReader(flowReader);
fjService.execute(flowReader);
RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.success();
return Futures.immediateFuture(rpcResultBuilder.build());
}
@Override
public Future<RpcResult<Void>> flowRpcAddTest(FlowRpcAddTestInput input) {
FlowWriterDirectOFRpc flowAddRpcTestImpl = new FlowWriterDirectOFRpc(dataBroker, flowService, fjService);
flowAddRpcTestImpl.rpcFlowAdd(
input.getDpnId(),
input.getFlowCount().intValue(),
input.getRpcBatchSize().intValue());
RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.success();
return Futures.immediateFuture(rpcResultBuilder.build());
}
@Override
public Future<RpcResult<Void>> register() {
RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.success();
try {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
String pathToMBean = String.format("%s:type=%s",
FlowCounter.class.getPackage().getName(),
FlowCounter.class.getSimpleName());
ObjectName name = null;
name = new ObjectName(pathToMBean);
mbs.registerMBean(flowCounterBeanImpl, name);
} catch (MalformedObjectNameException | InstanceAlreadyExistsException
| MBeanRegistrationException | NotCompliantMBeanException e) {
rpcResultBuilder = RpcResultBuilder.failed();
LOG.warn("Exception occurred: {} ", e.getMessage(), e);
}
return Futures.immediateFuture(rpcResultBuilder.build());
}
@Override
public Future<RpcResult<Void>> removeFlowsRpc(RemoveFlowsRpcInput input) {
List<ListenableFuture<RpcResult<RemoveFlowOutput>>> bulkResults = new ArrayList<>();
for (BulkFlowBaseContentGrouping bulkFlow : input.getBulkFlowItem()) {
RemoveFlowInputBuilder flowInputBuilder = new RemoveFlowInputBuilder((org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow) bulkFlow);
final NodeRef nodeRef = bulkFlow.getNode();
flowInputBuilder.setNode(nodeRef);
flowInputBuilder.setTableId(bulkFlow.getTableId());
Future<RpcResult<RemoveFlowOutput>> rpcAddFlowResult = flowService.removeFlow(flowInputBuilder.build());
bulkResults.add(JdkFutureAdapters.listenInPoolThread(rpcAddFlowResult));
}
return handleResultFuture(Futures.allAsList(bulkResults));
}
@Override
public Future<RpcResult<Void>> flowTest(FlowTestInput input) {
if (input.isTxChain()) {
FlowWriterTxChain flowTester = new FlowWriterTxChain(dataBroker, fjService);
flowCounterBeanImpl.setWriter(flowTester);
if (input.isIsAdd()){
flowTester.addFlows(input.getDpnCount().intValue(), input.getFlowsPerDpn().intValue(),
input.getBatchSize().intValue(), input.getSleepFor().intValue(),
input.getSleepAfter().intValue(), input.getStartTableId().shortValue(),
input.getEndTableId().shortValue(), input.isCreateParents());
} else {
flowTester.deleteFlows(input.getDpnCount().intValue(), input.getFlowsPerDpn().intValue(),
input.getBatchSize().intValue(), input.getStartTableId().shortValue(),
input.getEndTableId().shortValue());
}
RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.success();
return Futures.immediateFuture(rpcResultBuilder.build());
}
if (input.isSeq()) {
FlowWriterSequential flowTester = new FlowWriterSequential(dataBroker, fjService);
flowCounterBeanImpl.setWriter(flowTester);
if (input.isIsAdd()){
flowTester.addFlows(input.getDpnCount().intValue(), input.getFlowsPerDpn().intValue(),
input.getBatchSize().intValue(), input.getSleepFor().intValue(),
input.getStartTableId().shortValue(), input.getEndTableId().shortValue(),
input.isCreateParents());
} else {
flowTester.deleteFlows(input.getDpnCount().intValue(), input.getFlowsPerDpn().intValue(),
input.getBatchSize().intValue(), input.getStartTableId().shortValue(),
input.getEndTableId().shortValue());
}
} else {
FlowWriterConcurrent flowTester = new FlowWriterConcurrent(dataBroker, fjService);
flowCounterBeanImpl.setWriter(flowTester);
if (input.isIsAdd()){
flowTester.addFlows(input.getDpnCount().intValue(), input.getFlowsPerDpn().intValue(),
input.getBatchSize().intValue(), input.getSleepFor().intValue(),
input.getSleepAfter().intValue(), input.getStartTableId().shortValue(),
input.getEndTableId().shortValue(), input.isCreateParents());
} else {
flowTester.deleteFlows(input.getDpnCount().intValue(), input.getFlowsPerDpn().intValue(),
input.getBatchSize().intValue(), input.getStartTableId().shortValue(),
input.getEndTableId().shortValue());
}
}
RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.success();
return Futures.immediateFuture(rpcResultBuilder.build());
}
@Override
public Future<RpcResult<Void>> tableTest(final TableTestInput input) {
final TableWriter writer = new TableWriter(dataBroker, fjService);
flowCounterBeanImpl.setWriter(writer);
switch (input.getOperation()) {
case Add:
writer.addTables(input.getDpnCount().intValue(),
input.getStartTableId().shortValue(), input.getEndTableId().shortValue());
break;
case Delete:
writer.deleteTables(input.getDpnCount().intValue(),
input.getStartTableId().shortValue(), input.getEndTableId().shortValue());
break;
default:
RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.failed();
return Futures.immediateFuture(rpcResultBuilder.build());
}
RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.success();
return Futures.immediateFuture(rpcResultBuilder.build());
}
@Override
public Future<RpcResult<Void>> flowRpcAddMultiple(FlowRpcAddMultipleInput input) {
FlowWriterDirectOFRpc flowTesterRPC = new FlowWriterDirectOFRpc(dataBroker, flowService, fjService);
flowTesterRPC.rpcFlowAddAll(input.getFlowCount().intValue(), input.getRpcBatchSize().intValue());
RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.success();
return Futures.immediateFuture(rpcResultBuilder.build());
}
}