I have the following code in my update function.
I use the form that I pre-fill with data but when I submit the form i CANNOT update the existing object even if I set client.id manually.
Is it correct to use the commented code in order to first get the object from DB and then update every field one by one?
Form<Client> clientForm = form(Client.class).bindFromRequest();
Map<String, String> data = clientForm.data();
if (clientForm.hasErrors()) {
return badRequest(addEditClient.render("Edit Client", "Update Client", clientID, false, clientForm));
} else {
// do stuff
Client client = clientForm.get();
client.contact = User.findByID("1");
for(ClientTask ct : client.taskSet) {
Task t = Task.findByID(ct.t.id);
ct.t = t;
}
client.id = clientID;
//Client c = Client.findByID(clientID);
//c.name = "test12";
//etc...
//c.save();
client.save();
return GO_HOME;
}
Related
I am new to DynamoDB and working on a dynamo project. I am trying to update the item amount in a transaction with condition if_not_exists() with TransactionWriteRequest in DynamoDB Mapper.
As per the Doc, transactionWriteRequest.updateItem() takes DynamoDBTransactionWriteExpression which doesn't have any UpdateExpression. Class definition is attached bellow.,
Wanted to know How can i provide the if_not_exists() in DynamoDBTransactionWriteExpression to update the item in a transaction. Or there is no way to do this in a transactionWrite.
Please help here.
Thanks in advance
Judging from the snippet you shared it seems you are using Java SDK v1. Below is a code snippet which has 1 PutItem and 1 UpdateItem combined in a single TransactWrite request.
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
final String ORDER_TABLE_NAME = "test1";
/*
Update Item with condition
*/
HashMap<String,AttributeValue> myPk =
new HashMap<String,AttributeValue>();
myPk.put("pk", new AttributeValue("pkValue1"));
Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
expressionAttributeValues.put(":new_status", new AttributeValue("SOLD"));
Update markItemSold = new Update()
.withTableName(ORDER_TABLE_NAME)
.withKey(myPk)
.withUpdateExpression("SET ProductStatus = if_not_exists(createdAt, :new_status)")
.withExpressionAttributeValues(expressionAttributeValues)
.withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD);
/*
Put Item
*/
HashMap<String, AttributeValue> orderItem = new HashMap<>();
orderItem.put("pk", new AttributeValue("pkValue2"));
orderItem.put("OrderTotal", new AttributeValue("100"));
Put createOrder = new Put()
.withTableName(ORDER_TABLE_NAME)
.withItem(orderItem)
.withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD);
/*
Transaction
*/
Collection<TransactWriteItem> actions = Arrays.asList(
new TransactWriteItem().withUpdate(markItemSold),
new TransactWriteItem().withPut(createOrder));
TransactWriteItemsRequest placeOrderTransaction = new TransactWriteItemsRequest()
.withTransactItems(actions)
.withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);
try {
client.transactWriteItems(placeOrderTransaction);
System.out.println("Transaction Successful");
} catch (ResourceNotFoundException rnf) {
System.err.println("One of the table involved in the transaction is not found" + rnf.getMessage());
} catch (InternalServerErrorException ise) {
System.err.println("Internal Server Error" + ise.getMessage());
} catch (TransactionCanceledException tce) {
System.out.println("Transaction Canceled " + tce.getMessage());
} catch (AmazonServiceException e){
System.out.println(e.getMessage());
}
With the v2 version of the SDK you can do it like this
var table =
enhancedClient.table(<table name>, TableSchema.fromClass(DynamoEntity.class));
var transactWriteItemsEnhancedRequest = TransactWriteItemsEnhancedRequest
.builder()
.addUpdateItem(table,
TransactUpdateItemEnhancedRequest.builder(LoadTestEntity.class)
.item(<entity>)
.conditionExpression(Expression.builder().expression("attribute_not_exists(ID)").build())
.build())
.build();
enhancedClient.transactWriteItems(transactWriteItemsEnhancedRequest);
You might need to play around with the expression builder, I haven't tested it.
I have written a code which fetched the S3 objects from AWS s3 using S3 sdk and stores the same in our DB, the only problem is the task is repeated for three different services, the only thing is changed is the instance of service class.
I have copy and pasted code in each service layer just to changes the instance for an instance.
The task is repeated for service classes VehicleImageService, MsilLayoutService and NonMsilLayoutService, every layer is having its own repository.
I am trying to identify a way to accomplish the same by placing that snippet in one place and on an runtime using Reflection API I wish to pass the correct instance and invoke the method, but I want to achieve the same using best industry practices and pattern. I.e. I want to refactor into generic methods for other services, so instance can be passed at runtime.
So kindly assist me on the same.
public void persistImageDetails() {
log.info("MsilVehicleLayoutServiceImpl::persistImageDetails::START");
String bucketKey = null; //common param
String modelCode = null;//common param
List<S3Object> objList = new ArrayList<>(); //common param
String bucketName = s3BucketDetails.getBucketName();//common param
String bucketPath = s3BucketDetails.getBucketPrefix();//common param
try {
//the layoutRepository object can be MSILRepository,NonMSILRepository and VehilceImageRepository
List<ModelCode> modelCodes = layoutRepository.findDistinctAllBy(); // this line need to take care of
List<String> modelCodePresent = modelCodes.stream().map(ModelCode::getModelCode)
.collect(Collectors.toList());
List<CommonPrefix> allKeysInDesiredBucket = listAllKeysInsideBucket(bucketName, bucketPath);//common param
synchDB(modelCodePresent, allKeysInDesiredBucket);
if (null != allKeysInDesiredBucket && !allKeysInDesiredBucket.isEmpty()) {
for (CommonPrefix commonPrefix : allKeysInDesiredBucket) {
bucketKey = commonPrefix.prefix();
modelCode = new File(bucketKey).getName();
if (modelCodePresent.contains(modelCode)) {
log.info("skipping iteration for {} model code", modelCode);
continue;
}
objList = s3Service.getBucketObjects(bucketName, bucketKey);
if (null != objList && !objList.isEmpty()) {
for (S3Object object : AppUtil.skipFirst(objList)) {
saveLayout(bucketName, modelCode, object);
}
}
}
}
log.info("MSIL Vehicle Layout entries has been successfully saved");
} catch (Exception e) {
log.error("Error occured", e);
e.printStackTrace();
}
log.info("MsilVehicleLayoutServiceImpl::persistImageDetails::END");
}
private void saveLayout(String bucketName, String modelCode, S3Object object) {
log.info("Inside saveLayout::Start preparing entity to persist");
String resourceUri = null;
MsilVehicleLayout vehicleLayout = new MsilVehicleLayout();// this can be MsilVehicleLayout. NonMsilVehicleLayout, VehicleImage
vehicleLayout.setFileName(FilenameUtils.removeExtension(FilenameUtils.getName(object.key())));
vehicleLayout.setModelCode(modelCode);
vehicleLayout.setS3BucketKey(object.key());
resourceUri = getS3ObjectURI(bucketName, object.key());
vehicleLayout.setS3ObjectUri(resourceUri);
vehicleLayout.setS3PresignedUri(null);
vehicleLayout.setS3PresignedExpDate(null);
layoutRepository.save(vehicleLayout); //the layoutRepository object can be MSILRepository,NonMSILRepository and VehilceImageRepository
log.info("Exiting saveLayout::End entity saved");
}
I am creating a new state in the flow and then I am trying to consume the state by using reference input. But every time I see in the result as unconsumed state, though I was providing the reference state in the transaction's input.
public SignedTransaction call() throws FlowException {
//------------------------------------------------------------------------------------------------------------
// STEP-1:
// FIRST FLOW MUST CREATE THE NEW STATE WHICH HAS NO INPUT ( THIS WILL CREATE NEW RECORD-ANCHOR WITH LINEARID )
//
//------------------------------------------------------------------------------------------------------------
// We retrieve the notary identity from the network map.
Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
// We create the transaction components.
AnchorState outputState = new
AnchorState(ownerId,contentHash,description,classid,timestamp,expiry, getOurIdentity(), otherParty,new UniqueIdentifier());
//required signers
List<PublicKey> requiredSigners = Arrays.asList(getOurIdentity().getOwningKey(),otherParty.getOwningKey());
//send create command with required signer signatures as below
Command command = new Command<>(new AnchorStateContract.Commands.CreateRecAnchorCmd(), requiredSigners);
// We create a transaction builder and add the components.
TransactionBuilder txBuilder = new TransactionBuilder(notary)
.addOutputState(outputState, AnchorStateContract.ID)
.addCommand(command);
// Verifying the transaction.
txBuilder.verify(getServiceHub());
// Signing the transaction.
SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder);
// Creating a session with the other party.
FlowSession otherPartySession = initiateFlow(otherParty);
// Obtaining the counterparty's signature.
SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow(
signedTx, Arrays.asList(otherPartySession), CollectSignaturesFlow.Companion.tracker()));
//notarized transaction
SignedTransaction notraizedtransaction = subFlow(new FinalityFlow(fullySignedTx, otherPartySession));
//------------------------------------------------------------------------------------------------------------
// STEP-2:
// SINCE NOW WE HAVE A NEW UNCONSUMED RECORD-ANCHOR SO WE MUST MAKE IT CONSUMED ( BY USING THE PREVIOUS OUTPUT AS AN INPUT)
//
//------------------------------------------------------------------------------------------------------------
StateAndRef oldStateref = getServiceHub().toStateAndRef(new StateRef(notraizedtransaction.getId(),0));
Command storeCommand = new Command<>(new AnchorStateContract.Commands.ApproveRecAnchorCmd(), requiredSigners);
TransactionBuilder txBuilder2 = new TransactionBuilder(notary)
.addInputState(oldStateref)
.addOutputState(outputState, AnchorStateContract.ID)
.addCommand(storeCommand);
txBuilder2.verify(getServiceHub());
// signing
SignedTransaction signedTx2 = getServiceHub().signInitialTransaction(txBuilder2);
// Creating a session with the other party.
FlowSession otherPartySession2 = initiateFlow(otherParty);
// Finalising the transaction.
SignedTransaction fullySignedTx2 = subFlow(new CollectSignaturesFlow(
signedTx2, Arrays.asList(otherPartySession2), CollectSignaturesFlow.Companion.tracker()));
//notarized transaction
return subFlow(new FinalityFlow(fullySignedTx2, otherPartySession2));
}
In my flow initiator class I am first creating new state of a hash which I am calling as AnchorState. This state is coming from one of the participants and then it requests to the other participant to sign. afterward the signed record is stored in the ledger but its reference used as an input for a new state change, I simply want to make this state as consumed rather than unconsumed.
The responding flow class of participant B is as below
public SignedTransaction call() throws FlowException
{
//this class is used inside call function for the verification purposes before signed by this party
class SignTxFlow extends SignTransactionFlow
{
private SignTxFlow(FlowSession otherPartySession) {
super(otherPartySession);
}
#Override
protected void checkTransaction(SignedTransaction stx) {
requireThat(require -> {
ContractState output = stx.getTx().getOutputs().get(0).getData();
require.using("This must be an AnchorState transaction.", output instanceof AnchorState);
AnchorState state = (AnchorState) output;
require.using("The AnchorState's value should be more than 6 characters", state.getContentHash().length() > 6);
return null;
});
}
}
SecureHash expectedTxId = subFlow(new SignTxFlow(otherPartySession)).getId();
return subFlow(new ReceiveFinalityFlow(otherPartySession, expectedTxId));
}
This flow successfully runs and returns me unique id for the transaction but I tried everything and could not found how to change the state from unconsumed to consumed?
AFTER FIX
I realized that the vaultQuery on the CordaOS by default returns unconsumed state. Which is now clear why I was not able to get the consumed state in the first place. One more issue which I found, was lack of resources in CORDA for java though I found many kotlin based answers for a transaction with "creation and consumption" in single workflow however converting them into JAVA required some efforts.
Kotlin Based answer
Some differences I observed between Java and Kotlin approach
1) When I have tried to use the same session in my second transaction which was used in the first transaction then I get this error
java.util.concurrent.ExecutionException: net.corda.core.flows.UnexpectedFlowEndException: Tried to access ended session SessionId(toLong=1984916257986245538) with empty buffer
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at net.corda.core.internal.concurrent.CordaFutureImpl.get(CordaFutureImpl.kt)
Which means we have to create new session every time for the new transaction regardless if they are in the single workflow.
2) As I understood by looking at the Kotlin solution that we don't need to add output in the transaction if we just want to make it consumed. However when I do not add an output state in the second transaction then I get the following error which means even for the consumed state I must add the same output inside the transaction. Otherwise, the following error will get erupted again.
ava.util.concurrent.ExecutionException: net.corda.core.flows.UnexpectedFlowEndException: Counter-flow errored
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at net.corda.core.internal.concurrent.CordaFutureImpl.get(CordaFutureImpl.kt)
at com.etasjil.Client.testFlow(Client.java:92)
So it is clear that unlike kotlin, in java we need to explicitly add the output state and new session if we want to create and consume a state within same workflow.
Note: Since this is a new learning curve for me therefore, if I made any mistake in the above realization then kindly correct me. This answer could be good for the new comers in Corda who wants to code in Java rather than Kotlin.
State
#BelongsToContract(AnchorStateContract.class)
public class AnchorState implements LinearState {
public String ownerId,contentHash,description,classid,timestamp,expiry;
public Party initiatorParty, otherParty;
public UniqueIdentifier linearId;
#Override
public List<AbstractParty> getParticipants() {
return Arrays.asList(initiatorParty, otherParty);
}
public AnchorState() {
}
#ConstructorForDeserialization
public AnchorState(String ownerId, String contentHash, String description, String classid, String timestamp, String expiry, Party initiatorParty, Party otherParty, UniqueIdentifier linearId) {
this.ownerId = ownerId;
this.contentHash = contentHash;
this.description = description;
this.classid = classid;
this.timestamp = timestamp;
this.expiry = expiry;
this.initiatorParty = initiatorParty;
this.otherParty = otherParty;
this.linearId = linearId;
}
...
FlowTest case
...
...
#Test
public void test1() {
Future data = a.startFlow(new Initiator("Owner1", "1234567", "Description", "c1", Instant.now().toString(), Instant.MAX.toString(), b.getInfo().getLegalIdentities().get(0).getName().toString()));
network.runNetwork();
try {
System.out.println(data.get());
}catch (Exception e){
System.out.println(e.getMessage());
}
QueryCriteria.VaultQueryCriteria criteria1 = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.CONSUMED);
Vault.Page<AnchorState> results1 = a.getServices().getVaultService().queryBy(AnchorState.class, criteria1);
System.out.println("--------------------- "+ results1.getStates().size());
QueryCriteria.VaultQueryCriteria criteria2 = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL);
Vault.Page<AnchorState> results2 = a.getServices().getVaultService().queryBy(AnchorState.class, criteria2);
System.out.println("--------------------- "+ results2.getStates().size());
QueryCriteria.VaultQueryCriteria criteria3 = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.CONSUMED);
Vault.Page<AnchorState> results3 = b.getServices().getVaultService().queryBy(AnchorState.class, criteria3);
System.out.println("--------------------- "+ results3.getStates().size());
QueryCriteria.VaultQueryCriteria criteria4 = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL);
Vault.Page<AnchorState> results4 = b.getServices().getVaultService().queryBy(AnchorState.class, criteria4);
System.out.println("--------------------- "+ results4.getStates().size());
}
I got 1,2,1,2 as the outputs which tells 1 consumed state in node a & b, totally 2 states in node a and b(1 consumed and 1 unconsumed).
I have a below piece of code where I fetch the json data and pass it to the another method. Data will be keep changing on daily basis. Here, I want to retain my old Data, but somehow I am unable to do it.
Code to save the value:
json = getAllHistory(settings.getRapidView(),sprint.getId(),
settings.getCredentials(),settings.getBaseUrl());
List<History> historyList = new ArrayList<>();
Double completedIssues = ClientUtil.getJsonValue(json,sprint.getId(),"completedIssues");
Double allIssues = ClientUtil.getJsonValue(json,sprint.getId(),"allIssues");
Double remainingIssues = completedIssues-allIssues;
if (remainingIssues > 0) {
History history = new History();
history.setMiliseconds(ZonedDateTime.now().toInstant().toEpochMilli());
history.setCompletedIssues(completedIssues);
history.setAllIssues(allIssues);
history.setRemainingIssues(remainingIssues);
historyList.add(history);
sprintdata.gethistory().addAll(historyList);
sprintdata.setHistory(historyList);
}
Code to make the Rest call:
public static String getAllHistory(String rapidView, Long sprintId, String base64Credentials,String baseUrl) {
try
{
String query = String.format(GET_URL_DATA, rapidView, sprintId);
query=baseUrl+query;
HttpEntity<String> entity = new HttpEntity<String>(getHeader(base64Credentials));
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate.exchange(query, HttpMethod.GET, entity, String.class);
String outputJson= result.getBody();
return outputJson;
}
catch (Exception e)
{
// TODO: handle exception
return null;
}
}
Code to get the specific Json value:
public static Double getJsonValue(String json, Long sprintId, String field) {
try{
return new GsonBuilder().
create().
fromJson(json, JsonObject.class).
getAsJsonObject("contents").
getAsJsonObject(field).
get("value").
getAsDouble();
}
catch(Exception ex)
{
return null;
}
}
I can't find the error on my own, so please help me.
I apologize for my mistake.
A list of one element is created.
Then to the old history list of sprintdata: all items of the new list are added (1):
sprintdata.gethistory().addAll(historyList);
Then the old sprintdata history list is replaced with the new one of 1 element:
sprintdata.setHistory(historyList);
So the sole thing to do would be: add one element to the old history list.
sprintdata.gethistory().add(history);
First, I want to say thanks to everyone that took their time to help me figure this out because I was searching for more than a week for a solution to my problem. Here it is:
My goal is to start a custom workflow in Alfresco Community 5.2 and to set some custom properties in the first task trough a web script using only the Public Java API. My class is extending AbstractWebScript. Currently I have success with starting the workflow and setting properties like bpm:workflowDescription, but I'm not able to set my custom properties in the tasks.
Here is the code:
public class StartWorkflow extends AbstractWebScript {
/**
* The Alfresco Service Registry that gives access to all public content services in Alfresco.
*/
private ServiceRegistry serviceRegistry;
public void setServiceRegistry(ServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
#Override
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException {
// Create JSON object for the response
JSONObject obj = new JSONObject();
try {
// Check if parameter defName is present in the request
String wfDefFromReq = req.getParameter("defName");
if (wfDefFromReq == null) {
obj.put("resultCode", "1 (Error)");
obj.put("errorMessage", "Parameter defName not found.");
return;
}
// Get the WFL Service
WorkflowService workflowService = serviceRegistry.getWorkflowService();
// Build WFL Definition name
String wfDefName = "activiti$" + wfDefFromReq;
// Get WorkflowDefinition object
WorkflowDefinition wfDef = workflowService.getDefinitionByName(wfDefName);
// Check if such WorkflowDefinition exists
if (wfDef == null) {
obj.put("resultCode", "1 (Error)");
obj.put("errorMessage", "No workflow definition found for defName = " + wfDefName);
return;
}
// Get parameters from the request
Content reqContent = req.getContent();
if (reqContent == null) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Missing request body.");
}
String content;
content = reqContent.getContent();
if (content.isEmpty()) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Content is empty");
}
JSONTokener jsonTokener = new JSONTokener(content);
JSONObject json = new JSONObject(jsonTokener);
// Set the workflow description
Map<QName, Serializable> params = new HashMap();
params.put(WorkflowModel.PROP_WORKFLOW_DESCRIPTION, "Workflow started from JAVA API");
// Start the workflow
WorkflowPath wfPath = workflowService.startWorkflow(wfDef.getId(), params);
// Get params from the POST request
Map<QName, Serializable> reqParams = new HashMap();
Iterator<String> i = json.keys();
while (i.hasNext()) {
String paramName = i.next();
QName qName = QName.createQName(paramName);
String value = json.getString(qName.getLocalName());
reqParams.put(qName, value);
}
// Try to update the task properties
// Get the next active task which contains the properties to update
WorkflowTask wfTask = workflowService.getTasksForWorkflowPath(wfPath.getId()).get(0);
// Update properties
WorkflowTask updatedTask = workflowService.updateTask(wfTask.getId(), reqParams, null, null);
obj.put("resultCode", "0 (Success)");
obj.put("workflowId", wfPath.getId());
} catch (JSONException e) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
e.getLocalizedMessage());
} catch (IOException ioe) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
"Error when parsing the request.",
ioe);
} finally {
// build a JSON string and send it back
String jsonString = obj.toString();
res.getWriter().write(jsonString);
}
}
}
Here is how I call the webscript:
curl -v -uadmin:admin -X POST -d #postParams.json localhost:8080/alfresco/s/workflow/startJava?defName=nameOfTheWFLDefinition -H "Content-Type:application/json"
In postParams.json file I have the required pairs for property/value which I need to update:
{
"cmprop:propOne" : "Value 1",
"cmprop:propTwo" : "Value 2",
"cmprop:propThree" : "Value 3"
}
The workflow is started, bpm:workflowDescription is set correctly, but the properties in the task are not visible to be set.
I made a JS script which I call when the workflow is started:
execution.setVariable('bpm_workflowDescription', 'Some String ' + execution.getVariable('cmprop:propOne'));
And actually the value for cmprop:propOne is used and the description is properly updated - which means that those properties are updated somewhere (on execution level maybe?) but I cannot figure out why they are not visible when I open the task.
I had success with starting the workflow and updating the properties using the JavaScript API with:
if (wfdef) {
// Get the params
wfparams = {};
if (jsonRequest) {
for ( var prop in jsonRequest) {
wfparams[prop] = jsonRequest[prop];
}
}
wfpackage = workflow.createPackage();
wfpath = wfdef.startWorkflow(wfpackage, wfparams);
The problem is that I only want to use the public Java API, please help.
Thanks!
Do you set your variables locally in your tasks? From what I see, it seems that you define your variables at the execution level, but not at the state level. If you take a look at the ootb adhoc.bpmn20.xml file (https://github.com/Activiti/Activiti-Designer/blob/master/org.activiti.designer.eclipse/src/main/resources/templates/adhoc.bpmn20.xml), you can notice an event listener that sets the variable locally:
<extensionElements>
<activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string>
if (typeof bpm_workflowDueDate != 'undefined') task.setVariableLocal('bpm_dueDate', bpm_workflowDueDate);
if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;
</activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
Usually, I just try to import all tasks for my custom model prefix. So for you, it should look like that:
import java.util.Set;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.apache.log4j.Logger;
public class ImportVariables extends AbstractTaskListener {
private Logger logger = Logger.getLogger(ImportVariables.class);
#Override
public void notify(DelegateTask task) {
logger.debug("Inside ImportVariables.notify()");
logger.debug("Task ID:" + task.getId());
logger.debug("Task name:" + task.getName());
logger.debug("Task proc ID:" + task.getProcessInstanceId());
logger.debug("Task def key:" + task.getTaskDefinitionKey());
DelegateExecution execution = task.getExecution();
Set<String> executionVariables = execution.getVariableNamesLocal();
for (String variableName : executionVariables) {
// If the variable starts by "cmprop_"
if (variableName.startsWith("cmprop_")) {
// Publish it at the task level
task.setVariableLocal(variableName, execution.getVariableLocal(variableName));
}
}
}
}