@Override
  public void serialize(Item item, JsonGenerator jgen, SerializerProvider provider)
      throws IOException, JsonProcessingException {
    jgen.writeStartArray();

    jgen.writeStartObject();
    jgen.writeStringField("id", "i_" + String.valueOf(item.getId()));
    jgen.writeObjectField("title", item.getName());
    jgen.writeObjectField("type", item.getType());

    String imagePath = "i_image_" + item.getId() + "." + item.getImage().getExtention();

    jgen.writeObjectFieldStart("image");
    jgen.writeObjectField("type", item.getImage().getType());
    jgen.writeObjectField("path", imagePath);
    jgen.writeEndObject();

    jgen.writeObjectFieldStart("values");
    jgen.writeStringField("productName", item.getName());
    jgen.writeStringField("imageFullPath", imagePath);
    for (Description description : item.getDescription()) {
      if (description.getDescription().size() > 1) {
        jgen.writeArrayFieldStart(description.getValue().getKey());
        for (String desc : description.getDescription()) jgen.writeString(desc);
        jgen.writeEndArray();
      } else
        jgen.writeStringField(
            description.getValue().getKey(),
            (description.getDescription().size() == 0) ? "" : description.getDescription().get(0));
    }
    jgen.writeEndObject();

    jgen.writeEndObject();
    jgen.writeEndArray();
  }
    @Override
    public void serialize(
        final GraphSONVertex directionalVertex,
        final JsonGenerator jsonGenerator,
        final SerializerProvider serializerProvider)
        throws IOException, JsonGenerationException {
      final Vertex vertex = directionalVertex.getVertexToSerialize();
      jsonGenerator.writeStartObject();
      jsonGenerator.writeObjectField(GraphSONTokens.ID, vertex.getId());
      jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertex.getLabel());
      jsonGenerator.writeStringField(GraphSONTokens.TYPE, GraphSONTokens.VERTEX);

      if (normalize) {
        jsonGenerator.writeObjectFieldStart(GraphSONTokens.PROPERTIES);
        vertex
            .getProperties()
            .values()
            .stream()
            .sorted(Comparators.PROPERTY_COMPARATOR)
            .forEachOrdered(
                FunctionUtils.wrapConsumer(
                    e -> jsonGenerator.writeObjectField(e.getKey(), e.get())));
        jsonGenerator.writeEndObject();
      } else {
        jsonGenerator.writeObjectFieldStart(GraphSONTokens.PROPERTIES);
        vertex
            .getProperties()
            .values()
            .forEach(
                FunctionUtils.wrapConsumer(
                    e -> jsonGenerator.writeObjectField(e.getKey(), e.get())));
        jsonGenerator.writeEndObject();
      }

      if (directionalVertex.getDirection() == Direction.BOTH
          || directionalVertex.getDirection() == Direction.OUT) {
        jsonGenerator.writeArrayFieldStart(GraphSONTokens.OUT);
        if (normalize)
          vertex
              .outE()
              .order(Comparators.HELD_EDGE_COMPARATOR)
              .forEach(FunctionUtils.wrapConsumer(jsonGenerator::writeObject));
        else vertex.outE().forEach(FunctionUtils.wrapConsumer(jsonGenerator::writeObject));
        jsonGenerator.writeEndArray();
      }

      if (directionalVertex.getDirection() == Direction.BOTH
          || directionalVertex.getDirection() == Direction.IN) {
        jsonGenerator.writeArrayFieldStart(GraphSONTokens.IN);
        if (normalize)
          vertex
              .inE()
              .order(Comparators.HELD_EDGE_COMPARATOR)
              .forEach(FunctionUtils.wrapConsumer(jsonGenerator::writeObject));
        else vertex.inE().forEach(FunctionUtils.wrapConsumer(jsonGenerator::writeObject));
        jsonGenerator.writeEndArray();
      }
      jsonGenerator.writeEndObject();
    }
  /**
   * "hotspots": [{
   *
   * <p>"id": "test_1",
   *
   * <p>"anchor": { "geolocation": { "lat": 52.3729, "lon": 4.93 } },
   *
   * <p>"text": { "title": "The Layar Office", "description": "The Location of the Layar Office",
   * "footnote": "Powered by Layar" },
   *
   * <p>"imageURL": "http:\/\/custom.layar.nl\/layarimage.jpeg", }
   *
   * <p>]
   *
   * <p>See http://layar.com/documentation/browser/api/getpois-response/hotspots/
   *
   * @param generator
   * @param hotspots2
   * @throws IOException
   * @throws JsonGenerationException
   */
  private void createHotspots(JsonGenerator generator) throws JsonGenerationException, IOException {
    generator.writeFieldName("hotspots");
    generator.writeStartArray();
    for (Hotspot poi : this.hotspots) {

      generator.writeStartObject();
      generator.writeStringField("id", poi.id);

      // generator.writeFieldName("actions");
      // generator.writeStartArray();
      // if (layarPOI.actions != null) {
      // for (final LayarAction layarAction : layarPOI.actions) {
      // layarAction.toJSON(generator);
      // }
      // }
      // generator.writeEndArray();

      generator.writeObjectFieldStart("anchor");
      generator.writeObjectFieldStart("geolocation");
      generator.writeNumberField("lat", poi.lat);
      generator.writeNumberField("lon", poi.lon);
      generator.writeNumberField("alt", poi.alt);
      generator.writeEndObject();
      generator.writeEndObject();

      // generator.writeNumberField("distance", layarPOI.distance);
      // generator.writeNumberField("type", layarPOI.type);
      // generator.writeStringField("title", layarPOI.title);
      generator.writeObjectFieldStart("text");
      generator.writeStringField("title", poi.title);
      generator.writeStringField("description", poi.description);
      generator.writeStringField("footnote", "Service URL: ...");
      generator.writeEndObject();

      generator.writeStringField("attribution", poi.attribution);
      if (poi.imageURL != null) {
        generator.writeStringField("imageURL", poi.imageURL.toString());
      } else {
        generator.writeNullField("imageURL");
      }
      generator.writeEndObject();
    }
    generator.writeEndArray();
  }
 private void _serialise(final HyperLogLogPlus hyperLogLogPlus, final JsonGenerator jsonGenerator)
     throws IOException {
   jsonGenerator.writeObjectFieldStart("hyperLogLogPlus");
   jsonGenerator.writeObjectField(
       HyperLogLogPlusJsonConstants.HYPER_LOG_LOG_PLUS_SKETCH_BYTES_FIELD,
       hyperLogLogPlus.getBytes());
   jsonGenerator.writeNumberField(
       HyperLogLogPlusJsonConstants.CARDINALITY_FIELD, hyperLogLogPlus.cardinality());
   jsonGenerator.writeEndObject();
 }
 private void addServiceData(JsonGenerator json, ServiceInstance localService) throws IOException {
   json.writeObjectFieldStart("origin");
   json.writeStringField("host", localService.getHost());
   json.writeNumberField("port", localService.getPort());
   json.writeStringField("serviceId", localService.getServiceId());
   if (this.properties.isSendId()) {
     json.writeStringField("id", this.context.getId());
   }
   json.writeEndObject();
 }
  @Override
  protected ModelAndView handleRequestInternal(
      final HttpServletRequest request, final HttpServletResponse response) throws Exception {
    String accessToken = request.getParameter(OAuthConstants.ACCESS_TOKEN);
    if (StringUtils.isBlank(accessToken)) {
      final String authHeader = request.getHeader("Authorization");
      if (StringUtils.isNotBlank(authHeader)
          && authHeader.toLowerCase().startsWith(OAuthConstants.BEARER_TOKEN.toLowerCase() + ' ')) {
        accessToken = authHeader.substring(OAuthConstants.BEARER_TOKEN.length() + 1);
      }
    }
    LOGGER.debug("{} : {}", OAuthConstants.ACCESS_TOKEN, accessToken);

    try (final JsonGenerator jsonGenerator =
        this.jsonFactory.createJsonGenerator(response.getWriter())) {
      response.setContentType("application/json");
      // accessToken is required
      if (StringUtils.isBlank(accessToken)) {
        LOGGER.error("Missing {}", OAuthConstants.ACCESS_TOKEN);
        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("error", OAuthConstants.MISSING_ACCESS_TOKEN);
        jsonGenerator.writeEndObject();
        return null;
      }
      // get ticket granting ticket
      final TicketGrantingTicket ticketGrantingTicket =
          (TicketGrantingTicket) this.ticketRegistry.getTicket(accessToken);
      if (ticketGrantingTicket == null || ticketGrantingTicket.isExpired()) {
        LOGGER.error("expired accessToken : {}", accessToken);
        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("error", OAuthConstants.EXPIRED_ACCESS_TOKEN);
        jsonGenerator.writeEndObject();
        return null;
      }
      // generate profile : identifier + attributes
      final Principal principal = ticketGrantingTicket.getAuthentication().getPrincipal();
      jsonGenerator.writeStartObject();
      jsonGenerator.writeStringField(ID, principal.getId());
      jsonGenerator.writeObjectFieldStart(ATTRIBUTES);
      final Map<String, Object> attributes = principal.getAttributes();
      for (final Map.Entry<String, Object> entry : attributes.entrySet()) {
        //                jsonGenerator.writeStartObject();
        jsonGenerator.writeObjectField(entry.getKey(), entry.getValue());
        //                jsonGenerator.writeEndObject();
      }
      //            jsonGenerator.writeEndArray();
      jsonGenerator.writeEndObject();
      return null;
    } finally {
      response.flushBuffer();
    }
  }
    @Override
    public void serialize(Record record, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonProcessingException {
      jgen.writeStartObject();
      jgen.writeStringField("id", record.getId());
      jgen.writeStringField("type", record.getType());
      jgen.writeStringField("creationDate", record.getTime().toString());

      jgen.writeObjectFieldStart("fields");
      for (Map.Entry<String, Field> entry : record.getFieldsEntrySet()) {
        // retrieve event field
        String fieldName = entry.getKey();
        Field field = entry.getValue();
        Object fieldValue = field.getRawValue();
        String fieldType = field.getType().toString();

        // dump event field as record attribute

        try {
          switch (fieldType.toLowerCase()) {
            case "string":
              jgen.writeStringField(fieldName, (String) fieldValue);
              break;
            case "integer":
              jgen.writeNumberField(fieldName, (int) fieldValue);
              break;
            case "long":
              jgen.writeNumberField(fieldName, (long) fieldValue);
              break;
            case "float":
              jgen.writeNumberField(fieldName, (float) fieldValue);
              break;
            case "double":
              jgen.writeNumberField(fieldName, (double) fieldValue);
              break;
            case "boolean":
              jgen.writeBooleanField(fieldName, (boolean) fieldValue);
              break;
            default:
              jgen.writeObjectField(fieldName, fieldValue);
              break;
          }
        } catch (Exception ex) {
          logger.debug("exception while serializing field {}", field);
        }
      }
      jgen.writeEndObject();
      jgen.writeEndObject();
    }
  @Test
  public void writeJSONViaLowerlevelLibs() throws IOException {
    final StringWriter writer = new StringWriter();

    final ObjectMapper mapper = new ObjectMapper();

    final JsonGenerator jgen = mapper.getFactory().createGenerator(writer);

    jgen.writeStartObject();

    jgen.writeStringField(
        "odata.type", "Microsoft.Test.OData.Services.AstoriaDefaultService.Customer");

    jgen.writeStringField("*****@*****.**", "Edm.String");
    jgen.writeStringField("Name", "A name");

    jgen.writeStringField("*****@*****.**", "Edm.Int32");
    jgen.writeNumberField("CustomerId", 0);

    jgen.writeArrayFieldStart("BackupContactInfo");

    jgen.writeStartObject();

    jgen.writeArrayFieldStart("AlternativeNames");
    jgen.writeString("myname");
    jgen.writeEndArray();

    jgen.writeArrayFieldStart("EmailBag");
    jgen.writeString("*****@*****.**");
    jgen.writeEndArray();

    jgen.writeObjectFieldStart("ContactAlias");
    jgen.writeStringField(
        "odata.type", "Microsoft.Test.OData.Services.AstoriaDefaultService.Aliases");
    jgen.writeArrayFieldStart("AlternativeNames");
    jgen.writeString("myAlternativeName");
    jgen.writeEndArray();
    jgen.writeEndObject();

    jgen.writeEndObject();

    jgen.writeEndArray();

    jgen.writeEndObject();

    jgen.flush();

    assertFalse(writer.toString().isEmpty());
  }
 @Override
 public void serialize(
     BulkIndexOperationHeader bulkIndexOperationHeader,
     JsonGenerator json,
     SerializerProvider provider)
     throws IOException {
   json.writeStartObject();
   json.writeObjectFieldStart("index");
   if (bulkIndexOperationHeader.index != null) {
     json.writeStringField("_index", bulkIndexOperationHeader.index);
   }
   if (bulkIndexOperationHeader.type != null) {
     json.writeStringField("_type", bulkIndexOperationHeader.type);
   }
   json.writeEndObject();
   json.writeEndObject();
 }
  private void writeActionDescriptors(
      JsonGenerator jgen, String currentVocab, List<ActionDescriptor> actionDescriptors)
      throws IOException, IntrospectionException {
    for (ActionDescriptor actionDescriptor : actionDescriptors) {
      jgen.writeStartObject(); // begin a hydra:Operation

      final String semanticActionType = actionDescriptor.getSemanticActionType();
      if (semanticActionType != null) {
        jgen.writeStringField("@type", semanticActionType);
      }
      jgen.writeStringField("hydra:method", actionDescriptor.getHttpMethod());

      final ActionInputParameter requestBodyInputParameter = actionDescriptor.getRequestBody();
      if (requestBodyInputParameter != null) {

        jgen.writeObjectFieldStart("hydra:expects"); // begin hydra:expects

        final Class<?> clazz = requestBodyInputParameter.getParameterType();
        final Expose classExpose = clazz.getAnnotation(Expose.class);
        final String typeName;
        if (classExpose != null) {
          typeName = classExpose.value();
        } else {
          typeName = requestBodyInputParameter.getParameterType().getSimpleName();
        }
        jgen.writeStringField("@type", typeName);

        jgen.writeArrayFieldStart("hydra:supportedProperty"); // begin hydra:supportedProperty
        // TODO check need for actionDescriptor and requestBodyInputParameter here:
        recurseSupportedProperties(
            jgen,
            currentVocab,
            clazz,
            actionDescriptor,
            requestBodyInputParameter,
            requestBodyInputParameter.getCallValue());
        jgen.writeEndArray(); // end hydra:supportedProperty

        jgen.writeEndObject(); // end hydra:expects
      }

      jgen.writeEndObject(); // end hydra:Operation
    }
  }
 @Override
 public void serialize(MatchResult value, JsonGenerator jgen, SerializerProvider provider)
     throws IOException, JsonProcessingException {
   jgen.writeStartObject();
   writeNumberField(jgen, "score", value.getScore());
   writeNumberField(jgen, "kills", value.getKills());
   if (value.getMatch() != null) {
     writeNumberField(jgen, "cdate", value.getMatch().getCdate().getTime());
     writeNumberField(jgen, "lives", value.getMatch().getLives());
     writeStringField(jgen, "state", value.getMatch().getState().name());
     writeBooleanField(jgen, "victory", value.getMatch().getVictory());
     if (value.getMatch().getMap() != null) {
       Map map = value.getMatch().getMap();
       jgen.writeObjectFieldStart("map");
       writeNumberField(jgen, "id", map.getId());
       writeStringField(jgen, "name", map.getName());
       writeNumberField(jgen, "lives", map.getLives());
       jgen.writeEndObject();
     }
   }
   jgen.writeEndObject();
 }
Exemple #12
0
  @Override
  public void toJson(JsonGenerator gen) throws IOException {
    gen.writeStartObject();

    // common tags
    gen.writeObjectFieldStart("tags");
    for (Tag tag : tags) {
      gen.writeStringField(
          ValidCharacters.toValidCharset(tag.getKey()),
          ValidCharacters.toValidCharset(tag.getValue()));
    }
    gen.writeEndObject();

    gen.writeArrayFieldStart("metrics");
    for (AtlasMetric m : metrics) {
      m.toJson(gen);
    }
    gen.writeEndArray();

    gen.writeEndObject();
    gen.flush();
  }
  @Override
  public String handleRequest(ExecutionJobVertex jobVertex, Map<String, String> params)
      throws Exception {
    // Build a map that groups tasks by TaskManager
    Map<String, List<ExecutionVertex>> taskManagerVertices = new HashMap<>();

    for (ExecutionVertex vertex : jobVertex.getTaskVertices()) {
      TaskManagerLocation location = vertex.getCurrentAssignedResourceLocation();
      String taskManager =
          location == null ? "(unassigned)" : location.getHostname() + ":" + location.dataPort();

      List<ExecutionVertex> vertices = taskManagerVertices.get(taskManager);

      if (vertices == null) {
        vertices = new ArrayList<ExecutionVertex>();
        taskManagerVertices.put(taskManager, vertices);
      }

      vertices.add(vertex);
    }

    // Build JSON response
    final long now = System.currentTimeMillis();

    StringWriter writer = new StringWriter();
    JsonGenerator gen = JsonFactory.jacksonFactory.createGenerator(writer);

    gen.writeStartObject();

    gen.writeStringField("id", jobVertex.getJobVertexId().toString());
    gen.writeStringField("name", jobVertex.getJobVertex().getName());
    gen.writeNumberField("now", now);

    gen.writeArrayFieldStart("taskmanagers");
    for (Entry<String, List<ExecutionVertex>> entry : taskManagerVertices.entrySet()) {
      String host = entry.getKey();
      List<ExecutionVertex> taskVertices = entry.getValue();

      int[] tasksPerState = new int[ExecutionState.values().length];

      long startTime = Long.MAX_VALUE;
      long endTime = 0;
      boolean allFinished = true;

      LongCounter tmReadBytes = new LongCounter();
      LongCounter tmWriteBytes = new LongCounter();
      LongCounter tmReadRecords = new LongCounter();
      LongCounter tmWriteRecords = new LongCounter();

      for (ExecutionVertex vertex : taskVertices) {
        final ExecutionState state = vertex.getExecutionState();
        tasksPerState[state.ordinal()]++;

        // take the earliest start time
        long started = vertex.getStateTimestamp(ExecutionState.DEPLOYING);
        if (started > 0) {
          startTime = Math.min(startTime, started);
        }

        allFinished &= state.isTerminal();
        endTime = Math.max(endTime, vertex.getStateTimestamp(state));

        Map<AccumulatorRegistry.Metric, Accumulator<?, ?>> metrics =
            vertex.getCurrentExecutionAttempt().getFlinkAccumulators();

        if (metrics != null) {
          LongCounter readBytes =
              (LongCounter) metrics.get(AccumulatorRegistry.Metric.NUM_BYTES_IN);
          tmReadBytes.merge(readBytes);

          LongCounter writeBytes =
              (LongCounter) metrics.get(AccumulatorRegistry.Metric.NUM_BYTES_OUT);
          tmWriteBytes.merge(writeBytes);

          LongCounter readRecords =
              (LongCounter) metrics.get(AccumulatorRegistry.Metric.NUM_RECORDS_IN);
          tmReadRecords.merge(readRecords);

          LongCounter writeRecords =
              (LongCounter) metrics.get(AccumulatorRegistry.Metric.NUM_RECORDS_OUT);
          tmWriteRecords.merge(writeRecords);
        }
      }

      long duration;
      if (startTime < Long.MAX_VALUE) {
        if (allFinished) {
          duration = endTime - startTime;
        } else {
          endTime = -1L;
          duration = now - startTime;
        }
      } else {
        startTime = -1L;
        endTime = -1L;
        duration = -1L;
      }

      ExecutionState jobVertexState =
          ExecutionJobVertex.getAggregateJobVertexState(tasksPerState, taskVertices.size());

      gen.writeStartObject();

      gen.writeStringField("host", host);
      gen.writeStringField("status", jobVertexState.name());

      gen.writeNumberField("start-time", startTime);
      gen.writeNumberField("end-time", endTime);
      gen.writeNumberField("duration", duration);

      gen.writeObjectFieldStart("metrics");
      gen.writeNumberField("read-bytes", tmReadBytes.getLocalValuePrimitive());
      gen.writeNumberField("write-bytes", tmWriteBytes.getLocalValuePrimitive());
      gen.writeNumberField("read-records", tmReadRecords.getLocalValuePrimitive());
      gen.writeNumberField("write-records", tmWriteRecords.getLocalValuePrimitive());
      gen.writeEndObject();

      gen.writeObjectFieldStart("status-counts");
      for (ExecutionState state : ExecutionState.values()) {
        gen.writeNumberField(state.name(), tasksPerState[state.ordinal()]);
      }
      gen.writeEndObject();

      gen.writeEndObject();
    }
    gen.writeEndArray();

    gen.writeEndObject();

    gen.close();
    return writer.toString();
  }
    private String getCollapserJson(final HystrixCollapserMetrics collapserMetrics)
        throws IOException {
      HystrixCollapserKey key = collapserMetrics.getCollapserKey();
      StringWriter jsonString = new StringWriter();
      JsonGenerator json = jsonFactory.createJsonGenerator(jsonString);
      json.writeStartObject();

      json.writeStringField("type", "HystrixCollapser");
      json.writeStringField("name", key.name());
      json.writeNumberField("currentTime", System.currentTimeMillis());

      safelyWriteNumberField(
          json,
          "rollingCountRequestsBatched",
          new Func0<Long>() {
            @Override
            public Long call() {
              return collapserMetrics.getRollingCount(HystrixEventType.Collapser.ADDED_TO_BATCH);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountBatches",
          new Func0<Long>() {
            @Override
            public Long call() {
              return collapserMetrics.getRollingCount(HystrixEventType.Collapser.BATCH_EXECUTED);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountResponsesFromCache",
          new Func0<Long>() {
            @Override
            public Long call() {
              return collapserMetrics.getRollingCount(
                  HystrixEventType.Collapser.RESPONSE_FROM_CACHE);
            }
          });

      // batch size percentiles
      json.writeNumberField("batchSize_mean", collapserMetrics.getBatchSizeMean());
      json.writeObjectFieldStart("batchSize");
      json.writeNumberField("25", collapserMetrics.getBatchSizePercentile(25));
      json.writeNumberField("50", collapserMetrics.getBatchSizePercentile(50));
      json.writeNumberField("75", collapserMetrics.getBatchSizePercentile(75));
      json.writeNumberField("90", collapserMetrics.getBatchSizePercentile(90));
      json.writeNumberField("95", collapserMetrics.getBatchSizePercentile(95));
      json.writeNumberField("99", collapserMetrics.getBatchSizePercentile(99));
      json.writeNumberField("99.5", collapserMetrics.getBatchSizePercentile(99.5));
      json.writeNumberField("100", collapserMetrics.getBatchSizePercentile(100));
      json.writeEndObject();

      // shard size percentiles (commented-out for now)
      // json.writeNumberField("shardSize_mean", collapserMetrics.getShardSizeMean());
      // json.writeObjectFieldStart("shardSize");
      // json.writeNumberField("25", collapserMetrics.getShardSizePercentile(25));
      // json.writeNumberField("50", collapserMetrics.getShardSizePercentile(50));
      // json.writeNumberField("75", collapserMetrics.getShardSizePercentile(75));
      // json.writeNumberField("90", collapserMetrics.getShardSizePercentile(90));
      // json.writeNumberField("95", collapserMetrics.getShardSizePercentile(95));
      // json.writeNumberField("99", collapserMetrics.getShardSizePercentile(99));
      // json.writeNumberField("99.5", collapserMetrics.getShardSizePercentile(99.5));
      // json.writeNumberField("100", collapserMetrics.getShardSizePercentile(100));
      // json.writeEndObject();

      // json.writeNumberField("propertyValue_metricsRollingStatisticalWindowInMilliseconds",
      // collapserMetrics.getProperties().metricsRollingStatisticalWindowInMilliseconds().get());
      json.writeBooleanField(
          "propertyValue_requestCacheEnabled",
          collapserMetrics.getProperties().requestCacheEnabled().get());
      json.writeNumberField(
          "propertyValue_maxRequestsInBatch",
          collapserMetrics.getProperties().maxRequestsInBatch().get());
      json.writeNumberField(
          "propertyValue_timerDelayInMilliseconds",
          collapserMetrics.getProperties().timerDelayInMilliseconds().get());

      json.writeNumberField(
          "reportingHosts", 1); // this will get summed across all instances in a cluster

      json.writeEndObject();
      json.close();

      return jsonString.getBuffer().toString();
    }
    private String getCommandJson(final HystrixCommandMetrics commandMetrics) throws IOException {
      HystrixCommandKey key = commandMetrics.getCommandKey();
      HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(key);

      StringWriter jsonString = new StringWriter();
      JsonGenerator json = jsonFactory.createGenerator(jsonString);

      json.writeStartObject();
      json.writeStringField("type", "HystrixCommand");
      json.writeStringField("name", key.name());
      json.writeStringField("group", commandMetrics.getCommandGroup().name());
      json.writeNumberField("currentTime", System.currentTimeMillis());

      // circuit breaker
      if (circuitBreaker == null) {
        // circuit breaker is disabled and thus never open
        json.writeBooleanField("isCircuitBreakerOpen", false);
      } else {
        json.writeBooleanField("isCircuitBreakerOpen", circuitBreaker.isOpen());
      }
      HealthCounts healthCounts = commandMetrics.getHealthCounts();
      json.writeNumberField("errorPercentage", healthCounts.getErrorPercentage());
      json.writeNumberField("errorCount", healthCounts.getErrorCount());
      json.writeNumberField("requestCount", healthCounts.getTotalRequests());

      // rolling counters
      safelyWriteNumberField(
          json,
          "rollingCountBadRequests",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.BAD_REQUEST);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountCollapsedRequests",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.COLLAPSED);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountEmit",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.EMIT);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountExceptionsThrown",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.EXCEPTION_THROWN);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountFailure",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.FAILURE);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountFallbackEmit",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_EMIT);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountFallbackFailure",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_FAILURE);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountFallbackMissing",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_MISSING);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountFallbackRejection",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_REJECTION);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountFallbackSuccess",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_SUCCESS);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountResponsesFromCache",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.RESPONSE_FROM_CACHE);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountSemaphoreRejected",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.SEMAPHORE_REJECTED);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountShortCircuited",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.SHORT_CIRCUITED);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountSuccess",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.SUCCESS);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountThreadPoolRejected",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.THREAD_POOL_REJECTED);
            }
          });
      safelyWriteNumberField(
          json,
          "rollingCountTimeout",
          new Func0<Long>() {
            @Override
            public Long call() {
              return commandMetrics.getRollingCount(HystrixEventType.TIMEOUT);
            }
          });

      json.writeNumberField(
          "currentConcurrentExecutionCount", commandMetrics.getCurrentConcurrentExecutionCount());
      json.writeNumberField(
          "rollingMaxConcurrentExecutionCount", commandMetrics.getRollingMaxConcurrentExecutions());

      // latency percentiles
      json.writeNumberField("latencyExecute_mean", commandMetrics.getExecutionTimeMean());
      json.writeObjectFieldStart("latencyExecute");
      json.writeNumberField("0", commandMetrics.getExecutionTimePercentile(0));
      json.writeNumberField("25", commandMetrics.getExecutionTimePercentile(25));
      json.writeNumberField("50", commandMetrics.getExecutionTimePercentile(50));
      json.writeNumberField("75", commandMetrics.getExecutionTimePercentile(75));
      json.writeNumberField("90", commandMetrics.getExecutionTimePercentile(90));
      json.writeNumberField("95", commandMetrics.getExecutionTimePercentile(95));
      json.writeNumberField("99", commandMetrics.getExecutionTimePercentile(99));
      json.writeNumberField("99.5", commandMetrics.getExecutionTimePercentile(99.5));
      json.writeNumberField("100", commandMetrics.getExecutionTimePercentile(100));
      json.writeEndObject();
      //
      json.writeNumberField("latencyTotal_mean", commandMetrics.getTotalTimeMean());
      json.writeObjectFieldStart("latencyTotal");
      json.writeNumberField("0", commandMetrics.getTotalTimePercentile(0));
      json.writeNumberField("25", commandMetrics.getTotalTimePercentile(25));
      json.writeNumberField("50", commandMetrics.getTotalTimePercentile(50));
      json.writeNumberField("75", commandMetrics.getTotalTimePercentile(75));
      json.writeNumberField("90", commandMetrics.getTotalTimePercentile(90));
      json.writeNumberField("95", commandMetrics.getTotalTimePercentile(95));
      json.writeNumberField("99", commandMetrics.getTotalTimePercentile(99));
      json.writeNumberField("99.5", commandMetrics.getTotalTimePercentile(99.5));
      json.writeNumberField("100", commandMetrics.getTotalTimePercentile(100));
      json.writeEndObject();

      // property values for reporting what is actually seen by the command rather than what was set
      // somewhere
      HystrixCommandProperties commandProperties = commandMetrics.getProperties();

      json.writeNumberField(
          "propertyValue_circuitBreakerRequestVolumeThreshold",
          commandProperties.circuitBreakerRequestVolumeThreshold().get());
      json.writeNumberField(
          "propertyValue_circuitBreakerSleepWindowInMilliseconds",
          commandProperties.circuitBreakerSleepWindowInMilliseconds().get());
      json.writeNumberField(
          "propertyValue_circuitBreakerErrorThresholdPercentage",
          commandProperties.circuitBreakerErrorThresholdPercentage().get());
      json.writeBooleanField(
          "propertyValue_circuitBreakerForceOpen",
          commandProperties.circuitBreakerForceOpen().get());
      json.writeBooleanField(
          "propertyValue_circuitBreakerForceClosed",
          commandProperties.circuitBreakerForceClosed().get());
      json.writeBooleanField(
          "propertyValue_circuitBreakerEnabled", commandProperties.circuitBreakerEnabled().get());

      json.writeStringField(
          "propertyValue_executionIsolationStrategy",
          commandProperties.executionIsolationStrategy().get().name());
      json.writeNumberField(
          "propertyValue_executionIsolationThreadTimeoutInMilliseconds",
          commandProperties.executionTimeoutInMilliseconds().get());
      json.writeNumberField(
          "propertyValue_executionTimeoutInMilliseconds",
          commandProperties.executionTimeoutInMilliseconds().get());
      json.writeBooleanField(
          "propertyValue_executionIsolationThreadInterruptOnTimeout",
          commandProperties.executionIsolationThreadInterruptOnTimeout().get());
      json.writeStringField(
          "propertyValue_executionIsolationThreadPoolKeyOverride",
          commandProperties.executionIsolationThreadPoolKeyOverride().get());
      json.writeNumberField(
          "propertyValue_executionIsolationSemaphoreMaxConcurrentRequests",
          commandProperties.executionIsolationSemaphoreMaxConcurrentRequests().get());
      json.writeNumberField(
          "propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests",
          commandProperties.fallbackIsolationSemaphoreMaxConcurrentRequests().get());

      /*
       * The following are commented out as these rarely change and are verbose for streaming for something people don't change.
       * We could perhaps allow a property or request argument to include these.
       */

      //                    json.put("propertyValue_metricsRollingPercentileEnabled",
      // commandProperties.metricsRollingPercentileEnabled().get());
      //                    json.put("propertyValue_metricsRollingPercentileBucketSize",
      // commandProperties.metricsRollingPercentileBucketSize().get());
      //                    json.put("propertyValue_metricsRollingPercentileWindow",
      // commandProperties.metricsRollingPercentileWindowInMilliseconds().get());
      //                    json.put("propertyValue_metricsRollingPercentileWindowBuckets",
      // commandProperties.metricsRollingPercentileWindowBuckets().get());
      //                    json.put("propertyValue_metricsRollingStatisticalWindowBuckets",
      // commandProperties.metricsRollingStatisticalWindowBuckets().get());
      json.writeNumberField(
          "propertyValue_metricsRollingStatisticalWindowInMilliseconds",
          commandProperties.metricsRollingStatisticalWindowInMilliseconds().get());

      json.writeBooleanField(
          "propertyValue_requestCacheEnabled", commandProperties.requestCacheEnabled().get());
      json.writeBooleanField(
          "propertyValue_requestLogEnabled", commandProperties.requestLogEnabled().get());

      json.writeNumberField(
          "reportingHosts", 1); // this will get summed across all instances in a cluster
      json.writeStringField("threadPool", commandMetrics.getThreadPoolKey().name());

      json.writeEndObject();
      json.close();

      return jsonString.getBuffer().toString();
    }
  @Override
  public void serialize(CyNetworkView networkView, JsonGenerator jgen, SerializerProvider provider)
      throws IOException, JsonProcessingException {
    jgen.useDefaultPrettyPrinter();

    jgen.writeStartObject();
    jgen.writeStringField(
        CytoscapeJsNetworkModule.FORMAT_VERSION_TAG, CytoscapeJsNetworkModule.FORMAT_VERSION);
    jgen.writeStringField(CytoscapeJsNetworkModule.GENERATED_BY_TAG, "cytoscape-" + version);
    jgen.writeStringField(
        CytoscapeJsNetworkModule.TARGET_CYJS_VERSION_TAG,
        CytoscapeJsNetworkModule.CYTOSCAPEJS_VERSION);

    final CyNetwork network = networkView.getModel();

    // Serialize network data table
    jgen.writeObjectFieldStart(DATA.getTag());
    jgen.writeObject(network.getRow(network));
    jgen.writeEndObject();

    jgen.writeObjectFieldStart(ELEMENTS.getTag());

    // Write array
    final List<CyNode> nodes = network.getNodeList();
    final List<CyEdge> edges = network.getEdgeList();

    jgen.writeArrayFieldStart(NODES.getTag());
    for (final CyNode node : nodes) {
      jgen.writeStartObject();

      // Data field
      jgen.writeObjectFieldStart(DATA.getTag());
      jgen.writeStringField(ID.getTag(), node.getSUID().toString());
      // Write CyRow in "data" field
      jgen.writeObject(network.getRow(node));
      jgen.writeEndObject();

      // Position and other visual props
      jgen.writeObject(networkView.getNodeView(node));

      // Special case for cytoscape.js format:
      // - Selected
      jgen.writeBooleanField(
          CyNetwork.SELECTED, network.getRow(node).get(CyNetwork.SELECTED, Boolean.class));

      jgen.writeEndObject();
    }
    jgen.writeEndArray();

    jgen.writeArrayFieldStart(EDGES.getTag());
    for (final CyEdge edge : edges) {
      jgen.writeStartObject();

      jgen.writeObjectFieldStart(DATA.getTag());
      jgen.writeStringField(ID.getTag(), edge.getSUID().toString());
      jgen.writeStringField(SOURCE.getTag(), edge.getSource().getSUID().toString());
      jgen.writeStringField(TARGET.getTag(), edge.getTarget().getSUID().toString());

      // Write CyRow in "data" field
      jgen.writeObject(network.getRow(edge));

      jgen.writeEndObject();

      // Special case for cytoscape.js format:
      // - Selected
      jgen.writeBooleanField(
          CyNetwork.SELECTED, network.getRow(edge).get(CyNetwork.SELECTED, Boolean.class));

      jgen.writeEndObject();
    }
    jgen.writeEndArray();

    jgen.writeEndObject();
  }
  @Scheduled(fixedRateString = "${hystrix.stream.amqp.gatherRate:500}")
  public void gatherMetrics() {
    try {
      // command metrics
      Collection<HystrixCommandMetrics> instances = HystrixCommandMetrics.getInstances();
      if (!instances.isEmpty()) {
        log.trace("gathering metrics size: " + instances.size());
      }

      ServiceInstance localService = this.discoveryClient.getLocalServiceInstance();

      for (HystrixCommandMetrics commandMetrics : instances) {
        HystrixCommandKey key = commandMetrics.getCommandKey();
        HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(key);

        StringWriter jsonString = new StringWriter();
        JsonGenerator json = this.jsonFactory.createGenerator(jsonString);

        json.writeStartObject();

        addServiceData(json, localService);
        json.writeObjectFieldStart("data");
        json.writeStringField("type", "HystrixCommand");
        String name = key.name();

        if (this.properties.isPrefixMetricName()) {
          name = localService.getServiceId() + "." + name;
        }

        json.writeStringField("name", name);
        json.writeStringField("group", commandMetrics.getCommandGroup().name());
        json.writeNumberField("currentTime", System.currentTimeMillis());

        // circuit breaker
        if (circuitBreaker == null) {
          // circuit breaker is disabled and thus never open
          json.writeBooleanField("isCircuitBreakerOpen", false);
        } else {
          json.writeBooleanField("isCircuitBreakerOpen", circuitBreaker.isOpen());
        }
        HystrixCommandMetrics.HealthCounts healthCounts = commandMetrics.getHealthCounts();
        json.writeNumberField("errorPercentage", healthCounts.getErrorPercentage());
        json.writeNumberField("errorCount", healthCounts.getErrorCount());
        json.writeNumberField("requestCount", healthCounts.getTotalRequests());

        // rolling counters
        json.writeNumberField(
            "rollingCountCollapsedRequests",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.COLLAPSED));
        json.writeNumberField(
            "rollingCountExceptionsThrown",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN));
        json.writeNumberField(
            "rollingCountFailure",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.FAILURE));
        json.writeNumberField(
            "rollingCountFallbackFailure",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE));
        json.writeNumberField(
            "rollingCountFallbackRejection",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION));
        json.writeNumberField(
            "rollingCountFallbackSuccess",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS));
        json.writeNumberField(
            "rollingCountResponsesFromCache",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE));
        json.writeNumberField(
            "rollingCountSemaphoreRejected",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED));
        json.writeNumberField(
            "rollingCountShortCircuited",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED));
        json.writeNumberField(
            "rollingCountSuccess",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS));
        json.writeNumberField(
            "rollingCountThreadPoolRejected",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED));
        json.writeNumberField(
            "rollingCountTimeout",
            commandMetrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT));

        json.writeNumberField(
            "currentConcurrentExecutionCount", commandMetrics.getCurrentConcurrentExecutionCount());

        // latency percentiles
        json.writeNumberField("latencyExecute_mean", commandMetrics.getExecutionTimeMean());
        json.writeObjectFieldStart("latencyExecute");
        json.writeNumberField("0", commandMetrics.getExecutionTimePercentile(0));
        json.writeNumberField("25", commandMetrics.getExecutionTimePercentile(25));
        json.writeNumberField("50", commandMetrics.getExecutionTimePercentile(50));
        json.writeNumberField("75", commandMetrics.getExecutionTimePercentile(75));
        json.writeNumberField("90", commandMetrics.getExecutionTimePercentile(90));
        json.writeNumberField("95", commandMetrics.getExecutionTimePercentile(95));
        json.writeNumberField("99", commandMetrics.getExecutionTimePercentile(99));
        json.writeNumberField("99.5", commandMetrics.getExecutionTimePercentile(99.5));
        json.writeNumberField("100", commandMetrics.getExecutionTimePercentile(100));
        json.writeEndObject();
        //
        json.writeNumberField("latencyTotal_mean", commandMetrics.getTotalTimeMean());
        json.writeObjectFieldStart("latencyTotal");
        json.writeNumberField("0", commandMetrics.getTotalTimePercentile(0));
        json.writeNumberField("25", commandMetrics.getTotalTimePercentile(25));
        json.writeNumberField("50", commandMetrics.getTotalTimePercentile(50));
        json.writeNumberField("75", commandMetrics.getTotalTimePercentile(75));
        json.writeNumberField("90", commandMetrics.getTotalTimePercentile(90));
        json.writeNumberField("95", commandMetrics.getTotalTimePercentile(95));
        json.writeNumberField("99", commandMetrics.getTotalTimePercentile(99));
        json.writeNumberField("99.5", commandMetrics.getTotalTimePercentile(99.5));
        json.writeNumberField("100", commandMetrics.getTotalTimePercentile(100));
        json.writeEndObject();

        // property values for reporting what is actually seen by the command
        // rather than what was set somewhere
        HystrixCommandProperties commandProperties = commandMetrics.getProperties();

        json.writeNumberField(
            "propertyValue_circuitBreakerRequestVolumeThreshold",
            commandProperties.circuitBreakerRequestVolumeThreshold().get());
        json.writeNumberField(
            "propertyValue_circuitBreakerSleepWindowInMilliseconds",
            commandProperties.circuitBreakerSleepWindowInMilliseconds().get());
        json.writeNumberField(
            "propertyValue_circuitBreakerErrorThresholdPercentage",
            commandProperties.circuitBreakerErrorThresholdPercentage().get());
        json.writeBooleanField(
            "propertyValue_circuitBreakerForceOpen",
            commandProperties.circuitBreakerForceOpen().get());
        json.writeBooleanField(
            "propertyValue_circuitBreakerForceClosed",
            commandProperties.circuitBreakerForceClosed().get());
        json.writeBooleanField(
            "propertyValue_circuitBreakerEnabled", commandProperties.circuitBreakerEnabled().get());

        json.writeStringField(
            "propertyValue_executionIsolationStrategy",
            commandProperties.executionIsolationStrategy().get().name());
        json.writeNumberField(
            "propertyValue_executionIsolationThreadTimeoutInMilliseconds",
            commandProperties.executionIsolationThreadTimeoutInMilliseconds().get());
        json.writeBooleanField(
            "propertyValue_executionIsolationThreadInterruptOnTimeout",
            commandProperties.executionIsolationThreadInterruptOnTimeout().get());
        json.writeStringField(
            "propertyValue_executionIsolationThreadPoolKeyOverride",
            commandProperties.executionIsolationThreadPoolKeyOverride().get());
        json.writeNumberField(
            "propertyValue_executionIsolationSemaphoreMaxConcurrentRequests",
            commandProperties.executionIsolationSemaphoreMaxConcurrentRequests().get());
        json.writeNumberField(
            "propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests",
            commandProperties.fallbackIsolationSemaphoreMaxConcurrentRequests().get());

        // TODO
        /*
         * The following are commented out as these rarely change and are verbose
         * for streaming for something people don't change. We could perhaps allow
         * a property or request argument to include these.
         */

        // json.put("propertyValue_metricsRollingPercentileEnabled",
        // commandProperties.metricsRollingPercentileEnabled().get());
        // json.put("propertyValue_metricsRollingPercentileBucketSize",
        // commandProperties.metricsRollingPercentileBucketSize().get());
        // json.put("propertyValue_metricsRollingPercentileWindow",
        // commandProperties.metricsRollingPercentileWindowInMilliseconds().get());
        // json.put("propertyValue_metricsRollingPercentileWindowBuckets",
        // commandProperties.metricsRollingPercentileWindowBuckets().get());
        // json.put("propertyValue_metricsRollingStatisticalWindowBuckets",
        // commandProperties.metricsRollingStatisticalWindowBuckets().get());
        json.writeNumberField(
            "propertyValue_metricsRollingStatisticalWindowInMilliseconds",
            commandProperties.metricsRollingStatisticalWindowInMilliseconds().get());

        json.writeBooleanField(
            "propertyValue_requestCacheEnabled", commandProperties.requestCacheEnabled().get());
        json.writeBooleanField(
            "propertyValue_requestLogEnabled", commandProperties.requestLogEnabled().get());

        json.writeNumberField("reportingHosts", 1); // this will get summed across
        // all instances in a cluster

        json.writeEndObject(); // end data attribute
        json.writeEndObject();
        json.close();

        // output
        this.jsonMetrics.add(jsonString.getBuffer().toString());
      }

      // thread pool metrics
      for (HystrixThreadPoolMetrics threadPoolMetrics : HystrixThreadPoolMetrics.getInstances()) {
        HystrixThreadPoolKey key = threadPoolMetrics.getThreadPoolKey();

        StringWriter jsonString = new StringWriter();
        JsonGenerator json = this.jsonFactory.createGenerator(jsonString);
        json.writeStartObject();

        addServiceData(json, localService);
        json.writeObjectFieldStart("data");

        json.writeStringField("type", "HystrixThreadPool");
        json.writeStringField("name", key.name());
        json.writeNumberField("currentTime", System.currentTimeMillis());

        json.writeNumberField(
            "currentActiveCount", threadPoolMetrics.getCurrentActiveCount().intValue());
        json.writeNumberField(
            "currentCompletedTaskCount",
            threadPoolMetrics.getCurrentCompletedTaskCount().longValue());
        json.writeNumberField(
            "currentCorePoolSize", threadPoolMetrics.getCurrentCorePoolSize().intValue());
        json.writeNumberField(
            "currentLargestPoolSize", threadPoolMetrics.getCurrentLargestPoolSize().intValue());
        json.writeNumberField(
            "currentMaximumPoolSize", threadPoolMetrics.getCurrentMaximumPoolSize().intValue());
        json.writeNumberField("currentPoolSize", threadPoolMetrics.getCurrentPoolSize().intValue());
        json.writeNumberField(
            "currentQueueSize", threadPoolMetrics.getCurrentQueueSize().intValue());
        json.writeNumberField(
            "currentTaskCount", threadPoolMetrics.getCurrentTaskCount().longValue());
        json.writeNumberField(
            "rollingCountThreadsExecuted", threadPoolMetrics.getRollingCountThreadsExecuted());
        json.writeNumberField(
            "rollingMaxActiveThreads", threadPoolMetrics.getRollingMaxActiveThreads());

        json.writeNumberField(
            "propertyValue_queueSizeRejectionThreshold",
            threadPoolMetrics.getProperties().queueSizeRejectionThreshold().get());
        json.writeNumberField(
            "propertyValue_metricsRollingStatisticalWindowInMilliseconds",
            threadPoolMetrics
                .getProperties()
                .metricsRollingStatisticalWindowInMilliseconds()
                .get());

        json.writeNumberField("reportingHosts", 1); // this will get summed across
        // all instances in a cluster

        json.writeEndObject(); // end of data object
        json.writeEndObject();
        json.close();
        // output to stream
        this.jsonMetrics.add(jsonString.getBuffer().toString());
      }
    } catch (Exception ex) {
      log.error("Error adding metrics to queue", ex);
    }
  }
  private void recurseSupportedProperties(
      JsonGenerator jgen,
      String currentVocab,
      Class<?> beanType,
      ActionDescriptor actionDescriptor,
      ActionInputParameter actionInputParameter,
      Object currentCallValue)
      throws IntrospectionException, IOException {
    // TODO support Option provider by other method args?
    final BeanInfo beanInfo = Introspector.getBeanInfo(beanType);
    final PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
    // TODO collection and map

    for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
      final Method writeMethod = propertyDescriptor.getWriteMethod();
      if (writeMethod == null) {
        continue;
      }
      final Class<?> propertyType = propertyDescriptor.getPropertyType();
      // TODO: the property name must be a valid URI - need to check context for terms?
      String propertyName = getWritableExposedPropertyOrPropertyName(propertyDescriptor);
      if (DataType.isSingleValueType(propertyType)) {

        final Property property =
            new Property(
                beanType,
                propertyDescriptor.getReadMethod(),
                propertyDescriptor.getWriteMethod(),
                propertyDescriptor.getName());

        Object propertyValue = PropertyUtils.getPropertyValue(currentCallValue, propertyDescriptor);

        MethodParameter methodParameter =
            new MethodParameter(propertyDescriptor.getWriteMethod(), 0);
        ActionInputParameter propertySetterInputParameter =
            new ActionInputParameter(methodParameter, propertyValue);
        final Object[] possiblePropertyValues =
            actionInputParameter.getPossibleValues(
                propertyDescriptor.getWriteMethod(), 0, actionDescriptor);

        writeSupportedProperty(
            jgen,
            currentVocab,
            propertySetterInputParameter,
            propertyName,
            property,
            possiblePropertyValues);
      } else {
        jgen.writeStartObject();
        jgen.writeStringField("hydra:property", propertyName);
        // TODO: is the property required -> for bean props we need the Access annotation to express
        // that
        jgen.writeObjectFieldStart(
            getPropertyOrClassNameInVocab(
                currentVocab, "rangeIncludes", LdContextFactory.HTTP_SCHEMA_ORG, "schema:"));
        Expose expose = AnnotationUtils.getAnnotation(propertyType, Expose.class);
        String subClass;
        if (expose != null) {
          subClass = expose.value();
        } else {
          subClass = propertyType.getSimpleName();
        }
        jgen.writeStringField(
            getPropertyOrClassNameInVocab(
                currentVocab, "subClassOf", "http://www.w3.org/2000/01/rdf-schema#", "rdfs:"),
            subClass);

        jgen.writeArrayFieldStart("hydra:supportedProperty");

        Object propertyValue = PropertyUtils.getPropertyValue(currentCallValue, propertyDescriptor);

        recurseSupportedProperties(
            jgen,
            currentVocab,
            propertyType,
            actionDescriptor,
            actionInputParameter,
            propertyValue);
        jgen.writeEndArray();

        jgen.writeEndObject();
        jgen.writeEndObject();
      }
    }
  }
  @Override
  public void serialize(List<Link> links, JsonGenerator jgen, SerializerProvider serializerProvider)
      throws IOException {

    try {
      Collection<Link> simpleLinks = new ArrayList<Link>();
      Collection<Affordance> affordances = new ArrayList<Affordance>();
      Collection<Link> templatedLinks = new ArrayList<Link>();
      Collection<Affordance> templatedAffordances = new ArrayList<Affordance>();
      Collection<Affordance> collectionAffordances = new ArrayList<Affordance>();
      Link selfRel = null;
      for (Link link : links) {
        if (link instanceof Affordance) {
          final Affordance affordance = (Affordance) link;
          final List<ActionDescriptor> actionDescriptors = affordance.getActionDescriptors();
          if (!actionDescriptors.isEmpty()) {
            if (affordance.isTemplated()) {
              templatedAffordances.add(affordance);
            } else {
              if (!affordance.isSelfRel()
                  && Cardinality.COLLECTION == affordance.getCardinality()) {
                collectionAffordances.add(affordance);
              } else {
                affordances.add(affordance);
              }
            }
          } else {
            if (affordance.isTemplated()) {
              templatedLinks.add(affordance);
            } else {
              simpleLinks.add(affordance);
            }
          }
        } else if (link.isTemplated()) {
          templatedLinks.add(link);
        } else {
          simpleLinks.add(link);
        }
        if ("self".equals(link.getRel())) {
          selfRel = link;
        }
      }

      for (Affordance templatedAffordance : templatedAffordances) {
        jgen.writeObjectFieldStart(templatedAffordance.getRel());

        jgen.writeStringField("@type", "hydra:IriTemplate");
        jgen.writeStringField("hydra:template", templatedAffordance.getHref());
        final List<ActionDescriptor> actionDescriptors = templatedAffordance.getActionDescriptors();
        ActionDescriptor actionDescriptor = actionDescriptors.get(0);
        jgen.writeArrayFieldStart("hydra:mapping");
        writeHydraVariableMapping(jgen, actionDescriptor, actionDescriptor.getPathVariableNames());
        writeHydraVariableMapping(jgen, actionDescriptor, actionDescriptor.getRequestParamNames());
        jgen.writeEndArray();

        jgen.writeEndObject();
      }
      for (Link templatedLink : templatedLinks) {
        // we only have the template, no access to method params
        jgen.writeObjectFieldStart(templatedLink.getRel());

        jgen.writeStringField("@type", "hydra:IriTemplate");
        jgen.writeStringField("hydra:template", templatedLink.getHref());

        jgen.writeArrayFieldStart("hydra:mapping");
        writeHydraVariableMapping(jgen, null, templatedLink.getVariableNames());
        jgen.writeEndArray();

        jgen.writeEndObject();
      }

      @SuppressWarnings("unchecked")
      Deque<LdContext> contextStack =
          (Deque<LdContext>) serializerProvider.getAttribute(JacksonHydraSerializer.KEY_LD_CONTEXT);
      String currentVocab =
          (contextStack != null && !contextStack.isEmpty()) ? contextStack.peek().vocab : null;

      // related collections
      if (!collectionAffordances.isEmpty()) {
        jgen.writeArrayFieldStart("hydra:collection");

        for (Affordance collectionAffordance : collectionAffordances) {
          jgen.writeStartObject();
          jgen.writeStringField(JsonLdKeywords.AT_TYPE, "hydra:Collection");
          jgen.writeStringField(JsonLdKeywords.AT_ID, collectionAffordance.getHref());
          jgen.writeObjectFieldStart("hydra:manages");
          jgen.writeStringField("hydra:property", collectionAffordance.getRel());
          // a) in the case of </Alice> :knows /bob the subject must be /Alice
          // b) in the case of <> orderedItem /latte-1 the subject is an anonymous resource of type
          // Order
          // c) in the case of </order/1> :seller </store> the object must be the store
          // 1. where is the information *about* the subject or object: the type or @id
          // 2. how to decide if the collection manages items for a subject or object?
          // ad 1.)
          // ad a) self rel of the Resource that has the collection affordance: looking through link
          // list
          //       at serialization time is possible
          // ad b) a candidate is the class given as value of @ExposesResourceFor on the controller
          //       that defines the method which leads us to believe we have a collection:
          //       either a GET /orders handler having a collection return type or the POST /orders.
          //       Works only if the GET or POST has no request mapping path of its own
          //       an alternative is to use {} without type if @ExposesResourceFor is not present
          // ad c) like a
          // ad 2.)
          // we know the affordance is a collection
          // * we could pass information into build(rel), like
          // .rel().reverseRel("schema:seller").build()
          // * we could use build("myReversedTerm") and look at the @context to see if it is
          // reversed,
          //   if so, we know that the manages block must use object not subject. However weird if
          // the
          //   reverse term is never really used in the json-ld
          // * we could have a registry which says if a property is meant to be reversed in a
          // certain context
          //   and use that to find out if we need subject or object, like :seller ->
          if (selfRel != null) {
            // prefer rev over rel, assuming that rev exists to be used by RDF serialization
            if (collectionAffordance.getRev() != null) {
              jgen.writeStringField("hydra:object", selfRel.getHref());
            } else if (collectionAffordance.getRel() != null) {
              jgen.writeStringField("hydra:subject", selfRel.getHref());
            }
          } else {
            // prefer rev over rel, assuming that rev exists to be used by RDF serialization
            if (collectionAffordance.getRev() != null) {
              jgen.writeObjectFieldStart("hydra:object");
              jgen.writeEndObject();
            } else if (collectionAffordance.getRel() != null) {
              jgen.writeObjectFieldStart("hydra:subject");
              jgen.writeEndObject();
            }
          }
          jgen.writeEndObject(); // end manages

          List<ActionDescriptor> actionDescriptors = collectionAffordance.getActionDescriptors();
          if (!actionDescriptors.isEmpty()) {
            jgen.writeArrayFieldStart("hydra:operation");
          }
          writeActionDescriptors(jgen, currentVocab, actionDescriptors);
          if (!actionDescriptors.isEmpty()) {
            jgen.writeEndArray(); // end hydra:operation
          }

          jgen.writeEndObject(); // end collection
        }
        jgen.writeEndArray();
      }

      for (Affordance affordance : affordances) {
        final String rel = affordance.getRel();
        List<ActionDescriptor> actionDescriptors = affordance.getActionDescriptors();

        if (!actionDescriptors.isEmpty()) {
          if (!Link.REL_SELF.equals(rel)) {
            jgen.writeObjectFieldStart(rel); // begin rel
          }
          jgen.writeStringField(JsonLdKeywords.AT_ID, affordance.getHref());
          jgen.writeArrayFieldStart("hydra:operation");
        }

        writeActionDescriptors(jgen, currentVocab, actionDescriptors);

        if (!actionDescriptors.isEmpty()) {
          jgen.writeEndArray(); // end hydra:operation

          if (!Link.REL_SELF.equals(rel)) {
            jgen.writeEndObject(); // end rel
          }
        }
      }

      for (Link simpleLink : simpleLinks) {
        final String rel = simpleLink.getRel();
        if (Link.REL_SELF.equals(rel)) {
          jgen.writeStringField("@id", simpleLink.getHref());
        } else {
          String linkAttributeName = IanaRels.isIanaRel(rel) ? IANA_REL_PREFIX + rel : rel;
          jgen.writeObjectFieldStart(linkAttributeName);
          jgen.writeStringField("@id", simpleLink.getHref());
          jgen.writeEndObject();
        }
      }
    } catch (IntrospectionException e) {
      throw new RuntimeException(e);
    }
  }