Java tutorial
/* * Copyright 2017-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.glowroot.ui; import java.util.Iterator; import java.util.List; import java.util.Map; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimaps; import com.google.common.collect.Ordering; import com.google.common.primitives.Longs; import org.immutables.value.Value; import org.glowroot.common2.repo.SyntheticResult.ErrorInterval; import org.glowroot.ui.MultiErrorIntervalCollector.MultiErrorInterval; class MultiErrorIntervalMerger { private final List<GroupedMultiErrorInterval> groupedMultiErrorIntervals = Lists.newArrayList(); public void addMultiErrorIntervals(String syntheticMonitorId, List<MultiErrorInterval> multiErrorIntervals) { for (MultiErrorInterval multiErrorInterval : multiErrorIntervals) { addMultiErrorInterval(syntheticMonitorId, multiErrorInterval); } } private void addMultiErrorInterval(String syntheticMonitorId, MultiErrorInterval multiErrorInterval) { List<GroupedMultiErrorInterval> overlapping = Lists.newArrayList(); for (Iterator<GroupedMultiErrorInterval> i = groupedMultiErrorIntervals.iterator(); i.hasNext();) { GroupedMultiErrorInterval groupedMultiErrorInterval = i.next(); if (isOverlapping(multiErrorInterval, groupedMultiErrorInterval)) { overlapping.add(groupedMultiErrorInterval); i.remove(); } } if (overlapping.isEmpty()) { groupedMultiErrorIntervals.add(ImmutableGroupedMultiErrorInterval.builder() .from(multiErrorInterval.from()).to(multiErrorInterval.to()) .putErrorIntervals(syntheticMonitorId, multiErrorInterval.errorIntervals()).build()); } else { groupedMultiErrorIntervals.removeAll(overlapping); groupedMultiErrorIntervals .add(mergeWithOverlapping(syntheticMonitorId, multiErrorInterval, overlapping)); } } public List<GroupedMultiErrorInterval> getGroupedMultiErrorIntervals() { return new GroupedMultiErrorIntervalOrdering().sortedCopy(groupedMultiErrorIntervals); } private static boolean isOverlapping(MultiErrorInterval multiErrorInterval, GroupedMultiErrorInterval groupedMultiErrorInterval) { return multiErrorInterval.from() <= groupedMultiErrorInterval.to() && groupedMultiErrorInterval.from() <= multiErrorInterval.to(); } private static GroupedMultiErrorInterval mergeWithOverlapping(String syntheticMonitorId, MultiErrorInterval multiErrorInterval, List<GroupedMultiErrorInterval> overlapping) { long minFrom = multiErrorInterval.from(); long maxTo = multiErrorInterval.to(); ListMultimap<String, ErrorInterval> errorIntervals = ArrayListMultimap.create(); errorIntervals.putAll(syntheticMonitorId, multiErrorInterval.errorIntervals()); for (GroupedMultiErrorInterval groupedMultiErrorInterval : overlapping) { minFrom = Math.min(minFrom, groupedMultiErrorInterval.from()); maxTo = Math.max(maxTo, groupedMultiErrorInterval.to()); for (Map.Entry<String, List<ErrorInterval>> entry : groupedMultiErrorInterval.errorIntervals() .entrySet()) { errorIntervals.putAll(entry.getKey(), entry.getValue()); } } return ImmutableGroupedMultiErrorInterval.builder().from(minFrom).to(maxTo) .putAllErrorIntervals(Multimaps.asMap(errorIntervals)).build(); } @Value.Immutable public interface GroupedMultiErrorInterval { long from(); long to(); Map<String, List<ErrorInterval>> errorIntervals(); // key is synetheticMonitorId } private static class GroupedMultiErrorIntervalOrdering extends Ordering<GroupedMultiErrorInterval> { @Override public int compare(GroupedMultiErrorInterval left, GroupedMultiErrorInterval right) { return Longs.compare(left.from(), right.from()); } } }