Rovo (12) [Avatar] Offline
#1
Hi,

I'm currently going through the book and tried to implement an example on my own. I therefore implemented a basic payment service where a user may enter a coupon hash to reduce the required amout to pay by the value of the coupon with a similar logic as presented in chapter 7. I do however have some problems with the conditional routing after the XOR to either the webservice in case a coupon hash string was entered or to the end of the XOR if nothing was entered.

The bpmn20.xml contains the following entries:
...
<userTask id="getCouponHash" name="get coupon hash" activiti:assignee="kermit">
<extensionElements>
<activiti:formProperty id="couponHash" name="Coupon-Number" type="string" required="false" />
</extensionElements>
</userTask>
...
<sequenceFlow id="XOR_validateCoupon" name="hash" sourceRef="exclusivegateway3" targetRef="validateCoupon">
<conditionExpression xsi:type="tFormalExpression">${couponHash != ''}</conditionExpression>
</sequenceFlow>
...
<sequenceFlow id="XOR_noHash" name="noHash" sourceRef="exclusivegateway3" targetRef="exclusivegateway4">
<conditionExpression xsi:type="tFormalExpression">${couponHash == ''}</conditionExpression>
</sequenceFlow>
...
<serviceTask id="validateCoupon" name="validate coupon" activiti:class="wfm.couponValidation.CouponValidationWSBehavior">
<extensionElements>
<activiti:field name="service">
<activiti:string>http://localhost:63081/CouponValidationService</activiti:string>
</activiti:field>
<activiti:field name="successPath">
<activiti:string>validateCoupon_calculateNewPrice</activiti:string>
</activiti:field>
<activiti:field name="errorPath">
<activiti:string>validateCoupon_errorValidateCoupon</activiti:string>
</activiti:field>
<activiti:field name="couponHash">
<activiti:expression>${couponHash}</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>

This leads to execution of the validation service regardless of the input of couponHash. But I'd like to skip the service if nothing was added.

Thanks for any input in advance,
Roman
Rovo (12) [Avatar] Offline
#2
Re: Optional formProperty and conditionalExpression
As I tested this case in a new smaller scenario I surprisingly noticed that the whole construct does work - so I've created the whole case from scratch and it works now. But I don't really understand why the same construct in one case works and in the other does not - the only change between the two files are some association-names - but there are no name-conflicts in the file.

Besides the conditional association I had further problems with the joining parallel gateway as it did not proceed after all the previous task have finished - but this issue got solved by the newly created model too.

The only thing currently left for me to solve is a java.lang.VerifyError: (class: Script..., method run signature ()Ljava/lang/Objectsmilie Stack size to large

on a script output of:
out:println 'END RESULT:'
out:println 'Name: ' +firstName + ' ' + lastName
out:println 'Payment Method: ' + paymentMethod
out:println 'Price: ' + price

firstName and lastName are from a name- and address-input form, while paymentMethod is a enum of 3 payment method entries and price is defined in the start-node and might be changed in a script if a coupon has been entered. If I only print out firstName instead of firstName + ' ' + lastName then no exception is thrown. If I try to call customer.getFirstName() the same Exception will be thrown although the customer object was set in an ActivityBehavior via execution.setVariable("customer", customer);
tijs.rademakers (494) [Avatar] Offline
#3
Re: Optional formProperty and conditionalExpression
Hi,

For conditional sequence flows it's best to use the CDATA prefix as shown in the Activiti user guide:

<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${order.isStandardOrder()}]]>
</conditionExpression>

About your other question, I would need more information to be able to answer that. Best would be if you can create a unit test that shows the error.

Best regards,

Tijs
Rovo (12) [Avatar] Offline
#4
Re: Optional formProperty and conditionalExpression
Hi and thank you for your reply,

Activiti Designer automatically inserts scripts and expressions into CDATA-tags, I only omitted them for simplicity reasons.

I solved the "Stack size to large"-issue but not sure what is really causing this issues though. The exception was thrown in later scripts only - on simple process definitions I can use something like:

<scriptTask id="scripttask1" name="Script Task" scriptFormat="groovy">
<script><![CDATA[out:println 'Customer: ' + customer.getFirstName() + ' ' + customer.getLastName()]]></script>
</scriptTask>

without getting any errors, but if the process definitions has a couple of tasks this does not work for me anymore unfortunately. The workaround here is to define local variables and use them to output the variable(s):

<scriptTask id="debugOutput" name="debug output" scriptFormat="groovy">
<script><![CDATA[def name = customer.getFirstName() + ' ' +customer.getLastName() >
def address = customer.getAddress().getStreet()+', '+customer.getAddress().getZip()+' '+customer.getAddress().getCity()+', '+customer.getAddress().getCountry()
def telNo = customer.getTelNo()
out:println '
RESULT:'
out:println 'Name: ' + name
out:println 'Address: ' + address
out:println 'Telephone: ' + telNo
if (paymentMethod == 'bankTransferMethod') {
def bank = BankAccount.getBankName()+', '+BankAccount.getBankCode()+', '+BankAccount.getAccountNumber()+', '+BankAccount.getHoldersName()
out:println 'Bank data: '+bank
} else if (paymentMethod == 'creditCardMethod') {
def creditCard = creditCard.getCardNumber()+', '+creditCard.getCardType+', '+creditCard.getExpirationDate()+', '+creditCard.getCVV2Code()+', '+creditCard.getNameOfOwner()
out:println 'Credit card data: ' +creditCard
} else {
out:println 'Billing address: '+address
}
out:println 'Price: ' + price + ' Euro']]></script>

setting new variables with execution.setVariable('newVariableName', object.getMethod()) and afterwards printing newVariableName does work to, but I prefer the local variables

Kind regards,
Roman