1   /* Copyright 2002-2025 CS GROUP
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.data;
18  
19  import java.io.File;
20  import java.io.InputStream;
21  import java.net.URISyntaxException;
22  import java.util.IdentityHashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.regex.Matcher;
26  import java.util.regex.Pattern;
27  
28  import org.hipparchus.exception.DummyLocalizable;
29  import org.junit.jupiter.api.AfterEach;
30  import org.junit.jupiter.api.Assertions;
31  import org.junit.jupiter.api.Test;
32  import org.orekit.Utils;
33  import org.orekit.errors.OrekitException;
34  
35  public class DataProvidersManagerTest {
36  
37      @AfterEach
38      public void tearDown() {
39          // clear the filters so they don't change other tests
40          DataContext.getDefault().getDataProvidersManager().resetFiltersToDefault();
41      }
42  
43      @Test
44      public void testDefaultConfiguration() {
45          System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, getPath("regular-data"));
46          CountingLoader crawler = new CountingLoader(false);
47          DataContext.getDefault().getDataProvidersManager().clearProviders();
48          Assertions.assertFalse(DataContext.getDefault().getDataProvidersManager().isSupported(new DirectoryCrawler(new File(getPath("regular-data")))));
49          Assertions.assertTrue(DataContext.getDefault().getDataProvidersManager().feed(".*", crawler));
50          Assertions.assertEquals(20, crawler.getCount());
51      }
52  
53      @Test
54      public void testLoadMonitoring() {
55          System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, getPath("regular-data"));
56          DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
57          manager.clearProviders();
58          manager.clearLoadedDataNames();
59          Assertions.assertFalse(manager.isSupported(new DirectoryCrawler(new File(getPath("regular-data")))));
60          Assertions.assertEquals(0, manager.getLoadedDataNames().size());
61          CountingLoader tleCounter = new CountingLoader(false);
62          Assertions.assertFalse(manager.feed(".*\\.tle$", tleCounter));
63          Assertions.assertEquals(0, tleCounter.getCount());
64          Assertions.assertEquals(0, manager.getLoadedDataNames().size());
65          CountingLoader txtCounter = new CountingLoader(false);
66          Assertions.assertTrue(manager.feed(".*\\.txt$", txtCounter));
67          Assertions.assertEquals(6, txtCounter.getCount());
68          Assertions.assertEquals(6, manager.getLoadedDataNames().size());
69          CountingLoader de405Counter = new CountingLoader(false);
70          Assertions.assertTrue(manager.feed(".*\\.405$", de405Counter));
71          Assertions.assertEquals(4, de405Counter.getCount());
72          Assertions.assertEquals(10, manager.getLoadedDataNames().size());
73          manager.clearLoadedDataNames();
74          Assertions.assertEquals(0, manager.getLoadedDataNames().size());
75      }
76  
77      @Test
78      public void testLoadFailure() {
79          System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, getPath("regular-data"));
80          DataContext.getDefault().getDataProvidersManager().clearProviders();
81          CountingLoader crawler = new CountingLoader(true);
82          try {
83              DataContext.getDefault().getDataProvidersManager().feed(".*", crawler);
84              Assertions.fail("an exception should have been thrown");
85          } catch (OrekitException oe) {
86              // expected
87          }
88          Assertions.assertEquals(20, crawler.getCount());
89      }
90  
91      @Test
92      public void testEmptyProperty() {
93          System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, "");
94          CountingLoader crawler = new CountingLoader(false);
95          DataContext.getDefault().getDataProvidersManager().clearProviders();
96          DataContext.getDefault().getDataProvidersManager().feed(".*", crawler);
97          Assertions.assertEquals(0, crawler.getCount());
98      }
99  
100     @Test
101     public void testInexistentDirectory() {
102         Assertions.assertThrows(OrekitException.class, () -> {
103             File inexistent = new File(getPath("regular-data"), "inexistent");
104             System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, inexistent.getAbsolutePath());
105             CountingLoader crawler = new CountingLoader(false);
106             DataContext.getDefault().getDataProvidersManager().clearProviders();
107             DataContext.getDefault().getDataProvidersManager().feed(".*", crawler);
108         });
109     }
110 
111     @Test
112     public void testInexistentZipArchive() {
113         Assertions.assertThrows(OrekitException.class, () -> {
114             File inexistent = new File(getPath("regular-data"), "inexistent.zip");
115             System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, inexistent.getAbsolutePath());
116             CountingLoader crawler = new CountingLoader(false);
117             DataContext.getDefault().getDataProvidersManager().clearProviders();
118             DataContext.getDefault().getDataProvidersManager().feed(".*", crawler);
119         });
120     }
121 
122     @Test
123     public void testNeitherDirectoryNorZip() {
124         Assertions.assertThrows(OrekitException.class, () -> {
125             System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, getPath("regular-data/UTC-TAI.history"));
126             CountingLoader crawler = new CountingLoader(false);
127             DataContext.getDefault().getDataProvidersManager().clearProviders();
128             DataContext.getDefault().getDataProvidersManager().feed(".*", crawler);
129         });
130     }
131 
132     @Test
133     public void testListModification() {
134         System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, getPath("regular-data"));
135         CountingLoader crawler = new CountingLoader(false);
136         DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
137         manager.clearProviders();
138         Assertions.assertFalse(manager.isSupported(new DirectoryCrawler(new File(getPath("regular-data")))));
139         Assertions.assertTrue(manager.feed(".*", crawler));
140         Assertions.assertTrue(crawler.getCount() > 0);
141         List<DataProvider> providers = manager.getProviders();
142         Assertions.assertEquals(1, providers.size());
143         for (DataProvider provider : providers) {
144             Assertions.assertTrue(manager.isSupported(provider));
145         }
146         Assertions.assertNotNull(manager.removeProvider(providers.get(0)));
147         Assertions.assertEquals(0, manager.getProviders().size());
148         DataProvider provider = new DataProvider() {
149             public boolean feed(Pattern supported, DataLoader visitor, DataProvidersManager manager) {
150                 return true;
151             }
152         };
153         manager.addProvider(provider);
154         Assertions.assertEquals(1, manager.getProviders().size());
155         manager.addProvider(provider);
156         Assertions.assertEquals(2, manager.getProviders().size());
157         Assertions.assertNotNull(manager.removeProvider(provider));
158         Assertions.assertEquals(1, manager.getProviders().size());
159         Assertions.assertNull(manager.removeProvider(new DataProvider() {
160             public boolean feed(Pattern supported, DataLoader visitor, DataProvidersManager manager) {
161                 throw new OrekitException(new DummyLocalizable("oops!"));
162             }
163         }));
164         Assertions.assertEquals(1, manager.getProviders().size());
165         Assertions.assertNotNull(manager.removeProvider(manager.getProviders().get(0)));
166         Assertions.assertEquals(0, manager.getProviders().size());
167     }
168 
169     @Test
170     public void testComplexPropertySetting() {
171         String sep = System.getProperty("path.separator");
172         File top = new File(getPath("regular-data"));
173         File dir1 = new File(top, "de405-ephemerides");
174         File dir2 = new File(new File(top, "Earth-orientation-parameters"), "monthly");
175         System.setProperty(DataProvidersManager.OREKIT_DATA_PATH,
176                            dir1 + sep + sep + sep + sep + dir2);
177         DataContext.getDefault().getDataProvidersManager().clearProviders();
178 
179         CountingLoader crawler = new CountingLoader(false);
180         Assertions.assertTrue(DataContext.getDefault().getDataProvidersManager().feed(".*\\.405$", crawler));
181         Assertions.assertEquals(4, crawler.getCount());
182 
183         crawler = new CountingLoader(false);
184         Assertions.assertTrue(DataContext.getDefault().getDataProvidersManager().feed(".*\\.txt$", crawler));
185         Assertions.assertEquals(1, crawler.getCount());
186 
187         crawler = new CountingLoader(false);
188         Assertions.assertTrue(DataContext.getDefault().getDataProvidersManager().feed("bulletinb_.*\\.txt$", crawler));
189         Assertions.assertEquals(2, crawler.getCount());
190 
191     }
192 
193     @Test
194     public void testMultiZip() {
195         System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, getPath("zipped-data/multizip.zip"));
196         CountingLoader crawler = new CountingLoader(false);
197         DataContext.getDefault().getDataProvidersManager().clearProviders();
198         Assertions.assertTrue(DataContext.getDefault().getDataProvidersManager().feed(".*\\.txt$", crawler));
199         Assertions.assertEquals(6, crawler.getCount());
200     }
201 
202     @Test
203     public void testSimpleFilter() {
204         Utils.setDataRoot("regular-data");
205         CountingFilter filter = new CountingFilter();
206         DataContext.getDefault().getDataProvidersManager().getFiltersManager().addFilter(filter);
207         CountingLoader crawler = new CountingLoader(false);
208         Assertions.assertTrue(DataContext.getDefault().getDataProvidersManager().feed(".*", crawler));
209         Assertions.assertEquals(20, crawler.getCount());
210         Assertions.assertEquals(20, filter.getFilteredCount());
211         Assertions.assertEquals(20, filter.getOpenedCount());
212     }
213 
214     @Test
215     public void testMultiLayerFilter() {
216         Utils.setDataRoot("regular-data");
217         final int layers = 10;
218         MultiLayerFilter filter = new MultiLayerFilter(layers);
219         DataContext.getDefault().getDataProvidersManager().getFiltersManager().addFilter(filter);
220         CountingLoader crawler = new CountingLoader(false);
221         Assertions.assertTrue(DataContext.getDefault().getDataProvidersManager().feed(".*", crawler));
222         Assertions.assertEquals(20, crawler.getCount());
223         Assertions.assertEquals(20 * layers, filter.getOpenedCount());
224     }
225 
226     private static class CountingLoader implements DataLoader {
227         private boolean shouldFail;
228         private int count;
229         public CountingLoader(boolean shouldFail) {
230             this.shouldFail = shouldFail;
231             count = 0;
232         }
233         public boolean stillAcceptsData() {
234             return true;
235         }
236         public void loadData(InputStream input, String name)
237             {
238             ++count;
239             if (shouldFail) {
240                 throw new OrekitException(new DummyLocalizable("intentional failure"));
241             }
242         }
243         public int getCount() {
244             return count;
245         }
246     }
247 
248     private static class CountingFilter implements DataFilter {
249         private Map<DataSource, DataSource> filtered;
250         private int opened;
251         public CountingFilter() {
252             filtered = new IdentityHashMap<>();
253             opened   = 0;
254         }
255         public DataSource filter(DataSource original) {
256             if (filtered.containsKey(original)) {
257                 return original;
258             } else {
259                 DataSource f = new DataSource(original.getName(),
260                                             () -> {
261                                                 ++opened;
262                                                 return original.getOpener().openStreamOnce();
263                                             });
264                 filtered.put(f, f);
265                 return f;
266             }
267         }
268         public int getFilteredCount() {
269             return filtered.size();
270         }
271         public int getOpenedCount() {
272             return opened;
273         }
274     }
275 
276     private static class MultiLayerFilter implements DataFilter {
277         private static final String  PREFIX  = "multilayer-";
278         private static final Pattern PATTERN = Pattern.compile(PREFIX + "(\\d+)-(.*)");
279         private final int layers;
280         private int opened;
281         public MultiLayerFilter(final int layers) {
282             this.layers = layers;
283             this.opened = 0;
284         }
285         public DataSource filter(final DataSource original) {
286             Matcher matcher = PATTERN.matcher(original.getName());
287             int level = 0;
288             String baseName = original.getName();
289             if (matcher.matches()) {
290                 level = Integer.parseInt(matcher.group(1));
291                 baseName = matcher.group(2);
292             }
293             if (level++ < layers) {
294                 // add one filtering layer
295                 return new DataSource(PREFIX + level + "-" + baseName,
296                                      () -> {
297                                          ++opened;
298                                          return original.getOpener().openStreamOnce();
299                                      });
300             } else {
301                 // final layer, don't filter anymore
302                 return original;
303             }
304         }
305         public int getOpenedCount() {
306             return opened;
307         }
308     }
309 
310     private String getPath(String resourceName) {
311         try {
312             ClassLoader loader = DirectoryCrawlerTest.class.getClassLoader();
313             return loader.getResource(resourceName).toURI().getPath();
314         } catch (URISyntaxException e) {
315             Assertions.fail(e.getLocalizedMessage());
316             return null;
317         }
318     }
319 
320 }