View Javadoc
1   /*
2    * Prometheus: Application Framework
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * 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, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.prometheus.sheets;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
20  import io.github.tonywasher.joceanus.gordianknot.api.zip.GordianZipFactory;
21  import io.github.tonywasher.joceanus.gordianknot.api.zip.GordianZipFileContents;
22  import io.github.tonywasher.joceanus.gordianknot.api.zip.GordianZipFileEntry;
23  import io.github.tonywasher.joceanus.gordianknot.api.zip.GordianZipLock;
24  import io.github.tonywasher.joceanus.gordianknot.api.zip.GordianZipReadFile;
25  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
26  import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
27  import io.github.tonywasher.joceanus.prometheus.data.PrometheusCryptographyDataType;
28  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
29  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusDataException;
30  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusIOException;
31  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusSecurityException;
32  import io.github.tonywasher.joceanus.prometheus.security.PrometheusSecurityPasswordManager;
33  import io.github.tonywasher.joceanus.prometheus.service.sheet.PrometheusSheetProvider;
34  import io.github.tonywasher.joceanus.prometheus.service.sheet.PrometheusSheetWorkBook;
35  import io.github.tonywasher.joceanus.prometheus.service.sheet.PrometheusSheetWorkBookType;
36  import io.github.tonywasher.joceanus.tethys.api.thread.TethysUIThreadStatusReport;
37  
38  import java.io.File;
39  import java.io.FileInputStream;
40  import java.io.IOException;
41  import java.io.InputStream;
42  import java.util.ArrayList;
43  import java.util.Iterator;
44  import java.util.List;
45  
46  /**
47   * Load control for spreadsheets.
48   *
49   * @author Tony Washer
50   */
51  public abstract class PrometheusSheetReader
52          implements PrometheusSheetControl {
53      /**
54       * Report.
55       */
56      private final TethysUIThreadStatusReport theReport;
57  
58      /**
59       * The password manager.
60       */
61      private final PrometheusSecurityPasswordManager thePasswordMgr;
62  
63      /**
64       * Spreadsheet.
65       */
66      private PrometheusSheetWorkBook theWorkBook;
67  
68      /**
69       * DataSet.
70       */
71      private PrometheusDataSet theData;
72  
73      /**
74       * The WorkSheets.
75       */
76      private List<PrometheusSheetDataItem<?>> theSheets;
77  
78      /**
79       * Constructor.
80       *
81       * @param pReport      the report
82       * @param pPasswordMgr the password manager
83       */
84      protected PrometheusSheetReader(final TethysUIThreadStatusReport pReport,
85                                      final PrometheusSecurityPasswordManager pPasswordMgr) {
86          theReport = pReport;
87          thePasswordMgr = pPasswordMgr;
88      }
89  
90      @Override
91      public TethysUIThreadStatusReport getReport() {
92          return theReport;
93      }
94  
95      @Override
96      public PrometheusDataSet getData() {
97          return theData;
98      }
99  
100     @Override
101     public PrometheusSheetWorkBook getWorkBook() {
102         return theWorkBook;
103     }
104 
105     /**
106      * Add Sheet to list.
107      *
108      * @param pSheet the sheet
109      */
110     protected void addSheet(final PrometheusSheetDataItem<?> pSheet) {
111         theSheets.add(pSheet);
112     }
113 
114     /**
115      * Load a Backup Workbook.
116      *
117      * @param pData DataSet to load into
118      * @param pFile the file to load
119      * @throws OceanusException on error
120      */
121     public void loadBackup(final File pFile,
122                            final PrometheusDataSet pData) throws OceanusException {
123         try {
124             loadBackup(new FileInputStream(pFile), pData, pFile.getName());
125         } catch (IOException e) {
126             throw new PrometheusIOException("Failed to access Backup", e);
127         }
128     }
129 
130     /**
131      * Load a Backup Workbook.
132      *
133      * @param pInStream the zip input stream
134      * @param pData     the data to load into
135      * @param pName     the filename
136      * @throws OceanusException on error
137      */
138     public void loadBackup(final InputStream pInStream,
139                            final PrometheusDataSet pData,
140                            final String pName) throws OceanusException {
141         /* Protect against exceptions */
142         try {
143             /* Start the task */
144             OceanusProfile myTask = theReport.getActiveTask();
145             myTask = myTask.startTask("Loading");
146             theData = pData;
147 
148             /* Access the zip file */
149             final GordianZipFactory myZips = thePasswordMgr.getSecurityFactory().getZipFactory();
150             final GordianZipReadFile myFile = myZips.openZipFile(pInStream);
151 
152             /* Obtain the lock from the file */
153             final GordianZipLock myLock = myFile.getLock();
154 
155             /* Resolve the lock */
156             thePasswordMgr.resolveZipLock(myLock, pName);
157 
158             /* Access ZipFile contents */
159             final GordianZipFileContents myContents = myFile.getContents();
160 
161             /* Loop through the file entries */
162             final Iterator<GordianZipFileEntry> myIterator = myContents.iterator();
163             GordianZipFileEntry myEntry = null;
164             while (myIterator.hasNext()) {
165                 /* Access the entry */
166                 myEntry = myIterator.next();
167 
168                 /* Break loop if we have the right entry */
169                 if (myEntry.getFileName().startsWith(PrometheusSheetConstants.FILE_NAME)) {
170                     break;
171                 }
172             }
173 
174             /* If we did not find the entry */
175             if (myEntry == null) {
176                 throw new PrometheusDataException("Invalid input file");
177             }
178 
179             /* Load the workBook */
180             loadEntry(myFile, myEntry);
181 
182             /* Complete the task */
183             myTask.end();
184 
185         } catch (GordianException e) {
186             throw new PrometheusSecurityException(e);
187         }
188     }
189 
190     /**
191      * Load a Backup Workbook.
192      *
193      * @param pFile  the zip file
194      * @param pEntry the zip file entry
195      * @throws OceanusException on error
196      */
197     public void loadEntry(final GordianZipReadFile pFile,
198                           final GordianZipFileEntry pEntry) throws OceanusException {
199         /* Protect the workbook retrieval */
200         try (InputStream myStream = pFile.createInputStream(pEntry)) {
201             /* Obtain the active profile */
202             final OceanusProfile myTask = theReport.getActiveTask();
203             myTask.startTask("Parsing");
204 
205             /* Initialise the workbook */
206             initialiseWorkBook(myStream, PrometheusSheetWorkBookType.determineType(pEntry.getFileName()));
207 
208             /* Load the workbook */
209             myTask.startTask("Reading");
210             loadWorkBook();
211 
212             /* Close the Stream to force out errors */
213             myTask.startTask("Closing");
214 
215         } catch (IOException e) {
216             /* Report the error */
217             throw new PrometheusIOException("Failed to load Backup Workbook: " + pEntry.getFileName(), e);
218 
219         } catch (GordianException e) {
220             throw new PrometheusSecurityException(e);
221         }
222     }
223 
224     /**
225      * Register sheets.
226      */
227     protected abstract void registerSheets();
228 
229     /**
230      * Create the list of sheets to load.
231      *
232      * @param pStream the input stream
233      * @param pType   the workBookType
234      * @throws OceanusException on error
235      */
236     private void initialiseWorkBook(final InputStream pStream,
237                                     final PrometheusSheetWorkBookType pType) throws OceanusException {
238         /* Initialise the list */
239         theSheets = new ArrayList<>();
240 
241         /* Loop through the list types */
242         for (PrometheusCryptographyDataType myType : PrometheusCryptographyDataType.values()) {
243             /* Create the sheet */
244             theSheets.add(newSheet(myType));
245         }
246 
247         /* register additional sheets */
248         registerSheets();
249 
250         /* Note the stage */
251         theReport.setNewStage("Loading");
252 
253         /* Access the workbook from the stream */
254         theWorkBook = PrometheusSheetProvider.loadFromStream(pType, pStream);
255     }
256 
257     /**
258      * Create new sheet of required type.
259      *
260      * @param pListType the list type
261      * @return the new sheet
262      */
263     private PrometheusSheetDataItem<?> newSheet(final PrometheusCryptographyDataType pListType) {
264         /* Switch on list Type */
265         return switch (pListType) {
266             case CONTROLDATA -> new PrometheusSheetControlData(this);
267             case CONTROLKEY -> new PrometheusSheetControlKey(this);
268             case CONTROLKEYSET -> new PrometheusSheetControlKeySet(this);
269             case DATAKEYSET -> new PrometheusSheetDataKeySet(this);
270             default -> throw new IllegalArgumentException(pListType.toString());
271         };
272     }
273 
274     /**
275      * Load the WorkBook.
276      *
277      * @throws OceanusException on error
278      */
279     private void loadWorkBook() throws OceanusException {
280         /* Obtain the active profile */
281         final OceanusProfile myTask = theReport.getActiveTask();
282 
283         /* Declare the number of stages */
284         theReport.setNumStages(theSheets.size());
285 
286         /* Loop through the sheets */
287         for (PrometheusSheetDataItem<?> mySheet : theSheets) {
288             /* Load data for the sheet */
289             myTask.startTask(mySheet.toString());
290             mySheet.loadSpreadSheet();
291         }
292     }
293 }