package org.opendaylight.controller.forwardingrulesmanager.consumer.impl; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.opendaylight.controller.clustering.services.IClusterContainerServices; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.core.IContainer; import org.opendaylight.controller.sal.utils.ServiceHelper; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.Tables; import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.tables.Table; import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.SalTableService; import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.UpdateTableInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.table.update.UpdatedTableBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures; 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; public class TableFeaturesConsumerImpl { protected static final Logger logger = LoggerFactory.getLogger(TableFeaturesConsumerImpl.class); private SalTableService tableService; private TableDataCommitHandler commitHandler; private final IClusterContainerServices clusterContainerService = null; private IContainer container; private static final String NAMEREGEX = "^[a-zA-Z0-9]+$"; private boolean inContainerMode; // being used by global instance only public TableFeaturesConsumerImpl() { InstanceIdentifier path = InstanceIdentifier.builder(Tables.class).child(Table.class) .toInstance(); tableService = FRMConsumerImpl.getProviderSession().getRpcService(SalTableService.class); if (null == tableService) { logger.error("Consumer SAL Service is down or NULL. FRM may not function as intended"); System.out.println("Consumer SAL Service is down or NULL."); return; } System.out.println("-------------------------------------------------------------------"); commitHandler = new TableDataCommitHandler(); FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler); container = (IContainer) ServiceHelper.getGlobalInstance(IContainer.class, this); } /** * Updates TableFeatures to the southbound plugin and our internal database * * @param path * @param dataObject */ private void updateTableFeatures(InstanceIdentifier path, TableFeatures dataObject) { UpdateTableInputBuilder input = new UpdateTableInputBuilder(); UpdatedTableBuilder updatedtablebuilder = new UpdatedTableBuilder(); updatedtablebuilder.fieldsFrom(dataObject); List features = updatedtablebuilder.build().getTableFeatures(); for (TableFeatures feature : features) { if (feature != null && feature.getMaxEntries() != null) { logger.error("Max Entries field is read-only, cannot be changed"); return; } } input.setUpdatedTable(updatedtablebuilder.build()); // We send table feature update request to the sounthbound plugin tableService.updateTable(input.build()); } @SuppressWarnings("unchecked") private void commitToPlugin(internalTransaction transaction) { for (@SuppressWarnings("unused") Entry, TableFeatures> entry : transaction.updates.entrySet()) { System.out.println("Coming update cc in TableDatacommitHandler"); updateTableFeatures(entry.getKey(), entry.getValue()); } } private final class TableDataCommitHandler implements DataCommitHandler, DataObject> { @SuppressWarnings("unchecked") @Override public DataCommitTransaction requestCommit(DataModification, DataObject> modification) { // We should verify transaction System.out.println("Coming in TableFeaturesDatacommitHandler"); internalTransaction transaction = new internalTransaction(modification); transaction.prepareUpdate(); return transaction; } } private final class internalTransaction implements DataCommitTransaction, DataObject> { private final DataModification, DataObject> modification; @Override public DataModification, DataObject> getModification() { return modification; } public internalTransaction(DataModification, DataObject> modification) { this.modification = modification; } Map, TableFeatures> updates = new HashMap<>(); /** * We create a plan which table features will be updated. * */ void prepareUpdate() { Set, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet(); for (Entry, DataObject> entry : puts) { // validating the DataObject Status status = validate(container, (TableFeatures) entry); if (!status.isSuccess()) { logger.warn("Invalid Configuration for table features The failure is {}", entry, status.getDescription()); String error = "Invalid Configuration (" + status.getDescription() + ")"; logger.error(error); return; } if (entry.getValue() instanceof TableFeatures) { TableFeatures tablefeatures = (TableFeatures) entry.getValue(); preparePutEntry(entry.getKey(), tablefeatures); } } } private void preparePutEntry(InstanceIdentifier key, TableFeatures tablefeatures) { if (tablefeatures != null) { // Updating the Map System.out.println("Coming update in TableFeaturesDatacommitHandler"); updates.put(key, tablefeatures); } } /** * We are OK to go with execution of plan * */ @Override public RpcResult finish() throws IllegalStateException { commitToPlugin(this); // We return true if internal transaction is successful. // return Rpcs.getRpcResult(true, null, Collections.emptySet()); return Rpcs.getRpcResult(true, null, null); } /** * * We should rollback our preparation * */ @Override public RpcResult rollback() throws IllegalStateException { // NOOP - we did not modified any internal state during // requestCommit phase // return Rpcs.getRpcResult(true, null, Collections.emptySet()); return Rpcs.getRpcResult(true, null, null); } public Status validate(IContainer container, TableFeatures dataObject) { String tablename = dataObject.getName(); if (tablename == null || tablename.trim().isEmpty() || !tablename.matches(NAMEREGEX) || tablename.length() != 32) { return new Status(StatusCode.BADREQUEST, "Invalid table name"); } return new Status(StatusCode.SUCCESS); } } }