Example #1
0
  /**
   * Builds a map from collection name to a list of event maps, given a map from collection name to
   * a list of event handles. This method just uses the event store to retrieve each event by its
   * handle.
   *
   * @param eventHandles A map from collection name to a list of event handles in the event store.
   * @return A map from collection name to a list of event maps.
   * @throws IOException If there is an error retrieving events from the store.
   */
  private Map<String, List<Map<String, Object>>> buildEventMap(
      Map<String, List<Object>> eventHandles) throws IOException {
    Map<String, List<Map<String, Object>>> result =
        new HashMap<String, List<Map<String, Object>>>();
    for (Map.Entry<String, List<Object>> entry : eventHandles.entrySet()) {
      String eventCollection = entry.getKey();
      List<Object> handles = entry.getValue();

      // Skip event collections that don't contain any events.
      if (handles == null || handles.size() == 0) {
        continue;
      }

      // Build the event list by retrieving events from the store.
      List<Map<String, Object>> events = new ArrayList<Map<String, Object>>(handles.size());
      for (Object handle : handles) {
        // Get the event from the store.
        String jsonEvent = eventStore.get(handle);

        // De-serialize the event from its JSON.
        StringReader reader = new StringReader(jsonEvent);
        Map<String, Object> event = jsonHandler.readJson(reader);
        KeenUtils.closeQuietly(reader);
        events.add(event);
      }
      result.put(eventCollection, events);
    }
    return result;
  }
Example #2
0
  /**
   * 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);
    }
  }
Example #3
0
  /**
   * Handles a response from the Keen service to a batch post events operation. In particular, this
   * method will iterate through the responses and remove any successfully processed events (or
   * events which failed for known fatal reasons) from the event store so they won't be sent in
   * subsequent posts.
   *
   * @param handles A map from collection names to lists of handles in the event store. This is
   *     referenced against the response from the server to determine which events to remove from
   *     the store.
   * @param response The response from the server.
   * @throws IOException If there is an error removing events from the store.
   */
  @SuppressWarnings("unchecked")
  private void handleAddEventsResponse(Map<String, List<Object>> handles, String response)
      throws IOException {
    // Parse the response into a map.
    StringReader reader = new StringReader(response);
    Map<String, Object> responseMap;
    responseMap = jsonHandler.readJson(reader);

    // It's not obvious what the best way is to try and recover from them, but just hoping it
    // doesn't happen is probably the wrong answer.

    // Loop through all the event collections.
    for (Map.Entry<String, Object> entry : responseMap.entrySet()) {
      String collectionName = entry.getKey();

      // Get the list of handles in this collection.
      List<Object> collectionHandles = handles.get(collectionName);

      // Iterate through the elements in the collection
      List<Map<String, Object>> eventResults = (List<Map<String, Object>>) entry.getValue();
      int index = 0;
      for (Map<String, Object> eventResult : eventResults) {
        // now loop through each event collection's individual results
        boolean removeCacheEntry = true;
        boolean success = (Boolean) eventResult.get(KeenConstants.SUCCESS_PARAM);
        if (!success) {
          // grab error code and description
          Map errorDict = (Map) eventResult.get(KeenConstants.ERROR_PARAM);
          String errorCode = (String) errorDict.get(KeenConstants.NAME_PARAM);
          if (errorCode.equals(KeenConstants.INVALID_COLLECTION_NAME_ERROR)
              || errorCode.equals(KeenConstants.INVALID_PROPERTY_NAME_ERROR)
              || errorCode.equals(KeenConstants.INVALID_PROPERTY_VALUE_ERROR)) {
            removeCacheEntry = true;
            KeenLogging.log(
                "An invalid event was found. Deleting it. Error: "
                    + errorDict.get(KeenConstants.DESCRIPTION_PARAM));
          } else {
            String description = (String) errorDict.get(KeenConstants.DESCRIPTION_PARAM);
            removeCacheEntry = false;
            KeenLogging.log(
                String.format(
                    Locale.US,
                    "The event could not be inserted for some reason. "
                        + "Error name and description: %s %s",
                    errorCode,
                    description));
          }
        }

        // If the cache entry should be removed, get the handle at the appropriate index
        // and ask the event store to remove it.
        if (removeCacheEntry) {
          Object handle = collectionHandles.get(index);
          // Try to remove the object from the cache. Catch and log exceptions to prevent
          // a single failure from derailing the rest of the cleanup.
          try {
            eventStore.remove(handle);
          } catch (IOException e) {
            KeenLogging.log("Failed to remove object '" + handle + "' from cache");
          }
        }
        index++;
      }
    }
  }