/** * Synchronously sends all queued events for the given project. This method will immediately * publish the events to the Keen server in the current thread. * * @param project The project for which to send queued events. If a default project has been set * on the client this parameter may be null, in which case the default project will be used. * @param callback An optional callback to receive notification of success or failure. */ public synchronized void sendQueuedEvents(KeenProject project, KeenCallback callback) { if (!isActive) { handleLibraryInactive(callback); return; } if (project == null && defaultProject == null) { handleFailure( null, new IllegalStateException("No project specified, but no default project found")); return; } KeenProject useProject = (project == null ? defaultProject : project); try { String projectId = useProject.getProjectId(); Map<String, List<Object>> eventHandles = eventStore.getHandles(projectId); Map<String, List<Map<String, Object>>> events = buildEventMap(eventHandles); String response = publishAll(useProject, events); if (response != null) { try { handleAddEventsResponse(eventHandles, response); } catch (Exception e) { // Errors handling the response are non-fatal; just log them. KeenLogging.log("Error handling response to batch publish: " + e.getMessage()); } } handleSuccess(callback); } catch (Exception e) { handleFailure(callback, e); } }
/** * Publishes a batch of events to the Keen service. * * @param project The project in which to publish the event. * @param events A map from collection name to a list of event maps. * @return The response from the server. * @throws IOException If there was an error communicating with the server. */ private String publishAll(KeenProject project, Map<String, List<Map<String, Object>>> events) throws IOException { // just using basic JDK HTTP library String urlString = String.format( Locale.US, "%s/%s/projects/%s/events", getBaseUrl(), KeenConstants.API_VERSION, project.getProjectId()); URL url = new URL(urlString); return publishObject(project, url, events); }
/** * Posts a request to the server in the specified project, using the given URL and request data. * The request data will be serialized into JSON using the client's {@link * io.keen.client.java.KeenJsonHandler}. * * @param project The project in which the event(s) will be published; this is used to determine * the write key to use for authentication. * @param url The URL to which the POST should be sent. * @param requestData The request data, which will be serialized into JSON and sent in the request * body. * @return The response from the server. * @throws IOException If there was an error communicating with the server. */ private synchronized String publishObject( KeenProject project, URL url, final Map<String, ?> requestData) throws IOException { if (requestData == null || requestData.size() == 0) { KeenLogging.log("No API calls were made because there were no events to upload"); return null; } // Build an output source which simply writes the serialized JSON to the output. OutputSource source = new OutputSource() { @Override public void writeTo(OutputStream out) throws IOException { OutputStreamWriter writer = new OutputStreamWriter(out, ENCODING); jsonHandler.writeJson(writer, requestData); } }; // If logging is enabled, log the request being sent. if (KeenLogging.isLoggingEnabled()) { try { StringWriter writer = new StringWriter(); jsonHandler.writeJson(writer, requestData); String request = writer.toString(); KeenLogging.log( String.format(Locale.US, "Sent request '%s' to URL '%s'", request, url.toString())); } catch (IOException e) { KeenLogging.log("Couldn't log event written to file: "); e.printStackTrace(); } } // Send the request. String writeKey = project.getWriteKey(); Request request = new Request(url, "POST", writeKey, source); Response response = httpHandler.execute(request); // If logging is enabled, log the response. if (KeenLogging.isLoggingEnabled()) { KeenLogging.log( String.format( Locale.US, "Received response: '%s' (%d)", response.body, response.statusCode)); } // If the request succeeded, return the response body. Otherwise throw an exception. if (response.isSuccess()) { return response.body; } else { throw new ServerException(response.body); } }
/** * Synchronously queues an event for publishing. The event will be cached in the client's {@link * io.keen.client.java.KeenEventStore} until the next call to either {@link #sendQueuedEvents()} * or {@link #sendQueuedEventsAsync()}. * * @param project The project in which to publish the event. If a default project has been set on * the client this parameter may be null, in which case the default project will be used. * @param eventCollection The name of the collection in which to publish the event. * @param event A Map that consists of key/value pairs. Keen naming conventions apply (see docs). * Nested Maps and lists are acceptable (and encouraged!). * @param keenProperties A Map that consists of key/value pairs to override default properties. * ex: "timestamp" -> Calendar.getInstance() * @param callback An optional callback to receive notification of success or failure. */ public void queueEvent( KeenProject project, String eventCollection, Map<String, Object> event, Map<String, Object> keenProperties, final KeenCallback callback) { if (!isActive) { handleLibraryInactive(callback); return; } if (project == null && defaultProject == null) { handleFailure( null, new IllegalStateException("No project specified, but no default project found")); return; } KeenProject useProject = (project == null ? defaultProject : project); try { // Build the event Map<String, Object> newEvent = validateAndBuildEvent(useProject, eventCollection, event, keenProperties); // Serialize the event into JSON. StringWriter writer = new StringWriter(); jsonHandler.writeJson(writer, newEvent); String jsonEvent = writer.toString(); KeenUtils.closeQuietly(writer); // Save the JSON event out to the event store. eventStore.store(useProject.getProjectId(), eventCollection, jsonEvent); handleSuccess(callback); } catch (Exception e) { handleFailure(callback, e); } }
/** * Validates an event and inserts global properties, producing a new event object which is ready * to be published to the Keen service. * * @param project The project in which the event will be published. * @param eventCollection The name of the collection in which the event will be published. * @param event A Map that consists of key/value pairs. * @param keenProperties A Map that consists of key/value pairs to override default properties. * @return A new event Map containing Keen properties and global properties. */ protected Map<String, Object> validateAndBuildEvent( KeenProject project, String eventCollection, Map<String, Object> event, Map<String, Object> keenProperties) { if (project.getWriteKey() == null) { throw new NoWriteKeyException( "You can't send events to Keen IO if you haven't set a write key."); } validateEventCollection(eventCollection); validateEvent(event); KeenLogging.log(String.format(Locale.US, "Adding event to collection: %s", eventCollection)); // build the event Map<String, Object> newEvent = new HashMap<String, Object>(); // handle keen properties Calendar currentTime = Calendar.getInstance(); String timestamp = ISO_8601_FORMAT.format(currentTime.getTime()); if (keenProperties == null) { keenProperties = new HashMap<String, Object>(); keenProperties.put("timestamp", timestamp); } else { if (!keenProperties.containsKey("timestamp")) { keenProperties.put("timestamp", timestamp); } } newEvent.put("keen", keenProperties); // handle global properties Map<String, Object> globalProperties = getGlobalProperties(); if (globalProperties != null) { newEvent.putAll(globalProperties); } GlobalPropertiesEvaluator globalPropertiesEvaluator = getGlobalPropertiesEvaluator(); if (globalPropertiesEvaluator != null) { Map<String, Object> props = globalPropertiesEvaluator.getGlobalProperties(eventCollection); if (props != null) { newEvent.putAll(props); } } // now handle user-defined properties newEvent.putAll(event); return newEvent; }