1 package cz.cuni.amis.pogamut.base.utils.logging.marks; 2 3 import cz.cuni.amis.pogamut.base.utils.logging.LogCategory; 4 import java.io.Serializable; 5 import java.util.Calendar; 6 import java.util.logging.Level; 7 import java.util.logging.LogRecord; 8 9 /** 10 * DO NOT USE THIS CLASS!! Use methods in {@link LogCategory} to add events to the log. 11 * <p/> 12 * This class is special parameter of the {@link LogRecord} that means some 13 * kind of event has happend to the agent. The handler of log records can do some 14 * nifty stuff when he finds this object as parameter of {@link LogRecord}, 15 * like showing in some GUI. 16 * <p/> 17 * Under normal circumstances, you create new mark using one of create* methods, 18 * pass it as parameter of some log message, it gets transfered (probably through JMX) 19 * to some handler on the other side (in our particular case to Netbeans plugin 20 * and timeline), where some handler will look for {@link LogRecord LogRecords} 21 * with this object as one of parameters and when it finds it, it shows the mark 22 * in some GUI. 23 * {@code 24 * // create an event that with text "Text of event for GUI" that will be 25 * // shown for duration of 2 seconds. 26 * logger.info("Text of event for text logger" , new Object[]{LogEventMark.createFixedLengthEvent(Level.INFO, "Text of event for GUI", null, 2000)}); 27 * } 28 * 29 * @see LogMapMark 30 * @author Honza 31 */ 32 public class LogEventMark implements Serializable { 33 34 /** 35 * Type of {@link LogEventMark}. 36 */ 37 public enum Type { 38 39 /** 40 * Single time event. Event of this type has no duration, 41 * <p/> 42 * Example: I have died. 43 */ 44 SINGLE_EVENT, 45 /** 46 * Event that lasts for certain specified duration. 47 * <p/> 48 * Example: Item taken, won't spawn for 32 seconds 49 */ 50 FIXED_DURATION, 51 /** 52 * Used as start mark of event that has variable duration. This ends 53 * only when corresponding end event is send. 54 * <p/> 55 * Example: bot has been hurt, start event "bot is low on health" 56 */ 57 START_EVENT, 58 /** 59 * End mark of event with variable duration, shoudn't be created directly, 60 * but through {@link LogEventMark#getEndMark() } 61 * Example: bot picked health pack, end event "bot is low on health" 62 */ 63 END_EVENT 64 } 65 /** 66 * Generator of unique id. All create* methods are synchronized so you can't 67 * generate two marks with same id. 68 */ 69 private static int lastAssignedID = 0; 70 /** 71 * Unique id of event. Start and end marks of same event have same id. 72 */ 73 private final int id; 74 /** 75 * Level of event. 76 */ 77 private final Level level; 78 /** 79 * Text of event. 80 */ 81 private final String text; 82 /** 83 * Timestamp for when the event has started. In ms since epoch. 84 */ 85 private final long time; 86 /** 87 * How long should event last, in ms. 88 */ 89 private final long duration; 90 /** 91 * Type of event. 92 */ 93 private Type type; 94 95 /** 96 * Create new log event mark. For use of create* methods. 97 * @param id unique id of log event, only start and end marks of same event can have same id. 98 * @param level how important is this log event 99 * @param text text of event 100 * @param time when should event start, in ms since epoch 101 * @param duration how long should event last. 102 * @param type what is type of mark. 103 */ 104 private LogEventMark(int id, Level level, String text, long time, long duration, Type type) { 105 this.id = id; 106 this.level = level; 107 this.text = text; 108 this.time = time; 109 this.duration = duration; 110 this.type = type; 111 } 112 113 /** 114 * Create new log event mark. Create id from {@link LogEventMark#lastAssignedID} 115 * and set start time of event from from {@link Calendar#getTimeInMillis() }. 116 * Basically wrapper for {@link LogEventMark#LogEventMark(int, java.lang.String, long, long, cz.cuni.amis.pogamut.base.utils.logging.marks.LogEventMark.Type) }. 117 * @param level how important is this log event 118 * @param text text of event 119 * @param duration how long should event last. 120 * @param type what is type of mark. 121 */ 122 private LogEventMark(Level level, String text, long duration, Type type) { 123 this(++lastAssignedID, level, text, Calendar.getInstance().getTimeInMillis(), duration, type); 124 } 125 126 /** 127 * Create single event. Such event has no duration. 128 * @param level level of log event, should be same as carrying {@link LogRecord}. 129 * @param text text of single event 130 * @return created single event. 131 */ 132 public static synchronized LogEventMark createSingleLengthEvent(Level level, String text) { 133 return new LogEventMark(level, text, 0, Type.SINGLE_EVENT); 134 } 135 136 /** 137 * Create log event that will last for some time. 138 * @param level level of log event, should be same as carrying {@link LogRecord}. 139 * @param text Text of event 140 * @param duration how long should event last. 141 */ 142 public static synchronized LogEventMark createFixedLengthEvent(Level level, String text, long duration) { 143 return new LogEventMark(level, text, duration, Type.FIXED_DURATION); 144 } 145 146 /** 147 * Create log event that will last until notified it should stop. 148 * In order to stop the event, create end mark of event using 149 * {@link LogEventMark#getEndMark() }. 150 * @param level level of log event, should be same as carrying {@link LogRecord}. 151 * @param text text of event. 152 * @return created event. 153 */ 154 public static synchronized LogEventMark createVariableLengthEvent(Level level, String text) { 155 return new LogEventMark(level, text, Integer.MAX_VALUE, Type.START_EVENT); 156 } 157 158 /** 159 * Get human readable representation of LogEventMark. 160 */ 161 @Override 162 public String toString() { 163 return getClass().getSimpleName() + " " + getText(); 164 } 165 166 /** 167 * Get unique id of event. Start and end marks of variable event have 168 * same id, because they mark same event. 169 */ 170 public int getId() { 171 return id; 172 } 173 174 /** 175 * What is level of this event? 176 * @return level of event. 177 */ 178 public Level getLevel() { 179 return level; 180 } 181 182 /** 183 * @return the message of this event 184 */ 185 public String getText() { 186 return text; 187 } 188 189 /** 190 * @return when does event start 191 */ 192 public long getTime() { 193 return time; 194 } 195 196 /** 197 * @return the type of event 198 */ 199 public Type getType() { 200 return type; 201 } 202 203 /** 204 * @return the duration of event. 0 for single event, Integer.MAX_VALUE for variable length event 205 */ 206 public long getDuration() { 207 return duration; 208 } 209 210 /** 211 * Get ending mark for variable length event. 212 * @return if this mark is {@link Type#START_EVENT start mark}, create new end mark, 213 * if this mark is {@link Type#END_EVENT end mark}, return this mark (since we already are end mark). 214 * @throws IllegalStateException if {@link Type type} of mark is not 215 * {@link Type#START_EVENT start} or {@link Type#END_EVENT end}. 216 */ 217 public LogEventMark getEndMark() { 218 switch (getType()) { 219 case START_EVENT: 220 return new LogEventMark(this.id, this.level, this.text, this.time, this.duration, Type.END_EVENT); 221 case END_EVENT: 222 return this; 223 default: 224 throw new IllegalStateException("Unexpected type of mark: " + getType()); 225 } 226 } 227 228 @Override 229 public boolean equals(Object otherObject) { 230 if (this == otherObject) { 231 return true; 232 } 233 if (!(otherObject instanceof LogEventMark)) { 234 return false; 235 } 236 237 LogEventMark other = (LogEventMark) otherObject; 238 239 if (getId() != other.getId()) { 240 return false; 241 } 242 if (!getLevel().equals(other.getLevel())) { 243 return false; 244 } 245 boolean textEqual = getText() == null ? other.getText() == null : getText().equals(other.getText()); 246 if (!textEqual) { 247 return false; 248 } 249 if (getTime() != other.getTime()) { 250 return false; 251 } 252 if (getDuration() != other.getDuration()) { 253 return false; 254 } 255 if (getType() != other.getType()) { 256 return false; 257 } 258 259 return true; 260 } 261 262 @Override 263 public int hashCode() { 264 int hash = 7; 265 hash = 67 * hash + this.id; 266 hash = 67 * hash + (this.level != null ? this.level.hashCode() : 0); 267 hash = 67 * hash + (this.text != null ? this.text.hashCode() : 0); 268 hash = 67 * hash + (int) (this.time ^ (this.time >>> 32)); 269 hash = 67 * hash + (int) (this.duration ^ (this.duration >>> 32)); 270 return hash; 271 } 272 }