All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.opentcs.kernel.extensions.controlcenter.vehicles.AttachmentManager Maven / Gradle / Ivy
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.kernel.extensions.controlcenter.vehicles;
import static java.util.Objects.requireNonNull;
import com.google.common.base.Strings;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.inject.Inject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.opentcs.components.Lifecycle;
import org.opentcs.components.kernel.services.TCSObjectService;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.data.model.Vehicle;
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
import org.opentcs.drivers.vehicle.VehicleCommAdapterDescription;
import org.opentcs.drivers.vehicle.VehicleCommAdapterFactory;
import org.opentcs.drivers.vehicle.management.ProcessModelEvent;
import org.opentcs.drivers.vehicle.management.VehicleAttachmentEvent;
import org.opentcs.drivers.vehicle.management.VehicleAttachmentInformation;
import org.opentcs.drivers.vehicle.management.VehicleProcessModelTO;
import org.opentcs.kernel.KernelApplicationConfiguration;
import org.opentcs.kernel.vehicles.LocalVehicleControllerPool;
import org.opentcs.kernel.vehicles.VehicleCommAdapterRegistry;
import org.opentcs.util.Assertions;
import org.opentcs.util.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manages attachment and detachment of communication adapters to vehicles.
*/
public class AttachmentManager
implements
Lifecycle {
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(AttachmentManager.class);
/**
* This class's configuration.
*/
private final KernelApplicationConfiguration configuration;
/**
* The object service.
*/
private final TCSObjectService objectService;
/**
* The vehicle controller pool.
*/
private final LocalVehicleControllerPool controllerPool;
/**
* The comm adapter registry.
*/
private final VehicleCommAdapterRegistry commAdapterRegistry;
/**
* The pool of vehicle entries.
*/
private final VehicleEntryPool vehicleEntryPool;
/**
* The handler to send events to.
*/
private final EventHandler eventHandler;
/**
* The pool of comm adapter attachments.
*/
private final Map attachmentPool = new HashMap<>();
/**
* Whether the attachment manager is initialized or not.
*/
private boolean initialized;
/**
* Creates a new instance.
*
* @param objectService The object service.
* @param controllerPool The vehicle controller pool.
* @param commAdapterRegistry The comm adapter registry.
* @param vehicleEntryPool The pool of vehicle entries.
* @param eventHandler The handler to send events to.
* @param configuration This class's configuration.
*/
@Inject
public AttachmentManager(
@Nonnull
TCSObjectService objectService,
@Nonnull
LocalVehicleControllerPool controllerPool,
@Nonnull
VehicleCommAdapterRegistry commAdapterRegistry,
@Nonnull
VehicleEntryPool vehicleEntryPool,
@Nonnull
@ApplicationEventBus
EventHandler eventHandler,
@Nonnull
KernelApplicationConfiguration configuration
) {
this.objectService = requireNonNull(objectService, "objectService");
this.controllerPool = requireNonNull(controllerPool, "controllerPool");
this.commAdapterRegistry = requireNonNull(commAdapterRegistry, "commAdapterRegistry");
this.vehicleEntryPool = requireNonNull(vehicleEntryPool, "vehicleEntryPool");
this.eventHandler = requireNonNull(eventHandler, "eventHandler");
this.configuration = requireNonNull(configuration, "configuration");
}
@Override
public void initialize() {
if (isInitialized()) {
LOG.debug("Already initialized.");
return;
}
commAdapterRegistry.initialize();
vehicleEntryPool.initialize();
initAttachmentPool();
autoAttachAllAdapters();
if (configuration.autoEnableDriversOnStartup()) {
autoEnableAllAdapters();
}
initialized = true;
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public void terminate() {
if (!isInitialized()) {
LOG.debug("Not initialized.");
return;
}
// Detach all attached drivers to clean up.
detachAllAdapters();
vehicleEntryPool.terminate();
commAdapterRegistry.terminate();
initialized = false;
}
/**
* Attaches an adapter to a vehicle.
*
* @param vehicleName The vehicle name.
* @param factory The factory that provides the adapter to be assigned.
*/
public void attachAdapterToVehicle(
@Nonnull
String vehicleName,
@Nonnull
VehicleCommAdapterFactory factory
) {
requireNonNull(vehicleName, "vehicleName");
requireNonNull(factory, "factory");
LOG.info(
"Attaching vehicle comm adapter: '{}' -- '{}'...",
vehicleName,
factory.getClass().getName()
);
VehicleEntry vehicleEntry = vehicleEntryPool.getEntryFor(vehicleName);
if (vehicleEntry == null) {
LOG.warn(
"No vehicle entry found for '{}'. Entries: {}",
vehicleName,
vehicleEntryPool
);
return;
}
VehicleCommAdapter commAdapter = factory.getAdapterFor(vehicleEntry.getVehicle());
if (commAdapter == null) {
LOG.warn(
"Factory {} did not provide adapter for vehicle {}, ignoring.",
factory,
vehicleEntry.getVehicle().getName()
);
return;
}
// Perform a cleanup for the old adapter.
disableAndTerminateAdapter(vehicleEntry);
controllerPool.detachVehicleController(vehicleEntry.getVehicle().getName());
commAdapter.initialize();
controllerPool.attachVehicleController(vehicleEntry.getVehicle().getName(), commAdapter);
vehicleEntry.setCommAdapterFactory(factory);
vehicleEntry.setCommAdapter(commAdapter);
vehicleEntry.setProcessModel(commAdapter.getProcessModel());
objectService.updateObjectProperty(
vehicleEntry.getVehicle().getReference(),
Vehicle.PREFERRED_ADAPTER,
factory.getClass().getName()
);
updateAttachmentInformation(vehicleEntry);
}
/**
* Automatically attach a vehicle to an adapter.
*
* @param vehicleName The name of the vehicle to attach.
*/
public void autoAttachAdapterToVehicle(
@Nonnull
String vehicleName
) {
requireNonNull(vehicleName, "vehicleName");
VehicleEntry vehicleEntry = vehicleEntryPool.getEntryFor(vehicleName);
if (vehicleEntry == null) {
LOG.warn(
"No vehicle entry found for '{}'. Entries: {}",
vehicleName,
vehicleEntryPool
);
return;
}
// Do not auto-attach if there is already a comm adapter attached to the vehicle.
if (vehicleEntry.getCommAdapter() != null) {
return;
}
Vehicle vehicle = getUpdatedVehicle(vehicleEntry.getVehicle());
String prefAdapter = vehicle.getProperties().get(Vehicle.PREFERRED_ADAPTER);
VehicleCommAdapterFactory factory = findFactoryWithName(prefAdapter);
if (factory != null && factory.providesAdapterFor(vehicle)) {
attachAdapterToVehicle(vehicleName, factory);
}
else {
if (!Strings.isNullOrEmpty(prefAdapter)) {
LOG.warn(
"Couldn't attach preferred adapter {} to {}. Attaching first available adapter.",
prefAdapter,
vehicleEntry.getVehicle().getName()
);
}
List factories
= commAdapterRegistry.findFactoriesFor(vehicleEntry.getVehicle());
if (!factories.isEmpty()) {
attachAdapterToVehicle(vehicleName, factories.get(0));
}
}
}
/**
* Automatically attach all vehicles to an adapter.
*/
public void autoAttachAllAdapters() {
vehicleEntryPool.getEntries().forEach((vehicleName, entry) -> {
autoAttachAdapterToVehicle(vehicleName);
});
}
/**
* Returns the attachment information for a vehicle.
*
* @param vehicleName The name of the vehicle.
* @return Attachment information about the vehicle.
*/
public VehicleAttachmentInformation getAttachmentInformation(String vehicleName) {
requireNonNull(vehicleName, "vehicleName");
Assertions.checkArgument(
attachmentPool.get(vehicleName) != null,
"No attachment information for vehicle %s",
vehicleName
);
return attachmentPool.get(vehicleName);
}
public Map getAttachmentPool() {
return attachmentPool;
}
private void disableAndTerminateAdapter(
@Nonnull
VehicleEntry vehicleEntry
) {
requireNonNull(vehicleEntry, "vehicleEntry");
VehicleCommAdapter commAdapter = vehicleEntry.getCommAdapter();
if (commAdapter != null) {
commAdapter.disable();
// Let the adapter know cleanup time is here.
commAdapter.terminate();
}
}
private void initAttachmentPool() {
vehicleEntryPool.getEntries().forEach((vehicleName, entry) -> {
List availableCommAdapters
= commAdapterRegistry.getFactories().stream()
.filter(f -> f.providesAdapterFor(entry.getVehicle()))
.map(f -> f.getDescription())
.collect(Collectors.toList());
attachmentPool.put(
vehicleName,
new VehicleAttachmentInformation(
entry.getVehicle().getReference(),
availableCommAdapters,
new NullVehicleCommAdapterDescription()
)
);
});
}
private void updateAttachmentInformation(VehicleEntry entry) {
String vehicleName = entry.getVehicleName();
VehicleCommAdapterFactory factory = entry.getCommAdapterFactory();
VehicleAttachmentInformation newAttachment = attachmentPool.get(vehicleName)
.withAttachedCommAdapter(factory.getDescription());
attachmentPool.put(vehicleName, newAttachment);
eventHandler.onEvent(new VehicleAttachmentEvent(vehicleName, newAttachment));
if (entry.getCommAdapter() == null) {
// In case we are detached
eventHandler.onEvent(new ProcessModelEvent(vehicleName, new VehicleProcessModelTO()));
}
else {
eventHandler.onEvent(
new ProcessModelEvent(
vehicleName,
entry.getCommAdapter()
.createTransferableProcessModel()
)
);
}
}
/**
* Returns a fresh copy of a vehicle from the kernel.
*
* @param vehicle The old vehicle instance.
* @return The fresh vehicle instance.
*/
private Vehicle getUpdatedVehicle(
@Nonnull
Vehicle vehicle
) {
requireNonNull(vehicle, "vehicle");
return objectService.fetchObjects(Vehicle.class).stream()
.filter(updatedVehicle -> Objects.equals(updatedVehicle.getName(), vehicle.getName()))
.findFirst().orElse(vehicle);
}
private void autoEnableAllAdapters() {
vehicleEntryPool.getEntries().values().stream()
.map(entry -> entry.getCommAdapter())
.filter(adapter -> adapter != null)
.filter(adapter -> !adapter.isEnabled())
.forEach(adapter -> adapter.enable());
}
private void detachAllAdapters() {
LOG.debug("Detaching vehicle communication adapters...");
vehicleEntryPool.getEntries().forEach((vehicleName, entry) -> {
disableAndTerminateAdapter(entry);
});
LOG.debug("Detached vehicle communication adapters");
}
@Nullable
private VehicleCommAdapterFactory findFactoryWithName(
@Nullable
String name
) {
return commAdapterRegistry.getFactories().stream()
.filter(factory -> factory.getClass().getName().equals(name))
.findFirst()
.orElse(null);
}
}