Merge changes I0f752636,Idd154499,Ic35fa3e8
[controller.git] / opendaylight / md-sal / forwardingrules-manager / src / main / java / org / opendaylight / controller / forwardingrulesmanager / consumer / impl / TableFeaturesConsumerImpl.java
1 package org.opendaylight.controller.forwardingrulesmanager.consumer.impl;
2
3 import java.util.HashMap;
4 import java.util.List;
5 import java.util.Map;
6 import java.util.Map.Entry;
7 import java.util.Set;
8
9 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
10 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
11 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
12 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
13 import org.opendaylight.controller.sal.common.util.Rpcs;
14 import org.opendaylight.controller.sal.core.IContainer;
15 import org.opendaylight.controller.sal.utils.ServiceHelper;
16 import org.opendaylight.controller.sal.utils.Status;
17 import org.opendaylight.controller.sal.utils.StatusCode;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.Tables;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.tables.Table;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.SalTableService;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.UpdateTableInputBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.table.update.UpdatedTableBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
24 import org.opendaylight.yangtools.yang.binding.DataObject;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
26 import org.opendaylight.yangtools.yang.common.RpcResult;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 public class TableFeaturesConsumerImpl {
31     protected static final Logger logger = LoggerFactory.getLogger(TableFeaturesConsumerImpl.class);
32     private SalTableService tableService;
33     private TableDataCommitHandler commitHandler;
34     private final IClusterContainerServices clusterContainerService = null;
35     private IContainer container;
36     private static final String NAMEREGEX = "^[a-zA-Z0-9]+$";
37     private boolean inContainerMode; // being used by global instance only
38
39     public TableFeaturesConsumerImpl() {
40         InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Tables.class).child(Table.class)
41                 .toInstance();
42         tableService = FRMConsumerImpl.getProviderSession().getRpcService(SalTableService.class);
43
44         if (null == tableService) {
45             logger.error("Consumer SAL Service is down or NULL. FRM may not function as intended");
46             System.out.println("Consumer SAL Service is down or NULL.");
47             return;
48         }
49
50         System.out.println("-------------------------------------------------------------------");
51         commitHandler = new TableDataCommitHandler();
52         FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
53         container = (IContainer) ServiceHelper.getGlobalInstance(IContainer.class, this);
54     }
55
56     /**
57      * Updates TableFeatures to the southbound plugin and our internal database
58      *
59      * @param path
60      * @param dataObject
61      */
62     private void updateTableFeatures(InstanceIdentifier<?> path, TableFeatures dataObject) {
63
64         UpdateTableInputBuilder input = new UpdateTableInputBuilder();
65         UpdatedTableBuilder updatedtablebuilder = new UpdatedTableBuilder();
66         updatedtablebuilder.fieldsFrom(dataObject);
67         List<TableFeatures> features = updatedtablebuilder.build().getTableFeatures();
68         for (TableFeatures feature : features) {
69             if (feature != null && feature.getMaxEntries() != null) {
70                 logger.error("Max Entries field is read-only, cannot be changed");
71                 return;
72             }
73         }
74         input.setUpdatedTable(updatedtablebuilder.build());
75
76         // We send table feature update request to the sounthbound plugin
77         tableService.updateTable(input.build());
78     }
79
80     @SuppressWarnings("unchecked")
81     private void commitToPlugin(internalTransaction transaction) {
82
83         for (@SuppressWarnings("unused")
84         Entry<InstanceIdentifier<?>, TableFeatures> entry : transaction.updates.entrySet()) {
85             System.out.println("Coming update cc in TableDatacommitHandler");
86             updateTableFeatures(entry.getKey(), entry.getValue());
87         }
88
89     }
90
91     private final class TableDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
92
93         @SuppressWarnings("unchecked")
94         @Override
95         public DataCommitTransaction requestCommit(DataModification<InstanceIdentifier<?>, DataObject> modification) {
96             // We should verify transaction
97             System.out.println("Coming in TableFeaturesDatacommitHandler");
98             internalTransaction transaction = new internalTransaction(modification);
99             transaction.prepareUpdate();
100             return transaction;
101         }
102     }
103
104     private final class internalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
105
106         private final DataModification<InstanceIdentifier<?>, DataObject> modification;
107
108         @Override
109         public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
110             return modification;
111         }
112
113         public internalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
114             this.modification = modification;
115         }
116
117         Map<InstanceIdentifier<?>, TableFeatures> updates = new HashMap<>();
118
119         /**
120          * We create a plan which table features will be updated.
121          *
122          */
123         void prepareUpdate() {
124
125             Set<Entry<InstanceIdentifier<?>, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet();
126             for (Entry<InstanceIdentifier<?>, DataObject> entry : puts) {
127
128                 // validating the DataObject
129
130                 Status status = validate(container, (TableFeatures) entry);
131                 if (!status.isSuccess()) {
132                     logger.warn("Invalid Configuration for table features The failure is {}", entry,
133                             status.getDescription());
134                     String error = "Invalid Configuration (" + status.getDescription() + ")";
135                     logger.error(error);
136                     return;
137                 }
138                 if (entry.getValue() instanceof TableFeatures) {
139                     TableFeatures tablefeatures = (TableFeatures) entry.getValue();
140                     preparePutEntry(entry.getKey(), tablefeatures);
141                 }
142
143             }
144         }
145
146         private void preparePutEntry(InstanceIdentifier<?> key, TableFeatures tablefeatures) {
147             if (tablefeatures != null) {
148                 // Updating the Map
149                 System.out.println("Coming update  in TableFeaturesDatacommitHandler");
150                 updates.put(key, tablefeatures);
151             }
152         }
153
154         /**
155          * We are OK to go with execution of plan
156          *
157          */
158         @Override
159         public RpcResult<Void> finish() throws IllegalStateException {
160
161             commitToPlugin(this);
162             // We return true if internal transaction is successful.
163             // return Rpcs.getRpcResult(true, null, Collections.emptySet());
164             return Rpcs.getRpcResult(true, null, null);
165         }
166
167         /**
168          *
169          * We should rollback our preparation
170          *
171          */
172         @Override
173         public RpcResult<Void> rollback() throws IllegalStateException {
174             // NOOP - we did not modified any internal state during
175             // requestCommit phase
176             // return Rpcs.getRpcResult(true, null, Collections.emptySet());
177             return Rpcs.getRpcResult(true, null, null);
178
179         }
180
181         public Status validate(IContainer container, TableFeatures dataObject) {
182
183             String tablename = dataObject.getName();
184             if (tablename == null || tablename.trim().isEmpty() || !tablename.matches(NAMEREGEX)
185                     || tablename.length() != 32) {
186                 return new Status(StatusCode.BADREQUEST, "Invalid table name");
187             }
188
189             return new Status(StatusCode.SUCCESS);
190         }
191     }
192 }