Create and Use a Configuration

This page shows how to create various types of connected system plug-in configurations and how to use them to meet your use case.

Creating Input Fields

Fields are created by calling the setProperties(PropertyDescriptor...) method on the SimpleConfiguration object that has been passed to the getConfiguration method. In these examples you may see field properties (such as isExpressionable) not explicitly set when they are required. That is because these fields have defaults that result in valid configurations.

Creating a text input field

To create an input field for plain text, use the textProperty() method.

1
2
3
return simpleConfiguration.setProperties(
    textProperty("username").label("Username").build()
);

Screen_Shot_2019-01-10_at_3.49.04_PM.png

Creating a Secured Input Field

To create an input field that will store sensitive data, use the encryptedTextProperty() method. Values gathered through an encrypted text field are encrypted before being stored, cleared on export, must be provided on import via the properties file, and cannot be retrieved by the client after save.

Note: Encrypted text fields are only allowed in connected systems.

1
2
3
4
return simpleConfiguration.setProperties(
    textProperty("username").label("Username").build(),
    encryptedTextProperty("password").label("Password").build()
);

Screen_Shot_2019-01-10_at_3.51.15_PM.png

Creating a Dropdown Field

To create a dropdown field, create a text field and provide a list of choices that can be selected from the dropdown. The name method represents how the value is displayed to the user and the value method is how the value is stored in the SimpleConfiguration. We have the dropdownProperty method to help accomplish this.

1
2
3
4
5
6
7
return integrationConfiguration.setProperties(
    dropdownProperty("state", Arrays.asList(
             choice().name("Maryland").value("MD").build(),
             choice().name("Virginia").value("VA").build())
        .label("State")
        .build()
);

Screen_Shot_2019-01-10_at_3.55.12_PM.png

Adding Additional Information to a Field

Additional information can be added to the field as an instruction, a tooltip (description) or placeholder text. This information helps a user understand how to interact with the field.

1
2
3
4
textProperty("username").label("Username")
    .instructionText("This will be your work email")
    .placeholder("fake.name@appian.com")
    .build()

Screen_Shot_2019-01-10_at_4.03.33_PM.png

Creating a Boolean Field

To create a boolean field, use the booleanProperty() method. Boolean properties can render as a radio button or checkbox based on the provided displayMode().

1
2
3
4
5
6
return integrationConfiguration.setProperties(
    booleanProperty("verbose-output").label("Verbose Output")
        .displayMode(BooleanDisplayMode.RADIO_BUTTON) //Default display mode is checkbox
        .description("Should the request return additional metadata?")
        .build()
);

Screen_Shot_2019-01-10_at_3.59.07_PM.png

Making Fields Required

To mark a field as required use the isRequired() method on the property descriptor builder. The designer will be able to see which fields are required when configuring an integration or connected system.

1
2
3
4
5
textProperty("username").label("Username")
    .instructionText("This will be your work email")
    .placeholder("fake.name@appian.com")
	.isRequired(true)
	.build()

All template methods can be still executed with null values for required fields. Always have appropriate null handling for all fields, even required ones.

Screen_Shot_2019-01-10_at_4.06.00_PM.png

Ensuring Fields can Change between Environments

If a field's values are likely to change between environments use the isImportCustomizeable(true) method on the property builder.

1
2
3
4
5
6
7
8
9
10
11
12
return simpleConfiguration.setProperties(
    textProperty("username").label("Username")
	    .instructionText("This will be your work email")
		.placeholder("fake.name@appian.com")
		.isRequired(true)
		.isImportCustomizable(true)
    .build(),
	encryptedTextProperty("password").label("Password")
		.isRequired(true)
		.description("Make sure to keep this value a secret!")
		.build()
	);

Import customizable fields can be set through the import customization file on import. Only connected systems can have importCustomizable fields.

  • Encrypted fields are import customizable by default.
  • Lists, nested types and document fields cannot be import customizable.

Dynamic Fields

If you want to have dynamic fields then you must create a field where the refresh policy is set to ALWAYS. This triggers a call to getConfiguration when the value of that field is changed. This example shows how to create a dynamic field, retrieve the user-entered value and use that value to determine behavior. Only integrations can have dynamic behavior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
String state = integrationConfiguration.getValue("state");
if(state == null) {
    return integrationConfiguration.setProperties(
        textProperty("state").label("State")
            .choices(
                Choice.builder().name("Maryland").value("MD").build(),
                Choice.builder().name("Virginia").value("VA").build())
            .refresh(RefreshPolicy.ALWAYS)
            .build()
    );
}

String stateFlower = null;
if("VA".equals(state)) {
    stateFlower = "American dogwood";
} else if ("MD".equals(state)) {
    stateFlower = "Black-Eyed Susan";
}

return integrationConfiguration.setProperties(
    textProperty("state").label("State")
        .choices(
            Choice.builder().name("Maryland").value("MD").build(),
            Choice.builder().name("Virginia").value("VA").build())
        .refresh(RefreshPolicy.ALWAYS)
        .build(),
    textProperty("state-flower").label("State Flower")
        .instructionText(String.format("The official flower of %s", state))
            .isReadOnly(true)
            .build()
    ).setValue("state-flower", stateFlower);

Screen_Shot_2019-01-10_at_4.08.44_PM.png

Sending Documents

To send a document, create a document input field using the documentProperty() method.

1
2
3
4
5
return integrationConfiguration.setProperties(
    documentProperty("resume").label("Resume")
        .instructionText("Upload your resume here.")
        .build()
    );

This will allow the designer to provide a document from Appian to your plugin. The Document class then gives you access to an InputStream of the contents along with other metadata.

  • Only integrations can have document upload fields.
  • The document's contents will only be available on execute.
  • During getConfiguration the value for the document will be an integer id.
  • Remember to close the InputStream after consuming the contents.

Screen_Shot_2019-01-10_at_4.10.42_PM.png

Dynamic Input Fields

To allow designers to specify non-static values (SAIL expressions and rule inputs) in input fields, use the isExpressionable(true) method on the property builder.

1
2
3
4
5
6
return integrationConfiguration.setProperties(
    integerProperty("sandwiches").label("Number of Sandwiches Remaining")
        .instructionText("This value will be used to predict when there will be no remaining sandwiches")
        .isExpressionable(true)
        .build()
    );

  • Do not mark a field expressionable when its value should be constant across invocations of the integration.
  • Connected systems cannot have expressionable fields.
  • Some fields are set to be expressionable by default.
  • If the display hint is set to EXPRESSION, then the field must also be marked as expressionable.
  • Be careful when accessing the value from an Expressionable field on configuration. The value may be an Expression object.

Screen_Shot_2019-01-10_at_4.13.46_PM.png

Display a Field as an Expression Box

To display a field as an expression box, use the displayHint(DisplayHint.EXPRESSION) on the field's builder. The field be marked as expressionable and Connected systems cannot have fields with DisplayHint.EXPRESSION.

1
2
3
4
5
6
7
    return integrationConfiguration.setProperties(
        integerProperty("sandwiches").label("Number of Sandwiches Remaining")
            .instructionText("This value will be used to predict when there will be no remaining sandwiches")
            .displayHint(DisplayHint.EXPRESSION)
            .isExpressionable(true)
            .build()
    );

Screen_Shot_2019-01-10_at_4.16.58_PM.png

Creating a Complex Type Input

Complex types are referred to as "local types" in the SDK. Local types are custom dynamic data structures that you can define to fit your specific needs. To create a local type input, use the localTypeProperty() method. To create the local type definition, use the localType() method. List types must have an itemType provided, and be expressionable with a DisplayHint type of expression. List types cannot have a placeholder.

1
2
3
4
5
6
7
8
9
10
11
12
LocalTypeDescriptor addressType = localType("address").properties(
    textProperty("street").label("Street Name").build(),
    integerProperty("zip").label("Zip Code").build(),
    textProperty("state").label("State")
        .choices(
            Choice.builder().name("Maryland").value("MD").build(),
            Choice.builder().name("Virginia").value("VA").build())
        .build()
    ).build();
return integrationConfiguration.setProperties(
    localTypeProperty(addressType).label("Address").isExpressionable(true).build()
);

Screen_Shot_2019-01-10_at_4.18.43_PM.png

Creating a List Input

To create a list input, use the listTypeProperty() method. To set the item type, call the itemType() method, and provide a SystemType or local type.

1
2
3
4
5
	return integrationConfiguration.setProperties(
        listTypeProperty("testscores").label("Test Scores")
            .itemType(SystemType.DOUBLE)
            .build()
    );

Accessing Values Entered by the User

Values entered by the user are stored in the SimpleConfiguration object. To retrieve values use:

  • getValue(String) - Gets a value at the top level (not in a local type property).
  • getValue(PropertyPath) - Gets any value. getValue(new PropertyPath("key")) is equivalent to getValue("key")

  • The value returned by getValue() could be null, so don't store values in primitives
  • In the getConfiguration() method, values are not available for the following fields:
    • Documents
    • Any field that is currently an Expression. Expressions are evaluated at execution time.

Accessing Values

Suppose you have a SimpleConfiguration defined as follows and all of the _KEY variables are defined as unique strings:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LocalTypeDescriptor localTypeDescriptor = localType("localType")
    .property(
        textProperty(INNER + TEXT_PROP_KEY).build()
    ).build();
        
return simpleConfiguration.setProperties(
	textProperty(TEXT_PROP_KEY).build(),
    doubleProperty(DOUBLE_PROP_KEY).build(),
    integerProperty(INTEGER_PROP_KEY).build(),
    documentProperty(DOCUMENT_PROP_KEY).build(),
    listTypeProperty(LIST_PROP_KEY).itemType(SystemType.INTEGER).build(),
    localTypeProperty(localTypeDescriptor, LOCAL_TYPE_PROP_KEY).isExpressionable(true).build(),
    booleanProperty(BOOL_PROP_KEY).build(),
    encryptedTextProperty(ENC_PROP_KEY).build()
);

Retrieving text value with key TEXT_PROP_KEY
String value = simpleConfiguration.getValue(TEXT_PROP_KEY);

Retrieving double value with key DOUBLE_PROP_KEY
Double value = simpleConfiguration.getValue(DOUBLE_PROP_KEY);

Retrieving integer value with key INTEGER_PROP_KEY
Integer value = simpleConfiguration.getValue(INTEGER_PROP_KEY);

Retrieving document value with key DOCUMENT_PROP_KEY during execution
com.appian.connectedsystems.templateframework.sdk.configuration.Document value = simpleConfiguration.getValue(DOCUMENT_PROP_KEY);

Retrieving integer list value with key LIST_PROP_KEY during execution
List<Integer> value = simpleConfiguration.getValue(LIST_PROP_KEY);

Retrieving local type value with key LOCAL_TYPE_PROP_KEY during execution
Map<String, Object> value = simpleConfiguration.getValue(LOCAL_TYPE_PROP_KEY);

Retrieving boolean value with key BOOL_PROP_KEY
Boolean value = simpleConfiguration.getValue(BOOL_PROP_KEY);

Retrieving EncryptedText value with key ENC_PROP_KEY
String value = simpleConfiguration.getValue(ENC_PROP_KEY);

Accessing Nested Values

Suppose you have the following simpleConfiguration object:

1
2
3
4
5
6
7
8
9
10
11
12
13
String TEXT_PROP_KEY = "textPropertyKey";
String LOCAL_TYPE_KEY = "localTypePropertyKey";

LocalTypeDescriptor localTypeDescriptor = localType("localType")
    .property(
        textProperty(TEXT_PROP_KEY).build()
    ).build();

simpleConfiguration.setProperties(
    localTypeProperty(localTypeDescriptor)
        .key(LOCAL_TYPE_KEY)
        .build()
);

To access the value in the text field:
String text = simpleConfiguration.getValue(new PropertyPath(LOCAL_TYPE_KEY, TEXT_PROP_KEY));

Accessing Connected System Data from Integrations

To access values from the connected system in an integration's getConfiguration method:

1
2
3
4
5
6
7
8
9
@Override
protected SimpleConfiguration getConfiguration(
    SimpleConfiguration integrationConfiguration,
    SimpleConfiguration connectedSystemConfiguration,
    PropertyPath propertyPath,
    ExecutionContext executionContext) {
    String apiKey = connectedSystemConfiguration.getValue("API_KEY_PROPERTY_KEY");
    .....
}

To access values from the connected system in an integration's execute method:

1
2
3
4
5
6
7
8
@Override
protected IntegrationResponse execute(
    SimpleConfiguration integrationConfiguration,
    SimpleConfiguration connectedSystemConfiguration,
    ExecutionContext executionContext) {
    String apiKey = connectedSystemConfiguration.getValue("API_KEY_PROPERTY_KEY");
    ....
}

Setting Values Programmatically

It can be useful to set values on read only fields to display information to the designer. To set a value on a property use:

  • simpleConfiguration.setValue("propertyKey", object)
  • simpleConfiguration.setValue(new PropertyPath("localKey", "nestedKey", object)

Values for expressible and document fields cannot be set, only cleared.

  • Set an expressionable field to Expression.emptyExpression() to clear it
  • Set a Document field to Document.emptyDocument() to clear it
FEEDBACK