297 lines
11 KiB
Java
297 lines
11 KiB
Java
package be.seeseepuff.pcinv.services;
|
|
|
|
import be.seeseepuff.pcinv.meta.AssetDescriptor;
|
|
import be.seeseepuff.pcinv.meta.AssetDescriptors;
|
|
import be.seeseepuff.pcinv.meta.AssetInfo;
|
|
import be.seeseepuff.pcinv.meta.AssetProperty;
|
|
import be.seeseepuff.pcinv.models.Asset;
|
|
import be.seeseepuff.pcinv.models.GenericAsset;
|
|
import be.seeseepuff.pcinv.repositories.AssetRepository;
|
|
import be.seeseepuff.pcinv.repositories.GenericAssetRepository;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* Service for managing assets in the repository.
|
|
* Provides methods to interact with the asset repositories.
|
|
*/
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class AssetService {
|
|
private final GenericAssetRepository genericRepository;
|
|
private final Collection<AssetRepository<?>> repositories;
|
|
|
|
/**
|
|
* Returns the count of all assets in the repository.
|
|
*
|
|
* @return the total number of assets
|
|
*/
|
|
public long countAssets() {
|
|
return genericRepository.count();
|
|
}
|
|
|
|
/**
|
|
* Retrieves an asset by its QR code.
|
|
*
|
|
* @param qr the QR code of the asset to retrieve
|
|
* @return the Asset associated with the given QR code
|
|
* @throws IllegalArgumentException if no asset is found with the given QR code
|
|
*/
|
|
public Asset getAssetByQr(long qr) {
|
|
var genericAsset = genericRepository.findByQr(qr);
|
|
if (genericAsset == null) {
|
|
throw new IllegalArgumentException("No asset found with QR code: " + qr);
|
|
}
|
|
return getRepositoryFor(genericAsset.getType()).findByAsset(genericAsset);
|
|
}
|
|
|
|
/**
|
|
* Retrieves all assets of a specific type.
|
|
*
|
|
* @param type the type of asset to retrieve
|
|
* @return a list of assets of the specified type
|
|
*/
|
|
public List<? extends Asset> getAssetsByType(String type) {
|
|
return getRepositoryFor(type).findAll();
|
|
}
|
|
|
|
/**
|
|
* Retrieves the global asset descriptors for all asset types.
|
|
*
|
|
* @return the AssetProperties for the specified type
|
|
*/
|
|
public AssetDescriptors getAssetDescriptors() {
|
|
var descriptors = new AssetDescriptors();
|
|
descriptors.loadFrom(GenericAsset.class);
|
|
for (var repository : repositories) {
|
|
descriptors.loadFrom(repository.getAssetType());
|
|
}
|
|
return descriptors;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the asset properties for a specific type.
|
|
*
|
|
* @param type the type of asset to retrieve properties for
|
|
* @return the AssetProperties for the specified type
|
|
*/
|
|
public AssetDescriptor getAssetDescriptor(String type) {
|
|
return getAssetDescriptors().getAssets().stream()
|
|
.filter(asset -> asset.getType().equals(type))
|
|
.findFirst()
|
|
.orElseThrow(() -> new IllegalArgumentException("Unknown asset type: " + type));
|
|
}
|
|
|
|
/**
|
|
* Retrieves a tree of asset descriptors for the specified type.
|
|
*
|
|
* @param type the type of asset to retrieve descriptors for
|
|
* @return a list of AssetDescriptors for the specified type
|
|
*/
|
|
public List<AssetDescriptor> getAssetDescriptorTree(String type) {
|
|
if (type.equals(GenericAsset.TYPE)) {
|
|
return List.of(getAssetDescriptor(GenericAsset.TYPE));
|
|
}
|
|
return List.of(getAssetDescriptor(GenericAsset.TYPE), getAssetDescriptor(type));
|
|
}
|
|
|
|
/**
|
|
* Creates a new asset of the specified type with the provided form data.
|
|
*
|
|
* @param type The type of asset to create.
|
|
* @param formData The form data containing the asset properties.
|
|
* @return The created asset.
|
|
*/
|
|
@Transactional
|
|
public Asset createAsset(String type, Map<String, String> formData) {
|
|
var genericDescriptor = getAssetDescriptor(GenericAsset.TYPE);
|
|
var assetDescriptor = getAssetDescriptor(type);
|
|
|
|
var genericAsset = new GenericAsset();
|
|
genericAsset.setType(type);
|
|
fillIn(genericAsset, genericDescriptor, formData);
|
|
|
|
var asset = assetDescriptor.newInstance();
|
|
fillIn(asset, assetDescriptor, formData);
|
|
|
|
genericAsset = genericRepository.saveAndFlush(genericAsset);
|
|
asset.setAsset(genericAsset);
|
|
asset = getRepositoryFor(type).saveAndFlushAsset(asset);
|
|
return asset;
|
|
}
|
|
|
|
/**
|
|
* Edits an existing asset with the provided form data.
|
|
*
|
|
* @param qr The QR code of the asset to edit.
|
|
* @param formData The form data containing the updated asset properties.
|
|
* @return The updated asset.
|
|
*/
|
|
@Transactional
|
|
public Asset editAsset(long qr, Map<String, String> formData) {
|
|
var genericAsset = genericRepository.findByQr(qr);
|
|
if (genericAsset == null) {
|
|
throw new IllegalArgumentException("No asset found with QR code: " + qr);
|
|
}
|
|
|
|
var assetType = genericAsset.getType();
|
|
var assetDescriptor = getAssetDescriptor(assetType);
|
|
var asset = getRepositoryFor(assetType).findByAsset(genericAsset);
|
|
|
|
fillIn(genericAsset, getAssetDescriptor(GenericAsset.TYPE), formData);
|
|
fillIn(asset, assetDescriptor, formData);
|
|
|
|
genericRepository.saveAndFlush(genericAsset);
|
|
return getRepositoryFor(assetType).saveAndFlushAsset(asset);
|
|
}
|
|
|
|
/**
|
|
* Gets the asset repository for the specified type.
|
|
*
|
|
* @param type the type of asset to get the repository for
|
|
* @return the AssetRepository for the specified type
|
|
*/
|
|
private AssetRepository<?> getRepositoryFor(String type) {
|
|
return repositories.stream()
|
|
.filter(repo -> repo.getAssetType().getAnnotation(AssetInfo.class).type().equals(type))
|
|
.findFirst()
|
|
.orElseThrow(() -> new IllegalArgumentException("No repository found for type: " + type));
|
|
}
|
|
|
|
/**
|
|
* Fills in the properties of a generic asset from the form data.
|
|
*
|
|
* @param asset The generic asset to fill in.
|
|
* @param assetDescriptor The descriptor containing the properties to fill in.
|
|
* @param formData The form data containing the property values.
|
|
*/
|
|
private void fillIn(Object asset, AssetDescriptor assetDescriptor, Map<String, String> formData) {
|
|
for (var property : assetDescriptor.getProperties()) {
|
|
var value = parseValue(assetDescriptor, property, formData);
|
|
if (property.isInputList()) {
|
|
var selectedItem = formData.get(assetDescriptor.asString(property) + "-list");
|
|
if (selectedItem != null && !selectedItem.isBlank() && !selectedItem.equals("__new__")) {
|
|
value = selectedItem;
|
|
}
|
|
}
|
|
if (value == null && property.isRequired()) {
|
|
throw new IllegalArgumentException("Property '" + property.getName() + "' is required but not provided.");
|
|
}
|
|
property.setValue(asset, value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses the string value into the appropriate type based on the asset property.
|
|
*
|
|
* @param descriptor The asset descriptor containing the property.
|
|
* @param property The asset property to determine the type.
|
|
* @param values The map of values from the form data.
|
|
* @return The parsed value as an Object.
|
|
*/
|
|
private Object parseValue(AssetDescriptor descriptor, AssetProperty property, Map<String, String> values) {
|
|
if (property.getType() == AssetProperty.Type.CAPACITY) {
|
|
var value = values.get(descriptor.asString(property) + "-value");
|
|
var unit = values.get(descriptor.asString(property) + "-unit");
|
|
if (value == null || value.isBlank() || unit == null || unit.isBlank()) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return Long.parseLong(value) * Long.parseLong(unit);
|
|
} catch (NumberFormatException e) {
|
|
throw new IllegalArgumentException("Invalid numeric value for property '" + property.getName() + "': " + value, e);
|
|
}
|
|
}
|
|
|
|
var stringValue = values.get(descriptor.asString(property));
|
|
if (stringValue == null || stringValue.isBlank()) {
|
|
return null;
|
|
}
|
|
|
|
if (property.getType() == AssetProperty.Type.INTEGER) {
|
|
return Integer.parseInt(stringValue);
|
|
} else if (property.getType() == AssetProperty.Type.STRING) {
|
|
return stringValue;
|
|
} else if (property.getType() == AssetProperty.Type.BOOLEAN) {
|
|
return switch (stringValue.toLowerCase()) {
|
|
case "true" -> true;
|
|
case "false" -> false;
|
|
default -> null;
|
|
};
|
|
} else if (property.getType().isEnum) {
|
|
for (var option : property.getOptions()) {
|
|
if (option.getValue().equals(stringValue)) {
|
|
return option.getEnumConstant();
|
|
}
|
|
}
|
|
throw new IllegalArgumentException("Invalid value for enum property '" + property.getName() + "': " + stringValue);
|
|
} else {
|
|
throw new IllegalArgumentException("Unsupported property type: " + property.getType());
|
|
}
|
|
}
|
|
|
|
@Transactional
|
|
public void deleteAsset(long qr) {
|
|
var genericAsset = genericRepository.findByQr(qr);
|
|
if (genericAsset == null) {
|
|
throw new IllegalArgumentException("No asset found with QR code: " + qr);
|
|
}
|
|
var assetType = genericAsset.getType();
|
|
var assetRepository = getRepositoryFor(assetType);
|
|
assetRepository.deleteByAsset(genericAsset);
|
|
assetRepository.flush();
|
|
genericRepository.delete(genericAsset);
|
|
genericRepository.flush();
|
|
}
|
|
|
|
/**
|
|
* Retrieves the input list mapping for a specific asset type.
|
|
*
|
|
* @param type the type of asset to retrieve the input list for
|
|
* @return a map of input names to their corresponding list
|
|
*/
|
|
public Map<String, Set<String>> getInputList(String type) {
|
|
var map = new HashMap<String, Set<String>>();
|
|
var tree = getAssetDescriptorTree(type);
|
|
for (var descriptor : tree) {
|
|
for (var property : descriptor.getProperties()) {
|
|
if (property.isInputList()) {
|
|
var inputList = getInputList(descriptor, property);
|
|
map.put(descriptor.asString(property), inputList);
|
|
}
|
|
}
|
|
}
|
|
return map;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the input list for a specific asset descriptor and property.
|
|
*
|
|
* @param descriptor the asset descriptor containing the property
|
|
* @param property the asset property to retrieve the input list for
|
|
* @return a set of input values for the specified property
|
|
*/
|
|
private Set<String> getInputList(AssetDescriptor descriptor, AssetProperty property) {
|
|
List<?> entries;
|
|
if (descriptor.getType().equals(GenericAsset.TYPE)) {
|
|
entries = genericRepository.findAll();
|
|
} else {
|
|
var repository = getRepositoryFor(descriptor.getType());
|
|
entries = repository.findAll();
|
|
}
|
|
|
|
Set<String> inputList = new TreeSet<>();
|
|
for (var entry : entries) {
|
|
var value = property.getValue(entry);
|
|
if (value != null) {
|
|
inputList.add(value.toString());
|
|
}
|
|
}
|
|
return inputList;
|
|
}
|
|
}
|