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.foundation.doc.FlexoDocElement;
46  import org.openflexo.foundation.doc.FlexoDocFragment;
47  import org.openflexo.foundation.doc.FlexoDocFragment.FragmentConsistencyException;
48  import org.openflexo.foundation.doc.FlexoDocTable;
49  import org.openflexo.foundation.doc.FlexoDocTableCell;
50  import org.openflexo.foundation.doc.FlexoDocTableRow;
51  import org.openflexo.foundation.doc.FlexoDocument;
52  import org.openflexo.foundation.fml.annotations.FML;
53  import org.openflexo.foundation.fml.rt.ActorReference;
54  import org.openflexo.foundation.fml.rt.ModelSlotInstance;
55  import org.openflexo.logging.FlexoLogger;
56  import org.openflexo.pamela.annotations.Adder;
57  import org.openflexo.pamela.annotations.Embedded;
58  import org.openflexo.pamela.annotations.Getter;
59  import org.openflexo.pamela.annotations.ImplementationClass;
60  import org.openflexo.pamela.annotations.ModelEntity;
61  import org.openflexo.pamela.annotations.PropertyIdentifier;
62  import org.openflexo.pamela.annotations.Remover;
63  import org.openflexo.pamela.annotations.Setter;
64  import org.openflexo.pamela.annotations.XMLAttribute;
65  import org.openflexo.pamela.annotations.XMLElement;
66  import org.openflexo.pamela.annotations.Getter.Cardinality;
67  
68  /**
69   * Implements {@link ActorReference} for {@link FlexoDocFragment}.<br>
70   * Represents the actual links in a given {@link FlexoDocument} connecting a template fragment to a generated fragment<br>
71   * We need to store here the bindings between elements in template and corresponding elements in referenced {@link FlexoDocument}
72   * 
73   * @author sylvain
74   * 
75   * @param <T>
76   *            type of referenced object
77   */
78  @ModelEntity
79  @ImplementationClass(FragmentActorReference.FragmentActorReferenceImpl.class)
80  @XMLElement
81  @FML("FragmentActorReference")
82  public interface FragmentActorReference<F extends FlexoDocFragment<?, ?>> extends ActorReference<F> {
83  
84  	@PropertyIdentifier(type = ElementReference.class, cardinality = Cardinality.LIST)
85  	public static final String ELEMENT_REFERENCES_KEY = "elementReferences";
86  
87  	/**
88  	 * Return the list of root elements of this document (elements like paragraphs or tables, sequentially composing the document)
89  	 * 
90  	 * @return
91  	 */
92  	@Getter(value = ELEMENT_REFERENCES_KEY, cardinality = Cardinality.LIST)
93  	@XMLElement
94  	@Embedded
95  	public List<ElementReference> getElementReferences();
96  
97  	@Setter(ELEMENT_REFERENCES_KEY)
98  	public void setElementReferences(List<ElementReference> someElementReferences);
99  
100 	@Adder(ELEMENT_REFERENCES_KEY)
101 	public void addToElementReferences(ElementReference anElementReference);
102 
103 	@Remover(ELEMENT_REFERENCES_KEY)
104 	public void removeFromElementReferences(ElementReference anElementReference);
105 
106 	/**
107 	 * Return list of elements in generated fragment matching element identified by supplied templateElementId
108 	 * 
109 	 * @param templateElementId
110 	 *            identifier of template element
111 	 * @return
112 	 */
113 	public List<FlexoDocElement<?, ?>> getElementsMatchingTemplateElementId(String templateElementId);
114 
115 	/**
116 	 * Return list of elements in generated fragment matching supplied templateElement
117 	 * 
118 	 * @param templateElement
119 	 * @return
120 	 */
121 	public List<FlexoDocElement<?, ?>> getElementsMatchingTemplateElement(FlexoDocElement<?, ?> templateElement);
122 
123 	public void removeReferencesTo(FlexoDocElement<?, ?> element);
124 
125 	/**
126 	 * This method is called to extract a value from the federated data and apply it to the represented fragment representation
127 	 * 
128 	 */
129 	public void applyDataToDocument();
130 
131 	/**
132 	 * This method is called to extract a value from the fragment, and apply it to underlying federated data
133 	 * 
134 	 * @return
135 	 */
136 	public void reinjectDataFromDocument();
137 
138 	public abstract static class FragmentActorReferenceImpl<F extends FlexoDocFragment<?, ?>> extends ActorReferenceImpl<F>
139 			implements FragmentActorReference<F> {
140 
141 		private static final Logger logger = FlexoLogger.getLogger(FragmentActorReference.class.getPackage().toString());
142 
143 		private F fragment;
144 
145 		/**
146 		 * Default constructor
147 		 */
148 		public FragmentActorReferenceImpl() {
149 			super();
150 		}
151 
152 		public FlexoDocument<?, ?> getFlexoDocument() {
153 			ModelSlotInstance<?, ?> msInstance = getModelSlotInstance();
154 			if (msInstance != null && msInstance.getAccessedResourceData() != null) {
155 				return (FlexoDocument<?, ?>) msInstance.getAccessedResourceData();
156 			}
157 			return null;
158 		}
159 
160 		@Override
161 		public F getModellingElement(boolean forceLoading) {
162 
163 			if (fragment == null) {
164 				FlexoDocument<?, ?> document = getFlexoDocument();
165 				if (document != null) {
166 					if (getElementReferences().size() > 0) {
167 						FlexoDocElement startElement = null, endElement = null;
168 						int index = 0;
169 						for (ElementReference er : getElementReferences()) {
170 							FlexoDocElement<?, ?> element = document.getElementWithIdentifier(er.getElementId());
171 							if (element != null) {
172 								element.setBaseIdentifier(er.getTemplateElementId());
173 								if (index == 0) {
174 									startElement = element;
175 								}
176 								if (index == getElementReferences().size() - 1) {
177 									endElement = element;
178 								}
179 							}
180 							else {
181 								logger.warning("Could not find element matching " + er.getElementId());
182 							}
183 							index++;
184 						}
185 						try {
186 							fragment = (F) document.getFactory().makeFragment(startElement, endElement);
187 						} catch (FragmentConsistencyException e) {
188 							logger.warning("Could not build fragment");
189 							e.printStackTrace();
190 						}
191 					}
192 				}
193 				else {
194 					logger.warning("Could not access to document from model slot " + getModelSlotInstance());
195 				}
196 			}
197 
198 			return fragment;
199 		}
200 
201 		@Override
202 		public void setModellingElement(F aFragment) {
203 
204 			if (aFragment != fragment) {
205 
206 				// First remove all existing ElementReference occurences when it exists
207 				if (fragment != null) {
208 					for (ElementReference er : new ArrayList<>(getElementReferences())) {
209 						removeFromElementReferences(er);
210 					}
211 				}
212 
213 				// Retrieve template fragment
214 				// Unused F templateFragment = (F)
215 				((FlexoFragmentRole<?, ?, ?>) getFlexoRole()).getFragment();
216 
217 				if (aFragment != null) {
218 					for (FlexoDocElement<?, ?> element : aFragment.getElements()) {
219 						ElementReference er = getFactory().newInstance(ElementReference.class);
220 						er.setElementId(element.getIdentifier());
221 						if (element.getBaseIdentifier() != null) {
222 							er.setTemplateElementId(element.getBaseIdentifier());
223 						}
224 						addToElementReferences(er);
225 						if (element instanceof FlexoDocTable) {
226 							FlexoDocTable<?, ?> table = (FlexoDocTable<?, ?>) element;
227 							for (FlexoDocTableRow<?, ?> row : table.getTableRows()) {
228 								for (FlexoDocTableCell<?, ?> cell : row.getTableCells()) {
229 									for (FlexoDocElement<?, ?> e2 : cell.getElements()) {
230 										if (e2.getBaseIdentifier() != null) {
231 											ElementReference er2 = getFactory().newInstance(ElementReference.class);
232 											er2.setElementId(e2.getIdentifier());
233 											er2.setTemplateElementId(e2.getBaseIdentifier());
234 											addToElementReferences(er2);
235 										}
236 									}
237 								}
238 							}
239 						}
240 					}
241 				}
242 				fragment = aFragment;
243 			}
244 		}
245 
246 		/**
247 		 * This method is called to extract a value from the federated data and apply it to the represented fragment representation
248 		 * 
249 		 */
250 		@Override
251 		public void applyDataToDocument() {
252 			for (TextBinding<?, ?> tb : ((FlexoFragmentRole<?, ?, ?>) getFlexoRole()).getTextBindings()) {
253 				tb.applyToFragment(getFlexoConceptInstance());
254 			}
255 		}
256 
257 		/**
258 		 * This method is called to extract a value from the fragment, and apply it to underlying federated data
259 		 * 
260 		 * @return
261 		 */
262 		@Override
263 		public void reinjectDataFromDocument() {
264 			for (TextBinding<?, ?> tb : ((FlexoFragmentRole<?, ?, ?>) getFlexoRole()).getTextBindings()) {
265 				tb.extractFromFragment(getFlexoConceptInstance());
266 			}
267 		}
268 
269 		/**
270 		 * Return list of elements in generated fragment matching element identified by supplied templateElementId
271 		 * 
272 		 * @param templateElementId
273 		 *            identifier of template element
274 		 * @return
275 		 */
276 		@Override
277 		public List<FlexoDocElement<?, ?>> getElementsMatchingTemplateElementId(String templateElementId) {
278 			List<FlexoDocElement<?, ?>> returned = new ArrayList<>();
279 			for (ElementReference er : getElementReferences()) {
280 				if (er.getTemplateElementId().equals(templateElementId)) {
281 					returned.add(getFlexoDocument().getElementWithIdentifier(er.getElementId()));
282 				}
283 			}
284 			return returned;
285 		}
286 
287 		/**
288 		 * Return list of elements in generated fragment matching supplied templateElement
289 		 * 
290 		 * @param templateElement
291 		 * @return
292 		 */
293 		@Override
294 		public List<FlexoDocElement<?, ?>> getElementsMatchingTemplateElement(FlexoDocElement<?, ?> templateElement) {
295 			return getElementsMatchingTemplateElementId(templateElement.getIdentifier());
296 		}
297 
298 		@Override
299 		public void removeReferencesTo(FlexoDocElement<?, ?> element) {
300 			List<ElementReference> referencesToRemove = new ArrayList<>();
301 			for (ElementReference er : getElementReferences()) {
302 				if (er.getElementId().equals(element.getIdentifier())) {
303 					referencesToRemove.add(er);
304 				}
305 			}
306 			for (ElementReference er : referencesToRemove) {
307 				removeFromElementReferences(er);
308 			}
309 		}
310 
311 	}
312 
313 	@ModelEntity
314 	@XMLElement
315 	public interface ElementReference {
316 
317 		@PropertyIdentifier(type = String.class)
318 		public static final String TEMPLATE_ELEMENT_IDENTIFIER_KEY = "templateElementId";
319 		@PropertyIdentifier(type = String.class)
320 		public static final String ELEMENT_IDENTIFIER_KEY = "elementId";
321 
322 		@Getter(TEMPLATE_ELEMENT_IDENTIFIER_KEY)
323 		@XMLAttribute
324 		public String getTemplateElementId();
325 
326 		@Setter(TEMPLATE_ELEMENT_IDENTIFIER_KEY)
327 		public void setTemplateElementId(String elementId);
328 
329 		@Getter(ELEMENT_IDENTIFIER_KEY)
330 		@XMLAttribute
331 		public String getElementId();
332 
333 		@Setter(ELEMENT_IDENTIFIER_KEY)
334 		public void setElementId(String elementId);
335 
336 	}
337 
338 }