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