Commit cdd5f3b8 authored by Christos Tranoris's avatar Christos Tranoris
Browse files

fixes #88

parent 5c3d12ee
Loading
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -75,6 +75,20 @@ public class ServiceApiController implements ServiceApi {
				service.setRelatedParty(AddUserAsOwnerToRelatedParties.addUser(principal.getName(), principal.getName(),
						UserPartRoleType.REQUESTER, "", service.getRelatedParty()));

				// Create a temporary service object to check consistency
				Service tempService = new Service();
				tempService.setServiceSpecificationRef(service.getServiceSpecificationRef());
				if (service.getServiceCharacteristic() != null) {
					tempService.getServiceCharacteristic().addAll(service.getServiceCharacteristic());
				}

				// Check consistency before creating the service
				String consistencyReason = serviceRepoService.checkConsistencyReason(tempService);
				if (consistencyReason != null) {
					log.warn("Service consistency check failed: " + consistencyReason);
					return new ResponseEntity<Service>(HttpStatus.BAD_REQUEST);
				}

				Service c = serviceRepoService.addService(service);

				return new ResponseEntity<Service>(c, HttpStatus.OK);
+113 −15
Original line number Diff line number Diff line
@@ -22,24 +22,19 @@ package org.etsi.osl.tmf.sim638.service;
import java.io.UnsupportedEncodingException;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.etsi.osl.model.nfv.DeploymentDescriptor;
import org.etsi.osl.model.nfv.DeploymentDescriptorVxFInstanceInfo;
import org.etsi.osl.tmf.common.model.Any;
import org.etsi.osl.tmf.common.model.UserPartRoleType;
import org.etsi.osl.tmf.common.model.service.Characteristic;
@@ -80,8 +75,11 @@ import org.hibernate.transform.ResultTransformer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.etsi.osl.model.nfv.DeploymentDescriptor;
import org.etsi.osl.model.nfv.DeploymentDescriptorVxFInstanceInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule;
import jakarta.persistence.EntityManagerFactory;
import jakarta.validation.Valid;

@@ -1370,6 +1368,106 @@ public class ServiceRepoService {

    }

    /**
     * Checks the consistency between a Service and its ServiceSpecification and returns the reason if inconsistent.
     *
     * @param service The Service to check
     * @return null if consistent, otherwise a string describing the inconsistency reason
     */
    @Transactional
    public String checkConsistencyReason(Service service) {
        if (service == null) {
            return "Service is null";
        }

        if (service.getServiceSpecificationRef() == null) {
            return "Service has no ServiceSpecificationRef";
        }

        String specId = service.getServiceSpecificationRef().getId();
        if (specId == null || specId.isEmpty()) {
            return "ServiceSpecificationRef has no id";
        }

        // Retrieve the ServiceSpecification using the id from ServiceSpecificationRef
        org.etsi.osl.tmf.scm633.model.ServiceSpecification serviceSpec = serviceSpecRepoService.findByUuidEager(specId);

        if (serviceSpec == null) {
            return "ServiceSpecification not found with id " + specId;
        }

        // Get the service characteristics from both entities
        Set<Characteristic> serviceCharacteristics = service.getServiceCharacteristic();
        Set<org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristic> specCharacteristics = serviceSpec.getServiceSpecCharacteristic();

        // Create maps for easier lookup and validation
        Set<String> serviceCharNames = new HashSet<>();
        for (Characteristic serviceChar : serviceCharacteristics) {
            if (serviceChar.getName() != null) {
                serviceCharNames.add(serviceChar.getName());
            }
        }

        // Create a map of spec characteristic names to their configurable status
        Map<String, org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristic> specCharMap = new HashMap<>();
        for (org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristic specChar : specCharacteristics) {
            if (specChar.getName() != null) {
                specCharMap.put(specChar.getName(), specChar);
            }
        }

        // Validate each spec characteristic
        // Configurable characteristics MAY exist in service (optional)
        // Non-configurable characteristics must NOT exist in service
        for (org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristic specChar : specCharacteristics) {
            if (specChar.getName() == null) {
                continue;
            }

            boolean isConfigurable = specChar.isConfigurable() != null && specChar.isConfigurable();
            boolean existsInService = serviceCharNames.contains(specChar.getName());

            if (!isConfigurable && existsInService) {
                // Non-configurable characteristics must NOT exist in the service
                return "Service has non-configurable characteristic '" + specChar.getName() +
                       "' which should not exist in the service (non-configurable characteristics should not be instantiated)";
            }
        }

        // Check that all service characteristics are defined in the spec
        for (Characteristic serviceChar : serviceCharacteristics) {
            if (serviceChar.getName() == null) {
                return "Service has a characteristic with null name";
            }

            if (!specCharMap.containsKey(serviceChar.getName())) {
                return "Service has characteristic '" + serviceChar.getName() +
                       "' which is not defined in ServiceSpecification " + specId;
            }
        }

        return null; // Consistent
    }

    /**
     * Checks the consistency between a Service and its ServiceSpecification.
     * Compares the ServiceCharacteristics of the Service with the ServiceSpecCharacteristics
     * from the ServiceSpecification to ensure they have the same names and count.
     *
     * @param service The Service to check
     * @return true if the service characteristics are consistent with the specification, false otherwise
     */
    @Transactional
    public boolean checkConsistency(Service service) {
        String reason = checkConsistencyReason(service);
        if (reason != null) {
            logger.warn("checkConsistency: " + reason);
            return false;
        }
        logger.debug("checkConsistency: Service " + (service != null ? service.getId() : "null") + " is consistent with its ServiceSpecification");
        return true;
    }

    /**
     * This function will try to identify if the resource contains
     * a characteristic called "org.etsi.osl.serviceId" and will check if there is a related service.
+33 −4
Original line number Diff line number Diff line
@@ -136,6 +136,20 @@ public class ServiceOrderApiController implements ServiceOrderApi {
				}finally {

				}

				// Create a temporary ServiceOrder object to check consistency
				ServiceOrder tempServiceOrder = new ServiceOrder();
				if (serviceOrder.getOrderItem() != null) {
					tempServiceOrder.getOrderItem().addAll(serviceOrder.getOrderItem());
				}

				// Check consistency before creating the service order
				String consistencyReason = serviceOrderRepoService.checkConsistencyReason(tempServiceOrder);
				if (consistencyReason != null) {
					log.warn("Service Order consistency check failed: " + consistencyReason);
					return new ResponseEntity<ServiceOrder>(HttpStatus.BAD_REQUEST);
				}

				ServiceOrder c = serviceOrderRepoService.addServiceOrder(serviceOrder, autoAcknowledge);

				return new ResponseEntity<ServiceOrder>(c, HttpStatus.OK);
@@ -210,6 +224,21 @@ public class ServiceOrderApiController implements ServiceOrderApi {
			Principal principal,
			@Parameter(description = "Identifier of the ServiceOrder", required = true) @PathVariable("id") String id,
			@Parameter(description = "The ServiceOrder to be updated", required = true) @Valid @RequestBody ServiceOrderUpdate serviceOrder) {

		// Check consistency of order items if they are being updated
		if (serviceOrder.getOrderItem() != null && !serviceOrder.getOrderItem().isEmpty()) {
			// Create a temporary ServiceOrder object to check consistency
			ServiceOrder tempServiceOrder = new ServiceOrder();
			tempServiceOrder.getOrderItem().addAll(serviceOrder.getOrderItem());

			// Check consistency before updating the service order
			String consistencyReason = serviceOrderRepoService.checkConsistencyReason(tempServiceOrder);
			if (consistencyReason != null) {
				log.warn("Service Order consistency check failed during patch: " + consistencyReason);
				return new ResponseEntity<ServiceOrder>(HttpStatus.BAD_REQUEST);
			}
		}

		ServiceOrder c = serviceOrderRepoService.updateServiceOrder(id, serviceOrder);

		return new ResponseEntity<ServiceOrder>(c, HttpStatus.OK);
+83 −5
Original line number Diff line number Diff line
@@ -1019,7 +1019,85 @@ public class ServiceOrderRepoService {
	}


	/**
	 * Checks the consistency of all ServiceRestriction elements in a ServiceOrder's ServiceOrderItems.
	 * Each ServiceRestriction is transformed to a Service and validated against its ServiceSpecification.
	 *
	 * @param serviceOrder The ServiceOrder to check
	 * @return null if all ServiceRestrictions are consistent, otherwise a string describing the first inconsistency found
	 */
	@Transactional
	public String checkConsistencyReason(ServiceOrder serviceOrder) {
		if (serviceOrder == null) {
			return "ServiceOrder is null";
		}

		if (serviceOrder.getOrderItem() == null || serviceOrder.getOrderItem().isEmpty()) {
			return "ServiceOrder has no order items";
		}

		// Check each ServiceOrderItem
		for (ServiceOrderItem orderItem : serviceOrder.getOrderItem()) {
			if (orderItem == null) {
				continue;
			}

			ServiceRestriction serviceRestriction = orderItem.getService();
			if (serviceRestriction == null) {
				return "ServiceOrderItem " + orderItem.getId() + " has no ServiceRestriction";
			}

			// Transform ServiceRestriction to Service for consistency checking
			org.etsi.osl.tmf.sim638.model.Service tempService = transformServiceRestrictionToService(serviceRestriction);

			// Check consistency using ServiceRepoService
			String consistencyReason = serviceRepoService.checkConsistencyReason(tempService);
			if (consistencyReason != null) {
				return "ServiceOrderItem " + orderItem.getId() + ": " + consistencyReason;
			}
		}

		return null; // All ServiceRestrictions are consistent
	}

	/**
	 * Checks the consistency of all ServiceRestriction elements in a ServiceOrder.
	 *
	 * @param serviceOrder The ServiceOrder to check
	 * @return true if all ServiceRestrictions are consistent, false otherwise
	 */
	@Transactional
	public boolean checkConsistency(ServiceOrder serviceOrder) {
		String reason = checkConsistencyReason(serviceOrder);
		if (reason != null) {
			logger.warn("checkConsistency: " + reason);
			return false;
		}
		logger.debug("checkConsistency: ServiceOrder " + (serviceOrder != null ? serviceOrder.getId() : "null") + " is consistent");
		return true;
	}

	/**
	 * Transforms a ServiceRestriction to a Service object for consistency checking.
	 * Maps the relevant fields from ServiceRestriction to Service.
	 *
	 * @param serviceRestriction The ServiceRestriction to transform
	 * @return A Service object with the same ServiceSpecificationRef and ServiceCharacteristics
	 */
	private org.etsi.osl.tmf.sim638.model.Service transformServiceRestrictionToService(ServiceRestriction serviceRestriction) {
		org.etsi.osl.tmf.sim638.model.Service service = new org.etsi.osl.tmf.sim638.model.Service();

		// Map ServiceSpecificationRef
		if (serviceRestriction.getServiceSpecification() != null) {
			service.setServiceSpecificationRef(serviceRestriction.getServiceSpecification());
		}

		// Map ServiceCharacteristics
		if (serviceRestriction.getServiceCharacteristic() != null) {
			service.getServiceCharacteristic().addAll(serviceRestriction.getServiceCharacteristic());
		}

		return service;
	}

}
+5 −5
Original line number Diff line number Diff line
@@ -273,7 +273,7 @@ public class ServiceCatalogIntegrationTest extends BaseIT {
		ServiceSpecification responsesSpec = JsonUtils.toJsonObj(response,  ServiceSpecification.class);
		assertThat( responsesSpec.getName() ).isEqualTo( "Test Spec" );

		assertThat( responsesSpec.getServiceSpecCharacteristic().size() ).isEqualTo(2);
		assertThat( responsesSpec.getServiceSpecCharacteristic().size() ).isEqualTo(9);
		assertThat( responsesSpec.getServiceSpecCharacteristic().toArray( new ServiceSpecCharacteristic[0] )[0].getServiceSpecCharacteristicValue().size()  ).isEqualTo(1);

        assertThat( categRepoService.findAll().size() ).isEqualTo( 2 );
@@ -485,7 +485,7 @@ public class ServiceCatalogIntegrationTest extends BaseIT {
		ServiceSpecification responsesSpec2 = JsonUtils.toJsonObj(response2,  ServiceSpecification.class);
		assertThat( responsesSpec2.getName() ).isEqualTo( "Test Spec a attr" );
		assertThat( responsesSpec2.getVersion() ).isEqualTo( "2.x" );
		assertThat( responsesSpec2.getServiceSpecCharacteristic().size() ).isEqualTo(3);
		assertThat( responsesSpec2.getServiceSpecCharacteristic().size() ).isEqualTo(10);
		assertThat( responsesSpec2.getServiceSpecCharacteristic().toArray( new ServiceSpecCharacteristic[0] )[0].getServiceSpecCharacteristicValue().size()  ).isEqualTo(1);
		assertThat( responsesSpec2.findSpecCharacteristicByName("Coverage")   ).isNotNull();
		assertThat( responsesSpec2.findSpecCharacteristicByName("A new characteristic")   ).isNotNull();
@@ -546,7 +546,7 @@ public class ServiceCatalogIntegrationTest extends BaseIT {
		assertThat( specRepoService.findAll().size() ).isEqualTo( 33 );
		
		assertThat( responsesSpec2.getName() ).isEqualTo( "Test Spec" );
		assertThat( responsesSpec2.getServiceSpecCharacteristic().size() ).isEqualTo(2);
		assertThat( responsesSpec2.getServiceSpecCharacteristic().size() ).isEqualTo(9);
		assertThat( responsesSpec2.findSpecCharacteristicByName("Coverage")   ).isNotNull();
		assertThat( responsesSpec2.findSpecCharacteristicByName("Coverage").getServiceSpecCharacteristicValue().size()  ).isEqualTo(2);
		boolean secvalExists = false;
@@ -1167,7 +1167,7 @@ public class ServiceCatalogIntegrationTest extends BaseIT {
		ServiceSpecification responsesSpec1 = createServiceSpec(sspectext, sspeccr1);		

		assertThat( specRepoService.findAll().size() ).isEqualTo( 27 );
		assertThat( responsesSpec1.getServiceSpecCharacteristic()).hasSize(2) ;
		assertThat( responsesSpec1.getServiceSpecCharacteristic()).hasSize(9) ;
		
		/**
		 * we use responsesSpec1 as base to add another ServiceSpecification example from an external partner 
@@ -1189,7 +1189,7 @@ public class ServiceCatalogIntegrationTest extends BaseIT {
		ServiceSpecification specupd = specRepoService.updateExternalServiceSpec(externaluuid, o.getId(), responsesSpec1);
		assertThat( specRepoService.findAll().size() ).isEqualTo( 28 );
		assertThat( specupd.getRelatedParty()).hasSize(1);
		assertThat( specupd.getServiceSpecCharacteristic()).hasSize(2) ;
		assertThat( specupd.getServiceSpecCharacteristic()).hasSize(9) ;
		
		responsesSpec1.setName( responsesSpec1.getName() + "_NEWNAME");
		
Loading