METRICO integration

Closes #29 (closed)

Merge request reports

Loading
+2 −0
Changes for src/main/java/org/etsi/osl/osom/management/AutomationCheck.java: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -89,6 +89,8 @@ public class AutomationCheck implements JavaDelegate {
				execution.setVariable("brokeActivity", "RFS_OSM" ); 						
			}  else if ( spec.getType().equals("ResourceFacingServiceSpecification") &&  ( spec.findSpecCharacteristicByName( "_CR_SPEC" ) != null ) ) {
				execution.setVariable("brokeActivity", "RFS_CRSPEC" );
			}  else if ( spec.getType().equals("ResourceFacingServiceSpecification") &&  ( spec.findSpecCharacteristicByName( "_MT_QUERY" ) != null ) ) {
				 execution.setVariable("brokeActivity", "RFS_MTSPEC" );
			} else if ( spec.getType().equals("ResourceFacingServiceSpecification") ) {
              execution.setVariable("brokeActivity", "GRSPEC" );                      
          }		
+95 −0
Changes for src/main/java/org/etsi/osl/osom/management/MetricoOrchestrationCheckDeploymentService.java: 95 added lines, 0 removed lines.
Original line number Diff line number Diff line
package org.etsi.osl.osom.management;

import jakarta.validation.Valid;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.etsi.osl.tmf.common.model.service.Note;
import org.etsi.osl.tmf.common.model.service.ResourceRef;
import org.etsi.osl.tmf.common.model.service.ServiceStateType;
import org.etsi.osl.tmf.ri639.model.Resource;
import org.etsi.osl.tmf.sim638.model.Service;
import org.etsi.osl.tmf.sim638.model.ServiceUpdate;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;

@Component(value = "metricoOrchestrationCheckDeploymentService")
public class MetricoOrchestrationCheckDeploymentService implements JavaDelegate {
    private static final transient Log logger = LogFactory.getLog(MetricoOrchestrationCheckDeploymentService.class.getName());

    @Autowired
    private ServiceOrderManager serviceOrderManager;


    @Value("${spring.application.name}")
    private String compname;

    @Override
    public void execute(DelegateExecution execution) {

        logger.info( "MetricoOrchestrationCheckDeploymentService" );
        logger.info( execution.getVariableNames().toString() );

        if ( execution.getVariable("contextServiceId") == null) {

            logger.error( "Variable contextServiceId is NULL!" );
            execution.setVariable("serviceDeploymentFinished", Boolean.TRUE );
            return;
        }
        Service aService = serviceOrderManager.retrieveService( (String) execution.getVariable("contextServiceId") );

        if ( aService == null ) {
            logger.info( "aService is null for contextServiceId = " +(String) execution.getVariable("contextServiceId") );
            execution.setVariable("serviceDeploymentFinished", Boolean.TRUE );
            return;
        }

        execution.setVariable("serviceDeploymentFinished", Boolean.FALSE );
        ServiceUpdate supd = new ServiceUpdate();
        boolean propagateToSO = false;

        List<Resource> rlist = new ArrayList<Resource>();
        for (ResourceRef rref : aService.getSupportingResource()) {
            Resource res = serviceOrderManager.retrieveResource(rref.getId());

            if (  res == null ) {
                supd.setState( ServiceStateType.TERMINATED);
                execution.setVariable("serviceDeploymentFinished", Boolean.TRUE);
                Service serviceResult = serviceOrderManager.updateService( aService.getId(), supd, propagateToSO );
                return;
            }
            rlist.add(res);
        }
        @Valid
        ServiceStateType currentState = aService.getState();
        ServiceStateType nextState = aService.findNextStateBasedOnResourceList(rlist);

        if (!currentState.equals(nextState)) {
            supd.setState( nextState );
            Note n = new Note();
            n.setText("Service Status Changed to: " +  nextState);
            n.setAuthor(compname);
            n.setDate(OffsetDateTime.now(ZoneOffset.UTC).toString());
            supd.addNoteItem(n);
            aService = serviceOrderManager.updateService( aService.getId(), supd, propagateToSO );
        }

        if ( aService!= null ) {
            if ( aService.getState().equals(ServiceStateType.ACTIVE)
                    || aService.getState().equals(ServiceStateType.TERMINATED)) {

                logger.info("Deployment Status OK. Service state = " + aService.getState() );
                execution.setVariable("serviceDeploymentFinished", Boolean.TRUE);
                return;
            }
        }
        logger.info("Wait For Deployment Status. ");
    }
}
+266 −0
Changes for src/main/java/org/etsi/osl/osom/management/MetricoOrchestrationService.java: 266 added lines, 0 removed lines.
Original line number Diff line number Diff line
package org.etsi.osl.osom.management;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.camel.ProducerTemplate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.etsi.osl.tmf.common.model.service.Characteristic;
import org.etsi.osl.tmf.common.model.service.Note;
import org.etsi.osl.tmf.common.model.service.ResourceRef;
import org.etsi.osl.tmf.common.model.service.ServiceStateType;
import org.etsi.osl.tmf.common.model.Any;
import org.etsi.osl.tmf.pm628.model.*;
import org.etsi.osl.tmf.rcm634.model.ResourceSpecificationRef;
import org.etsi.osl.tmf.ri639.model.Resource;
import org.etsi.osl.tmf.ri639.model.ResourceCreate;
import org.etsi.osl.tmf.ri639.model.ResourceStatusType;
import org.etsi.osl.tmf.scm633.model.ServiceSpecification;
import org.etsi.osl.tmf.sim638.model.Service;
import org.etsi.osl.tmf.sim638.model.ServiceUpdate;
import org.etsi.osl.tmf.so641.model.ServiceOrder;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;

@Component(value = "metricoOrchestrationService") //bean name
public class MetricoOrchestrationService implements JavaDelegate {

	private static final transient Log logger = LogFactory.getLog(MetricoOrchestrationService.class.getName());

	
	
	@Value("${spring.application.name}")
	private String compname;
	
	
	@Autowired
	private ServiceOrderManager serviceOrderManager;
	

    @Override
    public void execute(DelegateExecution execution) {
		ServiceOrder sorder = serviceOrderManager.retrieveServiceOrder(execution.getVariable("orderid").toString());
		ServiceUpdate su = new ServiceUpdate();// the object to update the service
		Service aService = serviceOrderManager.retrieveService((String) execution.getVariable("contextServiceId"));
		logger.info("Service name:" + aService.getName());
		logger.info("Service state:" + aService.getState());
		logger.info("Request to TMF628 for Service: " + aService.getId());


		ServiceSpecification spec = serviceOrderManager.retrieveServiceSpec(aService.getServiceSpecificationRef().getId());

		if (spec != null) {

			Characteristic serviceCharacteristic;
			MeasurementCollectionJobFVO mcjFVO = new MeasurementCollectionJobFVO();
            mcjFVO.setCreationTime( OffsetDateTime.now());
            mcjFVO.setLastModifiedTime( OffsetDateTime.now());

			mcjFVO.setProducingApplicationId(aService.getId());

			serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_CHARACTERISTIC_NAME");
			String characteristicName = String.valueOf(serviceCharacteristic.getValue().getValue());
			mcjFVO.setOutputFormat(characteristicName);

			serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_SERVICEUUID");
			String cfs_id = String.valueOf(serviceCharacteristic.getValue().getValue());
			mcjFVO.setConsumingApplicationId(cfs_id);

			serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_END_TIME");
			String endTimeString = 	String.valueOf(serviceCharacteristic.getValue().getValue());
			ScheduleDefinitionFVO scheduleDefinition = new ScheduleDefinitionFVO();
			if (endTimeString != null && !endTimeString.equals("")) {
				OffsetDateTime endTime = convertStringToOffsetDateTime(endTimeString, DateTimeFormat.ISO.DATE_TIME );
				scheduleDefinition.setScheduleDefinitionEndTime(endTime);
			} else{
				OffsetDateTime endTime = OffsetDateTime.now().plusHours(1);
				scheduleDefinition.setScheduleDefinitionEndTime(endTime);
			}

			serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_START_TIME");
			String startTimeString = String.valueOf(serviceCharacteristic.getValue().getValue());
			if (startTimeString != null&& !startTimeString.equals("")) {
				OffsetDateTime startTime = convertStringToOffsetDateTime(startTimeString, DateTimeFormat.ISO.DATE_TIME );
				scheduleDefinition.setScheduleDefinitionStartTime(startTime);
			} else{
				OffsetDateTime startTime = OffsetDateTime.now();
				scheduleDefinition.setScheduleDefinitionStartTime(startTime);
			}
			List<ScheduleDefinitionFVO> scheduleDefinitions = new ArrayList<>();
			scheduleDefinitions.add(scheduleDefinition);
			mcjFVO.setScheduleDefinition(scheduleDefinitions);

			serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_RECURRING_INTERVAL");
			String recurringIntervalString = String.valueOf(serviceCharacteristic.getValue().getValue());
			if (recurringIntervalString != null) {
				if (Granularity.contains(recurringIntervalString)){
					Granularity recurringInterval = Granularity.valueOf(recurringIntervalString.toUpperCase());
					mcjFVO.setGranularity(recurringInterval);
				} else {
					logger.error("Invalid _MT_RECURRING_INTERVAL value. Valid values are:" + Granularity.getPossibleValues() + " It will be set to 1 minute.");
					Granularity recurringInterval = Granularity.G_1MN;
					mcjFVO.setGranularity(recurringInterval);
				}
			} else {
				Granularity recurringInterval = Granularity.G_1MN;
				mcjFVO.setGranularity(recurringInterval);
			}

			serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_TYPE");
			String monitoringType = String.valueOf(serviceCharacteristic.getValue().getValue());
			DataAccessEndpointFVO dataAccessEndpoint = new DataAccessEndpointFVO();
			dataAccessEndpoint.setApiType(monitoringType);

			serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_QUERY");
			String monitoringQuery = String.valueOf(serviceCharacteristic.getValue().getValue());
			serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_URL");
			String monitoringURL = String.valueOf(serviceCharacteristic.getValue().getValue());
            try {
                URI monitoringURI = createUri(monitoringURL, monitoringQuery);
				dataAccessEndpoint.setUri(monitoringURI);
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }

			List<DataAccessEndpointFVO> dataAccessEndpoints = new ArrayList<>();
			dataAccessEndpoints.add(dataAccessEndpoint);
			mcjFVO.setDataAccessEndpoint(dataAccessEndpoints);

			MeasurementCollectionJob mcj = serviceOrderManager.addMeasurementCollectionJob(mcjFVO);

			if  (mcj != null){

				ResourceSpecificationRef resourceSpecificationRef = spec.getResourceSpecification().stream().findFirst().get();
				Resource resourceMT = createRelatedResource( resourceSpecificationRef, sorder, aService, mcj );
				ResourceRef resourceRef = new ResourceRef();

				resourceRef.setId( resourceMT.getId() );
				resourceRef.setName( resourceMT.getName());
				resourceRef.setType( resourceMT.getType());
				su.addSupportingResourceItem( resourceRef );
				su.setState(ServiceStateType.RESERVED);
				Note successNoteItem = new Note();
				successNoteItem.setText(String.format("Requesting METRICO to create a new monitoring job"));
				successNoteItem.setDate(OffsetDateTime.now(ZoneOffset.UTC).toString());
				successNoteItem.setAuthor(compname);
				su.addNoteItem(successNoteItem);

			} else {
				logger.error("Measurement Collection Job was not created.");
                su.setState(ServiceStateType.TERMINATED);
			}

            Service supd = serviceOrderManager.updateService(aService.getId(), su, false);



		}
	}





//	Methods created to use in this class
	public static OffsetDateTime convertStringToOffsetDateTime(String dateTimeString, DateTimeFormat.ISO pattern) {
		DateTimeFormatter formatter;
		switch (pattern) {
			case DATE:
				formatter = DateTimeFormatter.ISO_DATE;
				break;
			case TIME:
				formatter = DateTimeFormatter.ISO_TIME;
				break;
			case DATE_TIME:
				formatter = DateTimeFormatter.ISO_DATE_TIME;
				break;
			default:
				throw new IllegalArgumentException("Unsupported DateTimeFormat.ISO pattern");
		}
		try {
			OffsetDateTime.parse(dateTimeString, formatter);
			return OffsetDateTime.parse(dateTimeString, formatter);
		} catch (DateTimeParseException e) {
			logger.error(e.getMessage());
			return null;
		}

	}

	public static URI createUri(String url, String query) throws URISyntaxException {
		return new URI(url + "?" + query);
	}

	public static <T> T toJsonObj(String content, Class<T> valueType)  throws IOException {
		ObjectMapper mapper = new ObjectMapper();
		mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		return mapper.readValue( content, valueType);
	}

	public static <T> String toJsonString(T object) {
		ObjectMapper mapper = new ObjectMapper();
		mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		try {
			return mapper.writeValueAsString(object);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
			return null;
		}
	}



	/**
	 *
	 * The resource maps the created MCJ
	 * @param rSpecRef
	 * @param sOrder
	 * @param aService
	 * @return
	 */
	private Resource createRelatedResource(ResourceSpecificationRef rSpecRef, ServiceOrder sOrder, Service aService, MeasurementCollectionJob mcj) {

		ResourceCreate resCreate = new ResourceCreate();
		resCreate.setName(   rSpecRef.getName() + "-" + aService.getId() );
		resCreate.setStartOperatingDate( aService.getStartDate() );
		resCreate.setEndOperatingDate(aService.getEndDate());
		resCreate.setResourceStatus (ResourceStatusType.RESERVED);

		ResourceSpecificationRef rSpecRefObj = new ResourceSpecificationRef() ;
		rSpecRefObj.id(rSpecRef.getId())
				.name( rSpecRef.getName())
				.setType(rSpecRef.getType());
		resCreate.setResourceSpecification(rSpecRefObj);

		org.etsi.osl.tmf.ri639.model.Characteristic resCharacteristicItem =  new org.etsi.osl.tmf.ri639.model.Characteristic();
		resCharacteristicItem.setName( "_MT_MCJ_REF" );
		resCharacteristicItem.setValueType( "TEXT" );
		Any val = new Any();
		val.setValue( mcj.getUuid() );
		val.setAlias( mcj.getUuid() );
		resCharacteristicItem.setValue( val );
		resCreate.addResourceCharacteristicItem(  resCharacteristicItem );


		// 1) need to copy the characteristics of the Resource Specification (use this instead of @param rSpecRef) and populate them with value from the aService (see GCOrchestrationService)
		// 2) also need to populate the characteristic _MT_MCJ_REF with the UUID of the created MCJ / pass it as @param mcj

		return serviceOrderManager.createResource( resCreate, sOrder, rSpecRef.getId() );
	}

}
+27 −0
Changes for src/main/java/org/etsi/osl/osom/management/ServiceOrderManager.java: 27 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ import org.etsi.osl.model.nfv.DeploymentDescriptor;
import org.etsi.osl.model.nfv.NetworkServiceDescriptor;
import org.etsi.osl.model.nfv.ScaleDescriptor;
import org.etsi.osl.osom.serviceactions.NSActionRequestPayload;
import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJob;
import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJobFVO;
import org.etsi.osl.tmf.pm632.model.Organization;
import org.etsi.osl.tmf.rcm634.model.LogicalResourceSpecification;
import org.etsi.osl.tmf.rcm634.model.ResourceSpecification;
@@ -195,6 +197,10 @@ public class ServiceOrderManager {
    @Value("${CATALOG_GET_RESOURCESPEC_BY_ID}")
    private String CATALOG_GET_RESOURCESPEC_BY_ID = "";

    @Value("${PM_MEASUREMENT_COLLECTION_JOB_ADD}")
    private String PM_MEASUREMENT_COLLECTION_JOB_ADD = "";

    
	@Transactional
	public void processOrder(ServiceOrder serviceOrder) {

@@ -1142,6 +1148,27 @@ public class ServiceOrderManager {
  }
  
  
  public MeasurementCollectionJob addMeasurementCollectionJob(MeasurementCollectionJobFVO mcjFVO) {

    logger.debug("Will create a new Measurement Collection Job");
    try {
        Object response = template.
                requestBody( PM_MEASUREMENT_COLLECTION_JOB_ADD, toJsonString(mcjFVO));
        if ( !(response instanceof String)) {
            logger.error("Measurement Collection Job object is wrong.");
            return null;
        }
        logger.debug("retrieveMeasurementCollectionJobById response is: " + response);
        MeasurementCollectionJob mcj = toJsonObj( (String)response, MeasurementCollectionJob.class);
        return mcj;
    }catch (Exception e) {
        logger.error("Cannot create a new Measurement Collection Job. " + e.toString());
    }
    return null;
}

  



}
+71 −0
Changes for src/main/resources/processes/MetricoDeploymentReq.bpmn: 71 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="procMetricoDeploymentRequest" name="Metrico Deployment Request" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <serviceTask id="stMetricoCreateTask" name="Metrico Create Task" activiti:delegateExpression="${metricoOrchestrationService}"></serviceTask>
    <serviceTask id="stCheckMetricoServiceDeployment" name="Check METRICO Service Deployment" activiti:delegateExpression="${metricoOrchestrationCheckDeploymentService}"></serviceTask>
    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
    <intermediateCatchEvent id="timerintermediatecatchevent1" name="TimerCatchEvent">
      <timerEventDefinition>
        <timeDuration>PT30S</timeDuration>
      </timerEventDefinition>
    </intermediateCatchEvent>
    <sequenceFlow id="flow3" sourceRef="stCheckMetricoServiceDeployment" targetRef="exclusivegateway1"></sequenceFlow>
    <sequenceFlow id="flow4" sourceRef="exclusivegateway1" targetRef="timerintermediatecatchevent1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!serviceDeploymentFinished}]]></conditionExpression>
    </sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow5" sourceRef="exclusivegateway1" targetRef="endevent1"></sequenceFlow>
    <sequenceFlow id="flow6" sourceRef="timerintermediatecatchevent1" targetRef="stCheckMetricoServiceDeployment"></sequenceFlow>
    <sequenceFlow id="flow7" sourceRef="stMetricoCreateTask" targetRef="stCheckMetricoServiceDeployment"></sequenceFlow>
    <sequenceFlow id="flow8" sourceRef="startevent1" targetRef="stMetricoCreateTask"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_procMetricoDeploymentRequest">
    <bpmndi:BPMNPlane bpmnElement="procMetricoDeploymentRequest" id="BPMNPlane_procMetricoDeploymentRequest">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="120.0" y="165.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="stMetricoCreateTask" id="BPMNShape_stMetricoCreateTask">
        <omgdc:Bounds height="91.0" width="105.0" x="250.0" y="140.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="stCheckMetricoServiceDeployment" id="BPMNShape_stCheckMetricoServiceDeployment">
        <omgdc:Bounds height="91.0" width="105.0" x="500.0" y="140.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1">
        <omgdc:Bounds height="40.0" width="40.0" x="800.0" y="165.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="timerintermediatecatchevent1" id="BPMNShape_timerintermediatecatchevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="650.0" y="330.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="950.0" y="165.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="605.0" y="185.0"></omgdi:waypoint>
        <omgdi:waypoint x="800.0" y="185.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="820.0" y="205.0"></omgdi:waypoint>
        <omgdi:waypoint x="820.0" y="347.0"></omgdi:waypoint>
        <omgdi:waypoint x="685.0" y="347.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
        <omgdi:waypoint x="840.0" y="185.0"></omgdi:waypoint>
        <omgdi:waypoint x="950.0" y="182.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
        <omgdi:waypoint x="650.0" y="347.0"></omgdi:waypoint>
        <omgdi:waypoint x="552.0" y="347.0"></omgdi:waypoint>
        <omgdi:waypoint x="552.0" y="231.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
        <omgdi:waypoint x="355.0" y="185.0"></omgdi:waypoint>
        <omgdi:waypoint x="500.0" y="185.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
        <omgdi:waypoint x="155.0" y="182.0"></omgdi:waypoint>
        <omgdi:waypoint x="250.0" y="185.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
 No newline at end of file
Loading
Loading