Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 1 | package net.floodlightcontroller.debugevent; |
| 2 | |
| 3 | import java.lang.ref.SoftReference; |
| 4 | import java.lang.reflect.Field; |
| 5 | import java.text.SimpleDateFormat; |
| 6 | import java.util.HashMap; |
| 7 | import java.util.List; |
| 8 | import java.util.Map; |
Jonathan Hart | c78b8f6 | 2014-08-07 22:31:09 -0700 | [diff] [blame] | 9 | import java.util.Set; |
Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 10 | |
| 11 | import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn; |
| 12 | import net.onrc.onos.core.packet.IPv4; |
| 13 | import net.onrc.onos.core.util.SwitchPort; |
| 14 | |
Jonathan Hart | c78b8f6 | 2014-08-07 22:31:09 -0700 | [diff] [blame] | 15 | import org.projectfloodlight.openflow.protocol.OFFlowModFlags; |
| 16 | import org.projectfloodlight.openflow.util.HexString; |
Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 17 | |
| 18 | public class Event { |
| 19 | long timestamp; |
| 20 | long threadId; |
| 21 | String threadName; |
| 22 | Object eventData; |
| 23 | private Map<String, String> returnMap; |
| 24 | |
| 25 | public Event(long timestamp, long threadId, String threadName, Object eventData) { |
| 26 | super(); |
| 27 | this.timestamp = timestamp; |
| 28 | this.threadId = threadId; |
| 29 | this.threadName = threadName; |
| 30 | this.eventData = eventData; |
| 31 | } |
| 32 | |
| 33 | public long getTimestamp() { |
| 34 | return timestamp; |
| 35 | } |
| 36 | |
| 37 | public void setTimestamp(long timestamp) { |
| 38 | this.timestamp = timestamp; |
| 39 | } |
| 40 | |
| 41 | public long getThreadId() { |
| 42 | return threadId; |
| 43 | } |
| 44 | |
| 45 | public void setThreadId(long threadId) { |
| 46 | this.threadId = threadId; |
| 47 | } |
| 48 | |
| 49 | public String getThreadName() { |
| 50 | return threadName; |
| 51 | } |
| 52 | |
| 53 | public void setThreadName(String threadName) { |
| 54 | this.threadName = threadName; |
| 55 | } |
| 56 | |
| 57 | public Object geteventData() { |
| 58 | return eventData; |
| 59 | } |
| 60 | |
| 61 | public void seteventData(Object eventData) { |
| 62 | this.eventData = eventData; |
| 63 | } |
| 64 | |
| 65 | /** |
| 66 | * If an old event (eg. popped from a circular buffer) is being re-used for |
| 67 | * storing a new event, it is very important to clear the cached formatted |
| 68 | * event, so that the formatting can be redone with the new event data. |
| 69 | * Otherwise it will appear as if the circular buffer is not getting updated |
| 70 | * at all as old (cached) formatted event is delivered to the user. |
| 71 | */ |
| 72 | public void nullifyCachedFormattedEvent() { |
| 73 | this.returnMap = null; |
| 74 | } |
| 75 | |
| 76 | @Override |
| 77 | public String toString() { |
| 78 | return "Event [timestamp=" + timestamp + ", threadId=" + threadId |
| 79 | + ", eventData=" + eventData.toString() + "]"; |
| 80 | } |
| 81 | |
| 82 | public Map<String, String> getFormattedEvent(Class<?> eventClass, String moduleEventName) { |
| 83 | if (eventClass == null || !eventClass.equals(eventData.getClass())) { |
| 84 | returnMap = new HashMap<String, String>(); |
| 85 | returnMap.put("Error", "null event data or event-class does not match event-data"); |
| 86 | return returnMap; |
| 87 | } |
| 88 | // return cached value if there is one |
| 89 | if (returnMap != null) |
| 90 | return returnMap; |
| 91 | |
| 92 | returnMap = new HashMap<String, String>(); |
| 93 | returnMap.put("Timestamp", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") |
| 94 | .format(timestamp)); |
| 95 | returnMap.put("Thread Id", String.valueOf(threadId)); |
| 96 | returnMap.put("Thread Name", String.valueOf(threadName)); |
| 97 | customFormat(eventClass, eventData, returnMap); |
| 98 | return returnMap; |
| 99 | } |
| 100 | |
| 101 | private void customFormat(Class<?> clazz, Object eventData, |
| 102 | Map<String, String> retMap) { |
| 103 | for (Field f : clazz.getDeclaredFields()) { |
| 104 | EventColumn ec = f.getAnnotation(EventColumn.class); |
| 105 | if (ec == null) continue; |
| 106 | f.setAccessible(true); |
| 107 | try { |
| 108 | Object obj = f.get(eventData); |
| 109 | |
| 110 | switch(ec.description()) { |
| 111 | case DPID: |
| 112 | retMap.put(ec.name(), HexString.toHexString((Long) obj)); |
| 113 | break; |
| 114 | case MAC: |
| 115 | retMap.put(ec.name(), HexString.toHexString((Long) obj, 6)); |
| 116 | break; |
| 117 | case IPv4: |
| 118 | retMap.put(ec.name(), net.onrc.onos.core.packet.IPv4.fromIPv4Address((Integer) obj)); |
| 119 | break; |
| 120 | case FLOW_MOD_FLAGS: |
Jonathan Hart | c78b8f6 | 2014-08-07 22:31:09 -0700 | [diff] [blame] | 121 | @SuppressWarnings("unchecked") |
| 122 | Set<OFFlowModFlags> flags = (Set<OFFlowModFlags>) obj; |
Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 123 | StringBuilder builder = new StringBuilder(); |
Jonathan Hart | c78b8f6 | 2014-08-07 22:31:09 -0700 | [diff] [blame] | 124 | if (flags.isEmpty()) { |
Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 125 | builder.append("None"); |
| 126 | } |
| 127 | else { |
Jonathan Hart | c78b8f6 | 2014-08-07 22:31:09 -0700 | [diff] [blame] | 128 | if (flags.contains(OFFlowModFlags.SEND_FLOW_REM)) { |
Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 129 | builder.append("SEND_FLOW_REM "); |
| 130 | } |
Jonathan Hart | c78b8f6 | 2014-08-07 22:31:09 -0700 | [diff] [blame] | 131 | if (flags.contains(OFFlowModFlags.CHECK_OVERLAP)) { |
Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 132 | builder.append("CHECK_OVERLAP "); |
| 133 | } |
Jonathan Hart | c78b8f6 | 2014-08-07 22:31:09 -0700 | [diff] [blame] | 134 | if (flags.contains(OFFlowModFlags.EMERG)) { |
Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 135 | builder.append("EMERG "); |
| 136 | } |
| 137 | } |
| 138 | retMap.put(ec.name(), builder.toString()); |
| 139 | break; |
| 140 | case LIST_IPV4: |
| 141 | @SuppressWarnings("unchecked") |
| 142 | List<Integer> ipv4Addresses = (List<Integer>)obj; |
| 143 | StringBuilder ipv4AddressesStr = new StringBuilder(); |
| 144 | if (ipv4Addresses.size() == 0) { |
| 145 | ipv4AddressesStr.append("--"); |
| 146 | } else { |
| 147 | for (Integer ipv4Addr : ipv4Addresses) { |
| 148 | ipv4AddressesStr.append(IPv4.fromIPv4Address(ipv4Addr.intValue())); |
| 149 | ipv4AddressesStr.append(" "); |
| 150 | } |
| 151 | } |
| 152 | retMap.put(ec.name(), ipv4AddressesStr.toString()); |
| 153 | break; |
| 154 | case LIST_ATTACHMENT_POINT: |
| 155 | @SuppressWarnings("unchecked") |
| 156 | List<SwitchPort> aps = (List<SwitchPort>)obj; |
| 157 | StringBuilder apsStr = new StringBuilder(); |
| 158 | if (aps.size() == 0) { |
| 159 | apsStr.append("--"); |
| 160 | } else { |
| 161 | for (SwitchPort ap : aps) { |
Pavlin Radoslavov | 3d322f4 | 2014-08-18 14:58:55 -0700 | [diff] [blame] | 162 | apsStr.append(HexString.toHexString(ap.getDpid().value())); |
Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 163 | apsStr.append("/"); |
Pavlin Radoslavov | 3d322f4 | 2014-08-18 14:58:55 -0700 | [diff] [blame] | 164 | apsStr.append(ap.getPortNumber().value()); |
Brian O'Connor | c67f9fa | 2014-08-07 18:17:46 -0700 | [diff] [blame] | 165 | apsStr.append(" "); |
| 166 | } |
| 167 | } |
| 168 | retMap.put(ec.name(), apsStr.toString()); |
| 169 | break; |
| 170 | case LIST_OBJECT: |
| 171 | @SuppressWarnings("unchecked") |
| 172 | List<Object> obl = (List<Object>)obj; |
| 173 | StringBuilder sbldr = new StringBuilder(); |
| 174 | if (obl.size() == 0) { |
| 175 | sbldr.append("--"); |
| 176 | } else { |
| 177 | for (Object o : obl) { |
| 178 | sbldr.append(o.toString()); |
| 179 | sbldr.append(" "); |
| 180 | } |
| 181 | } |
| 182 | retMap.put(ec.name(), sbldr.toString()); |
| 183 | break; |
| 184 | case SREF_LIST_OBJECT: |
| 185 | @SuppressWarnings("unchecked") |
| 186 | SoftReference<List<Object>> srefListObj = |
| 187 | (SoftReference<List<Object>>)obj; |
| 188 | List<Object> ol = srefListObj.get(); |
| 189 | if (ol != null) { |
| 190 | StringBuilder sb = new StringBuilder(); |
| 191 | if (ol.size() == 0) { |
| 192 | sb.append("--"); |
| 193 | } else { |
| 194 | for (Object o : ol) { |
| 195 | sb.append(o.toString()); |
| 196 | sb.append(" "); |
| 197 | } |
| 198 | } |
| 199 | retMap.put(ec.name(), sb.toString()); |
| 200 | } else { |
| 201 | retMap.put(ec.name(), "-- reference not available --"); |
| 202 | } |
| 203 | break; |
| 204 | case SREF_OBJECT: |
| 205 | @SuppressWarnings("unchecked") |
| 206 | SoftReference<Object> srefObj = (SoftReference<Object>)obj; |
| 207 | if (srefObj == null) { |
| 208 | retMap.put(ec.name(), "--"); |
| 209 | } else { |
| 210 | Object o = srefObj.get(); |
| 211 | if (o != null) { |
| 212 | retMap.put(ec.name(), o.toString()); |
| 213 | } else { |
| 214 | retMap.put(ec.name(), |
| 215 | "-- reference not available --"); |
| 216 | } |
| 217 | } |
| 218 | break; |
| 219 | case STRING: |
| 220 | case OBJECT: |
| 221 | case PRIMITIVE: |
| 222 | default: |
| 223 | retMap.put(ec.name(), obj.toString()); |
| 224 | } |
| 225 | } catch (ClassCastException e) { |
| 226 | retMap.put("Error", e.getMessage()); |
| 227 | } catch (IllegalArgumentException e) { |
| 228 | retMap.put("Error", e.getMessage()); |
| 229 | } catch (IllegalAccessException e) { |
| 230 | retMap.put("Error", e.getMessage()); |
| 231 | } |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | } |