1 /* Contributed in the public domain.
2 * Licensed to CS GROUP (CS) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * CS licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.orekit.utils;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.stream.Stream;
24
25 import org.hipparchus.exception.LocalizedCoreFormats;
26 import org.orekit.errors.OrekitException;
27 import org.orekit.errors.OrekitIllegalArgumentException;
28 import org.orekit.errors.OrekitIllegalStateException;
29 import org.orekit.errors.OrekitMessages;
30 import org.orekit.errors.TimeStampedCacheException;
31 import org.orekit.time.AbsoluteDate;
32 import org.orekit.time.ChronologicalComparator;
33 import org.orekit.time.TimeStamped;
34
35 /**
36 * A cache of {@link TimeStamped} data that provides concurrency through
37 * immutability. This strategy is suitable when all of the cached data is stored
38 * in memory. (For example, {@link org.orekit.time.UTCScale UTCScale}) This
39 * class then provides convenient methods for accessing the data.
40 *
41 * @author Evan Ward
42 * @param <T> the type of data
43 */
44 public class ImmutableTimeStampedCache<T extends TimeStamped>
45 implements TimeStampedCache<T> {
46
47 /**
48 * An empty immutable cache that always throws an exception on attempted
49 * access.
50 */
51 @SuppressWarnings("rawtypes")
52 private static final ImmutableTimeStampedCache EMPTY_CACHE =
53 new EmptyTimeStampedCache<>();
54
55 /**
56 * the cached data. Be careful not to modify it after the constructor, or
57 * return a reference that allows mutating this list.
58 */
59 private final List<T> data;
60
61 /**
62 * the maximum size list to return from {@link #getNeighbors(AbsoluteDate, int)}.
63 * @since 12.0
64 */
65 private final int maxNeighborsSize;
66
67 /**
68 * Create a new cache with the given neighbors size and data.
69 *
70 * @param maxNeighborsSize the maximum size of the list returned from
71 * {@link #getNeighbors(AbsoluteDate, int)}. Must be less than or equal to
72 * {@code data.size()}.
73 * @param data the backing data for this cache. The list will be copied to
74 * ensure immutability. To guarantee immutability the entries in
75 * {@code data} must be immutable themselves. There must be more data
76 * than {@code maxNeighborsSize}.
77 * @throws IllegalArgumentException if {@code neightborsSize > data.size()}
78 * or if {@code neighborsSize} is negative
79 */
80 public ImmutableTimeStampedCache(final int maxNeighborsSize,
81 final Collection<? extends T> data) {
82 // parameter check
83 if (maxNeighborsSize > data.size()) {
84 throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_CACHED_NEIGHBORS,
85 data.size(), maxNeighborsSize);
86 }
87 if (maxNeighborsSize < 1) {
88 throw new OrekitIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL,
89 maxNeighborsSize, 1);
90 }
91
92 // assign instance variables
93 this.maxNeighborsSize = maxNeighborsSize;
94 // sort and copy data first
95 this.data = new ArrayList<>(data);
96 this.data.sort(new ChronologicalComparator());
97
98 }
99
100 /**
101 * private constructor for {@link #EMPTY_CACHE}.
102 */
103 private ImmutableTimeStampedCache() {
104 this.data = null;
105 this.maxNeighborsSize = 0;
106 }
107
108 /** {@inheritDoc} */
109 public Stream<T> getNeighbors(final AbsoluteDate central, final int n) {
110 if (n > maxNeighborsSize) {
111 throw new OrekitException(OrekitMessages.NOT_ENOUGH_DATA, maxNeighborsSize);
112 }
113 return new SortedListTrimmer(n).getNeighborsSubList(central, data).stream();
114 }
115
116 /** {@inheritDoc} */
117 public int getMaxNeighborsSize() {
118 return maxNeighborsSize;
119 }
120
121 /** {@inheritDoc} */
122 public T getEarliest() {
123 return this.data.get(0);
124 }
125
126 /** {@inheritDoc} */
127 public T getLatest() {
128 return this.data.get(this.data.size() - 1);
129 }
130
131 /**
132 * Get all of the data in this cache.
133 *
134 * @return a sorted collection of all data passed in the
135 * {@link #ImmutableTimeStampedCache(int, Collection) constructor}.
136 */
137 public List<T> getAll() {
138 return Collections.unmodifiableList(this.data);
139 }
140
141 /** {@inheritDoc} */
142 @Override
143 public String toString() {
144 return "Immutable cache with " + this.data.size() + " entries";
145 }
146
147 /**
148 * An empty immutable cache that always throws an exception on attempted
149 * access.
150 */
151 private static class EmptyTimeStampedCache<T extends TimeStamped> extends ImmutableTimeStampedCache<T> {
152
153 /** {@inheritDoc} */
154 @Override
155 public Stream<T> getNeighbors(final AbsoluteDate central) {
156 throw new TimeStampedCacheException(OrekitMessages.NO_CACHED_ENTRIES);
157 }
158
159 /** {@inheritDoc} */
160 @Override
161 public int getMaxNeighborsSize() {
162 return 0;
163 }
164
165 /** {@inheritDoc} */
166 @Override
167 public T getEarliest() {
168 throw new OrekitIllegalStateException(OrekitMessages.NO_CACHED_ENTRIES);
169 }
170
171 /** {@inheritDoc} */
172 @Override
173 public T getLatest() {
174 throw new OrekitIllegalStateException(OrekitMessages.NO_CACHED_ENTRIES);
175 }
176
177 /** {@inheritDoc} */
178 @Override
179 public List<T> getAll() {
180 return Collections.emptyList();
181 }
182
183 /** {@inheritDoc} */
184 @Override
185 public String toString() {
186 return "Empty immutable cache";
187 }
188
189 }
190
191 /**
192 * Get an empty immutable cache, cast to the correct type.
193 * @param <TS> the type of data
194 * @return an empty {@link ImmutableTimeStampedCache}.
195 */
196 @SuppressWarnings("unchecked")
197 public static <TS extends TimeStamped> ImmutableTimeStampedCache<TS> emptyCache() {
198 return (ImmutableTimeStampedCache<TS>) EMPTY_CACHE;
199 }
200
201 }