1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.metapath.impl;
7   
8   import gov.nist.secauto.metaschema.core.metapath.item.IItem;
9   import gov.nist.secauto.metaschema.core.util.ObjectUtils;
10  
11  import java.util.List;
12  import java.util.Objects;
13  import java.util.function.Consumer;
14  import java.util.stream.Collectors;
15  import java.util.stream.Stream;
16  
17  import edu.umd.cs.findbugs.annotations.NonNull;
18  
19  /**
20   * A Metapath sequence supporting an unbounded number of items backed initially
21   * by a stream.
22   *
23   * @param <ITEM>
24   *          the Java type of the items
25   */
26  public class StreamSequence<ITEM extends IItem>
27      extends AbstractSequence<ITEM> {
28  
29    private Stream<ITEM> stream;
30    private List<ITEM> list;
31  
32    /**
33     * Construct a new sequence using the provided item stream.
34     *
35     * @param stream
36     *          the items to add to the sequence
37     */
38    public StreamSequence(@NonNull Stream<ITEM> stream) {
39      Objects.requireNonNull(stream, "stream");
40      this.stream = stream;
41    }
42  
43    @Override
44    public List<ITEM> getValue() {
45      synchronized (this) {
46        if (list == null) {
47          list = stream().collect(Collectors.toUnmodifiableList());
48        }
49        assert list != null;
50        return list;
51      }
52    }
53  
54    @Override
55    public Stream<ITEM> stream() {
56      @NonNull Stream<ITEM> retval;
57      // Ensure thread safety and prevent multiple consumptions of the stream
58      synchronized (this) {
59        if (list == null) {
60          if (stream == null) {
61            throw new IllegalStateException("stream is already consumed");
62          }
63          assert stream != null;
64          retval = stream;
65          stream = null; // NOPMD - readability
66        } else {
67          retval = ObjectUtils.notNull(list.stream());
68        }
69      }
70      return retval;
71    }
72  
73    @Override
74    public void forEach(Consumer<? super ITEM> action) {
75      stream().forEachOrdered(action);
76    }
77  }