All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.appian.connectedsystems.simplified.sdk.configuration.SimpleConfiguration Maven / Gradle / Ivy

package com.appian.connectedsystems.simplified.sdk.configuration;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

import com.appian.connectedsystems.simplified.sdk.SimpleConnectedSystemTemplate;
import com.appian.connectedsystems.simplified.sdk.SimpleIntegrationTemplate;
import com.appian.connectedsystems.templateframework.sdk.ExecutionContext;
import com.appian.connectedsystems.templateframework.sdk.configuration.ConfigurationDescriptor;
import com.appian.connectedsystems.templateframework.sdk.configuration.LocalTypeDescriptor;
import com.appian.connectedsystems.templateframework.sdk.configuration.PropertyDescriptor;
import com.appian.connectedsystems.templateframework.sdk.configuration.PropertyPath;
import com.appian.connectedsystems.templateframework.sdk.configuration.PropertyState;
import com.appian.connectedsystems.templateframework.sdk.configuration.StateGenerator;

/**
 * Defines the configuration of an Appian Connected System object or an Appian Integration object.
 *
 * The following example illustrates defining the structure of the data and UI, followed by setting a value and an error:
 *
 * 
 *  {@code
 *  integrationConfiguration.setProperties(
 *    textProperty("name")
 *    .label("Name")
 *    .build(),
 *   integerProperty("height")
 *    .label("Height")
 *    .build(),
 *   integerProperty("age")
 *    .label("Age")
 *    .build(),
 *   booleanProperty("requiresParentApproval")
 *    .label("Requires Parent Approval")
 *    .isReadOnly(true)
 *    .build());
 *
 *  Integer age = integrationConfiguration.getValue("age");
 *
 *  if (age != null)
 *    integrationConfiguration.setValue("requiresParentalApproval", age < 18);
 *
 *  Integer heightInInches = integrationConfiguration.getValue("height");
 *  if (heightInInches != null && heightInInches < 60)
 *    integrationConfiguration.setError("height", "You are not tall enough to ride.");
 * }
 * 
* * Supports: *
    *
  • setting and retrieving values on properties by keyed locations
  • *
  • setting and retrieving errors on properties by keyed locations
  • *
  • creating the UI and data structure on the Appian object
  • *
* *

{@link #setProperties(PropertyDescriptor...)} must be called per invocation of * {@link SimpleConnectedSystemTemplate#getConfiguration(SimpleConfiguration, ExecutionContext)} and * {@link SimpleIntegrationTemplate#getConfiguration(SimpleConfiguration, SimpleConfiguration, PropertyPath, ExecutionContext)}

* *

* As designers provide values, the SimpleConfiguration can be dynamically updated * to display additional configuration options, fill in dropdown choices, and set default values. *

* */ public class SimpleConfiguration { static final String DEFAULT_ROOT_TYPE_NAME = "RootType"; private TypePropertyFactory typePropertyFactory; private ExecutionContext executionContext; private ConfigurationDescriptor configurationDescriptor; private SimpleConfiguration( ConfigurationDescriptor configurationDescriptor, TypePropertyFactory typePropertyFactory, ExecutionContext executionContext) { this.typePropertyFactory = typePropertyFactory; this.executionContext = executionContext; if(configurationDescriptor == null) { this.configurationDescriptor = ConfigurationDescriptor.builder().build(); this.setProperties(); } else { this.configurationDescriptor = configurationDescriptor; } } /** * Defines the UI and data structure of the Appian object * *
   *  integrationConfiguration.setProperties(
   *    textProperty("name")
   *    .label("Name")
   *    .instructionText("Please enter your first and last name")
   *    .build(),
   *   integerProperty("height")
   *    .label("Height")
   *    .build(),
   *   integerProperty("age")
   *    .label("Age")
   *    .build(),
   *   booleanProperty("requiresParentApproval")
   *    .label("Requires Parent Approval")
   *    .description("If true, you need to ask your parents first!")
   *    .displayMode(BooleanDisplayMode.CHECKBOX)
   *    .isReadOnly(true)
   *    .build()
   *  )
   * 
* *

This method must be called per invocation of {@link SimpleConnectedSystemTemplate#getConfiguration(SimpleConfiguration, ExecutionContext)} and {@link SimpleIntegrationTemplate#getConfiguration(SimpleConfiguration, SimpleConfiguration, PropertyPath, ExecutionContext)}

* *

* Properties define how fields are displayed. * Each editable (non-read-only and non-hidden) property represents data the designer can configure. * Values can be modified using {@link #setValue(String, Object)} or retrieved using {@link #getValue(String)}. *

* *

All existing values are migrated to the new data structure based on the property keys. Newly added fields are set to default values defined by {@link com.appian.connectedsystems.templateframework.sdk.configuration.SystemType}.

* * @param properties fields to be displayed in the UI * @return updated SimpleConfiguration */ public SimpleConfiguration setProperties(PropertyDescriptor... properties) { return setPropertiesGeneric(properties); } /** *

* Properties define how fields are displayed. * Each editable (non-read-only and non-hidden) property represents data the designer can configure. * Values can be modified using {@link #setValue(String, Object)} or retrieved using {@link #getValue(String)}. *

* * @return list of properties that define the current UI */ public List getProperties() { return configurationDescriptor.getTypes().get(DEFAULT_ROOT_TYPE_NAME).getProperties(); } /** *

* Properties define how fields are displayed. * Each editable (non-read-only and non-hidden) property represents data the designer can configure. * Values can be modified using {@link #setValue(String, Object)} or retrieved using {@link #getValue(String)}. *

* * @param key property key uniquely identifying the property. * @return specific property of the configuration at the given key */ public PropertyDescriptor getProperty(String key) { return configurationDescriptor.getTypes().get(DEFAULT_ROOT_TYPE_NAME).getProperty(key).orElse(null); } /** * Gets a value stored in the configuration * * All values inside the configuration can be null. Use reference types. * *

This value could be:

*
    *
  • the default value on initialization. See {@link com.appian.connectedsystems.templateframework.sdk.configuration.SystemType}
  • *
  • set using {@link #setValue(String, Object)}
  • *
  • entered by a user
  • *
* * @param key property key uniquely identifying the property * @return T value at the given key */ public T getValue(String key) { return getValue(new PropertyPath(key)); } /** * Gets a value stored anywhere in the configuration. Use this method to access nested properties * * All values inside the configuration can be null. Use reference types. * *

This value could be:

*
    *
  • the default value on initialization. See {@link com.appian.connectedsystems.templateframework.sdk.configuration.SystemType}
  • *
  • set using {@link #setValue(String, Object)}
  • *
  • entered by a user
  • *
* *

Fetch the value of height inside local property "personType"

*
   *   PropertyPath path = new PropertyPath("personType", "height");
   *   Integer height = integrationConfiguration.getValue(path);
   * 
* * @param propertyPath list of property keys locating the property * @return T value at the given key */ public T getValue(PropertyPath propertyPath) { final PropertyState rootState = getRootState(); return (T)rootState.getValueAtPath(propertyPath); } /** * Sets a value stored in the configuration. * * This will override any user-entered value at the same key. * * @param key property key uniquely identifying the property * @param value value to insert at the key * @return {@code this} */ public SimpleConfiguration setValue( String key, Object value) { return setValue(new PropertyPath(key), value); } /** * Sets a value stored anywhere in the configuration. Use this method to access nested properties * * This will override any user-entered value at the same path. * *
   *   PropertyPath path = new PropertyPath("personType", "height");
   *   int heightInInches = 72;
   *   integrationConfiguration.setValue(path, heightInInches);
   * 
* * @param propertyPath list of property keys locating the property * @param value value to insert at the key * @return {@code this} */ public SimpleConfiguration setValue( PropertyPath propertyPath, Object value) { final PropertyState rootState = getRootState(); rootState.setValueAtPath(propertyPath, value); return this; } /** * Set errors at the highest level of the configuration * * Use this method to show invalid configurations in the connected system * or errors resulting from an invalid combination of multiple fields' configurations * * @param errors the errors to display * @return {@code this} */ public SimpleConfiguration setErrors(List errors) { final PropertyState rootState = getRootState(); rootState.setErrors(errors); return this; } /** * Sets an error in the configuration. * * This error is displayed as a validation on the property in the UI. * * @param key property key uniquely identifying the property * @param errors list of validations * @return {@code this} */ public SimpleConfiguration setErrors( String key, List errors) { return setErrors(new PropertyPath(key), errors); } /** * Sets an error anywhere in the configuration. Use this method to access nested properties * * This error is displayed as a validation on the property in the UI. * * @param propertyPath list of property keys locating the property * @param errors list of validations * @return {@code this} */ public SimpleConfiguration setErrors( PropertyPath propertyPath, List errors) { final PropertyState rootState = getRootState(); rootState.setErrorsAtPath(propertyPath, errors); return this; } public ConfigurationDescriptor toConfiguration() { return configurationDescriptor; } public static SimpleConfiguration from( ConfigurationDescriptor configDescriptor, TypePropertyFactory typePropertyFactory, ExecutionContext executionContext) { typePropertyFactory = typePropertyFactory == null ? new TypePropertyFactory() : typePropertyFactory; return new SimpleConfiguration(configDescriptor, typePropertyFactory, executionContext); } private String getRootTypeName() { PropertyState rootState = getRootState(); String rootTypeName = DEFAULT_ROOT_TYPE_NAME; if (rootState != null) { rootTypeName = rootState.getType().getUnqualifiedTypeName(); } return rootTypeName; } private SimpleConfiguration setPropertiesGeneric(PropertyDescriptor[] properties) { return setPropertiesGeneric(getRootTypeName(), properties); } private SimpleConfiguration setPropertiesGeneric(String typeName, PropertyDescriptor[] properties) { PropertyDescriptor[] builtProperties = filterProperties(properties); LocalTypeDescriptor type = LocalTypeDescriptor.builder() .name(typeName) .properties(builtProperties) .build(); Map newTypes = typePropertyFactory.getTypes(); newTypes.put(typeName, type); return getConfigurationDescriptor(type, newTypes.values()); } private PropertyState getRootState() { return configurationDescriptor.getRootState(); } private SimpleConfiguration getConfigurationDescriptor( LocalTypeDescriptor root, Collection types) { PropertyState state = new StateGenerator(types).generateFromExistingState(root, getRootState()); configurationDescriptor = ConfigurationDescriptor.builder() .withTypes(types) .withState(state) .build(); return this; } private PropertyDescriptor[] filterProperties(PropertyDescriptor[] properties) { Stream propStream = Arrays.stream(properties) .filter(Objects::nonNull); return propStream.toArray(PropertyDescriptor[]::new); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy