/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Portions copyright 2012-2015 ForgeRock AS.
*/
package org.forgerock.openidm.scheduler.impl;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.script.ScriptException;
import org.forgerock.services.context.Context;
import org.forgerock.json.JsonPointer;
import org.forgerock.json.JsonValue;
import org.forgerock.openidm.util.ConfigMacroUtil;
import org.forgerock.script.ScriptEntry;
import org.joda.time.Days;
import org.joda.time.ReadablePeriod;
/**
* Represents the information for a recurring {@link org.forgerock.openidm.scheduler.impl.TaskScannerJob}.
*
* This is carried over across all instances of the {@link org.forgerock.openidm.scheduler.impl.TaskScannerJob}
*/
public class TaskScannerContext {
enum TaskScannerState {
INITIALIZED,
ACTIVE,
COMPLETED,
CANCELLED,
ERROR
}
private String invokerName;
private String scriptName;
private JsonValue params;
private Context context;
private boolean canceled = false;
private TaskScannerStatistic statistics;
private TaskScannerState state;
private ScriptEntry scriptEntry;
public TaskScannerContext(String invokerName,
String scriptName,
JsonValue params,
Context context,
ScriptEntry scriptEntry)
throws ScriptException {
this.invokerName = invokerName;
this.scriptName = scriptName;
this.params = params;
this.context = context;
this.statistics = new TaskScannerStatistic();
this.state = TaskScannerState.INITIALIZED;
this.scriptEntry = scriptEntry;
}
public void startJob() {
state = TaskScannerState.ACTIVE;
statistics.jobStart();
}
public void endJob() {
state = TaskScannerState.COMPLETED;
statistics.jobEnd();
}
public void startQuery() {
statistics.queryStart();
}
public void endQuery() {
statistics.queryEnd();
}
public void cancel() {
state = TaskScannerState.CANCELLED;
this.canceled = true;
}
public void interrupted() {
state = TaskScannerState.ERROR;
}
public boolean isStarted() {
return state == TaskScannerState.ACTIVE;
}
public boolean isCompleted() {
return state == TaskScannerState.COMPLETED;
}
public boolean hasError() {
return state == TaskScannerState.ERROR;
}
public boolean isInactive() {
return !isStarted();
}
public boolean isCanceled() {
return this.canceled;
}
public String getState() {
return state.toString();
}
public void setNumberOfTasksToProcess(int number) {
statistics.setNumberOfTasksToProcess(number);
}
public Context getContext() {
return this.context;
}
public JsonValue getParams() {
return this.params;
}
public String getInvokerName() {
return this.invokerName;
}
public String getScriptName() {
return this.scriptName;
}
public ScriptEntry getScriptEntry() {
return this.scriptEntry;
}
public String getTaskScanID() {
return context.getId();
}
/**
* Retrieve the timeout period from the supplied config.
*
* @return the timeout period taken from the config
*/
public ReadablePeriod getRecoveryTimeout() {
String timeoutStr = getScanValue().get("recovery").get("timeout").asString();
// Default to a 0-Day period if there's nothing to add
if (timeoutStr == null) {
return Days.days(0);
}
return ConfigMacroUtil.getTimePeriod(timeoutStr);
}
public Integer getMaxRecords() {
return params.get("maxRecords").asInteger();
}
public JsonValue getScanValue() {
return params.get("scan").expect(Map.class);
}
public String getObjectID() {
return getScanValue().get("object").required().asString();
}
public JsonPointer getStartField() {
return getTaskStatePointer(getScanValue(), "started");
}
public JsonPointer getCompletedField() {
return getTaskStatePointer(getScanValue(), "completed");
}
public boolean getWaitForCompletion() {
JsonValue waitParam = params.get("waitForCompletion").defaultTo("false");
Boolean waitForCompletion = Boolean.FALSE;
if (waitParam.isBoolean()) {
waitForCompletion = waitParam.asBoolean();
} else {
waitForCompletion = Boolean.parseBoolean(waitParam.asString());
}
return waitForCompletion.booleanValue();
}
public int getNumberOfThreads() {
JsonValue numParams = params.get("numberOfThreads").defaultTo(10);
return numParams.asInteger();
}
public TaskScannerStatistic getStatistics() {
return this.statistics;
}
public Map<String, Object> getProgress() {
Map<String, Object> progress = new LinkedHashMap<String, Object>();
progress.put("state", state);
progress.put("processed", statistics.getNumberOfTasksProcessed());
progress.put("total", statistics.getNumberOfTasksToProcess());
progress.put("successes", statistics.getNumberOfTasksSucceeded());
progress.put("failures", statistics.getNumberOfTasksFailed());
return progress;
}
/**
* Fetches a JsonPointer from the "taskState" object in value
* @param value JsonValue to fetch the pointer from
* @param field the subfield to fetch from the taskState object
* @return the JsonPointer contained within the "taskState/${field}" object
*/
private JsonPointer getTaskStatePointer(JsonValue value, String field) {
return value.get("taskState").required().get(field).required().asPointer();
}
}