Skip to content

Commit

Permalink
Cleaned up /rpc/executeScript API
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed May 16, 2017
1 parent 090ccee commit ba0427f
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 103 deletions.
Expand Up @@ -355,7 +355,7 @@
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="ScriptExecutionResultType">
<xsd:complexType name="ExecuteScriptResponseType">
<xsd:annotation>
<xsd:documentation>
Result of a single script execution.
Expand All @@ -365,20 +365,13 @@
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="dataOutput" type="s:PipelineDataType" minOccurs="0">
<xsd:element name="output" type="s:ExecuteScriptOutputType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Data output of the execution of the script.
Data and console output of the execution of the script.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="consoleOutput" type="xsd:string" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Text ("console") output of the execution of the script.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="result" type="c:OperationResultType">
<xsd:annotation>
<xsd:documentation>
Expand All @@ -388,7 +381,7 @@
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="scriptExecutionResult" type="tns:ScriptExecutionResultType"/>
<xsd:element name="executeScriptResponse" type="tns:ExecuteScriptResponseType"/>

<xsd:complexType name="ScriptOutputsType">
<xsd:sequence>
Expand Down Expand Up @@ -516,7 +509,7 @@
</xsd:element>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="PolicyItemsDefinitionType">
<xsd:annotation>
<xsd:documentation>
Expand Down
Expand Up @@ -47,14 +47,6 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:element>

<!--<xsd:element name="scriptInput" type="apit:ItemListType">-->
<!--<xsd:annotation>-->
<!--<xsd:appinfo>-->
<!--<a:maxOccurs>1</a:maxOccurs> &lt;!&ndash; TODO (maybe there could be more scripts) &ndash;&gt;-->
<!--</xsd:appinfo>-->
<!--</xsd:annotation>-->
<!--</xsd:element>-->

</xsd:schema>

Expand Down
Expand Up @@ -426,29 +426,25 @@
Value of a parameter for an action.
</xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="tns:ScriptingExpressionType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Parameter name.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:choice>
<xsd:element ref="c:value" minOccurs="0"/>
<xsd:element ref="tns:scriptingExpression" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Parameter (argument) value.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:choice>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
<xsd:sequence>
<xsd:element name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Parameter name.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:choice>
<xsd:element ref="c:value" minOccurs="0"/>
<xsd:element ref="tns:scriptingExpression" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Parameter (argument) value.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>

<!--
Expand All @@ -468,6 +464,35 @@
<xsd:element name="options" type="tns:ScriptingExpressionEvaluationOptionsType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="executeScript" type="tns:ExecuteScriptType" /> <!-- collides with executeScript in extension, but let's ignore it for the moment -->

<xsd:complexType name="ExecuteScriptOutputType">
<xsd:annotation>
<xsd:documentation>
Output of a single script execution.
</xsd:documentation>
<xsd:appinfo>
<a:since>3.6</a:since>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="dataOutput" type="tns:PipelineDataType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Data output of the execution of the script.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="consoleOutput" type="xsd:string" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Text ("console") output of the execution of the script.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="executeScriptOutput" type="tns:ExecuteScriptOutputType"/>

<xsd:complexType name="ValueListType">
<xsd:sequence>
Expand Down
Expand Up @@ -20,6 +20,8 @@
import com.evolveum.midpoint.model.api.validator.Scope;
import com.evolveum.midpoint.model.api.validator.ValidationResult;
import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor;
import com.evolveum.midpoint.model.impl.rest.Convertor;
import com.evolveum.midpoint.model.impl.rest.ConvertorInterface;
import com.evolveum.midpoint.model.impl.rest.PATCH;
import com.evolveum.midpoint.model.impl.security.SecurityHelper;
import com.evolveum.midpoint.model.impl.util.RestServiceUtil;
Expand All @@ -42,6 +44,7 @@
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.MidPointConstants;
import com.evolveum.midpoint.schema.constants.ObjectTypes;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.security.api.SecurityUtil;
import com.evolveum.midpoint.task.api.Task;
Expand All @@ -55,7 +58,8 @@
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ExecuteScriptsResponseType;
import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExecuteScriptOutputType;
import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExecuteScriptType;
import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType;
import com.evolveum.prism.xml.ns._public.query_3.QueryType;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;
Expand All @@ -64,13 +68,15 @@
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.Validate;
import org.apache.cxf.jaxrs.ext.MessageContext;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import java.net.URI;
import java.util.ArrayList;
Expand Down Expand Up @@ -974,29 +980,29 @@ public Response suspendTasks(@PathParam("oid") String taskOid, @Context MessageC

// @DELETE
// @Path("tasks/{oid}/suspend")
public Response suspendAndDeleteTasks(@PathParam("oid") String taskOid, @Context MessageContext mc) {

Task task = RestServiceUtil.initRequest(mc);
OperationResult parentResult = task.getResult().createSubresult(OPERATION_SUSPEND_AND_DELETE_TASKS);

Response response;
Collection<String> taskOids = MiscUtil.createCollection(taskOid);
try {
model.suspendAndDeleteTasks(taskOids, WAIT_FOR_TASK_STOP, true, parentResult);

parentResult.computeStatus();
if (parentResult.isSuccess()) {
response = Response.accepted().build();
} else {
response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(parentResult.getMessage()).build();
}
} catch (Exception ex) {
response = RestServiceUtil.handleException(parentResult, ex);
}

finishRequest(task);
return response;
}
// public Response suspendAndDeleteTasks(@PathParam("oid") String taskOid, @Context MessageContext mc) {
//
// Task task = RestServiceUtil.initRequest(mc);
// OperationResult parentResult = task.getResult().createSubresult(OPERATION_SUSPEND_AND_DELETE_TASKS);
//
// Response response;
// Collection<String> taskOids = MiscUtil.createCollection(taskOid);
// try {
// model.suspendAndDeleteTasks(taskOids, WAIT_FOR_TASK_STOP, true, parentResult);
//
// parentResult.computeStatus();
// if (parentResult.isSuccess()) {
// response = Response.accepted().build();
// } else {
// response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(parentResult.getMessage()).build();
// }
// } catch (Exception ex) {
// response = RestServiceUtil.handleException(parentResult, ex);
// }
//
// finishRequest(task);
// return response;
// }

@POST
@Path("/tasks/{oid}/resume")
Expand Down Expand Up @@ -1054,47 +1060,56 @@ public Response scheduleTasksNow(@PathParam("oid") String taskOid, @Context Mess
return response;
}

public static class ExecuteScriptConvertor implements ConvertorInterface {
public ExecuteScriptType convert(@NotNull Object input) {
if (input instanceof ExecuteScriptType) {
return (ExecuteScriptType) input;
} else if (input instanceof ScriptingExpressionType) {
ScriptingExpressionType expression = (ScriptingExpressionType) input;
ExecuteScriptType command = new ExecuteScriptType();
@SuppressWarnings({ "unchecked", "raw" })
Class<ScriptingExpressionType> declaredClass = (Class<ScriptingExpressionType>) expression.getClass();
command.setScriptingExpression(new JAXBElement<>(SchemaConstants.C_VALUE, declaredClass, expression));
return command;
} else {
throw new IllegalArgumentException("Wrong input value: " + input);
}
}
}

@POST
@Path("/rpc/executeScript")
// @Produces({"text/html", "application/xml"})
@Consumes({"application/xml" })
public <T extends ObjectType> Response executeScript(ScriptingExpressionType scriptingExpression,
@QueryParam("asynchronous") Boolean asynchronous,
@Context UriInfo uriInfo, @Context MessageContext mc) {
public Response executeScript(@Convertor(ExecuteScriptConvertor.class) ExecuteScriptType command,
@QueryParam("asynchronous") Boolean asynchronous, @Context UriInfo uriInfo, @Context MessageContext mc) {

Task task = RestServiceUtil.initRequest(mc);
OperationResult result = task.getResult().createSubresult(OPERATION_EXECUTE_SCRIPT);

String oid;
Response response;
try {
ResponseBuilder builder;
if (Boolean.TRUE.equals(asynchronous)) {
scriptingService.evaluateExpression(scriptingExpression, task, result);
scriptingService.evaluateExpression(command, task, result);
URI resourceUri = uriInfo.getAbsolutePathBuilder().path(task.getOid()).build(task.getOid());
builder = Response.created(resourceUri);
} else {
ScriptExecutionResult executionResult = scriptingService.evaluateExpression(scriptingExpression, task, result);

ExecuteScriptsResponseType operationOutput = new ExecuteScriptsResponseType();
operationOutput.setResult(result.createOperationResultType());
ScriptOutputsType outputs = new ScriptOutputsType();
operationOutput.setOutputs(outputs);
SingleScriptOutputType output = new SingleScriptOutputType();
output.setTextOutput(executionResult.getConsoleOutput());
output.setDataOutput(ModelWebService.prepareXmlData(executionResult.getDataOutput()));
outputs.getOutput().add(output);
ScriptExecutionResult executionResult = scriptingService.evaluateExpression(command, task, result);

ExecuteScriptResponseType responseData = new ExecuteScriptResponseType()
.result(result.createOperationResultType())
.output(new ExecuteScriptOutputType()
.consoleOutput(executionResult.getConsoleOutput())
.dataOutput(ModelWebService.prepareXmlData(executionResult.getDataOutput())));
builder = Response.ok();
builder.entity(operationOutput);
builder.entity(responseData);
}

response = builder.build();
} catch (Exception ex) {
response = RestServiceUtil.handleException(result, ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't execute script.", ex);
}

result.computeStatus();
finishRequest(task);
return response;
Expand Down
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2010-2017 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.rest;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* @author mederly
*/
@Target({ ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Convertor {

Class<? extends ConvertorInterface> value();
}
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2010-2017 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.rest;

import org.jetbrains.annotations.NotNull;

/**
* @author mederly
*/
public interface ConvertorInterface {

/**
* Converts incoming object into a form that is consumable by the REST service.
*
* @param input Object to be converted (coming as input)
* @return Object to be passed to the REST service.
*/
Object convert(@NotNull Object input);
}

0 comments on commit ba0427f

Please sign in to comment.