001package com.box.sdk; 002 003import java.net.MalformedURLException; 004import java.net.URL; 005import java.util.Date; 006import java.util.HashSet; 007import java.util.Iterator; 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 + "&created_after=%s&created_before=%s"); 025 026 private final int chunkSize; 027 private final int limit; 028 private final long nextStreamPosition; 029 private final long streamPosition; 030 private final Set<BoxEvent> set; 031 032 private Date startDate; 033 private Date endDate; 034 035 EventLog(BoxAPIConnection api, JsonObject json, long streamPosition, int limit) { 036 this.streamPosition = streamPosition; 037 this.limit = limit; 038 this.nextStreamPosition = Long.parseLong(json.get("next_stream_position").asString()); 039 this.chunkSize = json.get("chunk_size").asInt(); 040 041 this.set = new HashSet<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, 0, 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, long position, Date after, Date before, 071 BoxEvent.Type... types) { 072 073 String afterString = BoxDateFormat.format(after); 074 String beforeString = BoxDateFormat.format(before); 075 URL url = ENTERPRISE_EVENT_URL_TEMPLATE.build(api.getBaseURL(), afterString, beforeString); 076 077 if (position != 0 || types.length > 0) { 078 QueryStringBuilder queryBuilder = new QueryStringBuilder(url.getQuery()); 079 080 if (position != 0) { 081 queryBuilder.appendParam("stream_position", position); 082 } 083 084 StringBuilder filterBuilder = new StringBuilder(); 085 for (BoxEvent.Type filterType : types) { 086 filterBuilder.append(filterType.name()); 087 filterBuilder.append(','); 088 } 089 filterBuilder.deleteCharAt(filterBuilder.length() - 1); 090 queryBuilder.appendParam("event_type", filterBuilder.toString()); 091 092 try { 093 url = queryBuilder.addToURL(url); 094 } catch (MalformedURLException e) { 095 throw new BoxAPIException("Couldn't append a query string to the provided URL."); 096 } 097 } 098 099 BoxAPIRequest request = new BoxAPIRequest(api, url, "GET"); 100 BoxJSONResponse response = (BoxJSONResponse) request.send(); 101 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 102 EventLog log = new EventLog(api, responseJSON, position, ENTERPRISE_LIMIT); 103 log.setStartDate(after); 104 log.setEndDate(before); 105 return log; 106 } 107 108 void setStartDate(Date startDate) { 109 this.startDate = startDate; 110 } 111 112 void setEndDate(Date endDate) { 113 this.endDate = endDate; 114 } 115 116 /** 117 * Returns an iterator over the events in this log. 118 * @return an iterator over the events in this log. 119 */ 120 @Override 121 public Iterator<BoxEvent> iterator() { 122 return this.set.iterator(); 123 } 124 125 /** 126 * Gets the date of the earliest event in this log. 127 * 128 * <p>The value returned by this method corresponds to the <code>created_after</code> URL parameter that was used 129 * when retrieving the events in this EventLog.</p> 130 * 131 * @return the date of the earliest event in this log. 132 */ 133 public Date getStartDate() { 134 return this.startDate; 135 } 136 137 /** 138 * Gets the date of the latest event in this log. 139 * 140 * <p>The value returned by this method corresponds to the <code>created_before</code> URL parameter that was used 141 * when retrieving the events in this EventLog.</p> 142 * 143 * @return the date of the latest event in this log. 144 */ 145 public Date getEndDate() { 146 return this.endDate; 147 } 148 149 /** 150 * Gets the maximum number of events that this event log could contain given its start date, end date, and stream 151 * position. 152 * 153 * <p>The value returned by this method corresponds to the <code>limit</code> URL parameter that was used when 154 * retrieving the events in this EventLog.</p> 155 * 156 * @return the maximum number of events. 157 */ 158 public int getLimit() { 159 return this.limit; 160 } 161 162 /** 163 * Gets the starting position of the events in this log within the event stream. 164 * 165 * <p>The value returned by this method corresponds to the <code>stream_position</code> URL parameter that was used 166 * when retrieving the events in this EventLog.</p> 167 * 168 * @return the starting position within the event stream. 169 */ 170 public long getStreamPosition() { 171 return this.streamPosition; 172 } 173 174 /** 175 * Gets the next position within the event stream for retrieving subsequent events. 176 * 177 * <p>The value returned by this method corresponds to the <code>next_stream_position</code> field returned by the 178 * API's events endpoint.</p> 179 * 180 * @return the next position within the event stream. 181 */ 182 public long getNextStreamPosition() { 183 return this.nextStreamPosition; 184 } 185 186 /** 187 * Gets the number of events in this log, including duplicate events. 188 * 189 * <p>The chunk size may not be representative of the number of events returned by this EventLog's iterator because 190 * the iterator will automatically ignore duplicate events.</p> 191 * 192 * <p>The value returned by this method corresponds to the <code>chunk_size</code> field returned by the API's 193 * events endpoint.</p> 194 * 195 * @return the number of events, including duplicates. 196 */ 197 public int getChunkSize() { 198 return this.chunkSize; 199 } 200 201 /** 202 * Gets the number of events in this list, excluding duplicate events. 203 * 204 * <p>The size is guaranteed to be representative of the number of events returned by this EventLog's iterator.</p> 205 * 206 * @return the number of events, excluding duplicates. 207 */ 208 public int getSize() { 209 return this.set.size(); 210 } 211}