001package com.box.sdk; 002 003import java.net.MalformedURLException; 004import java.net.URL; 005import java.util.Date; 006import java.util.Iterator; 007import java.util.LinkedHashSet; 008import java.util.Set; 009 010import com.eclipsesource.json.JsonArray; 011import com.eclipsesource.json.JsonObject; 012import com.eclipsesource.json.JsonValue; 013 014/** 015 * A log of events that were retrieved from the events endpoint. 016 * 017 * <p>An EventLog cannot be instantiated directly. Instead, use one of the static methods to retrieve a log of events. 018 * Unlike the {@link EventStream} class, EventLog doesn't support retrieving events in real-time. 019 * </p> 020 */ 021public class EventLog implements Iterable<BoxEvent> { 022 023 private static final int ENTERPRISE_LIMIT = 500; 024 /** 025 * Enterprise Event URL Template. 026 */ 027 public static final URLTemplate ENTERPRISE_EVENT_URL_TEMPLATE = new URLTemplate("events?stream_type=admin_logs&" 028 + "limit=" + ENTERPRISE_LIMIT); 029 private final int chunkSize; 030 private final int limit; 031 private final String nextStreamPosition; 032 private final String streamPosition; 033 private final Set<BoxEvent> set; 034 035 private Date startDate; 036 private Date endDate; 037 038 EventLog(BoxAPIConnection api, JsonObject json, String streamPosition, int limit) { 039 this.streamPosition = streamPosition; 040 this.limit = limit; 041 this.nextStreamPosition = json.get("next_stream_position").asString(); 042 this.chunkSize = json.get("chunk_size").asInt(); 043 044 this.set = new LinkedHashSet<BoxEvent>(this.chunkSize); 045 JsonArray entries = json.get("entries").asArray(); 046 for (JsonValue entry : entries) { 047 this.set.add(new BoxEvent(api, entry.asObject())); 048 } 049 } 050 051 /** 052 * Gets all the enterprise events that occurred within a specified date range, starting from a given position 053 * within the event stream. 054 * @param api the API connection to use. 055 * @param position the starting position of the event stream. 056 * @param after the lower bound on the timestamp of the events returned. 057 * @param before the upper bound on the timestamp of the events returned. 058 * @param types an optional list of event types to filter by. 059 * @return a log of all the events that met the given criteria. 060 */ 061 public static EventLog getEnterpriseEvents(BoxAPIConnection api, String position, Date after, Date before, 062 BoxEvent.Type... types) { 063 return getEnterpriseEvents(api, position, after, before, ENTERPRISE_LIMIT, types); 064 } 065 066 /** 067 * Gets all the enterprise events that occurred within a specified date range. 068 * @param api the API connection to use. 069 * @param after the lower bound on the timestamp of the events returned. 070 * @param before the upper bound on the timestamp of the events returned. 071 * @param types an optional list of event types to filter by. 072 * @return a log of all the events that met the given criteria. 073 */ 074 public static EventLog getEnterpriseEvents(BoxAPIConnection api, Date after, Date before, BoxEvent.Type... types) { 075 return getEnterpriseEvents(api, null, after, before, ENTERPRISE_LIMIT, types); 076 } 077 078 /** 079 * Gets all the enterprise events that occurred within a specified date range, starting from a given position 080 * within the event stream. 081 * @param api the API connection to use. 082 * @param position the starting position of the event stream. 083 * @param after the lower bound on the timestamp of the events returned. 084 * @param before the upper bound on the timestamp of the events returned. 085 * @param limit the number of entries to be returned in the response. 086 * @param types an optional list of event types to filter by. 087 * @return a log of all the events that met the given criteria. 088 */ 089 public static EventLog getEnterpriseEvents(BoxAPIConnection api, String position, Date after, Date before, 090 int limit, BoxEvent.Type... types) { 091 092 URL url = ENTERPRISE_EVENT_URL_TEMPLATE.build(api.getBaseURL()); 093 094 if (position != null || types.length > 0 || after != null 095 || before != null || limit != ENTERPRISE_LIMIT) { 096 QueryStringBuilder queryBuilder = new QueryStringBuilder(url.getQuery()); 097 098 if (after != null) { 099 queryBuilder.appendParam("created_after", 100 BoxDateFormat.format(after)); 101 } 102 103 if (before != null) { 104 queryBuilder.appendParam("created_before", 105 BoxDateFormat.format(before)); 106 } 107 108 if (position != null) { 109 queryBuilder.appendParam("stream_position", position); 110 } 111 112 if (limit != ENTERPRISE_LIMIT) { 113 queryBuilder.appendParam("limit", limit); 114 } 115 116 if (types.length > 0) { 117 StringBuilder filterBuilder = new StringBuilder(); 118 for (BoxEvent.Type filterType : types) { 119 filterBuilder.append(filterType.name()); 120 filterBuilder.append(','); 121 } 122 filterBuilder.deleteCharAt(filterBuilder.length() - 1); 123 queryBuilder.appendParam("event_type", filterBuilder.toString()); 124 } 125 126 try { 127 url = queryBuilder.addToURL(url); 128 } catch (MalformedURLException e) { 129 throw new BoxAPIException("Couldn't append a query string to the provided URL."); 130 } 131 } 132 133 BoxAPIRequest request = new BoxAPIRequest(api, url, "GET"); 134 BoxJSONResponse response = (BoxJSONResponse) request.send(); 135 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 136 EventLog log = new EventLog(api, responseJSON, position, limit); 137 log.setStartDate(after); 138 log.setEndDate(before); 139 return log; 140 } 141 142 void setStartDate(Date startDate) { 143 this.startDate = startDate; 144 } 145 146 void setEndDate(Date endDate) { 147 this.endDate = endDate; 148 } 149 150 /** 151 * Returns an iterator over the events in this log. 152 * @return an iterator over the events in this log. 153 */ 154 @Override 155 public Iterator<BoxEvent> iterator() { 156 return this.set.iterator(); 157 } 158 159 /** 160 * Gets the date of the earliest event in this log. 161 * 162 * <p>The value returned by this method corresponds to the <code>created_after</code> URL parameter that was used 163 * when retrieving the events in this EventLog.</p> 164 * 165 * @return the date of the earliest event in this log. 166 */ 167 public Date getStartDate() { 168 return this.startDate; 169 } 170 171 /** 172 * Gets the date of the latest event in this log. 173 * 174 * <p>The value returned by this method corresponds to the <code>created_before</code> URL parameter that was used 175 * when retrieving the events in this EventLog.</p> 176 * 177 * @return the date of the latest event in this log. 178 */ 179 public Date getEndDate() { 180 return this.endDate; 181 } 182 183 /** 184 * Gets the maximum number of events that this event log could contain given its start date, end date, and stream 185 * position. 186 * 187 * <p>The value returned by this method corresponds to the <code>limit</code> URL parameter that was used when 188 * retrieving the events in this EventLog.</p> 189 * 190 * @return the maximum number of events. 191 */ 192 public int getLimit() { 193 return this.limit; 194 } 195 196 /** 197 * Gets the starting position of the events in this log within the event stream. 198 * 199 * <p>The value returned by this method corresponds to the <code>stream_position</code> URL parameter that was used 200 * when retrieving the events in this EventLog.</p> 201 * 202 * @return the starting position within the event stream. 203 */ 204 public String getStreamPosition() { 205 return this.streamPosition; 206 } 207 208 /** 209 * Gets the next position within the event stream for retrieving subsequent events. 210 * 211 * <p>The value returned by this method corresponds to the <code>next_stream_position</code> field returned by the 212 * API's events endpoint.</p> 213 * 214 * @return the next position within the event stream. 215 */ 216 public String getNextStreamPosition() { 217 return this.nextStreamPosition; 218 } 219 220 /** 221 * Gets the number of events in this log, including duplicate events. 222 * 223 * <p>The chunk size may not be representative of the number of events returned by this EventLog's iterator because 224 * the iterator will automatically ignore duplicate events.</p> 225 * 226 * <p>The value returned by this method corresponds to the <code>chunk_size</code> field returned by the API's 227 * events endpoint.</p> 228 * 229 * @return the number of events, including duplicates. 230 */ 231 public int getChunkSize() { 232 return this.chunkSize; 233 } 234 235 /** 236 * Gets the number of events in this list, excluding duplicate events. 237 * 238 * <p>The size is guaranteed to be representative of the number of events returned by this EventLog's iterator.</p> 239 * 240 * @return the number of events, excluding duplicates. 241 */ 242 public int getSize() { 243 return this.set.size(); 244 } 245}