View Javadoc

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 		// set up pod relationship
103 		projectPod.add(activityPod);
104 		projectPod.touch(); // mark as having been modified
105 		activityPod.add(activity);
106 		activityPod.touch(); // mark as having been modified
107 
108 		// give the varname a random component so it doesn't conflict with a
109 		// future import
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 		// set up pod relationship
194 		activityPod.add(stepPod);
195 		activityPod.touch(); // mark as having been modified
196 		stepPod.add(step);
197 		stepPod.touch(); // mark as having been modified
198 
199 		// set up import of value between pods
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 		}// if
236 		return null;
237 	}// findPasProject
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 		// update activity list of project bean
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 		// must set the property for the project to know
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 		// update steps list of activity bean
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 		// must set the property for the activity to know
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 		// TODO operate more efficiently/simply when step is in same pod as
289 		// activities
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 		}// if
298 
299 		// first remove it from the source
300 		newSourceStepList.remove(movedStep);
301 
302 		// removeStep(activitySource, movedStep);
303 		// insert and shifts to right to the des list
304 		newDesStepList.add(newIndex, movedStep);
305 
306 		for (PasStep step : newSourceStepList) {
307 			addStep(activitySource, newSourceStepList.indexOf(step), step);
308 		}// for
309 
310 		for (PasStep step : newDesStepList) {
311 			addStep(activityDes, newDesStepList.indexOf(step), step);
312 		}// for
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 		// TODO operate more efficiently/simply when step is in same pod as
327 		// activity
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 		}// if
334 
335 		// first remove it
336 		newStepList.remove(movedStep);
337 
338 		// insert and shifts to right
339 		newStepList.add(newIndex, movedStep);
340 
341 		//first remove it
342 		removeStepFromActivityBean(activity, movedStep);
343 		
344 		//insert it again
345 		insertStepInActivityBean(activity, newIndex, movedStep);
346 //		activity.setSteps(beans)
347 //		for (PasStep step : newStepList) {
348 //			addStep(activity, newStepList.indexOf(step), step);
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 		// TODO operate more efficiently/simply when activity is in same pod as
366 		// project
367 
368 		// does this activity exist in the project?
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 		}// if
375 
376 		// remove the old one
377 		newActivityList.remove(movedActivity);
378 		// add new one
379 		newActivityList.add(newIndex, movedActivity);
380 
381 //		for (PasActivity pasActivity : newActivityList) {
382 //			addActivity(pasProject, newActivityList.indexOf(pasActivity),
383 //					pasActivity);
384 //		}
385 		
386 		//move the new activity list to the activities array
387 		newActivityList.toArray(activities);
388 		
389 		//set the activities in the project to the updated activities
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; // found
433 		}
434 
435 		// in case we passed through the end of the list
436 		if (index == oldActivities.length)
437 			throw new RuntimeException(
438 					"activity not in project's activity list");
439 
440 		// create new activity array from the old minus the removed activity
441 		PasActivity[] newActivities = new PasActivity[oldActivities.length - 1];
442 		System.arraycopy(oldActivities, 0, newActivities, 0, index);
443 		// skip the index which has the removed activity
444 		System.arraycopy(oldActivities, index + 1, newActivities, index,
445 				newActivities.length - index);
446 
447 		// set new shorter activity list
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 		// find the pods of the beans
463 		Pod projectPod = PodUtils.resolvePod(project);
464 		Pod activityPod = PodUtils.resolvePod(activity);
465 
466 		// mark the project pod as having been modified and do it before the
467 		// following code pulls up its pod id
468 		projectPod.touch();
469 
470 		// remove the activity pod from the project pod
471 		projectPod.remove(activityPod);
472 
473 		// remove from the imports and note which ref was the import
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 		// now remove from the project pod the assembly calls importing the
485 		// activity from its pod (using the acRef)
486 		// FIXME can't assume the default registry
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 		// must reassign rest of imports to target the correct index in the new
497 		// activities array
498 		Map<String, PropertyRef> vars = projectPod.getVars();
499 		Set<Entry<String, PropertyRef>> entrySet = vars.entrySet();
500 
501 		// iterate over copy to avoid ConcurrentModificationException
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 			// System.out.println("VAR ENTRY " + bindingKey + " = " +
510 			// entryValue);
511 
512 			if (entryValue instanceof IndexedPropertyRef) {
513 				IndexedPropertyRef ipRef = (IndexedPropertyRef) entryValue;
514 				// System.out.println("Binding name:" + bindingKey);
515 				// System.out.println("property name:" +
516 				// ipRef.getPropertyName());
517 				// System.out.println("index name:" + ipRef.getIndex());
518 				// System.out.println("TARGET: " + ipRef.getTarget());
519 				if (ipRef.getPropertyName().equals("activities")) {
520 					// ... it's an IndexedPropertyRef referrencing an index of
521 					// an "activities" property
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 						// then that's the import we need to remove
531 						activityPod.getVars().remove(bindingKey);
532 					} else if (refIndex >= index) {
533 						// then we need to shift it down one
534 						PropertyRef newRef = new IndexedPropertyRef(project,
535 								"activities", refIndex - 1);
536 
537 						// remove the current one
538 						projectPod.getVars().remove(bindingKey);
539 
540 						// now rebind
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; // found
592 		}
593 
594 		// in case we passed through the end of the list
595 		if (index == oldSteps.length)
596 			throw new RuntimeException("step not in activity's step list");
597 
598 		// create new activity array from the old minus the removed activity
599 		PasStep[] newSteps = new PasStep[oldSteps.length - 1];
600 		System.arraycopy(oldSteps, 0, newSteps, 0, index);
601 		// skip the index which has the removed activity
602 		System.arraycopy(oldSteps, index + 1, newSteps, index, newSteps.length
603 				- index);
604 
605 		// set new shorter activity list
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 		// find the pods of the beans
621 		Pod activityPod = PodUtils.resolvePod(activity);
622 		Pod stepPod = PodUtils.resolvePod(step);
623 
624 		// mark the project pod as having been modified and do it before the
625 		// following code pulls up its pod id
626 		activityPod.touch();
627 
628 		// remove the activity pod from the project pod
629 		activityPod.remove(stepPod);
630 
631 		// remove from the imports and note which ref was the import
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 		// now remove from the project pod the assembly calls importing the
643 		// activity from its pod (using the acRef)
644 		// FIXME can't assume the default registry
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 		// must reassign rest of imports to target the correct index in the new
655 		// activities array
656 		Map<String, PropertyRef> vars = activityPod.getVars();
657 		Set<Entry<String, PropertyRef>> entrySet = vars.entrySet();
658 
659 		// iterate over copy to avoid ConcurrentModificationException
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 					// ... it's an IndexedPropertyRef referrencing an index of
671 					// an "activities" property
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 						// then that's the import we need to remove
681 						activityPod.getVars().remove(bindingKey);
682 					} else if (refIndex >= index) {
683 						// then we need to shift it down one
684 						PropertyRef newRef = new IndexedPropertyRef(activity,
685 								"steps", refIndex - 1);
686 
687 						// remove the current one
688 						activityPod.getVars().remove(bindingKey);
689 
690 						// now rebind
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 }