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 com.fasterxml.jackson.annotation.JsonIgnore;
24  import com.fasterxml.jackson.annotation.JsonSetter;
25  import com.fasterxml.jackson.databind.JsonNode;
26  import fr.gouv.vitam.common.GlobalDataRest;
27  import fr.gouv.vitam.common.ParametersChecker;
28  import fr.gouv.vitam.common.StringUtils;
29  import fr.gouv.vitam.common.database.builder.query.VitamFieldsHelper;
30  import fr.gouv.vitam.common.exception.InvalidParseOperationException;
31  import fr.gouv.vitam.common.json.JsonHandler;
32  import fr.gouv.vitam.common.model.RequestResponseOK;
33  import org.waarp.common.exception.IllegalFiniteStateException;
34  import org.waarp.common.logging.WaarpLogger;
35  import org.waarp.common.logging.WaarpLoggerFactory;
36  import org.waarp.common.state.MachineState;
37  import org.waarp.common.state.Transition;
38  import org.waarp.vitam.common.AbstractVitamRequest;
39  import org.waarp.vitam.common.WaarpCommon.TaskOption;
40  
41  import java.io.File;
42  import java.util.EnumSet;
43  import java.util.concurrent.ConcurrentHashMap;
44  
45  public class DipRequest extends AbstractVitamRequest {
46    /**
47     * Internal Logger
48     */
49    private static final WaarpLogger logger =
50        WaarpLoggerFactory.getLogger(DipRequest.class);
51    @JsonIgnore
52    MachineState<DIPStep> step = DIPStep.newSessionMachineState();
53  
54    public DipRequest() {
55      // Empty constructor for Json
56    }
57  
58    /**
59     * Standard constructor
60     *
61     * @param taskOption
62     * @param factory
63     *
64     * @throws InvalidParseOperationException
65     */
66    public DipRequest(final TaskOption taskOption,
67                      final DipRequestFactory factory)
68        throws InvalidParseOperationException {
69      super(taskOption);
70      this.status = this.step.getCurrent().getStatusMonitor();
71      try {
72        factory.saveNewDipRequest(this);
73      } catch (InvalidParseOperationException e) {
74        logger.error("Will not be able to save: {}", this, e);
75        throw e;
76      }
77    }
78  
79    @Override
80    public String toString() {
81      return "DIP = Step: " + (step != null? step.getCurrent() : "noStep") + " " +
82             JsonHandler.unprettyPrint(this);
83    }
84  
85    /**
86     * Set extra information from first response from operation submission
87     *
88     * @param requestResponse
89     *
90     * @return this
91     */
92    @JsonIgnore
93    public DipRequest setFromRequestResponse(RequestResponseOK requestResponse) {
94      String requestIdNew =
95          requestResponse.getHeaderString(GlobalDataRest.X_REQUEST_ID);
96      // Shall be the same but get from Result preferred
97      JsonNode node = (JsonNode) requestResponse.getFirstResult();
98      if (node != null) {
99        node = node.get(VitamFieldsHelper.id());
100       if (node != null) {
101         requestIdNew = node.asText();
102       }
103     }
104     try {
105       ParametersChecker.checkParameterDefault(getCheckMessage(), requestIdNew);
106       StringUtils.checkSanityString(requestIdNew);
107     } catch (InvalidParseOperationException | IllegalArgumentException e) {
108       logger.error(e);
109       throw new IllegalArgumentException(e.getMessage(), e);
110     }
111     setRequestId(requestIdNew);
112     return this;
113   }
114 
115   /**
116    * Use to set the step and status accordingly.
117    *
118    * @param step
119    * @param status
120    * @param factory
121    *
122    * @return this
123    *
124    * @throws InvalidParseOperationException
125    */
126   @JsonIgnore
127   public DipRequest setStep(final DIPStep step, final int status,
128                             DipRequestFactory factory)
129       throws InvalidParseOperationException {
130     if (this.step == null) {
131       if (!step.equals(DIPStep.END)) {
132         logger.debug("Step {} could not be set since IngestRequest done", step);
133       }
134       // Nothing to do since already done
135       return this;
136     }
137     if (!step.equals(DIPStep.ERROR) && this.step.getCurrent().equals(step)) {
138       // nothing to do
139       return this;
140     }
141     try {
142       this.step.setCurrent(step);
143     } catch (IllegalFiniteStateException e) {
144       logger.error(e);
145       this.step.setDryCurrent(step);
146     }
147     setStatus(step != DIPStep.ERROR? step.getStatusMonitor() : status)
148         .setLastTryTime(System.currentTimeMillis());
149     return save(factory);
150   }
151 
152   /**
153    * Set the status AND the step according to the value of the status (if
154    * less than 0, it is a step value, not a final status), but in dry mode
155    * (no check, used by Json deserialization)
156    *
157    * @param status
158    *
159    * @return this
160    */
161   @JsonSetter("status")
162   public DipRequest setStatus(final int status) {
163     this.status = status;
164     if (step != null) {
165       step.setDryCurrent(DIPStep.getFromInt(status));
166     }
167     return this;
168   }
169 
170   /**
171    * Save this DipRequest
172    *
173    * @param factory
174    *
175    * @return this
176    *
177    * @throws InvalidParseOperationException
178    */
179   @JsonIgnore
180   public DipRequest save(DipRequestFactory factory)
181       throws InvalidParseOperationException {
182     factory.saveDipRequest(this);
183     return this;
184   }
185 
186   @JsonIgnore
187   public DIPStep getStep() {
188     if (step == null) {
189       return null;
190     }
191     return step.getCurrent();
192   }
193 
194   /**
195    * @return the DIP File pointer according to this
196    */
197   @JsonIgnore
198   public File getDipFile(DipRequestFactory factory) {
199     return factory.getDipFile(this);
200   }
201 
202   /**
203    * @return the Error File pointer according to this
204    */
205   @JsonIgnore
206   public File getErrorFile(DipRequestFactory factory) {
207     return factory.getErrorFile(this);
208   }
209 
210   /**
211    * @return the JsonNode for Vitam Request associated with this
212    *
213    * @throws InvalidParseOperationException
214    */
215   @JsonIgnore
216   public JsonNode getSelectJson() throws InvalidParseOperationException {
217     String path = getPath();
218     return JsonHandler.getFromFile(new File(path));
219   }
220 
221   /**
222    * Different steps of DIP export from Waarp point of view
223    */
224   enum DIPStep {
225     /**
226      * DipRequest not started yet
227      */
228     STARTUP(-1),
229     /**
230      * DipRequest SELECT to retry
231      */
232     RETRY_SELECT(-2),
233     /**
234      * DipRequest DIP get to retry
235      */
236     RETRY_DIP(-3),
237     /**
238      * DipRequest DIP to forward
239      */
240     RETRY_DIP_FORWARD(-4),
241     /**
242      * For Ingest compatibility
243      */
244     NO_STEP(-5),
245     /**
246      * DipRequest Error
247      */
248     ERROR(-7),
249     /**
250      * Final End step
251      */
252     END(-10);
253 
254     private static final ConcurrentHashMap<DIPStep, EnumSet<DIPStep>> stateMap =
255         new ConcurrentHashMap<>();
256 
257     static {
258       initR66FiniteStates();
259     }
260 
261     private final int statusMonitor;
262 
263     DIPStep(int status) {
264       this.statusMonitor = status;
265     }
266 
267     /**
268      * This method should be called once at startup to initialize the Finite
269      * States association.
270      */
271     private static void initR66FiniteStates() {
272       for (final DIPStep.IngestTransition trans : DIPStep.IngestTransition
273           .values()) {
274         stateMap.put(trans.elt.getState(), trans.elt.getSet());
275       }
276     }
277 
278     /**
279      * @return a new Session MachineState for OpenR66
280      */
281     private static MachineState<DIPStep> newSessionMachineState() {
282       return new MachineState<>(STARTUP, stateMap);
283     }
284 
285     /**
286      * @param machine the Session MachineState to release
287      */
288     static void endSessionMachineSate(MachineState<DIPStep> machine) {
289       if (machine != null) {
290         machine.release();
291       }
292     }
293 
294     static DIPStep getFromInt(int status) {
295       switch (status) {
296         case -1:
297           return STARTUP;
298         case -2:
299           return RETRY_SELECT;
300         case -3:
301           return RETRY_DIP;
302         case -4:
303           return RETRY_DIP_FORWARD;
304         case -5:
305           return NO_STEP;
306         case -10:
307           return END;
308         case -7:
309         default:
310           return ERROR;
311       }
312     }
313 
314     int getStatusMonitor() {
315       return statusMonitor;
316     }
317 
318     private enum IngestTransition {
319       T_STARTUP(STARTUP, EnumSet.of(RETRY_SELECT, ERROR)),
320       T_RETRY_SELECT(RETRY_SELECT, EnumSet.of(RETRY_DIP, ERROR)),
321       T_RETRY_DIP(RETRY_DIP, EnumSet.of(RETRY_DIP_FORWARD, ERROR, END)),
322       T_RETRY_DIP_FORWARD(RETRY_DIP_FORWARD, EnumSet.of(END, ERROR)),
323       T_ERROR(ERROR, EnumSet.of(ERROR, END)), T_END(END, EnumSet.of(END));
324 
325       private final Transition<DIPStep> elt;
326 
327       IngestTransition(DIPStep state, EnumSet<DIPStep> set) {
328         elt = new Transition<>(state, set);
329       }
330 
331     }
332   }
333 }