All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.activiti.engine.impl.bpmn.parser.BpmnParse Maven / Gradle / Ivy

The newest version!
/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.activiti.engine.impl.bpmn.parser;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.activiti.bpmn.constants.BpmnXMLConstants;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.exceptions.XMLException;
import org.activiti.bpmn.model.BoundaryEvent;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.Event;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.GraphicInfo;
import org.activiti.bpmn.model.Import;
import org.activiti.bpmn.model.Interface;
import org.activiti.bpmn.model.Message;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.SubProcess;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.impl.bpmn.data.ClassStructureDefinition;
import org.activiti.engine.impl.bpmn.data.ItemDefinition;
import org.activiti.engine.impl.bpmn.data.ItemKind;
import org.activiti.engine.impl.bpmn.data.StructureDefinition;
import org.activiti.engine.impl.bpmn.parser.factory.ActivityBehaviorFactory;
import org.activiti.engine.impl.bpmn.parser.factory.ListenerFactory;
import org.activiti.engine.impl.bpmn.webservice.BpmnInterface;
import org.activiti.engine.impl.bpmn.webservice.BpmnInterfaceImplementation;
import org.activiti.engine.impl.bpmn.webservice.MessageDefinition;
import org.activiti.engine.impl.bpmn.webservice.Operation;
import org.activiti.engine.impl.bpmn.webservice.OperationImplementation;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.el.ExpressionManager;
import org.activiti.engine.impl.persistence.entity.DeploymentEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.HasDIBounds;
import org.activiti.engine.impl.pvm.process.ScopeImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.impl.util.ReflectUtil;
import org.activiti.engine.impl.util.io.InputStreamSource;
import org.activiti.engine.impl.util.io.ResourceStreamSource;
import org.activiti.engine.impl.util.io.StreamSource;
import org.activiti.engine.impl.util.io.StringStreamSource;
import org.activiti.engine.impl.util.io.UrlStreamSource;
import org.activiti.validation.ProcessValidator;
import org.activiti.validation.ValidationError;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Specific parsing of one BPMN 2.0 XML file, created by the {@link BpmnParser}.
 * 
 * @author Tijs Rademakers
 * @author Joram Barrez
 */
public class BpmnParse implements BpmnXMLConstants {

  protected static final Logger LOGGER = LoggerFactory.getLogger(BpmnParse.class);

  public static final String PROPERTYNAME_INITIAL = "initial";
  public static final String PROPERTYNAME_INITIATOR_VARIABLE_NAME = "initiatorVariableName";
  public static final String PROPERTYNAME_CONDITION = "condition";
  public static final String PROPERTYNAME_CONDITION_TEXT = "conditionText";
  public static final String PROPERTYNAME_TIMER_DECLARATION = "timerDeclarations";
  public static final String PROPERTYNAME_ISEXPANDED = "isExpanded";
  public static final String PROPERTYNAME_START_TIMER = "timerStart";
  public static final String PROPERTYNAME_COMPENSATION_HANDLER_ID = "compensationHandler";
  public static final String PROPERTYNAME_IS_FOR_COMPENSATION = "isForCompensation";
  public static final String PROPERTYNAME_ERROR_EVENT_DEFINITIONS = "errorEventDefinitions";
  public static final String PROPERTYNAME_EVENT_SUBSCRIPTION_DECLARATION = "eventDefinitions";

  protected String name;

  protected boolean validateSchema = true;
  protected boolean validateProcess = true;
  
  protected StreamSource streamSource;
  protected String sourceSystemId;

  protected BpmnModel bpmnModel;

  protected String targetNamespace;

  /** The deployment to which the parsed process definitions will be added. */
  protected DeploymentEntity deployment;

  /** The end result of the parsing: a list of process definition. */
  protected List processDefinitions = new ArrayList();

  /** A map for storing sequence flow based on their id during parsing. */
  protected Map sequenceFlows;

  protected BpmnParseHandlers bpmnParserHandlers;

  protected ProcessDefinitionEntity currentProcessDefinition;

  protected FlowElement currentFlowElement;

  protected ActivityImpl currentActivity;

  protected LinkedList currentSubprocessStack = new LinkedList();

  protected LinkedList currentScopeStack = new LinkedList();

  /**
   * Mapping containing values stored during the first phase of parsing since
   * other elements can reference these messages.
   * 
   * All the map's elements are defined outside the process definition(s), which
   * means that this map doesn't need to be re-initialized for each new process
   * definition.
   */
  protected Map messages = new HashMap();
  protected Map structures = new HashMap();
  protected Map interfaceImplementations = new HashMap();
  protected Map operationImplementations = new HashMap();
  protected Map itemDefinitions = new HashMap();
  protected Map bpmnInterfaces = new HashMap();
  protected Map operations = new HashMap();

    protected Map importers;
  protected Map prefixs = new HashMap();

  // Factories
  protected ExpressionManager expressionManager;
  protected ActivityBehaviorFactory activityBehaviorFactory;
  protected ListenerFactory listenerFactory;

  /**
   * Constructor to be called by the {@link BpmnParser}.
   */
  public BpmnParse(BpmnParser parser) {
    this.expressionManager = parser.getExpressionManager();
    this.activityBehaviorFactory = parser.getActivityBehaviorFactory();
    this.listenerFactory = parser.getListenerFactory();
    this.bpmnParserHandlers = parser.getBpmnParserHandlers();
        this.importers = parser.getImporters();
    this.initializeXSDItemDefinitions();
  }

  protected void initializeXSDItemDefinitions() {
    this.itemDefinitions.put("http://www.w3.org/2001/XMLSchema:string", new ItemDefinition("http://www.w3.org/2001/XMLSchema:string",
            new ClassStructureDefinition(String.class)));
  }

  public BpmnParse deployment(DeploymentEntity deployment) {
    this.deployment = deployment;
    return this;
  }
  
  public BpmnParse execute() {
    try {

    	ProcessEngineConfigurationImpl processEngineConfiguration = Context.getProcessEngineConfiguration();
      BpmnXMLConverter converter = new BpmnXMLConverter();
      
      boolean enableSafeBpmnXml = false;
      String encoding = null;
      if (processEngineConfiguration != null) {
        enableSafeBpmnXml = processEngineConfiguration.isEnableSafeBpmnXml();
        encoding = processEngineConfiguration.getXmlEncoding();
      }
      
      if (encoding != null) {
        bpmnModel = converter.convertToBpmnModel(streamSource, validateSchema, enableSafeBpmnXml, encoding);
      } else {
        bpmnModel = converter.convertToBpmnModel(streamSource, validateSchema, enableSafeBpmnXml);
      }
      
      // XSD validation goes first, then process/semantic validation
      if (validateProcess) {
      	ProcessValidator processValidator = processEngineConfiguration.getProcessValidator();
      	if (processValidator == null) {
      		LOGGER.warn("Process should be validated, but no process validator is configured on the process engine configuration!");
      	} else {
      		List validationErrors = processValidator.validate(bpmnModel);
      		if(validationErrors != null && !validationErrors.isEmpty()) {
      			
      			StringBuilder warningBuilder = new StringBuilder();
	      		StringBuilder errorBuilder = new StringBuilder();
	      		
	          for (ValidationError error : validationErrors) {
	          	if (error.isWarning()) {
	          		warningBuilder.append(error.toString());
	          		warningBuilder.append("\n");
	          	} else {
	          		errorBuilder.append(error.toString());
	          		errorBuilder.append("\n");
	          	}
	          }
	           
	          // Throw exception if there is any error
	          if (errorBuilder.length() > 0) {
	          	throw new ActivitiException("Errors while parsing:\n" + errorBuilder.toString());
	          }
	          
	          // Write out warnings (if any)
	          if (warningBuilder.length() > 0) {
	          	LOGGER.warn("Following warnings encountered during process validation: " + warningBuilder.toString());
	          }
	          
      		}
      	}
      }
      
      // Validation successfull (or no validation)
      createImports();
      createItemDefinitions();
      createMessages();
      createOperations();
      transformProcessDefinitions();
      
    } catch (Exception e) {
      if (e instanceof ActivitiException) {
        throw (ActivitiException) e;
      } else if (e instanceof XMLException) {
        throw (XMLException) e;
      } else {
        throw new ActivitiException("Error parsing XML", e);
      }
    }

    return this;
  }

  public BpmnParse name(String name) {
    this.name = name;
    return this;
  }

  public BpmnParse sourceInputStream(InputStream inputStream) {
    if (name == null) {
      name("inputStream");
    }
    setStreamSource(new InputStreamSource(inputStream));
    return this;
  }

  public BpmnParse sourceResource(String resource) {
    return sourceResource(resource, null);
  }

  public BpmnParse sourceUrl(URL url) {
    if (name == null) {
      name(url.toString());
    }
    setStreamSource(new UrlStreamSource(url));
    return this;
  }

  public BpmnParse sourceUrl(String url) {
    try {
      return sourceUrl(new URL(url));
    } catch (MalformedURLException e) {
      throw new ActivitiIllegalArgumentException("malformed url: " + url, e);
    }
  }

  public BpmnParse sourceResource(String resource, ClassLoader classLoader) {
    if (name == null) {
      name(resource);
    }
    setStreamSource(new ResourceStreamSource(resource, classLoader));
    return this;
  }

  public BpmnParse sourceString(String string) {
    if (name == null) {
      name("string");
    }
    setStreamSource(new StringStreamSource(string));
    return this;
  }

  protected void setStreamSource(StreamSource streamSource) {
    if (this.streamSource != null) {
      throw new ActivitiIllegalArgumentException("invalid: multiple sources " + this.streamSource + " and " + streamSource);
    }
    this.streamSource = streamSource;
  }

  protected void createImports() {
    for (Import theImport : bpmnModel.getImports()) {
      XMLImporter importer = this.getImporter(theImport);
      if (importer == null) {
        throw new ActivitiException("Could not import item of type " + theImport.getImportType());
      } else {
        importer.importFrom(theImport, this);
      }
    }
  }

  protected XMLImporter getImporter(Import theImport) {
    if (this.importers.containsKey(theImport.getImportType())) {
      return this.importers.get(theImport.getImportType());
    } else {
      return null;
    }
  }

  public void createMessages() {
    for (Message messageElement : bpmnModel.getMessages()) {
      MessageDefinition messageDefinition = new MessageDefinition(messageElement.getId(), name);
      if (StringUtils.isNotEmpty(messageElement.getItemRef())) {
        if (this.itemDefinitions.containsKey(messageElement.getItemRef())) {
          ItemDefinition itemDefinition = this.itemDefinitions.get(messageElement.getItemRef());
          messageDefinition.setItemDefinition(itemDefinition);
        }
      }
      this.messages.put(messageDefinition.getId(), messageDefinition);

    }
  }

  protected void createItemDefinitions() {
    for (org.activiti.bpmn.model.ItemDefinition itemDefinitionElement : bpmnModel.getItemDefinitions().values()) {
      StructureDefinition structure = null;

      try {
        // it is a class
        Class< ? > classStructure = ReflectUtil.loadClass(itemDefinitionElement.getStructureRef());
        structure = new ClassStructureDefinition(classStructure);
      } catch (ActivitiException e) {
        // it is a reference to a different structure
        structure = this.structures.get(itemDefinitionElement.getStructureRef());
      }

      ItemDefinition itemDefinition = new ItemDefinition(itemDefinitionElement.getId(), structure);
      if (StringUtils.isNotEmpty(itemDefinitionElement.getItemKind())) {
        itemDefinition.setItemKind(ItemKind.valueOf(itemDefinitionElement.getItemKind()));
      }
      itemDefinitions.put(itemDefinition.getId(), itemDefinition);
    }
  }

  protected void createOperations() {
    for (Interface interfaceObject : bpmnModel.getInterfaces()) {
      BpmnInterface bpmnInterface = new BpmnInterface(interfaceObject.getId(), interfaceObject.getName());
      bpmnInterface.setImplementation(this.interfaceImplementations.get(interfaceObject.getImplementationRef()));

      for (org.activiti.bpmn.model.Operation operationObject : interfaceObject.getOperations()) {
        if (this.messages.containsKey(operationObject.getInMessageRef())) {
          MessageDefinition inMessage = this.messages.get(operationObject.getInMessageRef());
          Operation operation = new Operation(operationObject.getId(), operationObject.getName(), bpmnInterface, inMessage);
          operation.setImplementation(this.operationImplementations.get(operationObject.getImplementationRef()));

          if (StringUtils.isNotEmpty(operationObject.getOutMessageRef())) {
            if (this.messages.containsKey(operationObject.getOutMessageRef())) {
              MessageDefinition outMessage = this.messages.get(operationObject.getOutMessageRef());
              operation.setOutMessage(outMessage);
            }
          }

          operations.put(operation.getId(), operation);
        }
      }
    }
  }

  /**
   * Parses the 'definitions' root element
   */
  protected void transformProcessDefinitions() {
    sequenceFlows = new HashMap();
    for (Process process : bpmnModel.getProcesses()) {
      if (process.isExecutable()) {
        bpmnParserHandlers.parseElement(this, process);
      }
    }

    if (!processDefinitions.isEmpty()) {
      processDI();
    }
  }

  public void processFlowElements(Collection flowElements) {

    // Parsing the elements is done in a strict order of types,
    // as otherwise certain information might not be available when parsing a
    // certain type.
    
    // Using lists as we want to keep the order in which they are defined
    List sequenceFlowToParse = new ArrayList();
    List boundaryEventsToParse = new ArrayList();
    
    // Flow elements that depend on other elements are parse after the first run-through
    List defferedFlowElementsToParse = new ArrayList();

    // Activities are parsed first
    for (FlowElement flowElement : flowElements) {

      // Sequence flow are also flow elements, but are only parsed once everyactivity is found
      if (flowElement instanceof SequenceFlow) {
        sequenceFlowToParse.add((SequenceFlow) flowElement);
      } else if (flowElement instanceof BoundaryEvent) {
        boundaryEventsToParse.add((BoundaryEvent) flowElement);
      } else if (flowElement instanceof Event) {
        defferedFlowElementsToParse.add(flowElement);
      } else {
        bpmnParserHandlers.parseElement(this, flowElement);
      }

    }
    
    // Deferred elements
    for (FlowElement flowElement : defferedFlowElementsToParse) {
      bpmnParserHandlers.parseElement(this, flowElement);
    }

    // Boundary events are parsed after all the regular activities are parsed
    for (BoundaryEvent boundaryEvent : boundaryEventsToParse) {
      bpmnParserHandlers.parseElement(this, boundaryEvent);
    }

    // sequence flows
    for (SequenceFlow sequenceFlow : sequenceFlowToParse) {
      bpmnParserHandlers.parseElement(this, sequenceFlow);
    }
   
  }

  // Diagram interchange
  // /////////////////////////////////////////////////////////////////

  public void processDI() {
    if (!bpmnModel.getLocationMap().isEmpty()) {

      // Verify if all referenced elements exist
      for (String bpmnReference : bpmnModel.getLocationMap().keySet()) {
        if (bpmnModel.getFlowElement(bpmnReference) == null) {
        	// ACT-1625: don't warn when	artifacts are referenced from DI
        	if (bpmnModel.getArtifact(bpmnReference) == null) {
        	  // check if it's a Pool or Lane, then DI is ok
            if (bpmnModel.getPool(bpmnReference) == null && bpmnModel.getLane(bpmnReference) == null) {
              LOGGER.warn("Invalid reference in diagram interchange definition: could not find " + bpmnReference);
            }
        	}
        } else if (! (bpmnModel.getFlowElement(bpmnReference) instanceof FlowNode)) {
          LOGGER.warn("Invalid reference in diagram interchange definition: " + bpmnReference + " does not reference a flow node");
        }
      }
      for (String bpmnReference : bpmnModel.getFlowLocationMap().keySet()) {
        if (bpmnModel.getFlowElement(bpmnReference) == null) {
          // ACT-1625: don't warn when	artifacts are referenced from DI
        	if (bpmnModel.getArtifact(bpmnReference) == null) {
        		LOGGER.warn("Invalid reference in diagram interchange definition: could not find " + bpmnReference);
        	}	
        } else if (! (bpmnModel.getFlowElement(bpmnReference) instanceof SequenceFlow)) {
          LOGGER.warn("Invalid reference in diagram interchange definition: " + bpmnReference + " does not reference a sequence flow");
        }
      }
      
      for (Process process : bpmnModel.getProcesses()) {
        if (!process.isExecutable()) {
          continue;
        }
        
        // Parse diagram interchange information
        ProcessDefinitionEntity processDefinition = getProcessDefinition(process.getId());
        if (processDefinition != null) {
          processDefinition.setGraphicalNotationDefined(true);
          for (String shapeId : bpmnModel.getLocationMap().keySet()) {
            if (processDefinition.findActivity(shapeId) != null) {
              createBPMNShape(shapeId, bpmnModel.getGraphicInfo(shapeId), processDefinition);
            }
          }

          for (String edgeId : bpmnModel.getFlowLocationMap().keySet()) {
            if (bpmnModel.getFlowElement(edgeId) != null) {
              createBPMNEdge(edgeId, bpmnModel.getFlowLocationGraphicInfo(edgeId));
            }
          }
        }
      }
    }
  }
  
  public void createBPMNShape(String key, GraphicInfo graphicInfo, ProcessDefinitionEntity processDefinition) {
    ActivityImpl activity = processDefinition.findActivity(key);
    if (activity != null) {
      createDIBounds(graphicInfo, activity);

    } else {
      org.activiti.engine.impl.pvm.process.Lane lane = processDefinition.getLaneForId(key);

      if (lane != null) {
        // The shape represents a lane
        createDIBounds(graphicInfo, lane);
      }
    }
  }

  protected void createDIBounds(GraphicInfo graphicInfo, HasDIBounds target) {
    target.setX((int) graphicInfo.getX());
    target.setY((int) graphicInfo.getY());
    target.setWidth((int) graphicInfo.getWidth());
    target.setHeight((int) graphicInfo.getHeight());
  }

  public void createBPMNEdge(String key, List graphicList) {
    FlowElement flowElement = bpmnModel.getFlowElement(key);
    if (flowElement != null && sequenceFlows.containsKey(key)) {
      TransitionImpl sequenceFlow = sequenceFlows.get(key);
      List waypoints = new ArrayList();
      for (GraphicInfo waypointInfo : graphicList) {
        waypoints.add((int) waypointInfo.getX());
        waypoints.add((int) waypointInfo.getY());
      }
      sequenceFlow.setWaypoints(waypoints);
    } else if (bpmnModel.getArtifact(key) != null) {
      // it's an association, so nothing to do
    } else {
      LOGGER.warn("Invalid reference in 'bpmnElement' attribute, sequenceFlow " + key + " not found");
    }
  }

  public ProcessDefinitionEntity getProcessDefinition(String processDefinitionKey) {
    for (ProcessDefinitionEntity processDefinition : processDefinitions) {
      if (processDefinition.getKey().equals(processDefinitionKey)) {
        return processDefinition;
      }
    }
    return null;
  }

  public void addStructure(StructureDefinition structure) {
    this.structures.put(structure.getId(), structure);
  }

  public void addService(BpmnInterfaceImplementation bpmnInterfaceImplementation) {
    this.interfaceImplementations.put(bpmnInterfaceImplementation.getName(), bpmnInterfaceImplementation);
  }

  public void addOperation(OperationImplementation operationImplementation) {
    this.operationImplementations.put(operationImplementation.getId(), operationImplementation);
  }

  /*
   * ------------------- GETTERS AND SETTERS -------------------
   */
  
  public boolean isValidateSchema() {
		return validateSchema;
	}

	public void setValidateSchema(boolean validateSchema) {
		this.validateSchema = validateSchema;
	}

	public boolean isValidateProcess() {
		return validateProcess;
	}

	public void setValidateProcess(boolean validateProcess) {
		this.validateProcess = validateProcess;
	}
	
	public List getProcessDefinitions() {
		return processDefinitions;
	}

	public String getTargetNamespace() {
    return targetNamespace;
  }

  public BpmnParseHandlers getBpmnParserHandlers() {
    return bpmnParserHandlers;
  }

  public void setBpmnParserHandlers(BpmnParseHandlers bpmnParserHandlers) {
    this.bpmnParserHandlers = bpmnParserHandlers;
  }

  public DeploymentEntity getDeployment() {
    return deployment;
  }

  public void setDeployment(DeploymentEntity deployment) {
    this.deployment = deployment;
  }

  public BpmnModel getBpmnModel() {
    return bpmnModel;
  }

  public void setBpmnModel(BpmnModel bpmnModel) {
    this.bpmnModel = bpmnModel;
  }

  public ActivityBehaviorFactory getActivityBehaviorFactory() {
    return activityBehaviorFactory;
  }

  public void setActivityBehaviorFactory(ActivityBehaviorFactory activityBehaviorFactory) {
    this.activityBehaviorFactory = activityBehaviorFactory;
  }

  public ListenerFactory getListenerFactory() {
    return listenerFactory;
  }

  public void setListenerFactory(ListenerFactory listenerFactory) {
    this.listenerFactory = listenerFactory;
  }

  public ExpressionManager getExpressionManager() {
    return expressionManager;
  }

  public void setExpressionManager(ExpressionManager expressionManager) {
    this.expressionManager = expressionManager;
  }

  public Map getSequenceFlows() {
    return sequenceFlows;
  }

  public Map getMessages() {
    return messages;
  }

  public Map getInterfaceImplementations() {
    return interfaceImplementations;
  }

  public Map getItemDefinitions() {
    return itemDefinitions;
  }

  public Map getImporters() {
    return importers;
  }

  public Map getOperations() {
    return operations;
  }

  public void setOperations(Map operations) {
    this.operations = operations;
  }

  public ProcessDefinitionEntity getCurrentProcessDefinition() {
    return currentProcessDefinition;
  }

  public void setCurrentProcessDefinition(ProcessDefinitionEntity currentProcessDefinition) {
    this.currentProcessDefinition = currentProcessDefinition;
  }

  public FlowElement getCurrentFlowElement() {
    return currentFlowElement;
  }

  public void setCurrentFlowElement(FlowElement currentFlowElement) {
    this.currentFlowElement = currentFlowElement;
  }

  public ActivityImpl getCurrentActivity() {
    return currentActivity;
  }

  public void setCurrentActivity(ActivityImpl currentActivity) {
    this.currentActivity = currentActivity;
  }

  public void setCurrentSubProcess(SubProcess subProcess) {
    currentSubprocessStack.push(subProcess);
  }

  public SubProcess getCurrentSubProcess() {
    return currentSubprocessStack.peek();
  }

  public void removeCurrentSubProcess() {
    currentSubprocessStack.pop();
  }

  public void setCurrentScope(ScopeImpl scope) {
    currentScopeStack.push(scope);
  }

  public ScopeImpl getCurrentScope() {
    return currentScopeStack.peek();
  }

  public void removeCurrentScope() {
    currentScopeStack.pop();
  }
  
  public BpmnParse setSourceSystemId(String systemId) {
    sourceSystemId = systemId;
    return this;
  }
  
  public String getSourceSystemId() {
    return this.sourceSystemId;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy