# Hume Orchestra

# Rest API

Orchestra exposes a REST API for changing and reading the status of its engine.

# Orchestra interaction

# Export

GET /v1/workflows/{workflowId}/export

Parameters

Name In Type Required Description
workflowId path string true none
Status Meaning Description Schema
200 OK (opens new window) default response Workflow

# DryRun

PUT /v1/workflows/dryrun

Body parameter

{
  "version": "string",
  "name": "string",
  "autoStart": true,
  "skills": [
    {
      "name": "string",
      "type": "string",
      "url": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "resources": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "components": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      },
      "resource": "string",
      "skill": {
        "name": "string",
        "implementation": "string",
        "url": "string",
        "parameters": {
          "property1": {},
          "property2": {}
        }
      },
      "to": [
        {}
      ]
    }
  ]
}

Parameters

Name In Type Required Description
cutPointComponentId query string true none
maxNumberOfMessages query integer(int32) true none
body body WorkflowDefinition false none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response WorkflowDryRunResponse

# Metrics

GET /v1/workflows/{workflowId}

Parameters

Name In Type Required Description
workflowId path string true none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response WorkflowMetrics

# Restart

PUT /v1/workflows/{workflowId}/restart

Body parameter

{
  "version": "string",
  "name": "string",
  "autoStart": true,
  "skills": [
    {
      "name": "string",
      "type": "string",
      "url": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "resources": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "components": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      },
      "resource": "string",
      "skill": {
        "name": "string",
        "implementation": "string",
        "url": "string",
        "parameters": {
          "property1": {},
          "property2": {}
        }
      },
      "to": [
        {}
      ]
    }
  ]
}

Parameters

Name In Type Required Description
workflowId path string true none
body body WorkflowDefinition false none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response WorkflowResponse

# Delete

DELETE /v1/workflows/{workflowId}/delete

Parameters

Name In Type Required Description
workflowId path string true none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response WorkflowResponse

# StartWorkflow

PUT /v1/workflows/start

Body parameter

{
  "version": "string",
  "name": "string",
  "autoStart": true,
  "skills": [
    {
      "name": "string",
      "type": "string",
      "url": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "resources": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "components": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      },
      "resource": "string",
      "skill": {
        "name": "string",
        "implementation": "string",
        "url": "string",
        "parameters": {
          "property1": {},
          "property2": {}
        }
      },
      "to": [
        {}
      ]
    }
  ]
}

Parameters

Name In Type Required Description
body body WorkflowDefinition false none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response WorkflowResponse

# DryRunInfo

GET /v1/workflows/{workflowId}/dryrun

Parameters

Name In Type Required Description
workflowId path string true none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response WorkflowDryRunResponse

# Stop Workflow

POST /v1/workflows/{workflowId}/stop

Parameters

Name In Type Required Description
workflowId path string true none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response WorkflowResponse

# Validate Workflow Definition

POST /v1/workflows/validate

Body parameter

{
  "version": "string",
  "name": "string",
  "autoStart": true,
  "skills": [
    {
      "name": "string",
      "type": "string",
      "url": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "resources": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "components": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      },
      "resource": "string",
      "skill": {
        "name": "string",
        "implementation": "string",
        "url": "string",
        "parameters": {
          "property1": {},
          "property2": {}
        }
      },
      "to": [
        {}
      ]
    }
  ]
}

Parameters

Name In Type Required Description
body body WorkflowDefinition false none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response string

# Workflow status

GET /v1/workflows/{workflowId}/status

Parameters

Name In Type Required Description
workflowId path string true none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response string

# Get States by IDs

GET /v1/workflows/status/{workflowIds}

Parameters

Name In Type Required Description
workflowIds path array[string] true none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response Inline

Response Schema

Status Code 200

Name Type Required Restrictions Description
» additionalProperties string false none none

# Enumerated Values

Property Value
additionalProperties RUNNING
additionalProperties STOPPED
additionalProperties NOT_FOUND
additionalProperties STARTING
additionalProperties STOPPING
additionalProperties DELETING
additionalProperties DELETED
additionalProperties RESTARTING
additionalProperties DRYRUN

# Get States

GET /v1/workflows/status

Parameters

Name In Type Required Description
workflowIds path array[string] true none

Example responses

200 Response

Responses

Status Meaning Description Schema
200 OK (opens new window) default response Inline

Response Schema

Status Code 200

Name Type Required Restrictions Description
» additionalProperties string false none none

# Enumerated Values

Property Value
additionalProperties RUNNING
additionalProperties STOPPED
additionalProperties NOT_FOUND
additionalProperties STARTING
additionalProperties STOPPING
additionalProperties DELETING
additionalProperties DELETED
additionalProperties RESTARTING
additionalProperties DRYRUN

# Workflow Failures

GET /v1/workflows/{workflowId}/errors

Parameters

Name In Type Required Description
maxSize query integer(int32) false none
workflowId path string true none

Example responses

200 Response

Responses

Status Meaning Description Schema
200 OK (opens new window) default response Inline

Response Schema

Status Code 200

Name Type Required Restrictions Description
» additionalProperties object false none none

# Workflow Component Failures

GET /v1/workflows/{workflowId}/errors/{componentId}

Parameters

Name In Type Required Description
maxNumberOfFailures query integer(int32) false none
workflowId path string true none
componentId path string true none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response Inline

Response Schema

# Workflow Events

GET /v1/workflows/{workflowId}/events

Parameters

Name In Type Required Description
maxNumberOfEvents query integer(int32) false none
workflowId path string true none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response Inline

Response Schema

# Workflow Component - Get Latest Messages

GET /v1/workflows/{workflowId}/messages/{componentId}

Parameters

Name In Type Required Description
maxNumberOfMessages query integer(int32) false none
workflowId path string true none
componentId path string true none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response Inline

Response Schema

# Registry

# List of Component Types

GET /v1/components

Parameters

Name In Type Required Description
experimental query boolean false none

Responses

Status Meaning Description Schema
200 OK (opens new window) default response Inline

Response Schema

Status Code 200

Name Type Required Restrictions Description
anonymous [ComponentDefinition] false none none
» qualifiedName string false none none
» name string false none none
» type string false none none
» state string false none none
» inputType string false none none
» outputType string false none none
» options [ComponentOptionDefinition] false none none
»» group string false none none
»» name string false none none
»» type string false none none
»» label string false none none
»» required boolean false none none
»» defaultValue object false none none
»» overridable boolean false none none
» resource string false none none
» capabilityQualifiedName string false none none
» dryRunSupported boolean false none none

# List of Resource Types

GET /v1/resources

Responses

Status Meaning Description Schema
200 OK (opens new window) default response Inline

Response Schema

Status Code 200

Name Type Required Restrictions Description
anonymous [Resource] false none none
» qualifiedName string false none none
» name string false none none
» parameters [Parameter] false none none
»» name string false none none
»» type string false none none
»» required boolean false none none
» group string false none none
» experimental boolean false none none

# Enumerated Values

Property Value
type STRING
type ARRAY
type INTEGER
type NUMBER
type BOOLEAN
type PASSWORD
group FILE_SYSTEMS
group DATABASES
group MESSAGE_QUEUES
group MAIL

# Get Resource Groups

GET /v1/resources/groups

Responses

Status Meaning Description Schema
200 OK (opens new window) default response Inline

Response Schema

# Schemas

Component

{
  "qualifiedName": "string",
  "name": "string",
  "type": "DATA_SOURCE",
  "state": "AVAILABLE",
  "inputType": "string",
  "outputType": "string",
  "options": [
    {
      "group": "string",
      "name": "string",
      "type": "STRING",
      "label": "string",
      "required": true,
      "defaultValue": {},
      "overridable": true
    }
  ],
  "capabilityQualifiedName": "string",
  "experimental": true,
  "dryRunSupported": true
}

# Properties
Name Type Required Restrictions Description
qualifiedName string false none none
name string false none none
type string false none none
state string false none none
inputType string false none none
outputType string false none none
options [ComponentOption] false none none
capabilityQualifiedName string false none none
experimental boolean false none none
dryRunSupported boolean false none none
# Enumerated Values
Property Value
type DATA_SOURCE
type PROCESSOR
type SKILL
type PERSISTENCE
type MESSAGING
type CLOCK
type MONITOR
type FILTER
type FAILURE_HANDLER
type DATASCIENCE_TOOLKIT
type ACTION
state AVAILABLE
state UNAVAILABLE

ComponentOption

{
  "group": "string",
  "name": "string",
  "type": "STRING",
  "label": "string",
  "required": true,
  "defaultValue": {},
  "overridable": true
}

# Properties
Name Type Required Restrictions Description
group string false none none
name string false none none
type string false none none
label string false none none
required boolean false none none
defaultValue object false none none
overridable boolean false none none
# Enumerated Values
Property Value
type STRING
type INTEGER
type FLOAT
type TEXT
type BOOLEAN
type MULTI_KEY_VALUE
type DATETIME
type DATE
type CYPHER
type SQL
type PYTHON
type JSON
type COMPONENT_SELECTION_FAILURE_HANDLER

Parameter

{
  "name": "string",
  "type": "STRING",
  "required": true
}

# Properties
Name Type Required Restrictions Description
name string false none none
type string false none none
required boolean false none none
# Enumerated Values
Property Value
type STRING
type ARRAY
type INTEGER
type NUMBER
type BOOLEAN
type PASSWORD

Resource

{
  "qualifiedName": "string",
  "name": "string",
  "parameters": [
    {
      "name": "string",
      "type": "STRING",
      "required": true
    }
  ],
  "group": "FILE_SYSTEMS",
  "experimental": true
}

# Properties
Name Type Required Restrictions Description
qualifiedName string false none none
name string false none none
parameters [Parameter] false none none
group string false none none
experimental boolean false none none
# Enumerated Values
Property Value
group FILE_SYSTEMS
group DATABASES
group MESSAGE_QUEUES
group MAIL

Skill

{
  "name": "string",
  "implementation": "string",
  "url": "string",
  "parameters": {
    "property1": {},
    "property2": {}
  }
}

# Properties
Name Type Required Restrictions Description
name string false none none
implementation string false none none
url string false none none
parameters object false none none
» additionalProperties object false none none

Workflow

{
  "name": "string",
  "components": [
    {
      "name": "string",
      "component": {
        "qualifiedName": "string",
        "name": "string",
        "type": "DATA_SOURCE",
        "state": "AVAILABLE",
        "inputType": "string",
        "outputType": "string",
        "options": [
          {
            "group": "string",
            "name": "string",
            "type": "STRING",
            "label": "string",
            "required": true,
            "defaultValue": {},
            "overridable": true
          }
        ],
        "capabilityQualifiedName": "string",
        "experimental": true,
        "dryRunSupported": true
      },
      "options": [
        {
          "name": "string",
          "value": {}
        }
      ],
      "resource": {
        "name": "string",
        "resource": {
          "qualifiedName": "string",
          "name": "string",
          "parameters": [
            {
              "name": "string",
              "type": "STRING",
              "required": true
            }
          ],
          "group": "FILE_SYSTEMS",
          "experimental": true
        },
        "parameters": {
          "property1": {},
          "property2": {}
        }
      },
      "skill": {
        "name": "string",
        "implementation": "string",
        "url": "string",
        "parameters": {
          "property1": {},
          "property2": {}
        }
      },
      "skillConfiguration": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "links": [
    {
      "from": {
        "name": "string",
        "component": {
          "qualifiedName": "string",
          "name": "string",
          "type": "DATA_SOURCE",
          "state": "AVAILABLE",
          "inputType": "string",
          "outputType": "string",
          "options": [
            {
              "group": "string",
              "name": "string",
              "type": "STRING",
              "label": "string",
              "required": true,
              "defaultValue": {},
              "overridable": true
            }
          ],
          "capabilityQualifiedName": "string",
          "experimental": true,
          "dryRunSupported": true
        },
        "options": [
          {
            "name": "string",
            "value": {}
          }
        ],
        "resource": {
          "name": "string",
          "resource": {
            "qualifiedName": "string",
            "name": "string",
            "parameters": [
              {
                "name": "string",
                "type": "STRING",
                "required": true
              }
            ],
            "group": "FILE_SYSTEMS",
            "experimental": true
          },
          "parameters": {
            "property1": {},
            "property2": {}
          }
        },
        "skill": {
          "name": "string",
          "implementation": "string",
          "url": "string",
          "parameters": {
            "property1": {},
            "property2": {}
          }
        },
        "skillConfiguration": {
          "property1": {},
          "property2": {}
        }
      },
      "to": {
        "name": "string",
        "component": {
          "qualifiedName": "string",
          "name": "string",
          "type": "DATA_SOURCE",
          "state": "AVAILABLE",
          "inputType": "string",
          "outputType": "string",
          "options": [
            {
              "group": "string",
              "name": "string",
              "type": "STRING",
              "label": "string",
              "required": true,
              "defaultValue": {},
              "overridable": true
            }
          ],
          "capabilityQualifiedName": "string",
          "experimental": true,
          "dryRunSupported": true
        },
        "options": [
          {
            "name": "string",
            "value": {}
          }
        ],
        "resource": {
          "name": "string",
          "resource": {
            "qualifiedName": "string",
            "name": "string",
            "parameters": [
              {
                "name": "string",
                "type": "STRING",
                "required": true
              }
            ],
            "group": "FILE_SYSTEMS",
            "experimental": true
          },
          "parameters": {
            "property1": {},
            "property2": {}
          }
        },
        "skill": {
          "name": "string",
          "implementation": "string",
          "url": "string",
          "parameters": {
            "property1": {},
            "property2": {}
          }
        },
        "skillConfiguration": {
          "property1": {},
          "property2": {}
        }
      }
    }
  ],
  "resources": [
    {
      "name": "string",
      "resource": {
        "qualifiedName": "string",
        "name": "string",
        "parameters": [
          {
            "name": "string",
            "type": "STRING",
            "required": true
          }
        ],
        "group": "FILE_SYSTEMS",
        "experimental": true
      },
      "parameters": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "skills": [
    {
      "name": "string",
      "implementation": "string",
      "url": "string",
      "parameters": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "workflowResources": [
    {
      "name": "string",
      "resource": {
        "qualifiedName": "string",
        "name": "string",
        "parameters": [
          {
            "name": "string",
            "type": "STRING",
            "required": true
          }
        ],
        "group": "FILE_SYSTEMS",
        "experimental": true
      },
      "parameters": {
        "property1": {},
        "property2": {}
      }
    }
  ]
}

# Properties
Name Type Required Restrictions Description
name string false none none
components [WorkflowComponent] false none none
links [WorkflowLink] false none none
resources [WorkflowResource] false none none
skills [Skill] false none none
workflowResources [WorkflowResource] false none none

WorkflowComponent

{
  "name": "string",
  "component": {
    "qualifiedName": "string",
    "name": "string",
    "type": "DATA_SOURCE",
    "state": "AVAILABLE",
    "inputType": "string",
    "outputType": "string",
    "options": [
      {
        "group": "string",
        "name": "string",
        "type": "STRING",
        "label": "string",
        "required": true,
        "defaultValue": {},
        "overridable": true
      }
    ],
    "capabilityQualifiedName": "string",
    "experimental": true,
    "dryRunSupported": true
  },
  "options": [
    {
      "name": "string",
      "value": {}
    }
  ],
  "resource": {
    "name": "string",
    "resource": {
      "qualifiedName": "string",
      "name": "string",
      "parameters": [
        {
          "name": "string",
          "type": "STRING",
          "required": true
        }
      ],
      "group": "FILE_SYSTEMS",
      "experimental": true
    },
    "parameters": {
      "property1": {},
      "property2": {}
    }
  },
  "skill": {
    "name": "string",
    "implementation": "string",
    "url": "string",
    "parameters": {
      "property1": {},
      "property2": {}
    }
  },
  "skillConfiguration": {
    "property1": {},
    "property2": {}
  }
}

# Properties
Name Type Required Restrictions Description
name string false none none
component Component false none none
options [WorkflowComponentOption] false none none
resource WorkflowResource false none none
skill Skill false none none
skillConfiguration object false none none
» additionalProperties object false none none

WorkflowComponentOption

{
  "name": "string",
  "value": {}
}

# Properties
Name Type Required Restrictions Description
name string false none none
value object false none none
{
  "from": {
    "name": "string",
    "component": {
      "qualifiedName": "string",
      "name": "string",
      "type": "DATA_SOURCE",
      "state": "AVAILABLE",
      "inputType": "string",
      "outputType": "string",
      "options": [
        {
          "group": "string",
          "name": "string",
          "type": "STRING",
          "label": "string",
          "required": true,
          "defaultValue": {},
          "overridable": true
        }
      ],
      "capabilityQualifiedName": "string",
      "experimental": true,
      "dryRunSupported": true
    },
    "options": [
      {
        "name": "string",
        "value": {}
      }
    ],
    "resource": {
      "name": "string",
      "resource": {
        "qualifiedName": "string",
        "name": "string",
        "parameters": [
          {
            "name": "string",
            "type": "STRING",
            "required": true
          }
        ],
        "group": "FILE_SYSTEMS",
        "experimental": true
      },
      "parameters": {
        "property1": {},
        "property2": {}
      }
    },
    "skill": {
      "name": "string",
      "implementation": "string",
      "url": "string",
      "parameters": {
        "property1": {},
        "property2": {}
      }
    },
    "skillConfiguration": {
      "property1": {},
      "property2": {}
    }
  },
  "to": {
    "name": "string",
    "component": {
      "qualifiedName": "string",
      "name": "string",
      "type": "DATA_SOURCE",
      "state": "AVAILABLE",
      "inputType": "string",
      "outputType": "string",
      "options": [
        {
          "group": "string",
          "name": "string",
          "type": "STRING",
          "label": "string",
          "required": true,
          "defaultValue": {},
          "overridable": true
        }
      ],
      "capabilityQualifiedName": "string",
      "experimental": true,
      "dryRunSupported": true
    },
    "options": [
      {
        "name": "string",
        "value": {}
      }
    ],
    "resource": {
      "name": "string",
      "resource": {
        "qualifiedName": "string",
        "name": "string",
        "parameters": [
          {
            "name": "string",
            "type": "STRING",
            "required": true
          }
        ],
        "group": "FILE_SYSTEMS",
        "experimental": true
      },
      "parameters": {
        "property1": {},
        "property2": {}
      }
    },
    "skill": {
      "name": "string",
      "implementation": "string",
      "url": "string",
      "parameters": {
        "property1": {},
        "property2": {}
      }
    },
    "skillConfiguration": {
      "property1": {},
      "property2": {}
    }
  }
}

# Properties
Name Type Required Restrictions Description
from WorkflowComponent false none none
to WorkflowComponent false none none

WorkflowResource

{
  "name": "string",
  "resource": {
    "qualifiedName": "string",
    "name": "string",
    "parameters": [
      {
        "name": "string",
        "type": "STRING",
        "required": true
      }
    ],
    "group": "FILE_SYSTEMS",
    "experimental": true
  },
  "parameters": {
    "property1": {},
    "property2": {}
  }
}

# Properties
Name Type Required Restrictions Description
name string false none none
resource Resource false none none
parameters object false none none
» additionalProperties object false none none

ResourceDefinition

{
  "name": "string",
  "type": "string",
  "config": {
    "property1": {},
    "property2": {}
  }
}

# Properties
Name Type Required Restrictions Description
name string false none none
type string false none none
config object false none none
» additionalProperties object false none none

SkillDefinition

{
  "name": "string",
  "type": "string",
  "url": "string",
  "config": {
    "property1": {},
    "property2": {}
  }
}

# Properties
Name Type Required Restrictions Description
name string false none none
type string false none none
url string false none none
config object false none none
» additionalProperties object false none none

WorkflowComponentDefinition

{
  "name": "string",
  "type": "string",
  "config": {
    "property1": {},
    "property2": {}
  },
  "resource": "string",
  "skill": {
    "name": "string",
    "implementation": "string",
    "url": "string",
    "parameters": {
      "property1": {},
      "property2": {}
    }
  },
  "to": [
    {}
  ]
}

# Properties
Name Type Required Restrictions Description
name string false none none
type string false none none
config object false none none
» additionalProperties object false none none
resource string false none none
skill Skill false none none
to [object] false none none

WorkflowDefinition

{
  "version": "string",
  "name": "string",
  "autoStart": true,
  "skills": [
    {
      "name": "string",
      "type": "string",
      "url": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "resources": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      }
    }
  ],
  "components": [
    {
      "name": "string",
      "type": "string",
      "config": {
        "property1": {},
        "property2": {}
      },
      "resource": "string",
      "skill": {
        "name": "string",
        "implementation": "string",
        "url": "string",
        "parameters": {
          "property1": {},
          "property2": {}
        }
      },
      "to": [
        {}
      ]
    }
  ]
}

# Properties
Name Type Required Restrictions Description
version string false none none
name string false none none
autoStart boolean false none none
skills [SkillDefinition] false none none
resources [ResourceDefinition] false none none
components [WorkflowComponentDefinition] false none none

ErrorResponse

{
  "type": "string",
  "detail": "string"
}

# Properties
Name Type Required Restrictions Description
type string false none none
detail string false none none

WorkflowDryRunResponse

{
  "result": "SUCCESS",
  "status": "RUNNING",
  "exception": {
    "type": "string",
    "detail": "string"
  },
  "activeComponentIds": [
    "string"
  ],
  "cutPointComponentId": "string"
}

# Properties
Name Type Required Restrictions Description
result string false none none
status string false none none
exception ErrorResponse false none none
activeComponentIds [string] false none none
cutPointComponentId string false none none
# Enumerated Values
Property Value
result SUCCESS
result KO
status RUNNING
status STOPPED
status NOT_FOUND
status STARTING
status STOPPING
status DELETING
status DELETED
status RESTARTING
status DRYRUN

WorkflowMetrics

{
  "name": "string",
  "status": "RUNNING",
  "startedAt": "2019-08-24T14:15:22Z",
  "metrics": {
    "property1": {},
    "property2": {}
  }
}

# Properties
Name Type Required Restrictions Description
name string false none none
status string false none none
startedAt string(date-time) false none none
metrics object false none none
» additionalProperties object false none none
# Enumerated Values
Property Value
status RUNNING
status STOPPED
status NOT_FOUND
status STARTING
status STOPPING
status DELETING
status DELETED
status RESTARTING
status DRYRUN

WorkflowResponse

{
  "result": "SUCCESS",
  "status": "RUNNING",
  "exception": {
    "type": "string",
    "detail": "string"
  }
}

# Properties
Name Type Required Restrictions Description
result string false none none
status string false none none
exception ErrorResponse false none none
# Enumerated Values
Property Value
result SUCCESS
result KO
status RUNNING
status STOPPED
status NOT_FOUND
status STARTING
status STOPPING
status DELETING
status DELETED
status RESTARTING
status DRYRUN

ComponentDefinition

{
  "qualifiedName": "string",
  "name": "string",
  "type": "string",
  "state": "string",
  "inputType": "string",
  "outputType": "string",
  "options": [
    {
      "group": "string",
      "name": "string",
      "type": "string",
      "label": "string",
      "required": true,
      "defaultValue": {},
      "overridable": true
    }
  ],
  "resource": "string",
  "capabilityQualifiedName": "string",
  "dryRunSupported": true
}

# Properties
Name Type Required Restrictions Description
qualifiedName string false none none
name string false none none
type string false none none
state string false none none
inputType string false none none
outputType string false none none
options [ComponentOptionDefinition] false none none
resource string false none none
capabilityQualifiedName string false none none
dryRunSupported boolean false none none

ComponentOptionDefinition

{
  "group": "string",
  "name": "string",
  "type": "string",
  "label": "string",
  "required": true,
  "defaultValue": {},
  "overridable": true
}

# Properties
Name Type Required Restrictions Description
group string false none none
name string false none none
type string false none none
label string false none none
required boolean false none none
defaultValue object false none none
overridable boolean false none none

# Extending Hume Orchestra

In this section we will explain how to extend Hume in multiple ways:

  • by modifying core components;
  • by implementing new extensions.

# Getting started

In broad terms, an extension is an Orchestra component which is not included into core components, so it can be installed as a plugin.

Simply put, to install an extension on an existing Orchestra deployment,

  • the System Administrator will put the jar file of the extension in a directory belonging to Orchestra's filesystem (or shared with it);
  • during its startup, Orchestra will scan the directory and register all the extensions found in that folder.
  • The new extensions will now be available among the built-in ones.

Before starting the journey of Orchestra extensions, let us point out that, under the hood, Orchestra has a Camel-powered engine. Once you're made aware of this simple concept, you need to get familiar with some specific Camel terms, like route definition, mapper, etc. There are two main steps we've to do while developing an Orchestra Extension:

  1. Define a custom route definition:
  2. Implement a Camel Component, if it doesn't exist: sometimes it can happen that for a given platform, nobody has already developed a new component. It is, for instance, the case of our Neo4J writer component: we had to created our own component because it is not yet supported by Camel.

Among them, it's mandatory to implement only the first category because, in most cases, Camel provides the proper component out-of-the-box. So here we will focus on step 1.

# Step by step guide

In this section, we're going to explain how to develop and deploy a new Orchestra Extension plugin starting with an example: the implementation of a simple Hello World.

The goal of HelloWorld Extension is enriching the body of each message it receives with a new field, which value is to be specified in the component configuration.

# Project configuration: the POM

The project is a simple Java 11 project, using Maven as build automation tool; the general part of the pom.xml looks like this:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hume.orchestra.plugin</groupId>
    <artifactId>orchestra-helloworld-plugin</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>HelloWorld component</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <camel.version>3.4.3</camel.version>
    </properties>

The value of the properties will be used later on the POM. Please notice that we specified here which Camel version will support this plugin.

Regarding the dependencies, we need just a few of them in order to make the project compiling.


<dependencies>

        <dependency>
            <groupId>com.hume.orchestra</groupId>
            <artifactId>hume-orchestra-extension</artifactId>
            <version>2.6.0-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.hume.orchestra</groupId>
            <artifactId>hume-orchestra-domain</artifactId>
            <version>2.6.0-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.hume.orchestra</groupId>
            <artifactId>hume-orchestra-core</artifactId>
            <version>2.6.0-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>

        <!-- logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.30</version>
            <scope>test</scope>
        </dependency>

        <!-- testing -->
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-test</artifactId>
            <version>${camel.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>3.1.0</version>
            <scope>test</scope>
        </dependency>
</dependencies>

Please note that the first three dependencies are not public: they're stored in our GraphAware Maven Repository. In this case you need to ask access to this repo or import the required jars in another repo you own.

Finally, to build the jar, you need to provide further configuration in the build section of the POM. Just copy and paste the following snippet, paying attention to change the finalName of the artifact according to the project you're working on.

# Implementation

Basically, every component is composed of three parts:

  1. The general definition of the extension. Here we must provide the general information of the component, definition of the parameters and the Route Definition Mapper.
  2. The definition of the Route Definition Mapper
  3. The definition of the Processor
# General definition of the extension (HelloWorldExtension.java)

@OrchestraModule
public class HelloWorldExtension implements OrchestraExtension {

    public static final String NAME = "HelloWorld";

    public static final String MESSAGE = "message";

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    public ExtensionType getExtensionType() {
        return ExtensionType.MESSAGE_TRANSFORMER;
    }

    @Override
    public Component getComponent() {
        return buildComponent();
    }

    @Override
    public WorkflowComponentConsumer<RoutesDefinition, CamelContext> getConsumer() {
        return new HelloWorldRouteDefinitionMapper();
    }

    private Component buildComponent() {
        Component component = new Component();
        component.setName(getName());
        component.setQualifiedName(getFullyQualifiedName());
        component.setType(ComponentType.PROCESSOR);
        component.setInputType("javax.json.JsonObject");
        component.setOutputType("javax.json.JsonObject");
        component.setOptions(basicOptions());
        component.setState(ComponentState.AVAILABLE);
        component.setExperimental(true);

        return component;
    }

    private List<ComponentOption> basicOptions() {
        List<ComponentOption> options = new ArrayList<>();
        options.add(new ComponentOption("Main", MESSAGE, OrchestraDataType.STRING, "Message", false, "Hello World", true));
        options.add(new ComponentOption("Metrics", OPTION_STORE_ERROR_CONTENT, OrchestraDataType.BOOLEAN, OPTION_STORE_ERROR_CONTENT_LABEL, true, OPTION_STORE_ERROR_CONTENT_DEFAULT_VALUE, true));
        options.add(new ComponentOption("Metrics", OPTION_STORE_MESSAGE_CONTENT, OrchestraDataType.BOOLEAN, OPTION_STORE_MESSAGE_CONTENT_LABEL, true, OPTION_STORE_MESSAGE_CONTENT_DEFAULT_VALUE, true));
        options.add(new ComponentOption(FailureHandler.FAILURE_HANDLER_GROUP_LABEL, FailureHandler.OPTION_FAILURE_HANDLER, FailureHandler.FAILURE_HANDLER_DATA_TYPE, FailureHandler.FAILURE_HANDLER_OPTION_LABEL, false, null, true));

        return options;
    }
}

The first two most important aspects of this snippet are:

  • the @OrchestraModule annotation on top of the class name: it tells to Orchestra that this class is an extension and can be dynamically loaded.
  • the class implements the interface OrchestraExtension: we need to implement all the overridden methods to make the extension work.

Now let's dive into a quick description of some of the most important methods of this class:

@Override
public ExtensionType getExtensionType() {
    return ExtensionType.MESSAGE_TRANSFORMER;
}

The getExtensionType() method returns the category of the component: in other words it tells us what actually the extension will do with every incoming message.


...

    @Override
    public Component getComponent() {
        return buildComponent();
    }
   
....

    private Component buildComponent() {
        Component component = new Component();
        component.setName(getName());
        component.setQualifiedName(getFullyQualifiedName());
        component.setType(ComponentType.PROCESSOR);
        component.setInputType("javax.json.JsonObject");
        component.setOutputType("javax.json.JsonObject");
        component.setOptions(basicOptions());
        component.setState(ComponentState.AVAILABLE);
        component.setExperimental(true);

        return component;
    }

    private List<ComponentOption> basicOptions() {
        List<ComponentOption> options = new ArrayList<>();
        options.add(new ComponentOption("Main", MESSAGE, OrchestraDataType.STRING, "Message", false, "Hello World", true));
        options.add(new ComponentOption("Metrics", OPTION_STORE_ERROR_CONTENT, OrchestraDataType.BOOLEAN, OPTION_STORE_ERROR_CONTENT_LABEL, true, OPTION_STORE_ERROR_CONTENT_DEFAULT_VALUE, true));
        options.add(new ComponentOption("Metrics", OPTION_STORE_MESSAGE_CONTENT, OrchestraDataType.BOOLEAN, OPTION_STORE_MESSAGE_CONTENT_LABEL, true, OPTION_STORE_MESSAGE_CONTENT_DEFAULT_VALUE, true));
        options.add(new ComponentOption(FailureHandler.FAILURE_HANDLER_GROUP_LABEL, FailureHandler.OPTION_FAILURE_HANDLER, FailureHandler.FAILURE_HANDLER_DATA_TYPE, FailureHandler.FAILURE_HANDLER_OPTION_LABEL, false, null, true));

        return options;
    }

About the anatomy of the component itself you can see above that we've built it by specifying some general information like:

  • the display name of the component;
  • the qualified name of the component: unique identifier of the component;
  • the type of the component: PROCESSOR is basically a component whom goal is to manipulate the payload of each Camel message (header or body);
  • Input and Output type: we can specify one or both: only input or only output will be specified when the component is a terminal node (i.e.: a reader or a writer on a database)
  • the experimental flag states whether the component is suitable or not for a production environment (for instance, when the component has not been tested enough);
  • option will be also defined here: here we are telling Orchestra that we're providing four options:
    • MESSAGE, a string will be expected, not mandatory, but with a default value: "Hello World";
    • two options belonging to the Metrics group: if provided, metric options are useful for debugging purposes to check the content of messages or errors caught.
    • One failure handler option: useful to reprocess the failed messages.
@Override
public WorkflowComponentConsumer<RoutesDefinition, CamelContext> getConsumer() {
    return new HelloWorldRouteDefinitionMapper();
}

Finally, by providing a new instance of the mapper we're telling Orchestra how the component should behave. We will describe in detail HelloWorldRouteDefinitionMapper below.

# Route Definition Mapper (HelloWorldRouteDefinitionMapper.java)
public class HelloWorldRouteDefinitionMapper extends AbstractRouteDefinitionMapper {
   
    public RoutesDefinition accept(String groupId, WorkflowComponent workflowComponent, List<WorkflowComponent> successors, List<WorkflowComponent> predecessors) {
        Map<String, Object> optionsMap = WorkflowUtils.getOptions(workflowComponent);
        String message = Optional.ofNullable((String) (optionsMap.get(MESSAGE))).orElseThrow(() -> new IllegalArgumentException("Missing mandatory parameter"));

        String[] toUris = getToUris(successors);

        ComponentWatcherBean componentWatcher = MetricsWatcherBuilder.createMetricsWatcher(groupId, workflowComponent);

        RouteDefinition routeDefinition = new RouteDefinition();
        routeDefinition
                .autoStartup("false")
                .from("direct:" + workflowComponent.getName())
                .id(workflowComponent.getName())
                .routeProperty(STORE_LATEST_INCOMING_MESSAGES, "true")
                .group(groupId)
                .bean(componentWatcher, "onStart(${exchange})");

        routeDefinition.addOutput(buildOnExceptionDefinition(componentWatcher, "onError(${exchange})", optionsMap));
        routeDefinition
                .process(new HelloWorldProcessor(message))
                .bean(componentWatcher, "onStop(${exchange})");

        buildEndRouteDefinition(routeDefinition, toUris).to(toUris);

        RoutesDefinition routesDefinition = new RoutesDefinition();
        routesDefinition.getRoutes().add(routeDefinition);
        return routesDefinition;

    }
}

The Route Definition Mapper acts as a sort of mapper between Orchestra component and Camel. Basically, it takes the options of the component and creates one or more Camel Route Definitions (usually the mapping is one to one, however this is not always true), which are the implementations Camel-wise of the flow that every message is bound to follow.

Let's highlight some important parts of this class:

public class HelloWorldRouteDefinitionMapper extends AbstractRouteDefinitionMapper {

the mapper must extend the abstract class AbstractRouteDefinitionMapper in order to be decorated with all the methods required by Camel Engine

@Override
public RoutesDefinition accept(String groupId, WorkflowComponent workflowComponent, List<WorkflowComponent> successors, List<WorkflowComponent> predecessors) {

The only method we need to implement is accept, which takes as arguments, besides groupId and workflowComponent, the list of next and previous components (successors and predecessors).

Map<String, Object> optionsMap = WorkflowUtils.getOptions(workflowComponent);
String message = Optional.ofNullable((String) (optionsMap.get(MESSAGE)))
                    .orElseThrow(
                        () -> new IllegalArgumentException("Missing mandatory parameter")
);

Here we retrieve the options of the component specified in its definition. Then we pick the MESSAGE parameter from the optionMap: the value of this parameter is what the component will add to the body of the incoming message before sending it to its successors

 String[] toUris = getToUris(successors);
RouteDefinition routeDefinition = new RouteDefinition();
routeDefinition
        .autoStartup("false")
        .from("direct:" + workflowComponent.getName())
        .id(workflowComponent.getName())
        .routeProperty(STORE_LATEST_INCOMING_MESSAGES, "true")
        .group(groupId)
        .bean(componentWatcher, "onStart(${exchange})");

routeDefinition.addOutput(buildOnExceptionDefinition(componentWatcher, "onError(${exchange})", optionsMap));
routeDefinition
        .process(new HelloWorldProcessor(message))
        .bean(componentWatcher, "onStop(${exchange})");

buildEndRouteDefinition(routeDefinition, toUris).to(toUris);

In this case, we don't care about predecessors (so the content of the incoming messages), we just take the list of successors and convert it to an array of strings. Then we define our route definition: we are telling that the route has to be started manually (autoStartup("false")), we give it an identifier and a groupId.

Moreover, about metrics, we set the starting point and the ending point (bean(componentWatcher, "onStart(${exchange})") and bean(componentWatcher, "onStop(${exchange})")), and then we measure the execution time passed between them.

routeDefinition.addOutput(buildOnExceptionDefinition(componentWatcher, "onError(${exchange})", optionsMap));

here we're handling the exceptions occurred during the processing of a message (by firing an onError event).

routeDefinition.process(new HelloWorldProcessor(message))

the new HelloWorkdProcessor processor above specified is a kind of worker, because it manipulates the message (in this case it's going to add it a new field to inbound messages).

RoutesDefinition routesDefinition = new RoutesDefinition();
routesDefinition.getRoutes().add(routeDefinition);
return routesDefinition;

Since multiple route definitions can be mapped with a single component, here we're putting things together.

# Processor (HelloWorldProcessor.java)
public class HelloWorldProcessor implements Processor {

    private final String message;

    public HelloWorldProcessor(String message) {
        this.message = message;
    }

    @Override
    public void process(Exchange exchange) throws Exception {
        Map bodyMap = exchange.getMessage().getBody(Map.class);
        bodyMap.put("my_message", message);
    }
}

As explained above, the processor does the dirty work. In this simple class, we can notice that the body is a map and that we're going to add a field named "my_message".

# Packaging

Now it's time to generate the package we will load into Orchestra.

To do so, just run:

mvn clean package

Once finished, in the target folder there will be a Java Archive named hume-orchestra-hello-world-1.0.0-jar-with-dependencies.jar.

# Deploy

At this point, the new musician took its place, and then the Orchestra can start to play.

However, we have to specify the location where to find the extensions to load.

It works like this:

java \
    -classpath hume-orchestra.jar \
    -Dloader.path=<<your-extension-directory>> \
    org.springframework.boot.loader.PropertiesLauncher

where:

  • Dloader.path is the folder where Orchestra will scan for new extensions, so the hume-orchestra-hello-world-1.0.0-jar-with-dependencies.jar generated previously must be copied here.
  • hume-orchestra.jar is the name of your Orchestra JAR file (the name might be different on your installation).

If everything goes well, you will find in your log a row containing a text like this:

Adding external route definition with FullyQualifiedName #com.hume.orchestra.HelloWorldExtension to registry

Congratulations! You have just created your first Orchestra extension!