1 package org.telscenter.pas.util;
2
3 import java.io.File;
4 import java.io.FileOutputStream;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10 import java.util.Map.Entry;
11 import java.util.logging.Logger;
12
13 import net.sf.sail.core.beans.Pod;
14 import net.sf.sail.core.beans.assembly.Assignment;
15 import net.sf.sail.core.beans.assembly.IndexedPropertyRef;
16 import net.sf.sail.core.beans.assembly.PodRegistry;
17 import net.sf.sail.core.beans.assembly.PodVarDelegate;
18 import net.sf.sail.core.beans.assembly.PropertyRef;
19 import net.sf.sail.core.beans.assembly.SimpleContainer;
20 import net.sf.sail.core.util.BinaryUtils;
21 import net.sf.sail.core.util.PodUtils;
22 import net.sf.sail.core.util.SailBeanUtils;
23 import net.sf.sail.core.uuid.CurnitUuid;
24
25 import org.apache.commons.lang.math.RandomUtils;
26 import org.telscenter.pas.beans.PasActivity;
27 import org.telscenter.pas.beans.PasProject;
28 import org.telscenter.pas.beans.PasStep;
29
30 public class PasCurnitUtils {
31
32 /***
33 * Logger for this class
34 */
35 private static final Logger logger = Logger.getLogger(PasCurnitUtils.class
36 .getName());
37
38 /***
39 * @param activityPod
40 * @return
41 */
42 public static PasActivity activityFromPod(Pod activityPod) {
43 PasActivity activity = SailBeanUtils.firstChildOfType(activityPod,
44 PasActivity.class);
45 assert activity != null;
46 return activity;
47 }
48
49 /***
50 * Adds the activity bean into the project bean at the specified index.
51 *
52 * If the two beans are in the same pod, they will remain in the same pod.
53 *
54 * If they are in separate pods, a hierarchical relationship will be made
55 * between them and inter-pod links to reference the beans across the pod
56 * boundaries.
57 *
58 * Assumes that projectPod has one PasProject bean and activityPod has one
59 * PasActivity bean. Also that each bean has an enclosing pod.
60 */
61 public static void addActivity(PasProject project, int activityIndex,
62 PasActivity activity) {
63 Pod projectPod = PodUtils.resolvePod(project);
64 Pod activityPod = PodUtils.resolvePod(activity);
65 if (projectPod == activityPod)
66 addActivitySharePod(project, activityIndex, activity);
67 else
68 addActivityOwnPod(projectPod, project, activityIndex, activityPod,
69 activity);
70 }
71
72 /***
73 * To the project pod and its project bean, adds the activity pod and its
74 * activity bean at the specified index.
75 *
76 * Assumes that projectPod has one PasProject bean and activityPod has one
77 * PasActivity bean.
78 */
79 @Deprecated
80 public static void addActivity(Pod projectPod, int index, Pod activityPod) {
81 PasProject project = projectFromPod(projectPod);
82 PasActivity activity = activityFromPod(activityPod);
83 addActivityOwnPod(projectPod, project, index, activityPod, activity);
84 }
85
86 /***
87 * Makes activityPod a child of projectPod and adds an assembly assignment
88 * of the activity bean into the specified index of the project bean's
89 * activities property
90 *
91 * @param projectPod
92 * @param project
93 * @param activityIndex
94 * @param activityPod
95 * @param activity
96 */
97 static void addActivityOwnPod(Pod projectPod, PasProject project,
98 int activityIndex, Pod activityPod, PasActivity activity) {
99
100 insertActivityInProjectBean(project, activityIndex, activity);
101
102
103 projectPod.add(activityPod);
104 projectPod.touch();
105 activityPod.add(activity);
106 activityPod.touch();
107
108
109
110 String leftName = "importActivity-" + RandomUtils.nextInt();
111 PropertyRef pr = new IndexedPropertyRef(project, "activities",
112 activityIndex);
113 projectPod.importProperty(pr, leftName);
114 PodVarDelegate podIn = new PodVarDelegate(projectPod.getPodId(),
115 leftName);
116 String rightName = "activity";
117 PodVarDelegate podOut = new PodVarDelegate(activityPod.getPodId(),
118 rightName);
119 SimpleContainer sc = new SimpleContainer();
120 sc.setValue(activity);
121 activityPod.add(sc);
122 activityPod.exportProperty(sc.getPropertyRef(), rightName);
123 Assignment assignment = new Assignment(podIn, podOut);
124 projectPod.getAssemblyCalls().add(assignment);
125 }
126
127 /***
128 *
129 */
130 static void addActivitySharePod(PasProject project, int activityIndex,
131 PasActivity activity) {
132 Pod projectPod = PodUtils.resolvePod(project);
133 Pod activityPod = PodUtils.resolvePod(activity);
134 if (projectPod != activityPod)
135 throw new IllegalArgumentException(
136 "project and activity arguments must belong to same pod");
137
138 insertActivityInProjectBean(project, activityIndex, activity);
139 projectPod.touch();
140 }
141
142 /***
143 * Adds the step bean into the activity bean at the specified index.
144 *
145 * If the two beans are in the same pod, they will remain in the same pod.
146 *
147 * If they are in separate pods, a hierarchical relationship will be made
148 * between them and inter-pod links to reference the beans across the pod
149 * boundaries.
150 *
151 * Assumes that activityPod has one PasActivity bean and stepPod has one
152 * PasStep bean. Also that each bean has an enclosing pod.
153 */
154 public static void addStep(PasActivity activity, int stepIndex, PasStep step) {
155 Pod activityPod = PodUtils.resolvePod(activity);
156 Pod stepPod = PodUtils.resolvePod(step);
157 if (activityPod == stepPod)
158 addStepSharePod(activity, stepIndex, step);
159 else
160 addStepOwnPod(activityPod, activity, stepIndex, stepPod, step);
161 }
162
163 /***
164 * To the activity pod and its activity bean, adds the step pod and its step
165 * bean at the specified index.
166 *
167 * Assumes that activityPod has one PasActivity bean and stepPod has one
168 * PasStep bean.
169 */
170 @Deprecated
171 public static void addStep(Pod activityPod, int stepIndex, Pod stepPod) {
172 PasActivity activity = activityFromPod(activityPod);
173 PasStep step = stepFromPod(stepPod);
174 addStepOwnPod(activityPod, activity, stepIndex, stepPod, step);
175 }
176
177 /***
178 * Adds the step bean in the list of the activity bean's steps at the index;
179 * makes step pod a child of activity pod and adds an assembly assignment of
180 * the step bean into the specified index of the activity bean's steps
181 * property.
182 *
183 * @param activityPod
184 * @param activity
185 * @param stepIndex
186 * @param stepPod
187 * @param step
188 */
189 static void addStepOwnPod(Pod activityPod, PasActivity activity,
190 int stepIndex, Pod stepPod, PasStep step) {
191 insertStepInActivityBean(activity, stepIndex, step);
192
193
194 activityPod.add(stepPod);
195 activityPod.touch();
196 stepPod.add(step);
197 stepPod.touch();
198
199
200 String leftName = "importStep-" + RandomUtils.nextInt();
201 PropertyRef pr = new IndexedPropertyRef(activity, "steps", stepIndex);
202 activityPod.importProperty(pr, leftName);
203 PodVarDelegate podIn = new PodVarDelegate(activityPod.getPodId(),
204 leftName);
205 String rightName = "step";
206 PodVarDelegate podOut = new PodVarDelegate(stepPod.getPodId(),
207 rightName);
208 SimpleContainer sc = new SimpleContainer();
209 sc.setValue(step);
210 stepPod.add(sc);
211 stepPod.exportProperty(sc.getPropertyRef(), rightName);
212 Assignment assignment = new Assignment(podIn, podOut);
213 activityPod.getAssemblyCalls().add(assignment);
214 }
215
216 /***
217 *
218 */
219 static void addStepSharePod(PasActivity activity, int stepIndex,
220 PasStep step) {
221 Pod activityPod = PodUtils.resolvePod(activity);
222 Pod stepPod = PodUtils.resolvePod(step);
223 if (activityPod != stepPod)
224 throw new IllegalArgumentException(
225 "activity and step arguments must belong to same pod");
226
227 insertStepInActivityBean(activity, stepIndex, step);
228 activityPod.touch();
229 }
230
231 public static PasProject findPasProject(Pod pod) {
232 for (Object element : pod) {
233 if (element instanceof PasProject)
234 return (PasProject) element;
235 }
236 return null;
237 }
238
239 /***
240 * @param project
241 * @param activityIndex
242 * @param activity
243 */
244 public static void insertActivityInProjectBean(PasProject project,
245 int activityIndex, PasActivity activity) {
246
247 final PasActivity[] oldActivities = project.getActivities();
248 final PasActivity[] newActivities = new PasActivity[oldActivities.length + 1];
249 System.arraycopy(oldActivities, 0, newActivities, 0, activityIndex);
250 newActivities[activityIndex] = activity;
251 System.arraycopy(oldActivities, activityIndex, newActivities,
252 activityIndex + 1, oldActivities.length - activityIndex);
253
254
255 project.setActivities(newActivities);
256 }
257
258 /***
259 * @param activity
260 * @param stepIndex
261 * @param step
262 */
263 public static void insertStepInActivityBean(PasActivity activity,
264 int stepIndex, PasStep step) {
265
266 final PasStep[] oldSteps = activity.getSteps();
267 final PasStep[] newSteps = new PasStep[oldSteps.length + 1];
268 System.arraycopy(oldSteps, 0, newSteps, 0, stepIndex);
269 newSteps[stepIndex] = step;
270 System.arraycopy(oldSteps, stepIndex, newSteps, stepIndex + 1,
271 oldSteps.length - stepIndex);
272
273
274 activity.setSteps(newSteps);
275 }
276
277 /***
278 * move step to a different activity
279 *
280 *
281 * @param activityDes
282 * @param activitySource
283 * @param movedStep
284 * @param newIndex
285 */
286 public static void moveTo(PasActivity activityDes,
287 PasActivity activitySource, PasStep movedStep, int newIndex) {
288
289
290
291 List<PasStep> newDesStepList = new ArrayList<PasStep>(Arrays
292 .asList(activityDes.getSteps()));
293 List<PasStep> newSourceStepList = new ArrayList<PasStep>(Arrays
294 .asList(activitySource.getSteps()));
295 if (!newSourceStepList.contains(movedStep)) {
296 throw new RuntimeException("step not in activity on reorder");
297 }
298
299
300 newSourceStepList.remove(movedStep);
301
302
303
304 newDesStepList.add(newIndex, movedStep);
305
306 for (PasStep step : newSourceStepList) {
307 addStep(activitySource, newSourceStepList.indexOf(step), step);
308 }
309
310 for (PasStep step : newDesStepList) {
311 addStep(activityDes, newDesStepList.indexOf(step), step);
312 }
313
314 removeStep(activitySource, movedStep);
315 }
316
317 /***
318 * moves a step to a new position in the same activity
319 *
320 * @param activity
321 * @param movedStep
322 * @param newIndex
323 */
324 public static void moveTo(PasActivity activity, PasStep movedStep,
325 int newIndex) {
326
327
328
329 List<PasStep> newStepList = new ArrayList<PasStep>(Arrays
330 .asList(activity.getSteps()));
331 if (!newStepList.contains(movedStep)) {
332 throw new RuntimeException("step not in activity on reorder");
333 }
334
335
336 newStepList.remove(movedStep);
337
338
339 newStepList.add(newIndex, movedStep);
340
341
342 removeStepFromActivityBean(activity, movedStep);
343
344
345 insertStepInActivityBean(activity, newIndex, movedStep);
346
347
348
349
350
351 }
352
353 /***
354 * reorder the activities
355 *
356 * @param pasProject -
357 * the pasProject
358 * @param movedActivity -
359 * the activity to move somewhere
360 * @param newIndex -
361 * its new position
362 */
363 public static void moveTo(PasProject pasProject, PasActivity movedActivity,
364 int newIndex) {
365
366
367
368
369 PasActivity[] activities = pasProject.getActivities();
370 List<PasActivity> newActivityList = new ArrayList<PasActivity>(Arrays
371 .asList(activities));
372 if (!newActivityList.contains(movedActivity)) {
373 throw new RuntimeException("Activity not in project on reorder");
374 }
375
376
377 newActivityList.remove(movedActivity);
378
379 newActivityList.add(newIndex, movedActivity);
380
381
382
383
384
385
386
387 newActivityList.toArray(activities);
388
389
390 pasProject.setActivities(activities);
391 }
392
393 /***
394 * @param projectPod
395 * @return
396 */
397 public static PasProject projectFromPod(Pod projectPod) {
398 PasProject project = SailBeanUtils.firstChildOfType(projectPod,
399 PasProject.class);
400 assert project != null;
401 return project;
402 }
403
404 /***
405 * Removes the step bean and its enclosing pod from the project bean and its
406 * enclosing pod.
407 *
408 * @param project
409 * @param activity
410 */
411 public static void removeActivity(PasProject project, PasActivity activity) {
412 Pod projectPod = PodUtils.resolvePod(project);
413 Pod activityPod = PodUtils.resolvePod(activity);
414 if (projectPod == activityPod)
415 removeActivitySharePod(project, activity);
416 else
417 removeActivityOwnPod(project, activity);
418 }
419
420 /***
421 * @param project
422 * @param activity
423 * @return index of activity that was removed
424 */
425 public static int removeActivityFromProjectBean(PasProject project,
426 PasActivity activity) {
427 int index;
428 PasActivity[] oldActivities = project.getActivities();
429
430 for (index = 0; index < oldActivities.length; index++) {
431 if (activity == oldActivities[index])
432 break;
433 }
434
435
436 if (index == oldActivities.length)
437 throw new RuntimeException(
438 "activity not in project's activity list");
439
440
441 PasActivity[] newActivities = new PasActivity[oldActivities.length - 1];
442 System.arraycopy(oldActivities, 0, newActivities, 0, index);
443
444 System.arraycopy(oldActivities, index + 1, newActivities, index,
445 newActivities.length - index);
446
447
448 project.setActivities(newActivities);
449 return index;
450 }
451
452 /***
453 * Removes the activity bean and its enclosing pod from the project bean and
454 * its enclosing pod.
455 *
456 * @param project
457 * @param activity
458 */
459 static void removeActivityOwnPod(PasProject project, PasActivity activity) {
460 int index = removeActivityFromProjectBean(project, activity);
461
462
463 Pod projectPod = PodUtils.resolvePod(project);
464 Pod activityPod = PodUtils.resolvePod(activity);
465
466
467
468 projectPod.touch();
469
470
471 projectPod.remove(activityPod);
472
473
474 PropertyRef acRef = null;
475 Set<PropertyRef> transientRefs = projectPod.getTransientRefs();
476 for (PropertyRef importRef : transientRefs) {
477 if (activity == importRef.getTarget()) {
478 acRef = importRef;
479 transientRefs.remove(acRef);
480 break;
481 }
482 }
483
484
485
486
487 PodRegistry registry = PodRegistry.getDefaultRegistry();
488 List<Assignment> assemblyCalls = projectPod.getAssemblyCalls();
489 for (Assignment assignment : assemblyCalls) {
490 if (acRef == assignment.getLeft().getRef(registry)) {
491 assemblyCalls.remove(assignment);
492 break;
493 }
494 }
495
496
497
498 Map<String, PropertyRef> vars = projectPod.getVars();
499 Set<Entry<String, PropertyRef>> entrySet = vars.entrySet();
500
501
502 List<Entry<String, PropertyRef>> entries = new ArrayList<Entry<String, PropertyRef>>(
503 entrySet);
504 for (Map.Entry<String, PropertyRef> e : entries) {
505
506 String bindingKey = e.getKey();
507 PropertyRef entryValue = e.getValue();
508
509
510
511
512 if (entryValue instanceof IndexedPropertyRef) {
513 IndexedPropertyRef ipRef = (IndexedPropertyRef) entryValue;
514
515
516
517
518
519 if (ipRef.getPropertyName().equals("activities")) {
520
521
522
523 if (ipRef.getTarget() != project)
524 throw new IllegalStateException(
525 "\"activities\" property not on project bean");
526
527 int refIndex = ipRef.getIndex();
528
529 if (refIndex == index) {
530
531 activityPod.getVars().remove(bindingKey);
532 } else if (refIndex >= index) {
533
534 PropertyRef newRef = new IndexedPropertyRef(project,
535 "activities", refIndex - 1);
536
537
538 projectPod.getVars().remove(bindingKey);
539
540
541 projectPod.importProperty(newRef, bindingKey);
542 logger.info("rebound " + ipRef + " with " + newRef);
543 }
544 }
545 }
546 }
547
548 }
549
550 /***
551 * Removes the activity bean and its enclosing pod from the project bean and
552 * its enclosing pod.
553 *
554 * @param project
555 * @param activity
556 */
557 static void removeActivitySharePod(PasProject project, PasActivity activity) {
558 removeActivityFromProjectBean(project, activity);
559 Pod projectPod = PodUtils.resolvePod(project);
560 projectPod.touch();
561 }
562
563 /***
564 * Removes the step bean and its enclosing pod from the project bean and its
565 * enclosing pod.
566 *
567 * @param project
568 * @param activity
569 */
570 public static void removeStep(PasActivity activity, PasStep step) {
571 Pod activityPod = PodUtils.resolvePod(activity);
572 Pod stepPod = PodUtils.resolvePod(step);
573 if (activityPod == stepPod)
574 removeStepSharePod(activity, step);
575 else
576 removeStepOwnPod(activity, step);
577 }
578
579 /***
580 * @param activity
581 * @param step
582 * @return index of step that was removed
583 */
584 public static int removeStepFromActivityBean(PasActivity activity,
585 PasStep step) {
586 int index;
587 PasStep[] oldSteps = activity.getSteps();
588
589 for (index = 0; index < oldSteps.length; index++) {
590 if (step == oldSteps[index])
591 break;
592 }
593
594
595 if (index == oldSteps.length)
596 throw new RuntimeException("step not in activity's step list");
597
598
599 PasStep[] newSteps = new PasStep[oldSteps.length - 1];
600 System.arraycopy(oldSteps, 0, newSteps, 0, index);
601
602 System.arraycopy(oldSteps, index + 1, newSteps, index, newSteps.length
603 - index);
604
605
606 activity.setSteps(newSteps);
607 return index;
608 }
609
610 /***
611 * Removes the step bean and its enclosing pod from the project bean and its
612 * enclosing pod.
613 *
614 * @param project
615 * @param activity
616 */
617 static void removeStepOwnPod(PasActivity activity, PasStep step) {
618 int index = removeStepFromActivityBean(activity, step);
619
620
621 Pod activityPod = PodUtils.resolvePod(activity);
622 Pod stepPod = PodUtils.resolvePod(step);
623
624
625
626 activityPod.touch();
627
628
629 activityPod.remove(stepPod);
630
631
632 PropertyRef acRef = null;
633 Set<PropertyRef> transientRefs = activityPod.getTransientRefs();
634 for (PropertyRef importRef : transientRefs) {
635 if (step == importRef.getTarget()) {
636 acRef = importRef;
637 transientRefs.remove(acRef);
638 break;
639 }
640 }
641
642
643
644
645 PodRegistry registry = PodRegistry.getDefaultRegistry();
646 List<Assignment> assemblyCalls = activityPod.getAssemblyCalls();
647 for (Assignment assignment : assemblyCalls) {
648 if (acRef == assignment.getLeft().getRef(registry)) {
649 assemblyCalls.remove(assignment);
650 break;
651 }
652 }
653
654
655
656 Map<String, PropertyRef> vars = activityPod.getVars();
657 Set<Entry<String, PropertyRef>> entrySet = vars.entrySet();
658
659
660 List<Entry<String, PropertyRef>> entries = new ArrayList<Entry<String, PropertyRef>>(
661 entrySet);
662 for (Map.Entry<String, PropertyRef> e : entries) {
663
664 String bindingKey = e.getKey();
665 PropertyRef entryValue = e.getValue();
666
667 if (entryValue instanceof IndexedPropertyRef) {
668 IndexedPropertyRef ipRef = (IndexedPropertyRef) entryValue;
669 if (ipRef.getPropertyName().equals("steps")) {
670
671
672
673 if (ipRef.getTarget() != activity)
674 throw new IllegalStateException(
675 "\"steps\" property not on activity bean");
676
677 int refIndex = ipRef.getIndex();
678
679 if (refIndex == index) {
680
681 activityPod.getVars().remove(bindingKey);
682 } else if (refIndex >= index) {
683
684 PropertyRef newRef = new IndexedPropertyRef(activity,
685 "steps", refIndex - 1);
686
687
688 activityPod.getVars().remove(bindingKey);
689
690
691 activityPod.importProperty(newRef, bindingKey);
692 logger.info("rebound " + ipRef + " with " + newRef);
693 }
694 }
695 }
696 }
697
698 }
699
700 /***
701 * Removes the step from the activity and its enclosing pod.
702 *
703 * @param activity
704 * @param step
705 */
706 private static void removeStepSharePod(PasActivity activity, PasStep step) {
707 removeStepFromActivityBean(activity, step);
708 Pod activityPod = PodUtils.resolvePod(activity);
709 activityPod.remove(step);
710 }
711
712 /***
713 * @param stepPod
714 * @return
715 */
716 public static PasStep stepFromPod(Pod stepPod) {
717 PasStep step = SailBeanUtils.firstChildOfType(stepPod, PasStep.class);
718 assert step != null;
719 return step;
720 }
721
722 /***
723 * writes the curnit to a file
724 *
725 * @param curnitTitle
726 * @param curnitId
727 * @param rootPod
728 * @return
729 * @throws Exception
730 */
731 public static File writeCurnit(String path, String curnitTitle,
732 CurnitUuid curnitId, Pod rootPod) throws Exception {
733 File outputFile = new File(path + curnitTitle + ".jar");
734 FileOutputStream output = new FileOutputStream(outputFile);
735 BinaryUtils.writeCurnit(curnitId, curnitTitle, rootPod, output);
736 return outputFile;
737 }
738
739 }