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, {@link
117      * UTCTAIHistoryFilesLoader} that looks for a file named {@code UTC-TAI.history} that
118      * must be in the IERS format and {@link AGILeapSecondFilesLoader} that looks for a
119      * files named {@code LeapSecond.dat} that must be in AGI format. The {@link
120      * UTCTAIBulletinAFilesLoader} is<em>not</em> added by default as it is not recommended.
121      * USNO warned us that the TAI-UTC data present in bulletin A was for convenience only
122      * and was not reliable, there have been errors in several bulletins regarding these data.
123      * </p>
124      *
125      * @see <a href="http://maia.usno.navy.mil/ser7/tai-utc.dat">USNO tai-utc.dat
126      * file</a>
127      * @see <a href="http://hpiers.obspm.fr/eoppc/bul/bulc/UTC-TAI.history">IERS
128      * UTC-TAI.history file</a>
129      * @see TAIUTCDatFilesLoader
130      * @see UTCTAIHistoryFilesLoader
131      * @see AGILeapSecondFilesLoader
132      * @see #getUTC()
133      * @see #clearUTCTAIOffsetsLoaders()
134      * @since 7.1
135      */
136     public void addDefaultUTCTAIOffsetsLoaders() {
137         synchronized (this) {
138             final DataProvidersManager dataProvidersManager =
139                     lazyLoadedEop.getDataProvidersManager();
140             addUTCTAIOffsetsLoader(new TAIUTCDatFilesLoader(TAIUTCDatFilesLoader.DEFAULT_SUPPORTED_NAMES, dataProvidersManager));
141             addUTCTAIOffsetsLoader(new UTCTAIHistoryFilesLoader(dataProvidersManager));
142             addUTCTAIOffsetsLoader(new AGILeapSecondFilesLoader(AGILeapSecondFilesLoader.DEFAULT_SUPPORTED_NAMES, dataProvidersManager));
143         }
144     }
145 
146     /**
147      * Clear loaders for UTC-TAI offsets history files.
148      *
149      * @see #getUTC()
150      * @see #addUTCTAIOffsetsLoader(UTCTAIOffsetsLoader)
151      * @see #addDefaultUTCTAIOffsetsLoaders()
152      * @since 7.1
153      */
154     public void clearUTCTAIOffsetsLoaders() {
155         synchronized (this) {
156             loaders.clear();
157         }
158     }
159 
160     @Override
161     public TAIScale getTAI() {
162         synchronized (this) {
163 
164             if (tai == null) {
165                 tai = new TAIScale();
166             }
167 
168             return tai;
169 
170         }
171     }
172 
173     @Override
174     public UTCScale getUTC() {
175         synchronized (this) {
176             if (utc == null) {
177                 List<OffsetModel> entries = Collections.emptyList();
178                 if (loaders.isEmpty()) {
179                     addDefaultUTCTAIOffsetsLoaders();
180                 }
181                 for (UTCTAIOffsetsLoader loader : loaders) {
182                     entries = loader.loadOffsets();
183                     if (!entries.isEmpty()) {
184                         break;
185                     }
186                 }
187                 if (entries.isEmpty()) {
188                     throw new OrekitException(OrekitMessages.NO_IERS_UTC_TAI_HISTORY_DATA_LOADED);
189                 }
190                 utc = new UTCScale(getTAI(), entries);
191             }
192 
193             return utc;
194         }
195     }
196 
197     @Override
198     public UT1Scale getUT1(final IERSConventions conventions, final boolean simpleEOP) {
199         // synchronized to maintain the same semantics as Orekit 10.0
200         synchronized (this) {
201             return super.getUT1(conventions, simpleEOP);
202         }
203     }
204 
205     @Override
206     protected EOPHistory getEopHistory(final IERSConventions conventions,
207                                        final boolean simpleEOP) {
208         return lazyLoadedEop.getEOPHistory(conventions, simpleEOP, this);
209     }
210 
211     // need to make this public for compatibility. Provides access to UT1 constructor.
212     /** {@inheritDoc} */
213     @Override
214     public UT1Scale getUT1(final EOPHistory history) {
215         return super.getUT1(history);
216     }
217 
218     @Override
219     public TTScale getTT() {
220         synchronized (this) {
221 
222             if (tt == null) {
223                 tt = new TTScale();
224             }
225 
226             return tt;
227 
228         }
229     }
230 
231     @Override
232     public GalileoScale getGST() {
233         synchronized (this) {
234 
235             if (gst == null) {
236                 gst = new GalileoScale();
237             }
238 
239             return gst;
240 
241         }
242     }
243 
244     @Override
245     public GLONASSScale getGLONASS() {
246         synchronized (this) {
247 
248             if (glonass == null) {
249                 glonass = new GLONASSScale(getUTC());
250             }
251 
252             return glonass;
253 
254         }
255     }
256 
257     @Override
258     public QZSSScale getQZSS() {
259         synchronized (this) {
260 
261             if (qzss == null) {
262                 qzss = new QZSSScale();
263             }
264 
265             return qzss;
266 
267         }
268     }
269 
270     @Override
271     public GPSScale getGPS() {
272         synchronized (this) {
273 
274             if (gps == null) {
275                 gps = new GPSScale();
276             }
277 
278             return gps;
279 
280         }
281     }
282 
283     @Override
284     public TCGScale getTCG() {
285         synchronized (this) {
286 
287             if (tcg == null) {
288                 tcg = new TCGScale(getTT(), getTAI());
289             }
290 
291             return tcg;
292 
293         }
294     }
295 
296     @Override
297     public TDBScale getTDB() {
298         synchronized (this) {
299 
300             if (tdb == null) {
301                 tdb = new TDBScale(getTT(), getJ2000Epoch());
302             }
303 
304             return tdb;
305 
306         }
307     }
308 
309     @Override
310     public TCBScale getTCB() {
311         synchronized (this) {
312 
313             if (tcb == null) {
314                 tcb = new TCBScale(getTDB(), getTAI());
315             }
316 
317             return tcb;
318 
319         }
320     }
321 
322     @Override
323     public GMSTScale getGMST(final IERSConventions conventions, final boolean simpleEOP) {
324         // synchronized to maintain the same semantics as Orekit 10.0
325         synchronized (this) {
326             return super.getGMST(conventions, simpleEOP);
327         }
328     }
329 
330     @Override
331     public IRNSSScale getIRNSS() {
332         synchronized (this) {
333 
334             if (irnss == null) {
335                 irnss = new IRNSSScale();
336             }
337 
338             return irnss;
339 
340         }
341     }
342 
343     @Override
344     public BDTScale getBDT() {
345         synchronized (this) {
346 
347             if (bds == null) {
348                 bds = new BDTScale();
349             }
350 
351             return bds;
352 
353         }
354     }
355 
356 }