Versions Compared
Key
- This line was added.
- This line was removed.
- Formatting was changed.
Warning |
---|
When using external flow please make sure that the host and the target runtimes have the same major and minor versions. |
Introduction
The external flow is a concept that allows embedding and starting a flow from a different project, without the use of Portal Messages.
The value of this functionality is to get:
- a good design of the solution:
- Structure your application
- Make your solution scalable
- a good application UX:
- The end user directly see which information is loaded and what not
- a good application model:
- Modelling is more explicit which brings clarity in the model
Conceptually it works as depicted in the following figure.
Image Removed
This container will replace the AQ_Dashboard_FlowWidget and AQ_Dashboard_ProjectWidget.
Definitions
Requirements
In order to use this functionality you need to enable Blueriq External Flow Component.
Limitations
- Running the external flow using host and target runtimes with different major and minor versions is not supported.
Configuration
To configure the External Flow Container to work on the runtime you have to do the following:
- Enable
external-flow
profile inbootstrap.properties
. - Replace the material version (>=1.0.9)
Info |
---|
External flow functionality saves the profile in a Redis Datastore. Please consult Blueriq External Flow Component in order to see more details on how to configure the runtime to support the external flow. |
Using other datastore implementation
Blueriq provides IExternalFlowStore interface which can be used to interact with a generic datastore. A default implementation is already provided in the Blueriq External Flow Component. If other datastore implementation is desired the following have to be done:
- Add the
blueriq-component-api
to the project dependencies.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<project ...>
...
<dependencies>
...
<dependency>
<groupId>com.blueriq</groupId>
<artifactId>blueriq-component-api</artifactId>
<version>${blueriq.version}</version>
</dependency>
...
</dependencies>
...
</project> |
- Define the custom implementation like below:
Code Block | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
package ...;
import com.blueriq.component.api.store.externalflow.IExternalFlowStore;
// other imports ...
@Component
public class CustomExternalFlowStore implements IExternalFlowStore {
@Override
public void delete(String key)
throws ExternalFlowStoreException, IllegalArgumentException {
// add implementation here
}
@Override
public <T extends Serializable> T get(String key, Class<T> valueType)
throws ExternalFlowStoreException, IllegalArgumentException {
// add implementation here
return null;
}
@Override
public boolean hasKey(String key)
throws ExternalFlowStoreException, IllegalArgumentException {
// add implementation here
return false;
}
@Override
public void set(String key, Serializable value)
throws ExternalFlowStoreException, IllegalArgumentException {
// add implementation here
}
}
|
Hazelcast Datastore
Here is a Hazelcast implementation of the datastore.
Adding the dependencies
The following dependencies are required in the pom.xml
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<project ...>
...
<dependencies>
...
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-all</artifactId>
<version>${hazelcast.version}</version>
</dependency>
<dependency>
<groupId>com.blueriq</groupId>
<artifactId>blueriq-component-api</artifactId>
<version>${blueriq.version}</version>
</dependency>
...
<dependencies>
...
</project> |
Implementing the IExternalFlowStore Interface
Warning | ||
---|---|---|
| ||
Please make sure that HazelcastExternalFlowStore component is scanned by Spring. |
Code Block | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
package ...;
import com.blueriq.component.api.store.externalflow.IExternalFlowStore;
// other imports ...
@Component
public class HazelcastExternalFlowStore implements IExternalFlowStore {
private final IMap<String, Serializable> map;
public HazelcastExternalFlowStore() {
ClientConfig config = new ClientConfig();
// configure Hazelcast properties here
HazelcastInstance hazelcastInstance
= HazelcastClient.newHazelcastClient(config);
map = hazelcastInstance.getMap("blueriq");
}
@Override
public void delete(String key)
throws ExternalFlowStoreException, IllegalArgumentException {
if (isInvalid(key)) {
throw new IllegalArgumentException("Invalid key.");
}
try {
map.delete(key);
} catch (Exception e) {
throw new ExternalFlowStoreException("Something went wrong", e);
}
}
@Override
public <T extends Serializable> T get(String key, Class<T> valueType)
throws ExternalFlowStoreException, IllegalArgumentException {
if (isInvalid(key)) {
throw new IllegalArgumentException("Invalid key.");
}
try {
Serializable storedValue = map.get(key);
if (storedValue == null) {
return null;
}
if (valueType.isInstance(storedValue)) {
return valueType.cast(storedValue);
}
throw new IllegalArgumentException(
String.format("Cannot cast from %s to %s.",
storedValue.getClass(), valueType));
} catch (Exception e) {
throw new ExternalFlowStoreException("Something went wrong", e);
}
}
@Override
public boolean hasKey(String key)
throws ExternalFlowStoreException, IllegalArgumentException {
if (isInvalid(key)) {
throw new IllegalArgumentException("Invalid key.");
}
try {
return map.get(key) != null;
} catch (Exception e) {
throw new ExternalFlowStoreException("Something went wrong", e);
}
}
@Override
public void set(String key, Serializable value)
throws ExternalFlowStoreException, IllegalArgumentException {
if (isInvalid(key)) {
throw new IllegalArgumentException("Invalid key.");
}
try {
map.set(key, value, 1, TimeUnit.MINUTES);
} catch (Exception e) {
throw new ExternalFlowStoreException("Something went wrong", e);
}
}
private boolean isInvalid(String key) {
// define what an invalid key means
return false;
}
}
|
Modeling an External Flow
Todo
External Flow Endpoints
Init external flow
Code Block | ||
---|---|---|
| ||
POST /api/v2/session/{sessionId}/externalflow/init {"configurationId": "{configurationId}}" |
Description
Initialises the external container component on the HOST runtime.
Parameters
URL Segment | Expected Type | Description |
---|---|---|
sessionId | AquimaSession | Session for which the external container was expanded. |
The body must be a JSON containing the configuration ID of type string
Example Response
If successful, status 200 OK and :
Code Block |
---|
{ "configurationId" : "123-456-789" } |
Start external flow
Code Block | ||
---|---|---|
| ||
POST /api/v2/externalflow/start {"configurationId": "{configurationId}}" |
Description
Starts the external flow container on the TARGET runtime.
Parameters
A JSON containing the configuration ID of type string.
Example Response
If successful, status 200 OK and :
Code Block |
---|
{ "sessionId" : "123-456-789" } |
Complete external flow
Code Block | ||
---|---|---|
| ||
POST /api/v2/session/{sessionId}/externalflow/{configurationId}/complete |
Description
Completes the external flow and executes the mapping between the interface and source profile.
Parameters
URL Segment | Expected Type | Description |
---|---|---|
sessionId | AquimaSession | The Id of the AquimaSession from the host runtime. |
configurationId | string | Unique id for the external container configuration. |
Example Response
If successful, status 200 OK and :
Code Block |
---|
{ "events": [ { "sessionId": <sessionId>, "changes": {"changes": []}, "type": "page" }, ... ] } |
End external flow
Code Block | ||
---|---|---|
| ||
POST /api/v2/session/{sessionId}/externalflow/{configurationId}/end |
Description
Closes the external session
Parameters
URL Segment | Expected Type | Description |
---|---|---|
sessionId | AquimaSession | The Id of the AquimaSession from the target runtime. |
configurationId | string | Unique id for the external container configuration. |
Response
If successful, status code 200 OK
Known Issues
Todo ???
The
Table of Contents |
---|