@Override
    public SegmentResult next(SegmentContext ctx) {
        long n = now.next(null);
        final String serviceName = ctx.serviceName;
        final String serviceInstanceName = ctx.serviceInstanceName;
        final String endpointName = getEndpointName().next(null);
        if (segmentId == null) {
            StringGenerator.Builder segmentIdBuilder = new StringGenerator.Builder();
            segmentIdBuilder.setLength(20);
            segmentIdBuilder.setNumbers(true);
            segmentIdBuilder.setLetters(true);
            segmentId = segmentIdBuilder.build();
        }

        final SegmentReference sr = Optional.ofNullable(ctx.parentSegment).flatMap(parentSegment -> parentSegment.segmentObject.getSpansList().stream()
                        .filter(span -> !Strings.isNullOrEmpty(span.getPeer()))
                        .findFirst().map(span -> SegmentReference
                                .newBuilder()
                                .setTraceId(ctx.traceId)
                                .setParentServiceInstance(parentSegment.segmentObject.getServiceInstance())
                                .setParentService(parentSegment.segmentObject.getService())
                                .setParentSpanId(span.getSpanId())
                                .setParentTraceSegmentId(parentSegment.segment.getSegmentId())
                                .setParentEndpoint(IDManager.EndpointID.analysisId(parentSegment.segment.getEndpointId()).getEndpointName())
                                .setNetworkAddressUsedAtPeer(serviceInstanceName)
                                .build()))
                .orElse(null);
        final String segmentId = getSegmentId().next(null);

        final List<SpanGenerator> spanGenerators = getSpans().next(null);
        int size = spanGenerators.size();
        final SegmentObject segmentObj = SegmentObject
                .newBuilder()
                .setTraceId(ctx.traceId)
                .setTraceSegmentId(segmentId)
                .addAllSpans(
                        IntStream.range(0, size)
                                .mapToObj(i -> {
                                    SpanGenerator sg = spanGenerators.get(i);
                                    return sg.next(new SpanGenerator.SpanGeneratorContext(i, size, sr, ctx.peer, n));
                                })
                                .collect(Collectors.<SpanObject>toList()))
                .setService(serviceName)
                .setServiceInstance(serviceInstanceName)
                .build();

        // Reset the span generator to generate the span id from 0
        getSpans().reset();

        Long latency = segmentObj.getSpansList().stream().reduce(0L, (l, span) -> l + (span.getEndTime() - span.getStartTime()), Long::sum);

        final Segment segment = new Segment();
        segment.setSegmentId(segmentId);
        segment.setTraceId(ctx.traceId);
        segment.setServiceId(
                IDManager.ServiceID.buildId(serviceName, true));
        segment.setServiceInstanceId(
                IDManager.ServiceInstanceID.buildId(
                        segment.getServiceId(),
                        serviceInstanceName));
        segment.setEndpointId(
                IDManager.EndpointID.buildId(
                        segment.getServiceId(),
                        endpointName));
        segment.setStartTime(n - latency);
        segment.setLatency(latency.intValue());
        segment.setIsError(getError().next(null).intValue());
        segment.setTimeBucket(TimeBucket.getRecordTimeBucket(segment.getStartTime()));
        segment.setTags(
                getTags()
                        .next(null)
                        .stream()
                        .map(tg -> tg.next(null))
                        .collect(Collectors.<Tag>toList()));

        return new SegmentResult(segment, segmentObj);
    }
@Test
    void next() throws URISyntaxException, IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        URL url = getClass().getClassLoader().getResource("segment.tpl.json");
        assertNotNull(url);
        File jsonFile = new File(url.toURI());
        SegmentRequest sr = objectMapper.readValue(jsonFile, SegmentRequest.class);
        sr.init("");
        Set<String> serviceSet = new HashSet<>();
        Set<String> serviceInstanceSet = new HashSet<>();
        Set<String> endpointSet = new HashSet<>();
        for (int i = 0; i < 1000; i++) {
            List<SegmentGenerator.SegmentResult> ss = sr.next(null);
            assertFalse(ss.isEmpty());
            for (SegmentGenerator.SegmentResult s : ss) {
                serviceSet.add(s.segmentObject.getService());
                serviceInstanceSet.add(s.segmentObject.getServiceInstance());
                endpointSet.add(s.segment.getEndpointId());
            }
        }
        assertTrue(serviceSet.size() > 1);
        assertTrue(serviceSet.size() <= 10);
        assertTrue(serviceInstanceSet.size() > 1);
        assertTrue(serviceInstanceSet.size() <= 100);
        assertTrue(endpointSet.size() > 1);
        assertTrue(endpointSet.size() <= 100);
    }