-
Notifications
You must be signed in to change notification settings - Fork 15
Introduction to the BHoM_Adapter
Below you will find the theory about the BHoM Adapter.
To get started with the development, have a look at our guide to build a BHoM Toolkit.
As shown in the Structure of the BHoM framework, an adapter is the piece of code responsible to actuate the connection (import/export) between different software packages.
More exactly, the Adapter takes care of the translation between a specific software proprietary representation of an object, transforming it in our BHoM representation.
The BHoM_Adapter is yet another repository containing a Visual Studio solution, with one main Project called BHoM_Adapter
.
This project takes care of the backing actions needed to link a software to another software. It's the core communication interface that the BHoM exposes to allow for information interchange between different software packages.
It's important to keep in mind that the BHoM_Adapter should be seen as the background helper to connect between different software.
This is because when you actually want to implement a new software connection, or work on an existing one, you will have to create and work not on the BHoM_Adapter, but on a specific Toolkit.
This important aspect needs to be understood here:
when you want to create the connection between the BHoM and another software, you will have to create what is called a Toolkit. A Toolkit is yet another repository that contains a Visual Studio solution. A Toolkit is backed by (meaning that it contains, or better, extends) the BHoM_Adapter.
A Toolkit can be seen as the a concrete implementation of the BHoM_Adapter, meaning that it's the piece of code that actually implements the connection between different software.
You can read more on the Toolkit here.
First and foremost feature of the BHoM_Adapter are the its Adapter Actions.
The Actions correspond to the front-end methods available to the end-user to connect BHoM with any external software.
For example, in Grasshopper, there will be a component representing each action, so as in Dynamo; in the same way, in Excel you will find formulas corresponding to these methods. To see them in their UI context, taking the example of Grasshopper, you can find these methods in the Adapter subcategory:
So what are the Adapter actions?
They are actually an advanced concept, of which for now you just need to know the existence and some general things. Let's have a first overview of them all:
- Push: if objects don't exist yet, they are created, if they do, they will be replaced. It will also handle the case where the number of objects changes between pushes.
- Pull: This simply grabs all the objects that satisfy a certain query. If no query is specified, all the objects of the connected model will be taken. You can read more about the queries in a later paragraph.
- UpdateProperty: Instead of replacing/modifying entire objects, this will update one of their property with a new value.
- Delete: This will delete all the objects that match a specific filter.
- Execute: This is used to ask the external software to execute a specific command such as Run analysis, for example.
An important thing to notice and understand – as you might have guessed from their description – is that these methods take care of basic, fundamental things, like ID assignment, avoiding object duplication, distinguishing which object needs updating versus replacing, etc.
The following is an excerpt of the BHoMAdapter.cs
file contained in the "BHoM_Adapter" project.
The Public Adapter Methods have been designed to be as useful and flexible as they can possibly be. Their definition has been abstracted as much as possible, so they can be validly applied across any kind of implementation, with a minimum required effort. If you need to, you can also override them.
This means that when you want to contribute to the BHoM and create a new software connection, you will not need to implement the Public Adapter Methods, at least in most of the cases.
So what is it that you need to implement?
The answer is: the so called CRUD Methods. We will see them in the next page.
Additional note: overriding the Public Adapter Methods
If you need to re-implement one or more of the adapter methods for some specific reason, you are always able to do so.
That is because all those methods are defined asvirtual
, so you canoverride
them.This might be required only in very particular cases.
Additional note: why have we chosen the "Adapter Actions" strategy? Why using 5 different methods, and not something simpler, like "Export" and "Import"?
We have tailored the Public Adapter Methods to balance two competing aspects:
- Maximise code scalability[^1];
- Maximise ease of use.
You will find more information in the advanced parts of the wiki below.
As it can be noted, some Adapter Actions take particular input parameters that need to be explained:
- the Requests,
- the ActionConfig,
- the Data Tags.
Requests are an input to the Pull adapter Action.
They were formerly called Queries and are exactly that: Queries. You can specify a Request to do a variety of things that always involve Pulling data in from an external application or platform. For example:
- you can Request the results of an FE analysis from a connected FEM software,
- specify a GetRequest when using the HTTP_Toolkit to download some data from an online RESTFul Endpoint
- query a connected Database, for example when using Mongo_Toolkit.
Requests can be defined in Toolkits to be working specifically with it.
You can find some requests that are compatible with all Toolkits in the base BHoM object model. An example of those is the FilterRequest.
The FilterRequest is a common type of request that basically requests objects by some specified type. See FilterRequest
.
In general, however, Requests can range from simple filters to define the object you want to be sent, to elaborated ones where you are asking the external tool to run a series of complex data manipulation and calculation before sending you the result.
Additional note: batch requests
For the case of complex queries that need to be executed batched together without returning intermediate results, you can use a
BatchRequest
.
Additional note: Mongo requests
For those that use Mongo already, you might have noticed how much faster and convenient it is to let the database do the work for you instead doing that in Grasshopper. It also speeds up the data transfer in cases where the result is small in bytes but involves a lot of data to be calculated.
The ActionConfig is an object type used to specify any kind of Configuration that might be used by the Adapter Methods.
The base ActionConfig provides some configurations that are available to all Toolkits (you can find more info about those in the code itself).
You can inherit from the base ActionConfig to specify your own in your Toolkit. For example, if you are in the SpeckleToolkit, you will be able to find:
- SpecklePushConfig: inherits from ActionConfig
- SpecklePullConfig: inherits from ActionConfig
this allows some data to be specified when Pushing/Pulling.
ActionConfig is an input to all Adapter methods, so you can reference configurations in any method you might want to override.
When objects are pushed, it is important to have a way to know which objects they are replacing (if any). If the number of objects changes between pushes, you cannot rely on unique identifiers or other solutions that match the objects one-to-one. The problem is especially clear when you are pushing less objects than the last push. Attaching a unique tag to all the objects being pushed as a group is a lightweight and flexible way to find those objects later. For those using D3.js, it is equivalent to attaching a class to html elements. For those using Mongo or Flux, this is similar to the concept of key.
Keep in mind that some objects might end up with multiple tags. For example, if I push a set of bars to a structural analysis software with the tag "bars1", everything that those bars need to be fully defined will be pushed as well (i.e. the nodes, section properties, materials,...). Let's say I now push another set of bars corresponding to an adjacent part of the building with the tag "bars2", it might be that some of the nodes, section properties and materials will be common between those two groups. The common elements will therefore end up with two tags on them. If I then delete the elements with the tag "bars1", only the tag "bars2" will remain".
At the moment, each external software will likely require a different solution to attach those tags to the objects. If the software doesn't provide any solution to group objects or tag them, most of them provide a Name that can be used to save both the BHoM name of the object followed by the tags. The convention we are using for that is "Name Tags:tag1_/tag2/_tag3" for an object that has 3 tags attached to it. This is obviously a bit of a hack and will be replaced by a more permanent solution when databases (i.e. Mongo) become more mainstream as a workflow. Tags will then be stored on a database along with other relevant information such as object's history every time an object is being pushed to any adapter.
[^1]: Quoting this very well written article about Scalability, we can say that Code scalability means "that if a new requirements come to you, in how much of a change, you can adapt to that requirement. The lesser the lines required, the more scalable the code is".
-
Introduction to the BHoM:
What is the BHoM for?
Structure of the BHoM
Technical Philosophy of the BHoM -
Getting Started:
Installing the BHoM
Using the BHoM
Submitting an Issue
Getting started for developers -
Use GitHub & Visual Studio:
Using the SCRUM Board
Resolving an Issue
Avoiding Conflicts
Creating a new Repository
Using Visual Studio
Using Visual Studio Code -
Contribute:
The oM
The Engine
The Adapter
The Toolkit
The UI
The Tests -
Guidelines:
Unit convention
Geometry
BHoM_Engine Classes
The IImmutable Interface
Handling Exceptional Events
BHoM Structural Conventions
BHoM View Quality Conventions
Code Versioning
Wiki Style
Coding Style
Null Handling
Code Attributes
Creating Icons
Changelog
Releases and Versioning
Open Sourcing Procedure
Dataset guidelines -
Foundational Interfaces:
IElement Required Extension Methods -
Continuous Integration:
Introduction
Check-PR-Builds
Check-Core
Check-Installer -
Code Compliance:
Compliance -
Further Reading:
FAQ
Structural Adapters
Mongo_Toolkit
Socket_Toolkit