BUG 1839 - HTTP delete of non existing data
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / MultipartMessageManager.java
1 /*
2  * Copyright IBM Corporation, 2013.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.md.statistics.manager;
9
10 import java.util.Iterator;
11 import java.util.Map;
12 import java.util.concurrent.ConcurrentHashMap;
13
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.MultipartTransactionAware;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
17
18 import com.google.common.base.Preconditions;
19
20 /**
21  * Main responsibility of the class is to manage multipart response
22  * for multipart request. It also handles the flow aggregate request
23  * and response mapping.
24  * @author avishnoi@in.ibm.com
25  *
26  */
27 class MultipartMessageManager {
28     /*
29      *  Map for tx id and type of request, to keep track of all the request sent
30      *  by Statistics Manager. Statistics Manager won't entertain any multipart
31      *  response for which it didn't send the request.
32      */
33     private final Map<TxIdEntry,Long> txIdToRequestTypeMap = new ConcurrentHashMap<>();
34     /*
35      * Map to keep track of the request tx id for flow table statistics request.
36      * Because flow table statistics multi part response do not contains the table id.
37      */
38     private final Map<TxIdEntry,Short> txIdTotableIdMap = new ConcurrentHashMap<>();
39     private final long lifetimeNanos;
40
41     public MultipartMessageManager(long lifetimeNanos) {
42         this.lifetimeNanos = lifetimeNanos;
43     }
44
45     private static final class TxIdEntry {
46         private final TransactionId txId;
47
48         public TxIdEntry(TransactionId txId) {
49             this.txId = txId;
50         }
51         public TransactionId getTxId() {
52             return txId;
53         }
54         @Override
55         public int hashCode() {
56             final int prime = 31;
57             int result = 1;
58             result = prime * result + ((txId == null) ? 0 : txId.hashCode());
59             return result;
60         }
61         @Override
62         public boolean equals(Object obj) {
63             if (this == obj) {
64                 return true;
65             }
66             if (obj == null) {
67                 return false;
68             }
69             if (!(obj instanceof TxIdEntry)) {
70                 return false;
71             }
72             TxIdEntry other = (TxIdEntry) obj;
73
74             if (txId == null) {
75                 if (other.txId != null) {
76                     return false;
77                 }
78             } else if (!txId.equals(other.txId)) {
79                 return false;
80             }
81             return true;
82         }
83
84         @Override
85         public String toString() {
86             return "TxIdEntry [txId=" + txId + ']';
87         }
88     }
89
90     public void recordExpectedTableTransaction(TransactionId id, Short tableId) {
91         recordExpectedTransaction(id);
92         txIdTotableIdMap.put(new TxIdEntry(id), Preconditions.checkNotNull(tableId));
93     }
94
95     public Short isExpectedTableTransaction(TransactionAware transaction) {
96         Boolean more = null;
97         if (transaction instanceof MultipartTransactionAware) {
98             more = ((MultipartTransactionAware)transaction).isMoreReplies();
99         }
100
101         if (!isExpectedTransaction(transaction, more)) {
102             return null;
103         }
104
105         final TxIdEntry key = new TxIdEntry(transaction.getTransactionId());
106         if (more != null && more.booleanValue()) {
107             return txIdTotableIdMap.get(key);
108         } else {
109             return txIdTotableIdMap.remove(key);
110         }
111     }
112
113     public void recordExpectedTransaction(TransactionId id) {
114         TxIdEntry entry = new TxIdEntry(Preconditions.checkNotNull(id));
115         txIdToRequestTypeMap.put(entry, getExpiryTime());
116     }
117
118     private boolean isExpectedTransaction(TransactionAware transaction, Boolean more) {
119         final TxIdEntry entry = new TxIdEntry(transaction.getTransactionId());
120         if (more != null && more.booleanValue()) {
121             return txIdToRequestTypeMap.containsKey(entry);
122         } else {
123             return txIdToRequestTypeMap.remove(entry) != null;
124         }
125     }
126
127     public boolean isExpectedTransaction(TransactionAware transaction) {
128         Boolean more = null;
129         if (transaction instanceof MultipartTransactionAware) {
130             more = ((MultipartTransactionAware)transaction).isMoreReplies();
131         }
132
133         return isExpectedTransaction(transaction, more);
134     }
135
136     private Long getExpiryTime() {
137         return System.nanoTime() + lifetimeNanos;
138     }
139
140     public void cleanStaleTransactionIds() {
141         final long now = System.nanoTime();
142
143         for (Iterator<TxIdEntry> it = txIdToRequestTypeMap.keySet().iterator();it.hasNext();){
144             TxIdEntry txIdEntry = it.next();
145
146             Long expiryTime = txIdToRequestTypeMap.get(txIdEntry);
147             if(now > expiryTime){
148                 it.remove();
149                 txIdTotableIdMap.remove(txIdEntry);
150             }
151         }
152     }
153 }