TableFeatures Update,correcting InstanceIdentifier
[controller.git] / opendaylight / md-sal / forwardingrules-manager / src / main / java / org / opendaylight / controller / forwardingrulesmanager / consumer / impl / TableFeaturesConsumerImpl.java
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/TableFeaturesConsumerImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/TableFeaturesConsumerImpl.java
new file mode 100644 (file)
index 0000000..30556e4
--- /dev/null
@@ -0,0 +1,192 @@
+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<? extends DataObject> 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<TableFeatures> 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<InstanceIdentifier<?>, TableFeatures> entry : transaction.updates.entrySet()) {
+            System.out.println("Coming update cc in TableDatacommitHandler");
+            updateTableFeatures(entry.getKey(), entry.getValue());
+        }
+
+    }
+
+    private final class TableDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public DataCommitTransaction requestCommit(DataModification<InstanceIdentifier<?>, 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<InstanceIdentifier<?>, DataObject> {
+
+        private final DataModification<InstanceIdentifier<?>, DataObject> modification;
+
+        @Override
+        public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
+            return modification;
+        }
+
+        public internalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
+            this.modification = modification;
+        }
+
+        Map<InstanceIdentifier<?>, TableFeatures> updates = new HashMap<>();
+
+        /**
+         * We create a plan which table features will be updated.
+         *
+         */
+        void prepareUpdate() {
+
+            Set<Entry<InstanceIdentifier<?>, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet();
+            for (Entry<InstanceIdentifier<?>, 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<Void> 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<Void> 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);
+        }
+    }
+}