-
Notifications
You must be signed in to change notification settings - Fork 2
/
converters.py
660 lines (573 loc) · 24.5 KB
/
converters.py
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
import xml.etree.ElementTree as ET
from xml.sax.saxutils import escape
from constants import *
##########################################################################
# Various conversion helpers / base classes
class Output(object):
outputs = []
def __init__(self, output_dir, filename, module_name):
import os
self.outfile = os.path.join(output_dir, filename)
self.out = open(self.outfile,"w")
self.module_name = module_name
Output.outputs.append(self)
def begin(self, model_name, namespace_uri, namespace):
pass
def write(self, line):
self.out.write( line.encode("UTF-8") )
def complete(self):
self.out.close()
self.out = None
class BPMNFixer(object):
fixers = []
def __init__(self, tag, attr):
BPMNFixer.fixers.append(self)
self.attr = attr
self.tag = tag
def fix_for_tag(self, tag):
pass
def fix_for_attr(self, tag, attr_val):
pass
@staticmethod
def fix_all(wf):
for fixer in BPMNFixer.fixers:
if fixer.tag:
tags = wf.findall(".//%s" % fixer.tag)
for tag in tags:
fixer.fix_for_tag(tag)
if fixer.attr:
tags = wf.findall("**/[@%s]" % fixer.attr)
for tag in tags:
attr_val = tag.get(fixer.attr)
fixer.fix_for_attr(tag, attr_val)
@staticmethod
def add_script(ext_elem_tag, script_type, script):
# Add the appropriate listener
if script_type == "start":
listener = ET.SubElement(ext_elem_tag,"{%s}executionListener"%activiti_ns)
listener.set("event","start")
listener.set("class","org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener")
else:
listener = ET.SubElement(ext_elem_tag,"{%s}taskListener"%activiti_ns)
listener.set("event",script_type)
listener.set("class","org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener")
# Add the real script
fscript = ET.SubElement(listener,"{%s}field"%activiti_ns)
fscript.set("name","script")
fstring = ET.SubElement(fscript,"{%s}string"%activiti_ns)
fstring.text = script
##########################################################################
class ModelOutput(Output):
def __init__(self, output_dir, module_name):
Output.__init__(self,output_dir,"model.xml", module_name)
self.to_close = "types"
def begin(self, model_name, namespace_uri, namespace):
self.namespace = namespace
self.out.write("""<?xml version='1.0' encoding='UTF-8'?>
<model xmlns='http://www.alfresco.org/model/dictionary/1.0' name='%s'>
<version>1.0</version>
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
<import uri="http://www.alfresco.org/model/site/1.0" prefix="st"/>
<import uri="http://www.alfresco.org/model/bpm/1.0" prefix="bpm" />
</imports>
<namespaces>
<namespace uri="%s" prefix="%s"/>
</namespaces>
<types>
""" % (model_name, namespace_uri, namespace))
def _start(self):
self.aspects = []
self.associations = []
self.out.write(" <properties>\n")
def _end(self):
self.out.write(" </properties>\n")
if self.aspects:
self.out.write(" <mandatory-aspects>\n")
for aspect in self.aspects:
self.out.write(" <aspect>%s</aspect>\n" % aspect.name)
self.out.write(" </mandatory-aspects>\n")
if self.associations:
self.out.write(" <associations>\n")
for assoc in self.associations:
self.out.write(" <association name=\"%s\">\n" % assoc[0])
if assoc[1]:
self.out.write(" <title>%s</title>\n" % escape(assoc[1]))
self.out.write(" <source>\n")
self.out.write(" <mandatory>%s</mandatory>\n" % str(assoc[2][0]).lower())
self.out.write(" <many>%s</many>\n" % str(assoc[2][1]).lower())
self.out.write(" </source>\n")
self.out.write(" <target>\n")
self.out.write(" <class>%s</class>\n" % str(assoc[2][2]).lower())
self.out.write(" <mandatory>%s</mandatory>\n" % str(assoc[2][3]).lower())
self.out.write(" <many>%s</many>\n" % str(assoc[2][4]).lower())
self.out.write(" </target>\n")
self.out.write(" </association>\n")
self.out.write(" </associations>\n")
def start_type(self, form):
alf_task_type, is_start_task = get_alfresco_task_types(form)
self.out.write("\n")
self.out.write(" <type name=\"%s\">\n" % form.form_new_ref)
if form.form_title:
self.out.write(" <title>%s</title>\n" % escape(form.form_title))
self.out.write(" <parent>%s</parent>\n" % alf_task_type)
self._start()
self.aspects = form.aspects
def end_type(self, form):
self._end()
self.out.write(" </type>\n")
def start_aspect(self, name):
if self.to_close == "types":
self.to_close = "aspects"
self.out.write("""
</types>
<aspects>
""")
self.out.write("\n")
self.out.write(" <aspect name=\"%s\">\n" % name)
self._start()
def end_aspect(self):
self._end()
self.out.write(" </aspect>\n")
def convert_field(self, field):
field_id, alf_id, name = build_field_ids(field, self.namespace)
ftype, alf_type, options, required = build_field_type(field)
# TODO Handle default values, multiples etc
if alf_type:
self.write(" <property name=\"%s\">\n" % alf_id)
if name:
self.write(" <title>%s</title>\n" % escape(name))
self.write(" <type>%s</type>\n" % alf_type)
if ftype == "readonly-text":
self.write(" <default>%s</default>\n" % escape( field.get("value","") ))
if required:
self.write(" <mandatory>true</mandatory>\n")
if options:
self.write(" <constraints>\n")
self.write(" <constraint name=\"%sConstraint\" type=\"LIST\">\n" % alf_id)
self.write(" <parameter name=\"allowedValues\"><list>\n")
for opt in options:
self.write(" <value>%s</value>\n" % escape(opt["name"]))
self.write(" </list></parameter>\n")
self.write(" </constraint>\n")
self.write(" </constraints>\n")
self.write(" </property>\n")
if assoc_types.has_key(ftype):
self.associations.append((alf_id,name,assoc_types.get(ftype)))
def complete(self):
self.out.write("""
</%s>
</model>
""" % (self.to_close))
Output.complete(self)
class ContextOutput(Output):
def __init__(self, output_dir, module_name):
Output.__init__(self,output_dir,"module-context.xml", module_name)
def begin(self, model_name, namespace_uri, namespace):
self.out.write("""<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean id="%sModelBootstrap"
parent="dictionaryModelBootstrap"
depends-on="dictionaryBootstrap">
<property name="models">
<list>
<!-- TODO Correct this to where you put model.xml -->
<value>alfresco/module/%s/model.xml</value>
</list>
</property>
</bean>
<bean id="%sWorkflowDeployer"
parent="workflowDeployer">
<property name="workflowDefinitions">
<list>
<props>
<prop key="engineId">activiti</prop>
<!-- TODO Correct this to where you put the updated BPMN file -->
<prop key="location">alfresco/module/%s/%s.bpmn20.xml</prop>
<prop key="mimetype">text/xml</prop>
<prop key="redeploy">false</prop>
</props>
</list>
</property>
</bean>
""" % (namespace, self.module_name, namespace, self.module_name, self.module_name))
def complete(self):
self.out.write("""
</beans>
""")
Output.complete(self)
class ConstantsOutput(Output):
def __init__(self, output_dir, module_name):
self.classname = "%sWorkflowModel" % module_name
self.properties = {}
Output.__init__(self,output_dir,"%s.java"%self.classname, module_name)
def begin(self, model_name, namespace_uri, namespace):
self.out.write("""
// TODO Correct this for your real Java package name
package FIXME;
import org.alfresco.service.namespace.QName;
/**
* %s Workflow Model constants
*/
public interface %s
{
public static final String URI = "%s";
public static final String PREFIX = "%s";
""" % (self.module_name, self.classname, namespace_uri, namespace))
def convert_type(self, form):
name = form.form_new_name
self.out.write(" public static final QNAME TYPE_%s = QName.createQName(URI, \"%s\");\n" %
(name.upper(), name))
def convert_aspect(self, aspect):
aname = aspect.aspect_id_str.upper()
self.out.write(" public static final QNAME ASPECT_%s = QName.createQName(URI, \"%s\");\n" %
(aname, aspect.base_name))
def convert_property(self, field_id, name):
pname = name.replace(" ","_").upper()
self.properties[pname] = field_id
def complete(self):
self.out.write("\n")
for pname in sorted(self.properties.keys()):
self.out.write(" public static final QNAME PROP_%s = QName.createQName(URI, \"%s\");\n" %
(pname, self.properties[pname]))
self.out.write("}\n")
Output.complete(self)
class PropertiesLabelsOutput(Output):
def __init__(self, output_dir, module_name):
Output.__init__(self,output_dir,"custom-workflow.properties", module_name)
def begin(self, model_name, namespace_uri, namespace):
self.namespace_uri = namespace_uri
self.namespace = namespace
self.out.write("# Custom workflow labels\n")
def _convert(self, to, as_field):
self.out.write("\n")
self.out.write("# %s\n" % as_field["name"])
for oc in as_field["options"]:
ocid = oc.get("id",None)
ocname = oc["name"]
if not ocid:
ocid = ocname
self.out.write("%s.%s=%s\n" % (to, ocid,ocname))
def convert_outcome(self, as_field):
self._convert("workflowtask.outcome", as_field)
def convert_options(self, field):
field_id, alf_id, name = build_field_ids(field, self.namespace)
self._convert("listconstraint.%s_%s" % (self.namespace_uri, field_id), field)
def complete(self):
Output.complete(self)
class ShareConfigOutput(Output):
def __init__(self, output_dir, module_name):
Output.__init__(self,output_dir,"share.xml", module_name)
def begin(self, model_name, namespace_uri, namespace):
self.out.write("<alfresco-config>\n")
def complete(self):
self.out.write("""
</alfresco-config>
""")
Output.complete(self)
##########################################################################
class ShareFormConfigOutput(object):
default_indent = " "
def __init__(self, share_config, process_id, form_ref, namespace):
self.share_config = share_config
self.process_id = process_id
self.form_ref = form_ref
self.namespace = namespace
self.custom_transitions = []
self.visabilities = []
self.appearances = []
def record_visibility(self, vis):
self.visabilities.append(vis)
def record_appearance(self, app):
self.appearances.append(app)
def record_custom_transition(self, field_id):
self.custom_transitions.append(field_id)
def convert_field(self, field):
field_id, alf_id, name = build_field_ids(field, self.namespace)
ftype, alf_type, options, required = build_field_type(field)
# Record the Share "field-visibility" for this
self.record_visibility(alf_id)
# Record the appearance details
appearance = "<field id=\"%s\"" % alf_id
if name:
appearance += " label=\"%s\"" % escape(name)
if field.get("readOnly", False):
appearance += " read-only=\"true\""
appearance += ">\n"
value = escape(field.get("value",None) or "")
if ftype == "readonly-text":
appearance += " <control template=\"/org/alfresco/components/form/controls/readonly.ftl\">\n"
appearance += " <control-param name=\"value\">%s</control-param>\n" % value
appearance += " </control>\n"
if ftype == "multi-line-text":
appearance += " <control template=\"/org/alfresco/components/form/controls/textarea.ftl\">\n"
appearance += " <control-param name=\"value\">%s</control-param>\n" % value
appearance += " </control>\n"
if ftype in ("radio-buttons","dropdown") and options:
appearance += " <control template=\"/org/alfresco/components/form/controls/selectone.ftl\">\n"
appearance += " <control-param name=\"options\">%s</control-param>\n" % ",".join([ escape(o["name"]) for o in options])
appearance += " </control>\n"
if field.get("transition", False):
appearance += " <control template=\"/org/alfresco/components/form/controls/workflow/activiti-transitions.ftl\" />\n"
self.record_custom_transition(alf_id)
appearance += "</field>\n"
self.record_appearance(appearance)
def write_out(self, is_start=False, as_start=False):
share_config = self.share_config
default_indent = ShareFormConfigOutput.default_indent
if as_start:
share_config.write("""
<config evaluator="string-compare" condition="activiti$%s">
""" % (self.process_id))
else:
share_config.write("""
<config evaluator="task-type" condition="%s">
""" % (self.form_ref))
# TODO What about <form id="workflow-details"> for non-start tasks?
share_config.write(" <forms>\n")
share_config.write(" <form>\n")
share_config.write(default_indent+"<field-visibility>\n")
for vis in self.visabilities:
# Convert for non-start as needed
if not as_start and "bpm:assignee" == vis:
vis = "taskOwner"
# Custom transitions must come last
if vis in self.custom_transitions:
continue
# Output
share_config.write(default_indent+" <show id=\"%s\" />\n" % vis)
if not as_start:
share_config.write(default_indent+" <show id=\"%s\" />\n" % "bpm:taskId")
share_config.write(default_indent+" <show id=\"%s\" />\n" % "bpm:status")
if not is_start and not self.custom_transitions:
share_config.write(default_indent+" <show id=\"%s\" />\n" % "transitions")
for trnid in self.custom_transitions:
share_config.write(default_indent+" <show id=\"%s\" />\n" % trnid)
share_config.write(default_indent+"</field-visibility>\n")
share_config.write(default_indent+"<appearance>\n")
for app in self.appearances:
# Output as-is with indent
for l in [x for x in app.split("\n") if x]:
share_config.write("%s %s\n" % (default_indent,l))
if not is_start and not self.custom_transitions:
share_config.write(default_indent+" <field id=\"transitions\"/>\n")
share_config.write(default_indent+"</appearance>\n")
share_config.write(" </form>\n")
share_config.write(" </forms>\n")
share_config.write(" </config>\n")
##########################################################################
def get_alfresco_task_types(form):
"Returns the Alfresco model type and Share form type for a given task"
task_tag = form.form_tag
if "{" in task_tag and "}" in task_tag:
tag_ns = task_tag.split("{")[1].split("}")[0]
tag_name = task_tag.split("}")[1]
mt = model_types.get(tag_ns, None)
if not mt:
print "Error - no tag mappings found for namespace %s" % tag_ns
print "Unable to process %s" % task_tag
sys.exit(1)
alf_type = mt.get(tag_name, None)
if not alf_type:
print "Error - no tag mappings found for tag %s" % tag_name
print "Unable to process %s" % task_tag
sys.exit(1)
# Is it a start task?
is_start_task = False
if alf_type == start_task:
is_start_task = True
return (alf_type, is_start_task)
print "Error - Activiti task with form but no namespace - %s" % task_tag
sys.exit(1)
def build_field_ids(field, namespace):
field_id = field["id"]
for c in (u"\u2019","&",",",".",":",";"):
field_id = field_id.replace(c,"")
alf_id = "%s:%s" % (namespace, field_id)
name = field.get("name", None)
return (field_id, alf_id, name)
def build_field_type(field):
ftype = field["type"]
# If type is "readonly", ensure the read only flag is properly set
if ftype == "readonly":
field["readOnly"] = True
# Is it one where the type information is nested?
if ftype in type_nested_in_params:
ftype = field["params"]["field"]["type"]
# Check how to convert
if not property_types.has_key(ftype) and not assoc_types.has_key(ftype):
print "Warning - unhandled type %s" % ftype
print _field_to_json(field)
ftype = "text"
alf_type = property_types.get(ftype, None)
required = field.get("required", False)
options = field.get("options", None)
return (ftype, alf_type, options, required)
def _field_to_json(field):
# Exclude bits we added onto the field
import json
fieldsmpl = dict((k,v) for k,v in field.iteritems() if not "aspect" in k)
return json.dumps(fieldsmpl, sort_keys=True, indent=4, separators=(',', ': '))
##########################################################################
class AssigneeFixer(BPMNFixer):
def __init__(self):
BPMNFixer.__init__(self,None,"{%s}assignee" % activiti_ns)
def fix_for_attr(self, task, assignee):
if assignee in ("${initiator}","$INITIATOR"):
task.set(self.attr, "${initiator.properties.userName}")
AssigneeFixer()
class DueDateFixer(BPMNFixer):
def __init__(self):
BPMNFixer.__init__(self,None,"{%s}dueDate" % activiti_ns)
def fix_for_attr(self, task, due_date):
if "${taskDueDateBean" in due_date:
tag = task.tag.replace("{%s}"%activiti_ns,"").replace("{%s}"%bpmn20_ns,"")
print ""
print "WARNING: Activiti-online only Due Date found"
print " %s" % due_date
print "The due date for %s / %s will be removed" % (tag, task.get("id","n/a"))
task.attrib.pop(self.attr)
DueDateFixer()
class ActivitiMailFixer(BPMNFixer):
"""
Alfrecso doesn't override/customise the Activiti MailActivityBehavior.
To avoid mailing issues, we need to re-write Activiti mail service tasks
into Alfresco mail actions
"""
type_attr = "{%s}type"%activiti_ns
field_mappings = {"to":"to","from":"from","subject":"subject","text":"text"}
defaults = {"subject":"Activiti Workflow Task"}
def __init__(self):
BPMNFixer.__init__(self,"{%s}serviceTask"%bpmn20_ns,None)
def fix_for_tag(self, task):
if not task.get(ActivitiMailFixer.type_attr) == "mail":
return
extension = task.findall("{%s}extensionElements"%bpmn20_ns)[0]
# Change it to a script task
task.tag = "{%s}scriptTask"%bpmn20_ns
task.set("scriptFormat","javascript")
task.attrib.pop(ActivitiMailFixer.type_attr)
# Build the script for mailing, and remove the Activiti fields
script = "var mail = actions.create('mail');\n"
done_fields = []
for field in extension.findall("{%s}field" % activiti_ns):
ftype = field.get("name")
done_fields.append("field")
if ActivitiMailFixer.field_mappings.has_key(ftype):
alftype = ActivitiMailFixer.field_mappings[ftype]
value = field.findall("{%s}string"%activiti_ns)[0].text
script += "mail.parameters.%s = '%s';\n" % (alftype,value)
else:
print ""
print "WARNING: Unknown Activiti-online mail field found"
print " %s" % exp
extension.remove(field)
for req_field, value in ActivitiMailFixer.defaults.items():
if not req_field in done_fields:
script += "mail.parameters.%s = '%s';\n" % (req_field, value)
script += "mail.execute(bpm_package);\n"
# Add the mailing script to the BPMN
BPMNFixer.add_script(extension, "start", script)
# Add a dummy script tag in the "wrong" place
emptyscript = ET.SubElement(task, "{%s}script"%bpmn20_ns)
emptyscript.text = "// No script here, run via an Execution listener"
ActivitiMailFixer()
class FlowConditionFixer(BPMNFixer):
condition_bean = "activiti_flowConditionsBean"
condition_bean_exists = "%s.exists" % condition_bean
outcomes = {}
def __init__(self):
BPMNFixer.__init__(self,"{%s}conditionExpression"%bpmn20_ns,None)
@classmethod
def register_outcome(cls, form_ref, outcome_prop):
cls.outcomes[form_ref] = outcome_prop
def fix_for_tag(self, tag):
otype = tag.get("{%s}type" % xsi_ns)
if otype == "tFormalExpression":
exp = tag.text
for form_id,alf_prop in FlowConditionFixer.outcomes.items():
aoe = "${form" + form_id + "outcome"
if exp.startswith(aoe):
act_prop = alf_prop.replace(":","_")
repl = exp.replace(aoe, "${%s"%act_prop)
tag.text = repl
return
if FlowConditionFixer.condition_bean in exp:
# TODO Is this the right replacement?
import re
repl = re.sub(FlowConditionFixer.condition_bean_exists+"\((\w+),\s+(\'\w+\')\)","(exists \\1.getVariable(\\2))", exp)
if not FlowConditionFixer.condition_bean in repl:
tag.text = repl
return
# If we get here, we don't know how to fix it up!
print ""
print "WARNING: Activiti-online only sequence condition found"
print " %s" % exp
FlowConditionFixer()
class TaskToExecutionFixer(object):
"""
Annoyingly, in most cases, Activiti under Alfresco won't make the
task object available when scripts and expressions run
So, for those we know will need it, explicitly copy the values from
the task scope to the execution scope, so they can be used
"""
extensionElements = "{%s}extensionElements"%bpmn20_ns
@classmethod
def fix(cls, task_tag, property_ids, outcome_ids):
# Build the list of things to fix
tofix = {}
def to_fix(on, there, source):
if not tofix.has_key(on):
tofix[on] = {}
id1, id2 = [x.replace(":","_") for x in [there,source]]
tofix[on][id1] = id2
for alf_prop in property_ids:
to_fix("execution", alf_prop, alf_prop)
for alf_prop in outcome_ids:
to_fix("execution", alf_prop, alf_prop)
to_fix("execution", "bpmn_outcome", alf_prop)
to_fix("task", "bpmn_outcome", alf_prop)
# If nothing needed changing, finish now
if not tofix:
return
# Build the script to do the fixing
script = "\n// Sync variables with other scopes\n"
sscope = "var scopes = { "
script += "var fixes = {\n"
for idx, on in enumerate(tofix.keys()):
if idx != 0:
script += ",\n"
sscope += ", "
script += " '%s': {\n" % on
sscope += "'%s':%s" % (on,on)
first = True
for k in sorted(tofix[on].keys()):
v = tofix[on][k]
script += "%s '%s':'%s'" % ("" if first else ",\n",k,v)
first = False
script += "\n }"
script += "\n};\n"
script += sscope + " };\n"
script += "for (var vtype in fixes) {\n"
script += " for (var vn in fixes[vtype]) {\n"
script += " var vn2 = fixes[vtype][vn];\n"
script += " var val = task.getVariable(vn2);\n"
script += " if(val) { scopes[vtype].setVariable(vn, val); }\n"
script += " }\n"
script += " logger.debug('Synced ' + Object.keys(fixes[vtype].length) + ' items for ' + vtype);\n"
script += "}\n"
# Add the extension element if needed
ee = task_tag.findall(cls.extensionElements)
if ee:
extension = ee[0]
else:
extension = ET.SubElement(task_tag, cls.extensionElements)
# Work out the script type
script_type = "complete"
if task_tag.tag == start_task:
script_type = "start"
# Add the script
BPMNFixer.add_script(extension, script_type, script)