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