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. 053 * @param api the API connection to use. 054 * @param after the lower bound on the timestamp of the events returned. 055 * @param before the upper bound on the timestamp of the events returned. 056 * @param types an optional list of event types to filter by. 057 * @return a log of all the events that met the given criteria. 058 */ 059 public static EventLog getEnterpriseEvents(BoxAPIConnection api, Date after, Date before, BoxEvent.Type... types) { 060 return getEnterpriseEvents(api, null, after, before, types); 061 } 062 063 /** 064 * Gets all the enterprise events that occurred within a specified date range, starting from a given position 065 * within the event stream. 066 * @param api the API connection to use. 067 * @param position the starting position of the event stream. 068 * @param after the lower bound on the timestamp of the events returned. 069 * @param before the upper bound on the timestamp of the events returned. 070 * @param types an optional list of event types to filter by. 071 * @return a log of all the events that met the given criteria. 072 */ 073 public static EventLog getEnterpriseEvents(BoxAPIConnection api, String position, Date after, Date before, 074 BoxEvent.Type... types) { 075 076 URL url = ENTERPRISE_EVENT_URL_TEMPLATE.build(api.getBaseURL()); 077 078 if (position != null || types.length > 0 || after != null 079 || before != null) { 080 QueryStringBuilder queryBuilder = new QueryStringBuilder(url.getQuery()); 081 082 if (after != null) { 083 queryBuilder.appendParam("created_after", 084 BoxDateFormat.format(after)); 085 } 086 087 if (before != null) { 088 queryBuilder.appendParam("created_before", 089 BoxDateFormat.format(before)); 090 } 091 092 if (position != null) { 093 queryBuilder.appendParam("stream_position", position); 094 } 095 096 if (types.length > 0) { 097 StringBuilder filterBuilder = new StringBuilder(); 098 for (BoxEvent.Type filterType : types) { 099 filterBuilder.append(filterType.name()); 100 filterBuilder.append(','); 101 } 102 filterBuilder.deleteCharAt(filterBuilder.length() - 1); 103 queryBuilder.appendParam("event_type", filterBuilder.toString()); 104 } 105 106 try { 107 url = queryBuilder.addToURL(url); 108 } catch (MalformedURLException e) { 109 throw new BoxAPIException("Couldn't append a query string to the provided URL."); 110 } 111 } 112 113 BoxAPIRequest request = new BoxAPIRequest(api, url, "GET"); 114 BoxJSONResponse response = (BoxJSONResponse) request.send(); 115 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 116 EventLog log = new EventLog(api, responseJSON, position, ENTERPRISE_LIMIT); 117 log.setStartDate(after); 118 log.setEndDate(before); 119 return log; 120 } 121 122 void setStartDate(Date startDate) { 123 this.startDate = startDate; 124 } 125 126 void setEndDate(Date endDate) { 127 this.endDate = endDate; 128 } 129 130 /** 131 * Returns an iterator over the events in this log. 132 * @return an iterator over the events in this log. 133 */ 134 @Override 135 public Iterator<BoxEvent> iterator() { 136 return this.set.iterator(); 137 } 138 139 /** 140 * Gets the date of the earliest event in this log. 141 * 142 * <p>The value returned by this method corresponds to the <code>created_after</code> URL parameter that was used 143 * when retrieving the events in this EventLog.</p> 144 * 145 * @return the date of the earliest event in this log. 146 */ 147 public Date getStartDate() { 148 return this.startDate; 149 } 150 151 /** 152 * Gets the date of the latest event in this log. 153 * 154 * <p>The value returned by this method corresponds to the <code>created_before</code> URL parameter that was used 155 * when retrieving the events in this EventLog.</p> 156 * 157 * @return the date of the latest event in this log. 158 */ 159 public Date getEndDate() { 160 return this.endDate; 161 } 162 163 /** 164 * Gets the maximum number of events that this event log could contain given its start date, end date, and stream 165 * position. 166 * 167 * <p>The value returned by this method corresponds to the <code>limit</code> URL parameter that was used when 168 * retrieving the events in this EventLog.</p> 169 * 170 * @return the maximum number of events. 171 */ 172 public int getLimit() { 173 return this.limit; 174 } 175 176 /** 177 * Gets the starting position of the events in this log within the event stream. 178 * 179 * <p>The value returned by this method corresponds to the <code>stream_position</code> URL parameter that was used 180 * when retrieving the events in this EventLog.</p> 181 * 182 * @return the starting position within the event stream. 183 */ 184 public String getStreamPosition() { 185 return this.streamPosition; 186 } 187 188 /** 189 * Gets the next position within the event stream for retrieving subsequent events. 190 * 191 * <p>The value returned by this method corresponds to the <code>next_stream_position</code> field returned by the 192 * API's events endpoint.</p> 193 * 194 * @return the next position within the event stream. 195 */ 196 public String getNextStreamPosition() { 197 return this.nextStreamPosition; 198 } 199 200 /** 201 * Gets the number of events in this log, including duplicate events. 202 * 203 * <p>The chunk size may not be representative of the number of events returned by this EventLog's iterator because 204 * the iterator will automatically ignore duplicate events.</p> 205 * 206 * <p>The value returned by this method corresponds to the <code>chunk_size</code> field returned by the API's 207 * events endpoint.</p> 208 * 209 * @return the number of events, including duplicates. 210 */ 211 public int getChunkSize() { 212 return this.chunkSize; 213 } 214 215 /** 216 * Gets the number of events in this list, excluding duplicate events. 217 * 218 * <p>The size is guaranteed to be representative of the number of events returned by this EventLog's iterator.</p> 219 * 220 * @return the number of events, excluding duplicates. 221 */ 222 public int getSize() { 223 return this.set.size(); 224 } 225}