View Javadoc
1   /**
2    * 
3    * Copyright (c) 2014-2015, Openflexo
4    * 
5    * This file is part of Excelconnector, a component of the software infrastructure 
6    * developed at Openflexo.
7    * 
8    * 
9    * Openflexo is dual-licensed under the European Union Public License (EUPL, either 
10   * version 1.1 of the License, or any later version ), which is available at 
11   * https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
12   * and the GNU General Public License (GPL, either version 3 of the License, or any 
13   * later version), which is available at http://www.gnu.org/licenses/gpl.html .
14   * 
15   * You can redistribute it and/or modify under the terms of either of these licenses
16   * 
17   * If you choose to redistribute it and/or modify under the terms of the GNU GPL, you
18   * must include the following additional permission.
19   *
20   *          Additional permission under GNU GPL version 3 section 7
21   *
22   *          If you modify this Program, or any covered work, by linking or 
23   *          combining it with software containing parts covered by the terms 
24   *          of EPL 1.0, the licensors of this Program grant you additional permission
25   *          to convey the resulting work. * 
26   * 
27   * This software is distributed in the hope that it will be useful, but WITHOUT ANY 
28   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
29   * PARTICULAR PURPOSE. 
30   *
31   * See http://www.openflexo.org/license.html for details.
32   * 
33   * 
34   * Please contact Openflexo (openflexo-contacts@openflexo.org)
35   * or visit www.openflexo.org if you need additional information.
36   * 
37   */
38  
39  package org.openflexo.foundation.doc.fml;
40  
41  import java.util.ArrayList;
42  import java.util.List;
43  import java.util.logging.Logger;
44  
45  import org.openflexo.connie.BindingEvaluationContext;
46  import org.openflexo.connie.BindingVariable;
47  import org.openflexo.connie.exception.NotSettableContextException;
48  import org.openflexo.connie.exception.NullReferenceException;
49  import org.openflexo.connie.exception.TypeMismatchException;
50  import org.openflexo.connie.expr.ExpressionEvaluator;
51  import org.openflexo.foundation.doc.FlexoDocElement;
52  import org.openflexo.foundation.doc.FlexoDocTable;
53  import org.openflexo.foundation.doc.FlexoDocTableCell;
54  import org.openflexo.foundation.doc.FlexoDocTableRow;
55  import org.openflexo.foundation.doc.FlexoDocument;
56  import org.openflexo.foundation.doc.fml.FlexoTableRole.FlexoTableRoleImpl;
57  import org.openflexo.foundation.fml.annotations.FML;
58  import org.openflexo.foundation.fml.expr.FMLExpressionEvaluator;
59  import org.openflexo.foundation.fml.rt.ActorReference;
60  import org.openflexo.foundation.fml.rt.ModelSlotInstance;
61  import org.openflexo.logging.FlexoLogger;
62  import org.openflexo.pamela.annotations.Adder;
63  import org.openflexo.pamela.annotations.Embedded;
64  import org.openflexo.pamela.annotations.Getter;
65  import org.openflexo.pamela.annotations.Getter.Cardinality;
66  import org.openflexo.pamela.annotations.ImplementationClass;
67  import org.openflexo.pamela.annotations.ModelEntity;
68  import org.openflexo.pamela.annotations.PropertyIdentifier;
69  import org.openflexo.pamela.annotations.Remover;
70  import org.openflexo.pamela.annotations.Setter;
71  import org.openflexo.pamela.annotations.XMLAttribute;
72  import org.openflexo.pamela.annotations.XMLElement;
73  import org.openflexo.toolbox.StringUtils;
74  
75  /**
76   * Implements {@link ActorReference} for {@link FlexoTableRole}.<br>
77   * Represents the actual links in a given {@link FlexoDocument} connecting a template table to a generated table<br>
78   * We need to store here the mapping:
79   * <ul>
80   * <li>between static rows (link between id of row in template table and id of row in generated table)</li>
81   * <li>between dynamic rows (link between occurence of object from iteration and id of row in generated table)</li>
82   * </ul>
83   * 
84   * @author sylvain
85   * 
86   * @param <T>
87   *            type of referenced object (here this is a {@link FlexoDocTable})
88   */
89  @ModelEntity
90  @ImplementationClass(TableActorReference.TableActorReferenceImpl.class)
91  @XMLElement
92  @FML("TableActorReference")
93  public interface TableActorReference<T extends FlexoDocTable<?, ?>> extends ActorReference<T> {
94  
95  	@PropertyIdentifier(type = String.class)
96  	public static final String TABLE_IDENTIFIER_KEY = "tableIdentifier";
97  	@PropertyIdentifier(type = StaticRowReference.class, cardinality = Cardinality.LIST)
98  	public static final String STATIC_ROW_REFERENCES_KEY = "staticRowReferences";
99  	@PropertyIdentifier(type = DynamicRowReference.class, cardinality = Cardinality.LIST)
100 	public static final String DYNAMIC_ROW_REFERENCES_KEY = "dynamicRowReferences";
101 
102 	@Getter(TABLE_IDENTIFIER_KEY)
103 	@XMLAttribute
104 	public String getTableIdentifier();
105 
106 	@Setter(TABLE_IDENTIFIER_KEY)
107 	public void setTableIdentifier(String tableIdentifier);
108 
109 	/**
110 	 * Return the list of static row references
111 	 * 
112 	 * @return
113 	 */
114 	@Getter(value = STATIC_ROW_REFERENCES_KEY, cardinality = Cardinality.LIST)
115 	@XMLElement
116 	@Embedded
117 	public List<StaticRowReference> getStaticRowReferences();
118 
119 	@Setter(STATIC_ROW_REFERENCES_KEY)
120 	public void setStaticRowReferences(List<StaticRowReference> someReferences);
121 
122 	@Adder(STATIC_ROW_REFERENCES_KEY)
123 	public void addToStaticRowReferences(StaticRowReference aReference);
124 
125 	@Remover(STATIC_ROW_REFERENCES_KEY)
126 	public void removeFromStaticRowReferences(StaticRowReference aReference);
127 
128 	/**
129 	 * Return the list of dynamic row references
130 	 * 
131 	 * @return
132 	 */
133 	@Getter(value = DYNAMIC_ROW_REFERENCES_KEY, cardinality = Cardinality.LIST)
134 	@XMLElement
135 	@Embedded
136 	public List<DynamicRowReference> getDynamicRowReferences();
137 
138 	@Setter(DYNAMIC_ROW_REFERENCES_KEY)
139 	public void setDynamicRowReferences(List<DynamicRowReference> someReferences);
140 
141 	@Adder(DYNAMIC_ROW_REFERENCES_KEY)
142 	public void addToDynamicRowReferences(DynamicRowReference aReference);
143 
144 	@Remover(DYNAMIC_ROW_REFERENCES_KEY)
145 	public void removeFromDynamicRowReferences(DynamicRowReference aReference);
146 
147 	/**
148 	 * This method is called to extract a value from the federated data and apply it to the represented table representation
149 	 * 
150 	 */
151 	public void applyDataToDocument();
152 
153 	/**
154 	 * This method is called to extract a value from the table, and apply it to underlying federated data
155 	 * 
156 	 * @return
157 	 */
158 	public void reinjectDataFromDocument();
159 
160 	public abstract static class TableActorReferenceImpl<T extends FlexoDocTable<?, ?>> extends ActorReferenceImpl<T>
161 			implements TableActorReference<T> {
162 
163 		private static final Logger logger = FlexoLogger.getLogger(TableActorReference.class.getPackage().toString());
164 
165 		private T table;
166 		private String tableIdentifier;
167 
168 		/**
169 		 * Default constructor
170 		 */
171 		public TableActorReferenceImpl() {
172 			super();
173 		}
174 
175 		public FlexoDocument<?, ?> getFlexoDocument() {
176 			ModelSlotInstance<?, ?> msInstance = getModelSlotInstance();
177 			if (msInstance != null && msInstance.getAccessedResourceData() != null) {
178 				return (FlexoDocument<?, ?>) msInstance.getAccessedResourceData();
179 			}
180 			return null;
181 		}
182 
183 		@Override
184 		public String getTableIdentifier() {
185 			if (table != null) {
186 				return table.getIdentifier();
187 			}
188 			return tableIdentifier;
189 		}
190 
191 		@Override
192 		public void setTableIdentifier(String tableIdentifier) {
193 			this.tableIdentifier = tableIdentifier;
194 		}
195 
196 		@Override
197 		public T getModellingElement(boolean forceLoading) {
198 
199 			if (table == null) {
200 				FlexoDocument<?, ?> document = getFlexoDocument();
201 				if (document != null) {
202 					if (StringUtils.isNotEmpty(tableIdentifier)) {
203 						table = (T) document.getElementWithIdentifier(tableIdentifier);
204 					}
205 				}
206 			}
207 
208 			return table;
209 		}
210 
211 		@Override
212 		public void setModellingElement(T aTable) {
213 
214 			if (aTable != table) {
215 
216 				FlexoTableRole<T, ?, ?> tableRole = ((FlexoTableRole<T, ?, ?>) getFlexoRole());
217 
218 				// First remove all existing static references
219 				if (table != null) {
220 					for (StaticRowReference r : new ArrayList<>(getStaticRowReferences())) {
221 						removeFromStaticRowReferences(r);
222 					}
223 					/*for (DynamicRowReference r : new ArrayList<DynamicRowReference>(getDynamicRowReferences())) {
224 						removeFromDynamicRowReferences(r);
225 					}*/
226 				}
227 
228 				// Retrieve template table
229 				T templateTable = tableRole.getTable();
230 
231 				if (aTable != null) {
232 					for (int i = 0; i < aTable.getTableRows().size(); i++) {
233 						FlexoDocTableRow<?, ?> generatedRow = aTable.getTableRows().get(i);
234 						if (generatedRow.getTableCells().size() > 0 && generatedRow.getTableCells().get(0).getElements().size() > 0) {
235 							FlexoDocElement<?, ?> generatedElement = generatedRow.getTableCells().get(0).getElements().get(0);
236 							if (StringUtils.isNotEmpty(generatedElement.getBaseIdentifier())) {
237 								FlexoDocElement<?, ?> templateParagraph = templateTable
238 										.getElementWithIdentifier(generatedElement.getBaseIdentifier());
239 								FlexoDocTableCell<?, ?> templateCell = (FlexoDocTableCell<?, ?>) templateParagraph.getContainer();
240 								FlexoDocTableRow<?, ?> templateRow = templateCell.getRow();
241 								if (templateRow != null) {
242 									if (templateRow.getIndex() < tableRole.getStartIterationIndex()
243 											|| templateRow.getIndex() > tableRole.getEndIterationIndex()) {
244 										// This means that we found a matching between the two rows, outside iteration area
245 										// we need to store that information as a StaticRowReference
246 										System.out.println("OK pour la ligne " + i + " je trouve " + templateRow.getIdentifier());
247 										StaticRowReference srr = getFactory().newInstance(StaticRowReference.class);
248 										srr.setRowId(generatedRow.getIdentifier());
249 										srr.setTemplateRowId(templateRow.getIdentifier());
250 										addToStaticRowReferences(srr);
251 										System.out.println(
252 												"OK j'associe " + generatedRow.getIdentifier() + " a " + templateRow.getIdentifier());
253 									}
254 								}
255 							}
256 						}
257 					}
258 				}
259 				else {
260 					logger.warning("INVESTIGATE: Setting a tableActorReference (" + this.getRoleName() + ") to NULL in Concept"
261 							+ this.getFlexoConceptInstance());
262 				}
263 				table = aTable;
264 			}
265 		}
266 
267 		/**
268 		 * This method is called to extract a value from the federated data and apply it to the represented table representation
269 		 * 
270 		 */
271 		@Override
272 		public void applyDataToDocument() {
273 
274 			FlexoTableRole<T, ?, ?> tableRole = (FlexoTableRole<T, ?, ?>) getFlexoRole();
275 
276 			logger.info("Updating table");
277 
278 			// First, we have to retrieve all rows
279 
280 			List<Object> rowObjects = null;
281 			try {
282 				rowObjects = tableRole.getIteration().getBindingValue(getFlexoConceptInstance());
283 			} catch (TypeMismatchException e) {
284 				e.printStackTrace();
285 			} catch (NullReferenceException e) {
286 				e.printStackTrace();
287 			} catch (ReflectiveOperationException e) {
288 				e.printStackTrace();
289 			}
290 
291 			// First, we have to detect iteration range on generation target
292 			ObjectRowLookupResult lookup = lookupObjects();
293 
294 			logger.info("Generate between " + lookup.startIterationRowIndex + " et " + lookup.endIterationRowIndex);
295 
296 			int currentRowNumbers = lookup.endIterationRowIndex - lookup.startIterationRowIndex + 1;
297 
298 			if (currentRowNumbers < rowObjects.size()) {
299 				// Some rows need to be added
300 				for (int i = 0; i < rowObjects.size() - currentRowNumbers; i++) {
301 					logger.info("Add row " + (i + lookup.endIterationRowIndex + 1));
302 					FlexoDocTableRow<?, ?> rowToClone = getModellingElement().getTableRows().get(i + lookup.endIterationRowIndex);
303 					FlexoDocTableRow<?, ?> clonedRow = (FlexoDocTableRow<?, ?>) rowToClone.cloneObject();
304 					for (int j = 0; j < clonedRow.getTableCells().size(); j++) {
305 						FlexoDocTableCell<?, ?> cell = clonedRow.getTableCells().get(j);
306 						for (int k = 0; k < cell.getElements().size(); k++) {
307 							FlexoDocElement<?, ?> element = cell.getElements().get(k);
308 							element.setIdentifier(element.getFlexoDocument().getFactory().generateId());
309 						}
310 					}
311 
312 					getModellingElement().insertTableRowAtIndex((FlexoDocTableRow) clonedRow, (i + lookup.endIterationRowIndex + 1));
313 				}
314 			}
315 
316 			if (currentRowNumbers > rowObjects.size()) {
317 				// Some rows need to be removed
318 				for (int i = 0; i < currentRowNumbers - rowObjects.size(); i++) {
319 					logger.info("Remove row at index " + (i + lookup.endIterationRowIndex + 1));
320 					getModellingElement().removeFromTableRows(
321 							(FlexoDocTableRow) getModellingElement().getTableRows().get(i + lookup.endIterationRowIndex));
322 				}
323 			}
324 
325 			lookup.endIterationRowIndex = lookup.endIterationRowIndex + rowObjects.size() - currentRowNumbers;
326 			currentRowNumbers = rowObjects.size();
327 
328 			if (getModellingElement() != null) {
329 				for (DynamicRowReference drr : new ArrayList<>(getDynamicRowReferences())) {
330 					removeFromDynamicRowReferences(drr);
331 				}
332 			}
333 
334 			// At this point, we have the right number of rows
335 
336 			int i = 0;
337 			for (final Object rowObject : rowObjects) {
338 				for (ColumnTableBinding<?, ?> ctb : tableRole.getColumnBindings()) {
339 					try {
340 						Object value = ctb.getValue().getBindingValue(new BindingEvaluationContext() {
341 
342 							@Override
343 							public Object getValue(BindingVariable variable) {
344 								if (variable.getVariableName().equals(FlexoTableRoleImpl.ITERATOR_NAME)) {
345 									return rowObject;
346 								}
347 								return getFlexoConceptInstance().getValue(variable);
348 							}
349 
350 							@Override
351 							public ExpressionEvaluator getEvaluator() {
352 								return new FMLExpressionEvaluator(this);
353 							}
354 						});
355 						FlexoDocTableCell<?, ?> cell = getModellingElement().getCell(i + lookup.startIterationRowIndex,
356 								ctb.getColumnIndex());
357 						cell.setRawText((String) value);
358 
359 					} catch (TypeMismatchException e) {
360 						e.printStackTrace();
361 					} catch (NullReferenceException e) {
362 						e.printStackTrace();
363 					} catch (ReflectiveOperationException e) {
364 						e.printStackTrace();
365 					}
366 				}
367 
368 				DynamicRowReference drr = getFactory().newInstance(DynamicRowReference.class);
369 				drr.setRowId(getModellingElement().getTableRows().get(i + lookup.startIterationRowIndex).getIdentifier());
370 				drr.setIndex(i);
371 				addToDynamicRowReferences(drr);
372 
373 				i++;
374 
375 			}
376 
377 		}
378 
379 		/**
380 		 * Return list of rows in generated table matching row identified by supplied rowId
381 		 * 
382 		 * @param templateRowId
383 		 *            identifier of template row
384 		 * @return
385 		 */
386 		public List<FlexoDocTableRow<?, ?>> getRowsMatchingTemplateRowId(String templateRowId) {
387 			List<FlexoDocTableRow<?, ?>> returned = new ArrayList<>();
388 			for (StaticRowReference srr : getStaticRowReferences()) {
389 				if (srr.getTemplateRowId().equals(templateRowId)) {
390 					FlexoDocTableRow<?, ?> matchingRow = getModellingElement().getRowWithIdentifier(srr.getRowId());
391 					returned.add(matchingRow);
392 				}
393 			}
394 			return returned;
395 		}
396 
397 		/**
398 		 * Return list of rows in generated table matching supplied row
399 		 * 
400 		 * @param templateRow
401 		 * @return
402 		 */
403 		public List<FlexoDocTableRow<?, ?>> getRowsMatchingTemplateRow(FlexoDocTableRow<?, ?> templateRow) {
404 			return getRowsMatchingTemplateRowId(templateRow.getIdentifier());
405 		}
406 
407 		/**
408 		 * This method is called to extract a value from the table, and apply it to underlying federated data
409 		 * 
410 		 * @return
411 		 */
412 		@Override
413 		public void reinjectDataFromDocument() {
414 
415 			FlexoTableRole<T, ?, ?> tableRole = (FlexoTableRole<T, ?, ?>) getFlexoRole();
416 
417 			logger.info("DocXTable: reinjectDataFromDocument");
418 
419 			// First, we have to retrieve all rows
420 
421 			List<Object> rowObjects = null;
422 			try {
423 				rowObjects = tableRole.getIteration().getBindingValue(getFlexoConceptInstance());
424 			} catch (TypeMismatchException e) {
425 				e.printStackTrace();
426 			} catch (NullReferenceException e) {
427 				e.printStackTrace();
428 			} catch (ReflectiveOperationException e) {
429 				e.printStackTrace();
430 			}
431 
432 			System.out.println("rowObjects=" + rowObjects);
433 			System.out.println("getModellingElement()=" + getModellingElement());
434 
435 			ObjectRowLookupResult lookup = lookupObjects();
436 
437 			System.out.println("Du coup, on reinjecte entre " + lookup.startIterationRowIndex + " et " + lookup.endIterationRowIndex);
438 
439 			List<Object> objectsToCallFromDeletion = new ArrayList<>(rowObjects);
440 
441 			for (int rowIndex = lookup.startIterationRowIndex; rowIndex <= lookup.endIterationRowIndex; rowIndex++) {
442 				System.out.println("Row " + rowIndex);
443 				FlexoDocTableRow<?, ?> row = table.getTableRows().get(rowIndex);
444 				int objectIndex = expectedObjectIndexForRowId(row.getIdentifier());
445 				if (objectIndex == -1) {
446 					// Attempt to *guess*
447 					objectIndex = rowIndex - lookup.startIterationRowIndex;
448 				}
449 				if (objectIndex < rowObjects.size()) {
450 					final Object rowObject = rowObjects.get(objectIndex);
451 					System.out.println("Found a matching object : " + rowObject);
452 
453 					for (ColumnTableBinding<?, ?> ctb : tableRole.getColumnBindings()) {
454 						FlexoDocTableCell<?, ?> cell = getModellingElement().getCell(rowIndex, ctb.getColumnIndex());
455 						String rawTextToReinject = cell.getRawText();
456 
457 						try {
458 							ctb.getValue().setBindingValue(rawTextToReinject, new BindingEvaluationContext() {
459 
460 								@Override
461 								public Object getValue(BindingVariable variable) {
462 									if (variable.getVariableName().equals(FlexoTableRoleImpl.ITERATOR_NAME)) {
463 										return rowObject;
464 									}
465 									return getFlexoConceptInstance().getValue(variable);
466 								}
467 
468 								@Override
469 								public ExpressionEvaluator getEvaluator() {
470 									return new FMLExpressionEvaluator(this);
471 								}
472 							});
473 
474 						} catch (TypeMismatchException e) {
475 							e.printStackTrace();
476 						} catch (NullReferenceException e) {
477 							e.printStackTrace();
478 						} catch (ReflectiveOperationException e) {
479 							e.printStackTrace();
480 						} catch (NotSettableContextException e) {
481 							e.printStackTrace();
482 						}
483 					}
484 
485 					objectsToCallFromDeletion.remove(rowObject);
486 				}
487 				else {
488 					// This appear to be a new object
489 					System.out.println("Consider create a new object from row");
490 				}
491 			}
492 
493 			for (Object toDelete : objectsToCallFromDeletion) {
494 				System.out.println("Consider delete this object: " + toDelete);
495 			}
496 
497 		}
498 
499 		private int expectedObjectIndexForRowId(String rowId) {
500 			if (rowId == null) {
501 				return -1;
502 			}
503 			for (DynamicRowReference drr : getDynamicRowReferences()) {
504 				if (rowId.equals(drr.getRowId())) {
505 					return drr.getIndex();
506 				}
507 			}
508 			return -1;
509 		}
510 
511 		class ObjectRowLookupResult {
512 			int startIterationRowIndex;
513 			int endIterationRowIndex;
514 		}
515 
516 		private ObjectRowLookupResult lookupObjects() {
517 			ObjectRowLookupResult returned = new ObjectRowLookupResult();
518 
519 			FlexoTableRole<T, ?, ?> tableRole = (FlexoTableRole<T, ?, ?>) getFlexoRole();
520 
521 			// First, we have to detect iteration range on generation target
522 			returned.startIterationRowIndex = 0;
523 			returned.endIterationRowIndex = getModellingElement().getTableRows().size() - 1;
524 
525 			// start iteration row index is computed from the last static reference before iteration area
526 			if (tableRole.getStartIterationIndex() > 0) {
527 				FlexoDocTableRow<?, ?> lastTemplateHeaderRow = tableRole.getTable().getTableRows()
528 						.get(tableRole.getStartIterationIndex() - 1);
529 				List<FlexoDocTableRow<?, ?>> lastHeaderRows = getRowsMatchingTemplateRow(lastTemplateHeaderRow);
530 				if (lastHeaderRows.size() > 0) {
531 					FlexoDocTableRow<?, ?> lastHeaderRow = lastHeaderRows.get(0);
532 					returned.startIterationRowIndex = lastHeaderRow.getIndex() + 1;
533 				}
534 			}
535 			// end iteration row index is computed from the last static reference after iteration area
536 			if (tableRole.getEndIterationIndex() > 0 && tableRole.getEndIterationIndex() < tableRole.getTable().getTableRows().size() - 1) {
537 				FlexoDocTableRow<?, ?> firstTemplateFooterRow = tableRole.getTable().getTableRows()
538 						.get(tableRole.getEndIterationIndex() + 1);
539 				List<FlexoDocTableRow<?, ?>> firstFooterRows = getRowsMatchingTemplateRow(firstTemplateFooterRow);
540 				if (firstFooterRows.size() > 0) {
541 					FlexoDocTableRow<?, ?> firstFooterRow = firstFooterRows.get(0);
542 					returned.endIterationRowIndex = firstFooterRow.getIndex() - 1;
543 				}
544 			}
545 
546 			return returned;
547 		}
548 
549 	}
550 
551 	/**
552 	 * Used to store link between a row and its data
553 	 * 
554 	 * @author sylvain
555 	 *
556 	 */
557 	@ModelEntity(isAbstract = true)
558 	public interface AbstractRowReference {
559 
560 		@PropertyIdentifier(type = String.class)
561 		public static final String ROW_IDENTIFIER_KEY = "rowId";
562 
563 		@Getter(ROW_IDENTIFIER_KEY)
564 		@XMLAttribute
565 		public String getRowId();
566 
567 		@Setter(ROW_IDENTIFIER_KEY)
568 		public void setRowId(String rowId);
569 
570 	}
571 
572 	/**
573 	 * Used to store link between occurence of iteration object with index of row in table
574 	 * 
575 	 * @author sylvain
576 	 *
577 	 */
578 	@ModelEntity
579 	@XMLElement
580 	public interface DynamicRowReference extends AbstractRowReference {
581 
582 		@PropertyIdentifier(type = Integer.class)
583 		public static final String INDEX_KEY = "index";
584 
585 		/**
586 		 * Index of iterated object as it has been appeared in iteration
587 		 * 
588 		 * @return
589 		 */
590 		@Getter(value = INDEX_KEY, defaultValue = "-1")
591 		@XMLAttribute
592 		public int getIndex();
593 
594 		@Setter(INDEX_KEY)
595 		public void setIndex(int index);
596 
597 	}
598 
599 	/**
600 	 * Used to store link between occurence of iteration object with index of row in table
601 	 * 
602 	 * @author sylvain
603 	 *
604 	 */
605 	@ModelEntity
606 	@XMLElement
607 	public interface StaticRowReference extends AbstractRowReference {
608 
609 		@PropertyIdentifier(type = String.class)
610 		public static final String TEMPLATE_ROW_IDENTIFIER_KEY = "templateRowId";
611 
612 		@Getter(TEMPLATE_ROW_IDENTIFIER_KEY)
613 		@XMLAttribute
614 		public String getTemplateRowId();
615 
616 		@Setter(TEMPLATE_ROW_IDENTIFIER_KEY)
617 		public void setTemplateRowId(String templateRowId);
618 
619 	}
620 
621 }