aspose template, trackVars bugfix
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
package com.customer.work.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.flowable.eventregistry.api.EventRegistry;
|
||||
import org.flowable.eventregistry.api.model.EventPayloadTypes;
|
||||
import org.flowable.eventregistry.api.runtime.EventPayloadInstance;
|
||||
import org.flowable.eventregistry.impl.runtime.EventInstanceImpl;
|
||||
import org.flowable.eventregistry.impl.runtime.EventPayloadInstanceImpl;
|
||||
import org.flowable.eventregistry.model.EventPayload;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
@Service
|
||||
public class TaskListenerService {
|
||||
private final EventRegistry eventRegistry;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public TaskListenerService(EventRegistry eventRegistry, ObjectMapper objectMapper) {
|
||||
this.eventRegistry = eventRegistry;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
public void throwTaskListenerEvent(String rootCaseId, String eventKey, DelegateTask task, String message) {
|
||||
ObjectNode jsonTask = objectMapper.createObjectNode();
|
||||
jsonTask.put("modelId", task.getTaskDefinitionKey());
|
||||
jsonTask.put("assignee", task.getAssignee());
|
||||
jsonTask.put("name", task.getName());
|
||||
|
||||
Collection<EventPayloadInstance> instances = new ArrayList<>();
|
||||
instances.add(new EventPayloadInstanceImpl(EventPayload.correlation("caseId", EventPayloadTypes.STRING), rootCaseId));
|
||||
instances.add(new EventPayloadInstanceImpl(new EventPayload("taskListenerTask", EventPayloadTypes.JSON), jsonTask));
|
||||
instances.add(new EventPayloadInstanceImpl(new EventPayload("taskListenerMessage", EventPayloadTypes.STRING), message));
|
||||
|
||||
EventInstanceImpl event = new EventInstanceImpl(eventKey, instances, task.getTenantId());
|
||||
eventRegistry.sendSystemEventOutbound(event);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.customer.work.service;
|
||||
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Component("taskProcessStarter")
|
||||
public class TaskProcessStarter {
|
||||
@Autowired
|
||||
private RuntimeService runtimeService;
|
||||
|
||||
public void start(String processKey, DelegateTask task) {
|
||||
|
||||
Map<String, Object> vars = new HashMap<>(task.getVariables()); // carry over existing vars
|
||||
vars.put("originTaskId", task.getId());
|
||||
vars.put("originTaskName", task.getName());
|
||||
|
||||
runtimeService.startProcessInstanceByKey(processKey, vars);
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.flowable.cmmn.api.CmmnRuntimeService;
|
||||
import org.flowable.cmmn.api.runtime.CaseInstance;
|
||||
import org.flowable.cmmn.api.runtime.PlanItemInstance;
|
||||
import org.flowable.cmmn.engine.CmmnEngineConfiguration;
|
||||
import org.flowable.cmmn.engine.impl.persistence.entity.CaseInstanceEntity;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
|
||||
import org.flowable.engine.ProcessEngineConfiguration;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
|
||||
@@ -23,7 +18,6 @@ import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.variable.api.delegate.VariableScope;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -33,29 +27,19 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* General-purpose Flowable variable utility bean.
|
||||
* Usable in BPMN process and CMMN case backend expressions without any scope parameter:
|
||||
* ${varUtils.get('order.customer.name')}
|
||||
* ${varUtils.track('order.customer.name,order.total,status')}
|
||||
* Root variables are supported.
|
||||
* How the scope is resolved without a parameter
|
||||
* -----------------------------------------------
|
||||
* The bean registers itself as a Flowable event listener on both engines.
|
||||
* Before a service task expression is evaluated, Flowable fires events on the
|
||||
* same thread that allow us to capture the current variable scope:
|
||||
* BPMN — PROCESS_STARTED fires a FlowableEngineEntityEvent.
|
||||
* The execution is retrieved via event.getEntity().
|
||||
|
||||
* CMMN — CASE_STARTED fires a FlowableEngineEntityEvent.; Instead, when a plan
|
||||
* The case instance is retrieved via event.getEntity().
|
||||
* General-purpose Flowable variable utility bean for tracking variable changes.
|
||||
* Usable in BPMN process and CMMN case backend expressions:
|
||||
* ${varUtils.trackVars('root.snapshot', 'order.customer.name,order.total,status')}
|
||||
* ${varUtils.trackVars(execution, 'root.snapshot', 'status')} — BPMN, explicit scope
|
||||
* ${varUtils.trackVars(planItemInstance, 'root.snapshot', 'status')} — CMMN, explicit scope
|
||||
* Variable paths use dot notation; a leading "root." prefix addresses the root
|
||||
* instance of a nested case/process hierarchy.
|
||||
*/
|
||||
@Component("varUtils")
|
||||
public class VarUtils implements FlowableEventListener, SmartInitializingSingleton {
|
||||
public class VarUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(VarUtils.class);
|
||||
|
||||
private static final ThreadLocal<VariableScope> SCOPE = new ThreadLocal<>();
|
||||
|
||||
private static final ObjectMapper MAPPER;
|
||||
static {
|
||||
MAPPER = new ObjectMapper();
|
||||
@@ -63,72 +47,12 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ProcessEngineConfiguration processEngineConfiguration;
|
||||
|
||||
@Autowired
|
||||
private CmmnEngineConfiguration cmmnEngineConfiguration;
|
||||
|
||||
@Autowired
|
||||
private RuntimeService runtimeService;
|
||||
|
||||
@Autowired
|
||||
private CmmnRuntimeService cmmnRuntimeService;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Listener registration — runs after all beans are ready
|
||||
// -------------------------------------------------------------------------
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
if (processEngineConfiguration != null) {
|
||||
processEngineConfiguration.getEventDispatcher().addEventListener(this);
|
||||
LOGGER.debug("varUtils registered on BPMN event dispatcher");
|
||||
}
|
||||
if (cmmnEngineConfiguration != null) {
|
||||
cmmnEngineConfiguration.getEventDispatcher().addEventListener(this);
|
||||
LOGGER.debug("varUtils registered on CMMN event dispatcher");
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// FlowableEventListener — bind / unbind the scope ThreadLocal
|
||||
// -------------------------------------------------------------------------
|
||||
@Override
|
||||
public void onEvent(FlowableEvent event) {
|
||||
|
||||
if (event instanceof FlowableEngineEntityEvent entityEvent) {
|
||||
String typeName = event.getType().name();
|
||||
Object entity = entityEvent.getEntity();
|
||||
|
||||
// BPMN execution
|
||||
if (entity instanceof ExecutionEntity execution) {
|
||||
switch (typeName) {
|
||||
case "PROCESS_STARTED"
|
||||
-> SCOPE.set(execution);
|
||||
case "PROCESS_CANCELLED",
|
||||
"PROCESS_COMPLETED",
|
||||
"PROCESS_COMPLETED_WITH_ERROR_END_EVENT",
|
||||
"PROCESS_COMPLETED_WITH_ESCALATION_END_EVENT",
|
||||
"PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT"
|
||||
-> SCOPE.remove();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// CMMN case instance itself
|
||||
if (entity instanceof CaseInstanceEntity caseInstance) {
|
||||
if ("CASE_STARTED".equals(typeName))
|
||||
SCOPE.set(caseInstance);
|
||||
else if ("CASE_ENDED".equals(typeName))
|
||||
SCOPE.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean isFailOnException() { return false; }
|
||||
@Override public boolean isFireOnTransactionLifecycleEvent() { return false; }
|
||||
@Override public String getOnTransaction() { return null; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public API — called from Flowable expressions
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -136,39 +60,41 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
/**
|
||||
* Checks which of the given comma-separated variable paths changed since the
|
||||
* last call and returns a JSON array describing each change.
|
||||
* ${varUtils.trackVars('root.snapshot', 'root.myString, status')}
|
||||
* {@code snapshotPath} is a dot-notation path (supports the {@code root.} prefix)
|
||||
* pointing to where the previous-values snapshot is stored and updated.
|
||||
* Each subsequent call compares against the previous snapshot and updates it.
|
||||
* Example call:
|
||||
* ${varUtils.trackVars(self, 'root.snapshot', 'root.status, status')}
|
||||
* Example return value:
|
||||
* [{"path":"root.myString","oldValue":"a","newValue":"b"}]
|
||||
* [{"path":"root.status","oldValue":"a","newValue":"b"}, {"path":"status","oldValue":"c","newValue":"d"}]
|
||||
*/
|
||||
public ArrayNode trackVars(String snapshotPath, String variablePathsCsv) {
|
||||
public ArrayNode trackVars(VariableScope currentScope, String snapshotPath, String variablePathsCsv) {
|
||||
|
||||
// Check parameters
|
||||
// Reject blank parameters early — report "no changes" instead of failing,
|
||||
// so a misconfigured expression cannot break the surrounding process/case.
|
||||
if (snapshotPath == null || snapshotPath.isBlank() || variablePathsCsv == null || variablePathsCsv.isBlank()) {
|
||||
LOGGER.debug("{}.trackVars: empty parameters", getClass().getName());
|
||||
return MAPPER.createArrayNode();
|
||||
}
|
||||
|
||||
// Get current scope
|
||||
VariableScope currentScope = getCurrentScope();
|
||||
// Without a resolvable scope there is nothing to read from or write to.
|
||||
if (currentScope == null) {
|
||||
LOGGER.debug("{}.trackVars: currentScope not found", getClass().getName());
|
||||
return MAPPER.createArrayNode();
|
||||
}
|
||||
|
||||
// Create paths list
|
||||
// Split the CSV into individual variable paths, dropping blanks and whitespace.
|
||||
List<String> paths = Arrays.stream(variablePathsCsv.split(","))
|
||||
.map(String::trim).filter(s -> !s.isEmpty()).toList();
|
||||
|
||||
// Load the previous values (persisted as a JSON string variable at
|
||||
// snapshotPath) to compare the current values against.
|
||||
Map<String, JsonNode> oldSnapshot = loadSnapshot(currentScope, snapshotPath);
|
||||
Map<String, JsonNode> newSnapshot = new HashMap<>();
|
||||
ArrayNode changes = MAPPER.createArrayNode();
|
||||
|
||||
// Loop paths list
|
||||
// For every tracked path: read the current value, normalize it so it
|
||||
// compares consistently with the reloaded snapshot, and record a change
|
||||
// entry whenever old != new.
|
||||
for (String path : paths) {
|
||||
JsonNode newValue = toJson(readVariableFromPath(currentScope, path));
|
||||
JsonNode newValue = normalize(toJson(readVariableFromPath(currentScope, path)));
|
||||
newSnapshot.put(path, newValue);
|
||||
|
||||
JsonNode oldValue = oldSnapshot.getOrDefault(path, MAPPER.nullNode());
|
||||
@@ -181,6 +107,7 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
}
|
||||
}
|
||||
|
||||
// Persist the current values as the reference snapshot for the next call.
|
||||
saveSnapshot(currentScope, snapshotPath, newSnapshot);
|
||||
|
||||
return changes;
|
||||
@@ -190,10 +117,18 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
// Path resolution
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Reads a value via a dot-notation path, e.g. "order.customer.name".
|
||||
* The first segment names a Flowable variable; the remaining segments navigate
|
||||
* into that value (maps, lists/arrays by index, JsonNodes, POJOs — see
|
||||
* {@link #getNestedVariable}). Returns null when any segment cannot be resolved.
|
||||
*/
|
||||
private Object readVariableFromPath(VariableScope scope, String path) {
|
||||
String[] segments = path.split("\\.", -1);
|
||||
if (segments.length < 1) return null;
|
||||
|
||||
// A leading "root." switches to the root instance of the surrounding
|
||||
// case/process hierarchy before resolving the variable.
|
||||
int startIndex = 0;
|
||||
if ("root".equals(segments[0])) {
|
||||
if (segments.length < 2) return null;
|
||||
@@ -202,6 +137,7 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
}
|
||||
if (scope == null) return null;
|
||||
|
||||
// Read the top-level variable, then walk the remaining segments into it.
|
||||
Object currentValue = scope.getVariable(segments[startIndex]);
|
||||
for (int i = startIndex + 1; i < segments.length; i++) {
|
||||
if (currentValue == null) return null;
|
||||
@@ -210,10 +146,18 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a value via a dot-notation path (same syntax as
|
||||
* {@link #readVariableFromPath}). A single-segment path sets a plain Flowable
|
||||
* variable; a nested path mutates the container inside the top-level variable
|
||||
* and writes that variable back so the engine persists the change.
|
||||
*/
|
||||
private void writeVariableToPath(VariableScope scope, String path, Object value) {
|
||||
String[] segments = path.split("\\.", -1);
|
||||
if (segments.length < 1) return;
|
||||
|
||||
// A leading "root." redirects the write to the root instance of the
|
||||
// surrounding case/process hierarchy.
|
||||
VariableScope targetScope;
|
||||
String[] varSegments;
|
||||
if ("root".equals(segments[0])) {
|
||||
@@ -249,6 +193,11 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
targetScope.setVariable(topVar, topValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets one key on a mutable container (Map or ObjectNode). Anything else —
|
||||
* including POJOs, which are read-only for this bean — is rejected with a
|
||||
* warning so a bad path never breaks the calling expression.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean setNestedValue(Object parent, String key, Object value, String path) {
|
||||
if (parent instanceof Map map) {
|
||||
@@ -268,20 +217,27 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
// Scope resolution
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private VariableScope getCurrentScope() {
|
||||
VariableScope scope = SCOPE.get();
|
||||
if (scope == null) {
|
||||
LOGGER.error("{}.getCurrentScope called without an active Flowable scope", getClass().getName());
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Climbs from the given scope to the root VariableScope of the surrounding
|
||||
* case/process hierarchy, following call-activity parents (BPMN) and
|
||||
* parent/callback links (CMMN) across engine boundaries.
|
||||
*/
|
||||
private VariableScope getRootScope(VariableScope scope) {
|
||||
if (scope instanceof DelegateExecution ex) return findBpmnRootScope(ex.getProcessInstanceId());
|
||||
if (scope instanceof PlanItemInstance pii) return findCmmnRootScope(pii.getCaseInstanceId());
|
||||
if (scope instanceof CaseInstance ci) return findCmmnRootScope(ci.getId());
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the root scope starting from a BPMN process instance:
|
||||
* 1. started by a call activity → recurse into the calling process instance,
|
||||
* 2. started from a CMMN plan item (callback) → continue climbing in the case,
|
||||
* 3. otherwise this process instance is itself the root.
|
||||
* NOTE: the returned object is a detached query result used as VariableScope;
|
||||
* its variable access only works because expression evaluation runs inside an
|
||||
* active Flowable command context.
|
||||
*/
|
||||
private VariableScope findBpmnRootScope(String processInstanceId) {
|
||||
if (processInstanceId == null || runtimeService == null) return null;
|
||||
try {
|
||||
@@ -309,6 +265,13 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the root scope starting from a CMMN case instance:
|
||||
* 1. sub-case → recurse into the parent case,
|
||||
* 2. started from a BPMN call/task (callback) → continue climbing in the process,
|
||||
* 3. otherwise this case instance is itself the root.
|
||||
* Same detached-query-result caveat as {@link #findBpmnRootScope}.
|
||||
*/
|
||||
private VariableScope findCmmnRootScope(String caseInstanceId) {
|
||||
if (caseInstanceId == null || cmmnRuntimeService == null) return null;
|
||||
try {
|
||||
@@ -331,7 +294,16 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves one path segment against a value: list/array index, map key,
|
||||
* JsonNode field (scalars are unwrapped to plain Java values), and finally
|
||||
* POJO access via getX()/isX() getters or a declared field.
|
||||
*/
|
||||
private static Object getNestedVariable(Object obj, String segment) {
|
||||
// Empty segments (e.g. from "a..b" or a trailing dot) cannot address anything.
|
||||
if (segment == null || segment.isEmpty()) return null;
|
||||
|
||||
// Lists and arrays are addressed by numeric index, e.g. "items.0.name".
|
||||
if (obj instanceof List<?> list) {
|
||||
try {
|
||||
int i = Integer.parseInt(segment);
|
||||
@@ -345,6 +317,9 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
if (obj instanceof Map<?, ?> map) return map.get(segment);
|
||||
|
||||
// JsonNode: unwrap scalar fields to plain Java values so they compare and
|
||||
// serialize the same way as values read from Map/POJO variables.
|
||||
if (obj instanceof JsonNode jn) {
|
||||
JsonNode node = jn.get(segment);
|
||||
if (node == null || node.isNull()) return null;
|
||||
@@ -355,6 +330,9 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
if (node.isDouble()) return node.asDouble();
|
||||
return node;
|
||||
}
|
||||
|
||||
// Fallback for POJOs: try bean getters first, then a declared field
|
||||
// (climbing the class hierarchy). Read-only — writes reject POJO parents.
|
||||
String cap = Character.toUpperCase(segment.charAt(0)) + segment.substring(1);
|
||||
try {
|
||||
return obj.getClass().getMethod("get" + cap).invoke(obj);
|
||||
@@ -370,6 +348,7 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Looks up a declared field by name, walking up the class hierarchy. */
|
||||
private static java.lang.reflect.Field findField(Class<?> c, String name) {
|
||||
while (c != null && c != Object.class) {
|
||||
try { return c.getDeclaredField(name); }
|
||||
@@ -382,6 +361,12 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
// Snapshot persistence
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Loads the previous-values snapshot: reads the variable at {@code path}
|
||||
* (persisted as a JSON string by {@link #saveSnapshot}) and parses it back
|
||||
* into a path → value-node map. Returns an empty map when there is no
|
||||
* snapshot yet (first call) or it is unreadable.
|
||||
*/
|
||||
private Map<String, JsonNode> loadSnapshot(VariableScope scope, String path) {
|
||||
Object raw = readVariableFromPath(scope, path);
|
||||
if (raw == null) return new HashMap<>();
|
||||
@@ -398,6 +383,7 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
}
|
||||
}
|
||||
|
||||
/** Persists the snapshot map as a JSON string variable at {@code path}. */
|
||||
private void saveSnapshot(VariableScope scope, String path, Map<String, JsonNode> snapshot) {
|
||||
try {
|
||||
writeVariableToPath(scope, path, MAPPER.writeValueAsString(snapshot));
|
||||
@@ -410,9 +396,25 @@ public class VarUtils implements FlowableEventListener, SmartInitializingSinglet
|
||||
// Helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Wraps any Java value into a JsonNode (null-safe). */
|
||||
private static JsonNode toJson(Object value) {
|
||||
if (value == null) return MAPPER.nullNode();
|
||||
if (value instanceof JsonNode jn) return jn;
|
||||
return MAPPER.valueToTree(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes and re-parses a node so its value types match what
|
||||
* {@link #loadSnapshot} produces when reading the persisted snapshot back
|
||||
* (e.g. a Long 5 read from a variable and an Integer 5 parsed from the
|
||||
* snapshot JSON both become the same numeric node). Without this, unchanged
|
||||
* numeric values would be reported as changes on every call.
|
||||
*/
|
||||
private static JsonNode normalize(JsonNode node) {
|
||||
try {
|
||||
return MAPPER.readTree(MAPPER.writeValueAsString(node));
|
||||
} catch (Exception e) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,12 @@ flowable.platform.enable-latest-form-definition-lookup=true
|
||||
|
||||
# Server URL for REST calls
|
||||
baseUrl=http://localhost:8105
|
||||
flowable.security.oauth2.post-logout-redirect-url=http://localhost:8105
|
||||
flowable.security.basic-auth.username=admin
|
||||
flowable.security.basic-auth.password=test
|
||||
|
||||
# Email: Fake SMTP
|
||||
flowable.mail.server.host=localhost
|
||||
flowable.mail.server.port=2525
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user