1 package cz.cuni.amis.pogamut.base.utils.logging.marks;
2
3 import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
4 import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
5
6 import java.io.Serializable;
7 import java.util.Calendar;
8 import java.util.logging.Level;
9 import java.util.logging.LogRecord;
10
11 /**
12 * DON'T USE THIS CLASS! Use methods in {@link LogCategory} to place mark on the map.
13 * <p/>
14 * This is an object that is passed through log infrastructure to appear on the other side
15 * through JMX and it is utilized there to add mark on the map.
16 * <p/>
17 * Basically, if you want to use it directly (DON'T), create LogMapMark using some of
18 * the create*Event method and pass it to log as parameter of log message.
19 * {@code
20 * // create a mark that with text "text to show in map" that will be
21 * // shown at the position of agent for its duration of 2secibds.
22 * logger.info("Text to log" , new Object[]{LogMapMark.createFixedLengthEvent(Level.INFO, "text to show in map", null, 2000)});
23 * }
24 * @author Honza
25 */
26 public class LogMapMark implements Serializable {
27
28 public enum Type {
29
30 FIXED_DURATION,
31 START_EVENT,
32 END_EVENT
33 }
34 /**
35 * Generator of unique id. All create* methods are synchronized so you can't
36 * generate two marks with same id.
37 */
38 private static int lastAssignedID = 0;
39 /**
40 * Custom generated id. Start and end mark of variable elngth map mark have same id.
41 */
42 private final int id;
43 /**
44 * What level is this mark?
45 */
46 private final Level level;
47 /**
48 * text shown by this mark
49 */
50 private final String message;
51 /**
52 * Location, where is mark placed. If null, follow agent.
53 */
54 private final Location location;
55 /**
56 * Timestamp when should mark first appear in the map.
57 */
58 private final long created;
59 /**
60 * For how long should map appear in the map.
61 */
62 private final long duration;
63 /**
64 * Type of mark. There are basically only two types: with fixed duration and
65 * varible length. Mark with variable length starts with START_EVENT and is finished
66 * by END_EVENT.
67 */
68 private Type type;
69
70 /**
71 * Create new map mark.
72 * @param id unique id of map mark, only start and end mark of same map mark have same id.
73 * @param level what importance is this map mark? User can filter out some levels.
74 * @param message What is the text that should be displayed on the mark?
75 * @param location location, at which map mark should be located. If null, than mark will follow agent.
76 * @param created when should map mark first appear in map
77 * @param duration for how long should map mark be shown in the map.
78 * @param type What type is this mark.
79 */
80 private LogMapMark(int id, Level level, String message, Location location, long created, long duration, Type type) {
81 this.id = id;
82 this.level = level;
83 this.message = message;
84 this.location = location != null ? new Location(location) : null;
85 this.created = created;
86 this.duration = duration;
87 this.type = type;
88 }
89
90 /**
91 * Create new map mark. For parameters see {@link LogMapMark#LogMapMark(int, java.util.logging.Level, java.lang.String, cz.cuni.amis.pogamut.base3d.worldview.object.Location, long, long, cz.cuni.amis.pogamut.base.utils.logging.marks.LogMapMark.Type)
92 */
93 private LogMapMark(Level level, String message, Location location, long created, long duration, Type type) {
94 this(++lastAssignedID, level, message, location, created, duration, type);
95 }
96
97 /**
98 * Create mark on the map that will stay there for some time.
99 * @param level level of mark, should be same as the level of carrying {@link LogRecord}
100 * @param message text of map mark
101 * @param location location, at which map mark should be located. If null, than mark will follow agent.
102 * @param duration how long should map mark be shown in the map.
103 * @return
104 */
105 public synchronized static LogMapMark createFixedLengthEvent(Level level, String message, Location location, long duration) {
106 long time = Calendar.getInstance().getTimeInMillis();
107 return new LogMapMark(level, message, location, time, duration, Type.FIXED_DURATION);
108 }
109
110 /**
111 * Create map mark that appear in the map for certain time and will be always shown
112 * at the current position of agent.
113 * @param level level of mark, should be same as the level of carrying {@link LogRecord}
114 * @param message text of mark
115 * @param duration how long should be mark shown
116 * @return created mark.
117 */
118 public synchronized static LogMapMark createAgentFixedLengthEvent(Level level, String message, long duration) {
119 long time = Calendar.getInstance().getTimeInMillis();
120 return new LogMapMark(level, message, null, time, duration, Type.FIXED_DURATION);
121 }
122
123 /**
124 * Create mark that will always be shown at the position of agent.
125 * <p/>
126 * If you don't want to show mark in the map anymore, you have to create
127 * end mark and pass it to log infrastucture. You can create end mark
128 * by calling {@link LogMapMark#getEndMark()} on the starting mark (the one
129 * returned by this method).
130 * @param level level of mark, should be same as the level of carrying {@link LogRecord}
131 * @param message text to be shown
132 * @return created mark.
133 */
134 public synchronized static LogMapMark createAgentVariableLengthEvent(Level level, String message) {
135 long time = Calendar.getInstance().getTimeInMillis();
136 return new LogMapMark(level, message, null, time, Integer.MAX_VALUE, Type.START_EVENT);
137 }
138
139 /**
140 * Create starting map mark.
141 * <p/>
142 * In order to end the map mark, create end mark by calling
143 * {@link LogMapMark#getEndMark()} on the starting mark (the one
144 * returned by this method) and pass it to same log as starting mark.
145 * @param message text of mark
146 * @param location location, at which map mark should be located. If null, than mark will follow agent.
147 * @return starting map mark
148 */
149 public synchronized static LogMapMark createVariableLengthEvent(Level level, String message, Location location) {
150 long time = Calendar.getInstance().getTimeInMillis();
151 return new LogMapMark(level, message, location, time, Integer.MAX_VALUE, Type.START_EVENT);
152 }
153
154 @Override
155 public boolean equals(Object otherObject) {
156 if (this == otherObject) {
157 return true;
158 }
159 if (!(otherObject instanceof LogMapMark)) {
160 return false;
161 }
162
163 LogMapMark other = (LogMapMark) otherObject;
164
165 if (this.getId() != other.getId()) {
166 return false;
167 }
168 if (getType() != other.getType()) {
169 return false;
170 }
171 boolean msgEqual = this.getMessage() == null ? other.getMessage() == null : this.getMessage().equals(other.getMessage());
172 if (!msgEqual) {
173 return false;
174 }
175
176 boolean locEqual = this.getLocation() == null ? other.getLocation() == null : this.getLocation().equals(other.getLocation());
177 if (!locEqual) {
178 return false;
179 }
180 if (getCreated() != other.getCreated()) {
181 return false;
182 }
183 if (getDuration() != other.getDuration()) {
184 return false;
185 }
186
187 return true;
188 }
189
190 @Override
191 public int hashCode() {
192 int hash = 5;
193 hash = 71 * hash + (this.message != null ? this.message.hashCode() : 0);
194 hash = 71 * hash + (this.location != null ? this.location.hashCode() : 0);
195 hash = 71 * hash + (int) (this.created ^ (this.created >>> 32));
196 hash = 71 * hash + (int) (this.duration ^ (this.duration >>> 32));
197 return hash;
198 }
199
200 /**
201 * Get unique id of this map mark
202 * @return id of mark
203 */
204 public int getId() {
205 return id;
206 }
207
208 /**
209 * Get level of mark, used mainly to send end marks at same level as starting.
210 * @return level of the mark.
211 */
212 public Level getLevel() {
213 return level;
214 }
215
216 public String getMessage() {
217 return message;
218 }
219
220 /**
221 * Get location of mark. If location is null, mark is supposed to
222 * follow agent.
223 * @see LogMapMark#getLocation(cz.cuni.amis.pogamut.base3d.worldview.object.Location)
224 * @return copy of marks location or null.
225 */
226 public Location getLocation() {
227 return location != null ? new Location(location) : null;
228 }
229
230 /**
231 * Get location, where mark is supposed to be.
232 * <p/>
233 * If marks location is null, return location of entity
234 * @param entityLoc location of agent this map mark belongs to
235 * @return copy of location, where mark is supposed to be.
236 */
237 public Location getLocation(Location entityLoc) {
238 Location markLocation = getLocation();
239 return markLocation != null ? markLocation : new Location(entityLoc);
240 }
241
242 public long getCreated() {
243 return created;
244 }
245
246 public long getDuration() {
247 return duration;
248 }
249
250 public Type getType() {
251 return type;
252 }
253
254 /**
255 * Get end mark to make some map mark disappear from map.
256 * <p/>
257 * This is method that should be used only by map marks without defined
258 * duration (starting map marks).
259 * @return end mark to be passed to same log as the starting mark was.
260 */
261 public LogMapMark getEndMark() {
262 if (this.getType() == Type.START_EVENT || this.getType() == Type.END_EVENT) {
263 LogMapMark endMark = new LogMapMark(this.id, this.level, this.message, this.location, this.created, this.duration, Type.END_EVENT);
264 return endMark;
265 } else {
266 throw new IllegalStateException("Mark is not in a state that can be changed to END_EVENT, it is in " + getType());
267 }
268 }
269 }