This commit is contained in:
22
opentcs-kernel-extension-http-services/build.gradle
Normal file
22
opentcs-kernel-extension-http-services/build.gradle
Normal file
@@ -0,0 +1,22 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
apply from: "${rootDir}/gradle/java-project.gradle"
|
||||
apply from: "${rootDir}/gradle/java-codequality.gradle"
|
||||
apply from: "${rootDir}/gradle/guice-project.gradle"
|
||||
apply from: "${rootDir}/gradle/publishing-java.gradle"
|
||||
|
||||
dependencies {
|
||||
api project(':opentcs-api-injection')
|
||||
api project(':opentcs-common')
|
||||
|
||||
api group: 'com.sparkjava', name: 'spark-core', version: '2.9.4'
|
||||
|
||||
api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.0'
|
||||
api group: 'com.fasterxml.jackson.module', name: 'jackson-module-jsonSchema', version: '2.18.0'
|
||||
api group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.18.0'
|
||||
}
|
||||
|
||||
task release {
|
||||
dependsOn build
|
||||
}
|
||||
40
opentcs-kernel-extension-http-services/gradle.properties
Normal file
40
opentcs-kernel-extension-http-services/gradle.properties
Normal file
@@ -0,0 +1,40 @@
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapAnnotationArgs=WRAP_IF_LONG
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineMethodParams=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapAfterDotInChainedMethodCalls=false
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineDisjunctiveCatchTypes=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineFor=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineImplements=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapFor=WRAP_IF_LONG
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.sortMembersByVisibility=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.visibilityOrder=PUBLIC;PROTECTED;DEFAULT;PRIVATE
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeFinallyOnNewLine=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapMethodParams=WRAP_IF_LONG
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.enable-indent=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineArrayInit=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineCallArgs=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapDisjunctiveCatchTypes=WRAP_IF_LONG
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.keepGettersAndSettersTogether=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapExtendsImplementsList=WRAP_ALWAYS
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapThrowsKeyword=WRAP_ALWAYS
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapExtendsImplementsKeyword=WRAP_ALWAYS
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classMembersOrder=STATIC FIELD;FIELD;STATIC_INIT;CONSTRUCTOR;INSTANCE_INIT;STATIC METHOD;METHOD;STATIC CLASS;CLASS
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapEnumConstants=WRAP_ALWAYS
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapCommentText=false
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapThrowsList=WRAP_IF_LONG
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapAssert=WRAP_IF_LONG
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder=*
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.continuationIndentSize=4
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeElseOnNewLine=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeCatchOnNewLine=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineAnnotationArgs=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineTryResources=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.preserveNewLinesInComments=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineParenthesized=true
|
||||
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineThrows=true
|
||||
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap=none
|
||||
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width=2
|
||||
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab=2
|
||||
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=2
|
||||
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=100
|
||||
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs=true
|
||||
netbeans.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project
|
||||
@@ -0,0 +1,48 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.adminwebapi;
|
||||
|
||||
import jakarta.inject.Singleton;
|
||||
import org.opentcs.customizations.kernel.KernelInjectionModule;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Configures the admin web API extension.
|
||||
*/
|
||||
public class AdminWebApiModule
|
||||
extends
|
||||
KernelInjectionModule {
|
||||
|
||||
/**
|
||||
* This class's logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AdminWebApiModule.class);
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public AdminWebApiModule() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
AdminWebApiConfiguration configuration
|
||||
= getConfigBindingProvider().get(
|
||||
AdminWebApiConfiguration.PREFIX,
|
||||
AdminWebApiConfiguration.class
|
||||
);
|
||||
|
||||
if (!configuration.enable()) {
|
||||
LOG.info("Admin web API disabled by configuration.");
|
||||
return;
|
||||
}
|
||||
|
||||
bind(AdminWebApiConfiguration.class)
|
||||
.toInstance(configuration);
|
||||
|
||||
extensionsBinderAllModes().addBinding()
|
||||
.to(AdminWebApi.class)
|
||||
.in(Singleton.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import jakarta.inject.Singleton;
|
||||
import org.opentcs.customizations.kernel.KernelInjectionModule;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Configures the service web API extension.
|
||||
*/
|
||||
public class ServiceWebApiModule
|
||||
extends
|
||||
KernelInjectionModule {
|
||||
|
||||
/**
|
||||
* This class's logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServiceWebApiModule.class);
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public ServiceWebApiModule() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
ServiceWebApiConfiguration configuration
|
||||
= getConfigBindingProvider().get(
|
||||
ServiceWebApiConfiguration.PREFIX,
|
||||
ServiceWebApiConfiguration.class
|
||||
);
|
||||
|
||||
if (!configuration.enable()) {
|
||||
LOG.info("Service web API disabled by configuration.");
|
||||
return;
|
||||
}
|
||||
|
||||
bind(ServiceWebApiConfiguration.class)
|
||||
.toInstance(configuration);
|
||||
|
||||
extensionsBinderAllModes().addBinding()
|
||||
.to(ServiceWebApi.class)
|
||||
.in(Singleton.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: The openTCS Authors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
org.opentcs.kernel.extensions.adminwebapi.AdminWebApiModule
|
||||
org.opentcs.kernel.extensions.servicewebapi.ServiceWebApiModule
|
||||
@@ -0,0 +1,98 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.adminwebapi;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.opentcs.components.kernel.KernelExtension;
|
||||
import org.opentcs.kernel.extensions.adminwebapi.v1.V1RequestHandler;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.HttpConstants;
|
||||
import spark.Service;
|
||||
|
||||
/**
|
||||
* Provides an HTTP interface for basic administration needs.
|
||||
*/
|
||||
public class AdminWebApi
|
||||
implements
|
||||
KernelExtension {
|
||||
|
||||
/**
|
||||
* The interface configuration.
|
||||
*/
|
||||
private final AdminWebApiConfiguration configuration;
|
||||
/**
|
||||
* Handles requests for API version 1.
|
||||
*/
|
||||
private final V1RequestHandler v1RequestHandler;
|
||||
/**
|
||||
* The actual HTTP service.
|
||||
*/
|
||||
private Service service;
|
||||
/**
|
||||
* Whether this kernel extension is initialized.
|
||||
*/
|
||||
private boolean initialized;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param configuration The interface configuration.
|
||||
* @param v1RequestHandler Handles requests for API version 1.
|
||||
*/
|
||||
@Inject
|
||||
public AdminWebApi(
|
||||
AdminWebApiConfiguration configuration,
|
||||
V1RequestHandler v1RequestHandler
|
||||
) {
|
||||
this.configuration = requireNonNull(configuration, "configuration");
|
||||
this.v1RequestHandler = requireNonNull(v1RequestHandler, "v1RequestHandler");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
service = Service.ignite()
|
||||
.ipAddress(configuration.bindAddress())
|
||||
.port(configuration.bindPort());
|
||||
|
||||
service.path("/v1", () -> {
|
||||
service.get("/version", v1RequestHandler::handleGetVersion);
|
||||
service.get("/status", v1RequestHandler::handleGetStatus);
|
||||
service.delete("/kernel", v1RequestHandler::handleDeleteKernel);
|
||||
}
|
||||
);
|
||||
service.exception(IllegalArgumentException.class, (exception, request, response) -> {
|
||||
response.status(400);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
response.body(exception.getMessage());
|
||||
});
|
||||
service.exception(IllegalStateException.class, (exception, request, response) -> {
|
||||
response.status(500);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
response.body(exception.getMessage());
|
||||
});
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
if (!isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
service.stop();
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.adminwebapi;
|
||||
|
||||
import org.opentcs.configuration.ConfigurationEntry;
|
||||
import org.opentcs.configuration.ConfigurationPrefix;
|
||||
|
||||
/**
|
||||
* Configuration entries for the administration web API.
|
||||
*/
|
||||
@ConfigurationPrefix(AdminWebApiConfiguration.PREFIX)
|
||||
public interface AdminWebApiConfiguration {
|
||||
|
||||
/**
|
||||
* The prefix for all configuration entries here.
|
||||
*/
|
||||
String PREFIX = "adminwebapi";
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Boolean",
|
||||
description = "Whether to enable the admin interface.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
|
||||
orderKey = "0"
|
||||
)
|
||||
boolean enable();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "IP address",
|
||||
description = "Address to which to bind the HTTP server, e.g. 0.0.0.0. (Default: 127.0.0.1.)",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
|
||||
orderKey = "1"
|
||||
)
|
||||
String bindAddress();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Integer",
|
||||
description = "Port to which to bind the HTTP server.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
|
||||
orderKey = "2"
|
||||
)
|
||||
int bindPort();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.adminwebapi.v1;
|
||||
|
||||
/**
|
||||
* Describes the kernel process's current status.
|
||||
*/
|
||||
public class Status {
|
||||
|
||||
private String heapSize = String.valueOf(Runtime.getRuntime().totalMemory());
|
||||
|
||||
private String maxHeapSize = String.valueOf(Runtime.getRuntime().maxMemory());
|
||||
|
||||
private String freeInHeap = String.valueOf(Runtime.getRuntime().freeMemory());
|
||||
|
||||
public Status() {
|
||||
}
|
||||
|
||||
public String getHeapSize() {
|
||||
return heapSize;
|
||||
}
|
||||
|
||||
public void setHeapSize(String heapSize) {
|
||||
this.heapSize = heapSize;
|
||||
}
|
||||
|
||||
public String getMaxHeapSize() {
|
||||
return maxHeapSize;
|
||||
}
|
||||
|
||||
public void setMaxHeapSize(String maxHeapSize) {
|
||||
this.maxHeapSize = maxHeapSize;
|
||||
}
|
||||
|
||||
public String getFreeInHeap() {
|
||||
return freeInHeap;
|
||||
}
|
||||
|
||||
public void setFreeInHeap(String freeInHeap) {
|
||||
this.freeInHeap = freeInHeap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.adminwebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.opentcs.access.Kernel;
|
||||
import org.opentcs.access.LocalKernel;
|
||||
import org.opentcs.components.Lifecycle;
|
||||
import org.opentcs.customizations.kernel.KernelExecutor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
|
||||
/**
|
||||
* Handles requests and produces responses for version 1 of the admin web API.
|
||||
*/
|
||||
public class V1RequestHandler
|
||||
implements
|
||||
Lifecycle {
|
||||
|
||||
/**
|
||||
* This class's logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(V1RequestHandler.class);
|
||||
/**
|
||||
* Maps between objects and their JSON representations.
|
||||
*/
|
||||
private final ObjectMapper objectMapper
|
||||
= new ObjectMapper()
|
||||
.registerModule(new JavaTimeModule())
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
/**
|
||||
* The local kernel.
|
||||
*/
|
||||
private final LocalKernel kernel;
|
||||
/**
|
||||
* Used to schedule kernel shutdowns.
|
||||
*/
|
||||
private final ScheduledExecutorService kernelExecutor;
|
||||
/**
|
||||
* Whether this instance is initialized.
|
||||
*/
|
||||
private boolean initialized;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param kernel The local kernel.
|
||||
* @param kernelExecutor Use to schedule kernel shutdowns.
|
||||
*/
|
||||
@Inject
|
||||
public V1RequestHandler(
|
||||
LocalKernel kernel,
|
||||
@KernelExecutor
|
||||
ScheduledExecutorService kernelExecutor
|
||||
) {
|
||||
this.kernel = requireNonNull(kernel, "kernel");
|
||||
this.kernelExecutor = requireNonNull(kernelExecutor, "kernelExecutor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
if (!isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
public Object handleGetVersion(Request request, Response response) {
|
||||
return toJson(new Version());
|
||||
}
|
||||
|
||||
public Object handleGetStatus(Request request, Response response) {
|
||||
return toJson(new Status());
|
||||
}
|
||||
|
||||
public Object handleDeleteKernel(Request request, Response response) {
|
||||
LOG.info("Initiating kernel shutdown as requested from {}...", request.ip());
|
||||
kernelExecutor.schedule(() -> kernel.setState(Kernel.State.SHUTDOWN), 1, TimeUnit.SECONDS);
|
||||
return "";
|
||||
}
|
||||
|
||||
private <T> T fromJson(String jsonString, Class<T> clazz)
|
||||
throws IllegalArgumentException {
|
||||
try {
|
||||
return objectMapper.readValue(jsonString, clazz);
|
||||
}
|
||||
catch (IOException exc) {
|
||||
throw new IllegalArgumentException("Could not parse JSON input", exc);
|
||||
}
|
||||
}
|
||||
|
||||
private String toJson(Object object)
|
||||
throws IllegalStateException {
|
||||
try {
|
||||
return objectMapper
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(object);
|
||||
}
|
||||
catch (JsonProcessingException exc) {
|
||||
throw new IllegalStateException("Could not produce JSON output", exc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.adminwebapi.v1;
|
||||
|
||||
import org.opentcs.util.Environment;
|
||||
|
||||
/**
|
||||
* Describes the version of the running kernel.
|
||||
*/
|
||||
public class Version {
|
||||
|
||||
private String baselineVersion = Environment.getBaselineVersion();
|
||||
|
||||
private String customizationName = Environment.getCustomizationName();
|
||||
|
||||
private String customizationVersion = Environment.getCustomizationVersion();
|
||||
|
||||
public Version() {
|
||||
}
|
||||
|
||||
public String getBaselineVersion() {
|
||||
return baselineVersion;
|
||||
}
|
||||
|
||||
public void setBaselineVersion(String baselineVersion) {
|
||||
this.baselineVersion = baselineVersion;
|
||||
}
|
||||
|
||||
public String getCustomizationName() {
|
||||
return customizationName;
|
||||
}
|
||||
|
||||
public void setCustomizationName(String customizationName) {
|
||||
this.customizationName = customizationName;
|
||||
}
|
||||
|
||||
public String getCustomizationVersion() {
|
||||
return customizationVersion;
|
||||
}
|
||||
|
||||
public void setCustomizationVersion(String customizationVersion) {
|
||||
this.customizationVersion = customizationVersion;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.Objects;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import spark.Request;
|
||||
|
||||
/**
|
||||
* Authenticates incoming requests.
|
||||
*/
|
||||
public class Authenticator {
|
||||
|
||||
/**
|
||||
* This class's logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Authenticator.class);
|
||||
/**
|
||||
* Defines the required access rules.
|
||||
*/
|
||||
private final ServiceWebApiConfiguration configuration;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param configuration Defines the required access rules.
|
||||
*/
|
||||
@Inject
|
||||
public Authenticator(ServiceWebApiConfiguration configuration) {
|
||||
this.configuration = requireNonNull(configuration, "configuration");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether authentication is required and the given request is authenticated.
|
||||
*
|
||||
* @param request The request to be checked.
|
||||
* @return <code>true</code> if, and only if, authentication is required and the given request is
|
||||
* authenticated.
|
||||
*/
|
||||
public boolean isAuthenticated(Request request) {
|
||||
requireNonNull(request, "request");
|
||||
|
||||
String requestAccessKey = request.headers(HttpConstants.HEADER_NAME_ACCESS_KEY);
|
||||
LOG.debug(
|
||||
"Provided access key in header is '{}', required value is '{}'",
|
||||
requestAccessKey,
|
||||
configuration.accessKey()
|
||||
);
|
||||
|
||||
// Any empty access key indicates authentication is not required.
|
||||
if (Strings.isNullOrEmpty(configuration.accessKey())) {
|
||||
LOG.debug("No access key, authentication not required.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return Objects.equals(requestAccessKey, configuration.accessKey());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
/**
|
||||
* Defines some HTTP-related constants.
|
||||
*/
|
||||
public class HttpConstants {
|
||||
|
||||
/**
|
||||
* Name of the header that is expected to contain the API access keys.
|
||||
*/
|
||||
public static final String HEADER_NAME_ACCESS_KEY = "X-Api-Access-Key";
|
||||
/**
|
||||
* Content type for plain text.
|
||||
*/
|
||||
public static final String CONTENT_TYPE_TEXT_PLAIN_UTF8 = "text/plain; charset=utf-8";
|
||||
/**
|
||||
* Content type for JSON structures.
|
||||
*/
|
||||
public static final String CONTENT_TYPE_APPLICATION_JSON_UTF8 = "application/json; charset=utf-8";
|
||||
|
||||
/**
|
||||
* Prevents instantiation.
|
||||
*/
|
||||
private HttpConstants() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Binds JSON strings to objects and vice versa.
|
||||
*/
|
||||
public class JsonBinder {
|
||||
|
||||
/**
|
||||
* Maps between objects and their JSON representations.
|
||||
*/
|
||||
private final ObjectMapper objectMapper
|
||||
= new ObjectMapper()
|
||||
.registerModule(new JavaTimeModule())
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public JsonBinder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given JSON string to an object.
|
||||
*
|
||||
* @param <T> The type of object to map to.
|
||||
* @param jsonString The JSON string.
|
||||
* @param clazz The type of object to map to.
|
||||
* @return The object created from the JSON string.
|
||||
* @throws IllegalArgumentException In case there was a problem mapping the given object from
|
||||
* JSON.
|
||||
* (An IllegalArgumentException is mapped to HTTP status code 400, indicating a client error.)
|
||||
*/
|
||||
public <T> T fromJson(String jsonString, Class<T> clazz)
|
||||
throws IllegalArgumentException {
|
||||
try {
|
||||
return objectMapper.readValue(jsonString, clazz);
|
||||
}
|
||||
catch (IOException exc) {
|
||||
throw new IllegalArgumentException("Could not parse JSON input", exc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given object to a JSON string.
|
||||
*
|
||||
* @param object The object to be mapped.
|
||||
* @return The JSON string representation of the object.
|
||||
* @throws IllegalStateException In case there was a problem mapping the given object to JSON.
|
||||
* (An IllegalStateException is mapped to HTTP status code 500, indicating an internal error.)
|
||||
*/
|
||||
public String toJson(Object object)
|
||||
throws IllegalStateException {
|
||||
try {
|
||||
return objectMapper
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(object);
|
||||
}
|
||||
catch (JsonProcessingException exc) {
|
||||
throw new IllegalStateException("Could not produce JSON output", exc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given throwable to a JSON string.
|
||||
*
|
||||
* @param t The throwable to be mapped.
|
||||
* @return A JSON string for the given throwable, consisting of a single-element array containing
|
||||
* the throwable's message.
|
||||
* @throws IllegalStateException In case there was a problem mapping the given object to JSON.
|
||||
* (An IllegalStateException is mapped to HTTP status code 500, indicating an internal error.)
|
||||
*/
|
||||
public String toJson(Throwable t)
|
||||
throws IllegalStateException {
|
||||
try {
|
||||
return objectMapper
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(objectMapper.createArrayNode().add(t.getMessage()));
|
||||
}
|
||||
catch (JsonProcessingException exc) {
|
||||
throw new IllegalStateException("Could not produce JSON output", exc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.opentcs.access.KernelRuntimeException;
|
||||
import org.opentcs.customizations.kernel.KernelExecutor;
|
||||
|
||||
/**
|
||||
* Calls callables/runnables via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
public class KernelExecutorWrapper {
|
||||
|
||||
private final ExecutorService kernelExecutor;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param kernelExecutor The kernel executor.
|
||||
*/
|
||||
@Inject
|
||||
public KernelExecutorWrapper(
|
||||
@KernelExecutor
|
||||
ExecutorService kernelExecutor
|
||||
) {
|
||||
this.kernelExecutor = requireNonNull(kernelExecutor, "kernelExecutor");
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given callable via the kernel executor and waits for the outcome.
|
||||
*
|
||||
* @param <T> The callable's return type.
|
||||
* @param callable The callable.
|
||||
* @return The result of the call.
|
||||
* @throws IllegalStateException In case the call via the kernel executor was unexpectedly
|
||||
* interrupted.
|
||||
* @throws RuntimeException In case an exception was thrown from the callable. If the exception
|
||||
* thrown is a {@code RuntimeException}, it is forwarded directly; if it is not a
|
||||
* {@code RuntimeException}, it is wrapped in a {@link KernelRuntimeException}.
|
||||
*/
|
||||
public <T> T callAndWait(Callable<T> callable)
|
||||
throws IllegalStateException,
|
||||
RuntimeException {
|
||||
requireNonNull(callable, "callable");
|
||||
|
||||
try {
|
||||
return kernelExecutor.submit(callable).get();
|
||||
}
|
||||
catch (InterruptedException exc) {
|
||||
throw new IllegalStateException("Unexpectedly interrupted");
|
||||
}
|
||||
catch (ExecutionException exc) {
|
||||
if (exc.getCause() instanceof RuntimeException) {
|
||||
throw (RuntimeException) exc.getCause();
|
||||
}
|
||||
throw new KernelRuntimeException(exc.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given runnable via the kernel executor and waits for the outcome.
|
||||
*
|
||||
* @param runnable The runnable.
|
||||
* @throws IllegalStateException In case the call via the kernel executor was unexpectedly
|
||||
* interrupted.
|
||||
* @throws RuntimeException In case an exception was thrown from the runnable. If the exception
|
||||
* thrown is a {@code RuntimeException}, it is forwarded directly; if it is not a
|
||||
* {@code RuntimeException}, it is wrapped in a {@link KernelRuntimeException}.
|
||||
*/
|
||||
public void callAndWait(Runnable runnable)
|
||||
throws IllegalStateException,
|
||||
RuntimeException {
|
||||
requireNonNull(runnable, "runnable");
|
||||
|
||||
callAndWait(Executors.callable(runnable));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import org.opentcs.components.Lifecycle;
|
||||
import spark.Service;
|
||||
|
||||
/**
|
||||
* A request handler.
|
||||
*/
|
||||
public interface RequestHandler
|
||||
extends
|
||||
Lifecycle {
|
||||
|
||||
/**
|
||||
* Registers the handler's routes with the given service.
|
||||
*
|
||||
* @param service The service to register the routes with.
|
||||
*/
|
||||
void addRoutes(Service service);
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.opentcs.access.KernelRuntimeException;
|
||||
import org.opentcs.access.SslParameterSet;
|
||||
import org.opentcs.components.kernel.KernelExtension;
|
||||
import org.opentcs.data.ObjectExistsException;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.V1RequestHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import spark.Service;
|
||||
|
||||
/**
|
||||
* Provides an HTTP interface for basic administration needs.
|
||||
*/
|
||||
public class ServiceWebApi
|
||||
implements
|
||||
KernelExtension {
|
||||
|
||||
/**
|
||||
* This class's logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServiceWebApi.class);
|
||||
/**
|
||||
* The interface configuration.
|
||||
*/
|
||||
private final ServiceWebApiConfiguration configuration;
|
||||
/**
|
||||
* Authenticates incoming requests.
|
||||
*/
|
||||
private final Authenticator authenticator;
|
||||
/**
|
||||
* Handles requests for API version 1.
|
||||
*/
|
||||
private final V1RequestHandler v1RequestHandler;
|
||||
/**
|
||||
* Binds JSON data to objects and vice versa.
|
||||
*/
|
||||
private final JsonBinder jsonBinder;
|
||||
/**
|
||||
* The connection encryption configuration.
|
||||
*/
|
||||
private final SslParameterSet sslParamSet;
|
||||
/**
|
||||
* The actual HTTP service.
|
||||
*/
|
||||
private Service service;
|
||||
/**
|
||||
* Whether this kernel extension is initialized.
|
||||
*/
|
||||
private boolean initialized;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param configuration The interface configuration.
|
||||
* @param sslParamSet The SSL parameter set.
|
||||
* @param authenticator Authenticates incoming requests.
|
||||
* @param jsonBinder Binds JSON data to objects and vice versa.
|
||||
* @param v1RequestHandler Handles requests for API version 1.
|
||||
*/
|
||||
@Inject
|
||||
public ServiceWebApi(
|
||||
ServiceWebApiConfiguration configuration,
|
||||
SslParameterSet sslParamSet,
|
||||
Authenticator authenticator,
|
||||
JsonBinder jsonBinder,
|
||||
V1RequestHandler v1RequestHandler
|
||||
) {
|
||||
this.configuration = requireNonNull(configuration, "configuration");
|
||||
this.sslParamSet = requireNonNull(sslParamSet, "sslParamSet");
|
||||
this.authenticator = requireNonNull(authenticator, "authenticator");
|
||||
this.jsonBinder = requireNonNull(jsonBinder, "jsonBinder");
|
||||
this.v1RequestHandler = requireNonNull(v1RequestHandler, "v1RequestHandler");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
v1RequestHandler.initialize();
|
||||
|
||||
service = Service.ignite()
|
||||
.ipAddress(configuration.bindAddress())
|
||||
.port(configuration.bindPort());
|
||||
|
||||
if (configuration.useSsl()) {
|
||||
service.secure(
|
||||
sslParamSet.getKeystoreFile().getAbsolutePath(),
|
||||
sslParamSet.getKeystorePassword(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
else {
|
||||
LOG.warn("Encryption disabled, connections will not be secured!");
|
||||
}
|
||||
|
||||
service.before((request, response) -> {
|
||||
if (!authenticator.isAuthenticated(request)) {
|
||||
// Delay the response a bit to slow down brute force attacks.
|
||||
Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
|
||||
service.halt(403, "Not authenticated.");
|
||||
}
|
||||
|
||||
// Add a CORS header to allow cross-origin requests from all hosts.
|
||||
// This also makes using the "try it out" buttons in the Swagger UI documentation possible.
|
||||
response.header("Access-Control-Allow-Origin", "*");
|
||||
});
|
||||
|
||||
// Reflect that we allow cross-origin requests for any headers and methods.
|
||||
service.options(
|
||||
"/*",
|
||||
(request, response) -> {
|
||||
String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
|
||||
if (accessControlRequestHeaders != null) {
|
||||
response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
|
||||
}
|
||||
|
||||
String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
|
||||
if (accessControlRequestMethod != null) {
|
||||
response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
|
||||
}
|
||||
|
||||
return "OK";
|
||||
}
|
||||
);
|
||||
|
||||
// Register routes for API versions here.
|
||||
service.path("/v1", () -> v1RequestHandler.addRoutes(service));
|
||||
|
||||
service.exception(IllegalArgumentException.class, (exception, request, response) -> {
|
||||
response.status(400);
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
response.body(jsonBinder.toJson(exception));
|
||||
});
|
||||
service.exception(ObjectUnknownException.class, (exception, request, response) -> {
|
||||
response.status(404);
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
response.body(jsonBinder.toJson(exception));
|
||||
});
|
||||
service.exception(ObjectExistsException.class, (exception, request, response) -> {
|
||||
response.status(409);
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
response.body(jsonBinder.toJson(exception));
|
||||
});
|
||||
service.exception(KernelRuntimeException.class, (exception, request, response) -> {
|
||||
response.status(500);
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
response.body(jsonBinder.toJson(exception));
|
||||
});
|
||||
service.exception(IllegalStateException.class, (exception, request, response) -> {
|
||||
response.status(500);
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
response.body(jsonBinder.toJson(exception));
|
||||
});
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
if (!isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
v1RequestHandler.terminate();
|
||||
service.stop();
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import org.opentcs.configuration.ConfigurationEntry;
|
||||
import org.opentcs.configuration.ConfigurationPrefix;
|
||||
|
||||
/**
|
||||
* Configuration entries for the service web API.
|
||||
*/
|
||||
@ConfigurationPrefix(ServiceWebApiConfiguration.PREFIX)
|
||||
public interface ServiceWebApiConfiguration {
|
||||
|
||||
/**
|
||||
* The prefix for all configuration entries here.
|
||||
*/
|
||||
String PREFIX = "servicewebapi";
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Boolean",
|
||||
description = "Whether to enable the interface.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
|
||||
orderKey = "0"
|
||||
)
|
||||
boolean enable();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "IP address",
|
||||
description = "Address to which to bind the HTTP server, e.g. 0.0.0.0 or 127.0.0.1.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
|
||||
orderKey = "1"
|
||||
)
|
||||
String bindAddress();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Integer",
|
||||
description = "Port to which to bind the HTTP server.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
|
||||
orderKey = "2"
|
||||
)
|
||||
int bindPort();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "String",
|
||||
description = "Key allowing access to the API.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
|
||||
orderKey = "3"
|
||||
)
|
||||
String accessKey();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Integer",
|
||||
description = "Maximum number of status events to be kept.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
|
||||
orderKey = "4"
|
||||
)
|
||||
int statusEventsCapacity();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Boolean",
|
||||
description = "Whether to use SSL to encrypt connections.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
|
||||
orderKey = "5"
|
||||
)
|
||||
boolean useSsl();
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.OrderSequence;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
|
||||
/**
|
||||
* Provides some commonly used object filters.
|
||||
*/
|
||||
public class Filters {
|
||||
|
||||
/**
|
||||
* Prevents instantiation.
|
||||
*/
|
||||
private Filters() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that is true only for transport orders whose intended vehicle is the given
|
||||
* one.
|
||||
* In case the given vehicle reference is null, all transport orders are accepted.
|
||||
*
|
||||
* @param vehicleRef The vehicle reference.
|
||||
* @return A predicate that is true only for transport orders whose intended vehicle is the given
|
||||
* one.
|
||||
*/
|
||||
public static Predicate<TransportOrder> transportOrderWithIntendedVehicle(
|
||||
@Nullable
|
||||
TCSObjectReference<Vehicle> vehicleRef
|
||||
) {
|
||||
return vehicleRef == null
|
||||
? order -> true
|
||||
: order -> Objects.equals(vehicleRef, order.getIntendedVehicle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that is true only for order sequences whose intended vehicle is the given
|
||||
* one.
|
||||
* In case the given vehicle reference is null, all order sequences are accepted.
|
||||
*
|
||||
* @param vehicleRef The vehicle reference.
|
||||
* @return A predicate that is true only for order sequences whose intended vehicle is the given
|
||||
* one.
|
||||
*/
|
||||
public static Predicate<OrderSequence> orderSequenceWithIntendedVehicle(
|
||||
@Nullable
|
||||
TCSObjectReference<Vehicle> vehicleRef
|
||||
) {
|
||||
return vehicleRef == null
|
||||
? sequence -> true
|
||||
: sequence -> Objects.equals(vehicleRef, sequence.getIntendedVehicle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that is true only for peripheral jobs whose related vehicle is the given
|
||||
* one.
|
||||
* In case the given vehicle reference is null, all peripheral jobs are accepted.
|
||||
*
|
||||
* @param vehicleRef The vehicle reference.
|
||||
* @return A predicate that is true only for peripheral jobs whose related vehicle is the given
|
||||
* one.
|
||||
*/
|
||||
public static Predicate<PeripheralJob> peripheralJobWithRelatedVehicle(
|
||||
@Nullable
|
||||
TCSObjectReference<Vehicle> vehicleRef
|
||||
) {
|
||||
return vehicleRef == null
|
||||
? job -> true
|
||||
: job -> Objects.equals(vehicleRef, job.getRelatedVehicle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that is true only for peripheral jobs whose related transport order is the
|
||||
* given one.
|
||||
* In case the given vehicle reference is null, all peripheral jobs are accepted.
|
||||
*
|
||||
* @param orderRef The transport order reference.
|
||||
* @return A predicate that is true only for peripheral jobs whose related transport order is the
|
||||
* given one.
|
||||
*/
|
||||
public static Predicate<PeripheralJob> peripheralJobWithRelatedTransportOrder(
|
||||
@Nullable
|
||||
TCSObjectReference<TransportOrder> orderRef
|
||||
) {
|
||||
return orderRef == null
|
||||
? job -> true
|
||||
: job -> Objects.equals(orderRef, job.getRelatedTransportOrder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that is true only for vehicles whose processing state is the given one.
|
||||
* In case the given procState is null, all vehicles are accepted.
|
||||
*
|
||||
* @param procState The processing state.
|
||||
* @return A predicate that is true only for vehicles whose processing state is the given one.
|
||||
*/
|
||||
public static Predicate<Vehicle> vehicleWithProcState(
|
||||
@Nullable
|
||||
Vehicle.ProcState procState
|
||||
) {
|
||||
return procState == null
|
||||
? vehicle -> true
|
||||
: vehicle -> Objects.equals(procState, vehicle.getProcState());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.inject.Inject;
|
||||
import org.opentcs.components.kernel.services.PlantModelService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Handles requests related to locations.
|
||||
*/
|
||||
public class LocationHandler {
|
||||
|
||||
private final PlantModelService plantModelService;
|
||||
private final KernelExecutorWrapper executorWrapper;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param plantModelService Used to retrieve and update location instances.
|
||||
* @param executorWrapper Executes calls via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
@Inject
|
||||
public LocationHandler(
|
||||
PlantModelService plantModelService,
|
||||
KernelExecutorWrapper executorWrapper
|
||||
) {
|
||||
this.plantModelService = requireNonNull(plantModelService, "plantModelService");
|
||||
this.executorWrapper = requireNonNull(executorWrapper, "executorWrapper");
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the locked state of the location with the given name.
|
||||
*
|
||||
* @param locationName The name of the location to update.
|
||||
* @param lockedValue The location's new locked state (a boolean as a string).
|
||||
* @throws ObjectUnknownException If a location with the given name could not be found.
|
||||
*/
|
||||
public void updateLocationLock(
|
||||
@Nonnull
|
||||
String locationName,
|
||||
String lockedValue
|
||||
)
|
||||
throws ObjectUnknownException {
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Location location = plantModelService.fetchObject(Location.class, locationName);
|
||||
if (location == null) {
|
||||
throw new ObjectUnknownException("Unknown location: " + locationName);
|
||||
}
|
||||
|
||||
plantModelService.updateLocationLock(
|
||||
location.getReference(),
|
||||
Boolean.parseBoolean(lockedValue)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.inject.Inject;
|
||||
import org.opentcs.components.kernel.services.PlantModelService;
|
||||
import org.opentcs.components.kernel.services.TCSObjectService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Path;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Handles requests related to paths.
|
||||
*/
|
||||
public class PathHandler {
|
||||
|
||||
private final TCSObjectService objectService;
|
||||
private final KernelExecutorWrapper executorWrapper;
|
||||
private final PlantModelService plantModelService;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param objectService Used to retrieve path instances.
|
||||
* @param plantModelService Used to update path locks.
|
||||
* @param executorWrapper Executes calls via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
@Inject
|
||||
public PathHandler(
|
||||
TCSObjectService objectService,
|
||||
KernelExecutorWrapper executorWrapper,
|
||||
PlantModelService plantModelService
|
||||
) {
|
||||
this.objectService = requireNonNull(objectService, "objectService");
|
||||
this.executorWrapper = requireNonNull(executorWrapper, "executorWrapper");
|
||||
this.plantModelService = requireNonNull(plantModelService, "plantModelService");
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the locked state of the path with the given name.
|
||||
*
|
||||
* @param pathName The name of the path to update.
|
||||
* @param lockedValue The path's new locked state (a boolean as a string).
|
||||
* @throws ObjectUnknownException If a path with the given name could not be found.
|
||||
*/
|
||||
public void updatePathLock(
|
||||
@Nonnull
|
||||
String pathName,
|
||||
String lockedValue
|
||||
)
|
||||
throws ObjectUnknownException {
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Path path = objectService.fetchObject(Path.class, pathName);
|
||||
if (path == null) {
|
||||
throw new ObjectUnknownException("Unknown path: " + pathName);
|
||||
}
|
||||
plantModelService.updatePathLock(path.getReference(), Boolean.parseBoolean(lockedValue));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.opentcs.components.kernel.services.PeripheralService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.drivers.peripherals.PeripheralCommAdapterDescription;
|
||||
import org.opentcs.drivers.peripherals.management.PeripheralAttachmentInformation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Handles requests related to peripherals.
|
||||
*/
|
||||
public class PeripheralHandler {
|
||||
|
||||
private final PeripheralService peripheralService;
|
||||
private final KernelExecutorWrapper executorWrapper;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param peripheralService The service used to manage peripherals.
|
||||
* @param executorWrapper Executes calls via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
@Inject
|
||||
public PeripheralHandler(
|
||||
PeripheralService peripheralService,
|
||||
KernelExecutorWrapper executorWrapper
|
||||
) {
|
||||
this.peripheralService = requireNonNull(peripheralService, "peripheralService");
|
||||
this.executorWrapper = requireNonNull(executorWrapper, "executorWrapper");
|
||||
}
|
||||
|
||||
public void putPeripheralCommAdapter(String name, String value)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(value, "value");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Location location = peripheralService.fetchObject(Location.class, name);
|
||||
if (location == null) {
|
||||
throw new ObjectUnknownException("Unknown location: " + name);
|
||||
}
|
||||
|
||||
PeripheralCommAdapterDescription newAdapter
|
||||
= peripheralService.fetchAttachmentInformation(location.getReference())
|
||||
.getAvailableCommAdapters()
|
||||
.stream()
|
||||
.filter(description -> description.getClass().getName().equals(value))
|
||||
.findAny()
|
||||
.orElseThrow(
|
||||
() -> new IllegalArgumentException(
|
||||
"Unknown peripheral driver class name: " + value
|
||||
)
|
||||
);
|
||||
|
||||
peripheralService.attachCommAdapter(location.getReference(), newAdapter);
|
||||
});
|
||||
}
|
||||
|
||||
public void putPeripheralCommAdapterEnabled(String name, String value)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(value, "value");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Location location = peripheralService.fetchObject(Location.class, name);
|
||||
if (location == null) {
|
||||
throw new ObjectUnknownException("Unknown location: " + name);
|
||||
}
|
||||
|
||||
if (Boolean.parseBoolean(value)) {
|
||||
peripheralService.enableCommAdapter(location.getReference());
|
||||
}
|
||||
else {
|
||||
peripheralService.disableCommAdapter(location.getReference());
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public PeripheralAttachmentInformation getPeripheralCommAdapterAttachmentInformation(String name)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
Location location = peripheralService.fetchObject(Location.class, name);
|
||||
if (location == null) {
|
||||
throw new ObjectUnknownException("Unknown location: " + name);
|
||||
}
|
||||
|
||||
return peripheralService.fetchAttachmentInformation(location.getReference());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.opentcs.components.kernel.services.PeripheralDispatcherService;
|
||||
import org.opentcs.components.kernel.services.PeripheralJobService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Handles requests related to peripheral job dispatching.
|
||||
*/
|
||||
public class PeripheralJobDispatcherHandler {
|
||||
|
||||
private final PeripheralJobService jobService;
|
||||
private final PeripheralDispatcherService jobDispatcherService;
|
||||
private final KernelExecutorWrapper executorWrapper;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param jobService Used to create peripheral jobs.
|
||||
* @param jobDispatcherService Used to dispatch peripheral jobs.
|
||||
* @param executorWrapper Executes calls via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
@Inject
|
||||
public PeripheralJobDispatcherHandler(
|
||||
PeripheralJobService jobService,
|
||||
PeripheralDispatcherService jobDispatcherService,
|
||||
KernelExecutorWrapper executorWrapper
|
||||
) {
|
||||
this.jobService = requireNonNull(jobService, "jobService");
|
||||
this.jobDispatcherService = requireNonNull(jobDispatcherService, "jobDispatcherService");
|
||||
this.executorWrapper = requireNonNull(executorWrapper, "executorWrapper");
|
||||
}
|
||||
|
||||
public void triggerJobDispatcher() {
|
||||
executorWrapper.callAndWait(() -> jobDispatcherService.dispatch());
|
||||
}
|
||||
|
||||
public void withdrawPeripheralJobByLocation(String name)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Location location = jobService.fetchObject(Location.class, name);
|
||||
if (location == null) {
|
||||
throw new ObjectUnknownException("Unknown location: " + name);
|
||||
}
|
||||
|
||||
jobDispatcherService.withdrawByLocation(location.getReference());
|
||||
});
|
||||
}
|
||||
|
||||
public void withdrawPeripheralJob(String name)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
PeripheralJob job = jobService.fetchObject(PeripheralJob.class, name);
|
||||
if (job == null) {
|
||||
throw new ObjectUnknownException("Unknown peripheral job: " + name);
|
||||
}
|
||||
|
||||
jobDispatcherService.withdrawByPeripheralJob(job.getReference());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.to.peripherals.PeripheralJobCreationTO;
|
||||
import org.opentcs.access.to.peripherals.PeripheralOperationCreationTO;
|
||||
import org.opentcs.components.kernel.services.PeripheralDispatcherService;
|
||||
import org.opentcs.components.kernel.services.PeripheralJobService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetPeripheralJobResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostPeripheralJobRequestTO;
|
||||
|
||||
/**
|
||||
* Handles requests related to peripheral jobs.
|
||||
*/
|
||||
public class PeripheralJobHandler {
|
||||
|
||||
private final PeripheralJobService jobService;
|
||||
private final PeripheralDispatcherService jobDispatcherService;
|
||||
private final KernelExecutorWrapper executorWrapper;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param jobService Used to create peripheral jobs.
|
||||
* @param jobDispatcherService Used to dispatch peripheral jobs.
|
||||
* @param executorWrapper Executes calls via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
@Inject
|
||||
public PeripheralJobHandler(
|
||||
PeripheralJobService jobService,
|
||||
PeripheralDispatcherService jobDispatcherService,
|
||||
KernelExecutorWrapper executorWrapper
|
||||
) {
|
||||
this.jobService = requireNonNull(jobService, "jobService");
|
||||
this.jobDispatcherService = requireNonNull(jobDispatcherService, "jobDispatcherService");
|
||||
this.executorWrapper = requireNonNull(executorWrapper, "executorWrapper");
|
||||
}
|
||||
|
||||
public PeripheralJob createPeripheralJob(String name, PostPeripheralJobRequestTO job) {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(job, "job");
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
// Check if the vehicle, location and transport order exist.
|
||||
if (job.getRelatedVehicle() != null
|
||||
&& jobService.fetchObject(Vehicle.class, job.getRelatedVehicle()) == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + job.getRelatedVehicle());
|
||||
}
|
||||
if (job.getRelatedTransportOrder() != null
|
||||
&& jobService.fetchObject(
|
||||
TransportOrder.class,
|
||||
job.getRelatedTransportOrder()
|
||||
) == null) {
|
||||
throw new ObjectUnknownException(
|
||||
"Unknown transport order: " + job.getRelatedTransportOrder()
|
||||
);
|
||||
}
|
||||
if (job.getPeripheralOperation().getLocationName() != null
|
||||
&& jobService.fetchObject(
|
||||
Location.class,
|
||||
job.getPeripheralOperation().getLocationName()
|
||||
) == null) {
|
||||
throw new ObjectUnknownException(
|
||||
"Unknown location: " + job.getPeripheralOperation().getLocationName()
|
||||
);
|
||||
}
|
||||
|
||||
// Peripheral jobs created via the web API are expected to be executed immediately and
|
||||
// require no completion. Therefore, explicitly ignore the corresponding provided values.
|
||||
PeripheralOperationCreationTO operationCreationTO = new PeripheralOperationCreationTO(
|
||||
job.getPeripheralOperation().getOperation(),
|
||||
job.getPeripheralOperation().getLocationName()
|
||||
);
|
||||
|
||||
PeripheralJobCreationTO jobCreationTO = new PeripheralJobCreationTO(
|
||||
name,
|
||||
job.getReservationToken(),
|
||||
operationCreationTO
|
||||
)
|
||||
.withIncompleteName(job.isIncompleteName());
|
||||
if (job.getProperties() != null) {
|
||||
jobCreationTO = jobCreationTO.withProperties(
|
||||
job.getProperties().stream()
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
property -> property.getKey(),
|
||||
property -> property.getValue()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (job.getRelatedTransportOrder() != null) {
|
||||
jobCreationTO = jobCreationTO.withRelatedTransportOrderName(job.getRelatedTransportOrder());
|
||||
}
|
||||
if (job.getRelatedVehicle() != null) {
|
||||
jobCreationTO = jobCreationTO.withRelatedVehicleName(job.getRelatedVehicle());
|
||||
}
|
||||
|
||||
return jobService.createPeripheralJob(jobCreationTO);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all peripheral jobs, optionally filtered using the given parameters.
|
||||
*
|
||||
* @param relatedVehicle Which vehicle to filter peripheral jobs for. Not filtered if the value is
|
||||
* null.
|
||||
* @param relatedTransportOrder Which transport order to filter peripheral jobs for. Not filtered
|
||||
* if the value is null.
|
||||
* @return List of peripheral job states.
|
||||
*/
|
||||
public List<GetPeripheralJobResponseTO> getPeripheralJobs(
|
||||
@Nullable
|
||||
String relatedVehicle,
|
||||
@Nullable
|
||||
String relatedTransportOrder
|
||||
) {
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
// If a related vehicle is set, make sure it exists.
|
||||
TCSObjectReference<Vehicle> relatedVehicleRef
|
||||
= Optional.ofNullable(relatedVehicle)
|
||||
.map(name -> jobService.fetchObject(Vehicle.class, name))
|
||||
.map(Vehicle::getReference)
|
||||
.orElse(null);
|
||||
|
||||
if (relatedVehicle != null && relatedVehicleRef == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + relatedVehicle);
|
||||
}
|
||||
|
||||
// If a related transport order is set, make sure it exists.
|
||||
TCSObjectReference<TransportOrder> relatedOrderRef
|
||||
= Optional.ofNullable(relatedTransportOrder)
|
||||
.map(name -> jobService.fetchObject(TransportOrder.class, name))
|
||||
.map(TransportOrder::getReference)
|
||||
.orElse(null);
|
||||
|
||||
if (relatedTransportOrder != null && relatedOrderRef == null) {
|
||||
throw new ObjectUnknownException("Unknown oransport order: " + relatedVehicle);
|
||||
}
|
||||
|
||||
return jobService.fetchObjects(
|
||||
PeripheralJob.class,
|
||||
Filters.peripheralJobWithRelatedVehicle(relatedVehicleRef)
|
||||
.and(Filters.peripheralJobWithRelatedTransportOrder(relatedOrderRef))
|
||||
)
|
||||
.stream()
|
||||
.map(GetPeripheralJobResponseTO::fromPeripheralJob)
|
||||
.sorted(Comparator.comparing(GetPeripheralJobResponseTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a peripheral job by name.
|
||||
*
|
||||
* @param name The name of the peripheral job.
|
||||
* @return The peripheral job state.
|
||||
*/
|
||||
public GetPeripheralJobResponseTO getPeripheralJobByName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
PeripheralJob job = jobService.fetchObject(PeripheralJob.class, name);
|
||||
if (job == null) {
|
||||
throw new ObjectUnknownException("Unknown peripheral job: " + name);
|
||||
}
|
||||
|
||||
return GetPeripheralJobResponseTO.fromPeripheralJob(job);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.opentcs.access.to.model.PlantModelCreationTO;
|
||||
import org.opentcs.components.kernel.services.PlantModelService;
|
||||
import org.opentcs.components.kernel.services.RouterService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.model.Path;
|
||||
import org.opentcs.data.model.PlantModel;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PlantModelTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostTopologyUpdateRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.BlockConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.LocationConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.LocationTypeConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.PathConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.PointConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.PropertyConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.VehicleConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.VisualLayoutConverter;
|
||||
|
||||
/**
|
||||
* Handles requests related to plant models.
|
||||
*/
|
||||
public class PlantModelHandler {
|
||||
|
||||
/**
|
||||
* Used to set or retrieve plant models.
|
||||
*/
|
||||
private final PlantModelService plantModelService;
|
||||
/**
|
||||
* Executes calls via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
private final KernelExecutorWrapper executorWrapper;
|
||||
|
||||
private final PointConverter pointConverter;
|
||||
private final PathConverter pathConverter;
|
||||
private final LocationTypeConverter locationTypeConverter;
|
||||
private final LocationConverter locationConverter;
|
||||
private final BlockConverter blockConverter;
|
||||
private final VehicleConverter vehicleConverter;
|
||||
private final VisualLayoutConverter visualLayoutConverter;
|
||||
private final PropertyConverter propertyConverter;
|
||||
private final RouterService routerService;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param plantModelService Used to set or retrieve plant models.
|
||||
* @param executorWrapper Executes calls via the kernel executor and waits for the outcome.
|
||||
* @param pointConverter Converts point instances.
|
||||
* @param pathConverter Converts path instances.
|
||||
* @param locationTypeConverter Converts location type instances.
|
||||
* @param locationConverter Converts location instances.
|
||||
* @param blockConverter Converts block instances.
|
||||
* @param vehicleConverter Converts vehicle instances.
|
||||
* @param visualLayoutConverter Converts visual layout instances.
|
||||
* @param propertyConverter Converts property instances.
|
||||
* @param routerService Provides methods concerning the router.
|
||||
*/
|
||||
@Inject
|
||||
public PlantModelHandler(
|
||||
PlantModelService plantModelService,
|
||||
KernelExecutorWrapper executorWrapper,
|
||||
PointConverter pointConverter,
|
||||
PathConverter pathConverter,
|
||||
LocationTypeConverter locationTypeConverter,
|
||||
LocationConverter locationConverter,
|
||||
BlockConverter blockConverter,
|
||||
VehicleConverter vehicleConverter,
|
||||
VisualLayoutConverter visualLayoutConverter,
|
||||
PropertyConverter propertyConverter,
|
||||
RouterService routerService
|
||||
) {
|
||||
this.plantModelService = requireNonNull(plantModelService, "plantModelService");
|
||||
this.executorWrapper = requireNonNull(executorWrapper, "executorWrapper");
|
||||
this.pointConverter = requireNonNull(pointConverter, "pointConverter");
|
||||
this.pathConverter = requireNonNull(pathConverter, "pathConverter");
|
||||
this.locationTypeConverter = requireNonNull(locationTypeConverter, "locationTypeConverter");
|
||||
this.locationConverter = requireNonNull(locationConverter, "locationConverter");
|
||||
this.blockConverter = requireNonNull(blockConverter, "blockConverter");
|
||||
this.vehicleConverter = requireNonNull(vehicleConverter, "vehicleConverter");
|
||||
this.visualLayoutConverter = requireNonNull(visualLayoutConverter, "visualLayoutConverter");
|
||||
this.propertyConverter = requireNonNull(propertyConverter, "propertyConverter");
|
||||
this.routerService = requireNonNull(routerService, "routerService");
|
||||
}
|
||||
|
||||
public void putPlantModel(PlantModelTO putPlantModel)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
requireNonNull(putPlantModel, "putPlantModel");
|
||||
|
||||
PlantModelCreationTO plantModelCreationTO = new PlantModelCreationTO(putPlantModel.getName())
|
||||
.withPoints(pointConverter.toPointCreationTOs(putPlantModel.getPoints()))
|
||||
.withPaths(pathConverter.toPathCreationTOs(putPlantModel.getPaths()))
|
||||
.withLocationTypes(
|
||||
locationTypeConverter.toLocationTypeCreationTOs(putPlantModel.getLocationTypes())
|
||||
)
|
||||
.withLocations(locationConverter.toLocationCreationTOs(putPlantModel.getLocations()))
|
||||
.withBlocks(blockConverter.toBlockCreationTOs(putPlantModel.getBlocks()))
|
||||
.withVehicles(vehicleConverter.toVehicleCreationTOs(putPlantModel.getVehicles()))
|
||||
.withVisualLayout(
|
||||
visualLayoutConverter.toVisualLayoutCreationTO(putPlantModel.getVisualLayout())
|
||||
)
|
||||
.withProperties(propertyConverter.toPropertyMap(putPlantModel.getProperties()));
|
||||
|
||||
executorWrapper.callAndWait(() -> plantModelService.createPlantModel(plantModelCreationTO));
|
||||
}
|
||||
|
||||
public PlantModelTO getPlantModel() {
|
||||
PlantModel plantModel = plantModelService.getPlantModel();
|
||||
return new PlantModelTO(plantModel.getName())
|
||||
.setPoints(pointConverter.toPointTOs(plantModel.getPoints()))
|
||||
.setPaths(pathConverter.toPathTOs(plantModel.getPaths()))
|
||||
.setLocationTypes(locationTypeConverter.toLocationTypeTOs(plantModel.getLocationTypes()))
|
||||
.setLocations(locationConverter.toLocationTOs(plantModel.getLocations()))
|
||||
.setBlocks(blockConverter.toBlockTOs(plantModel.getBlocks()))
|
||||
.setVehicles(vehicleConverter.toVehicleTOs(plantModel.getVehicles()))
|
||||
.setVisualLayout(visualLayoutConverter.toVisualLayoutTO(plantModel.getVisualLayout()))
|
||||
.setProperties(propertyConverter.toPropertyTOs(plantModel.getProperties()));
|
||||
}
|
||||
|
||||
public void requestTopologyUpdate(PostTopologyUpdateRequestTO request)
|
||||
throws ObjectUnknownException {
|
||||
executorWrapper.callAndWait(
|
||||
() -> routerService.updateRoutingTopology(toResourceReferences(request.getPaths()))
|
||||
);
|
||||
}
|
||||
|
||||
private Set<TCSObjectReference<Path>> toResourceReferences(List<String> paths) {
|
||||
Set<TCSObjectReference<Path>> pathsToUpdate = new HashSet<>();
|
||||
|
||||
for (String name : paths) {
|
||||
Path path = plantModelService.fetchObject(Path.class, name);
|
||||
if (path == null) {
|
||||
throw new ObjectUnknownException("Unknown path: " + name);
|
||||
}
|
||||
pathsToUpdate.add(path.getReference());
|
||||
}
|
||||
|
||||
return pathsToUpdate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.opentcs.util.Assertions.checkInRange;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import org.opentcs.access.Kernel;
|
||||
import org.opentcs.access.KernelStateTransitionEvent;
|
||||
import org.opentcs.components.Lifecycle;
|
||||
import org.opentcs.customizations.ApplicationEventBus;
|
||||
import org.opentcs.data.TCSObject;
|
||||
import org.opentcs.data.TCSObjectEvent;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.ServiceWebApiConfiguration;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetEventsResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.OrderStatusMessage;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.PeripheralJobStatusMessage;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.StatusMessage;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.VehicleStatusMessage;
|
||||
import org.opentcs.util.event.EventHandler;
|
||||
import org.opentcs.util.event.EventSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Provides descriptions of recent events.
|
||||
*/
|
||||
public class StatusEventDispatcher
|
||||
implements
|
||||
Lifecycle,
|
||||
EventHandler {
|
||||
|
||||
/**
|
||||
* This class's logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StatusEventDispatcher.class);
|
||||
/**
|
||||
* The interface configuration.
|
||||
*/
|
||||
private final ServiceWebApiConfiguration configuration;
|
||||
/**
|
||||
* Where we register for application events.
|
||||
*/
|
||||
private final EventSource eventSource;
|
||||
/**
|
||||
* The events collected.
|
||||
*/
|
||||
private final SortedMap<Long, StatusMessage> events = new TreeMap<>();
|
||||
/**
|
||||
* The number of events collected so far.
|
||||
*/
|
||||
private long eventCount;
|
||||
/**
|
||||
* Whether this instance is initialized.
|
||||
*/
|
||||
private boolean initialized;
|
||||
/**
|
||||
* Whether we are collecting events.
|
||||
*/
|
||||
private boolean eventCollectingOn;
|
||||
|
||||
@Inject
|
||||
public StatusEventDispatcher(
|
||||
ServiceWebApiConfiguration configuration,
|
||||
@ApplicationEventBus
|
||||
EventSource eventSource
|
||||
) {
|
||||
this.configuration = requireNonNull(configuration, "configuration");
|
||||
this.eventSource = requireNonNull(eventSource, "eventSource");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
eventSource.subscribe(this);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
if (!isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
eventSource.unsubscribe(this);
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(Object event) {
|
||||
if (event instanceof KernelStateTransitionEvent) {
|
||||
handleStateTransition((KernelStateTransitionEvent) event);
|
||||
}
|
||||
|
||||
if (!eventCollectingOn) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event instanceof TCSObjectEvent) {
|
||||
handleObjectEvent((TCSObjectEvent) event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of events within the given range, waiting at most <code>timeout</code>
|
||||
* milliseconds for new events if there currently aren't any.
|
||||
*
|
||||
* @param minSequenceNo The minimum sequence number for accepted events.
|
||||
* @param maxSequenceNo The maximum sequence number for accepted events.
|
||||
* @param timeout The maximum time to wait for events (in ms) if there currently aren't any.
|
||||
* @return A list of events within the given range.
|
||||
*/
|
||||
public GetEventsResponseTO fetchEvents(long minSequenceNo, long maxSequenceNo, long timeout)
|
||||
throws IllegalArgumentException {
|
||||
checkInRange(minSequenceNo, 0, Long.MAX_VALUE, "minSequenceNo");
|
||||
checkInRange(maxSequenceNo, minSequenceNo, Long.MAX_VALUE, "maxSequenceNo");
|
||||
checkInRange(timeout, 0, Long.MAX_VALUE, "timeout");
|
||||
|
||||
GetEventsResponseTO result = new GetEventsResponseTO();
|
||||
synchronized (events) {
|
||||
Collection<StatusMessage> messages = events.subMap(minSequenceNo, maxSequenceNo).values();
|
||||
if (messages.isEmpty()) {
|
||||
try {
|
||||
events.wait(timeout);
|
||||
}
|
||||
catch (InterruptedException exc) {
|
||||
LOG.warn("Unexpectedly interrupted", exc);
|
||||
}
|
||||
}
|
||||
messages = events.subMap(minSequenceNo, maxSequenceNo).values();
|
||||
result.getStatusMessages().addAll(messages);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void handleStateTransition(KernelStateTransitionEvent event) {
|
||||
boolean wasOn = eventCollectingOn;
|
||||
eventCollectingOn
|
||||
= event.getEnteredState() == Kernel.State.OPERATING && event.isTransitionFinished();
|
||||
|
||||
// When switching collecting of events on, ensure we start clean.
|
||||
if (!wasOn && eventCollectingOn) {
|
||||
synchronized (events) {
|
||||
eventCount = 0;
|
||||
events.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleObjectEvent(TCSObjectEvent event) {
|
||||
TCSObject<?> object = event.getCurrentOrPreviousObjectState();
|
||||
if (object instanceof TransportOrder) {
|
||||
synchronized (events) {
|
||||
addOrderStatusMessage((TransportOrder) object, eventCount);
|
||||
eventCount++;
|
||||
cleanUpEvents();
|
||||
events.notifyAll();
|
||||
}
|
||||
}
|
||||
else if (object instanceof Vehicle) {
|
||||
synchronized (events) {
|
||||
addVehicleStatusMessage((Vehicle) object, eventCount);
|
||||
eventCount++;
|
||||
cleanUpEvents();
|
||||
events.notifyAll();
|
||||
}
|
||||
}
|
||||
else if (object instanceof PeripheralJob) {
|
||||
synchronized (events) {
|
||||
addPeripheralStatusMessage((PeripheralJob) object, eventCount);
|
||||
eventCount++;
|
||||
cleanUpEvents();
|
||||
events.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addOrderStatusMessage(TransportOrder order, long sequenceNumber) {
|
||||
events.put(sequenceNumber, OrderStatusMessage.fromTransportOrder(order, sequenceNumber));
|
||||
}
|
||||
|
||||
private void addVehicleStatusMessage(Vehicle vehicle, long sequenceNumber) {
|
||||
events.put(sequenceNumber, VehicleStatusMessage.fromVehicle(vehicle, sequenceNumber));
|
||||
}
|
||||
|
||||
private void addPeripheralStatusMessage(PeripheralJob job, long sequenceNumber) {
|
||||
events.put(sequenceNumber, PeripheralJobStatusMessage.fromPeripheralJob(job, sequenceNumber));
|
||||
}
|
||||
|
||||
private void cleanUpEvents() {
|
||||
// XXX Sanitize maxEventCount
|
||||
int maxEventCount = configuration.statusEventsCapacity();
|
||||
while (events.size() > maxEventCount) {
|
||||
events.remove(events.firstKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.opentcs.components.kernel.services.DispatcherService;
|
||||
import org.opentcs.components.kernel.services.VehicleService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.ReroutingType;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Handles requests related to transport order dispatching.
|
||||
*/
|
||||
public class TransportOrderDispatcherHandler {
|
||||
|
||||
private final VehicleService vehicleService;
|
||||
private final DispatcherService dispatcherService;
|
||||
private final KernelExecutorWrapper executorWrapper;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param vehicleService Used to update vehicle state.
|
||||
* @param dispatcherService Used to withdraw transport orders.
|
||||
* @param executorWrapper Executes calls via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
@Inject
|
||||
public TransportOrderDispatcherHandler(
|
||||
VehicleService vehicleService,
|
||||
DispatcherService dispatcherService,
|
||||
KernelExecutorWrapper executorWrapper
|
||||
) {
|
||||
this.vehicleService = requireNonNull(vehicleService, "vehicleService");
|
||||
this.dispatcherService = requireNonNull(dispatcherService, "dispatcherService");
|
||||
this.executorWrapper = requireNonNull(executorWrapper, "executorWrapper");
|
||||
}
|
||||
|
||||
public void triggerDispatcher() {
|
||||
executorWrapper.callAndWait(() -> dispatcherService.dispatch());
|
||||
}
|
||||
|
||||
public void tryImmediateAssignment(String name)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
TransportOrder order = vehicleService.fetchObject(TransportOrder.class, name);
|
||||
if (order == null) {
|
||||
throw new ObjectUnknownException("Unknown transport order: " + name);
|
||||
}
|
||||
|
||||
dispatcherService.assignNow(order.getReference());
|
||||
});
|
||||
}
|
||||
|
||||
public void withdrawByTransportOrder(String name, boolean immediate, boolean disableVehicle)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
if (vehicleService.fetchObject(TransportOrder.class, name) == null) {
|
||||
throw new ObjectUnknownException("Unknown transport order: " + name);
|
||||
}
|
||||
|
||||
TransportOrder order = vehicleService.fetchObject(TransportOrder.class, name);
|
||||
if (disableVehicle && order.getProcessingVehicle() != null) {
|
||||
vehicleService.updateVehicleIntegrationLevel(
|
||||
order.getProcessingVehicle(),
|
||||
Vehicle.IntegrationLevel.TO_BE_RESPECTED
|
||||
);
|
||||
}
|
||||
|
||||
dispatcherService.withdrawByTransportOrder(order.getReference(), immediate);
|
||||
});
|
||||
}
|
||||
|
||||
public void withdrawByVehicle(String name, boolean immediate, boolean disableVehicle)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
|
||||
if (disableVehicle) {
|
||||
vehicleService.updateVehicleIntegrationLevel(
|
||||
vehicle.getReference(),
|
||||
Vehicle.IntegrationLevel.TO_BE_RESPECTED
|
||||
);
|
||||
}
|
||||
|
||||
dispatcherService.withdrawByVehicle(vehicle.getReference(), immediate);
|
||||
});
|
||||
}
|
||||
|
||||
public void reroute(String vehicleName, boolean forced)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(vehicleName, "vehicleName");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, vehicleName);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + vehicleName);
|
||||
}
|
||||
|
||||
dispatcherService.reroute(
|
||||
vehicle.getReference(),
|
||||
forced ? ReroutingType.FORCED : ReroutingType.REGULAR
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.KernelRuntimeException;
|
||||
import org.opentcs.access.to.order.DestinationCreationTO;
|
||||
import org.opentcs.access.to.order.OrderSequenceCreationTO;
|
||||
import org.opentcs.access.to.order.TransportOrderCreationTO;
|
||||
import org.opentcs.components.kernel.services.TransportOrderService;
|
||||
import org.opentcs.data.ObjectExistsException;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.OrderConstants;
|
||||
import org.opentcs.data.order.OrderSequence;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetOrderSequenceResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetTransportOrderResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostOrderSequenceRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostTransportOrderRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.posttransportorder.Destination;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* Handles requests related to transport orders and order sequences.
|
||||
*/
|
||||
public class TransportOrderHandler {
|
||||
|
||||
private final TransportOrderService orderService;
|
||||
private final KernelExecutorWrapper executorWrapper;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param orderService The service we use to get the transport orders.
|
||||
* @param executorWrapper Executes calls via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
@Inject
|
||||
public TransportOrderHandler(
|
||||
TransportOrderService orderService,
|
||||
KernelExecutorWrapper executorWrapper
|
||||
) {
|
||||
this.orderService = requireNonNull(orderService, "orderService");
|
||||
this.executorWrapper = requireNonNull(executorWrapper, "executorWrapper");
|
||||
}
|
||||
|
||||
public TransportOrder createOrder(String name, PostTransportOrderRequestTO order)
|
||||
throws ObjectUnknownException,
|
||||
ObjectExistsException,
|
||||
KernelRuntimeException,
|
||||
IllegalStateException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(order, "order");
|
||||
|
||||
TransportOrderCreationTO to
|
||||
= new TransportOrderCreationTO(name, destinations(order))
|
||||
.withIncompleteName(order.isIncompleteName())
|
||||
.withDispensable(order.isDispensable())
|
||||
.withIntendedVehicleName(order.getIntendedVehicle())
|
||||
.withDependencyNames(dependencyNames(order.getDependencies()))
|
||||
.withDeadline(deadline(order))
|
||||
.withPeripheralReservationToken(order.getPeripheralReservationToken())
|
||||
.withWrappingSequence(order.getWrappingSequence())
|
||||
.withType(order.getType() == null ? OrderConstants.TYPE_NONE : order.getType())
|
||||
.withProperties(properties(order.getProperties()));
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
return orderService.createTransportOrder(to);
|
||||
});
|
||||
}
|
||||
|
||||
public void updateTransportOrderIntendedVehicle(
|
||||
String orderName,
|
||||
@Nullable
|
||||
String vehicleName
|
||||
)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(orderName, "orderName");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
TransportOrder order = orderService.fetchObject(TransportOrder.class, orderName);
|
||||
if (order == null) {
|
||||
throw new ObjectUnknownException("Unknown transport order: " + orderName);
|
||||
}
|
||||
Vehicle vehicle = null;
|
||||
if (vehicleName != null) {
|
||||
vehicle = orderService.fetchObject(Vehicle.class, vehicleName);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + vehicleName);
|
||||
}
|
||||
}
|
||||
|
||||
orderService.updateTransportOrderIntendedVehicle(
|
||||
order.getReference(),
|
||||
vehicle != null ? vehicle.getReference() : null
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all transport orders and filters depending on the given parameters.
|
||||
*
|
||||
* @param intendedVehicle The filter parameter for the name of the
|
||||
* intended vehicle for the transport order. The filtering is disabled for this parameter if the
|
||||
* value is null.
|
||||
* @return A list of transport orders that match the filter.
|
||||
*/
|
||||
public List<GetTransportOrderResponseTO> getTransportOrders(
|
||||
@Nullable
|
||||
String intendedVehicle
|
||||
) {
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
TCSObjectReference<Vehicle> intendedVehicleRef
|
||||
= Optional.ofNullable(intendedVehicle)
|
||||
.map(name -> orderService.fetchObject(Vehicle.class, name))
|
||||
.map(Vehicle::getReference)
|
||||
.orElse(null);
|
||||
|
||||
if (intendedVehicle != null && intendedVehicleRef == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + intendedVehicle);
|
||||
}
|
||||
|
||||
return orderService.fetchObjects(
|
||||
TransportOrder.class,
|
||||
Filters.transportOrderWithIntendedVehicle(intendedVehicleRef)
|
||||
)
|
||||
.stream()
|
||||
.map(GetTransportOrderResponseTO::fromTransportOrder)
|
||||
.sorted(Comparator.comparing(GetTransportOrderResponseTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the transport order with the given name.
|
||||
*
|
||||
* @param name The name of the requested transport order.
|
||||
* @return A single transport order with the given name.
|
||||
* @throws ObjectUnknownException If a transport order with the given name does not exist.
|
||||
*/
|
||||
public GetTransportOrderResponseTO getTransportOrderByName(String name)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
return Optional.ofNullable(orderService.fetchObject(TransportOrder.class, name))
|
||||
.map(GetTransportOrderResponseTO::fromTransportOrder)
|
||||
.orElseThrow(() -> new ObjectUnknownException("Unknown transport order: " + name));
|
||||
});
|
||||
}
|
||||
|
||||
public OrderSequence createOrderSequence(String name, PostOrderSequenceRequestTO sequence)
|
||||
throws ObjectUnknownException,
|
||||
ObjectExistsException,
|
||||
KernelRuntimeException,
|
||||
IllegalStateException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(sequence, "sequence");
|
||||
|
||||
OrderSequenceCreationTO to = new OrderSequenceCreationTO(name)
|
||||
.withFailureFatal(sequence.isFailureFatal())
|
||||
.withIncompleteName(sequence.isIncompleteName())
|
||||
.withIntendedVehicleName(sequence.getIntendedVehicle())
|
||||
.withProperties(properties(sequence.getProperties()))
|
||||
.withType(sequence.getType());
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
return orderService.createOrderSequence(to);
|
||||
});
|
||||
}
|
||||
|
||||
public void putOrderSequenceComplete(String name)
|
||||
throws ObjectUnknownException,
|
||||
IllegalStateException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
OrderSequence orderSequence = orderService.fetchObject(OrderSequence.class, name);
|
||||
if (orderSequence == null) {
|
||||
throw new ObjectUnknownException("Unknown order sequence: " + name);
|
||||
}
|
||||
orderService.markOrderSequenceComplete(orderSequence.getReference());
|
||||
});
|
||||
}
|
||||
|
||||
public List<GetOrderSequenceResponseTO> getOrderSequences(
|
||||
@Nullable
|
||||
String intendedVehicle
|
||||
) {
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
TCSObjectReference<Vehicle> intendedVehicleRef
|
||||
= Optional.ofNullable(intendedVehicle)
|
||||
.map(name -> orderService.fetchObject(Vehicle.class, name))
|
||||
.map(Vehicle::getReference)
|
||||
.orElse(null);
|
||||
|
||||
if (intendedVehicle != null && intendedVehicleRef == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + intendedVehicle);
|
||||
}
|
||||
|
||||
return orderService.fetchObjects(
|
||||
OrderSequence.class,
|
||||
Filters.orderSequenceWithIntendedVehicle(intendedVehicleRef)
|
||||
)
|
||||
.stream()
|
||||
.map(GetOrderSequenceResponseTO::fromOrderSequence)
|
||||
.sorted(Comparator.comparing(GetOrderSequenceResponseTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO getOrderSequenceByName(String name)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
return Optional.ofNullable(orderService.fetchObject(OrderSequence.class, name))
|
||||
.map(GetOrderSequenceResponseTO::fromOrderSequence)
|
||||
.orElseThrow(() -> new ObjectUnknownException("Unknown transport order: " + name));
|
||||
});
|
||||
}
|
||||
|
||||
private List<DestinationCreationTO> destinations(PostTransportOrderRequestTO order) {
|
||||
List<DestinationCreationTO> result = new ArrayList<>(order.getDestinations().size());
|
||||
|
||||
for (Destination dest : order.getDestinations()) {
|
||||
DestinationCreationTO to = new DestinationCreationTO(
|
||||
dest.getLocationName(),
|
||||
dest.getOperation()
|
||||
);
|
||||
|
||||
if (dest.getProperties() != null) {
|
||||
for (Property prop : dest.getProperties()) {
|
||||
to = to.withProperty(prop.getKey(), prop.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
result.add(to);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<String> dependencyNames(List<String> dependencies) {
|
||||
return dependencies == null ? new HashSet<>() : new HashSet<>(dependencies);
|
||||
}
|
||||
|
||||
private Instant deadline(PostTransportOrderRequestTO order) {
|
||||
return order.getDeadline() == null ? Instant.MAX : order.getDeadline();
|
||||
}
|
||||
|
||||
private Map<String, String> properties(List<Property> properties) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
if (properties != null) {
|
||||
for (Property prop : properties) {
|
||||
result.put(prop.getKey(), prop.getValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,735 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import org.opentcs.access.KernelRuntimeException;
|
||||
import org.opentcs.data.ObjectExistsException;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.HttpConstants;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.JsonBinder;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.RequestHandler;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetOrderSequenceResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetPeripheralAttachmentInfoResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetPeripheralJobResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetTransportOrderResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetVehicleAttachmentInfoResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PlantModelTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostOrderSequenceRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostPeripheralJobRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostTopologyUpdateRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostTransportOrderRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostVehicleRoutesRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostVehicleRoutesResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PutVehicleAllowedOrderTypesTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PutVehicleEnergyLevelThresholdSetTO;
|
||||
import spark.QueryParamsMap;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Service;
|
||||
|
||||
/**
|
||||
* Handles requests and produces responses for version 1 of the web API.
|
||||
*/
|
||||
public class V1RequestHandler
|
||||
implements
|
||||
RequestHandler {
|
||||
|
||||
private final JsonBinder jsonBinder;
|
||||
private final StatusEventDispatcher statusEventDispatcher;
|
||||
private final TransportOrderDispatcherHandler orderDispatcherHandler;
|
||||
private final TransportOrderHandler transportOrderHandler;
|
||||
private final PeripheralJobHandler peripheralJobHandler;
|
||||
private final PeripheralJobDispatcherHandler jobDispatcherHandler;
|
||||
private final PlantModelHandler plantModelHandler;
|
||||
private final VehicleHandler vehicleHandler;
|
||||
private final PathHandler pathHandler;
|
||||
private final LocationHandler locationHandler;
|
||||
private final PeripheralHandler peripheralHandler;
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
@Inject
|
||||
public V1RequestHandler(
|
||||
JsonBinder jsonBinder,
|
||||
StatusEventDispatcher statusEventDispatcher,
|
||||
TransportOrderDispatcherHandler orderDispatcherHandler,
|
||||
TransportOrderHandler transportOrderHandler,
|
||||
PeripheralJobHandler peripheralJobHandler,
|
||||
PeripheralJobDispatcherHandler jobDispatcherHandler,
|
||||
PlantModelHandler plantModelHandler,
|
||||
VehicleHandler vehicleHandler,
|
||||
PathHandler pathHandler,
|
||||
LocationHandler locationHandler,
|
||||
PeripheralHandler peripheralHandler
|
||||
) {
|
||||
this.jsonBinder = requireNonNull(jsonBinder, "jsonBinder");
|
||||
this.statusEventDispatcher = requireNonNull(statusEventDispatcher, "statusEventDispatcher");
|
||||
this.orderDispatcherHandler = requireNonNull(orderDispatcherHandler, "orderDispatcherHandler");
|
||||
this.transportOrderHandler = requireNonNull(transportOrderHandler, "transportOrderHandler");
|
||||
this.peripheralJobHandler = requireNonNull(peripheralJobHandler, "peripheralJobHandler");
|
||||
this.jobDispatcherHandler = requireNonNull(jobDispatcherHandler, "jobDispatcherHandler");
|
||||
this.plantModelHandler = requireNonNull(plantModelHandler, "plantModelHandler");
|
||||
this.vehicleHandler = requireNonNull(vehicleHandler, "vehicleHandler");
|
||||
this.pathHandler = requireNonNull(pathHandler, "pathHandler");
|
||||
this.locationHandler = requireNonNull(locationHandler, "locationHandler");
|
||||
this.peripheralHandler = requireNonNull(peripheralHandler, "peripheralHandler");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
statusEventDispatcher.initialize();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
if (!isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
statusEventDispatcher.terminate();
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRoutes(Service service) {
|
||||
requireNonNull(service, "service");
|
||||
|
||||
service.get(
|
||||
"/events",
|
||||
this::handleGetEvents
|
||||
);
|
||||
service.post(
|
||||
"/vehicles/dispatcher/trigger",
|
||||
this::handlePostDispatcherTrigger
|
||||
);
|
||||
service.post(
|
||||
"/vehicles/:NAME/routeComputationQuery",
|
||||
this::handleGetVehicleRoutes
|
||||
);
|
||||
service.put(
|
||||
"/vehicles/:NAME/commAdapter/attachment",
|
||||
this::handlePutVehicleCommAdapterAttachment
|
||||
);
|
||||
service.get(
|
||||
"/vehicles/:NAME/commAdapter/attachmentInformation",
|
||||
this::handleGetVehicleCommAdapterAttachmentInfo
|
||||
);
|
||||
service.put(
|
||||
"/vehicles/:NAME/commAdapter/enabled",
|
||||
this::handlePutVehicleCommAdapterEnabled
|
||||
);
|
||||
service.put(
|
||||
"/vehicles/:NAME/paused",
|
||||
this::handlePutVehiclePaused
|
||||
);
|
||||
service.put(
|
||||
"/vehicles/:NAME/integrationLevel",
|
||||
this::handlePutVehicleIntegrationLevel
|
||||
);
|
||||
service.post(
|
||||
"/vehicles/:NAME/withdrawal",
|
||||
this::handlePostWithdrawalByVehicle
|
||||
);
|
||||
service.post(
|
||||
"/vehicles/:NAME/rerouteRequest",
|
||||
this::handlePostVehicleRerouteRequest
|
||||
);
|
||||
service.put(
|
||||
"/vehicles/:NAME/allowedOrderTypes",
|
||||
this::handlePutVehicleAllowedOrderTypes
|
||||
);
|
||||
service.put(
|
||||
"/vehicles/:NAME/energyLevelThresholdSet",
|
||||
this::handlePutVehicleEnergyLevelThresholdSet
|
||||
);
|
||||
service.put(
|
||||
"/vehicles/:NAME/envelopeKey",
|
||||
this::handlePutVehicleEnvelopeKey
|
||||
);
|
||||
service.get(
|
||||
"/vehicles/:NAME",
|
||||
this::handleGetVehicleByName
|
||||
);
|
||||
service.get(
|
||||
"/vehicles",
|
||||
this::handleGetVehicles
|
||||
);
|
||||
service.post(
|
||||
"/transportOrders/dispatcher/trigger",
|
||||
this::handlePostDispatcherTrigger
|
||||
);
|
||||
service.post(
|
||||
"/transportOrders/:NAME/immediateAssignment",
|
||||
this::handlePostImmediateAssignment
|
||||
);
|
||||
service.post(
|
||||
"/transportOrders/:NAME/withdrawal",
|
||||
this::handlePostWithdrawalByOrder
|
||||
);
|
||||
service.post(
|
||||
"/transportOrders/:NAME",
|
||||
this::handlePostTransportOrder
|
||||
);
|
||||
service.put(
|
||||
"/transportOrders/:NAME/intendedVehicle",
|
||||
this::handlePutTransportOrderIntendedVehicle
|
||||
);
|
||||
service.get(
|
||||
"/transportOrders/:NAME",
|
||||
this::handleGetTransportOrderByName
|
||||
);
|
||||
service.get(
|
||||
"/transportOrders",
|
||||
this::handleGetTransportOrders
|
||||
);
|
||||
service.post(
|
||||
"/orderSequences/:NAME",
|
||||
this::handlePostOrderSequence
|
||||
);
|
||||
service.get(
|
||||
"/orderSequences",
|
||||
this::handleGetOrderSequences
|
||||
);
|
||||
service.get(
|
||||
"/orderSequences/:NAME",
|
||||
this::handleGetOrderSequenceByName
|
||||
);
|
||||
service.put(
|
||||
"/orderSequences/:NAME/complete",
|
||||
this::handlePutOrderSequenceComplete
|
||||
);
|
||||
service.put(
|
||||
"/plantModel",
|
||||
this::handlePutPlantModel
|
||||
);
|
||||
service.get(
|
||||
"/plantModel",
|
||||
this::handleGetPlantModel
|
||||
);
|
||||
service.post(
|
||||
"/plantModel/topologyUpdateRequest",
|
||||
this::handlePostUpdateTopology
|
||||
);
|
||||
service.put(
|
||||
"/paths/:NAME/locked",
|
||||
this::handlePutPathLocked
|
||||
);
|
||||
service.put(
|
||||
"/locations/:NAME/locked",
|
||||
this::handlePutLocationLocked
|
||||
);
|
||||
service.post(
|
||||
"/dispatcher/trigger",
|
||||
this::handlePostDispatcherTrigger
|
||||
);
|
||||
service.post(
|
||||
"/peripherals/dispatcher/trigger",
|
||||
this::handlePostPeripheralJobsDispatchTrigger
|
||||
);
|
||||
service.post(
|
||||
"/peripherals/:NAME/withdrawal",
|
||||
this::handlePostPeripheralWithdrawal
|
||||
);
|
||||
service.put(
|
||||
"/peripherals/:NAME/commAdapter/enabled",
|
||||
this::handlePutPeripheralCommAdapterEnabled
|
||||
);
|
||||
service.get(
|
||||
"/peripherals/:NAME/commAdapter/attachmentInformation",
|
||||
this::handleGetPeripheralCommAdapterAttachmentInfo
|
||||
);
|
||||
service.put(
|
||||
"/peripherals/:NAME/commAdapter/attachment",
|
||||
this::handlePutPeripheralCommAdapterAttachment
|
||||
);
|
||||
service.get(
|
||||
"/peripheralJobs",
|
||||
this::handleGetPeripheralJobs
|
||||
);
|
||||
service.get(
|
||||
"/peripheralJobs/:NAME",
|
||||
this::handleGetPeripheralJobsByName
|
||||
);
|
||||
service.post(
|
||||
"/peripheralJobs/:NAME",
|
||||
this::handlePostPeripheralJobsByName
|
||||
);
|
||||
service.post(
|
||||
"/peripheralJobs/:NAME/withdrawal",
|
||||
this::handlePostPeripheralJobWithdrawal
|
||||
);
|
||||
service.post(
|
||||
"/peripheralJobs/dispatcher/trigger",
|
||||
this::handlePostPeripheralJobsDispatchTrigger
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePostDispatcherTrigger(Request request, Response response)
|
||||
throws KernelRuntimeException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
orderDispatcherHandler.triggerDispatcher();
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handleGetEvents(Request request, Response response)
|
||||
throws IllegalArgumentException,
|
||||
IllegalStateException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
statusEventDispatcher.fetchEvents(
|
||||
minSequenceNo(request),
|
||||
maxSequenceNo(request),
|
||||
timeout(request)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePutVehicleCommAdapterEnabled(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
vehicleHandler.putVehicleCommAdapterEnabled(
|
||||
request.params(":NAME"),
|
||||
valueIfKeyPresent(request.queryMap(), "newValue")
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handleGetVehicleCommAdapterAttachmentInfo(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
GetVehicleAttachmentInfoResponseTO.fromAttachmentInformation(
|
||||
vehicleHandler.getVehicleCommAdapterAttachmentInformation(
|
||||
request.params(":NAME")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handleGetVehicleRoutes(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
PostVehicleRoutesResponseTO.fromMap(
|
||||
vehicleHandler.getVehicleRoutes(
|
||||
request.params(":NAME"),
|
||||
jsonBinder.fromJson(request.body(), PostVehicleRoutesRequestTO.class)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePutVehicleCommAdapterAttachment(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
vehicleHandler.putVehicleCommAdapter(
|
||||
request.params(":NAME"),
|
||||
valueIfKeyPresent(request.queryMap(), "newValue")
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePostTransportOrder(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
ObjectExistsException,
|
||||
IllegalArgumentException,
|
||||
IllegalStateException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
GetTransportOrderResponseTO.fromTransportOrder(
|
||||
transportOrderHandler.createOrder(
|
||||
request.params(":NAME"),
|
||||
jsonBinder.fromJson(request.body(), PostTransportOrderRequestTO.class)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePutTransportOrderIntendedVehicle(Request request, Response response)
|
||||
throws ObjectUnknownException {
|
||||
transportOrderHandler.updateTransportOrderIntendedVehicle(
|
||||
request.params(":NAME"),
|
||||
request.queryParamOrDefault("vehicle", null)
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePostOrderSequence(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
ObjectExistsException,
|
||||
IllegalArgumentException,
|
||||
IllegalStateException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
GetOrderSequenceResponseTO.fromOrderSequence(
|
||||
transportOrderHandler.createOrderSequence(
|
||||
request.params(":NAME"),
|
||||
jsonBinder.fromJson(request.body(), PostOrderSequenceRequestTO.class)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handleGetOrderSequences(Request request, Response response) {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
transportOrderHandler.getOrderSequences(
|
||||
valueIfKeyPresent(request.queryMap(), "intendedVehicle")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handleGetOrderSequenceByName(Request request, Response response) {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
transportOrderHandler.getOrderSequenceByName(request.params(":NAME"))
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePutOrderSequenceComplete(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException,
|
||||
InterruptedException,
|
||||
ExecutionException {
|
||||
transportOrderHandler.putOrderSequenceComplete(request.params(":NAME"));
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePostImmediateAssignment(Request request, Response response)
|
||||
throws ObjectUnknownException {
|
||||
orderDispatcherHandler.tryImmediateAssignment(request.params(":NAME"));
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePostWithdrawalByOrder(Request request, Response response)
|
||||
throws ObjectUnknownException {
|
||||
orderDispatcherHandler.withdrawByTransportOrder(
|
||||
request.params(":NAME"),
|
||||
immediate(request),
|
||||
disableVehicle(request)
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePostWithdrawalByVehicle(Request request, Response response)
|
||||
throws ObjectUnknownException {
|
||||
orderDispatcherHandler.withdrawByVehicle(
|
||||
request.params(":NAME"),
|
||||
immediate(request),
|
||||
disableVehicle(request)
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePostPeripheralJobWithdrawal(Request request, Response response)
|
||||
throws KernelRuntimeException {
|
||||
jobDispatcherHandler.withdrawPeripheralJob(request.params(":NAME"));
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePostVehicleRerouteRequest(Request request, Response response)
|
||||
throws ObjectUnknownException {
|
||||
orderDispatcherHandler.reroute(request.params(":NAME"), forced(request));
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handleGetTransportOrders(Request request, Response response) {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
transportOrderHandler.getTransportOrders(
|
||||
valueIfKeyPresent(request.queryMap(), "intendedVehicle")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePutPlantModel(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
plantModelHandler.putPlantModel(jsonBinder.fromJson(request.body(), PlantModelTO.class));
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handleGetPlantModel(Request request, Response response) {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(plantModelHandler.getPlantModel());
|
||||
}
|
||||
|
||||
private Object handlePostUpdateTopology(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
KernelRuntimeException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
if (request.body().isBlank()) {
|
||||
plantModelHandler.requestTopologyUpdate(new PostTopologyUpdateRequestTO(List.of()));
|
||||
}
|
||||
else {
|
||||
plantModelHandler
|
||||
.requestTopologyUpdate(
|
||||
jsonBinder.fromJson(request.body(), PostTopologyUpdateRequestTO.class)
|
||||
);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePutPathLocked(Request request, Response response) {
|
||||
pathHandler.updatePathLock(
|
||||
request.params(":NAME"),
|
||||
valueIfKeyPresent(request.queryMap(), "newValue")
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePutLocationLocked(Request request, Response response) {
|
||||
locationHandler.updateLocationLock(
|
||||
request.params(":NAME"),
|
||||
valueIfKeyPresent(request.queryMap(), "newValue")
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handleGetTransportOrderByName(Request request, Response response) {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
transportOrderHandler.getTransportOrderByName(request.params(":NAME"))
|
||||
);
|
||||
}
|
||||
|
||||
private Object handleGetVehicles(Request request, Response response)
|
||||
throws IllegalArgumentException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
vehicleHandler.getVehiclesState(
|
||||
valueIfKeyPresent(
|
||||
request.queryMap(),
|
||||
"procState"
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handleGetVehicleByName(Request request, Response response)
|
||||
throws ObjectUnknownException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
vehicleHandler.getVehicleStateByName(request.params(":NAME"))
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePutVehicleIntegrationLevel(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
vehicleHandler.putVehicleIntegrationLevel(
|
||||
request.params(":NAME"),
|
||||
valueIfKeyPresent(request.queryMap(), "newValue")
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePutVehiclePaused(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
vehicleHandler.putVehiclePaused(
|
||||
request.params(":NAME"),
|
||||
valueIfKeyPresent(request.queryMap(), "newValue")
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePutVehicleAllowedOrderTypes(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
vehicleHandler.putVehicleAllowedOrderTypes(
|
||||
request.params(":NAME"),
|
||||
jsonBinder.fromJson(request.body(), PutVehicleAllowedOrderTypesTO.class)
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePutVehicleEnergyLevelThresholdSet(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
vehicleHandler.putVehicleEnergyLevelThresholdSet(
|
||||
request.params(":NAME"),
|
||||
jsonBinder.fromJson(request.body(), PutVehicleEnergyLevelThresholdSetTO.class)
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePutVehicleEnvelopeKey(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
vehicleHandler.putVehicleEnvelopeKey(
|
||||
request.params(":NAME"),
|
||||
valueIfKeyPresent(request.queryMap(), "newValue")
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePostPeripheralWithdrawal(Request request, Response response)
|
||||
throws KernelRuntimeException {
|
||||
jobDispatcherHandler.withdrawPeripheralJobByLocation(request.params(":NAME"));
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handlePutPeripheralCommAdapterEnabled(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
peripheralHandler.putPeripheralCommAdapterEnabled(
|
||||
request.params(":NAME"),
|
||||
valueIfKeyPresent(request.queryMap(), "newValue")
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handleGetPeripheralCommAdapterAttachmentInfo(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
GetPeripheralAttachmentInfoResponseTO.fromAttachmentInformation(
|
||||
peripheralHandler.getPeripheralCommAdapterAttachmentInformation(
|
||||
request.params(":NAME")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handleGetPeripheralJobs(Request request, Response response) {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
peripheralJobHandler.getPeripheralJobs(
|
||||
valueIfKeyPresent(request.queryMap(), "relatedVehicle"),
|
||||
valueIfKeyPresent(request.queryMap(), "relatedTransportOrder")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePutPeripheralCommAdapterAttachment(Request request, Response response)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
peripheralHandler.putPeripheralCommAdapter(
|
||||
request.params(":NAME"),
|
||||
valueIfKeyPresent(request.queryMap(), "newValue")
|
||||
);
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
return "";
|
||||
}
|
||||
|
||||
private Object handleGetPeripheralJobsByName(Request request, Response response) {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
peripheralJobHandler.getPeripheralJobByName(request.params(":NAME"))
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePostPeripheralJobsByName(Request request, Response response) {
|
||||
response.type(HttpConstants.CONTENT_TYPE_APPLICATION_JSON_UTF8);
|
||||
return jsonBinder.toJson(
|
||||
GetPeripheralJobResponseTO.fromPeripheralJob(
|
||||
peripheralJobHandler.createPeripheralJob(
|
||||
request.params(":NAME"),
|
||||
jsonBinder.fromJson(request.body(), PostPeripheralJobRequestTO.class)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Object handlePostPeripheralJobsDispatchTrigger(Request request, Response response) {
|
||||
response.type(HttpConstants.CONTENT_TYPE_TEXT_PLAIN_UTF8);
|
||||
jobDispatcherHandler.triggerJobDispatcher();
|
||||
return "";
|
||||
}
|
||||
|
||||
private String valueIfKeyPresent(QueryParamsMap queryParams, String key) {
|
||||
if (queryParams.hasKey(key)) {
|
||||
return queryParams.value(key);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private long minSequenceNo(Request request)
|
||||
throws IllegalArgumentException {
|
||||
String param = request.queryParamOrDefault("minSequenceNo", "0");
|
||||
try {
|
||||
return Long.parseLong(param);
|
||||
}
|
||||
catch (NumberFormatException exc) {
|
||||
throw new IllegalArgumentException("Malformed minSequenceNo: " + param);
|
||||
}
|
||||
}
|
||||
|
||||
private long maxSequenceNo(Request request)
|
||||
throws IllegalArgumentException {
|
||||
String param = request.queryParamOrDefault("maxSequenceNo", String.valueOf(Long.MAX_VALUE));
|
||||
try {
|
||||
return Long.parseLong(param);
|
||||
}
|
||||
catch (NumberFormatException exc) {
|
||||
throw new IllegalArgumentException("Malformed minSequenceNo: " + param);
|
||||
}
|
||||
}
|
||||
|
||||
private long timeout(Request request)
|
||||
throws IllegalArgumentException {
|
||||
String param = request.queryParamOrDefault("timeout", "1000");
|
||||
try {
|
||||
// Allow a maximum timeout of 10 seconds so server threads are only bound for a limited time.
|
||||
return Math.min(10000, Long.parseLong(param));
|
||||
}
|
||||
catch (NumberFormatException exc) {
|
||||
throw new IllegalArgumentException("Malformed timeout: " + param);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean immediate(Request request) {
|
||||
return Boolean.parseBoolean(request.queryParamOrDefault("immediate", "false"));
|
||||
}
|
||||
|
||||
private boolean disableVehicle(Request request) {
|
||||
return Boolean.parseBoolean(request.queryParamOrDefault("disableVehicle", "false"));
|
||||
}
|
||||
|
||||
private boolean forced(Request request) {
|
||||
return Boolean.parseBoolean(request.queryParamOrDefault("forced", "false"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.components.kernel.services.RouterService;
|
||||
import org.opentcs.components.kernel.services.VehicleService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.Path;
|
||||
import org.opentcs.data.model.Point;
|
||||
import org.opentcs.data.model.TCSResourceReference;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.model.Vehicle.EnergyLevelThresholdSet;
|
||||
import org.opentcs.data.order.Route;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapterDescription;
|
||||
import org.opentcs.drivers.vehicle.management.VehicleAttachmentInformation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetVehicleResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostVehicleRoutesRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PutVehicleAllowedOrderTypesTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PutVehicleEnergyLevelThresholdSetTO;
|
||||
|
||||
/**
|
||||
* Handles requests related to vehicles.
|
||||
*/
|
||||
public class VehicleHandler {
|
||||
|
||||
private final VehicleService vehicleService;
|
||||
private final RouterService routerService;
|
||||
private final KernelExecutorWrapper executorWrapper;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param vehicleService Used to update vehicle instances.
|
||||
* @param routerService Used to get information about potential routes.
|
||||
* @param executorWrapper Executes calls via the kernel executor and waits for the outcome.
|
||||
*/
|
||||
@Inject
|
||||
public VehicleHandler(
|
||||
VehicleService vehicleService,
|
||||
RouterService routerService,
|
||||
KernelExecutorWrapper executorWrapper
|
||||
) {
|
||||
this.vehicleService = requireNonNull(vehicleService, "vehicleService");
|
||||
this.routerService = requireNonNull(routerService, "routerService");
|
||||
this.executorWrapper = requireNonNull(executorWrapper, "executorWrapper");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all vehicles orders and filters depending on the given parameters.
|
||||
*
|
||||
* @param procStateName The filter parameter for the processing state of the vehicle.
|
||||
* The filtering is disabled for this parameter if the value is null.
|
||||
* @return A list of vehicles, that match the filter.
|
||||
* @throws IllegalArgumentException If procStateName could not be parsed.
|
||||
*/
|
||||
public List<GetVehicleResponseTO> getVehiclesState(
|
||||
@Nullable
|
||||
String procStateName
|
||||
)
|
||||
throws IllegalArgumentException {
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
Vehicle.ProcState pState = procStateName == null
|
||||
? null
|
||||
: Vehicle.ProcState.valueOf(procStateName);
|
||||
|
||||
return vehicleService.fetchObjects(Vehicle.class, Filters.vehicleWithProcState(pState))
|
||||
.stream()
|
||||
.map(GetVehicleResponseTO::fromVehicle)
|
||||
.sorted(Comparator.comparing(GetVehicleResponseTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the vehicle with the given name.
|
||||
*
|
||||
* @param name The name of the requested vehicle.
|
||||
* @return A single vehicle that has the given name.
|
||||
* @throws ObjectUnknownException If a vehicle with the given name does not exist.
|
||||
*/
|
||||
public GetVehicleResponseTO getVehicleStateByName(String name)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
return Optional.ofNullable(vehicleService.fetchObject(Vehicle.class, name))
|
||||
.map(GetVehicleResponseTO::fromVehicle)
|
||||
.orElseThrow(() -> new ObjectUnknownException("Unknown vehicle: " + name));
|
||||
});
|
||||
}
|
||||
|
||||
public void putVehicleIntegrationLevel(String name, String value)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(value, "value");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
|
||||
vehicleService.updateVehicleIntegrationLevel(
|
||||
vehicle.getReference(),
|
||||
Vehicle.IntegrationLevel.valueOf(value)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public void putVehiclePaused(String name, String value)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(value, "value");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
|
||||
vehicleService.updateVehiclePaused(vehicle.getReference(), Boolean.parseBoolean(value));
|
||||
});
|
||||
}
|
||||
|
||||
public void putVehicleEnvelopeKey(String name, String value)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
|
||||
vehicleService.updateVehicleEnvelopeKey(vehicle.getReference(), value);
|
||||
});
|
||||
}
|
||||
|
||||
public void putVehicleCommAdapterEnabled(String name, String value)
|
||||
throws ObjectUnknownException,
|
||||
IllegalArgumentException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(value, "value");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
|
||||
if (Boolean.parseBoolean(value)) {
|
||||
vehicleService.enableCommAdapter(vehicle.getReference());
|
||||
}
|
||||
else {
|
||||
vehicleService.disableCommAdapter(vehicle.getReference());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public VehicleAttachmentInformation getVehicleCommAdapterAttachmentInformation(String name)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
|
||||
return vehicleService.fetchAttachmentInformation(vehicle.getReference());
|
||||
});
|
||||
}
|
||||
|
||||
public void putVehicleCommAdapter(String name, String value)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(value, "value");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
|
||||
VehicleCommAdapterDescription newAdapter
|
||||
= vehicleService.fetchAttachmentInformation(vehicle.getReference())
|
||||
.getAvailableCommAdapters()
|
||||
.stream()
|
||||
.filter(description -> description.getClass().getName().equals(value))
|
||||
.findAny()
|
||||
.orElseThrow(
|
||||
() -> new IllegalArgumentException("Unknown vehicle driver class name: " + value)
|
||||
);
|
||||
vehicleService.attachCommAdapter(vehicle.getReference(), newAdapter);
|
||||
});
|
||||
}
|
||||
|
||||
public void putVehicleAllowedOrderTypes(
|
||||
String name,
|
||||
PutVehicleAllowedOrderTypesTO allowedOrderTypes
|
||||
)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(allowedOrderTypes, "allowedOrderTypes");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
vehicleService.updateVehicleAllowedOrderTypes(
|
||||
vehicle.getReference(), new HashSet<>(allowedOrderTypes.getOrderTypes())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public void putVehicleEnergyLevelThresholdSet(
|
||||
String name,
|
||||
PutVehicleEnergyLevelThresholdSetTO energyLevelThresholdSet
|
||||
)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(energyLevelThresholdSet, "energyLevelThresholdSet");
|
||||
|
||||
executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
|
||||
vehicleService.updateVehicleEnergyLevelThresholdSet(
|
||||
vehicle.getReference(),
|
||||
new EnergyLevelThresholdSet(
|
||||
energyLevelThresholdSet.getEnergyLevelCritical(),
|
||||
energyLevelThresholdSet.getEnergyLevelGood(),
|
||||
energyLevelThresholdSet.getEnergyLevelSufficientlyRecharged(),
|
||||
energyLevelThresholdSet.getEnergyLevelFullyRecharged()
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public Map<TCSObjectReference<Point>, Route> getVehicleRoutes(
|
||||
String name,
|
||||
PostVehicleRoutesRequestTO request
|
||||
)
|
||||
throws ObjectUnknownException {
|
||||
requireNonNull(name, "name");
|
||||
requireNonNull(request, "request");
|
||||
|
||||
return executorWrapper.callAndWait(() -> {
|
||||
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
if (vehicle == null) {
|
||||
throw new ObjectUnknownException("Unknown vehicle: " + name);
|
||||
}
|
||||
|
||||
TCSObjectReference<Point> sourcePointRef;
|
||||
if (request.getSourcePoint() == null) {
|
||||
if (vehicle.getCurrentPosition() == null) {
|
||||
throw new IllegalArgumentException("Unknown vehicle position: " + vehicle.getName());
|
||||
}
|
||||
sourcePointRef = vehicle.getCurrentPosition();
|
||||
}
|
||||
else {
|
||||
Point sourcePoint = vehicleService.fetchObject(Point.class, request.getSourcePoint());
|
||||
if (sourcePoint == null) {
|
||||
throw new ObjectUnknownException("Unknown source point: " + request.getSourcePoint());
|
||||
}
|
||||
sourcePointRef = sourcePoint.getReference();
|
||||
}
|
||||
|
||||
Set<TCSObjectReference<Point>> destinationPointRefs = request.getDestinationPoints()
|
||||
.stream()
|
||||
.map(destPointName -> {
|
||||
Point destPoint = vehicleService.fetchObject(Point.class, destPointName);
|
||||
if (destPoint == null) {
|
||||
throw new ObjectUnknownException("Unknown destination point: " + destPointName);
|
||||
}
|
||||
return destPoint.getReference();
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<TCSResourceReference<?>> resourcesToAvoid = new HashSet<>();
|
||||
|
||||
if (request.getResourcesToAvoid() != null) {
|
||||
for (String resourceName : request.getResourcesToAvoid()) {
|
||||
Point point = vehicleService.fetchObject(Point.class, resourceName);
|
||||
if (point != null) {
|
||||
resourcesToAvoid.add(point.getReference());
|
||||
continue;
|
||||
}
|
||||
|
||||
Path path = vehicleService.fetchObject(Path.class, resourceName);
|
||||
if (path != null) {
|
||||
resourcesToAvoid.add(path.getReference());
|
||||
continue;
|
||||
}
|
||||
|
||||
Location location = vehicleService.fetchObject(Location.class, resourceName);
|
||||
if (location != null) {
|
||||
resourcesToAvoid.add(location.getReference());
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new ObjectUnknownException("Unknown resource: " + resourceName);
|
||||
}
|
||||
}
|
||||
|
||||
return routerService.computeRoutes(
|
||||
vehicle.getReference(),
|
||||
sourcePointRef,
|
||||
destinationPointRefs,
|
||||
resourcesToAvoid
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.StatusMessage;
|
||||
|
||||
/**
|
||||
* A set of status messages sent via the status channel.
|
||||
*/
|
||||
public class GetEventsResponseTO {
|
||||
|
||||
private Instant timeStamp = Instant.now();
|
||||
|
||||
private List<StatusMessage> statusMessages = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public GetEventsResponseTO() {
|
||||
}
|
||||
|
||||
public List<StatusMessage> getStatusMessages() {
|
||||
return statusMessages;
|
||||
}
|
||||
|
||||
public GetEventsResponseTO setStatusMessages(List<StatusMessage> statusMessages) {
|
||||
this.statusMessages = requireNonNull(statusMessages, "statusMessages");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Instant getTimeStamp() {
|
||||
return timeStamp;
|
||||
}
|
||||
|
||||
public GetEventsResponseTO setTimeStamp(Instant timeStamp) {
|
||||
this.timeStamp = requireNonNull(timeStamp, "timeStamp");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.order.OrderConstants;
|
||||
import org.opentcs.data.order.OrderSequence;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* The current state of an order sequence.
|
||||
*/
|
||||
public class GetOrderSequenceResponseTO {
|
||||
|
||||
@Nonnull
|
||||
private String name;
|
||||
|
||||
@Nonnull
|
||||
private String type = OrderConstants.TYPE_NONE;
|
||||
|
||||
@Nonnull
|
||||
private List<String> orders = List.of();
|
||||
|
||||
private int finishedIndex;
|
||||
|
||||
private boolean complete;
|
||||
|
||||
private boolean finished;
|
||||
|
||||
private boolean failureFatal;
|
||||
|
||||
@Nullable
|
||||
private String intendedVehicle;
|
||||
|
||||
@Nullable
|
||||
private String processingVehicle;
|
||||
|
||||
@Nonnull
|
||||
private List<Property> properties = List.of();
|
||||
|
||||
public GetOrderSequenceResponseTO(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setType(
|
||||
@Nonnull
|
||||
String type
|
||||
) {
|
||||
this.type = requireNonNull(type, "type");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<String> getOrders() {
|
||||
return orders;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setOrders(
|
||||
@Nonnull
|
||||
List<String> orders
|
||||
) {
|
||||
this.orders = requireNonNull(orders, "orders");
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getFinishedIndex() {
|
||||
return finishedIndex;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setFinishedIndex(int finishedIndex) {
|
||||
this.finishedIndex = finishedIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setComplete(boolean complete) {
|
||||
this.complete = complete;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setFinished(boolean finished) {
|
||||
this.finished = finished;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isFailureFatal() {
|
||||
return failureFatal;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setFailureFatal(boolean failureFatal) {
|
||||
this.failureFatal = failureFatal;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getIntendedVehicle() {
|
||||
return intendedVehicle;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setIntendedVehicle(
|
||||
@Nullable
|
||||
String intendedVehicle
|
||||
) {
|
||||
this.intendedVehicle = intendedVehicle;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getProcessingVehicle() {
|
||||
return processingVehicle;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setProcessingVehicle(
|
||||
@Nullable
|
||||
String processingVehicle
|
||||
) {
|
||||
this.processingVehicle = processingVehicle;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public GetOrderSequenceResponseTO setProperties(
|
||||
@Nonnull
|
||||
List<Property> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static GetOrderSequenceResponseTO fromOrderSequence(OrderSequence orderSequence) {
|
||||
return new GetOrderSequenceResponseTO(orderSequence.getName())
|
||||
.setComplete(orderSequence.isComplete())
|
||||
.setFailureFatal(orderSequence.isFailureFatal())
|
||||
.setFinished(orderSequence.isFinished())
|
||||
.setFinishedIndex(orderSequence.getFinishedIndex())
|
||||
.setType(orderSequence.getType())
|
||||
.setOrders(
|
||||
orderSequence.getOrders()
|
||||
.stream()
|
||||
.map(TCSObjectReference::getName)
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
.setProcessingVehicle(nameOfNullableReference(orderSequence.getProcessingVehicle()))
|
||||
.setIntendedVehicle(nameOfNullableReference(orderSequence.getIntendedVehicle()))
|
||||
.setProperties(convertProperties(orderSequence.getProperties()));
|
||||
}
|
||||
|
||||
private static String nameOfNullableReference(
|
||||
@Nullable
|
||||
TCSObjectReference<?> reference
|
||||
) {
|
||||
return reference == null ? null : reference.getName();
|
||||
}
|
||||
|
||||
private static List<Property> convertProperties(Map<String, String> properties) {
|
||||
return properties.entrySet().stream()
|
||||
.map(property -> new Property(property.getKey(), property.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.drivers.peripherals.management.PeripheralAttachmentInformation;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class GetPeripheralAttachmentInfoResponseTO {
|
||||
|
||||
@Nonnull
|
||||
private String locationName;
|
||||
|
||||
@Nonnull
|
||||
private List<String> availableCommAdapters;
|
||||
|
||||
@Nonnull
|
||||
private String attachedCommAdapter;
|
||||
|
||||
public GetPeripheralAttachmentInfoResponseTO(
|
||||
@Nonnull
|
||||
String locationName,
|
||||
@Nonnull
|
||||
String attachedCommAdapter,
|
||||
@Nonnull
|
||||
List<String> availableCommAdapters
|
||||
) {
|
||||
this.locationName = requireNonNull(locationName, "locationName");
|
||||
this.attachedCommAdapter = requireNonNull(attachedCommAdapter, "attachedCommAdapter");
|
||||
this.availableCommAdapters = requireNonNull(availableCommAdapters, "availableCommAdapters");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getLocationName() {
|
||||
return locationName;
|
||||
}
|
||||
|
||||
public GetPeripheralAttachmentInfoResponseTO setLocationName(
|
||||
@Nonnull
|
||||
String locationName
|
||||
) {
|
||||
this.locationName = requireNonNull(locationName, "locationName");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<String> getAvailableCommAdapters() {
|
||||
return availableCommAdapters;
|
||||
}
|
||||
|
||||
public GetPeripheralAttachmentInfoResponseTO setAvailableCommAdapters(
|
||||
@Nonnull
|
||||
List<String> availableCommAdapters
|
||||
) {
|
||||
this.availableCommAdapters = requireNonNull(availableCommAdapters, "availableCommAdapters");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getAttachedCommAdapter() {
|
||||
return attachedCommAdapter;
|
||||
}
|
||||
|
||||
public GetPeripheralAttachmentInfoResponseTO setAttachedCommAdapter(
|
||||
@Nonnull
|
||||
String attachedCommAdapter
|
||||
) {
|
||||
this.attachedCommAdapter = requireNonNull(attachedCommAdapter, "attachedCommAdapter");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static GetPeripheralAttachmentInfoResponseTO fromAttachmentInformation(
|
||||
@Nullable
|
||||
PeripheralAttachmentInformation peripheralAttachmentInfo
|
||||
) {
|
||||
if (peripheralAttachmentInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> availableAdapters = peripheralAttachmentInfo.getAvailableCommAdapters()
|
||||
.stream()
|
||||
.map(description -> description.getClass().getName())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new GetPeripheralAttachmentInfoResponseTO(
|
||||
peripheralAttachmentInfo.getLocationReference().getName(),
|
||||
peripheralAttachmentInfo.getAttachedCommAdapter().getClass().getName(),
|
||||
availableAdapters
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.data.peripherals.PeripheralJob.State;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PeripheralOperationDescription;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* The current state of a peripheral job.
|
||||
*/
|
||||
public class GetPeripheralJobResponseTO {
|
||||
|
||||
private String name;
|
||||
|
||||
private String reservationToken;
|
||||
|
||||
private String relatedVehicle;
|
||||
|
||||
private String relatedTransportOrder;
|
||||
|
||||
private PeripheralOperationDescription peripheralOperation;
|
||||
|
||||
private State state;
|
||||
|
||||
private Instant creationTime;
|
||||
|
||||
private Instant finishedTime;
|
||||
|
||||
private List<Property> properties;
|
||||
|
||||
public GetPeripheralJobResponseTO() {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public GetPeripheralJobResponseTO setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getReservationToken() {
|
||||
return reservationToken;
|
||||
}
|
||||
|
||||
public GetPeripheralJobResponseTO setReservationToken(String reservationToken) {
|
||||
this.reservationToken = reservationToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRelatedVehicle() {
|
||||
return relatedVehicle;
|
||||
}
|
||||
|
||||
public GetPeripheralJobResponseTO setRelatedVehicle(String relatedVehicle) {
|
||||
this.relatedVehicle = relatedVehicle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRelatedTransportOrder() {
|
||||
return relatedTransportOrder;
|
||||
}
|
||||
|
||||
public GetPeripheralJobResponseTO setRelatedTransportOrder(String relatedTransportOrder) {
|
||||
this.relatedTransportOrder = relatedTransportOrder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PeripheralOperationDescription getPeripheralOperation() {
|
||||
return peripheralOperation;
|
||||
}
|
||||
|
||||
public GetPeripheralJobResponseTO setPeripheralOperation(
|
||||
PeripheralOperationDescription peripheralOperation
|
||||
) {
|
||||
this.peripheralOperation = peripheralOperation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public GetPeripheralJobResponseTO setState(State state) {
|
||||
this.state = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Instant getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
public GetPeripheralJobResponseTO setCreationTime(Instant creationTime) {
|
||||
this.creationTime = creationTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Instant getFinishedTime() {
|
||||
return finishedTime;
|
||||
}
|
||||
|
||||
public GetPeripheralJobResponseTO setFinishedTime(Instant finishedTime) {
|
||||
this.finishedTime = finishedTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public GetPeripheralJobResponseTO setProperties(List<Property> properties) {
|
||||
this.properties = properties;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static GetPeripheralJobResponseTO fromPeripheralJob(PeripheralJob job) {
|
||||
GetPeripheralJobResponseTO state = new GetPeripheralJobResponseTO();
|
||||
state.name = job.getName();
|
||||
state.reservationToken = job.getReservationToken();
|
||||
if (job.getRelatedVehicle() != null) {
|
||||
state.relatedVehicle = job.getRelatedVehicle().getName();
|
||||
}
|
||||
if (job.getRelatedTransportOrder() != null) {
|
||||
state.relatedTransportOrder = job.getRelatedTransportOrder().getName();
|
||||
}
|
||||
state.peripheralOperation
|
||||
= PeripheralOperationDescription.fromPeripheralOperation(job.getPeripheralOperation());
|
||||
state.state = job.getState();
|
||||
state.creationTime = job.getCreationTime();
|
||||
state.finishedTime = job.getFinishedTime();
|
||||
state.properties = job.getProperties().entrySet().stream()
|
||||
.map(entry -> new Property(entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.DestinationState;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class GetTransportOrderResponseTO {
|
||||
|
||||
private boolean dispensable;
|
||||
|
||||
private String name = "";
|
||||
|
||||
private String peripheralReservationToken;
|
||||
|
||||
private String wrappingSequence;
|
||||
|
||||
private String type = "";
|
||||
|
||||
private TransportOrder.State state = TransportOrder.State.RAW;
|
||||
|
||||
private String intendedVehicle;
|
||||
|
||||
private String processingVehicle;
|
||||
|
||||
private List<DestinationState> destinations = new ArrayList<>();
|
||||
|
||||
public GetTransportOrderResponseTO() {
|
||||
}
|
||||
|
||||
public boolean isDispensable() {
|
||||
return dispensable;
|
||||
}
|
||||
|
||||
public GetTransportOrderResponseTO setDispensable(boolean dispensable) {
|
||||
this.dispensable = dispensable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public GetTransportOrderResponseTO setName(String name) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPeripheralReservationToken() {
|
||||
return peripheralReservationToken;
|
||||
}
|
||||
|
||||
public GetTransportOrderResponseTO setPeripheralReservationToken(
|
||||
String peripheralReservationToken
|
||||
) {
|
||||
this.peripheralReservationToken = peripheralReservationToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getWrappingSequence() {
|
||||
return wrappingSequence;
|
||||
}
|
||||
|
||||
public GetTransportOrderResponseTO setWrappingSequence(String wrappingSequence) {
|
||||
this.wrappingSequence = wrappingSequence;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public GetTransportOrderResponseTO setType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TransportOrder.State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public GetTransportOrderResponseTO setState(TransportOrder.State state) {
|
||||
this.state = requireNonNull(state, "state");
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getIntendedVehicle() {
|
||||
return intendedVehicle;
|
||||
}
|
||||
|
||||
public GetTransportOrderResponseTO setIntendedVehicle(String intendedVehicle) {
|
||||
this.intendedVehicle = intendedVehicle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getProcessingVehicle() {
|
||||
return processingVehicle;
|
||||
}
|
||||
|
||||
public GetTransportOrderResponseTO setProcessingVehicle(String processingVehicle) {
|
||||
this.processingVehicle = processingVehicle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<DestinationState> getDestinations() {
|
||||
return destinations;
|
||||
}
|
||||
|
||||
public GetTransportOrderResponseTO setDestinations(List<DestinationState> destinations) {
|
||||
this.destinations = requireNonNull(destinations, "destinations");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from a <code>TransportOrder</code>.
|
||||
*
|
||||
* @param transportOrder The transport order to create an instance from.
|
||||
* @return A new instance containing the data from the given transport order.
|
||||
*/
|
||||
public static GetTransportOrderResponseTO fromTransportOrder(TransportOrder transportOrder) {
|
||||
if (transportOrder == null) {
|
||||
return null;
|
||||
}
|
||||
GetTransportOrderResponseTO transportOrderState = new GetTransportOrderResponseTO();
|
||||
transportOrderState.setDispensable(transportOrder.isDispensable());
|
||||
transportOrderState.setName(transportOrder.getName());
|
||||
transportOrderState.setPeripheralReservationToken(
|
||||
transportOrder.getPeripheralReservationToken()
|
||||
);
|
||||
transportOrderState.setWrappingSequence(
|
||||
nameOfNullableReference(transportOrder.getWrappingSequence())
|
||||
);
|
||||
transportOrderState.setType(transportOrder.getType());
|
||||
transportOrderState.setDestinations(
|
||||
transportOrder.getAllDriveOrders()
|
||||
.stream()
|
||||
.map(driveOrder -> DestinationState.fromDriveOrder(driveOrder))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
transportOrderState.setIntendedVehicle(
|
||||
nameOfNullableReference(transportOrder.getIntendedVehicle())
|
||||
);
|
||||
transportOrderState.setProcessingVehicle(
|
||||
nameOfNullableReference(transportOrder.getProcessingVehicle())
|
||||
);
|
||||
transportOrderState.setState(transportOrder.getState());
|
||||
return transportOrderState;
|
||||
}
|
||||
|
||||
private static String nameOfNullableReference(
|
||||
@Nullable
|
||||
TCSObjectReference<?> reference
|
||||
) {
|
||||
return reference == null ? null : reference.getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.drivers.vehicle.management.VehicleAttachmentInformation;
|
||||
|
||||
/**
|
||||
* Arranges the data from a vehicle's <code>AttachmentInformation</code> for transferring.
|
||||
*/
|
||||
public class GetVehicleAttachmentInfoResponseTO {
|
||||
|
||||
/**
|
||||
* The vehicle this attachment information belongs to.
|
||||
*/
|
||||
private String vehicleName;
|
||||
/**
|
||||
* The list of comm adapters available to be attached to the referenced vehicle.
|
||||
*/
|
||||
private List<String> availableCommAdapters;
|
||||
/**
|
||||
* The comm adapter attached to the referenced vehicle.
|
||||
*/
|
||||
private String attachedCommAdapter;
|
||||
|
||||
public GetVehicleAttachmentInfoResponseTO() {
|
||||
}
|
||||
|
||||
public GetVehicleAttachmentInfoResponseTO setVehicleName(String vehicleName) {
|
||||
this.vehicleName = requireNonNull(vehicleName, "vehicleName");
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getVehicleName() {
|
||||
return vehicleName;
|
||||
}
|
||||
|
||||
public GetVehicleAttachmentInfoResponseTO setAvailableCommAdapters(
|
||||
List<String> availableCommAdapters
|
||||
) {
|
||||
this.availableCommAdapters = requireNonNull(availableCommAdapters, "availableCommAdapters");
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getAvailableCommAdapters() {
|
||||
return availableCommAdapters;
|
||||
}
|
||||
|
||||
public GetVehicleAttachmentInfoResponseTO setAttachedCommAdapter(String attachedCommAdapter) {
|
||||
this.attachedCommAdapter = requireNonNull(attachedCommAdapter, "attachedCommAdapter");
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAttachedCommAdapter() {
|
||||
return attachedCommAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from <code>AttachmentInformation</code>.
|
||||
*
|
||||
* @param attachmentInformation The <code>AttachmentInformation</code> to create an
|
||||
* instance from.
|
||||
* @return A new instance containing the data from the given <code>AttachmentInformation</code>.
|
||||
*/
|
||||
public static GetVehicleAttachmentInfoResponseTO fromAttachmentInformation(
|
||||
VehicleAttachmentInformation attachmentInformation
|
||||
) {
|
||||
if (attachmentInformation == null) {
|
||||
return null;
|
||||
}
|
||||
GetVehicleAttachmentInfoResponseTO attachmentInformationTO
|
||||
= new GetVehicleAttachmentInfoResponseTO();
|
||||
|
||||
attachmentInformationTO.setVehicleName(
|
||||
attachmentInformation.getVehicleReference()
|
||||
.getName()
|
||||
);
|
||||
attachmentInformationTO.setAvailableCommAdapters(
|
||||
attachmentInformation.getAvailableCommAdapters()
|
||||
.stream()
|
||||
.map(description -> description.getClass().getName())
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
attachmentInformationTO.setAttachedCommAdapter(
|
||||
attachmentInformation.getAttachedCommAdapter()
|
||||
.getClass()
|
||||
.getName()
|
||||
);
|
||||
|
||||
return attachmentInformationTO;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.model.TCSResourceReference;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.model.Vehicle.IntegrationLevel;
|
||||
import org.opentcs.data.model.Vehicle.ProcState;
|
||||
import org.opentcs.data.model.Vehicle.State;
|
||||
import org.opentcs.util.annotations.ScheduledApiChange;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class GetVehicleResponseTO {
|
||||
|
||||
private String name;
|
||||
|
||||
private Map<String, String> properties = new HashMap<>();
|
||||
|
||||
private int length;
|
||||
|
||||
private int energyLevelGood;
|
||||
|
||||
private int energyLevelCritical;
|
||||
|
||||
private int energyLevelSufficientlyRecharged;
|
||||
|
||||
private int energyLevelFullyRecharged;
|
||||
|
||||
private int energyLevel;
|
||||
|
||||
private IntegrationLevel integrationLevel = IntegrationLevel.TO_BE_RESPECTED;
|
||||
|
||||
private boolean paused;
|
||||
|
||||
private ProcState procState = ProcState.IDLE;
|
||||
|
||||
private String transportOrder;
|
||||
|
||||
private String currentPosition;
|
||||
|
||||
private PrecisePosition precisePosition;
|
||||
|
||||
private double orientationAngle;
|
||||
|
||||
private State state = State.UNKNOWN;
|
||||
|
||||
private List<List<String>> allocatedResources = new ArrayList<>();
|
||||
|
||||
private List<List<String>> claimedResources = new ArrayList<>();
|
||||
|
||||
private List<String> allowedOrderTypes = new ArrayList<>();
|
||||
|
||||
private String envelopeKey;
|
||||
|
||||
public GetVehicleResponseTO() {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setName(String name) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setLength(int length) {
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelGood() {
|
||||
return energyLevelGood;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setEnergyLevelGood(int energyLevelGood) {
|
||||
this.energyLevelGood = energyLevelGood;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelCritical() {
|
||||
return energyLevelCritical;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setEnergyLevelCritical(int energyLevelCritical) {
|
||||
this.energyLevelCritical = energyLevelCritical;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelSufficientlyRecharged() {
|
||||
return energyLevelSufficientlyRecharged;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setEnergyLevelSufficientlyRecharged(
|
||||
int energyLevelSufficientlyRecharged
|
||||
) {
|
||||
this.energyLevelSufficientlyRecharged = energyLevelSufficientlyRecharged;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelFullyRecharged() {
|
||||
return energyLevelFullyRecharged;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setEnergyLevelFullyRecharged(int energyLevelFullyRecharged) {
|
||||
this.energyLevelFullyRecharged = energyLevelFullyRecharged;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevel() {
|
||||
return energyLevel;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setEnergyLevel(int energyLevel) {
|
||||
this.energyLevel = energyLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IntegrationLevel getIntegrationLevel() {
|
||||
return integrationLevel;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setIntegrationLevel(IntegrationLevel integrationLevel) {
|
||||
this.integrationLevel = requireNonNull(integrationLevel, "integrationLevel");
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isPaused() {
|
||||
return paused;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setPaused(boolean paused) {
|
||||
this.paused = paused;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProcState getProcState() {
|
||||
return procState;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setProcState(Vehicle.ProcState procState) {
|
||||
this.procState = requireNonNull(procState, "procState");
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTransportOrder() {
|
||||
return transportOrder;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setTransportOrder(String transportOrder) {
|
||||
this.transportOrder = transportOrder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getCurrentPosition() {
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setCurrentPosition(String currentPosition) {
|
||||
this.currentPosition = currentPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PrecisePosition getPrecisePosition() {
|
||||
return precisePosition;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setPrecisePosition(PrecisePosition precisePosition) {
|
||||
this.precisePosition = precisePosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getOrientationAngle() {
|
||||
return orientationAngle;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setOrientationAngle(double orientationAngle) {
|
||||
this.orientationAngle = orientationAngle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setState(State state) {
|
||||
this.state = requireNonNull(state, "state");
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<List<String>> getAllocatedResources() {
|
||||
return allocatedResources;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setAllocatedResources(List<List<String>> allocatedResources) {
|
||||
this.allocatedResources = requireNonNull(allocatedResources, "allocatedResources");
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<List<String>> getClaimedResources() {
|
||||
return claimedResources;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setClaimedResources(List<List<String>> claimedResources) {
|
||||
this.claimedResources = requireNonNull(claimedResources, "claimedResources");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setProperties(Map<String, String> properties) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getAllowedOrderTypes() {
|
||||
return allowedOrderTypes;
|
||||
}
|
||||
|
||||
public GetVehicleResponseTO setAllowedOrderTypes(List<String> allowedOrderTypes) {
|
||||
this.allowedOrderTypes = requireNonNull(allowedOrderTypes, "allowedOrderTypes");
|
||||
return this;
|
||||
}
|
||||
|
||||
@ScheduledApiChange(when = "7.0", details = "Envelope key will become non-null.")
|
||||
@Nullable
|
||||
public String getEnvelopeKey() {
|
||||
return envelopeKey;
|
||||
}
|
||||
|
||||
@ScheduledApiChange(when = "7.0", details = "Envelope key will become non-null.")
|
||||
public GetVehicleResponseTO setEnvelopeKey(
|
||||
@Nullable
|
||||
String envelopeKey
|
||||
) {
|
||||
this.envelopeKey = envelopeKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <Code>VehicleState</Code> instance from a <Code>Vehicle</Code> instance.
|
||||
*
|
||||
* @param vehicle The vehicle whose properties will be used to create a <Code>VehicleState</Code>
|
||||
* instance.
|
||||
* @return A new <Code>VehicleState</Code> instance filled with data from the given vehicle.
|
||||
*/
|
||||
public static GetVehicleResponseTO fromVehicle(Vehicle vehicle) {
|
||||
if (vehicle == null) {
|
||||
return null;
|
||||
}
|
||||
GetVehicleResponseTO vehicleState = new GetVehicleResponseTO();
|
||||
vehicleState.setName(vehicle.getName());
|
||||
vehicleState.setProperties(vehicle.getProperties());
|
||||
vehicleState.setLength((int) vehicle.getBoundingBox().getLength());
|
||||
vehicleState.setEnergyLevelCritical(
|
||||
vehicle.getEnergyLevelThresholdSet().getEnergyLevelCritical()
|
||||
);
|
||||
vehicleState.setEnergyLevelGood(vehicle.getEnergyLevelThresholdSet().getEnergyLevelGood());
|
||||
vehicleState.setEnergyLevelSufficientlyRecharged(
|
||||
vehicle.getEnergyLevelThresholdSet().getEnergyLevelSufficientlyRecharged()
|
||||
);
|
||||
vehicleState.setEnergyLevelFullyRecharged(
|
||||
vehicle.getEnergyLevelThresholdSet().getEnergyLevelFullyRecharged()
|
||||
);
|
||||
vehicleState.setEnergyLevel(vehicle.getEnergyLevel());
|
||||
vehicleState.setIntegrationLevel(vehicle.getIntegrationLevel());
|
||||
vehicleState.setPaused(vehicle.isPaused());
|
||||
vehicleState.setProcState(vehicle.getProcState());
|
||||
vehicleState.setTransportOrder(nameOfNullableReference(vehicle.getTransportOrder()));
|
||||
vehicleState.setCurrentPosition(nameOfNullableReference(vehicle.getCurrentPosition()));
|
||||
if (vehicle.getPose().getPosition() != null) {
|
||||
vehicleState.setPrecisePosition(
|
||||
new PrecisePosition(
|
||||
vehicle.getPose().getPosition().getX(),
|
||||
vehicle.getPose().getPosition().getY(),
|
||||
vehicle.getPose().getPosition().getZ()
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
vehicleState.setPrecisePosition(null);
|
||||
}
|
||||
vehicleState.setOrientationAngle(vehicle.getPose().getOrientationAngle());
|
||||
vehicleState.setState(vehicle.getState());
|
||||
vehicleState.setAllocatedResources(toListOfListOfNames(vehicle.getAllocatedResources()));
|
||||
vehicleState.setClaimedResources(toListOfListOfNames(vehicle.getClaimedResources()));
|
||||
vehicleState.setEnvelopeKey(vehicle.getEnvelopeKey());
|
||||
vehicleState.setAllowedOrderTypes(
|
||||
vehicle.getAllowedOrderTypes()
|
||||
.stream()
|
||||
.sorted()
|
||||
.collect(Collectors.toCollection(ArrayList::new))
|
||||
);
|
||||
return vehicleState;
|
||||
}
|
||||
|
||||
private static String nameOfNullableReference(
|
||||
@Nullable
|
||||
TCSObjectReference<?> reference
|
||||
) {
|
||||
return reference == null ? null : reference.getName();
|
||||
}
|
||||
|
||||
private static List<List<String>> toListOfListOfNames(
|
||||
List<Set<TCSResourceReference<?>>> resources
|
||||
) {
|
||||
List<List<String>> result = new ArrayList<>(resources.size());
|
||||
|
||||
for (Set<TCSResourceReference<?>> resSet : resources) {
|
||||
result.add(
|
||||
resSet.stream()
|
||||
.map(resRef -> resRef.getName())
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A precise position of a vehicle.
|
||||
*/
|
||||
public static class PrecisePosition {
|
||||
|
||||
private long x;
|
||||
|
||||
private long y;
|
||||
|
||||
private long z;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public PrecisePosition() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param x x value
|
||||
* @param y y value
|
||||
* @param z z value
|
||||
*/
|
||||
public PrecisePosition(long x, long y, long z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public long getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(long x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public long getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(long y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public long getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(long z) {
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.BlockTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.LocationTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.LocationTypeTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.PathTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.PointTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.VehicleTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.VisualLayoutTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class PlantModelTO {
|
||||
|
||||
private String name;
|
||||
private List<PointTO> points = List.of();
|
||||
private List<PathTO> paths = List.of();
|
||||
private List<LocationTypeTO> locationTypes = List.of();
|
||||
private List<LocationTO> locations = List.of();
|
||||
private List<BlockTO> blocks = List.of();
|
||||
private List<VehicleTO> vehicles = List.of();
|
||||
private VisualLayoutTO visualLayout = new VisualLayoutTO("unnamed");
|
||||
private List<PropertyTO> properties = List.of();
|
||||
|
||||
@JsonCreator
|
||||
public PlantModelTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public PlantModelTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PropertyTO> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public PlantModelTO setProperties(
|
||||
@Nonnull
|
||||
List<PropertyTO> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PointTO> getPoints() {
|
||||
return points;
|
||||
}
|
||||
|
||||
public PlantModelTO setPoints(
|
||||
@Nonnull
|
||||
List<PointTO> points
|
||||
) {
|
||||
this.points = requireNonNull(points, "points");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PathTO> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
public PlantModelTO setPaths(
|
||||
@Nonnull
|
||||
List<PathTO> paths
|
||||
) {
|
||||
this.paths = requireNonNull(paths, "paths");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<LocationTO> getLocations() {
|
||||
return locations;
|
||||
}
|
||||
|
||||
public PlantModelTO setLocations(
|
||||
@Nonnull
|
||||
List<LocationTO> locations
|
||||
) {
|
||||
this.locations = requireNonNull(locations, "locations");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<LocationTypeTO> getLocationTypes() {
|
||||
return locationTypes;
|
||||
}
|
||||
|
||||
public PlantModelTO setLocationTypes(
|
||||
@Nonnull
|
||||
List<LocationTypeTO> locationTypes
|
||||
) {
|
||||
this.locationTypes = requireNonNull(locationTypes, "locationTypes");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<BlockTO> getBlocks() {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public PlantModelTO setBlocks(
|
||||
@Nonnull
|
||||
List<BlockTO> blocks
|
||||
) {
|
||||
this.blocks = requireNonNull(blocks, "blocks");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<VehicleTO> getVehicles() {
|
||||
return vehicles;
|
||||
}
|
||||
|
||||
public PlantModelTO setVehicles(
|
||||
@Nonnull
|
||||
List<VehicleTO> vehicles
|
||||
) {
|
||||
this.vehicles = requireNonNull(vehicles, "vehicles");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public VisualLayoutTO getVisualLayout() {
|
||||
return visualLayout;
|
||||
}
|
||||
|
||||
public PlantModelTO setVisualLayout(
|
||||
@Nonnull
|
||||
VisualLayoutTO visualLayout
|
||||
) {
|
||||
this.visualLayout = requireNonNull(visualLayout, "visualLayout");
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import org.opentcs.data.order.OrderConstants;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* An order sequence to be created by the kernel.
|
||||
*/
|
||||
public class PostOrderSequenceRequestTO {
|
||||
|
||||
private boolean incompleteName;
|
||||
|
||||
@Nonnull
|
||||
private String type = OrderConstants.TYPE_NONE;
|
||||
|
||||
@Nullable
|
||||
private String intendedVehicle;
|
||||
|
||||
private boolean failureFatal;
|
||||
|
||||
@Nonnull
|
||||
private List<Property> properties = List.of();
|
||||
|
||||
public PostOrderSequenceRequestTO() {
|
||||
|
||||
}
|
||||
|
||||
public boolean isIncompleteName() {
|
||||
return incompleteName;
|
||||
}
|
||||
|
||||
public PostOrderSequenceRequestTO setIncompleteName(boolean incompleteName) {
|
||||
this.incompleteName = incompleteName;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public PostOrderSequenceRequestTO setType(
|
||||
@Nonnull
|
||||
String type
|
||||
) {
|
||||
this.type = requireNonNull(type, "type");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getIntendedVehicle() {
|
||||
return intendedVehicle;
|
||||
}
|
||||
|
||||
public PostOrderSequenceRequestTO setIntendedVehicle(
|
||||
@Nullable
|
||||
String intendedVehicle
|
||||
) {
|
||||
this.intendedVehicle = intendedVehicle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isFailureFatal() {
|
||||
return failureFatal;
|
||||
}
|
||||
|
||||
public PostOrderSequenceRequestTO setFailureFatal(boolean failureFatal) {
|
||||
this.failureFatal = failureFatal;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public PostOrderSequenceRequestTO setProperties(
|
||||
@Nonnull
|
||||
List<Property> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import java.util.List;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PeripheralOperationDescription;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* A peripheral job to be processed by the kernel.
|
||||
*/
|
||||
public class PostPeripheralJobRequestTO {
|
||||
|
||||
private boolean incompleteName;
|
||||
|
||||
private String reservationToken;
|
||||
|
||||
private String relatedVehicle;
|
||||
|
||||
private String relatedTransportOrder;
|
||||
|
||||
private PeripheralOperationDescription peripheralOperation;
|
||||
|
||||
private List<Property> properties;
|
||||
|
||||
public PostPeripheralJobRequestTO() {
|
||||
}
|
||||
|
||||
public boolean isIncompleteName() {
|
||||
return incompleteName;
|
||||
}
|
||||
|
||||
public PostPeripheralJobRequestTO setIncompleteName(boolean incompleteName) {
|
||||
this.incompleteName = incompleteName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getReservationToken() {
|
||||
return reservationToken;
|
||||
}
|
||||
|
||||
public PostPeripheralJobRequestTO setReservationToken(String reservationToken) {
|
||||
this.reservationToken = reservationToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRelatedVehicle() {
|
||||
return relatedVehicle;
|
||||
}
|
||||
|
||||
public PostPeripheralJobRequestTO setRelatedVehicle(String relatedVehicle) {
|
||||
this.relatedVehicle = relatedVehicle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRelatedTransportOrder() {
|
||||
return relatedTransportOrder;
|
||||
}
|
||||
|
||||
public PostPeripheralJobRequestTO setRelatedTransportOrder(String relatedTransportOrder) {
|
||||
this.relatedTransportOrder = relatedTransportOrder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PeripheralOperationDescription getPeripheralOperation() {
|
||||
return peripheralOperation;
|
||||
}
|
||||
|
||||
public PostPeripheralJobRequestTO setPeripheralOperation(
|
||||
PeripheralOperationDescription peripheralOperation
|
||||
) {
|
||||
this.peripheralOperation = peripheralOperation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public PostPeripheralJobRequestTO setProperties(List<Property> properties) {
|
||||
this.properties = properties;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A list of paths that are to be updated when the routing topology gets updated.
|
||||
*/
|
||||
public class PostTopologyUpdateRequestTO {
|
||||
|
||||
@Nonnull
|
||||
private List<String> paths;
|
||||
|
||||
@JsonCreator
|
||||
public PostTopologyUpdateRequestTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "paths", required = true)
|
||||
List<String> paths
|
||||
) {
|
||||
this.paths = requireNonNull(paths, "paths");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<String> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
public PostTopologyUpdateRequestTO setPaths(
|
||||
@Nonnull
|
||||
List<String> paths
|
||||
) {
|
||||
this.paths = requireNonNull(paths, "paths");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.posttransportorder.Destination;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* A transport order to be processed by the kernel.
|
||||
*/
|
||||
public class PostTransportOrderRequestTO {
|
||||
|
||||
private boolean incompleteName;
|
||||
|
||||
private boolean dispensable;
|
||||
|
||||
private Instant deadline;
|
||||
|
||||
private String intendedVehicle;
|
||||
|
||||
private String peripheralReservationToken;
|
||||
|
||||
private String wrappingSequence;
|
||||
|
||||
private String type;
|
||||
|
||||
private List<Destination> destinations;
|
||||
|
||||
private List<Property> properties;
|
||||
|
||||
private List<String> dependencies;
|
||||
|
||||
// CHECKSTYLE:OFF (because of very long parameter declarations)
|
||||
@JsonCreator
|
||||
public PostTransportOrderRequestTO(
|
||||
@JsonProperty(required = false, value = "incompleteName")
|
||||
boolean incompleteName,
|
||||
@JsonProperty(required = false, value = "dispensable")
|
||||
boolean dispensable,
|
||||
@Nullable
|
||||
@JsonProperty(required = false, value = "deadline")
|
||||
Instant deadline,
|
||||
@Nullable
|
||||
@JsonProperty(required = false, value = "intendedVehicle")
|
||||
String intendedVehicle,
|
||||
@Nullable
|
||||
@JsonProperty(required = false, value = "peripheralReservationToken")
|
||||
String peripheralReservationToken,
|
||||
@Nullable
|
||||
@JsonProperty(required = false, value = "wrappingSequence")
|
||||
String wrappingSequence,
|
||||
@Nullable
|
||||
@JsonProperty(required = false, value = "type")
|
||||
String type,
|
||||
@Nonnull
|
||||
@JsonProperty(required = true, value = "destinations")
|
||||
List<Destination> destinations,
|
||||
@Nullable
|
||||
@JsonProperty(required = false, value = "properties")
|
||||
List<Property> properties,
|
||||
@Nullable
|
||||
@JsonProperty(required = false, value = "dependencies")
|
||||
List<String> dependencies
|
||||
) {
|
||||
this.incompleteName = incompleteName;
|
||||
this.dispensable = dispensable;
|
||||
this.deadline = deadline;
|
||||
this.intendedVehicle = intendedVehicle;
|
||||
this.peripheralReservationToken = peripheralReservationToken;
|
||||
this.wrappingSequence = wrappingSequence;
|
||||
this.type = type;
|
||||
this.destinations = requireNonNull(destinations, "destinations");
|
||||
this.properties = properties;
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
// CHECKSTYLE:ON
|
||||
|
||||
public PostTransportOrderRequestTO() {
|
||||
}
|
||||
|
||||
public boolean isIncompleteName() {
|
||||
return incompleteName;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setIncompleteName(boolean incompleteName) {
|
||||
this.incompleteName = incompleteName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isDispensable() {
|
||||
return dispensable;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setDispensable(boolean dispensable) {
|
||||
this.dispensable = dispensable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Instant getDeadline() {
|
||||
return deadline;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setDeadline(
|
||||
@Nullable
|
||||
Instant deadline
|
||||
) {
|
||||
this.deadline = deadline;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getIntendedVehicle() {
|
||||
return intendedVehicle;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setIntendedVehicle(
|
||||
@Nullable
|
||||
String intendedVehicle
|
||||
) {
|
||||
this.intendedVehicle = intendedVehicle;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPeripheralReservationToken() {
|
||||
return peripheralReservationToken;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setPeripheralReservationToken(
|
||||
@Nullable
|
||||
String peripheralReservationToken
|
||||
) {
|
||||
this.peripheralReservationToken = peripheralReservationToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getWrappingSequence() {
|
||||
return wrappingSequence;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setWrappingSequence(
|
||||
@Nullable
|
||||
String wrappingSequence
|
||||
) {
|
||||
this.wrappingSequence = wrappingSequence;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setType(
|
||||
@Nullable
|
||||
String type
|
||||
) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<Destination> getDestinations() {
|
||||
return destinations;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setDestinations(
|
||||
@Nonnull
|
||||
List<Destination> destinations
|
||||
) {
|
||||
this.destinations = requireNonNull(destinations, "destinations");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setProperties(
|
||||
@Nullable
|
||||
List<Property> properties
|
||||
) {
|
||||
this.properties = properties;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
public PostTransportOrderRequestTO setDependencies(
|
||||
@Nullable
|
||||
List<String> dependencies
|
||||
) {
|
||||
this.dependencies = dependencies;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class PostVehicleRoutesRequestTO {
|
||||
|
||||
private String sourcePoint;
|
||||
private List<String> destinationPoints;
|
||||
private List<String> resourcesToAvoid;
|
||||
|
||||
@JsonCreator
|
||||
@SuppressWarnings("checkstyle:LineLength")
|
||||
public PostVehicleRoutesRequestTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "destinationPoints", required = true)
|
||||
List<String> destinationPoints
|
||||
) {
|
||||
this.destinationPoints = requireNonNull(destinationPoints, "destinationPoints");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSourcePoint() {
|
||||
return sourcePoint;
|
||||
}
|
||||
|
||||
public PostVehicleRoutesRequestTO setSourcePoint(
|
||||
@Nullable
|
||||
String sourcePoint
|
||||
) {
|
||||
this.sourcePoint = sourcePoint;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<String> getDestinationPoints() {
|
||||
return destinationPoints;
|
||||
}
|
||||
|
||||
public PostVehicleRoutesRequestTO setDestinationPoints(
|
||||
@Nonnull
|
||||
List<String> destinationPoints
|
||||
) {
|
||||
this.destinationPoints = requireNonNull(destinationPoints, "destinationPoints");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getResourcesToAvoid() {
|
||||
return resourcesToAvoid;
|
||||
}
|
||||
|
||||
public PostVehicleRoutesRequestTO setResourcesToAvoid(
|
||||
@Nullable
|
||||
List<String> resourcesToAvoid
|
||||
) {
|
||||
this.resourcesToAvoid = resourcesToAvoid;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.model.Point;
|
||||
import org.opentcs.data.order.Route;
|
||||
import org.opentcs.data.order.Route.Step;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getvehicleroutes.RouteTO;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class PostVehicleRoutesResponseTO {
|
||||
|
||||
private List<RouteTO> routes = List.of();
|
||||
|
||||
public PostVehicleRoutesResponseTO() {
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<RouteTO> getRoutes() {
|
||||
return routes;
|
||||
}
|
||||
|
||||
public PostVehicleRoutesResponseTO setRoutes(
|
||||
@Nonnull
|
||||
List<RouteTO> routes
|
||||
) {
|
||||
this.routes = requireNonNull(routes, "routes");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static PostVehicleRoutesResponseTO fromMap(
|
||||
Map<TCSObjectReference<Point>, Route> routeMap
|
||||
) {
|
||||
return new PostVehicleRoutesResponseTO()
|
||||
.setRoutes(
|
||||
routeMap.entrySet().stream()
|
||||
.map(PostVehicleRoutesResponseTO::toRouteTO)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
private static RouteTO toRouteTO(Map.Entry<TCSObjectReference<Point>, Route> entry) {
|
||||
if (entry.getValue() == null) {
|
||||
return new RouteTO()
|
||||
.setDestinationPoint(entry.getKey().getName())
|
||||
.setCosts(-1)
|
||||
.setSteps(null);
|
||||
}
|
||||
|
||||
return new RouteTO()
|
||||
.setDestinationPoint(entry.getKey().getName())
|
||||
.setCosts(entry.getValue().getCosts())
|
||||
.setSteps(toSteps(entry.getValue().getSteps()));
|
||||
}
|
||||
|
||||
private static List<RouteTO.Step> toSteps(List<Step> steps) {
|
||||
return steps.stream()
|
||||
.map(
|
||||
step -> new RouteTO.Step()
|
||||
.setDestinationPoint(step.getDestinationPoint().getName())
|
||||
.setSourcePoint(
|
||||
(step.getSourcePoint() != null) ? step.getSourcePoint().getName() : null
|
||||
)
|
||||
.setPath((step.getPath() != null) ? step.getPath().getName() : null)
|
||||
.setVehicleOrientation(step.getVehicleOrientation().name())
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An update for a vehicle's list of allowed order types.
|
||||
*/
|
||||
public class PutVehicleAllowedOrderTypesTO {
|
||||
|
||||
@Nonnull
|
||||
private List<String> orderTypes;
|
||||
|
||||
@JsonCreator
|
||||
public PutVehicleAllowedOrderTypesTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "orderTypes", required = true)
|
||||
List<String> orderTypes
|
||||
) {
|
||||
this.orderTypes = requireNonNull(orderTypes, "orderTypes");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<String> getOrderTypes() {
|
||||
return orderTypes;
|
||||
}
|
||||
|
||||
public PutVehicleAllowedOrderTypesTO setOrderTypes(
|
||||
@Nonnull
|
||||
List<String> orderTypes
|
||||
) {
|
||||
this.orderTypes = requireNonNull(orderTypes, "orderTypes");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* An update for a vehicle's energy level threshold set.
|
||||
*/
|
||||
public class PutVehicleEnergyLevelThresholdSetTO {
|
||||
|
||||
private int energyLevelCritical;
|
||||
private int energyLevelGood;
|
||||
private int energyLevelSufficientlyRecharged;
|
||||
private int energyLevelFullyRecharged;
|
||||
|
||||
@JsonCreator
|
||||
public PutVehicleEnergyLevelThresholdSetTO(
|
||||
@JsonProperty(value = "energyLevelCritical", required = true)
|
||||
int energyLevelCritical,
|
||||
@JsonProperty(value = "energyLevelGood", required = true)
|
||||
int energyLevelGood,
|
||||
@JsonProperty(value = "energyLevelSufficientlyRecharged", required = true)
|
||||
int energyLevelSufficientlyRecharged,
|
||||
@JsonProperty(value = "energyLevelFullyRecharged", required = true)
|
||||
int energyLevelFullyRecharged
|
||||
) {
|
||||
this.energyLevelCritical = energyLevelCritical;
|
||||
this.energyLevelGood = energyLevelGood;
|
||||
this.energyLevelSufficientlyRecharged = energyLevelSufficientlyRecharged;
|
||||
this.energyLevelFullyRecharged = energyLevelFullyRecharged;
|
||||
}
|
||||
|
||||
public int getEnergyLevelCritical() {
|
||||
return energyLevelCritical;
|
||||
}
|
||||
|
||||
public PutVehicleEnergyLevelThresholdSetTO setEnergyLevelCritical(int energyLevelCritical) {
|
||||
this.energyLevelCritical = energyLevelCritical;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelGood() {
|
||||
return energyLevelGood;
|
||||
}
|
||||
|
||||
public PutVehicleEnergyLevelThresholdSetTO setEnergyLevelGood(int energyLevelGood) {
|
||||
this.energyLevelGood = energyLevelGood;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelSufficientlyRecharged() {
|
||||
return energyLevelSufficientlyRecharged;
|
||||
}
|
||||
|
||||
public PutVehicleEnergyLevelThresholdSetTO setEnergyLevelSufficientlyRecharged(
|
||||
int energyLevelSufficientlyRecharged
|
||||
) {
|
||||
this.energyLevelSufficientlyRecharged = energyLevelSufficientlyRecharged;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelFullyRecharged() {
|
||||
return energyLevelFullyRecharged;
|
||||
}
|
||||
|
||||
public PutVehicleEnergyLevelThresholdSetTO setEnergyLevelFullyRecharged(
|
||||
int energyLevelFullyRecharged
|
||||
) {
|
||||
this.energyLevelFullyRecharged = energyLevelFullyRecharged;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.opentcs.data.order.DriveOrder;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.DestinationState;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* A status message containing details about a transport order.
|
||||
*/
|
||||
public class OrderStatusMessage
|
||||
extends
|
||||
StatusMessage {
|
||||
|
||||
private String orderName;
|
||||
|
||||
private String processingVehicleName;
|
||||
|
||||
private OrderState orderState;
|
||||
|
||||
private List<DestinationState> destinations = new ArrayList<>();
|
||||
|
||||
private List<Property> properties = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public OrderStatusMessage() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderStatusMessage setSequenceNumber(long sequenceNumber) {
|
||||
return (OrderStatusMessage) super.setSequenceNumber(sequenceNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderStatusMessage setCreationTimeStamp(Instant creationTimeStamp) {
|
||||
return (OrderStatusMessage) super.setCreationTimeStamp(creationTimeStamp);
|
||||
}
|
||||
|
||||
public String getOrderName() {
|
||||
return orderName;
|
||||
}
|
||||
|
||||
public OrderStatusMessage setOrderName(String orderName) {
|
||||
this.orderName = orderName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getProcessingVehicleName() {
|
||||
return processingVehicleName;
|
||||
}
|
||||
|
||||
public OrderStatusMessage setProcessingVehicleName(String processingVehicleName) {
|
||||
this.processingVehicleName = processingVehicleName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrderState getOrderState() {
|
||||
return orderState;
|
||||
}
|
||||
|
||||
public OrderStatusMessage setOrderState(OrderState orderState) {
|
||||
this.orderState = orderState;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<DestinationState> getDestinations() {
|
||||
return destinations;
|
||||
}
|
||||
|
||||
public OrderStatusMessage setDestinations(List<DestinationState> destinations) {
|
||||
this.destinations = destinations;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public OrderStatusMessage setProperties(List<Property> properties) {
|
||||
this.properties = properties;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static OrderStatusMessage fromTransportOrder(
|
||||
TransportOrder order,
|
||||
long sequenceNumber
|
||||
) {
|
||||
return fromTransportOrder(order, sequenceNumber, Instant.now());
|
||||
}
|
||||
|
||||
public static OrderStatusMessage fromTransportOrder(
|
||||
TransportOrder order,
|
||||
long sequenceNumber,
|
||||
Instant creationTimeStamp
|
||||
) {
|
||||
OrderStatusMessage orderMessage = new OrderStatusMessage();
|
||||
orderMessage.setSequenceNumber(sequenceNumber);
|
||||
orderMessage.setCreationTimeStamp(creationTimeStamp);
|
||||
orderMessage.setOrderName(order.getName());
|
||||
orderMessage.setProcessingVehicleName(
|
||||
order.getProcessingVehicle() == null ? null : order.getProcessingVehicle().getName()
|
||||
);
|
||||
orderMessage.setOrderState(OrderState.fromTransportOrderState(order.getState()));
|
||||
for (DriveOrder curDriveOrder : order.getAllDriveOrders()) {
|
||||
orderMessage.getDestinations().add(DestinationState.fromDriveOrder(curDriveOrder));
|
||||
}
|
||||
for (Map.Entry<String, String> mapEntry : order.getProperties().entrySet()) {
|
||||
orderMessage.getProperties().add(new Property(mapEntry.getKey(), mapEntry.getValue()));
|
||||
}
|
||||
return orderMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* The various states a transport order may be in.
|
||||
*/
|
||||
public enum OrderState {
|
||||
/**
|
||||
* A transport order's initial state.
|
||||
*/
|
||||
RAW,
|
||||
/**
|
||||
* Indicates a transport order's parameters have been set up completely and the kernel should
|
||||
* dispatch it when possible.
|
||||
*/
|
||||
ACTIVE,
|
||||
/**
|
||||
* Marks a transport order as ready to be dispatched to a vehicle.
|
||||
*/
|
||||
DISPATCHABLE,
|
||||
/**
|
||||
* Marks a transport order as being processed by a vehicle.
|
||||
*/
|
||||
BEING_PROCESSED,
|
||||
/**
|
||||
* Indicates the transport order is withdrawn from a processing vehicle but not yet in its
|
||||
* final state, as the vehicle has not yet finished/cleaned up.
|
||||
*/
|
||||
WITHDRAWN,
|
||||
/**
|
||||
* Marks a transport order as successfully completed.
|
||||
*/
|
||||
FINISHED,
|
||||
/**
|
||||
* General failure state that marks a transport order as failed.
|
||||
*/
|
||||
FAILED,
|
||||
/**
|
||||
* Failure state that marks a transport order as unroutable.
|
||||
*/
|
||||
UNROUTABLE;
|
||||
|
||||
/**
|
||||
* Maps a transpor order's {@link TransportOrder#state state} to the corresponding
|
||||
* {@link OrderState}.
|
||||
*
|
||||
* @param state The transport order's state.
|
||||
* @return The corresponding OrderState.
|
||||
*/
|
||||
public static OrderState fromTransportOrderState(TransportOrder.State state) {
|
||||
switch (state) {
|
||||
case RAW:
|
||||
return RAW;
|
||||
case ACTIVE:
|
||||
return ACTIVE;
|
||||
case DISPATCHABLE:
|
||||
return DISPATCHABLE;
|
||||
case BEING_PROCESSED:
|
||||
return BEING_PROCESSED;
|
||||
case WITHDRAWN:
|
||||
return WITHDRAWN;
|
||||
case FINISHED:
|
||||
return FINISHED;
|
||||
case FAILED:
|
||||
return FAILED;
|
||||
case UNROUTABLE:
|
||||
return UNROUTABLE;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown transport order state.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.data.peripherals.PeripheralJob.State;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PeripheralOperationDescription;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* A status message containing information about a peripheral job.
|
||||
*/
|
||||
public class PeripheralJobStatusMessage
|
||||
extends
|
||||
StatusMessage {
|
||||
|
||||
private String name;
|
||||
|
||||
private String reservationToken;
|
||||
|
||||
private String relatedVehicle;
|
||||
|
||||
private String relatedTransportOrder;
|
||||
|
||||
private PeripheralOperationDescription peripheralOperation;
|
||||
|
||||
private State state;
|
||||
|
||||
private Instant creationTime;
|
||||
|
||||
private Instant finishedTime;
|
||||
|
||||
private List<Property> properties;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public PeripheralJobStatusMessage() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PeripheralJobStatusMessage setSequenceNumber(long sequenceNumber) {
|
||||
return (PeripheralJobStatusMessage) super.setSequenceNumber(sequenceNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PeripheralJobStatusMessage setCreationTimeStamp(Instant creationTimeStamp) {
|
||||
return (PeripheralJobStatusMessage) super.setCreationTimeStamp(creationTimeStamp);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public PeripheralJobStatusMessage setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getReservationToken() {
|
||||
return reservationToken;
|
||||
}
|
||||
|
||||
public PeripheralJobStatusMessage setReservationToken(String reservationToken) {
|
||||
this.reservationToken = reservationToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRelatedVehicle() {
|
||||
return relatedVehicle;
|
||||
}
|
||||
|
||||
public PeripheralJobStatusMessage setRelatedVehicle(String relatedVehicle) {
|
||||
this.relatedVehicle = relatedVehicle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRelatedTransportOrder() {
|
||||
return relatedTransportOrder;
|
||||
}
|
||||
|
||||
public PeripheralJobStatusMessage setRelatedTransportOrder(String relatedTransportOrder) {
|
||||
this.relatedTransportOrder = relatedTransportOrder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PeripheralOperationDescription getPeripheralOperation() {
|
||||
return peripheralOperation;
|
||||
}
|
||||
|
||||
public PeripheralJobStatusMessage setPeripheralOperation(
|
||||
PeripheralOperationDescription peripheralOperation
|
||||
) {
|
||||
this.peripheralOperation = peripheralOperation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public PeripheralJobStatusMessage setState(State state) {
|
||||
this.state = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Instant getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
public PeripheralJobStatusMessage setCreationTime(Instant creationTime) {
|
||||
this.creationTime = creationTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Instant getFinishedTime() {
|
||||
return finishedTime;
|
||||
}
|
||||
|
||||
public PeripheralJobStatusMessage setFinishedTime(Instant finishedTime) {
|
||||
this.finishedTime = finishedTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public PeripheralJobStatusMessage setProperties(List<Property> properties) {
|
||||
this.properties = properties;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static PeripheralJobStatusMessage fromPeripheralJob(
|
||||
PeripheralJob job,
|
||||
long sequenceNumber
|
||||
) {
|
||||
return fromPeripheralJob(job, sequenceNumber, Instant.now());
|
||||
}
|
||||
|
||||
public static PeripheralJobStatusMessage fromPeripheralJob(
|
||||
PeripheralJob job,
|
||||
long sequenceNumber,
|
||||
Instant creationTimestamp
|
||||
) {
|
||||
PeripheralJobStatusMessage message = new PeripheralJobStatusMessage();
|
||||
message.setSequenceNumber(sequenceNumber);
|
||||
message.setCreationTimeStamp(creationTimestamp);
|
||||
|
||||
message.setName(job.getName());
|
||||
message.setReservationToken(job.getReservationToken());
|
||||
if (job.getRelatedVehicle() != null) {
|
||||
message.setRelatedVehicle(job.getRelatedVehicle().getName());
|
||||
}
|
||||
if (job.getRelatedTransportOrder() != null) {
|
||||
message.setRelatedTransportOrder(job.getRelatedTransportOrder().getName());
|
||||
}
|
||||
message.setPeripheralOperation(
|
||||
PeripheralOperationDescription.fromPeripheralOperation(job.getPeripheralOperation())
|
||||
);
|
||||
message.setState(job.getState());
|
||||
message.setCreationTime(job.getCreationTime());
|
||||
message.setFinishedTime(job.getFinishedTime());
|
||||
message.setProperties(
|
||||
job.getProperties().entrySet().stream()
|
||||
.map(entry -> new Property(entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* A generic status message.
|
||||
*/
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
property = "type"
|
||||
)
|
||||
@JsonSubTypes(
|
||||
{
|
||||
@JsonSubTypes.Type(value = OrderStatusMessage.class, name = "TransportOrder"),
|
||||
@JsonSubTypes.Type(value = VehicleStatusMessage.class, name = "Vehicle"),
|
||||
@JsonSubTypes.Type(value = PeripheralJobStatusMessage.class, name = "PeripheralJob")
|
||||
}
|
||||
)
|
||||
public abstract class StatusMessage {
|
||||
|
||||
private long sequenceNumber;
|
||||
|
||||
private Instant creationTimeStamp = Instant.now();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public StatusMessage() {
|
||||
}
|
||||
|
||||
public long getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
public StatusMessage setSequenceNumber(long sequenceNumber) {
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Instant getCreationTimeStamp() {
|
||||
return creationTimeStamp;
|
||||
}
|
||||
|
||||
public StatusMessage setCreationTimeStamp(Instant creationTimeStamp) {
|
||||
this.creationTimeStamp = creationTimeStamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.data.model.TCSResourceReference;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
|
||||
/**
|
||||
* A status message containing information about a vehicle.
|
||||
*/
|
||||
public class VehicleStatusMessage
|
||||
extends
|
||||
StatusMessage {
|
||||
|
||||
private String vehicleName = "";
|
||||
|
||||
private String transportOrderName = "";
|
||||
|
||||
private String position;
|
||||
|
||||
private PrecisePosition precisePosition;
|
||||
|
||||
private double orientationAngle;
|
||||
|
||||
private boolean paused;
|
||||
|
||||
private Vehicle.State state;
|
||||
|
||||
private Vehicle.ProcState procState;
|
||||
|
||||
private List<List<String>> allocatedResources = new ArrayList<>();
|
||||
|
||||
private List<List<String>> claimedResources = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public VehicleStatusMessage() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VehicleStatusMessage setSequenceNumber(long sequenceNumber) {
|
||||
return (VehicleStatusMessage) super.setSequenceNumber(sequenceNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VehicleStatusMessage setCreationTimeStamp(Instant creationTimeStamp) {
|
||||
return (VehicleStatusMessage) super.setCreationTimeStamp(creationTimeStamp);
|
||||
}
|
||||
|
||||
public String getVehicleName() {
|
||||
return vehicleName;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setVehicleName(String vehicleName) {
|
||||
this.vehicleName = vehicleName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTransportOrderName() {
|
||||
return transportOrderName;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setTransportOrderName(String transportOrderName) {
|
||||
this.transportOrderName = transportOrderName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setPosition(String position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PrecisePosition getPrecisePosition() {
|
||||
return precisePosition;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setPrecisePosition(PrecisePosition precisePosition) {
|
||||
this.precisePosition = precisePosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getOrientationAngle() {
|
||||
return orientationAngle;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setOrientationAngle(double orientationAngle) {
|
||||
this.orientationAngle = orientationAngle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isPaused() {
|
||||
return paused;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setPaused(boolean paused) {
|
||||
this.paused = paused;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vehicle.State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setState(Vehicle.State state) {
|
||||
this.state = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vehicle.ProcState getProcState() {
|
||||
return procState;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setProcState(Vehicle.ProcState procState) {
|
||||
this.procState = procState;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<List<String>> getAllocatedResources() {
|
||||
return allocatedResources;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setAllocatedResources(List<List<String>> allocatedResources) {
|
||||
this.allocatedResources = requireNonNull(allocatedResources, "allocatedResources");
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<List<String>> getClaimedResources() {
|
||||
return claimedResources;
|
||||
}
|
||||
|
||||
public VehicleStatusMessage setClaimedResources(List<List<String>> claimedResources) {
|
||||
this.claimedResources = requireNonNull(claimedResources, "claimedResources");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static VehicleStatusMessage fromVehicle(
|
||||
Vehicle vehicle,
|
||||
long sequenceNumber
|
||||
) {
|
||||
return fromVehicle(vehicle, sequenceNumber, Instant.now());
|
||||
}
|
||||
|
||||
public static VehicleStatusMessage fromVehicle(
|
||||
Vehicle vehicle,
|
||||
long sequenceNumber,
|
||||
Instant creationTimeStamp
|
||||
) {
|
||||
VehicleStatusMessage vehicleMessage = new VehicleStatusMessage();
|
||||
vehicleMessage.setSequenceNumber(sequenceNumber);
|
||||
vehicleMessage.setCreationTimeStamp(creationTimeStamp);
|
||||
vehicleMessage.setVehicleName(vehicle.getName());
|
||||
vehicleMessage.setTransportOrderName(
|
||||
vehicle.getTransportOrder() == null ? null : vehicle.getTransportOrder().getName()
|
||||
);
|
||||
vehicleMessage.setPosition(
|
||||
vehicle.getCurrentPosition() == null ? null : vehicle.getCurrentPosition().getName()
|
||||
);
|
||||
vehicleMessage.setPaused(vehicle.isPaused());
|
||||
vehicleMessage.setState(vehicle.getState());
|
||||
vehicleMessage.setProcState(vehicle.getProcState());
|
||||
if (vehicle.getPose().getPosition() != null) {
|
||||
vehicleMessage.setPrecisePosition(
|
||||
new PrecisePosition(
|
||||
vehicle.getPose().getPosition().getX(),
|
||||
vehicle.getPose().getPosition().getY(),
|
||||
vehicle.getPose().getPosition().getZ()
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
vehicleMessage.setPrecisePosition(null);
|
||||
}
|
||||
vehicleMessage.setOrientationAngle(vehicle.getPose().getOrientationAngle());
|
||||
vehicleMessage.setAllocatedResources(toListOfListOfNames(vehicle.getAllocatedResources()));
|
||||
vehicleMessage.setClaimedResources(toListOfListOfNames(vehicle.getClaimedResources()));
|
||||
return vehicleMessage;
|
||||
}
|
||||
|
||||
private static List<List<String>> toListOfListOfNames(
|
||||
List<Set<TCSResourceReference<?>>> resources
|
||||
) {
|
||||
List<List<String>> result = new ArrayList<>(resources.size());
|
||||
|
||||
for (Set<TCSResourceReference<?>> resSet : resources) {
|
||||
result.add(
|
||||
resSet.stream()
|
||||
.map(resRef -> resRef.getName())
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A precise position of a vehicle.
|
||||
*/
|
||||
public static class PrecisePosition {
|
||||
|
||||
private long x;
|
||||
|
||||
private long y;
|
||||
|
||||
private long z;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public PrecisePosition() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param x x value
|
||||
* @param y y value
|
||||
* @param z z value
|
||||
*/
|
||||
public PrecisePosition(long x, long y, long z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public long getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(long x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public long getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(long y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public long getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(long z) {
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.getvehicleroutes;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
|
||||
/**
|
||||
* The web API representation of a route.
|
||||
*/
|
||||
public class RouteTO {
|
||||
|
||||
private String destinationPoint = "";
|
||||
private long costs = -1;
|
||||
private List<Step> steps;
|
||||
|
||||
public RouteTO() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getDestinationPoint() {
|
||||
return destinationPoint;
|
||||
}
|
||||
|
||||
public RouteTO setDestinationPoint(
|
||||
@Nonnull
|
||||
String destinationPoint
|
||||
) {
|
||||
this.destinationPoint = requireNonNull(destinationPoint, "destinationPoint");
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getCosts() {
|
||||
return costs;
|
||||
}
|
||||
|
||||
public RouteTO setCosts(long costs) {
|
||||
this.costs = costs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Step> getSteps() {
|
||||
return steps;
|
||||
}
|
||||
|
||||
public RouteTO setSteps(List<Step> steps) {
|
||||
this.steps = steps;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Step {
|
||||
|
||||
private String path;
|
||||
private String sourcePoint;
|
||||
private String destinationPoint = "";
|
||||
private String vehicleOrientation = Vehicle.Orientation.UNDEFINED.name();
|
||||
|
||||
public Step() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public Step setPath(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSourcePoint() {
|
||||
return sourcePoint;
|
||||
}
|
||||
|
||||
public Step setSourcePoint(String sourcePoint) {
|
||||
this.sourcePoint = sourcePoint;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getDestinationPoint() {
|
||||
return destinationPoint;
|
||||
}
|
||||
|
||||
public Step setDestinationPoint(
|
||||
@Nonnull
|
||||
String destinationPoint
|
||||
) {
|
||||
this.destinationPoint = requireNonNull(destinationPoint, "destinationPoint");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getVehicleOrientation() {
|
||||
return vehicleOrientation;
|
||||
}
|
||||
|
||||
public Step setVehicleOrientation(
|
||||
@Nonnull
|
||||
String vehicleOrientation
|
||||
) {
|
||||
this.vehicleOrientation = requireNonNull(vehicleOrientation, "vehicleOrientation");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.opentcs.data.model.Block;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class BlockTO {
|
||||
|
||||
private String name;
|
||||
private String type = Block.Type.SINGLE_VEHICLE_ONLY.name();
|
||||
private Layout layout = new Layout();
|
||||
private Set<String> memberNames = Set.of();
|
||||
private List<PropertyTO> properties = List.of();
|
||||
|
||||
@JsonCreator
|
||||
public BlockTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public BlockTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PropertyTO> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public BlockTO setProperties(
|
||||
@Nonnull
|
||||
List<PropertyTO> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public BlockTO setType(
|
||||
@Nonnull
|
||||
String type
|
||||
) {
|
||||
this.type = requireNonNull(type, "type");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Layout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
public BlockTO setLayout(
|
||||
@Nonnull
|
||||
Layout layout
|
||||
) {
|
||||
this.layout = requireNonNull(layout, "layout");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Set<String> getMemberNames() {
|
||||
return memberNames;
|
||||
}
|
||||
|
||||
public BlockTO setMemberNames(
|
||||
@Nonnull
|
||||
Set<String> memberNames
|
||||
) {
|
||||
this.memberNames = requireNonNull(memberNames, "memberNames");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Layout {
|
||||
|
||||
private String color = "#FF0000";
|
||||
|
||||
public Layout() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Layout setColor(
|
||||
@Nonnull
|
||||
String color
|
||||
) {
|
||||
this.color = requireNonNull(color, "color");
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class LayerGroupTO {
|
||||
|
||||
private int id;
|
||||
private String name;
|
||||
private boolean visible;
|
||||
|
||||
@JsonCreator
|
||||
public LayerGroupTO(
|
||||
@JsonProperty(value = "id", required = true)
|
||||
int id,
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name,
|
||||
@JsonProperty(value = "visible", required = true)
|
||||
boolean visible
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = requireNonNull(name, "name");
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public LayerGroupTO setId(int id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LayerGroupTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public LayerGroupTO setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class LayerTO {
|
||||
|
||||
private int id;
|
||||
private int ordinal;
|
||||
private boolean visible;
|
||||
private String name;
|
||||
private int groupId;
|
||||
|
||||
@JsonCreator
|
||||
public LayerTO(
|
||||
@JsonProperty(value = "id", required = true)
|
||||
int id,
|
||||
@JsonProperty(value = "ordinal", required = true)
|
||||
int ordinal,
|
||||
@JsonProperty(value = "visible", required = true)
|
||||
boolean visible,
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name,
|
||||
@JsonProperty(value = "groupId", required = true)
|
||||
int groupId
|
||||
) {
|
||||
this.id = id;
|
||||
this.ordinal = ordinal;
|
||||
this.visible = visible;
|
||||
this.name = requireNonNull(name, "name");
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public LayerTO setId(int id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
public LayerTO setOrdinal(int ordinal) {
|
||||
this.ordinal = ordinal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public LayerTO setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LayerTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public LayerTO setGroupId(int groupId) {
|
||||
this.groupId = groupId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import org.opentcs.data.model.visualization.LocationRepresentation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.CoupleTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.LinkTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.TripleTO;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class LocationTO {
|
||||
|
||||
private String name;
|
||||
private String typeName;
|
||||
private TripleTO position;
|
||||
private List<LinkTO> links = List.of();
|
||||
private boolean locked;
|
||||
private Layout layout = new Layout();
|
||||
private List<PropertyTO> properties = List.of();
|
||||
|
||||
@JsonCreator
|
||||
public LocationTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name,
|
||||
@Nonnull
|
||||
@JsonProperty(value = "typeName", required = true)
|
||||
String typeName,
|
||||
@Nonnull
|
||||
@JsonProperty(value = "position", required = true)
|
||||
TripleTO position
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
this.typeName = requireNonNull(typeName, "typeName");
|
||||
this.position = requireNonNull(position, "position");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LocationTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PropertyTO> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public LocationTO setProperties(
|
||||
@Nonnull
|
||||
List<PropertyTO> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
|
||||
public LocationTO setTypeName(
|
||||
@Nonnull
|
||||
String typeName
|
||||
) {
|
||||
this.typeName = requireNonNull(typeName, "typeName");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public TripleTO getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public LocationTO setPosition(
|
||||
@Nonnull
|
||||
TripleTO position
|
||||
) {
|
||||
this.position = requireNonNull(position, "position");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<LinkTO> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public LocationTO setLinks(
|
||||
@Nonnull
|
||||
List<LinkTO> links
|
||||
) {
|
||||
this.links = requireNonNull(links, "links");
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
public LocationTO setLocked(boolean locked) {
|
||||
this.locked = locked;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Layout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public LocationTO setLayout(
|
||||
@Nonnull
|
||||
Layout layout
|
||||
) {
|
||||
this.layout = requireNonNull(layout, "layout");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Layout {
|
||||
|
||||
private CoupleTO position = new CoupleTO(0, 0);
|
||||
private CoupleTO labelOffset = new CoupleTO(0, 0);
|
||||
private String locationRepresentation = LocationRepresentation.DEFAULT.name();
|
||||
private int layerId;
|
||||
|
||||
public Layout() {
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CoupleTO getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public Layout setPosition(
|
||||
@Nonnull
|
||||
CoupleTO position
|
||||
) {
|
||||
this.position = requireNonNull(position, "position");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CoupleTO getLabelOffset() {
|
||||
return labelOffset;
|
||||
}
|
||||
|
||||
public Layout setLabelOffset(
|
||||
@Nonnull
|
||||
CoupleTO labelOffset
|
||||
) {
|
||||
this.labelOffset = requireNonNull(labelOffset, "labelOffset");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getLocationRepresentation() {
|
||||
return locationRepresentation;
|
||||
}
|
||||
|
||||
public Layout setLocationRepresentation(
|
||||
@Nonnull
|
||||
String locationRepresentation
|
||||
) {
|
||||
this.locationRepresentation = requireNonNull(
|
||||
locationRepresentation, "locationRepresentation"
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getLayerId() {
|
||||
return layerId;
|
||||
}
|
||||
|
||||
public Layout setLayerId(int layerId) {
|
||||
this.layerId = layerId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import org.opentcs.data.model.visualization.LocationRepresentation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class LocationTypeTO {
|
||||
|
||||
private String name;
|
||||
private List<String> allowedOperations = List.of();
|
||||
private List<String> allowedPeripheralOperations = List.of();
|
||||
private Layout layout = new Layout();
|
||||
private List<PropertyTO> properties = List.of();
|
||||
|
||||
@JsonCreator
|
||||
public LocationTypeTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LocationTypeTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PropertyTO> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public LocationTypeTO setProperties(
|
||||
@Nonnull
|
||||
List<PropertyTO> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<String> getAllowedOperations() {
|
||||
return allowedOperations;
|
||||
}
|
||||
|
||||
public LocationTypeTO setAllowedOperations(
|
||||
@Nonnull
|
||||
List<String> allowedOperations
|
||||
) {
|
||||
this.allowedOperations = requireNonNull(allowedOperations, "allowedOperations");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<String> getAllowedPeripheralOperations() {
|
||||
return allowedPeripheralOperations;
|
||||
}
|
||||
|
||||
public LocationTypeTO setAllowedPeripheralOperations(
|
||||
@Nonnull
|
||||
List<String> allowedPeripheralOperations
|
||||
) {
|
||||
this.allowedPeripheralOperations = requireNonNull(
|
||||
allowedPeripheralOperations,
|
||||
"allowedPeripheralOperations"
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Layout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
public LocationTypeTO setLayout(
|
||||
@Nonnull
|
||||
Layout layout
|
||||
) {
|
||||
this.layout = requireNonNull(layout, "layout");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Layout {
|
||||
|
||||
private String locationRepresentation = LocationRepresentation.NONE.name();
|
||||
|
||||
public Layout() {
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getLocationRepresentation() {
|
||||
return locationRepresentation;
|
||||
}
|
||||
|
||||
public Layout setLocationRepresentation(
|
||||
@Nonnull
|
||||
String locationRepresentation
|
||||
) {
|
||||
this.locationRepresentation = requireNonNull(
|
||||
locationRepresentation,
|
||||
"locationRepresentation"
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import org.opentcs.data.model.Path;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.CoupleTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.EnvelopeTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class PathTO {
|
||||
|
||||
private String name;
|
||||
private String srcPointName;
|
||||
private String destPointName;
|
||||
private long length = 1;
|
||||
private int maxVelocity;
|
||||
private int maxReverseVelocity;
|
||||
private List<PeripheralOperationTO> peripheralOperations = List.of();
|
||||
private boolean locked;
|
||||
private Layout layout = new Layout();
|
||||
private List<EnvelopeTO> vehicleEnvelopes = List.of();
|
||||
private List<PropertyTO> properties = List.of();
|
||||
|
||||
@JsonCreator
|
||||
public PathTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name,
|
||||
@Nonnull
|
||||
@JsonProperty(value = "srcPointName", required = true)
|
||||
String srcPointName,
|
||||
@Nonnull
|
||||
@JsonProperty(value = "destPointName", required = true)
|
||||
String destPointName
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
this.srcPointName = requireNonNull(srcPointName, "srcPointName");
|
||||
this.destPointName = requireNonNull(destPointName, "destPointName");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public PathTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PropertyTO> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public PathTO setProperties(
|
||||
@Nonnull
|
||||
List<PropertyTO> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getSrcPointName() {
|
||||
return srcPointName;
|
||||
}
|
||||
|
||||
public PathTO setSrcPointName(
|
||||
@Nonnull
|
||||
String srcPointName
|
||||
) {
|
||||
this.srcPointName = requireNonNull(srcPointName, "srcPointName");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getDestPointName() {
|
||||
return destPointName;
|
||||
}
|
||||
|
||||
public PathTO setDestPointName(
|
||||
@Nonnull
|
||||
String destPointName
|
||||
) {
|
||||
this.destPointName = requireNonNull(destPointName, "destPointName");
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public PathTO setLength(long length) {
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxVelocity() {
|
||||
return maxVelocity;
|
||||
}
|
||||
|
||||
public PathTO setMaxVelocity(int maxVelocity) {
|
||||
this.maxVelocity = maxVelocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxReverseVelocity() {
|
||||
return maxReverseVelocity;
|
||||
}
|
||||
|
||||
public PathTO setMaxReverseVelocity(int maxReverseVelocity) {
|
||||
this.maxReverseVelocity = maxReverseVelocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PeripheralOperationTO> getPeripheralOperations() {
|
||||
return peripheralOperations;
|
||||
}
|
||||
|
||||
public PathTO setPeripheralOperations(
|
||||
@Nonnull
|
||||
List<PeripheralOperationTO> peripheralOperations
|
||||
) {
|
||||
this.peripheralOperations = requireNonNull(peripheralOperations, "peripheralOperations");
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
public PathTO setLocked(boolean locked) {
|
||||
this.locked = locked;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Layout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
public PathTO setLayout(
|
||||
@Nonnull
|
||||
Layout layout
|
||||
) {
|
||||
this.layout = requireNonNull(layout, "layout");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<EnvelopeTO> getVehicleEnvelopes() {
|
||||
return vehicleEnvelopes;
|
||||
}
|
||||
|
||||
public PathTO setVehicleEnvelopes(
|
||||
@Nonnull
|
||||
List<EnvelopeTO> vehicleEnvelopes
|
||||
) {
|
||||
this.vehicleEnvelopes = requireNonNull(vehicleEnvelopes, "vehicleEnvelopes");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Layout {
|
||||
|
||||
private String connectionType = Path.Layout.ConnectionType.DIRECT.name();
|
||||
private List<CoupleTO> controlPoints = List.of();
|
||||
private int layerId;
|
||||
|
||||
public Layout() {
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getConnectionType() {
|
||||
return connectionType;
|
||||
}
|
||||
|
||||
public Layout setConnectionType(
|
||||
@Nonnull
|
||||
String connectionType
|
||||
) {
|
||||
this.connectionType = requireNonNull(connectionType, "connectionType");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<CoupleTO> getControlPoints() {
|
||||
return controlPoints;
|
||||
}
|
||||
|
||||
public Layout setControlPoints(
|
||||
@Nonnull
|
||||
List<CoupleTO> controlPoints
|
||||
) {
|
||||
this.controlPoints = requireNonNull(controlPoints, "controlPoints");
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getLayerId() {
|
||||
return layerId;
|
||||
}
|
||||
|
||||
public Layout setLayerId(int layerId) {
|
||||
this.layerId = layerId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.opentcs.data.peripherals.PeripheralOperation;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class PeripheralOperationTO {
|
||||
|
||||
private String operation;
|
||||
private String locationName;
|
||||
private String executionTrigger = PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION.name();
|
||||
private boolean completionRequired;
|
||||
|
||||
@JsonCreator
|
||||
public PeripheralOperationTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "operation", required = true)
|
||||
String operation,
|
||||
@Nonnull
|
||||
@JsonProperty(value = "locationName", required = true)
|
||||
String locationName
|
||||
) {
|
||||
this.operation = requireNonNull(operation, "operation");
|
||||
this.locationName = requireNonNull(locationName, "locationName");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public PeripheralOperationTO setOperation(
|
||||
@Nonnull
|
||||
String operation
|
||||
) {
|
||||
this.operation = requireNonNull(operation, "operation");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getLocationName() {
|
||||
return locationName;
|
||||
}
|
||||
|
||||
public PeripheralOperationTO setLocationName(
|
||||
@Nonnull
|
||||
String locationName
|
||||
) {
|
||||
this.locationName = requireNonNull(locationName, "locationName");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getExecutionTrigger() {
|
||||
return executionTrigger;
|
||||
}
|
||||
|
||||
public PeripheralOperationTO setExecutionTrigger(
|
||||
@Nonnull
|
||||
String executionTrigger
|
||||
) {
|
||||
this.executionTrigger = requireNonNull(executionTrigger, "executionTrigger");
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isCompletionRequired() {
|
||||
return completionRequired;
|
||||
}
|
||||
|
||||
public PeripheralOperationTO setCompletionRequired(boolean completionRequired) {
|
||||
this.completionRequired = completionRequired;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import org.opentcs.data.model.Point;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.CoupleTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.EnvelopeTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.TripleTO;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class PointTO {
|
||||
|
||||
private String name;
|
||||
private TripleTO position = new TripleTO(0, 0, 0);
|
||||
private double vehicleOrientationAngle = Double.NaN;
|
||||
private String type = Point.Type.HALT_POSITION.name();
|
||||
private Layout layout = new Layout();
|
||||
private List<EnvelopeTO> vehicleEnvelopes = List.of();
|
||||
private List<PropertyTO> properties = List.of();
|
||||
|
||||
@JsonCreator
|
||||
public PointTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public PointTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PropertyTO> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public PointTO setProperties(
|
||||
@Nonnull
|
||||
List<PropertyTO> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public TripleTO getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public PointTO setPosition(
|
||||
@Nonnull
|
||||
TripleTO position
|
||||
) {
|
||||
this.position = requireNonNull(position, "position");
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getVehicleOrientationAngle() {
|
||||
return vehicleOrientationAngle;
|
||||
}
|
||||
|
||||
public PointTO setVehicleOrientationAngle(double vehicleOrientationAngle) {
|
||||
this.vehicleOrientationAngle = vehicleOrientationAngle;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public PointTO setType(
|
||||
@Nonnull
|
||||
String type
|
||||
) {
|
||||
this.type = requireNonNull(type, "type");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Layout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
public PointTO setLayout(
|
||||
@Nonnull
|
||||
Layout pointLayout
|
||||
) {
|
||||
this.layout = requireNonNull(pointLayout, "pointLayout");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<EnvelopeTO> getVehicleEnvelopes() {
|
||||
return vehicleEnvelopes;
|
||||
}
|
||||
|
||||
public PointTO setVehicleEnvelopes(
|
||||
@Nonnull
|
||||
List<EnvelopeTO> vehicleEnvelopes
|
||||
) {
|
||||
this.vehicleEnvelopes = requireNonNull(vehicleEnvelopes, "vehicleEnvelopes");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Layout {
|
||||
|
||||
private CoupleTO position = new CoupleTO(0, 0);
|
||||
private CoupleTO labelOffset = new CoupleTO(0, 0);
|
||||
private int layerId;
|
||||
|
||||
public Layout() {
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CoupleTO getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public Layout setPosition(
|
||||
@Nonnull
|
||||
CoupleTO position
|
||||
) {
|
||||
this.position = requireNonNull(position, "position");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CoupleTO getLabelOffset() {
|
||||
return labelOffset;
|
||||
}
|
||||
|
||||
public Layout setLabelOffset(
|
||||
@Nonnull
|
||||
CoupleTO labelOffset
|
||||
) {
|
||||
this.labelOffset = requireNonNull(labelOffset, "labelOffset");
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getLayerId() {
|
||||
return layerId;
|
||||
}
|
||||
|
||||
public Layout setLayerId(int layerId) {
|
||||
this.layerId = layerId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class VehicleTO {
|
||||
|
||||
private String name;
|
||||
private int length = 1000;
|
||||
private int energyLevelCritical = 30;
|
||||
private int energyLevelGood = 90;
|
||||
private int energyLevelFullyRecharged = 90;
|
||||
private int energyLevelSufficientlyRecharged = 30;
|
||||
private int maxVelocity = 1000;
|
||||
private int maxReverseVelocity = 1000;
|
||||
private Layout layout = new Layout();
|
||||
private List<PropertyTO> properties = List.of();
|
||||
|
||||
@JsonCreator
|
||||
public VehicleTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public VehicleTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PropertyTO> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public VehicleTO setProperties(
|
||||
@Nonnull
|
||||
List<PropertyTO> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public VehicleTO setLength(int length) {
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelCritical() {
|
||||
return energyLevelCritical;
|
||||
}
|
||||
|
||||
public VehicleTO setEnergyLevelCritical(int energyLevelCritical) {
|
||||
this.energyLevelCritical = energyLevelCritical;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelGood() {
|
||||
return energyLevelGood;
|
||||
}
|
||||
|
||||
public VehicleTO setEnergyLevelGood(int energyLevelGood) {
|
||||
this.energyLevelGood = energyLevelGood;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelFullyRecharged() {
|
||||
return energyLevelFullyRecharged;
|
||||
}
|
||||
|
||||
public VehicleTO setEnergyLevelFullyRecharged(int energyLevelFullyRecharged) {
|
||||
this.energyLevelFullyRecharged = energyLevelFullyRecharged;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEnergyLevelSufficientlyRecharged() {
|
||||
return energyLevelSufficientlyRecharged;
|
||||
}
|
||||
|
||||
public VehicleTO setEnergyLevelSufficientlyRecharged(int energyLevelSufficientlyRecharged) {
|
||||
this.energyLevelSufficientlyRecharged = energyLevelSufficientlyRecharged;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxVelocity() {
|
||||
return maxVelocity;
|
||||
}
|
||||
|
||||
public VehicleTO setMaxVelocity(int maxVelocity) {
|
||||
this.maxVelocity = maxVelocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxReverseVelocity() {
|
||||
return maxReverseVelocity;
|
||||
}
|
||||
|
||||
public VehicleTO setMaxReverseVelocity(int maxReverseVelocity) {
|
||||
this.maxReverseVelocity = maxReverseVelocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Layout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
public VehicleTO setLayout(
|
||||
@Nonnull
|
||||
Layout layout
|
||||
) {
|
||||
this.layout = requireNonNull(layout, "layout");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Layout {
|
||||
|
||||
private String routeColor = "#00FF00";
|
||||
|
||||
public Layout() {
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getRouteColor() {
|
||||
return routeColor;
|
||||
}
|
||||
|
||||
public Layout setRouteColor(
|
||||
@Nonnull
|
||||
String routeColor
|
||||
) {
|
||||
this.routeColor = requireNonNull(routeColor, "routeColor");
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class VisualLayoutTO {
|
||||
|
||||
private String name;
|
||||
private double scaleX = 50.0;
|
||||
private double scaleY = 50.0;
|
||||
private List<LayerTO> layers = List.of(new LayerTO(0, 0, true, "layer0", 0));
|
||||
private List<LayerGroupTO> layerGroups = List.of(new LayerGroupTO(0, "layerGroup0", true));
|
||||
private List<PropertyTO> properties = List.of();
|
||||
|
||||
@JsonCreator
|
||||
public VisualLayoutTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public VisualLayoutTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<PropertyTO> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public VisualLayoutTO setProperties(
|
||||
@Nonnull
|
||||
List<PropertyTO> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getScaleX() {
|
||||
return scaleX;
|
||||
}
|
||||
|
||||
public VisualLayoutTO setScaleX(double scaleX) {
|
||||
this.scaleX = scaleX;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getScaleY() {
|
||||
return scaleY;
|
||||
}
|
||||
|
||||
public VisualLayoutTO setScaleY(double scaleY) {
|
||||
this.scaleY = scaleY;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<LayerTO> getLayers() {
|
||||
return layers;
|
||||
}
|
||||
|
||||
public VisualLayoutTO setLayers(
|
||||
@Nonnull
|
||||
List<LayerTO> layers
|
||||
) {
|
||||
this.layers = requireNonNull(layers, "layers");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<LayerGroupTO> getLayerGroups() {
|
||||
return layerGroups;
|
||||
}
|
||||
|
||||
public VisualLayoutTO setLayerGroups(
|
||||
@Nonnull
|
||||
List<LayerGroupTO> layerGroups
|
||||
) {
|
||||
this.layerGroups = requireNonNull(layerGroups, "layerGroups");
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.posttransportorder;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* A destination of a transport.
|
||||
*/
|
||||
public class Destination {
|
||||
|
||||
private String locationName;
|
||||
|
||||
private String operation;
|
||||
|
||||
private List<Property> properties;
|
||||
|
||||
@JsonCreator
|
||||
public Destination(
|
||||
@Nonnull
|
||||
@JsonProperty(required = true, value = "locationName")
|
||||
String locationName,
|
||||
@Nonnull
|
||||
@JsonProperty(required = true, value = "operation")
|
||||
String operation,
|
||||
@Nullable
|
||||
@JsonProperty(required = false, value = "properties")
|
||||
List<Property> properties
|
||||
) {
|
||||
this.locationName = requireNonNull(locationName, "locationName");
|
||||
this.operation = requireNonNull(operation, "operation");
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public Destination() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getLocationName() {
|
||||
return locationName;
|
||||
}
|
||||
|
||||
public Destination setLocationName(
|
||||
@Nonnull
|
||||
String locationName
|
||||
) {
|
||||
this.locationName = requireNonNull(locationName, "locationName");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public Destination setOperation(
|
||||
@Nonnull
|
||||
String operation
|
||||
) {
|
||||
this.operation = requireNonNull(operation, "operation");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public Destination setProperties(
|
||||
@Nullable
|
||||
List<Property> properties
|
||||
) {
|
||||
this.properties = properties;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class CoupleTO {
|
||||
|
||||
private long x;
|
||||
private long y;
|
||||
|
||||
@JsonCreator
|
||||
public CoupleTO(
|
||||
@JsonProperty(value = "x", required = true)
|
||||
long x,
|
||||
@JsonProperty(value = "y", required = true)
|
||||
long y
|
||||
) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public long getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public CoupleTO setX(long x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public CoupleTO setY(long y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.opentcs.data.order.DriveOrder;
|
||||
|
||||
/**
|
||||
* A {@link org.opentcs.data.order.DriveOrder DriveOrder}'s destination.
|
||||
*/
|
||||
public class DestinationState {
|
||||
|
||||
private String locationName = "";
|
||||
|
||||
private String operation = "";
|
||||
|
||||
private State state = State.PRISTINE;
|
||||
|
||||
private List<Property> properties = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public DestinationState() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getLocationName() {
|
||||
return locationName;
|
||||
}
|
||||
|
||||
public DestinationState setLocationName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.locationName = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public DestinationState setOperation(
|
||||
@Nonnull
|
||||
String operation
|
||||
) {
|
||||
this.operation = requireNonNull(operation, "operation");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public DestinationState setState(
|
||||
@Nonnull
|
||||
State state
|
||||
) {
|
||||
this.state = requireNonNull(state, "state");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public DestinationState setProperties(
|
||||
@Nonnull
|
||||
List<Property> properties
|
||||
) {
|
||||
this.properties = requireNonNull(properties, "properties");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static DestinationState fromDriveOrder(DriveOrder driveOrder) {
|
||||
if (driveOrder == null) {
|
||||
return null;
|
||||
}
|
||||
DestinationState destination = new DestinationState();
|
||||
destination.setLocationName(driveOrder.getDestination().getDestination().getName());
|
||||
destination.setOperation(driveOrder.getDestination().getOperation());
|
||||
destination.setState(mapDriveOrderState(driveOrder.getState()));
|
||||
|
||||
for (Map.Entry<String, String> mapEntry : driveOrder.getDestination().getProperties()
|
||||
.entrySet()) {
|
||||
destination.getProperties().add(new Property(mapEntry.getKey(), mapEntry.getValue()));
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
private static DestinationState.State mapDriveOrderState(DriveOrder.State driveOrderState) {
|
||||
switch (driveOrderState) {
|
||||
case PRISTINE:
|
||||
return DestinationState.State.PRISTINE;
|
||||
case TRAVELLING:
|
||||
return DestinationState.State.TRAVELLING;
|
||||
case OPERATING:
|
||||
return DestinationState.State.OPERATING;
|
||||
case FINISHED:
|
||||
return DestinationState.State.FINISHED;
|
||||
case FAILED:
|
||||
return DestinationState.State.FAILED;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unhandled drive order state: " + driveOrderState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This enumeration defines the various states a DriveOrder may be in.
|
||||
*/
|
||||
public enum State {
|
||||
|
||||
/**
|
||||
* A DriveOrder's initial state, indicating it being still untouched/not
|
||||
* being processed.
|
||||
*/
|
||||
PRISTINE,
|
||||
/**
|
||||
* Indicates this drive order being processed at the moment.
|
||||
*/
|
||||
TRAVELLING,
|
||||
/**
|
||||
* Indicates the vehicle processing an order is currently executing an
|
||||
* operation.
|
||||
*/
|
||||
OPERATING,
|
||||
/**
|
||||
* Marks a DriveOrder as successfully completed.
|
||||
*/
|
||||
FINISHED,
|
||||
/**
|
||||
* Marks a DriveOrder as failed.
|
||||
*/
|
||||
FAILED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class EnvelopeTO {
|
||||
|
||||
private String key;
|
||||
private List<CoupleTO> vertices;
|
||||
|
||||
@JsonCreator
|
||||
public EnvelopeTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "key", required = true)
|
||||
String key,
|
||||
@Nonnull
|
||||
@JsonProperty(value = "vertices", required = true)
|
||||
List<CoupleTO> vertices
|
||||
) {
|
||||
this.key = requireNonNull(key, "key");
|
||||
this.vertices = requireNonNull(vertices, "vertices");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public EnvelopeTO setKey(
|
||||
@Nonnull
|
||||
String key
|
||||
) {
|
||||
this.key = requireNonNull(key, "key");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<CoupleTO> getVertices() {
|
||||
return vertices;
|
||||
}
|
||||
|
||||
public EnvelopeTO setVertices(
|
||||
@Nonnull
|
||||
List<CoupleTO> vertices
|
||||
) {
|
||||
this.vertices = requireNonNull(vertices, "vertices");
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class LinkTO {
|
||||
|
||||
private String pointName = "";
|
||||
private Set<String> allowedOperations = Set.of();
|
||||
|
||||
public LinkTO() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getPointName() {
|
||||
return pointName;
|
||||
}
|
||||
|
||||
public LinkTO setPointName(
|
||||
@Nonnull
|
||||
String pointName
|
||||
) {
|
||||
this.pointName = requireNonNull(pointName, "pointName");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Set<String> getAllowedOperations() {
|
||||
return allowedOperations;
|
||||
}
|
||||
|
||||
public LinkTO setAllowedOperations(
|
||||
@Nonnull
|
||||
Set<String> allowedOperations
|
||||
) {
|
||||
this.allowedOperations = requireNonNull(allowedOperations, "allowedOperations");
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared;
|
||||
|
||||
import org.opentcs.data.peripherals.PeripheralOperation;
|
||||
import org.opentcs.data.peripherals.PeripheralOperation.ExecutionTrigger;
|
||||
|
||||
/**
|
||||
* Describes a peripheral operation.
|
||||
*/
|
||||
public class PeripheralOperationDescription {
|
||||
|
||||
private String operation;
|
||||
|
||||
private String locationName;
|
||||
|
||||
private ExecutionTrigger executionTrigger;
|
||||
|
||||
private boolean completionRequired;
|
||||
|
||||
public PeripheralOperationDescription() {
|
||||
}
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public PeripheralOperationDescription setOperation(String operation) {
|
||||
this.operation = operation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getLocationName() {
|
||||
return locationName;
|
||||
}
|
||||
|
||||
public PeripheralOperationDescription setLocationName(String locationName) {
|
||||
this.locationName = locationName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExecutionTrigger getExecutionTrigger() {
|
||||
return executionTrigger;
|
||||
}
|
||||
|
||||
public PeripheralOperationDescription setExecutionTrigger(ExecutionTrigger executionTrigger) {
|
||||
this.executionTrigger = executionTrigger;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isCompletionRequired() {
|
||||
return completionRequired;
|
||||
}
|
||||
|
||||
public PeripheralOperationDescription setCompletionRequired(boolean completionRequired) {
|
||||
this.completionRequired = completionRequired;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static PeripheralOperationDescription fromPeripheralOperation(
|
||||
PeripheralOperation operation
|
||||
) {
|
||||
PeripheralOperationDescription state = new PeripheralOperationDescription();
|
||||
state.operation = operation.getOperation();
|
||||
state.locationName = operation.getLocation().getName();
|
||||
state.executionTrigger = operation.getExecutionTrigger();
|
||||
state.completionRequired = operation.isCompletionRequired();
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A key-value property.
|
||||
*/
|
||||
public class Property {
|
||||
|
||||
private String key;
|
||||
|
||||
private String value;
|
||||
|
||||
public Property(
|
||||
@Nonnull
|
||||
@JsonProperty(required = true, value = "key")
|
||||
String key,
|
||||
@Nullable
|
||||
@JsonProperty(required = false, value = "value")
|
||||
String value
|
||||
) {
|
||||
this.key = requireNonNull(key, "key");
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property key.
|
||||
*
|
||||
* @return The property key.
|
||||
*/
|
||||
@Nonnull
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property key.
|
||||
*
|
||||
* @param key The new key.
|
||||
*/
|
||||
public void setKey(
|
||||
@Nonnull
|
||||
String key
|
||||
) {
|
||||
this.key = requireNonNull(key, "key");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property value.
|
||||
*
|
||||
* @return The property value.
|
||||
*/
|
||||
@Nullable
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property value.
|
||||
*
|
||||
* @param value The new value.
|
||||
*/
|
||||
public void setValue(
|
||||
@Nullable
|
||||
String value
|
||||
) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class PropertyTO {
|
||||
|
||||
private String name;
|
||||
private String value;
|
||||
|
||||
@JsonCreator
|
||||
public PropertyTO(
|
||||
@Nonnull
|
||||
@JsonProperty(value = "name", required = true)
|
||||
String name,
|
||||
@Nonnull
|
||||
@JsonProperty(value = "value", required = true)
|
||||
String value
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
this.value = requireNonNull(value, "value");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public PropertyTO setName(
|
||||
@Nonnull
|
||||
String name
|
||||
) {
|
||||
this.name = requireNonNull(name, "name");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public PropertyTO setValue(
|
||||
@Nonnull
|
||||
String value
|
||||
) {
|
||||
this.value = requireNonNull(value, "value");
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class TripleTO {
|
||||
|
||||
private long x;
|
||||
private long y;
|
||||
private long z;
|
||||
|
||||
@JsonCreator
|
||||
public TripleTO(
|
||||
@JsonProperty(value = "x", required = true)
|
||||
long x,
|
||||
@JsonProperty(value = "y", required = true)
|
||||
long y,
|
||||
@JsonProperty(value = "z", required = true)
|
||||
long z
|
||||
) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public long getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public TripleTO setX(long x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public TripleTO setY(long y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public TripleTO setZ(long z) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.to.model.BlockCreationTO;
|
||||
import org.opentcs.data.model.Block;
|
||||
import org.opentcs.data.model.TCSResourceReference;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.BlockTO;
|
||||
import org.opentcs.util.Colors;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all Block classes.
|
||||
*/
|
||||
public class BlockConverter {
|
||||
|
||||
private final PropertyConverter pConverter;
|
||||
|
||||
@Inject
|
||||
public BlockConverter(PropertyConverter pConverter) {
|
||||
this.pConverter = requireNonNull(pConverter, "pConverter");
|
||||
}
|
||||
|
||||
public List<BlockCreationTO> toBlockCreationTOs(List<BlockTO> blocks) {
|
||||
return blocks.stream()
|
||||
.map(
|
||||
block -> new BlockCreationTO(block.getName())
|
||||
.withProperties(pConverter.toPropertyMap(block.getProperties()))
|
||||
.withMemberNames(block.getMemberNames())
|
||||
.withType(Block.Type.valueOf(block.getType()))
|
||||
.withLayout(
|
||||
new BlockCreationTO.Layout(
|
||||
Colors.decodeFromHexRGB(block.getLayout().getColor())
|
||||
)
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
public List<BlockTO> toBlockTOs(Set<Block> blocks) {
|
||||
return blocks.stream()
|
||||
.map(
|
||||
block -> new BlockTO(block.getName())
|
||||
.setType(block.getType().name())
|
||||
.setMemberNames(convertMemberNames(block.getMembers()))
|
||||
.setLayout(
|
||||
new BlockTO.Layout()
|
||||
.setColor(Colors.encodeToHexRGB(block.getLayout().getColor()))
|
||||
)
|
||||
.setProperties(pConverter.toPropertyTOs(block.getProperties()))
|
||||
)
|
||||
.sorted(Comparator.comparing(BlockTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Set<String> convertMemberNames(Set<TCSResourceReference<?>> members) {
|
||||
return members.stream()
|
||||
.map(TCSResourceReference::getName)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.data.model.Couple;
|
||||
import org.opentcs.data.model.Envelope;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.CoupleTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.EnvelopeTO;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all Envelope classes.
|
||||
*/
|
||||
public class EnvelopeConverter {
|
||||
|
||||
public EnvelopeConverter() {
|
||||
}
|
||||
|
||||
public Map<String, Envelope> toVehicleEnvelopeMap(List<EnvelopeTO> envelopeEntries) {
|
||||
return envelopeEntries.stream()
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
EnvelopeTO::getKey,
|
||||
entry -> {
|
||||
List<Couple> couples = entry.getVertices().stream()
|
||||
.map(coupleTO -> new Couple(coupleTO.getX(), coupleTO.getY()))
|
||||
.collect(Collectors.toList());
|
||||
return new Envelope(couples);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public List<EnvelopeTO> toEnvelopeTOs(Map<String, Envelope> envelopeMap) {
|
||||
return envelopeMap.entrySet().stream()
|
||||
.map(
|
||||
entry -> new EnvelopeTO(
|
||||
entry.getKey(),
|
||||
entry.getValue().getVertices().stream()
|
||||
.map(couple -> new CoupleTO(couple.getX(), couple.getY()))
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
)
|
||||
.sorted(Comparator.comparing(EnvelopeTO::getKey))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.to.model.LocationCreationTO;
|
||||
import org.opentcs.data.model.Couple;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.Triple;
|
||||
import org.opentcs.data.model.visualization.LocationRepresentation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.LocationTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.CoupleTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.LinkTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.TripleTO;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all Location classes.
|
||||
*/
|
||||
public class LocationConverter {
|
||||
|
||||
private final PropertyConverter pConverter;
|
||||
|
||||
@Inject
|
||||
public LocationConverter(PropertyConverter pConverter) {
|
||||
this.pConverter = requireNonNull(pConverter, "pConverter");
|
||||
}
|
||||
|
||||
public List<LocationCreationTO> toLocationCreationTOs(List<LocationTO> locations) {
|
||||
return locations.stream()
|
||||
.map(
|
||||
location -> new LocationCreationTO(
|
||||
location.getName(),
|
||||
location.getTypeName(),
|
||||
new Triple(
|
||||
location.getPosition().getX(),
|
||||
location.getPosition().getY(),
|
||||
location.getPosition().getZ()
|
||||
)
|
||||
)
|
||||
.withProperties(pConverter.toPropertyMap(location.getProperties()))
|
||||
.withLinks(toLinkMap(location.getLinks()))
|
||||
.withLocked(location.isLocked())
|
||||
.withLayout(
|
||||
new LocationCreationTO.Layout(
|
||||
new Couple(
|
||||
location.getLayout().getPosition().getX(),
|
||||
location.getLayout().getPosition().getY()
|
||||
),
|
||||
new Couple(
|
||||
location.getLayout().getLabelOffset().getX(),
|
||||
location.getLayout().getLabelOffset().getY()
|
||||
),
|
||||
LocationRepresentation.valueOf(
|
||||
location.getLayout().getLocationRepresentation()
|
||||
),
|
||||
location.getLayout().getLayerId()
|
||||
)
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
public List<LocationTO> toLocationTOs(Set<Location> locations) {
|
||||
return locations.stream()
|
||||
.map(
|
||||
location -> new LocationTO(
|
||||
location.getName(),
|
||||
location.getType().getName(),
|
||||
new TripleTO(
|
||||
location.getPosition().getX(),
|
||||
location.getPosition().getY(),
|
||||
location.getPosition().getZ()
|
||||
)
|
||||
)
|
||||
.setLocked(location.isLocked())
|
||||
.setProperties(pConverter.toPropertyTOs(location.getProperties()))
|
||||
.setLinks(toLinkTOs(location.getAttachedLinks()))
|
||||
.setLayout(
|
||||
new LocationTO.Layout()
|
||||
.setLayerId(location.getLayout().getLayerId())
|
||||
.setLocationRepresentation(
|
||||
location.getLayout().getLocationRepresentation().name()
|
||||
)
|
||||
.setLabelOffset(
|
||||
new CoupleTO(
|
||||
location.getLayout().getLabelOffset().getX(),
|
||||
location.getLayout().getLabelOffset().getY()
|
||||
)
|
||||
)
|
||||
.setPosition(
|
||||
new CoupleTO(
|
||||
location.getLayout().getPosition().getX(),
|
||||
location.getLayout().getPosition().getY()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.sorted(Comparator.comparing(LocationTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Map<String, Set<String>> toLinkMap(List<LinkTO> links) {
|
||||
return links.stream()
|
||||
.collect(Collectors.toMap(LinkTO::getPointName, LinkTO::getAllowedOperations));
|
||||
}
|
||||
|
||||
private List<LinkTO> toLinkTOs(Set<Location.Link> links) {
|
||||
return links.stream()
|
||||
.map(
|
||||
link -> new LinkTO()
|
||||
.setPointName(link.getPoint().getName())
|
||||
.setAllowedOperations(link.getAllowedOperations())
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.to.model.LocationTypeCreationTO;
|
||||
import org.opentcs.data.model.LocationType;
|
||||
import org.opentcs.data.model.visualization.LocationRepresentation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.LocationTypeTO;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all LocationType classes.
|
||||
*/
|
||||
public class LocationTypeConverter {
|
||||
|
||||
private final PropertyConverter pConverter;
|
||||
|
||||
@Inject
|
||||
public LocationTypeConverter(PropertyConverter pConverter) {
|
||||
this.pConverter = requireNonNull(pConverter, "pConverter");
|
||||
}
|
||||
|
||||
public List<LocationTypeCreationTO> toLocationTypeCreationTOs(List<LocationTypeTO> locTypes) {
|
||||
return locTypes.stream()
|
||||
.map(
|
||||
locationType -> new LocationTypeCreationTO(locationType.getName())
|
||||
.withAllowedOperations(locationType.getAllowedOperations())
|
||||
.withAllowedPeripheralOperations(
|
||||
locationType.getAllowedPeripheralOperations()
|
||||
)
|
||||
.withProperties(pConverter.toPropertyMap(locationType.getProperties()))
|
||||
.withLayout(
|
||||
new LocationTypeCreationTO.Layout(
|
||||
LocationRepresentation.valueOf(
|
||||
locationType.getLayout().getLocationRepresentation()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
public List<LocationTypeTO> toLocationTypeTOs(Set<LocationType> locationTypes) {
|
||||
return locationTypes.stream()
|
||||
.map(
|
||||
locationType -> new LocationTypeTO(locationType.getName())
|
||||
.setProperties(pConverter.toPropertyTOs(locationType.getProperties()))
|
||||
.setAllowedOperations(locationType.getAllowedOperations())
|
||||
.setAllowedPeripheralOperations(locationType.getAllowedPeripheralOperations())
|
||||
.setLayout(
|
||||
new LocationTypeTO.Layout()
|
||||
.setLocationRepresentation(
|
||||
locationType.getLayout().getLocationRepresentation().name()
|
||||
)
|
||||
)
|
||||
)
|
||||
.sorted(Comparator.comparing(LocationTypeTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.to.model.PathCreationTO;
|
||||
import org.opentcs.data.model.Couple;
|
||||
import org.opentcs.data.model.Path;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.PathTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.CoupleTO;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all Path classes.
|
||||
*/
|
||||
public class PathConverter {
|
||||
|
||||
private final PropertyConverter pConverter;
|
||||
private final PeripheralOperationConverter pOConverter;
|
||||
private final EnvelopeConverter envelopeConverter;
|
||||
|
||||
@Inject
|
||||
public PathConverter(
|
||||
PropertyConverter pConverter, PeripheralOperationConverter pOConverter,
|
||||
EnvelopeConverter envelopeConverter
|
||||
) {
|
||||
this.pConverter = requireNonNull(pConverter, "pConverter");
|
||||
this.pOConverter = requireNonNull(pOConverter, "pOConverter");
|
||||
this.envelopeConverter = requireNonNull(envelopeConverter, "envelopeConverter");
|
||||
}
|
||||
|
||||
public List<PathTO> toPathTOs(Set<Path> paths) {
|
||||
return paths.stream()
|
||||
.map(
|
||||
path -> new PathTO(
|
||||
path.getName(),
|
||||
path.getSourcePoint().getName(),
|
||||
path.getDestinationPoint().getName()
|
||||
)
|
||||
.setLength(path.getLength())
|
||||
.setLocked(path.isLocked())
|
||||
.setMaxReverseVelocity(path.getMaxReverseVelocity())
|
||||
.setMaxVelocity(path.getMaxVelocity())
|
||||
.setVehicleEnvelopes(envelopeConverter.toEnvelopeTOs(path.getVehicleEnvelopes()))
|
||||
.setProperties(pConverter.toPropertyTOs(path.getProperties()))
|
||||
.setPeripheralOperations(
|
||||
pOConverter.toPeripheralOperationsTOs(path.getPeripheralOperations())
|
||||
)
|
||||
.setLayout(
|
||||
new PathTO.Layout()
|
||||
.setLayerId(path.getLayout().getLayerId())
|
||||
.setConnectionType(path.getLayout().getConnectionType().name())
|
||||
.setControlPoints(toCoupleTOs(path.getLayout().getControlPoints()))
|
||||
)
|
||||
)
|
||||
.sorted(Comparator.comparing(PathTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<PathCreationTO> toPathCreationTOs(List<PathTO> paths) {
|
||||
return paths.stream()
|
||||
.map(
|
||||
path -> new PathCreationTO(
|
||||
path.getName(),
|
||||
path.getSrcPointName(),
|
||||
path.getDestPointName()
|
||||
)
|
||||
.withName(path.getName())
|
||||
.withProperties(pConverter.toPropertyMap(path.getProperties()))
|
||||
.withLength(path.getLength())
|
||||
.withMaxVelocity(path.getMaxVelocity())
|
||||
.withMaxReverseVelocity(path.getMaxReverseVelocity())
|
||||
.withLocked(path.isLocked())
|
||||
.withLayout(toPathCreationTOLayout(path.getLayout()))
|
||||
.withVehicleEnvelopes(
|
||||
envelopeConverter
|
||||
.toVehicleEnvelopeMap(path.getVehicleEnvelopes())
|
||||
)
|
||||
.withPeripheralOperations(
|
||||
pOConverter.toPeripheralOperationCreationTOs(path.getPeripheralOperations())
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
private PathCreationTO.Layout toPathCreationTOLayout(PathTO.Layout layout) {
|
||||
return new PathCreationTO.Layout(
|
||||
Path.Layout.ConnectionType.valueOf(layout.getConnectionType()),
|
||||
layout.getControlPoints()
|
||||
.stream()
|
||||
.map(cp -> new Couple(cp.getX(), cp.getY()))
|
||||
.collect(Collectors.toList()),
|
||||
layout.getLayerId()
|
||||
);
|
||||
}
|
||||
|
||||
private List<CoupleTO> toCoupleTOs(List<Couple> controlPoints) {
|
||||
return controlPoints.stream()
|
||||
.map(cp -> new CoupleTO(cp.getX(), cp.getY()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.to.peripherals.PeripheralOperationCreationTO;
|
||||
import org.opentcs.data.peripherals.PeripheralOperation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.PeripheralOperationTO;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all PeripheralOperation classes.
|
||||
*/
|
||||
public class PeripheralOperationConverter {
|
||||
|
||||
public PeripheralOperationConverter() {
|
||||
}
|
||||
|
||||
public List<PeripheralOperationTO> toPeripheralOperationsTOs(
|
||||
List<PeripheralOperation> peripheralOperations
|
||||
) {
|
||||
return peripheralOperations.stream()
|
||||
.map(
|
||||
perOp -> new PeripheralOperationTO(
|
||||
perOp.getOperation(),
|
||||
perOp.getLocation().getName()
|
||||
)
|
||||
.setCompletionRequired(perOp.isCompletionRequired())
|
||||
.setExecutionTrigger(
|
||||
perOp.getExecutionTrigger().name()
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<PeripheralOperationCreationTO> toPeripheralOperationCreationTOs(
|
||||
List<PeripheralOperationTO> perOps
|
||||
) {
|
||||
return perOps.stream()
|
||||
.map(
|
||||
perOp -> new PeripheralOperationCreationTO(
|
||||
perOp.getOperation(),
|
||||
perOp.getLocationName()
|
||||
)
|
||||
.withCompletionRequired(perOp.isCompletionRequired())
|
||||
.withExecutionTrigger(
|
||||
PeripheralOperation.ExecutionTrigger.valueOf(
|
||||
perOp.getExecutionTrigger()
|
||||
)
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.to.model.PointCreationTO;
|
||||
import org.opentcs.data.model.Couple;
|
||||
import org.opentcs.data.model.Point;
|
||||
import org.opentcs.data.model.Pose;
|
||||
import org.opentcs.data.model.Triple;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.PointTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.CoupleTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.TripleTO;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all Point classes.
|
||||
*/
|
||||
public class PointConverter {
|
||||
|
||||
private final PropertyConverter pConverter;
|
||||
private final EnvelopeConverter envelopeConverter;
|
||||
|
||||
@Inject
|
||||
public PointConverter(PropertyConverter pConverter, EnvelopeConverter envelopeConverter) {
|
||||
this.pConverter = requireNonNull(pConverter, "pConverter");
|
||||
this.envelopeConverter = requireNonNull(envelopeConverter, "envelopeConverter");
|
||||
}
|
||||
|
||||
public List<PointTO> toPointTOs(Set<Point> points) {
|
||||
return points.stream()
|
||||
.map(
|
||||
point -> new PointTO(point.getName())
|
||||
.setPosition(
|
||||
new TripleTO(
|
||||
point.getPose().getPosition().getX(),
|
||||
point.getPose().getPosition().getY(),
|
||||
point.getPose().getPosition().getZ()
|
||||
)
|
||||
)
|
||||
.setType(point.getType().name())
|
||||
.setVehicleOrientationAngle(point.getPose().getOrientationAngle())
|
||||
.setVehicleEnvelopes(envelopeConverter.toEnvelopeTOs(point.getVehicleEnvelopes()))
|
||||
.setProperties(pConverter.toPropertyTOs(point.getProperties()))
|
||||
.setLayout(
|
||||
new PointTO.Layout()
|
||||
.setLabelOffset(
|
||||
new CoupleTO(
|
||||
point.getLayout().getLabelOffset().getX(),
|
||||
point.getLayout().getLabelOffset().getY()
|
||||
)
|
||||
)
|
||||
.setPosition(
|
||||
new CoupleTO(
|
||||
point.getLayout().getPosition().getX(),
|
||||
point.getLayout().getPosition().getY()
|
||||
)
|
||||
)
|
||||
.setLayerId(point.getLayout().getLayerId())
|
||||
)
|
||||
)
|
||||
.sorted(Comparator.comparing(PointTO::getName))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
public List<PointCreationTO> toPointCreationTOs(List<PointTO> points) {
|
||||
return points.stream()
|
||||
.map(
|
||||
point -> new PointCreationTO(point.getName())
|
||||
.withProperties(pConverter.toPropertyMap(point.getProperties()))
|
||||
.withPose(
|
||||
new Pose(
|
||||
new Triple(
|
||||
point.getPosition().getX(),
|
||||
point.getPosition().getY(),
|
||||
point.getPosition().getZ()
|
||||
),
|
||||
point.getVehicleOrientationAngle()
|
||||
)
|
||||
)
|
||||
.withType(Point.Type.valueOf(point.getType()))
|
||||
.withLayout(
|
||||
new PointCreationTO.Layout(
|
||||
new Couple(
|
||||
point.getLayout().getPosition().getX(),
|
||||
point.getLayout().getPosition().getY()
|
||||
),
|
||||
new Couple(
|
||||
point.getLayout().getLabelOffset().getX(),
|
||||
point.getLayout().getLabelOffset().getY()
|
||||
),
|
||||
point.getLayout().getLayerId()
|
||||
)
|
||||
)
|
||||
.withVehicleEnvelopes(
|
||||
envelopeConverter
|
||||
.toVehicleEnvelopeMap(point.getVehicleEnvelopes())
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all Property classes.
|
||||
*/
|
||||
public class PropertyConverter {
|
||||
|
||||
public PropertyConverter() {
|
||||
}
|
||||
|
||||
public List<PropertyTO> toPropertyTOs(Map<String, String> properties) {
|
||||
return properties.entrySet().stream()
|
||||
.map(property -> new PropertyTO(property.getKey(), property.getValue()))
|
||||
.sorted(Comparator.comparing(PropertyTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Map<String, String> toPropertyMap(List<PropertyTO> properties) {
|
||||
return properties.stream()
|
||||
.collect(Collectors.toMap(PropertyTO::getName, PropertyTO::getValue));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.to.model.BoundingBoxCreationTO;
|
||||
import org.opentcs.access.to.model.VehicleCreationTO;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.VehicleTO;
|
||||
import org.opentcs.util.Colors;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all Vehicle classes.
|
||||
*/
|
||||
public class VehicleConverter {
|
||||
|
||||
private final PropertyConverter pConverter;
|
||||
|
||||
@Inject
|
||||
public VehicleConverter(PropertyConverter pConverter) {
|
||||
this.pConverter = requireNonNull(pConverter, "pConverter");
|
||||
}
|
||||
|
||||
public List<VehicleCreationTO> toVehicleCreationTOs(List<VehicleTO> vehicles) {
|
||||
return vehicles.stream()
|
||||
.map(
|
||||
vehicle -> new VehicleCreationTO(vehicle.getName())
|
||||
.withProperties(pConverter.toPropertyMap(vehicle.getProperties()))
|
||||
.withBoundingBox(new BoundingBoxCreationTO(vehicle.getLength(), 1000, 1000))
|
||||
.withEnergyLevelThresholdSet(
|
||||
new VehicleCreationTO.EnergyLevelThresholdSet(
|
||||
vehicle.getEnergyLevelCritical(),
|
||||
vehicle.getEnergyLevelGood(),
|
||||
vehicle.getEnergyLevelSufficientlyRecharged(),
|
||||
vehicle.getEnergyLevelFullyRecharged()
|
||||
)
|
||||
)
|
||||
.withMaxVelocity(vehicle.getMaxVelocity())
|
||||
.withMaxReverseVelocity(vehicle.getMaxReverseVelocity())
|
||||
.withLayout(
|
||||
new VehicleCreationTO.Layout(
|
||||
Colors.decodeFromHexRGB(vehicle.getLayout().getRouteColor())
|
||||
)
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
public List<VehicleTO> toVehicleTOs(Set<Vehicle> vehicles) {
|
||||
return vehicles.stream()
|
||||
.map(
|
||||
vehicle -> new VehicleTO(vehicle.getName())
|
||||
.setLength((int) vehicle.getBoundingBox().getLength())
|
||||
.setEnergyLevelCritical(
|
||||
vehicle.getEnergyLevelThresholdSet().getEnergyLevelCritical()
|
||||
)
|
||||
.setEnergyLevelGood(vehicle.getEnergyLevelThresholdSet().getEnergyLevelGood())
|
||||
.setEnergyLevelFullyRecharged(
|
||||
vehicle.getEnergyLevelThresholdSet().getEnergyLevelFullyRecharged()
|
||||
)
|
||||
.setEnergyLevelSufficientlyRecharged(
|
||||
vehicle.getEnergyLevelThresholdSet().getEnergyLevelSufficientlyRecharged()
|
||||
)
|
||||
.setMaxVelocity(vehicle.getMaxVelocity())
|
||||
.setMaxReverseVelocity(vehicle.getMaxReverseVelocity())
|
||||
.setLayout(
|
||||
new VehicleTO.Layout()
|
||||
.setRouteColor(Colors.encodeToHexRGB(vehicle.getLayout().getRouteColor()))
|
||||
)
|
||||
.setProperties(pConverter.toPropertyTOs(vehicle.getProperties()))
|
||||
)
|
||||
.sorted(Comparator.comparing(VehicleTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.converter;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.access.to.model.VisualLayoutCreationTO;
|
||||
import org.opentcs.data.model.visualization.Layer;
|
||||
import org.opentcs.data.model.visualization.LayerGroup;
|
||||
import org.opentcs.data.model.visualization.VisualLayout;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.LayerGroupTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.LayerTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.VisualLayoutTO;
|
||||
|
||||
/**
|
||||
* Includes the conversion methods for all VisualLayout classes.
|
||||
*/
|
||||
public class VisualLayoutConverter {
|
||||
|
||||
private final PropertyConverter pConverter;
|
||||
|
||||
@Inject
|
||||
public VisualLayoutConverter(PropertyConverter pConverter) {
|
||||
this.pConverter = requireNonNull(pConverter, "pConverter");
|
||||
}
|
||||
|
||||
public VisualLayoutCreationTO toVisualLayoutCreationTO(VisualLayoutTO vLayout) {
|
||||
return new VisualLayoutCreationTO(vLayout.getName())
|
||||
.withProperties(pConverter.toPropertyMap(vLayout.getProperties()))
|
||||
.withScaleX(vLayout.getScaleX())
|
||||
.withScaleY(vLayout.getScaleY())
|
||||
.withLayers(convertLayers(vLayout.getLayers()))
|
||||
.withLayerGroups(convertLayerGroups(vLayout.getLayerGroups()));
|
||||
}
|
||||
|
||||
public VisualLayoutTO toVisualLayoutTO(VisualLayout visualLayout) {
|
||||
return new VisualLayoutTO(visualLayout.getName())
|
||||
.setProperties(pConverter.toPropertyTOs(visualLayout.getProperties()))
|
||||
.setScaleX(visualLayout.getScaleX())
|
||||
.setScaleY(visualLayout.getScaleY())
|
||||
.setLayers(toLayerTOs(visualLayout.getLayers()))
|
||||
.setLayerGroups(toLayerGroupTOs(visualLayout.getLayerGroups()));
|
||||
}
|
||||
|
||||
private List<LayerGroup> convertLayerGroups(List<LayerGroupTO> layerGroups) {
|
||||
return layerGroups.stream()
|
||||
.map(
|
||||
layerGroup -> new LayerGroup(
|
||||
layerGroup.getId(),
|
||||
layerGroup.getName(),
|
||||
layerGroup.isVisible()
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<LayerGroupTO> toLayerGroupTOs(List<LayerGroup> layerGroups) {
|
||||
return layerGroups.stream()
|
||||
.map(
|
||||
layerGroup -> new LayerGroupTO(
|
||||
layerGroup.getId(),
|
||||
layerGroup.getName(),
|
||||
layerGroup.isVisible()
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Layer> convertLayers(List<LayerTO> layers) {
|
||||
return layers.stream()
|
||||
.map(
|
||||
layer -> new Layer(
|
||||
layer.getId(),
|
||||
layer.getOrdinal(),
|
||||
layer.isVisible(),
|
||||
layer.getName(),
|
||||
layer.getGroupId()
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<LayerTO> toLayerTOs(List<Layer> layers) {
|
||||
return layers.stream()
|
||||
.map(
|
||||
layer -> new LayerTO(
|
||||
layer.getId(),
|
||||
layer.getOrdinal(),
|
||||
layer.isVisible(),
|
||||
layer.getName(),
|
||||
layer.getGroupId()
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import spark.Request;
|
||||
|
||||
/**
|
||||
*/
|
||||
class AuthenticatorTest {
|
||||
|
||||
private ServiceWebApiConfiguration configuration;
|
||||
|
||||
private Authenticator authenticator;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
configuration = mock(ServiceWebApiConfiguration.class);
|
||||
authenticator = new Authenticator(configuration);
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowRequestsIfNoAccessKeyConfigured() {
|
||||
when(configuration.accessKey()).thenReturn("");
|
||||
|
||||
assertTrue(authenticator.isAuthenticated(aRequestWithAccessKey(null)));
|
||||
assertTrue(authenticator.isAuthenticated(aRequestWithAccessKey("")));
|
||||
assertTrue(authenticator.isAuthenticated(aRequestWithAccessKey("some random value")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowRequestIfCorrectAccessKeyGiven() {
|
||||
when(configuration.accessKey()).thenReturn("my access key");
|
||||
|
||||
assertTrue(authenticator.isAuthenticated(aRequestWithAccessKey("my access key")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void disallowRequestIfWrongAccessKeyGiven() {
|
||||
when(configuration.accessKey()).thenReturn("my access key");
|
||||
|
||||
assertFalse(authenticator.isAuthenticated(aRequestWithAccessKey(null)));
|
||||
assertFalse(authenticator.isAuthenticated(aRequestWithAccessKey("")));
|
||||
assertFalse(authenticator.isAuthenticated(aRequestWithAccessKey("some random value")));
|
||||
}
|
||||
|
||||
private Request aRequestWithAccessKey(String accessKey) {
|
||||
Request request = mock(Request.class);
|
||||
|
||||
when(request.headers(HttpConstants.HEADER_NAME_ACCESS_KEY)).thenReturn(accessKey);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import org.approvaltests.Approvals;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link JsonBinder}.
|
||||
*/
|
||||
class JsonBinderTest {
|
||||
|
||||
private JsonBinder jsonBinder;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
jsonBinder = new JsonBinder();
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeAndParseObject() {
|
||||
String json = jsonBinder.toJson(new TestObject().setName("some-name"));
|
||||
|
||||
Approvals.verify(json);
|
||||
|
||||
TestObject parsedObject = jsonBinder.fromJson(json, TestObject.class);
|
||||
|
||||
assertThat(parsedObject.getName(), is(equalTo("some-name")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeAndParseThrowable() {
|
||||
Approvals.verify(jsonBinder.toJson(new TestException("some-message")));
|
||||
}
|
||||
|
||||
private static class TestObject {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public TestObject setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestException
|
||||
extends
|
||||
Exception {
|
||||
|
||||
TestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name" : "some-name"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
[ "some-message" ]
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentcs.access.KernelRuntimeException;
|
||||
import org.opentcs.data.ObjectExistsException;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
|
||||
/**
|
||||
* Tests for {@link KernelExecutorWrapper}.
|
||||
*/
|
||||
class KernelExecutorWrapperTest {
|
||||
|
||||
private ExecutorService executorService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.executorService = Executors.newSingleThreadExecutor();
|
||||
this.executorWrapper = new KernelExecutorWrapper(executorService);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
executorService.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnValueReturnedInCallable() {
|
||||
assertThat(
|
||||
executorWrapper.callAndWait(() -> "my result"),
|
||||
is("my result")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void forwardCausingExceptionIfRuntimeException() {
|
||||
assertThrows(
|
||||
ObjectUnknownException.class,
|
||||
() -> {
|
||||
executorWrapper.callAndWait(() -> {
|
||||
throw new ObjectUnknownException("some exception");
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
ObjectExistsException.class,
|
||||
() -> {
|
||||
executorWrapper.callAndWait(() -> {
|
||||
throw new ObjectExistsException("some exception");
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrapUnhandledExceptionInKernelRuntimeException() {
|
||||
assertThrows(
|
||||
KernelRuntimeException.class,
|
||||
() -> {
|
||||
executorWrapper.callAndWait(() -> {
|
||||
throw new Exception("some exception");
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.LocationType;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.OrderSequence;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.data.peripherals.PeripheralOperation;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link Filters}.
|
||||
*/
|
||||
class FiltersTest {
|
||||
|
||||
@Test
|
||||
void acceptTransportOrdersRegardlessOfIntendedVehicle() {
|
||||
assertThat(
|
||||
Filters.transportOrderWithIntendedVehicle(null)
|
||||
.test(
|
||||
new TransportOrder("some-order", List.of())
|
||||
.withIntendedVehicle(null)
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.transportOrderWithIntendedVehicle(null)
|
||||
.test(
|
||||
new TransportOrder("some-order", List.of())
|
||||
.withIntendedVehicle(new Vehicle("some-vehicle").getReference())
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptTransportOrdersWithGivenIntendedVehicle() {
|
||||
Vehicle vehicle = new Vehicle("some-vehicle");
|
||||
|
||||
assertThat(
|
||||
Filters.transportOrderWithIntendedVehicle(vehicle.getReference())
|
||||
.test(
|
||||
new TransportOrder("some-order", List.of())
|
||||
.withIntendedVehicle(null)
|
||||
),
|
||||
is(false)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.transportOrderWithIntendedVehicle(null)
|
||||
.test(
|
||||
new TransportOrder("some-order", List.of())
|
||||
.withIntendedVehicle(vehicle.getReference())
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptOrderSequencesRegardlessOfIntendedVehicle() {
|
||||
assertThat(
|
||||
Filters.orderSequenceWithIntendedVehicle(null)
|
||||
.test(
|
||||
new OrderSequence("some-sequence")
|
||||
.withIntendedVehicle(null)
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.orderSequenceWithIntendedVehicle(null)
|
||||
.test(
|
||||
new OrderSequence("some-sequence")
|
||||
.withIntendedVehicle(new Vehicle("some-vehicle").getReference())
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptOrderSequenceWithGivenIntendedVehicle() {
|
||||
Vehicle vehicle = new Vehicle("some-vehicle");
|
||||
|
||||
assertThat(
|
||||
Filters.orderSequenceWithIntendedVehicle(vehicle.getReference())
|
||||
.test(
|
||||
new OrderSequence("some-sequence")
|
||||
.withIntendedVehicle(null)
|
||||
),
|
||||
is(false)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.orderSequenceWithIntendedVehicle(null)
|
||||
.test(
|
||||
new OrderSequence("some-sequence")
|
||||
.withIntendedVehicle(new Vehicle("some-vehicle").getReference())
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptPeripheralJobsRegardlessOfRelatedVehicle() {
|
||||
Location location
|
||||
= new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
PeripheralJob job = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.peripheralJobWithRelatedVehicle(null)
|
||||
.test(
|
||||
job.withRelatedVehicle(null)
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.peripheralJobWithRelatedVehicle(null)
|
||||
.test(
|
||||
job.withRelatedVehicle(new Vehicle("some-vehicle").getReference())
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptPeripheralJobsWithGivenRelatedVehicle() {
|
||||
Location location
|
||||
= new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
PeripheralJob job = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
Vehicle vehicle = new Vehicle("some-vehicle");
|
||||
|
||||
assertThat(
|
||||
Filters.peripheralJobWithRelatedVehicle(vehicle.getReference())
|
||||
.test(
|
||||
job.withRelatedVehicle(null)
|
||||
),
|
||||
is(false)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.peripheralJobWithRelatedVehicle(vehicle.getReference())
|
||||
.test(
|
||||
job.withRelatedVehicle(vehicle.getReference())
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptPeripheralJobsRegardlessOfRelatedTransportOrder() {
|
||||
Location location
|
||||
= new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
PeripheralJob job = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.peripheralJobWithRelatedTransportOrder(null)
|
||||
.test(
|
||||
job.withRelatedTransportOrder(null)
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.peripheralJobWithRelatedTransportOrder(null)
|
||||
.test(
|
||||
job.withRelatedTransportOrder(
|
||||
new TransportOrder("some-order", List.of()).getReference()
|
||||
)
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptPeripheralJobsWithGivenRelatedTransportOrder() {
|
||||
Location location
|
||||
= new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
PeripheralJob job = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
TransportOrder order = new TransportOrder("some-order", List.of());
|
||||
|
||||
assertThat(
|
||||
Filters.peripheralJobWithRelatedTransportOrder(order.getReference())
|
||||
.test(
|
||||
job.withRelatedTransportOrder(null)
|
||||
),
|
||||
is(false)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.peripheralJobWithRelatedTransportOrder(order.getReference())
|
||||
.test(
|
||||
job.withRelatedTransportOrder(order.getReference())
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(Vehicle.ProcState.class)
|
||||
void acceptVehiclesWithAnyProcState(Vehicle.ProcState procState) {
|
||||
assertThat(
|
||||
Filters.vehicleWithProcState(null)
|
||||
.test(
|
||||
new Vehicle("some-vehicle")
|
||||
.withProcState(procState)
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptVehiclesWithGivenProcStateOnly() {
|
||||
assertThat(
|
||||
Filters.vehicleWithProcState(Vehicle.ProcState.IDLE)
|
||||
.test(
|
||||
new Vehicle("some-vehicle")
|
||||
.withProcState(Vehicle.ProcState.IDLE)
|
||||
),
|
||||
is(true)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
Filters.vehicleWithProcState(Vehicle.ProcState.IDLE)
|
||||
.test(
|
||||
new Vehicle("some-vehicle")
|
||||
.withProcState(Vehicle.ProcState.AWAITING_ORDER)
|
||||
),
|
||||
is(false)
|
||||
);
|
||||
assertThat(
|
||||
Filters.vehicleWithProcState(Vehicle.ProcState.IDLE)
|
||||
.test(
|
||||
new Vehicle("some-vehicle")
|
||||
.withProcState(Vehicle.ProcState.PROCESSING_ORDER)
|
||||
),
|
||||
is(false)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.opentcs.components.kernel.services.PlantModelService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.LocationType;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Tests for {@link LocationHandler}.
|
||||
*/
|
||||
class LocationHandlerTest {
|
||||
|
||||
private PlantModelService plantModelService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
|
||||
private LocationHandler handler;
|
||||
|
||||
private Location location;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
plantModelService = mock();
|
||||
executorWrapper = new KernelExecutorWrapper(Executors.newSingleThreadExecutor());
|
||||
|
||||
handler = new LocationHandler(plantModelService, executorWrapper);
|
||||
|
||||
location = new Location(
|
||||
"some-location",
|
||||
new LocationType("some-location-type").getReference()
|
||||
);
|
||||
given(plantModelService.fetchObject(Location.class, "some-location"))
|
||||
.willReturn(location);
|
||||
}
|
||||
|
||||
@Test
|
||||
void lockLocation() {
|
||||
handler.updateLocationLock("some-location", "true");
|
||||
|
||||
then(plantModelService).should().updateLocationLock(location.getReference(), true);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"false", "flase", "some-value-that-is-not-true"})
|
||||
void unlockLocationOnAnyNontrueValue(String value) {
|
||||
handler.updateLocationLock("some-location", value);
|
||||
|
||||
then(plantModelService).should().updateLocationLock(location.getReference(), false);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"true", "false"})
|
||||
void throwOnLockUnknownLocation(String value) {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.updateLocationLock("some-unknown-location", value));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.opentcs.components.kernel.services.PlantModelService;
|
||||
import org.opentcs.components.kernel.services.TCSObjectService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Path;
|
||||
import org.opentcs.data.model.Point;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Tests for {@link PathHandler}.
|
||||
*/
|
||||
class PathHandlerTest {
|
||||
|
||||
private TCSObjectService objectService;
|
||||
private PlantModelService plantModelService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
|
||||
private PathHandler handler;
|
||||
|
||||
private Path path;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
objectService = mock();
|
||||
plantModelService = mock();
|
||||
executorWrapper = new KernelExecutorWrapper(Executors.newSingleThreadExecutor());
|
||||
|
||||
handler = new PathHandler(objectService, executorWrapper, plantModelService);
|
||||
|
||||
path = new Path(
|
||||
"some-path",
|
||||
new Point("some-point-1").getReference(),
|
||||
new Point("some-point-2").getReference()
|
||||
);
|
||||
given(objectService.fetchObject(Path.class, "some-path"))
|
||||
.willReturn(path);
|
||||
}
|
||||
|
||||
@Test
|
||||
void lockPath() {
|
||||
handler.updatePathLock("some-path", "true");
|
||||
|
||||
then(plantModelService).should().updatePathLock(path.getReference(), true);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"false", "flase", "some-value-that-is-not-true"})
|
||||
void unlockPathOnAnyNontrueValue(String value) {
|
||||
handler.updatePathLock("some-path", value);
|
||||
|
||||
then(plantModelService).should().updatePathLock(path.getReference(), false);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"true", "false"})
|
||||
void throwOnLockUnknownPath(String value) {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.updatePathLock("some-unknown-path", value));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.opentcs.common.peripherals.NullPeripheralCommAdapterDescription;
|
||||
import org.opentcs.components.kernel.services.PeripheralService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.LocationType;
|
||||
import org.opentcs.drivers.peripherals.PeripheralCommAdapterDescription;
|
||||
import org.opentcs.drivers.peripherals.management.PeripheralAttachmentInformation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PeripheralJobHandler}.
|
||||
*/
|
||||
class PeripheralHandlerTest {
|
||||
|
||||
private PeripheralService peripheralService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
|
||||
private PeripheralHandler handler;
|
||||
|
||||
private Location location;
|
||||
private PeripheralCommAdapterDescription adapterDescriptionNull;
|
||||
private PeripheralCommAdapterDescription adapterDescriptionMock;
|
||||
private PeripheralAttachmentInformation attachmentInfo;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
peripheralService = mock();
|
||||
executorWrapper = new KernelExecutorWrapper(Executors.newSingleThreadExecutor());
|
||||
|
||||
handler = new PeripheralHandler(peripheralService, executorWrapper);
|
||||
|
||||
location = new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
adapterDescriptionNull = new NullPeripheralCommAdapterDescription();
|
||||
adapterDescriptionMock = new MockPeripheralCommAdapterDescription();
|
||||
attachmentInfo = new PeripheralAttachmentInformation(
|
||||
location.getReference(),
|
||||
List.of(
|
||||
adapterDescriptionNull,
|
||||
adapterDescriptionMock
|
||||
),
|
||||
adapterDescriptionNull
|
||||
);
|
||||
|
||||
given(peripheralService.fetchObject(Location.class, "some-location"))
|
||||
.willReturn(location);
|
||||
given(peripheralService.fetchAttachmentInformation(location.getReference()))
|
||||
.willReturn(attachmentInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
void attachNullPeripheralAdapter() {
|
||||
handler.putPeripheralCommAdapter(
|
||||
"some-location",
|
||||
NullPeripheralCommAdapterDescription.class.getName()
|
||||
);
|
||||
|
||||
then(peripheralService)
|
||||
.should()
|
||||
.attachCommAdapter(location.getReference(), adapterDescriptionNull);
|
||||
}
|
||||
|
||||
@Test
|
||||
void attachMockPeripheralAdapter() {
|
||||
handler.putPeripheralCommAdapter(
|
||||
"some-location",
|
||||
MockPeripheralCommAdapterDescription.class.getName()
|
||||
);
|
||||
|
||||
then(peripheralService)
|
||||
.should()
|
||||
.attachCommAdapter(location.getReference(), adapterDescriptionMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnAttachAdapterForUnknownLocation() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.putPeripheralCommAdapter(
|
||||
"some-unknown-location",
|
||||
NullPeripheralCommAdapterDescription.class.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnAttachUnknownAdapter() {
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.putPeripheralCommAdapter(
|
||||
"some-location",
|
||||
"some-unknown-adapter-class-name"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void enableCommAdapter() {
|
||||
handler.putPeripheralCommAdapterEnabled("some-location", "true");
|
||||
|
||||
then(peripheralService).should().enableCommAdapter(location.getReference());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"false", "flase", "some-value-that-is-not-true"})
|
||||
void disableCommAdapterOnAnyNontrueValue(String value) {
|
||||
handler.putPeripheralCommAdapterEnabled("some-location", value);
|
||||
|
||||
then(peripheralService).should().disableCommAdapter(location.getReference());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"true ", "false"})
|
||||
void throwOnEnableUnknownLocation(String value) {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.putPeripheralCommAdapterEnabled("some-unknown-location", value));
|
||||
}
|
||||
|
||||
@Test
|
||||
void fetchAttachmentInformation() {
|
||||
assertThat(handler.getPeripheralCommAdapterAttachmentInformation("some-location"))
|
||||
.isSameAs(attachmentInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnFetchInfoForUnknownLocation() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.getPeripheralCommAdapterAttachmentInformation("some-unknown-location")
|
||||
);
|
||||
}
|
||||
|
||||
static class MockPeripheralCommAdapterDescription
|
||||
extends
|
||||
PeripheralCommAdapterDescription {
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "some-peripheral-comm-adapter";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentcs.components.kernel.services.PeripheralDispatcherService;
|
||||
import org.opentcs.components.kernel.services.PeripheralJobService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.LocationType;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.data.peripherals.PeripheralOperation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PeripheralJobDispatcherHandler}.
|
||||
*/
|
||||
class PeripheralJobDispatcherHandlerTest {
|
||||
|
||||
private PeripheralJobService jobService;
|
||||
private PeripheralDispatcherService jobDispatcherService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
|
||||
private PeripheralJobDispatcherHandler handler;
|
||||
|
||||
private Location location;
|
||||
private PeripheralJob job;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
jobService = mock();
|
||||
jobDispatcherService = mock();
|
||||
executorWrapper = new KernelExecutorWrapper(Executors.newSingleThreadExecutor());
|
||||
|
||||
handler = new PeripheralJobDispatcherHandler(
|
||||
jobService,
|
||||
jobDispatcherService,
|
||||
executorWrapper
|
||||
);
|
||||
|
||||
location = new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
job = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
given(jobService.fetchObject(Location.class, "some-location"))
|
||||
.willReturn(location);
|
||||
given(jobService.fetchObject(PeripheralJob.class, "some-job"))
|
||||
.willReturn(job);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withdrawPeripheralJobByLocation() {
|
||||
handler.withdrawPeripheralJobByLocation("some-location");
|
||||
then(jobDispatcherService).should().withdrawByLocation(location.getReference());
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnWithdrawPeripheralJobByUnknownLocation() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.withdrawPeripheralJobByLocation("some-unknown-location"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withdrawPeripheralJob() {
|
||||
handler.withdrawPeripheralJob("some-job");
|
||||
then(jobDispatcherService).should().withdrawByPeripheralJob(job.getReference());
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnWithdrawUnknownPeripheralJob() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.withdrawPeripheralJob("some-unknown-job"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.theInstance;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.opentcs.access.to.peripherals.PeripheralJobCreationTO;
|
||||
import org.opentcs.components.kernel.services.PeripheralDispatcherService;
|
||||
import org.opentcs.components.kernel.services.PeripheralJobService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.LocationType;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.data.peripherals.PeripheralOperation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetPeripheralJobResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostPeripheralJobRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PeripheralOperationDescription;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PeripheralJobHandler}.
|
||||
*/
|
||||
class PeripheralJobHandlerTest {
|
||||
|
||||
private PeripheralJobService jobService;
|
||||
private PeripheralDispatcherService jobDispatcherService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
|
||||
private PeripheralJobHandler handler;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
jobService = mock();
|
||||
jobDispatcherService = mock();
|
||||
executorWrapper = new KernelExecutorWrapper(Executors.newSingleThreadExecutor());
|
||||
|
||||
handler = new PeripheralJobHandler(
|
||||
jobService,
|
||||
jobDispatcherService,
|
||||
executorWrapper
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createPeripheralJob() {
|
||||
// Arrange
|
||||
Location location
|
||||
= new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
Vehicle vehicle = new Vehicle("some-vehicle");
|
||||
TransportOrder order = new TransportOrder("some-order", List.of());
|
||||
PeripheralJob job = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
)
|
||||
.withRelatedVehicle(vehicle.getReference())
|
||||
.withRelatedTransportOrder(order.getReference())
|
||||
.withProperty("some-prop-key", "some-prop-value");
|
||||
given(jobService.fetchObject(Location.class, "some-location"))
|
||||
.willReturn(location);
|
||||
given(jobService.fetchObject(Vehicle.class, "some-vehicle"))
|
||||
.willReturn(vehicle);
|
||||
given(jobService.fetchObject(TransportOrder.class, "some-order"))
|
||||
.willReturn(order);
|
||||
given(jobService.createPeripheralJob(any(PeripheralJobCreationTO.class)))
|
||||
.willReturn(job);
|
||||
|
||||
// Act
|
||||
PeripheralJob result = handler.createPeripheralJob(
|
||||
"some-job",
|
||||
new PostPeripheralJobRequestTO()
|
||||
.setIncompleteName(false)
|
||||
.setReservationToken("some-token")
|
||||
.setPeripheralOperation(
|
||||
new PeripheralOperationDescription()
|
||||
.setLocationName("some-location")
|
||||
.setOperation("some-operation")
|
||||
.setExecutionTrigger(PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION)
|
||||
.setCompletionRequired(true)
|
||||
)
|
||||
.setRelatedVehicle("some-vehicle")
|
||||
.setRelatedTransportOrder("some-order")
|
||||
.setProperties(List.of(new Property("some-prop-key", "some-prop-value")))
|
||||
);
|
||||
|
||||
// Assert
|
||||
assertThat(result, is(theInstance(job)));
|
||||
then(jobService).should().createPeripheralJob(any(PeripheralJobCreationTO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrievePeripheralJobsUnfiltered() {
|
||||
// Arrange
|
||||
Location location
|
||||
= new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
PeripheralJob job1 = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
PeripheralJob job2 = new PeripheralJob(
|
||||
"some-job-2",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
given(
|
||||
jobService.fetchObjects(ArgumentMatchers.<Class<PeripheralJob>>any(), any())
|
||||
)
|
||||
.willReturn(Set.of(job1, job2));
|
||||
|
||||
// Act
|
||||
List<GetPeripheralJobResponseTO> result = handler.getPeripheralJobs(null, null);
|
||||
|
||||
// Assert
|
||||
assertThat(result, hasSize(2));
|
||||
then(jobService).should().fetchObjects(ArgumentMatchers.<Class<PeripheralJob>>any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrievePeripheralJobsFilteredByRelatedVehicle() {
|
||||
// Arrange
|
||||
Location location
|
||||
= new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
PeripheralJob job1 = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
PeripheralJob job2 = new PeripheralJob(
|
||||
"some-job-2",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
Vehicle vehicle = new Vehicle("some-vehicle");
|
||||
given(jobService.fetchObject(Vehicle.class, "some-vehicle"))
|
||||
.willReturn(vehicle);
|
||||
given(
|
||||
jobService.fetchObjects(ArgumentMatchers.<Class<PeripheralJob>>any(), any())
|
||||
)
|
||||
.willReturn(Set.of(job1, job2));
|
||||
|
||||
// Act & Assert: happy path
|
||||
List<GetPeripheralJobResponseTO> result = handler.getPeripheralJobs("some-vehicle", null);
|
||||
|
||||
assertThat(result, hasSize(2));
|
||||
then(jobService).should().fetchObjects(ArgumentMatchers.<Class<PeripheralJob>>any(), any());
|
||||
|
||||
// Act & Assert: nonexistent vehicle
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.getPeripheralJobs("some-unknown-vehicle", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrievePeripheralJobsFilteredByRelatedTransportOrder() {
|
||||
// Arrange
|
||||
Location location
|
||||
= new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
PeripheralJob job1 = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
PeripheralJob job2 = new PeripheralJob(
|
||||
"some-job-2",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
TransportOrder transportOrder = new TransportOrder("some-order", List.of());
|
||||
given(jobService.fetchObject(TransportOrder.class, "some-order"))
|
||||
.willReturn(transportOrder);
|
||||
given(
|
||||
jobService.fetchObjects(ArgumentMatchers.<Class<PeripheralJob>>any(), any())
|
||||
)
|
||||
.willReturn(Set.of(job1, job2));
|
||||
|
||||
// Act & Assert: happy path
|
||||
List<GetPeripheralJobResponseTO> result = handler.getPeripheralJobs(null, "some-order");
|
||||
|
||||
assertThat(result, hasSize(2));
|
||||
then(jobService).should().fetchObjects(ArgumentMatchers.<Class<PeripheralJob>>any(), any());
|
||||
|
||||
// Act & Assert: nonexistent vehicle
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.getPeripheralJobs(null, "some-unknown-order"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrievPeripheralJobByName() {
|
||||
// Arrange
|
||||
Location location
|
||||
= new Location("some-location", new LocationType("some-location-type").getReference());
|
||||
PeripheralJob job = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
location.getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
given(jobService.fetchObject(PeripheralJob.class, "some-job"))
|
||||
.willReturn(job);
|
||||
|
||||
// Act & Assert: happy path
|
||||
GetPeripheralJobResponseTO result = handler.getPeripheralJobByName("some-job");
|
||||
assertThat(result, is(notNullValue()));
|
||||
then(jobService).should().fetchObject(PeripheralJob.class, "some-job");
|
||||
|
||||
// Act & Assert: nonexistent order
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.getPeripheralJobByName("some-unknown-order"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.opentcs.access.to.model.PlantModelCreationTO;
|
||||
import org.opentcs.components.kernel.services.PlantModelService;
|
||||
import org.opentcs.components.kernel.services.RouterService;
|
||||
import org.opentcs.data.model.Block;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.LocationType;
|
||||
import org.opentcs.data.model.Path;
|
||||
import org.opentcs.data.model.PlantModel;
|
||||
import org.opentcs.data.model.Point;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.model.visualization.VisualLayout;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PlantModelTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostTopologyUpdateRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.BlockTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.LocationTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.LocationTypeTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.PathTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.PointTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.VehicleTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.plantmodel.VisualLayoutTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PropertyTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.TripleTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.BlockConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.EnvelopeConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.LocationConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.LocationTypeConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.PathConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.PeripheralOperationConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.PointConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.PropertyConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.VehicleConverter;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.converter.VisualLayoutConverter;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PlantModelHandler}.
|
||||
*/
|
||||
class PlantModelHandlerTest {
|
||||
|
||||
private PlantModelService orderService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
private PlantModelHandler handler;
|
||||
private RouterService routerService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
orderService = mock();
|
||||
executorWrapper = new KernelExecutorWrapper(Executors.newSingleThreadExecutor());
|
||||
EnvelopeConverter envelopeConverter = new EnvelopeConverter();
|
||||
PropertyConverter propertyConverter = new PropertyConverter();
|
||||
routerService = mock();
|
||||
|
||||
handler = new PlantModelHandler(
|
||||
orderService,
|
||||
executorWrapper,
|
||||
new PointConverter(propertyConverter, envelopeConverter),
|
||||
new PathConverter(
|
||||
propertyConverter,
|
||||
new PeripheralOperationConverter(),
|
||||
envelopeConverter
|
||||
),
|
||||
new LocationTypeConverter(propertyConverter),
|
||||
new LocationConverter(propertyConverter),
|
||||
new BlockConverter(propertyConverter),
|
||||
new VehicleConverter(propertyConverter),
|
||||
new VisualLayoutConverter(propertyConverter),
|
||||
propertyConverter,
|
||||
routerService
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void putPlantModel() {
|
||||
// Act
|
||||
handler.putPlantModel(
|
||||
new PlantModelTO("name")
|
||||
.setPoints(
|
||||
List.of(
|
||||
new PointTO("some-point"),
|
||||
new PointTO("some-other-point")
|
||||
)
|
||||
)
|
||||
.setPaths(
|
||||
List.of(
|
||||
new PathTO("some-path", "src-point", "dest-point")
|
||||
)
|
||||
)
|
||||
.setLocationTypes(
|
||||
List.of(
|
||||
new LocationTypeTO("some-loc-type"),
|
||||
new LocationTypeTO("some-other-loc-type")
|
||||
)
|
||||
)
|
||||
.setLocations(
|
||||
List.of(
|
||||
new LocationTO(
|
||||
"some-location",
|
||||
"some-loc-type",
|
||||
new TripleTO(1, 2, 3)
|
||||
),
|
||||
new LocationTO(
|
||||
"some-other-location",
|
||||
"some-other-loc-type",
|
||||
new TripleTO(4, 5, 6)
|
||||
)
|
||||
)
|
||||
)
|
||||
.setBlocks(
|
||||
List.of(
|
||||
new BlockTO("some-block")
|
||||
)
|
||||
)
|
||||
.setVehicles(
|
||||
List.of(
|
||||
new VehicleTO("some-vehicle"),
|
||||
new VehicleTO("some-other-vehicle")
|
||||
)
|
||||
)
|
||||
.setVisualLayout(new VisualLayoutTO("some-layout"))
|
||||
.setProperties(
|
||||
List.of(
|
||||
new PropertyTO("some-key", "some-value")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Assert
|
||||
ArgumentCaptor<PlantModelCreationTO> captor
|
||||
= ArgumentCaptor.forClass(PlantModelCreationTO.class);
|
||||
then(orderService).should().createPlantModel(captor.capture());
|
||||
assertThat(captor.getValue().getPoints()).hasSize(2);
|
||||
assertThat(captor.getValue().getPaths()).hasSize(1);
|
||||
assertThat(captor.getValue().getLocationTypes()).hasSize(2);
|
||||
assertThat(captor.getValue().getLocations()).hasSize(2);
|
||||
assertThat(captor.getValue().getBlocks()).hasSize(1);
|
||||
assertThat(captor.getValue().getVehicles()).hasSize(2);
|
||||
assertThat(captor.getValue().getVisualLayout()).isNotNull();
|
||||
assertThat(captor.getValue().getProperties()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPlantModel() {
|
||||
// Arrange
|
||||
PlantModel plantModel
|
||||
= new PlantModel("some-plant-model")
|
||||
.withPoints(
|
||||
Set.of(
|
||||
new Point("some-point"),
|
||||
new Point("some-other-point")
|
||||
)
|
||||
)
|
||||
.withPaths(
|
||||
Set.of(
|
||||
new Path(
|
||||
"some-path",
|
||||
new Point("src-point").getReference(),
|
||||
new Point("dest-point").getReference()
|
||||
)
|
||||
)
|
||||
)
|
||||
.withLocationTypes(
|
||||
Set.of(
|
||||
new LocationType("some-loc-type"),
|
||||
new LocationType("some-other-loc-type")
|
||||
)
|
||||
)
|
||||
.withLocations(
|
||||
Set.of(
|
||||
new Location(
|
||||
"some-location",
|
||||
new LocationType("loc-type").getReference()
|
||||
),
|
||||
new Location(
|
||||
"some-other-location",
|
||||
new LocationType("loc-other-type").getReference()
|
||||
)
|
||||
)
|
||||
)
|
||||
.withBlocks(
|
||||
Set.of(
|
||||
new Block("some-block")
|
||||
)
|
||||
)
|
||||
.withVehicles(
|
||||
Set.of(
|
||||
new Vehicle("some-vehicle"),
|
||||
new Vehicle("some-other-vehicle")
|
||||
)
|
||||
)
|
||||
.withVisualLayout(new VisualLayout("some-layout"))
|
||||
.withProperties(
|
||||
Map.of("some-key", "some-value")
|
||||
);
|
||||
given(orderService.getPlantModel())
|
||||
.willReturn(plantModel);
|
||||
|
||||
// Act
|
||||
PlantModelTO to = handler.getPlantModel();
|
||||
|
||||
// Assert
|
||||
then(orderService).should().getPlantModel();
|
||||
assertThat(to)
|
||||
.returns("some-plant-model", PlantModelTO::getName);
|
||||
assertThat(to.getPoints()).hasSize(2);
|
||||
assertThat(to.getPaths()).hasSize(1);
|
||||
assertThat(to.getLocationTypes()).hasSize(2);
|
||||
assertThat(to.getLocations()).hasSize(2);
|
||||
assertThat(to.getBlocks()).hasSize(1);
|
||||
assertThat(to.getVehicles()).hasSize(2);
|
||||
assertThat(to.getVisualLayout()).isNotNull();
|
||||
assertThat(to.getProperties()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void requestTopologyUpdate() {
|
||||
handler.requestTopologyUpdate(
|
||||
new PostTopologyUpdateRequestTO(List.of())
|
||||
);
|
||||
then(routerService).should().updateRoutingTopology(Set.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
void requestTopologyUpdateWithPath() {
|
||||
Path path1 = new Path(
|
||||
"path1",
|
||||
new Point("source").getReference(),
|
||||
new Point("dest").getReference()
|
||||
);
|
||||
|
||||
given(orderService.fetchObject(Path.class, "path1")).willReturn(path1);
|
||||
|
||||
handler.requestTopologyUpdate(
|
||||
new PostTopologyUpdateRequestTO(List.of("path1"))
|
||||
);
|
||||
then(routerService).should().updateRoutingTopology(Set.of(path1.getReference()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentcs.access.Kernel;
|
||||
import org.opentcs.access.KernelStateTransitionEvent;
|
||||
import org.opentcs.data.TCSObjectEvent;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.LocationType;
|
||||
import org.opentcs.data.model.Point;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.data.peripherals.PeripheralOperation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.ServiceWebApiConfiguration;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetEventsResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.OrderStatusMessage;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.PeripheralJobStatusMessage;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.VehicleStatusMessage;
|
||||
import org.opentcs.util.event.EventSource;
|
||||
import org.opentcs.util.event.SimpleEventBus;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link StatusEventDispatcher}.
|
||||
*/
|
||||
class StatusEventDispatcherTest {
|
||||
|
||||
private ServiceWebApiConfiguration configuration;
|
||||
private EventSource eventSource;
|
||||
private StatusEventDispatcher statusEventDispatcher;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
configuration = mock(ServiceWebApiConfiguration.class);
|
||||
eventSource = new SimpleEventBus();
|
||||
statusEventDispatcher = new StatusEventDispatcher(configuration, eventSource);
|
||||
|
||||
given(configuration.statusEventsCapacity())
|
||||
.willReturn(10);
|
||||
|
||||
statusEventDispatcher.initialize();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
statusEventDispatcher.terminate();
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnEmptyListInitially() {
|
||||
GetEventsResponseTO result = statusEventDispatcher.fetchEvents(0, Long.MAX_VALUE, 1);
|
||||
|
||||
assertThat(result.getStatusMessages()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void suppressEventCollectionInModellingMode() {
|
||||
// Arrange
|
||||
statusEventDispatcher.onEvent(
|
||||
new KernelStateTransitionEvent(Kernel.State.MODELLING, Kernel.State.OPERATING, true)
|
||||
);
|
||||
statusEventDispatcher.onEvent(
|
||||
new KernelStateTransitionEvent(Kernel.State.OPERATING, Kernel.State.MODELLING, true)
|
||||
);
|
||||
|
||||
TransportOrder order = new TransportOrder("some-order", List.of());
|
||||
for (int i = 0; i < 5; i++) {
|
||||
statusEventDispatcher.onEvent(
|
||||
new TCSObjectEvent(order, order, TCSObjectEvent.Type.OBJECT_MODIFIED)
|
||||
);
|
||||
}
|
||||
|
||||
// Act
|
||||
GetEventsResponseTO result = statusEventDispatcher.fetchEvents(0, Long.MAX_VALUE, 1);
|
||||
|
||||
// Assert
|
||||
assertThat(result.getStatusMessages()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void respectConfiguredCapacity() {
|
||||
// Arrange
|
||||
statusEventDispatcher.onEvent(
|
||||
new KernelStateTransitionEvent(Kernel.State.MODELLING, Kernel.State.OPERATING, true)
|
||||
);
|
||||
|
||||
TransportOrder order = new TransportOrder("some-order", List.of());
|
||||
for (int i = 0; i < 20; i++) {
|
||||
statusEventDispatcher.onEvent(
|
||||
new TCSObjectEvent(order, order, TCSObjectEvent.Type.OBJECT_MODIFIED)
|
||||
);
|
||||
}
|
||||
|
||||
// Act
|
||||
GetEventsResponseTO result = statusEventDispatcher.fetchEvents(0, Long.MAX_VALUE, 1);
|
||||
|
||||
// Assert
|
||||
assertThat(result.getStatusMessages()).hasSize(10);
|
||||
assertThat(result.getStatusMessages().get(9).getSequenceNumber()).isEqualTo(19);
|
||||
}
|
||||
|
||||
@Test
|
||||
void processEventsForRelatedObjects() {
|
||||
// Arrange
|
||||
statusEventDispatcher.onEvent(
|
||||
new KernelStateTransitionEvent(Kernel.State.MODELLING, Kernel.State.OPERATING, true)
|
||||
);
|
||||
|
||||
TransportOrder order = new TransportOrder("some-order", List.of());
|
||||
Vehicle vehicle = new Vehicle("some-vehicle");
|
||||
PeripheralJob job = new PeripheralJob(
|
||||
"some-job",
|
||||
"some-token",
|
||||
new PeripheralOperation(
|
||||
new Location(
|
||||
"some-location",
|
||||
new LocationType("some-location-type").getReference()
|
||||
).getReference(),
|
||||
"some-operation",
|
||||
PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION,
|
||||
true
|
||||
)
|
||||
);
|
||||
Point point = new Point("some-point");
|
||||
|
||||
statusEventDispatcher.onEvent(
|
||||
new TCSObjectEvent(order, order, TCSObjectEvent.Type.OBJECT_MODIFIED)
|
||||
);
|
||||
statusEventDispatcher.onEvent(
|
||||
new TCSObjectEvent(vehicle, vehicle, TCSObjectEvent.Type.OBJECT_MODIFIED)
|
||||
);
|
||||
statusEventDispatcher.onEvent(
|
||||
new TCSObjectEvent(job, job, TCSObjectEvent.Type.OBJECT_MODIFIED)
|
||||
);
|
||||
// Events for other object types, e.g. points, should be ignored.
|
||||
statusEventDispatcher.onEvent(
|
||||
new TCSObjectEvent(point, point, TCSObjectEvent.Type.OBJECT_MODIFIED)
|
||||
);
|
||||
|
||||
// Act
|
||||
GetEventsResponseTO list = statusEventDispatcher.fetchEvents(0, Long.MAX_VALUE, 1);
|
||||
|
||||
// Assert
|
||||
assertThat(list.getStatusMessages()).hasSize(3);
|
||||
assertThat(list.getStatusMessages().get(0))
|
||||
.isInstanceOf(OrderStatusMessage.class)
|
||||
.matches(msg -> msg.getSequenceNumber() == 0);
|
||||
assertThat(list.getStatusMessages().get(1))
|
||||
.isInstanceOf(VehicleStatusMessage.class)
|
||||
.matches(msg -> msg.getSequenceNumber() == 1);
|
||||
assertThat(list.getStatusMessages().get(2))
|
||||
.isInstanceOf(PeripheralJobStatusMessage.class)
|
||||
.matches(msg -> msg.getSequenceNumber() == 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentcs.components.kernel.services.DispatcherService;
|
||||
import org.opentcs.components.kernel.services.VehicleService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.ReroutingType;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TransportOrderDispatcherHandler}.
|
||||
*/
|
||||
class TransportOrderDispatcherHandlerTest {
|
||||
|
||||
private VehicleService vehicleService;
|
||||
private DispatcherService dispatcherService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
private TransportOrderDispatcherHandler handler;
|
||||
|
||||
private Vehicle vehicle;
|
||||
private TransportOrder order;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
vehicleService = mock();
|
||||
dispatcherService = mock();
|
||||
executorWrapper = new KernelExecutorWrapper(Executors.newSingleThreadExecutor());
|
||||
|
||||
handler = new TransportOrderDispatcherHandler(
|
||||
vehicleService,
|
||||
dispatcherService,
|
||||
executorWrapper
|
||||
);
|
||||
|
||||
vehicle = new Vehicle("some-vehicle");
|
||||
order = new TransportOrder("some-order", List.of())
|
||||
.withProcessingVehicle(vehicle.getReference());
|
||||
|
||||
given(vehicleService.fetchObject(Vehicle.class, "some-vehicle"))
|
||||
.willReturn(vehicle);
|
||||
given(vehicleService.fetchObject(TransportOrder.class, "some-order"))
|
||||
.willReturn(order);
|
||||
}
|
||||
|
||||
@Test
|
||||
void triggerDispatcher() {
|
||||
handler.triggerDispatcher();
|
||||
|
||||
then(dispatcherService).should().dispatch();
|
||||
}
|
||||
|
||||
@Test
|
||||
void tryImmediateAssignmentUsingKnownOrder() {
|
||||
handler.tryImmediateAssignment("some-order");
|
||||
|
||||
then(dispatcherService).should().assignNow(order.getReference());
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnImmediateAssignmentUsingUnknownOrderName() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.tryImmediateAssignment("some-unknown-order"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withdrawByTransportOrderRegularly() {
|
||||
handler.withdrawByTransportOrder("some-order", false, false);
|
||||
|
||||
then(dispatcherService).should().withdrawByTransportOrder(order.getReference(), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withdrawByTransportOrderImmediately() {
|
||||
handler.withdrawByTransportOrder("some-order", true, false);
|
||||
|
||||
then(dispatcherService).should().withdrawByTransportOrder(order.getReference(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withdrawByTransportOrderAlsoDisablingVehicle() {
|
||||
handler.withdrawByTransportOrder("some-order", false, true);
|
||||
|
||||
then(vehicleService)
|
||||
.should()
|
||||
.updateVehicleIntegrationLevel(
|
||||
vehicle.getReference(),
|
||||
Vehicle.IntegrationLevel.TO_BE_RESPECTED
|
||||
);
|
||||
then(dispatcherService).should().withdrawByTransportOrder(order.getReference(), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnWithdrawUsingUnknownOrderName() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.withdrawByTransportOrder("some-unknown-order", false, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withdrawByVehicleRegularly() {
|
||||
handler.withdrawByVehicle("some-vehicle", false, false);
|
||||
|
||||
then(dispatcherService).should().withdrawByVehicle(vehicle.getReference(), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withdrawByVehicleImmediately() {
|
||||
handler.withdrawByVehicle("some-vehicle", true, false);
|
||||
|
||||
then(dispatcherService).should().withdrawByVehicle(vehicle.getReference(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withdrawByVehicleAlsoDisablingVehicle() {
|
||||
handler.withdrawByVehicle("some-vehicle", false, true);
|
||||
|
||||
then(vehicleService)
|
||||
.should()
|
||||
.updateVehicleIntegrationLevel(
|
||||
vehicle.getReference(),
|
||||
Vehicle.IntegrationLevel.TO_BE_RESPECTED
|
||||
);
|
||||
then(dispatcherService).should().withdrawByVehicle(vehicle.getReference(), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnWithdrawUsingUnknownVehicleName() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.withdrawByVehicle("some-unknown-vehicle", false, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rerouteRegularly() {
|
||||
handler.reroute("some-vehicle", false);
|
||||
|
||||
then(dispatcherService).should().reroute(vehicle.getReference(), ReroutingType.REGULAR);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rerouteForcibly() {
|
||||
handler.reroute("some-vehicle", true);
|
||||
|
||||
then(dispatcherService).should().reroute(vehicle.getReference(), ReroutingType.FORCED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnRerouteUsingUnknownVehicleName() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.reroute("some-unknown-vehicle", false));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.from;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.theInstance;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.opentcs.access.to.order.DestinationCreationTO;
|
||||
import org.opentcs.access.to.order.OrderSequenceCreationTO;
|
||||
import org.opentcs.access.to.order.TransportOrderCreationTO;
|
||||
import org.opentcs.components.kernel.services.TransportOrderService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.OrderSequence;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetOrderSequenceResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetTransportOrderResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostOrderSequenceRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostTransportOrderRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.posttransportorder.Destination;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TransportOrderHandler}.
|
||||
*/
|
||||
class TransportOrderHandlerTest {
|
||||
|
||||
private TransportOrderService orderService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
private TransportOrderHandler handler;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
orderService = mock();
|
||||
executorWrapper = new KernelExecutorWrapper(Executors.newSingleThreadExecutor());
|
||||
|
||||
handler = new TransportOrderHandler(orderService, executorWrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createTransportOrder() {
|
||||
// Arrange
|
||||
TransportOrder transportOrder = new TransportOrder("some-order", List.of());
|
||||
given(orderService.createTransportOrder(any(TransportOrderCreationTO.class)))
|
||||
.willReturn(transportOrder);
|
||||
|
||||
// Act
|
||||
TransportOrder result = handler.createOrder(
|
||||
"some-order",
|
||||
new PostTransportOrderRequestTO(
|
||||
false,
|
||||
false,
|
||||
Instant.MAX,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
List.of(
|
||||
new Destination(
|
||||
"some-location",
|
||||
"some-operation",
|
||||
List.of(
|
||||
new Property("some-dest-key", "some-dest-value")
|
||||
)
|
||||
)
|
||||
),
|
||||
List.of(
|
||||
new Property("some-key", "some-value")
|
||||
),
|
||||
null
|
||||
)
|
||||
);
|
||||
|
||||
// Assert
|
||||
assertThat(result, is(theInstance(transportOrder)));
|
||||
|
||||
ArgumentCaptor<TransportOrderCreationTO> captor
|
||||
= ArgumentCaptor.forClass(TransportOrderCreationTO.class);
|
||||
then(orderService).should().createTransportOrder(captor.capture());
|
||||
assertThat(captor.getValue())
|
||||
.returns("some-order", from(TransportOrderCreationTO::getName))
|
||||
.returns(false, from(TransportOrderCreationTO::hasIncompleteName))
|
||||
.returns(false, from(TransportOrderCreationTO::isDispensable))
|
||||
.returns(Instant.MAX, from(TransportOrderCreationTO::getDeadline))
|
||||
.returns(null, from(TransportOrderCreationTO::getWrappingSequence))
|
||||
.returns(null, from(TransportOrderCreationTO::getPeripheralReservationToken))
|
||||
.returns(Set.of(), from(TransportOrderCreationTO::getDependencyNames))
|
||||
.returns(Map.of("some-key", "some-value"), from(TransportOrderCreationTO::getProperties));
|
||||
assertThat(captor.getValue().getDestinations()).hasSize(1);
|
||||
assertThat(captor.getValue().getDestinations().get(0))
|
||||
.returns("some-location", from(DestinationCreationTO::getDestLocationName))
|
||||
.returns("some-operation", from(DestinationCreationTO::getDestOperation))
|
||||
.returns(
|
||||
Map.of("some-dest-key", "some-dest-value"),
|
||||
from(DestinationCreationTO::getProperties)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setTransportOrderIntendedVehicle() {
|
||||
// Arrange
|
||||
TransportOrder transportOrder = new TransportOrder("some-order", List.of());
|
||||
Vehicle vehicle = new Vehicle("some-vehicle");
|
||||
|
||||
given(orderService.fetchObject(TransportOrder.class, "some-order"))
|
||||
.willReturn(transportOrder);
|
||||
given(orderService.fetchObject(Vehicle.class, "some-vehicle"))
|
||||
.willReturn(vehicle);
|
||||
|
||||
// Act & Assert: set to vehicle
|
||||
handler.updateTransportOrderIntendedVehicle("some-order", "some-vehicle");
|
||||
then(orderService).should().updateTransportOrderIntendedVehicle(
|
||||
transportOrder.getReference(),
|
||||
vehicle.getReference()
|
||||
);
|
||||
|
||||
// Act & Assert: set to null
|
||||
handler.updateTransportOrderIntendedVehicle("some-order", null);
|
||||
then(orderService).should().updateTransportOrderIntendedVehicle(
|
||||
transportOrder.getReference(),
|
||||
null
|
||||
);
|
||||
|
||||
// Act & Assert: nonexistent transport order
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.updateTransportOrderIntendedVehicle("some-unknown-order", null));
|
||||
|
||||
// Act & Assert: nonexistent vehicle
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.updateTransportOrderIntendedVehicle("some-order", "some-unknown-vehicle")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveTransportOrdersUnfiltered() {
|
||||
// Arrange
|
||||
TransportOrder transportOrder1 = new TransportOrder("some-order", List.of());
|
||||
TransportOrder transportOrder2 = new TransportOrder("some-order-2", List.of());
|
||||
|
||||
given(
|
||||
orderService.fetchObjects(ArgumentMatchers.<Class<TransportOrder>>any(), any())
|
||||
)
|
||||
.willReturn(Set.of(transportOrder1, transportOrder2));
|
||||
|
||||
// Act
|
||||
List<GetTransportOrderResponseTO> result = handler.getTransportOrders(null);
|
||||
|
||||
// Assert
|
||||
assertThat(result, hasSize(2));
|
||||
then(orderService).should().fetchObjects(ArgumentMatchers.<Class<TransportOrder>>any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveTransportOrdersFilteredByIntendedVehicle() {
|
||||
// Arrange
|
||||
TransportOrder transportOrder1 = new TransportOrder("some-order", List.of());
|
||||
TransportOrder transportOrder2 = new TransportOrder("some-order-2", List.of());
|
||||
Vehicle vehicle = new Vehicle("some-vehicle");
|
||||
|
||||
given(
|
||||
orderService.fetchObject(Vehicle.class, "some-vehicle")
|
||||
)
|
||||
.willReturn(vehicle);
|
||||
given(
|
||||
orderService.fetchObjects(ArgumentMatchers.<Class<TransportOrder>>any(), any())
|
||||
)
|
||||
.willReturn(Set.of(transportOrder1, transportOrder2));
|
||||
|
||||
// Act & Assert: happy path
|
||||
List<GetTransportOrderResponseTO> result = handler.getTransportOrders("some-vehicle");
|
||||
assertThat(result, hasSize(2));
|
||||
then(orderService).should().fetchObjects(ArgumentMatchers.<Class<TransportOrder>>any(), any());
|
||||
|
||||
// Act & Assert: nonexistent vehicle
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.getTransportOrders("some-other-vehicle"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveTransportOrderByName() {
|
||||
// Arrange
|
||||
TransportOrder transportOrder = new TransportOrder("some-order", List.of());
|
||||
|
||||
given(
|
||||
orderService.fetchObject(TransportOrder.class, "some-order")
|
||||
)
|
||||
.willReturn(transportOrder);
|
||||
|
||||
// Act & Assert: happy path
|
||||
GetTransportOrderResponseTO result = handler.getTransportOrderByName("some-order");
|
||||
assertThat(result, is(notNullValue()));
|
||||
then(orderService).should().fetchObject(TransportOrder.class, "some-order");
|
||||
|
||||
// Act & Assert: nonexistent order
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.getTransportOrderByName("some-other-order"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createOrderSequence() {
|
||||
// Arrange
|
||||
OrderSequence orderSequence = new OrderSequence("some-sequence");
|
||||
given(orderService.createOrderSequence(any(OrderSequenceCreationTO.class)))
|
||||
.willReturn(orderSequence);
|
||||
|
||||
// Act
|
||||
OrderSequence result = handler.createOrderSequence(
|
||||
"some-sequence",
|
||||
new PostOrderSequenceRequestTO()
|
||||
.setIncompleteName(false)
|
||||
.setFailureFatal(false)
|
||||
.setIntendedVehicle(null)
|
||||
.setType("some-type")
|
||||
.setProperties(
|
||||
List.of(
|
||||
new Property("some-key", "some-value")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Assert
|
||||
assertThat(result, is(theInstance(orderSequence)));
|
||||
|
||||
ArgumentCaptor<OrderSequenceCreationTO> captor
|
||||
= ArgumentCaptor.forClass(OrderSequenceCreationTO.class);
|
||||
then(orderService).should().createOrderSequence(captor.capture());
|
||||
assertThat(captor.getValue())
|
||||
.returns(false, from(OrderSequenceCreationTO::hasIncompleteName))
|
||||
.returns(null, from(OrderSequenceCreationTO::getIntendedVehicleName))
|
||||
.returns(false, from(OrderSequenceCreationTO::isFailureFatal))
|
||||
.returns("some-type", from(OrderSequenceCreationTO::getType))
|
||||
.returns(
|
||||
Map.of("some-key", "some-value"),
|
||||
from(OrderSequenceCreationTO::getProperties)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setOrderSequenceComplete() {
|
||||
// Arrange
|
||||
OrderSequence orderSequence = new OrderSequence("some-sequence");
|
||||
|
||||
given(orderService.fetchObject(OrderSequence.class, "some-sequence"))
|
||||
.willReturn(orderSequence);
|
||||
|
||||
// Act & Assert: happy path
|
||||
handler.putOrderSequenceComplete("some-sequence");
|
||||
then(orderService).should().markOrderSequenceComplete(orderSequence.getReference());
|
||||
|
||||
// Act & Assert: nonexistent order sequence
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.putOrderSequenceComplete("some-other-sequence"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveOrderSequencesUnfiltered() {
|
||||
// Arrange
|
||||
OrderSequence sequence1 = new OrderSequence("some-sequence");
|
||||
OrderSequence sequence2 = new OrderSequence("some-sequence-2");
|
||||
|
||||
given(
|
||||
orderService.fetchObjects(ArgumentMatchers.<Class<OrderSequence>>any(), any())
|
||||
)
|
||||
.willReturn(Set.of(sequence1, sequence2));
|
||||
|
||||
// Act
|
||||
List<GetOrderSequenceResponseTO> result = handler.getOrderSequences(null);
|
||||
|
||||
// Assert
|
||||
assertThat(result, hasSize(2));
|
||||
then(orderService).should().fetchObjects(ArgumentMatchers.<Class<OrderSequence>>any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveOrderSequencesFilteredByIntendedVehicle() {
|
||||
// Arrange
|
||||
OrderSequence sequence1 = new OrderSequence("some-sequence");
|
||||
OrderSequence sequence2 = new OrderSequence("some-sequence-2");
|
||||
Vehicle vehicle = new Vehicle("some-vehicle");
|
||||
|
||||
given(
|
||||
orderService.fetchObject(Vehicle.class, "some-vehicle")
|
||||
)
|
||||
.willReturn(vehicle);
|
||||
given(
|
||||
orderService.fetchObjects(ArgumentMatchers.<Class<OrderSequence>>any(), any())
|
||||
)
|
||||
.willReturn(Set.of(sequence1, sequence2));
|
||||
|
||||
// Act & Assert: happy path
|
||||
List<GetOrderSequenceResponseTO> result = handler.getOrderSequences("some-vehicle");
|
||||
assertThat(result, hasSize(2));
|
||||
then(orderService).should().fetchObjects(ArgumentMatchers.<Class<OrderSequence>>any(), any());
|
||||
|
||||
// Act & Assert: nonexistent vehicle
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.getOrderSequences("some-other-vehicle"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveOrderSequenceByName() {
|
||||
// Arrange
|
||||
OrderSequence orderSequence = new OrderSequence("some-sequence");
|
||||
|
||||
given(
|
||||
orderService.fetchObject(OrderSequence.class, "some-sequence")
|
||||
)
|
||||
.willReturn(orderSequence);
|
||||
|
||||
// Act & Assert: happy path
|
||||
GetOrderSequenceResponseTO result = handler.getOrderSequenceByName("some-sequence");
|
||||
assertThat(result, is(notNullValue()));
|
||||
then(orderService).should().fetchObject(OrderSequence.class, "some-sequence");
|
||||
|
||||
// Act & Assert: nonexistent order
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.getOrderSequenceByName("some-other-sequence"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,470 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.opentcs.components.kernel.services.RouterService;
|
||||
import org.opentcs.components.kernel.services.VehicleService;
|
||||
import org.opentcs.data.ObjectUnknownException;
|
||||
import org.opentcs.data.model.Location;
|
||||
import org.opentcs.data.model.LocationType;
|
||||
import org.opentcs.data.model.Path;
|
||||
import org.opentcs.data.model.Point;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapterDescription;
|
||||
import org.opentcs.drivers.vehicle.management.VehicleAttachmentInformation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.KernelExecutorWrapper;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.GetVehicleResponseTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PostVehicleRoutesRequestTO;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.PutVehicleAllowedOrderTypesTO;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link VehicleHandler}.
|
||||
*/
|
||||
class VehicleHandlerTest {
|
||||
|
||||
private VehicleService vehicleService;
|
||||
private RouterService routerService;
|
||||
private KernelExecutorWrapper executorWrapper;
|
||||
|
||||
private VehicleHandler handler;
|
||||
|
||||
private Vehicle vehicle;
|
||||
private VehicleCommAdapterDescription adapterDescriptionMock;
|
||||
private VehicleAttachmentInformation attachmentInfo;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
vehicleService = mock();
|
||||
routerService = mock();
|
||||
executorWrapper = new KernelExecutorWrapper(Executors.newSingleThreadExecutor());
|
||||
|
||||
handler = new VehicleHandler(vehicleService, routerService, executorWrapper);
|
||||
|
||||
vehicle = new Vehicle("some-vehicle");
|
||||
adapterDescriptionMock = new MockVehicleCommAdapterDescription();
|
||||
|
||||
attachmentInfo = new VehicleAttachmentInformation(
|
||||
vehicle.getReference(),
|
||||
List.of(adapterDescriptionMock),
|
||||
adapterDescriptionMock
|
||||
);
|
||||
|
||||
given(vehicleService.fetchObject(Vehicle.class, "some-vehicle"))
|
||||
.willReturn(vehicle);
|
||||
given(vehicleService.fetchAttachmentInformation(vehicle.getReference()))
|
||||
.willReturn(attachmentInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
void attachMockVehicleAdapter() {
|
||||
// Act
|
||||
handler.putVehicleCommAdapter(
|
||||
"some-vehicle",
|
||||
MockVehicleCommAdapterDescription.class.getName()
|
||||
);
|
||||
|
||||
// Assert
|
||||
then(vehicleService)
|
||||
.should()
|
||||
.attachCommAdapter(vehicle.getReference(), adapterDescriptionMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnAttachAdapterForUnknownVehicle() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.putVehicleCommAdapter(
|
||||
"some-unknown-vehicle",
|
||||
MockVehicleCommAdapterDescription.class.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnAttachUnknownAdapter() {
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.putVehicleCommAdapter(
|
||||
"some-vehicle",
|
||||
"some-unknown-adapter-class-name"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void enableCommAdapter() {
|
||||
handler.putVehicleCommAdapterEnabled("some-vehicle", "true");
|
||||
|
||||
then(vehicleService).should().enableCommAdapter(vehicle.getReference());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"false", "flase", "some-value-that-is-not-true"})
|
||||
void disableCommAdapterOnAnyNontrueValue(String value) {
|
||||
handler.putVehicleCommAdapterEnabled("some-vehicle", value);
|
||||
|
||||
then(vehicleService).should().disableCommAdapter(vehicle.getReference());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"true ", "false"})
|
||||
void throwOnEnableUnknownVehicle(String value) {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.putVehicleCommAdapterEnabled("some-unknown-vehicle", value));
|
||||
}
|
||||
|
||||
@Test
|
||||
void fetchAttachmentInformation() {
|
||||
assertThat(handler.getVehicleCommAdapterAttachmentInformation("some-vehicle"))
|
||||
.isSameAs(attachmentInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnFetchInfoForUnknownLocation() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.getVehicleCommAdapterAttachmentInformation("some-unknown-vehicle")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(Vehicle.ProcState.class)
|
||||
void retrieveVehiclesByProcState(Vehicle.ProcState procState) {
|
||||
// Arrange
|
||||
Vehicle vehicleWithProcState = vehicle.withProcState(procState);
|
||||
given(vehicleService.fetchObjects(ArgumentMatchers.<Class<Vehicle>>any(), any()))
|
||||
.willReturn(Set.of(vehicleWithProcState));
|
||||
|
||||
// Act & Assert
|
||||
List<GetVehicleResponseTO> result = handler.getVehiclesState(procState.name());
|
||||
MatcherAssert.assertThat(result, hasSize(1));
|
||||
then(vehicleService).should().fetchObjects(ArgumentMatchers.<Class<Vehicle>>any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnRetrieveVehiclesForUnknownProcState() {
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> handler.getVehiclesState("some-unknown-proc-state"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveVehicleByName() {
|
||||
// Act & Assert: happy path
|
||||
GetVehicleResponseTO result = handler.getVehicleStateByName("some-vehicle");
|
||||
MatcherAssert.assertThat(result, is(notNullValue()));
|
||||
then(vehicleService).should().fetchObject(Vehicle.class, "some-vehicle");
|
||||
|
||||
// Act & Assert: nonexistent vehicle
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.getVehicleStateByName("some-other-vehicle"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(Vehicle.IntegrationLevel.class)
|
||||
void updateVehicleIntegrationLevel(Vehicle.IntegrationLevel integrationLevel) {
|
||||
handler.putVehicleIntegrationLevel("some-vehicle", integrationLevel.name());
|
||||
then(vehicleService)
|
||||
.should()
|
||||
.updateVehicleIntegrationLevel(vehicle.getReference(), integrationLevel);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnUpdateIntegrationLevelForUnknownVehicleOrIntegrationLevel() {
|
||||
// Act & Assert: nonexistent vehicle
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.putVehicleIntegrationLevel(
|
||||
"some-unknown-vehicle",
|
||||
"TO_BE_UTILIZED"
|
||||
)
|
||||
);
|
||||
|
||||
// Act & Assert: unknown integration level
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.putVehicleIntegrationLevel(
|
||||
"some-vehicle",
|
||||
"some-unknown-integration-level"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void pauseVehicle() {
|
||||
handler.putVehiclePaused("some-vehicle", "true");
|
||||
|
||||
then(vehicleService).should().updateVehiclePaused(vehicle.getReference(), true);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"false", "flase", "some-value-that-is-not-true"})
|
||||
void unpauseVehicleOnAnyNontrueValue(String value) {
|
||||
handler.putVehiclePaused("some-vehicle", value);
|
||||
|
||||
then(vehicleService).should().updateVehiclePaused(vehicle.getReference(), false);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"true ", "false"})
|
||||
void throwOnPauseUnknownVehicle(String value) {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.putVehiclePaused("some-unknown-vehicle", value));
|
||||
}
|
||||
|
||||
@Test
|
||||
void setVehicleEnvelopeKey() {
|
||||
handler.putVehicleEnvelopeKey("some-vehicle", "some-key");
|
||||
|
||||
then(vehicleService).should().updateVehicleEnvelopeKey(vehicle.getReference(), "some-key");
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullVehicleEnvelopeKey() {
|
||||
handler.putVehicleEnvelopeKey("some-vehicle", null);
|
||||
|
||||
then(vehicleService).should().updateVehicleEnvelopeKey(vehicle.getReference(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnSetEnvelopeUnknownVehicle() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(() -> handler.putVehicleEnvelopeKey("some-unknown-vehicle", "some-key"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateVehicleAllowedOrderTypes() {
|
||||
// Act
|
||||
handler.putVehicleAllowedOrderTypes(
|
||||
"some-vehicle",
|
||||
new PutVehicleAllowedOrderTypesTO(List.of("some-order-type", "some-other-order-type"))
|
||||
);
|
||||
|
||||
// Assert
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<Set<String>> captor = ArgumentCaptor.forClass(Set.class);
|
||||
then(vehicleService)
|
||||
.should()
|
||||
.updateVehicleAllowedOrderTypes(eq(vehicle.getReference()), captor.capture());
|
||||
assertThat(captor.getValue())
|
||||
.hasSize(2)
|
||||
.contains("some-order-type", "some-other-order-type");
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnUpdateAllowedOrderTypesForUnknownVehicle() {
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.putVehicleAllowedOrderTypes(
|
||||
"some-unknown-vehicle",
|
||||
new PutVehicleAllowedOrderTypesTO(List.of())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveVehicleRoutesForCurrentPosition() {
|
||||
// Arrange
|
||||
Point vehiclePosition = new Point("some-point");
|
||||
Point destinationPoint1 = new Point("some-destination-point");
|
||||
Point destinationPoint2 = new Point("some-destination-point-2");
|
||||
Vehicle vehicleWithPosition = vehicle.withCurrentPosition(vehiclePosition.getReference());
|
||||
given(vehicleService.fetchObject(Point.class, "some-point"))
|
||||
.willReturn(vehiclePosition);
|
||||
given(vehicleService.fetchObject(Point.class, "some-destination-point"))
|
||||
.willReturn(destinationPoint1);
|
||||
given(vehicleService.fetchObject(Point.class, "some-destination-point-2"))
|
||||
.willReturn(destinationPoint2);
|
||||
given(vehicleService.fetchObject(Vehicle.class, "some-vehicle"))
|
||||
.willReturn(vehicleWithPosition);
|
||||
|
||||
// Act & Assert: happy path
|
||||
handler.getVehicleRoutes(
|
||||
"some-vehicle",
|
||||
new PostVehicleRoutesRequestTO(
|
||||
List.of("some-destination-point", "some-destination-point-2")
|
||||
)
|
||||
);
|
||||
|
||||
then(routerService)
|
||||
.should()
|
||||
.computeRoutes(
|
||||
vehicle.getReference(),
|
||||
vehiclePosition.getReference(),
|
||||
Set.of(destinationPoint1.getReference(), destinationPoint2.getReference()),
|
||||
Set.of()
|
||||
);
|
||||
|
||||
// Act & Assert: nonexistent vehicle
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.getVehicleRoutes(
|
||||
"some-unknown-vehicle",
|
||||
new PostVehicleRoutesRequestTO(List.of("some-destination-point"))
|
||||
)
|
||||
);
|
||||
|
||||
// Act & Assert: nonexistent destination point
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.getVehicleRoutes(
|
||||
"some-vehicle",
|
||||
new PostVehicleRoutesRequestTO(List.of("some-unknown-destination-point"))
|
||||
)
|
||||
);
|
||||
|
||||
// Act & Assert: unknown vehicle position
|
||||
given(vehicleService.fetchObject(Vehicle.class, "some-vehicle"))
|
||||
.willReturn(vehicle);
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.getVehicleRoutes(
|
||||
"some-vehicle",
|
||||
new PostVehicleRoutesRequestTO(List.of("some-destination-point"))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveVehicleRoutesForPositionProvidedInRequest() {
|
||||
// Arrange
|
||||
Point sourcePoint = new Point("some-source-point");
|
||||
Point destinationPoint1 = new Point("some-destination-point");
|
||||
Point destinationPoint2 = new Point("some-destination-point-2");
|
||||
given(vehicleService.fetchObject(Point.class, "some-source-point"))
|
||||
.willReturn(sourcePoint);
|
||||
given(vehicleService.fetchObject(Point.class, "some-destination-point"))
|
||||
.willReturn(destinationPoint1);
|
||||
given(vehicleService.fetchObject(Point.class, "some-destination-point-2"))
|
||||
.willReturn(destinationPoint2);
|
||||
|
||||
// Act & Assert: happy path
|
||||
handler.getVehicleRoutes(
|
||||
"some-vehicle",
|
||||
new PostVehicleRoutesRequestTO(
|
||||
List.of("some-destination-point", "some-destination-point-2")
|
||||
).setSourcePoint("some-source-point")
|
||||
);
|
||||
|
||||
then(routerService)
|
||||
.should()
|
||||
.computeRoutes(
|
||||
vehicle.getReference(),
|
||||
sourcePoint.getReference(),
|
||||
Set.of(destinationPoint1.getReference(), destinationPoint2.getReference()),
|
||||
Set.of()
|
||||
);
|
||||
|
||||
// Act & Assert: nonexistent source point
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.getVehicleRoutes(
|
||||
"some-vehicle",
|
||||
new PostVehicleRoutesRequestTO(List.of("some-destination-point"))
|
||||
.setSourcePoint("some-unknown-source-point")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveVehicleRoutesForResourcesToAvoid() {
|
||||
// Arrange
|
||||
Point sourcePoint = new Point("some-source-point");
|
||||
Point destinationPoint1 = new Point("some-destination-point");
|
||||
Point destinationPoint2 = new Point("some-destination-point-2");
|
||||
Point pointToAvoid = new Point("some-point-to-avoid");
|
||||
Path pathToAvoid = new Path(
|
||||
"some-path",
|
||||
sourcePoint.getReference(),
|
||||
destinationPoint1.getReference()
|
||||
);
|
||||
Location locationToAvoid = new Location(
|
||||
"some-location",
|
||||
new LocationType("some-locType").getReference()
|
||||
);
|
||||
given(vehicleService.fetchObject(Point.class, "some-source-point"))
|
||||
.willReturn(sourcePoint);
|
||||
given(vehicleService.fetchObject(Point.class, "some-destination-point"))
|
||||
.willReturn(destinationPoint1);
|
||||
given(vehicleService.fetchObject(Point.class, "some-destination-point-2"))
|
||||
.willReturn(destinationPoint2);
|
||||
given(vehicleService.fetchObject(Point.class, "some-point-to-avoid"))
|
||||
.willReturn(pointToAvoid);
|
||||
given(vehicleService.fetchObject(Path.class, "some-path"))
|
||||
.willReturn(pathToAvoid);
|
||||
given(vehicleService.fetchObject(Location.class, "some-location"))
|
||||
.willReturn(locationToAvoid);
|
||||
|
||||
// Act & Assert: happy path
|
||||
handler.getVehicleRoutes(
|
||||
"some-vehicle",
|
||||
new PostVehicleRoutesRequestTO(
|
||||
List.of("some-destination-point", "some-destination-point-2")
|
||||
)
|
||||
.setSourcePoint("some-source-point")
|
||||
.setResourcesToAvoid(
|
||||
List.of("some-point-to-avoid", "some-path", "some-location")
|
||||
)
|
||||
);
|
||||
|
||||
then(routerService)
|
||||
.should()
|
||||
.computeRoutes(
|
||||
vehicle.getReference(),
|
||||
sourcePoint.getReference(),
|
||||
Set.of(destinationPoint1.getReference(), destinationPoint2.getReference()),
|
||||
Set.of(
|
||||
pointToAvoid.getReference(),
|
||||
pathToAvoid.getReference(),
|
||||
locationToAvoid.getReference()
|
||||
)
|
||||
);
|
||||
|
||||
// Act & Assert: nonexistent resource to avoid
|
||||
assertThatExceptionOfType(ObjectUnknownException.class)
|
||||
.isThrownBy(
|
||||
() -> handler.getVehicleRoutes(
|
||||
"some-vehicle",
|
||||
new PostVehicleRoutesRequestTO(List.of("some-destination-point"))
|
||||
.setSourcePoint("some-source-point")
|
||||
.setResourcesToAvoid(List.of("some-unknown-resource"))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
static class MockVehicleCommAdapterDescription
|
||||
extends
|
||||
VehicleCommAdapterDescription {
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "some-vehicle-comm-adapter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSimVehicleCommAdapter() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import org.approvaltests.Approvals;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.peripherals.PeripheralJob;
|
||||
import org.opentcs.data.peripherals.PeripheralOperation;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.JsonBinder;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.OrderStatusMessage;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.PeripheralJobStatusMessage;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.getevents.VehicleStatusMessage;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.DestinationState;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.PeripheralOperationDescription;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GetEventsResponseTO}.
|
||||
*/
|
||||
class GetEventsResponseTOTest {
|
||||
|
||||
private JsonBinder jsonBinder;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
jsonBinder = new JsonBinder();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(doubles = {Double.NaN, 90.0})
|
||||
void jsonSample(double orientationAngle) {
|
||||
GetEventsResponseTO to
|
||||
= new GetEventsResponseTO()
|
||||
.setTimeStamp(Instant.EPOCH)
|
||||
.setStatusMessages(
|
||||
List.of(
|
||||
createVehicleStatusMessage(0).setOrientationAngle(orientationAngle),
|
||||
createOrderStatusMessage(1),
|
||||
createPeripheralJobStatusMessage(2)
|
||||
)
|
||||
);
|
||||
|
||||
Approvals.verify(
|
||||
jsonBinder.toJson(to),
|
||||
Approvals.NAMES.withParameters("orientationAngle-" + orientationAngle)
|
||||
);
|
||||
}
|
||||
|
||||
private VehicleStatusMessage createVehicleStatusMessage(long sequenceNo) {
|
||||
return new VehicleStatusMessage()
|
||||
.setSequenceNumber(sequenceNo)
|
||||
.setCreationTimeStamp(Instant.EPOCH)
|
||||
.setVehicleName("some-vehicle")
|
||||
.setTransportOrderName("some-transport-order")
|
||||
.setPosition("some-point")
|
||||
.setPrecisePosition(new VehicleStatusMessage.PrecisePosition(1, 2, 3))
|
||||
.setPaused(false)
|
||||
.setState(Vehicle.State.IDLE)
|
||||
.setProcState(Vehicle.ProcState.IDLE)
|
||||
.setAllocatedResources(
|
||||
List.of(
|
||||
List.of("some-path", "some-point"),
|
||||
List.of("some-other-path", "some-other-point")
|
||||
)
|
||||
)
|
||||
.setClaimedResources(
|
||||
List.of(
|
||||
List.of("some-path", "some-point"),
|
||||
List.of("some-other-path", "some-other-point")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private OrderStatusMessage createOrderStatusMessage(long sequenceNo) {
|
||||
return new OrderStatusMessage()
|
||||
.setSequenceNumber(sequenceNo)
|
||||
.setCreationTimeStamp(Instant.EPOCH)
|
||||
.setOrderName("some-order")
|
||||
.setProcessingVehicleName("some-vehicle")
|
||||
.setOrderState(OrderStatusMessage.OrderState.BEING_PROCESSED)
|
||||
.setDestinations(
|
||||
List.of(
|
||||
new DestinationState()
|
||||
.setLocationName("some-location")
|
||||
.setOperation("some-operation")
|
||||
.setState(DestinationState.State.TRAVELLING)
|
||||
.setProperties(
|
||||
List.of(
|
||||
new Property("some-key", "some-value"),
|
||||
new Property("some-other-key", "some-other-value")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.setProperties(
|
||||
List.of(
|
||||
new Property("some-key", "some-value"),
|
||||
new Property("some-other-key", "some-other-value")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private PeripheralJobStatusMessage createPeripheralJobStatusMessage(long sequenceNo) {
|
||||
return new PeripheralJobStatusMessage()
|
||||
.setSequenceNumber(sequenceNo)
|
||||
.setCreationTimeStamp(Instant.EPOCH)
|
||||
.setName("some-peripheral-job")
|
||||
.setReservationToken("some-token")
|
||||
.setRelatedVehicle("some-vehicle")
|
||||
.setRelatedTransportOrder("some-order")
|
||||
.setPeripheralOperation(
|
||||
new PeripheralOperationDescription()
|
||||
.setOperation("some-operation")
|
||||
.setLocationName("some-location")
|
||||
.setExecutionTrigger(PeripheralOperation.ExecutionTrigger.AFTER_ALLOCATION)
|
||||
.setCompletionRequired(true)
|
||||
)
|
||||
.setState(PeripheralJob.State.BEING_PROCESSED)
|
||||
.setCreationTime(Instant.EPOCH)
|
||||
.setFinishedTime(Instant.MAX)
|
||||
.setProperties(
|
||||
List.of(
|
||||
new Property("some-key", "some-value"),
|
||||
new Property("some-other-key", "some-other-value")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"timeStamp" : "1970-01-01T00:00:00Z",
|
||||
"statusMessages" : [ {
|
||||
"type" : "Vehicle",
|
||||
"sequenceNumber" : 0,
|
||||
"creationTimeStamp" : "1970-01-01T00:00:00Z",
|
||||
"vehicleName" : "some-vehicle",
|
||||
"transportOrderName" : "some-transport-order",
|
||||
"position" : "some-point",
|
||||
"precisePosition" : {
|
||||
"x" : 1,
|
||||
"y" : 2,
|
||||
"z" : 3
|
||||
},
|
||||
"orientationAngle" : 90.0,
|
||||
"paused" : false,
|
||||
"state" : "IDLE",
|
||||
"procState" : "IDLE",
|
||||
"allocatedResources" : [ [ "some-path", "some-point" ], [ "some-other-path", "some-other-point" ] ],
|
||||
"claimedResources" : [ [ "some-path", "some-point" ], [ "some-other-path", "some-other-point" ] ]
|
||||
}, {
|
||||
"type" : "TransportOrder",
|
||||
"sequenceNumber" : 1,
|
||||
"creationTimeStamp" : "1970-01-01T00:00:00Z",
|
||||
"orderName" : "some-order",
|
||||
"processingVehicleName" : "some-vehicle",
|
||||
"orderState" : "BEING_PROCESSED",
|
||||
"destinations" : [ {
|
||||
"locationName" : "some-location",
|
||||
"operation" : "some-operation",
|
||||
"state" : "TRAVELLING",
|
||||
"properties" : [ {
|
||||
"key" : "some-key",
|
||||
"value" : "some-value"
|
||||
}, {
|
||||
"key" : "some-other-key",
|
||||
"value" : "some-other-value"
|
||||
} ]
|
||||
} ],
|
||||
"properties" : [ {
|
||||
"key" : "some-key",
|
||||
"value" : "some-value"
|
||||
}, {
|
||||
"key" : "some-other-key",
|
||||
"value" : "some-other-value"
|
||||
} ]
|
||||
}, {
|
||||
"type" : "PeripheralJob",
|
||||
"sequenceNumber" : 2,
|
||||
"creationTimeStamp" : "1970-01-01T00:00:00Z",
|
||||
"name" : "some-peripheral-job",
|
||||
"reservationToken" : "some-token",
|
||||
"relatedVehicle" : "some-vehicle",
|
||||
"relatedTransportOrder" : "some-order",
|
||||
"peripheralOperation" : {
|
||||
"operation" : "some-operation",
|
||||
"locationName" : "some-location",
|
||||
"executionTrigger" : "AFTER_ALLOCATION",
|
||||
"completionRequired" : true
|
||||
},
|
||||
"state" : "BEING_PROCESSED",
|
||||
"creationTime" : "1970-01-01T00:00:00Z",
|
||||
"finishedTime" : "+1000000000-12-31T23:59:59.999999999Z",
|
||||
"properties" : [ {
|
||||
"key" : "some-key",
|
||||
"value" : "some-value"
|
||||
}, {
|
||||
"key" : "some-other-key",
|
||||
"value" : "some-other-value"
|
||||
} ]
|
||||
} ]
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"timeStamp" : "1970-01-01T00:00:00Z",
|
||||
"statusMessages" : [ {
|
||||
"type" : "Vehicle",
|
||||
"sequenceNumber" : 0,
|
||||
"creationTimeStamp" : "1970-01-01T00:00:00Z",
|
||||
"vehicleName" : "some-vehicle",
|
||||
"transportOrderName" : "some-transport-order",
|
||||
"position" : "some-point",
|
||||
"precisePosition" : {
|
||||
"x" : 1,
|
||||
"y" : 2,
|
||||
"z" : 3
|
||||
},
|
||||
"orientationAngle" : "NaN",
|
||||
"paused" : false,
|
||||
"state" : "IDLE",
|
||||
"procState" : "IDLE",
|
||||
"allocatedResources" : [ [ "some-path", "some-point" ], [ "some-other-path", "some-other-point" ] ],
|
||||
"claimedResources" : [ [ "some-path", "some-point" ], [ "some-other-path", "some-other-point" ] ]
|
||||
}, {
|
||||
"type" : "TransportOrder",
|
||||
"sequenceNumber" : 1,
|
||||
"creationTimeStamp" : "1970-01-01T00:00:00Z",
|
||||
"orderName" : "some-order",
|
||||
"processingVehicleName" : "some-vehicle",
|
||||
"orderState" : "BEING_PROCESSED",
|
||||
"destinations" : [ {
|
||||
"locationName" : "some-location",
|
||||
"operation" : "some-operation",
|
||||
"state" : "TRAVELLING",
|
||||
"properties" : [ {
|
||||
"key" : "some-key",
|
||||
"value" : "some-value"
|
||||
}, {
|
||||
"key" : "some-other-key",
|
||||
"value" : "some-other-value"
|
||||
} ]
|
||||
} ],
|
||||
"properties" : [ {
|
||||
"key" : "some-key",
|
||||
"value" : "some-value"
|
||||
}, {
|
||||
"key" : "some-other-key",
|
||||
"value" : "some-other-value"
|
||||
} ]
|
||||
}, {
|
||||
"type" : "PeripheralJob",
|
||||
"sequenceNumber" : 2,
|
||||
"creationTimeStamp" : "1970-01-01T00:00:00Z",
|
||||
"name" : "some-peripheral-job",
|
||||
"reservationToken" : "some-token",
|
||||
"relatedVehicle" : "some-vehicle",
|
||||
"relatedTransportOrder" : "some-order",
|
||||
"peripheralOperation" : {
|
||||
"operation" : "some-operation",
|
||||
"locationName" : "some-location",
|
||||
"executionTrigger" : "AFTER_ALLOCATION",
|
||||
"completionRequired" : true
|
||||
},
|
||||
"state" : "BEING_PROCESSED",
|
||||
"creationTime" : "1970-01-01T00:00:00Z",
|
||||
"finishedTime" : "+1000000000-12-31T23:59:59.999999999Z",
|
||||
"properties" : [ {
|
||||
"key" : "some-key",
|
||||
"value" : "some-value"
|
||||
}, {
|
||||
"key" : "some-other-key",
|
||||
"value" : "some-other-value"
|
||||
} ]
|
||||
} ]
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.kernel.extensions.servicewebapi.v1.binding;
|
||||
|
||||
import java.util.List;
|
||||
import org.approvaltests.Approvals;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.JsonBinder;
|
||||
import org.opentcs.kernel.extensions.servicewebapi.v1.binding.shared.Property;
|
||||
|
||||
/**
|
||||
*/
|
||||
class GetOrderSequenceResponseTOTest {
|
||||
|
||||
private JsonBinder jsonBinder;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
jsonBinder = new JsonBinder();
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonSample() {
|
||||
GetOrderSequenceResponseTO to = new GetOrderSequenceResponseTO("some-order-sequence")
|
||||
.setType("Charge")
|
||||
.setOrders(List.of("some-order", "another-order", "order-3"))
|
||||
.setFinishedIndex(3)
|
||||
.setComplete(false)
|
||||
.setFinished(false)
|
||||
.setFailureFatal(true)
|
||||
.setIntendedVehicle("some-vehicle")
|
||||
.setProcessingVehicle(null)
|
||||
.setProperties(
|
||||
List.of(
|
||||
new Property("some-key", "some-value"),
|
||||
new Property("another-key", "another-value")
|
||||
)
|
||||
);
|
||||
|
||||
Approvals.verify(jsonBinder.toJson(to));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name" : "some-order-sequence",
|
||||
"type" : "Charge",
|
||||
"orders" : [ "some-order", "another-order", "order-3" ],
|
||||
"finishedIndex" : 3,
|
||||
"complete" : false,
|
||||
"finished" : false,
|
||||
"failureFatal" : true,
|
||||
"intendedVehicle" : "some-vehicle",
|
||||
"processingVehicle" : null,
|
||||
"properties" : [ {
|
||||
"key" : "some-key",
|
||||
"value" : "some-value"
|
||||
}, {
|
||||
"key" : "another-key",
|
||||
"value" : "another-value"
|
||||
} ]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user