DipRequest.java
/*
* This file is part of Waarp Project (named also Waarp or GG).
*
* Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
* tags. See the COPYRIGHT.txt in the distribution for a full listing of
* individual contributors.
*
* All Waarp Project is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Waarp . If not, see <http://www.gnu.org/licenses/>.
*/
package org.waarp.vitam.dip;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.JsonNode;
import fr.gouv.vitam.common.GlobalDataRest;
import fr.gouv.vitam.common.ParametersChecker;
import fr.gouv.vitam.common.StringUtils;
import fr.gouv.vitam.common.database.builder.query.VitamFieldsHelper;
import fr.gouv.vitam.common.exception.InvalidParseOperationException;
import fr.gouv.vitam.common.json.JsonHandler;
import fr.gouv.vitam.common.model.RequestResponseOK;
import org.waarp.common.exception.IllegalFiniteStateException;
import org.waarp.common.logging.WaarpLogger;
import org.waarp.common.logging.WaarpLoggerFactory;
import org.waarp.common.state.MachineState;
import org.waarp.common.state.Transition;
import org.waarp.vitam.common.AbstractVitamRequest;
import org.waarp.vitam.common.WaarpCommon.TaskOption;
import java.io.File;
import java.util.EnumSet;
import java.util.concurrent.ConcurrentHashMap;
public class DipRequest extends AbstractVitamRequest {
/**
* Internal Logger
*/
private static final WaarpLogger logger =
WaarpLoggerFactory.getLogger(DipRequest.class);
@JsonIgnore
MachineState<DIPStep> step = DIPStep.newSessionMachineState();
public DipRequest() {
// Empty constructor for Json
}
/**
* Standard constructor
*
* @param taskOption
* @param factory
*
* @throws InvalidParseOperationException
*/
public DipRequest(final TaskOption taskOption,
final DipRequestFactory factory)
throws InvalidParseOperationException {
super(taskOption);
this.status = this.step.getCurrent().getStatusMonitor();
try {
factory.saveNewDipRequest(this);
} catch (InvalidParseOperationException e) {
logger.error("Will not be able to save: {}", this, e);
throw e;
}
}
@Override
public String toString() {
return "DIP = Step: " + (step != null? step.getCurrent() : "noStep") + " " +
JsonHandler.unprettyPrint(this);
}
/**
* Set extra information from first response from operation submission
*
* @param requestResponse
*
* @return this
*/
@JsonIgnore
public DipRequest setFromRequestResponse(RequestResponseOK requestResponse) {
String requestIdNew =
requestResponse.getHeaderString(GlobalDataRest.X_REQUEST_ID);
// Shall be the same but get from Result preferred
JsonNode node = (JsonNode) requestResponse.getFirstResult();
if (node != null) {
node = node.get(VitamFieldsHelper.id());
if (node != null) {
requestIdNew = node.asText();
}
}
try {
ParametersChecker.checkParameterDefault(getCheckMessage(), requestIdNew);
StringUtils.checkSanityString(requestIdNew);
} catch (InvalidParseOperationException | IllegalArgumentException e) {
logger.error(e);
throw new IllegalArgumentException(e.getMessage(), e);
}
setRequestId(requestIdNew);
return this;
}
/**
* Use to set the step and status accordingly.
*
* @param step
* @param status
* @param factory
*
* @return this
*
* @throws InvalidParseOperationException
*/
@JsonIgnore
public DipRequest setStep(final DIPStep step, final int status,
DipRequestFactory factory)
throws InvalidParseOperationException {
if (this.step == null) {
if (!step.equals(DIPStep.END)) {
logger.debug("Step {} could not be set since IngestRequest done", step);
}
// Nothing to do since already done
return this;
}
if (!step.equals(DIPStep.ERROR) && this.step.getCurrent().equals(step)) {
// nothing to do
return this;
}
try {
this.step.setCurrent(step);
} catch (IllegalFiniteStateException e) {
logger.error(e);
this.step.setDryCurrent(step);
}
setStatus(step != DIPStep.ERROR? step.getStatusMonitor() : status)
.setLastTryTime(System.currentTimeMillis());
return save(factory);
}
/**
* Set the status AND the step according to the value of the status (if
* less than 0, it is a step value, not a final status), but in dry mode
* (no check, used by Json deserialization)
*
* @param status
*
* @return this
*/
@JsonSetter("status")
public DipRequest setStatus(final int status) {
this.status = status;
if (step != null) {
step.setDryCurrent(DIPStep.getFromInt(status));
}
return this;
}
/**
* Save this DipRequest
*
* @param factory
*
* @return this
*
* @throws InvalidParseOperationException
*/
@JsonIgnore
public DipRequest save(DipRequestFactory factory)
throws InvalidParseOperationException {
factory.saveDipRequest(this);
return this;
}
@JsonIgnore
public DIPStep getStep() {
if (step == null) {
return null;
}
return step.getCurrent();
}
/**
* @return the DIP File pointer according to this
*/
@JsonIgnore
public File getDipFile(DipRequestFactory factory) {
return factory.getDipFile(this);
}
/**
* @return the Error File pointer according to this
*/
@JsonIgnore
public File getErrorFile(DipRequestFactory factory) {
return factory.getErrorFile(this);
}
/**
* @return the JsonNode for Vitam Request associated with this
*
* @throws InvalidParseOperationException
*/
@JsonIgnore
public JsonNode getSelectJson() throws InvalidParseOperationException {
String path = getPath();
return JsonHandler.getFromFile(new File(path));
}
/**
* Different steps of DIP export from Waarp point of view
*/
enum DIPStep {
/**
* DipRequest not started yet
*/
STARTUP(-1),
/**
* DipRequest SELECT to retry
*/
RETRY_SELECT(-2),
/**
* DipRequest DIP get to retry
*/
RETRY_DIP(-3),
/**
* DipRequest DIP to forward
*/
RETRY_DIP_FORWARD(-4),
/**
* For Ingest compatibility
*/
NO_STEP(-5),
/**
* DipRequest Error
*/
ERROR(-7),
/**
* Final End step
*/
END(-10);
private static final ConcurrentHashMap<DIPStep, EnumSet<DIPStep>> stateMap =
new ConcurrentHashMap<>();
static {
initR66FiniteStates();
}
private final int statusMonitor;
DIPStep(int status) {
this.statusMonitor = status;
}
/**
* This method should be called once at startup to initialize the Finite
* States association.
*/
private static void initR66FiniteStates() {
for (final DIPStep.IngestTransition trans : DIPStep.IngestTransition
.values()) {
stateMap.put(trans.elt.getState(), trans.elt.getSet());
}
}
/**
* @return a new Session MachineState for OpenR66
*/
private static MachineState<DIPStep> newSessionMachineState() {
return new MachineState<>(STARTUP, stateMap);
}
/**
* @param machine the Session MachineState to release
*/
static void endSessionMachineSate(MachineState<DIPStep> machine) {
if (machine != null) {
machine.release();
}
}
static DIPStep getFromInt(int status) {
switch (status) {
case -1:
return STARTUP;
case -2:
return RETRY_SELECT;
case -3:
return RETRY_DIP;
case -4:
return RETRY_DIP_FORWARD;
case -5:
return NO_STEP;
case -10:
return END;
case -7:
default:
return ERROR;
}
}
int getStatusMonitor() {
return statusMonitor;
}
private enum IngestTransition {
T_STARTUP(STARTUP, EnumSet.of(RETRY_SELECT, ERROR)),
T_RETRY_SELECT(RETRY_SELECT, EnumSet.of(RETRY_DIP, ERROR)),
T_RETRY_DIP(RETRY_DIP, EnumSet.of(RETRY_DIP_FORWARD, ERROR, END)),
T_RETRY_DIP_FORWARD(RETRY_DIP_FORWARD, EnumSet.of(END, ERROR)),
T_ERROR(ERROR, EnumSet.of(ERROR, END)), T_END(END, EnumSet.of(END));
private final Transition<DIPStep> elt;
IngestTransition(DIPStep state, EnumSet<DIPStep> set) {
elt = new Transition<>(state, set);
}
}
}
}