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.factory.GordianFactory.GordianFactoryLock;
21  import io.github.tonywasher.joceanus.gordianknot.api.zip.GordianZipFactory;
22  import io.github.tonywasher.joceanus.gordianknot.api.zip.GordianZipLock;
23  import io.github.tonywasher.joceanus.gordianknot.api.zip.GordianZipWriteFile;
24  import io.github.tonywasher.joceanus.metis.toolkit.MetisToolkit;
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.PrometheusIOException;
30  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusSecurityException;
31  import io.github.tonywasher.joceanus.prometheus.security.PrometheusSecurityPasswordManager;
32  import io.github.tonywasher.joceanus.prometheus.service.sheet.PrometheusSheetProvider;
33  import io.github.tonywasher.joceanus.prometheus.service.sheet.PrometheusSheetWorkBook;
34  import io.github.tonywasher.joceanus.prometheus.service.sheet.PrometheusSheetWorkBookType;
35  import io.github.tonywasher.joceanus.tethys.api.thread.TethysUIThreadStatusReport;
36  
37  import java.io.File;
38  import java.io.FileOutputStream;
39  import java.io.IOException;
40  import java.io.OutputStream;
41  import java.util.ArrayList;
42  import java.util.List;
43  
44  /**
45   * Write control for spreadsheets.
46   *
47   * @author Tony Washer
48   */
49  public abstract class PrometheusSheetWriter
50          implements PrometheusSheetControl {
51      /**
52       * Report.
53       */
54      private final TethysUIThreadStatusReport theReport;
55  
56      /**
57       * Writable spreadsheet.
58       */
59      private PrometheusSheetWorkBook theWorkBook;
60  
61      /**
62       * The DataSet.
63       */
64      private PrometheusDataSet theData;
65  
66      /**
67       * The Sheet Type.
68       */
69      private PrometheusSheetWorkBookType theType;
70  
71      /**
72       * The WorkSheets.
73       */
74      private List<PrometheusSheetDataItem<?>> theSheets;
75  
76      /**
77       * Constructor.
78       *
79       * @param pReport the report
80       */
81      protected PrometheusSheetWriter(final TethysUIThreadStatusReport pReport) {
82          theReport = pReport;
83      }
84  
85      @Override
86      public TethysUIThreadStatusReport getReport() {
87          return theReport;
88      }
89  
90      @Override
91      public PrometheusSheetWorkBook getWorkBook() {
92          return theWorkBook;
93      }
94  
95      @Override
96      public PrometheusDataSet getData() {
97          return theData;
98      }
99  
100     /**
101      * Add Sheet to list.
102      *
103      * @param pSheet the sheet
104      */
105     protected void addSheet(final PrometheusSheetDataItem<?> pSheet) {
106         theSheets.add(pSheet);
107     }
108 
109     /**
110      * Create a Backup Workbook.
111      *
112      * @param pData Data to write out
113      * @param pFile the backup file to write to
114      * @param pType the workBookType
115      * @throws OceanusException on error
116      */
117     public void createBackup(final PrometheusDataSet pData,
118                              final File pFile,
119                              final PrometheusSheetWorkBookType pType) throws OceanusException {
120         /* Protect against exceptions */
121         boolean writeFailed = false;
122         try (FileOutputStream myOutputStream = new FileOutputStream(pFile)) {
123             /* Create the backup */
124             createBackup(pData, myOutputStream, pType);
125 
126             /* Handle exceptions */
127         } catch (IOException
128                  | OceanusException e) {
129             writeFailed = true;
130             throw new PrometheusIOException("Failed to create backup Workbook", e);
131 
132             /* Handle cleanup */
133         } finally {
134             /* Try to delete the file if required */
135             if (writeFailed) {
136                 MetisToolkit.cleanUpFile(pFile);
137             }
138         }
139     }
140 
141     /**
142      * Create a Backup Workbook.
143      *
144      * @param pData      Data to write out
145      * @param pZipStream the output stream
146      * @param pType      the workBookType
147      * @throws OceanusException on error
148      */
149     public void createBackup(final PrometheusDataSet pData,
150                              final OutputStream pZipStream,
151                              final PrometheusSheetWorkBookType pType) throws OceanusException {
152         /* Record details */
153         theData = pData;
154         theType = pType;
155 
156         /* Create the backup */
157         createBackup(pZipStream);
158     }
159 
160     /**
161      * Create a Backup Workbook.
162      *
163      * @param pZipStream the backup file to write to
164      * @throws OceanusException on error
165      */
166     public void createBackup(final OutputStream pZipStream) throws OceanusException {
167         /* Obtain the active profile */
168         OceanusProfile myTask = theReport.getActiveTask();
169         myTask = myTask.startTask("Writing");
170 
171         /* Protect against exceptions */
172         try {
173             /* Create a similar security control */
174             final PrometheusSecurityPasswordManager myPasswordMgr = theData.getPasswordMgr();
175             final GordianFactoryLock myBase = theData.getFactoryLock();
176             final GordianFactoryLock myLock = myPasswordMgr.similarFactoryLock(myBase);
177             final GordianZipFactory myZips = myPasswordMgr.getSecurityFactory().getZipFactory();
178             final GordianZipLock myZipLock = myZips.zipLock(myLock);
179 
180             /* Create the backup */
181             createBackup(myZipLock, pZipStream);
182 
183             /* Handle exceptions */
184         } catch (GordianException e) {
185             throw new PrometheusSecurityException(e);
186         }
187 
188         /* Complete task */
189         myTask.end();
190     }
191 
192     /**
193      * Create a Backup Workbook.
194      *
195      * @param pZipLock   the zipLock
196      * @param pZipStream the backup file to write to
197      * @throws OceanusException on error
198      */
199     public void createBackup(final GordianZipLock pZipLock,
200                              final OutputStream pZipStream) throws OceanusException {
201         /* Access Zip factory */
202         final PrometheusSecurityPasswordManager myPasswordMgr = theData.getPasswordMgr();
203         final GordianZipFactory myZips = myPasswordMgr.getSecurityFactory().getZipFactory();
204 
205         /* Assume failure */
206         final String myName = PrometheusSheetConstants.FILE_NAME + theType.getExtension();
207 
208         /* Protect the workbook access */
209         try (GordianZipWriteFile myZipFile = myZips.createZipFile(pZipLock, pZipStream);
210              OutputStream myStream = myZipFile.createOutputStream(new File(myName), false)) {
211             /* Initialise the WorkBook */
212             initialiseWorkBook(theType);
213 
214             /* Write the data to the work book */
215             writeWorkBook(myStream);
216 
217         } catch (IOException
218                  | OceanusException e) {
219             /* Report the error */
220             throw new PrometheusIOException("Failed to create Backup Workbook", e);
221         } catch (GordianException e) {
222             throw new PrometheusSecurityException(e);
223         }
224     }
225 
226     /**
227      * Register sheets.
228      */
229     protected abstract void registerSheets();
230 
231     /**
232      * Create the list of sheets to write.
233      *
234      * @param pType the workBookType
235      * @throws OceanusException on error
236      */
237     private void initialiseWorkBook(final PrometheusSheetWorkBookType pType) throws OceanusException {
238         /* Create the workbook attached to the output stream */
239         theWorkBook = PrometheusSheetProvider.newWorkBook(pType);
240 
241         /* Initialise the list */
242         theSheets = new ArrayList<>();
243 
244         /* Loop through the list types */
245         for (PrometheusCryptographyDataType myType : PrometheusCryptographyDataType.values()) {
246             /* Create the sheet */
247             theSheets.add(newSheet(myType));
248         }
249 
250         /* register additional sheets */
251         registerSheets();
252     }
253 
254     /**
255      * Create new sheet of required type.
256      *
257      * @param pListType the list type
258      * @return the new sheet
259      */
260     private PrometheusSheetDataItem<?> newSheet(final PrometheusCryptographyDataType pListType) {
261         /* Switch on list Type */
262         return switch (pListType) {
263             case CONTROLDATA -> new PrometheusSheetControlData(this);
264             case CONTROLKEY -> new PrometheusSheetControlKey(this);
265             case CONTROLKEYSET -> new PrometheusSheetControlKeySet(this);
266             case DATAKEYSET -> new PrometheusSheetDataKeySet(this);
267             default -> throw new IllegalArgumentException(pListType.toString());
268         };
269     }
270 
271     /**
272      * Write the WorkBook.
273      *
274      * @param pStream the output stream
275      * @throws OceanusException on error
276      */
277     private void writeWorkBook(final OutputStream pStream) throws OceanusException {
278         /* Obtain the active profile */
279         final OceanusProfile myTask = theReport.getActiveTask();
280 
281         /* Declare the number of stages */
282         theReport.setNumStages(theSheets.size() + 1);
283 
284         /* Loop through the sheets */
285         for (PrometheusSheetDataItem<?> mySheet : theSheets) {
286             /* Access the next sheet */
287             /* Write data for the sheet */
288             myTask.startTask(mySheet.toString());
289             mySheet.writeSpreadSheet();
290         }
291 
292         /* If we have built all the sheets */
293         theReport.setNewStage("Writing");
294 
295         /* If we have created the workbook OK */
296         /* Write it out to disk and close the stream */
297         myTask.startTask("Saving");
298         theWorkBook.saveToStream(pStream);
299     }
300 }