View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  package org.waarp.vitam.dip;
22  
23  import fr.gouv.vitam.access.external.client.AccessExternalClient;
24  import fr.gouv.vitam.access.external.client.AccessExternalClientFactory;
25  import fr.gouv.vitam.common.exception.InvalidParseOperationException;
26  import fr.gouv.vitam.common.json.JsonHandler;
27  import org.apache.commons.cli.CommandLine;
28  import org.apache.commons.cli.Option;
29  import org.waarp.common.guid.GUID;
30  import org.waarp.common.logging.SysErrLogger;
31  import org.waarp.common.logging.WaarpLogger;
32  import org.waarp.common.logging.WaarpLoggerFactory;
33  import org.waarp.common.utility.SystemPropertyUtil;
34  import org.waarp.vitam.common.waarp.ManagerToWaarp;
35  import org.waarp.vitam.common.waarp.ManagerToWaarpFactory;
36  
37  import java.io.File;
38  import java.io.FilenameFilter;
39  import java.io.IOException;
40  import java.nio.file.Files;
41  import java.util.ArrayList;
42  import java.util.List;
43  import java.util.Properties;
44  
45  /**
46   * Factory that handles DipRequest within a directory
47   */
48  public class DipRequestFactory {
49    static final String DEFAULT_DIP_FACTORY = "/waarp/data/r66/DipFactory";
50    static final String ORG_WAARP_DIP_BASEDIR = "org.waarp.dip.basedir";
51    /**
52     * Internal Logger
53     */
54    private static final WaarpLogger logger =
55        WaarpLoggerFactory.getLogger(DipRequestFactory.class);
56    private static final String WORK = "work";
57    private static final String BASENAME = DipRequest.class.getSimpleName() + ".";
58    private static final String EXTENSION = ".json";
59    private static final String RESULT_EXTENSION = ".zip";
60    private static final FilenameFilter JSON_ONLY =
61        (dir, name) -> name.startsWith(BASENAME) && name.endsWith(EXTENSION);
62    private static final DipRequestFactoryml#DipRequestFactory">DipRequestFactory FACTORY = new DipRequestFactory();
63  
64    static {
65      setBaseDir(new File(DEFAULT_DIP_FACTORY));
66    }
67  
68    private File baseDir;
69    private File workDir;
70    private AccessExternalClientFactory clientFactory =
71        AccessExternalClientFactory.getInstance();
72  
73    private DipRequestFactory() {
74      // empty
75    }
76  
77    /**
78     * Common options
79     *
80     * @return common Options
81     */
82    static Option getDirectoryOption() {
83      Option property =
84          new Option("D", "Use value for property " + ORG_WAARP_DIP_BASEDIR);
85      property.setArgName("property=value");
86      property.setArgs(2);
87      property.setValueSeparator('=');
88      return property;
89    }
90  
91    /**
92     * Common parse command line and setup Base Directory
93     *
94     * @param cmd
95     */
96    static void parseDirectoryOption(CommandLine cmd) {
97      if (cmd.hasOption('D')) {
98        Properties properties = cmd.getOptionProperties("D");
99        setBaseDir(new File(
100           properties.getProperty(ORG_WAARP_DIP_BASEDIR, DEFAULT_DIP_FACTORY)));
101     } else if (SystemPropertyUtil.contains(ORG_WAARP_DIP_BASEDIR)) {
102       setBaseDir(new File(
103           SystemPropertyUtil.get(ORG_WAARP_DIP_BASEDIR, DEFAULT_DIP_FACTORY)));
104     } else {
105       setBaseDir(new File(DEFAULT_DIP_FACTORY));
106     }
107   }
108 
109   /**
110    * Set Base Directory
111    *
112    * @param baseDirToSet
113    */
114   static void setBaseDir(File baseDirToSet) {
115     FACTORY.baseDir = baseDirToSet;
116     FACTORY.baseDir.mkdirs();
117     FACTORY.workDir = new File(FACTORY.baseDir, WORK);
118     FACTORY.workDir.mkdirs();
119   }
120 
121   /**
122    * @return the instance of the factory
123    */
124   public static DipRequestFactory getInstance() {
125     return FACTORY;
126   }
127 
128   /**
129    * Used in JUnit
130    */
131   void setBaseDir() {
132     baseDir = FACTORY.baseDir;
133     workDir = FACTORY.workDir;
134   }
135 
136   /**
137    * @return the base directory
138    */
139   File getBaseDir() {
140     return baseDir;
141   }
142 
143   /**
144    * @return the Access Vitam client
145    */
146   public AccessExternalClient getClient() {
147     return clientFactory.getClient();
148   }
149 
150   /**
151    * @param dipRequest
152    *
153    * @return the associated ManagerToWaarp
154    */
155   public ManagerToWaarp getManagerToWaarp(DipRequest dipRequest) {
156     return ManagerToWaarpFactory.getManagerToWaarp(dipRequest.getWaarpModel());
157   }
158 
159   /**
160    * Save the DipRequest as a new one, creating file
161    *
162    * @param dipRequest
163    *
164    * @throws InvalidParseOperationException
165    */
166   synchronized void saveNewDipRequest(DipRequest dipRequest)
167       throws InvalidParseOperationException {
168     File newFile = new File(baseDir, getNewName());
169     dipRequest.setJsonPath(newFile.getName());
170     JsonHandler.writeAsFile(dipRequest, newFile);
171   }
172 
173   /**
174    * @return the unique name for JSON
175    */
176   private static String getNewName() {
177     synchronized (FACTORY) {
178       GUID guid = new GUID();
179       return BASENAME + guid.getId() + EXTENSION;
180     }
181   }
182 
183   /**
184    * Update the DipRequest
185    *
186    * @param dipRequest
187    *
188    * @return true if saved
189    *
190    * @throws InvalidParseOperationException
191    */
192   synchronized boolean saveDipRequest(DipRequest dipRequest)
193       throws InvalidParseOperationException {
194     File existingFile = new File(baseDir, dipRequest.getJsonPath());
195     if (existingFile.canRead()) {
196       JsonHandler.writeAsFile(dipRequest, existingFile);
197       return true;
198     }
199     throw new InvalidParseOperationException("Json File does not exist");
200   }
201 
202   /**
203    * Clean and remove all traces of this DipRequest
204    *
205    * @param dipRequest
206    *
207    * @return true if totally done
208    */
209   synchronized boolean removeDipRequest(DipRequest dipRequest) {
210     if (dipRequest.getJsonPath() != null) {
211       File existingFile = new File(baseDir, dipRequest.getJsonPath());
212       boolean status = deleteFile(existingFile);
213       // Delete the ATR file if any
214       File zipDipFile = getDipFile(dipRequest);
215       status &= deleteFile(zipDipFile);
216       File errorFile = getErrorFile(dipRequest);
217       status &= deleteFile(errorFile);
218       DipRequest.DIPStep.endSessionMachineSate(dipRequest.step);
219       // Ensure file are deleted there
220       while (existingFile.exists()) {
221         try {
222           FACTORY.wait(10);
223         } catch (InterruptedException ignore) {//NOSONAR
224           logger.debug(ignore);
225         }
226       }
227       return status;
228     }
229     return false;
230   }
231 
232   /**
233    * Internal
234    *
235    * @param file
236    *
237    * @return true if done
238    */
239   private boolean deleteFile(File file) {
240     if (file.canRead()) {
241       try {
242         Files.delete(file.toPath());
243       } catch (IOException e) {
244         logger.warn("Cannot delete file", e);
245         return false;
246       }
247     }
248     return true;
249   }
250 
251   /**
252    * @param dipRequest
253    *
254    * @return the File pointer to the DIP file
255    */
256   File getDipFile(DipRequest dipRequest) {
257     return new File(workDir, dipRequest.getJsonPath() + RESULT_EXTENSION);
258   }
259 
260   /**
261    * @param dipRequest
262    *
263    * @return the error file pointer
264    */
265   File getErrorFile(DipRequest dipRequest) {
266     return new File(workDir, dipRequest.getJsonPath() + EXTENSION);
267   }
268 
269   /**
270    * @return the list of existing DipRequests. Some can be not ready or ended
271    */
272   synchronized List<DipRequest> getExistingDips() {
273     List<DipRequest> list = new ArrayList<>();
274     File[] files = baseDir.listFiles(JSON_ONLY);
275     if (files != null) {
276       for (File file : files) {
277         try {
278           DipRequest dipRequest =
279               JsonHandler.getFromFile(file, DipRequest.class);
280           list.add(dipRequest);
281         } catch (InvalidParseOperationException ignored) {
282           // File could be deleted during read operation
283           SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
284         }
285       }
286     }
287     return list;
288   }
289 
290   /**
291    * @param filename
292    *
293    * @return the DipRequest if found
294    *
295    * @throws InvalidParseOperationException
296    */
297   synchronized DipRequest getSpecificDipRequest(String filename)
298       throws InvalidParseOperationException {
299     File file = new File(baseDir, filename);
300     if (file.exists()) {
301       return JsonHandler.getFromFile(file, DipRequest.class);
302     }
303     throw new InvalidParseOperationException("Cannot find " + filename);
304   }
305 }