001/*- 002 * #%L 003 * HAPI FHIR - Core Library 004 * %% 005 * Copyright (C) 2014 - 2025 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.util; 021 022import jakarta.annotation.Nonnull; 023 024import java.util.ArrayList; 025import java.util.Collections; 026import java.util.List; 027import java.util.concurrent.atomic.AtomicBoolean; 028import java.util.stream.Stream; 029 030/** 031 * This class collects items from a stream to a given limit and know whether there are 032 * still more items beyond that limit. 033 * 034 * @param <T> the type of object being streamed 035 */ 036public class StopLimitAccumulator<T> { 037 private final boolean isTruncated; 038 private final List<T> myList; 039 040 private StopLimitAccumulator(List<T> theList, boolean theIsTruncated) { 041 myList = Collections.unmodifiableList(theList); 042 isTruncated = theIsTruncated; 043 } 044 045 public static <T> StopLimitAccumulator<T> fromStreamAndLimit(@Nonnull Stream<T> theItemStream, long theLimit) { 046 assert theLimit > 0; 047 AtomicBoolean isBeyondLimit = new AtomicBoolean(false); 048 List<T> accumulator = new ArrayList<>(); 049 050 theItemStream 051 .limit(theLimit + 1) // Fetch one extra item to see if there are any more items past our limit 052 .forEach(item -> { 053 if (accumulator.size() < theLimit) { 054 accumulator.add(item); 055 } else { 056 isBeyondLimit.set(true); 057 } 058 }); 059 return new StopLimitAccumulator<>(accumulator, isBeyondLimit.get()); 060 } 061 062 public boolean isTruncated() { 063 return isTruncated; 064 } 065 066 public List<T> getItemList() { 067 return myList; 068 } 069}