/*
 * Copyright (c) 2010-2018 Evolveum
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.evolveum.midpoint.model.impl.scripting;

import com.evolveum.midpoint.model.api.ModelPublicConstants;
import com.evolveum.midpoint.model.api.ScriptExecutionException;
import com.evolveum.midpoint.model.api.ScriptExecutionResult;
import com.evolveum.midpoint.model.api.ScriptingService;
import com.evolveum.midpoint.model.impl.util.AbstractSearchIterativeModelTaskHandler;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.repo.common.task.AbstractSearchIterativeResultHandler;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.task.api.TaskCategory;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.task.api.TaskRunResult;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExecuteScriptType;
import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ValueListType;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

import static java.util.Collections.emptyMap;

@Component
public class IterativeScriptExecutionTaskHandler extends AbstractSearchIterativeModelTaskHandler<ObjectType, AbstractSearchIterativeResultHandler<ObjectType>> {

    @Autowired private TaskManager taskManager;
	@Autowired private ScriptingService scriptingService;

	private static final transient Trace LOGGER = TraceManager.getTrace(IterativeScriptExecutionTaskHandler.class);

	public IterativeScriptExecutionTaskHandler() {
        super("Execute script", OperationConstants.EXECUTE_SCRIPT);
		setLogFinishInfo(true);     // todo
    }

	@PostConstruct
	private void initialize() {
		taskManager.registerHandler(ModelPublicConstants.ITERATIVE_SCRIPT_EXECUTION_TASK_HANDLER_URI, this);
	}

	protected Class<? extends ObjectType> getType(Task task) {
		return getTypeFromTask(task, ObjectType.class);
	}

	@NotNull
	@Override
	protected AbstractSearchIterativeResultHandler<ObjectType> createHandler(TaskRunResult runResult, final Task coordinatorTask,
			OperationResult opResult) {

		PrismProperty<ExecuteScriptType> executeScriptProperty = coordinatorTask.getExtensionProperty(SchemaConstants.SE_EXECUTE_SCRIPT);
		if (executeScriptProperty == null || executeScriptProperty.getValue().getValue() == null ||
				executeScriptProperty.getValue().getValue().getScriptingExpression() == null) {
			throw new IllegalStateException("There's no script to be run in task " + coordinatorTask + " (property " + SchemaConstants.SE_EXECUTE_SCRIPT + ")");
		}
		ExecuteScriptType executeScriptRequest = executeScriptProperty.getRealValue();
		if (executeScriptRequest.getInput() != null && !executeScriptRequest.getInput().getValue().isEmpty()) {
			LOGGER.warn("Ignoring input values in executeScript data in task {}", coordinatorTask);
		}

		AbstractSearchIterativeResultHandler<ObjectType> handler = new AbstractSearchIterativeResultHandler<ObjectType>(
				coordinatorTask, IterativeScriptExecutionTaskHandler.class.getName(), "execute", "execute task", taskManager) {
			@Override
			protected boolean handleObject(PrismObject<ObjectType> object, Task workerTask, OperationResult result) {
				try {
					executeScriptRequest.setInput(new ValueListType().value(object.asObjectable()));
					ScriptExecutionResult executionResult = scriptingService.evaluateExpression(executeScriptRequest, emptyMap(), workerTask, result);
					LOGGER.debug("Execution output: {} item(s)", executionResult.getDataOutput().size());
					LOGGER.debug("Execution result:\n{}", executionResult.getConsoleOutput());
					result.computeStatus();
				} catch (ScriptExecutionException | SecurityViolationException | SchemaException | ObjectNotFoundException | ExpressionEvaluationException | CommunicationException | ConfigurationException e) {
					result.recordFatalError("Couldn't execute script: " + e.getMessage(), e);
					LoggingUtils.logUnexpectedException(LOGGER, "Couldn't execute script", e);
				}
				executeScriptRequest.setInput(null);            // to avoid warnings above (during next bucket processing)
				return true;
			}
		};
        handler.setStopOnError(false);
        return handler;
	}

    @Override
    public String getCategoryName(Task task) {
        return TaskCategory.BULK_ACTIONS;
    }
}

@@ -3730,16 +3730,24 @@
 tRequest
+Template
  = execu
@@ -3797,32 +3797,40 @@
 uteScriptRequest
+Template
 .getInput() != n
@@ -3857,16 +3857,24 @@
 tRequest
+Template
 .getInpu
@@ -4360,16 +4360,100 @@
 %09%09try %7B%0A
+%09%09%09%09%09ExecuteScriptType executeScriptRequest = executeScriptRequestTemplate.clone();%0A
 %09%09%09%09%09exe
@@ -5233,119 +5233,8 @@
 %09%09%7D%0A
-%09%09%09%09executeScriptRequest.setInput(null);            // to avoid warnings above (during next bucket processing)%0A
 %09%09%09%09

Fix nasty multithreaded iterative scripting bug