Package org.data2semantics.platform.util

Source Code of org.data2semantics.platform.util.WorkflowParser

package org.data2semantics.platform.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.data2semantics.platform.Global;
import org.data2semantics.platform.core.Workflow;
import org.data2semantics.platform.core.data.DataType;
import org.data2semantics.platform.domain.Domain;
import org.data2semantics.platform.exception.InconsistentWorkflowException;
import org.yaml.snakeyaml.Yaml;

/**
* For now this class will parse YAML, and then produces the workflow representation
* @author wibisono
*
*/
public class WorkflowParser {

  private String workflowDescription;
  private static Yaml yaml = new Yaml();
 
  /**
   * Perhaps not only the parsed yaml file will be required here as parameter, but also what kind of wrapper.
   * @param yamlFile
   * @return
   */
  public static Workflow parseYAML(String yamlFile)
    throws IOException
  {
    return parseYAML(new File(yamlFile));
  }
 
  public static Workflow parseYAML(File yamlFile)
    throws IOException
  {
   
    Workflow.WorkflowBuilder builder = Workflow.builder();
   
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(yamlFile));
   
    // Need to create bean instead of directly working with map
    Map<?, ?> loadMap = (Map<?, ?>) yaml.load(bis);
    Map<?, ?> workflowMap = (Map<?, ?>) loadMap.get("workflow");
    ArrayList<Map<?, ?>> modules = (ArrayList <Map<?, ?>>) workflowMap.get("modules");
 
    // workflow name
    String workflowName= (String) workflowMap.get("name");
    builder.name(workflowName);
    builder.file(yamlFile);
   
   
    /**
     * First setup the workflow to contain all modules.
     */
    for (Map m : modules)
    {
      Map module = (Map) m.get("module");

      String moduleName = (String) module.get("name");
      String source = (String) module.get("source");

      // Default domain
      Domain domain;
      String domainPrefix, sourceTail;
     
      if(! source.contains(":"))
      {
        domain = Global.defaultDomain();
        domainPrefix = "java";
        sourceTail = source;
      } else
      {
        domainPrefix = source.split(":")[0];
        sourceTail = source.split(":", 2)[1];
       
        if(! Global.domainExists(domainPrefix))
          throw new RuntimeException("Domain "+domainPrefix+" is not known");
       
        domain = Global.domain(domainPrefix);
      }

      // get name
      builder.module(moduleName, domain);

      // get the source
      builder.source(moduleName, sourceTail);

      // get the inputs
      Map inputMap = (Map) module.get("inputs");
     
      // Get the coupled inputs
      List<?> couples = (List <?>) module.get("couple");
   
     
      List<String> errors = new ArrayList<String>();
     
      if(!domain.validate(source, errors)){
        throw new InconsistentWorkflowException(errors);
      }
     
      parseInputAndCouples(builder, moduleName, domain, sourceTail, inputMap, couples);
     
      // ask the domain object for the outputs
      Map<String, DataType> outputTypeMap = getOutputTypes(source, domain);
     
      for(String outputName : outputTypeMap.keySet())
      {
        boolean print = domain.printOutput(sourceTail, outputName);

        String description = domain.outputDescription(sourceTail, outputName);
        builder.output(moduleName, outputName, description, outputTypeMap.get(outputName), print);
      }
    }
   
    return builder.workflow();
  }

  private static void parseInputAndCouples(Workflow.WorkflowBuilder builder,
      String moduleName, Domain domain, String sourceTail, Map inputMap,
      List<?> couples)
  {
    // Process all the inputs.
    for (Object inputKey : inputMap.keySet())
    {
      String inputName = inputKey.toString();

      Object inputValue = inputMap.get(inputKey);
     
      // If the input is a map, then it is actually a reference input
      if (inputValue instanceof Map)
      {
        Map ref = (Map) inputValue;
        String referenceString = (String) ref.get("reference");

        // Reference is in : module.output format, we split using .
        String referencedModule = referenceString.split("\\.")[0];
        String referencedOutput = referenceString.split("\\.")[1];

        DataType inputType = domain.inputType(sourceTail, inputName);
       
        String description = domain.inputDescription(sourceTail, inputName);
        boolean print = domain.printInput(sourceTail, inputName);
       
       
        builder.refInput(moduleName, inputName, description, referencedModule,
            referencedOutput, inputType, print);
       
      } else
      {
       
        DataType inputDataType = domain.inputType(sourceTail, inputName);
       
        String description = domain.inputDescription(sourceTail, inputName);
       
       
        // First handle multi input case, now we include  the case that items in this list this might also be reference.
        if(inputValue instanceof List<?>){
         
          // Each item in the list matches the expected input datatype in this domain, we are doing a sweep a.k.a. multi value solely consisting of raw inputs.
          if(listItemMatch((List<?>) inputValue, inputDataType, domain)){
            builder.multiInput(moduleName,  description, inputName, (List<?>)inputValue, inputDataType);
          } else
          // Either items in the list are references or they match the expected input data type
          if(listItemMatchOrReference((List<?>)inputValue, inputDataType, domain)){
            builder.multiInputRef(moduleName, description, inputName, (List<?>) inputValue, inputDataType);
          } else
          // The input are expecting a list.
          if(domain.valueMatches(inputValue, inputDataType)){
            boolean print = domain.printInput(sourceTail, inputName);
           
            builder.rawInput(moduleName, description, inputName, inputValue, domain.inputType(sourceTail, inputName), print);
             
          } else
            throw new InconsistentWorkflowException("Module "+moduleName+", input " + inputName + ": value ("+inputValue+") does not match the required data type ("+inputDataType+").");
         
        }
        else
        if(domain.valueMatches(inputValue, inputDataType)){
          boolean print = domain.printInput(sourceTail, inputName);

          builder.rawInput(moduleName, description, inputName, inputValue, domain.inputType(sourceTail, inputName), print);
         
        }
       
        else
          throw new InconsistentWorkflowException("Module "+moduleName+", input " + inputName + ": value ("+inputValue+") does not match the required data type ("+inputDataType+").");
      }
    }
   
    // Process the couple lists
    if(couples != null)
    for(Object couple : couples){
      if(!(couple instanceof List)) throw new InconsistentWorkflowException("Couple info is not a list, it should be a list of input names in this module");
      List <String> coupleLS = (List<String>) couple;
      for(String inputName : coupleLS){
        if(!inputMap.containsKey(inputName)){
          throw new InconsistentWorkflowException("Couple list contains input "+inputName+" which is not defined for this module ");
        }
      }
     
      builder.coupledInputs(moduleName, coupleLS);
    }
  }
 
  // Check if list of values provided in workflow description matches the input datatype expected in this domain.
  private static boolean listItemMatch(List<?> list, DataType type, Domain domain)
  {
    for(Object item : list) {
   
      if(! domain.valueMatches(item, type)){
        return false;
      }
    }
   
    return true;
  }

  private static boolean listItemMatchOrReference(List<?> list, DataType type, Domain domain)
  {
    for(Object item : list) {
   
      if(!isAReference(item) && ! domain.valueMatches(item, type)){
        return false;
      }
    }
   
    return true;
  }
 
  // A reference is a map which has "reference" as key
  private static boolean isAReference(Object item) {
    if((item instanceof Map)) {
      Map mitem = (Map) item;
       return mitem.containsKey("reference");
    }
   
    return false;
  }

  private static Map<String, DataType> getOutputTypes(String source, Domain domain)
  {
    Map<String, DataType> result = new LinkedHashMap<String, DataType>();
   
    for(String output : domain.outputs(source))
      result.put(output, domain.outputType(source, output));
   
    return result;
  }

  public String getWorkflowDescription()
  {
    return workflowDescription;
  }

  public void setWorkflowDescription(String workflowDescription)
  {
    this.workflowDescription = workflowDescription;
  }
 
}
TOP

Related Classes of org.data2semantics.platform.util.WorkflowParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.