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.IOException;
20 import java.io.InputStream;
21 import java.text.ParseException;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.regex.Pattern;
26 import java.util.stream.Collectors;
27
28 import org.hipparchus.exception.DummyLocalizable;
29 import org.orekit.errors.OrekitException;
30
31
32 /** Provider for data files defined in a list.
33 * <p>
34 * All {@link FiltersManager#addFilter(DataFilter) registered}
35 * {@link DataFilter filters} are applied.
36 * </p>
37 * <p>
38 * Zip archives entries are supported recursively.
39 * </p>
40 * @since 10.1
41 * @see DataProvidersManager
42 * @see NetworkCrawler
43 * @see FilesListCrawler
44 * @author Luc Maisonobe
45 * @param <T> The type of resource, e.g. File or URL.
46 */
47 public abstract class AbstractListCrawler<T> implements DataProvider {
48
49 /** Inputs list. */
50 private final List<T> inputs;
51
52 /** Build a data classpath crawler.
53 * @param inputs list of inputs (may be empty if {@link #addInput(Object) addInput} is called later)
54 */
55 @SafeVarargs
56 protected AbstractListCrawler(final T... inputs) {
57 this.inputs = Arrays.stream(inputs).collect(Collectors.toList());
58 }
59
60 /** Add an input to the supported list.
61 * @param input input to add
62 */
63 public void addInput(final T input) {
64 inputs.add(input);
65 }
66
67 /** Get the list of inputs supported by the instance.
68 * @return unmodifiable view of the list of inputs supported by the instance
69 */
70 public List<T> getInputs() {
71 return Collections.unmodifiableList(inputs);
72 }
73
74 /** Get the complete name of a input.
75 * @param input input to consider
76 * @return complete name of the input
77 */
78 protected abstract String getCompleteName(T input);
79
80 /** Get the base name of an input.
81 * @param input input to consider
82 * @return base name of the input
83 */
84 protected abstract String getBaseName(T input);
85
86 /** Get a zip/jar crawler for an input.
87 * @param input input to consider
88 * @return zip/jar crawler for an input
89 */
90 protected abstract ZipJarCrawler getZipJarCrawler(T input);
91
92 /** Get the stream to read from an input.
93 * @param input input to read from
94 * @return stream to read the content of the input
95 * @throws IOException if the input cannot be opened for reading
96 */
97 protected abstract InputStream getStream(T input) throws IOException;
98
99 /** {@inheritDoc} */
100 @Override
101 public boolean feed(final Pattern supported,
102 final DataLoader visitor,
103 final DataProvidersManager manager) {
104
105 try {
106 OrekitException delayedException = null;
107 boolean loaded = false;
108 for (T input : inputs) {
109 try {
110
111 if (visitor.stillAcceptsData()) {
112 final String name = getCompleteName(input);
113 final String fileName = getBaseName(input);
114 if (ZIP_ARCHIVE_PATTERN.matcher(fileName).matches()) {
115
116 // browse inside the zip/jar file
117 getZipJarCrawler(input).feed(supported, visitor, manager);
118 loaded = true;
119
120 } else {
121
122 // apply all registered filters
123 DataSource data = new DataSource(fileName, () -> getStream(input));
124 data = manager.getFiltersManager().applyRelevantFilters(data);
125
126 if (supported.matcher(data.getName()).matches()) {
127 // visit the current file
128 try (InputStream is = data.getOpener().openStreamOnce()) {
129 visitor.loadData(is, name);
130 loaded = true;
131 }
132 }
133
134 }
135 }
136
137 } catch (OrekitException oe) {
138 // maybe the next path component will be able to provide data
139 // wait until all components have been tried
140 delayedException = oe;
141 }
142 }
143
144 if (!loaded && delayedException != null) {
145 throw delayedException;
146 }
147
148 return loaded;
149
150 } catch (IOException | ParseException e) {
151 throw new OrekitException(e, new DummyLocalizable(e.getMessage()));
152 }
153
154 }
155
156 }