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