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.time;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.List;
22  
23  import org.orekit.data.DataProvidersManager;
24  import org.orekit.errors.OrekitException;
25  import org.orekit.errors.OrekitMessages;
26  import org.orekit.frames.EOPHistory;
27  import org.orekit.frames.LazyLoadedEop;
28  import org.orekit.utils.IERSConventions;
29  
30  /**
31   * An implementation of {@link TimeScales} that loads auxiliary data, leap seconds and
32   * UT1-UTC, when it is first accessed. The list of loaders may be modified before the
33   * first data access.
34   *
35   * @author Luc Maisonobe
36   * @author Evan Ward
37   * @see TimeScalesFactory
38   * @since 10.1
39   */
40  public class LazyLoadedTimeScales extends AbstractTimeScales {
41  
42      /** Source of EOP data. */
43      private final LazyLoadedEop lazyLoadedEop;
44  
45      /** UTCTAI offsets loaders. */
46      private final List<UTCTAIOffsetsLoader> loaders = new ArrayList<>();
47      /** Universal Time Coordinate scale. */
48      private UTCScale utc = null;
49  
50      /** International Atomic Time scale. */
51      private TAIScale tai = null;
52  
53      /** Terrestrial Time scale. */
54      private TTScale tt = null;
55  
56      /** Galileo System Time scale. */
57      private GalileoScale gst = null;
58  
59      /** GLObal NAvigation Satellite System scale. */
60      private GLONASSScale glonass = null;
61  
62      /** Quasi-Zenith Satellite System scale. */
63      private QZSSScale qzss = null;
64  
65      /** Global Positioning System scale. */
66      private GPSScale gps = null;
67  
68      /** Geocentric Coordinate Time scale. */
69      private TCGScale tcg = null;
70  
71      /** Barycentric Dynamic Time scale. */
72      private TDBScale tdb = null;
73  
74      /** Barycentric Coordinate Time scale. */
75      private TCBScale tcb = null;
76  
77      /** IRNSS System Time scale. */
78      private IRNSSScale irnss = null;
79  
80      /** BDS System Time scale. */
81      private BDTScale bds = null;
82  
83      /**
84       * Create a new set of time scales with the given sources of auxiliary data. This
85       * constructor uses the same {@link DataProvidersManager} for the default EOP loaders
86       * and the default leap second loaders.
87       *
88       * @param lazyLoadedEop loads Earth Orientation Parameters for {@link
89       *                      #getUT1(IERSConventions, boolean)}.
90       */
91      public LazyLoadedTimeScales(final LazyLoadedEop lazyLoadedEop) {
92          this.lazyLoadedEop = lazyLoadedEop;
93      }
94  
95      /**
96       * Add a loader for UTC-TAI offsets history files.
97       *
98       * @param loader custom loader to add
99       * @see TAIUTCDatFilesLoader
100      * @see UTCTAIHistoryFilesLoader
101      * @see UTCTAIBulletinAFilesLoader
102      * @see #getUTC()
103      * @see #clearUTCTAIOffsetsLoaders()
104      * @since 7.1
105      */
106     public void addUTCTAIOffsetsLoader(final UTCTAIOffsetsLoader loader) {
107         synchronized (this) {
108             loaders.add(loader);
109         }
110     }
111 
112     /**
113      * Add the default loaders for UTC-TAI offsets history files (both IERS and USNO).
114      * <p>
115      * The default loaders are {@link TAIUTCDatFilesLoader} that looks for a file named
116      * {@code tai-utc.dat} that must be in USNO format and {@link
117      * UTCTAIHistoryFilesLoader} that looks fir a file named {@code UTC-TAI.history} that
118      * must be in the IERS format. The {@link UTCTAIBulletinAFilesLoader} is
119      * <em>not</em> added by default as it is not recommended. USNO warned us that
120      * the TAI-UTC data present in bulletin A was for convenience only and was not
121      * reliable, there have been errors in several bulletins regarding these data.
122      * </p>
123      *
124      * @see <a href="http://maia.usno.navy.mil/ser7/tai-utc.dat">USNO tai-utc.dat
125      * file</a>
126      * @see <a href="http://hpiers.obspm.fr/eoppc/bul/bulc/UTC-TAI.history">IERS
127      * UTC-TAI.history file</a>
128      * @see TAIUTCDatFilesLoader
129      * @see UTCTAIHistoryFilesLoader
130      * @see #getUTC()
131      * @see #clearUTCTAIOffsetsLoaders()
132      * @since 7.1
133      */
134     public void addDefaultUTCTAIOffsetsLoaders() {
135         synchronized (this) {
136             final DataProvidersManager dataProvidersManager =
137                     lazyLoadedEop.getDataProvidersManager();
138             addUTCTAIOffsetsLoader(new TAIUTCDatFilesLoader(TAIUTCDatFilesLoader.DEFAULT_SUPPORTED_NAMES, dataProvidersManager));
139             addUTCTAIOffsetsLoader(new UTCTAIHistoryFilesLoader(dataProvidersManager));
140         }
141     }
142 
143     /**
144      * Clear loaders for UTC-TAI offsets history files.
145      *
146      * @see #getUTC()
147      * @see #addUTCTAIOffsetsLoader(UTCTAIOffsetsLoader)
148      * @see #addDefaultUTCTAIOffsetsLoaders()
149      * @since 7.1
150      */
151     public void clearUTCTAIOffsetsLoaders() {
152         synchronized (this) {
153             loaders.clear();
154         }
155     }
156 
157     @Override
158     public TAIScale getTAI() {
159         synchronized (this) {
160 
161             if (tai == null) {
162                 tai = new TAIScale();
163             }
164 
165             return tai;
166 
167         }
168     }
169 
170     @Override
171     public UTCScale getUTC() {
172         synchronized (this) {
173             if (utc == null) {
174                 List<OffsetModel> entries = Collections.emptyList();
175                 if (loaders.isEmpty()) {
176                     addDefaultUTCTAIOffsetsLoaders();
177                 }
178                 for (UTCTAIOffsetsLoader loader : loaders) {
179                     entries = loader.loadOffsets();
180                     if (!entries.isEmpty()) {
181                         break;
182                     }
183                 }
184                 if (entries.isEmpty()) {
185                     throw new OrekitException(OrekitMessages.NO_IERS_UTC_TAI_HISTORY_DATA_LOADED);
186                 }
187                 utc = new UTCScale(getTAI(), entries);
188             }
189 
190             return utc;
191         }
192     }
193 
194     @Override
195     public UT1Scale getUT1(final IERSConventions conventions, final boolean simpleEOP) {
196         // synchronized to maintain the same semantics as Orekit 10.0
197         synchronized (this) {
198             return super.getUT1(conventions, simpleEOP);
199         }
200     }
201 
202     @Override
203     protected EOPHistory getEopHistory(final IERSConventions conventions,
204                                        final boolean simpleEOP) {
205         return lazyLoadedEop.getEOPHistory(conventions, simpleEOP, this);
206     }
207 
208     // need to make this public for compatibility. Provides access to UT1 constructor.
209     /** {@inheritDoc} */
210     @Override
211     public UT1Scale getUT1(final EOPHistory history) {
212         return super.getUT1(history);
213     }
214 
215     @Override
216     public TTScale getTT() {
217         synchronized (this) {
218 
219             if (tt == null) {
220                 tt = new TTScale();
221             }
222 
223             return tt;
224 
225         }
226     }
227 
228     @Override
229     public GalileoScale getGST() {
230         synchronized (this) {
231 
232             if (gst == null) {
233                 gst = new GalileoScale();
234             }
235 
236             return gst;
237 
238         }
239     }
240 
241     @Override
242     public GLONASSScale getGLONASS() {
243         synchronized (this) {
244 
245             if (glonass == null) {
246                 glonass = new GLONASSScale(getUTC());
247             }
248 
249             return glonass;
250 
251         }
252     }
253 
254     @Override
255     public QZSSScale getQZSS() {
256         synchronized (this) {
257 
258             if (qzss == null) {
259                 qzss = new QZSSScale();
260             }
261 
262             return qzss;
263 
264         }
265     }
266 
267     @Override
268     public GPSScale getGPS() {
269         synchronized (this) {
270 
271             if (gps == null) {
272                 gps = new GPSScale();
273             }
274 
275             return gps;
276 
277         }
278     }
279 
280     @Override
281     public TCGScale getTCG() {
282         synchronized (this) {
283 
284             if (tcg == null) {
285                 tcg = new TCGScale(getTT(), getTAI());
286             }
287 
288             return tcg;
289 
290         }
291     }
292 
293     @Override
294     public TDBScale getTDB() {
295         synchronized (this) {
296 
297             if (tdb == null) {
298                 tdb = new TDBScale(getTT(), getJ2000Epoch());
299             }
300 
301             return tdb;
302 
303         }
304     }
305 
306     @Override
307     public TCBScale getTCB() {
308         synchronized (this) {
309 
310             if (tcb == null) {
311                 tcb = new TCBScale(getTDB(), getTAI());
312             }
313 
314             return tcb;
315 
316         }
317     }
318 
319     @Override
320     public GMSTScale getGMST(final IERSConventions conventions, final boolean simpleEOP) {
321         // synchronized to maintain the same semantics as Orekit 10.0
322         synchronized (this) {
323             return super.getGMST(conventions, simpleEOP);
324         }
325     }
326 
327     @Override
328     public IRNSSScale getIRNSS() {
329         synchronized (this) {
330 
331             if (irnss == null) {
332                 irnss = new IRNSSScale();
333             }
334 
335             return irnss;
336 
337         }
338     }
339 
340     @Override
341     public BDTScale getBDT() {
342         synchronized (this) {
343 
344             if (bds == null) {
345                 bds = new BDTScale();
346             }
347 
348             return bds;
349 
350         }
351     }
352 
353 }