1
2
3
4
5
6
7
8
9
10
11
12 package sk.uniba.euromath.gene;
13 import java.io.File;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.EnumSet;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import javax.xml.transform.Result;
23 import javax.xml.transform.Source;
24 import javax.xml.transform.dom.DOMResult;
25 import javax.xml.transform.dom.DOMSource;
26 import javax.xml.transform.stream.StreamResult;
27 import org.w3c.dom.Document;
28 import org.w3c.dom.DocumentFragment;
29 import org.w3c.dom.Element;
30 import org.w3c.dom.Node;
31 import org.w3c.dom.ProcessingInstruction;
32 import sk.baka.ikslibs.ObjectSource;
33 import sk.baka.ikslibs.ResultEnum;
34 import sk.baka.ikslibs.SourceEnum;
35 import sk.baka.ikslibs.TransformUtils;
36 import sk.baka.ikslibs.modify.DOMChangeCollector;
37 import sk.baka.ikslibs.modify.IChangeCollector;
38 import sk.baka.ikslibs.modify.ObjectChangeCollector;
39 import sk.baka.ikslibs.splitted.SplittedDocHolder;
40 import sk.baka.xml.gene.CoordinatorInfo;
41 import sk.baka.xml.gene.CoordinatorInputKey;
42 import sk.baka.xml.gene.ExportContext;
43 import sk.baka.xml.gene.ExportException;
44 import sk.baka.xml.gene.ExportUtils;
45 import sk.baka.xml.gene.IConfigurator;
46 import sk.baka.xml.gene.ICoordinator;
47 import sk.baka.xml.gene.IExporter;
48 import sk.baka.xml.gene.controller.NamespacePath;
49 import sk.baka.xml.gene.exportgraph.ExportGraphBuilder;
50 import sk.baka.xml.gene.exportgraph.TransformGraph;
51 import sk.uniba.euromath.document.XMLAccess;
52 import sk.uniba.euromath.editor.EditorException;
53 import sk.uniba.euromath.editor.EditorSite;
54 import sk.uniba.euromath.editor.IInputPreprocessor;
55 import sk.uniba.euromath.editor.IRenderer;
56 import sk.uniba.euromath.editor.RendererInfo;
57 import sk.uniba.euromath.editor.RendererSelector;
58 import sk.uniba.euromath.tools.StringTools;
59 import sk.uniba.euromath.tools.URLDir;
60 /***
61 * <p>
62 * Acts as a GENE coordinator. Collects GENE output, instantiates and
63 * initializes renderers, and fires events on document change.
64 * </p>
65 * <h3>Implementation of GENE output handler</h3>
66 * <p>
67 * The object produces a special tree (using the
68 * {@link Coordinator#partialResultEvent(DocumentFragment, NamespacePath, Source, String, CoordinatorInputKey)}
69 * function), that is processed by the object itself on
70 * {@link Coordinator#finishExport()} function. This tree is intended to capture
71 * the tree structure of nametrees in output document (and renderers, rendering
72 * these nametrees).
73 * </p>
74 * <p>
75 * Each
76 * {@link Coordinator#partialResultEvent(DocumentFragment, NamespacePath, Source, String, CoordinatorInputKey)}
77 * constructs (or updates) a renderer, associates it with the
78 * {@link CoordinatorInputKey key} and produces some elements. These elements
79 * must be able to provide:
80 * </p>
81 * <ul>
82 * <li>a mapping from GENE-providen ID (given to the renderer via the
83 * <code>emp:mark</code> element) to the key (we must be able to provide child
84 * renderers to a renderer, that uses ID as their identification key), and</li>
85 * <li>a parent-child relation for renderers, to verify renderers requirements
86 * for child renderers.</li>
87 * </ul>
88 * <p>
89 * These elements are produced:
90 * </p>
91 * <ul>
92 * <li><code>ref</code> element - serves for identification of the renderer.
93 * Contains attribute <code>id</code> that uniquely identifies key in the
94 * renderer tree.</li>
95 * <li>We must store ids for each child nametree. Thus, each
96 * <code>emp:mark</code> element is copied and placed in
97 * <code>child-renderer</code>, whose ID attribute identifies the child
98 * nametree (it is a copy of <code>emp:id</code> element placed in the
99 * <code>emp:mark</code> element).</li>
100 * </ul>
101 * <p>
102 * <code>ref</code> element will receive same namespace as the input of the
103 * renderer it references. All child <code>child-renderer</code> elements will
104 * have same namespace as their parent <code>ref</code>. This will allow GENE
105 * to provide correct namespace paths.
106 * </p>
107 * <p>
108 * Following this algorithm (when GENE resolves all <code>emp:mark</code>
109 * elements) we receive this document in the <code>finishExport()</code>
110 * method: root element is <code>keyref</code> identifying root renderer. Each
111 * <code>keyref</code> contains zero or more <code>child-renderer</code>
112 * elements, containing ids of children renderers. Each
113 * <code>child-renderer</code> contains one <code>keyref</code> element,
114 * identifying this renderer, etc.
115 * </p>
116 * @author Martin Vysny
117 */
118 public final class GeneDataProvider {
119 /***
120 * Localname (and qname, because of <code>null</code> namespace) of the
121 * <code>keyref</code> element.
122 */
123 private final static String KEYREF_ELEMENT_NAME = "keyref";
124 /***
125 * Localname (and qname, because of <code>null</code> namespace) of the
126 * <code>child-renderer</code> element.
127 */
128 private final static String CHILD_RENDERER_ELEMENT_NAME = "child-renderer";
129 /***
130 * Localname (and qname, because of <code>null</code> namespace) of the
131 * <code>id</code> attribute.
132 */
133 private final static String ID_ATTRIBUTE_NAME = "id";
134 /***
135 * Constructor.
136 * @param selector the renderer selector.
137 * @param xmlAccess the transformed document.
138 * @param edr the data receiver.
139 */
140 public GeneDataProvider(final RendererSelector selector,
141 final XMLAccess xmlAccess, final IEditorDataReceiver edr) {
142 super();
143 this.selector = new RendererSelector(selector);
144 this.coordinator = new Coordinator();
145 this.coordinator.edr = edr;
146 edr.initReceiver();
147 this.context = new RendererContext(this.coordinator.geneIdMapping,
148 this.coordinator.rendererKeys, xmlAccess);
149
150 final Map<String, EnumSet<SourceEnum>> accepts = selector
151 .getRenderable();
152
153 this.coordinatorInfo = new CoordinatorInfo(COORDINATOR_ID, null,
154 "The GENE output to editor framework data redirector",
155 "application/X-gene-direct-rendering", null, accepts);
156 }
157 /***
158 * The renderer selector instance.
159 */
160 private final RendererSelector selector;
161 /***
162 * Returns the coordinator instance - this object receives GENE output.
163 * @return GENE's coordinator instance.
164 */
165 public ICoordinator getCoordinator() {
166 return this.coordinator;
167 }
168 /***
169 * The coordinator id.
170 */
171 private final static String COORDINATOR_ID = GeneDataProvider.class
172 .getName()
173 + GeneDataProvider.class.hashCode();
174 /***
175 * <p>
176 * GENE's coordinator instance, captures GENE output and builds a tree of
177 * renderers.
178 * </p>
179 * <p>
180 * The following properties are valid when the GENE data receiving is
181 * complete:
182 * </p>
183 * <ul>
184 * <li>{@link #rendererKeys} - maps coordinator 'pipe' key to the renderer,
185 * processing the pipe output.</li>
186 * <li>{@link #rootKey} - defines root nametree and its renderer.</li>
187 * <li>{@link #geneIdMapping} - useful for {@link RendererContext} to
188 * resolve GENE-specific IDs (passed in form of <code>emp:mark</code>
189 * elements in Source to the renderer) into the renderer instances.</li>
190 * <li>{@link #nametreeHierarchy} - defines the nametree hierarchy. Useful
191 * for {@link EditorSite} when creating IEditor instances.</li>
192 * <li>{@link #newKeys} and {@link #deletedKeys} - shows new or deleted
193 * nametrees.</li>
194 * </ul>
195 * @author Martin Vysny
196 */
197 private final class Coordinator implements ICoordinator {
198 /***
199 * The data receiver.
200 */
201 private IEditorDataReceiver edr;
202 /***
203 * Constructor.
204 */
205 public Coordinator() {
206 super();
207 }
208
209
210
211
212 public void finishExport() throws ExportException, IOException {
213
214 final DocumentFragment frag = (DocumentFragment) this.rendererTree
215 .getNode();
216
217 final Element rootKeyRef = (Element) frag.getFirstChild();
218 assert rootKeyRef != null;
219 this.geneIdMapping.clear();
220 this.rootKey = processHierarchy(rootKeyRef);
221
222
223 this.rendererTree = null;
224 this.keyMap.clear();
225
226 this.rendererKeys.keySet().removeAll(this.deletedKeys);
227
228
229
230
231
232
233
234 try {
235 initializeRenderer(this.rootKey);
236 } catch (EditorException ex) {
237 throw new ExportException("Failed to initialize renderers", ex);
238 }
239
240 try {
241 this.edr.dataChanged(this.rendererKeys, this.rootKey,
242 this.nametreeHierarchy, this.geneIdMapping,
243 this.newKeys, this.deletedKeys);
244 } catch (EditorException ex) {
245 throw new ExportException(ex);
246 }
247 }
248 /***
249 * Processes hierarchy of <code>keyref</code> and
250 * <code>child-renderer</code> elements.
251 * @param keyRef the <code>keyref</code> element.
252 * @return the coordinator input key, represented by the
253 * <code>keyref</code> element.
254 */
255 private CoordinatorInputKey processHierarchy(final Element keyRef) {
256 assert keyRef.getLocalName().equals(KEYREF_ELEMENT_NAME);
257 final String id = keyRef.getAttributeNS(null, ID_ATTRIBUTE_NAME);
258 assert id != null;
259 final CoordinatorInputKey key = this.keyMap.get(id);
260 assert key != null;
261
262 Set<CoordinatorInputKey> children = this.nametreeHierarchy.get(key);
263 if (children == null) {
264 children = new HashSet<CoordinatorInputKey>();
265 this.nametreeHierarchy.put(key, children);
266 }
267 for (Element childRenderer = (Element) keyRef.getFirstChild(); childRenderer != null; childRenderer = (Element) childRenderer
268 .getNextSibling()) {
269 assert childRenderer.getLocalName().equals(
270 CHILD_RENDERER_ELEMENT_NAME);
271 final String geneId = childRenderer.getAttributeNS(null,
272 ID_ATTRIBUTE_NAME);
273 assert geneId != null;
274
275 final Element childKeyRef = (Element) childRenderer
276 .getFirstChild();
277 assert childKeyRef.getNextSibling() == null;
278 final CoordinatorInputKey childKey = processHierarchy(childKeyRef);
279
280 this.geneIdMapping.put(geneId, childKey);
281 children.add(childKey);
282 }
283 return key;
284 }
285 /***
286 * Initializes renderer with given key. Children renderers are
287 * initialized before the renderer itself, to prevent queries for
288 * uninitialized renderers.
289 * @param key identifies the renderer to be initialized.
290 * @throws EditorException
291 */
292 private void initializeRenderer(final CoordinatorInputKey key)
293 throws EditorException {
294
295 Set<CoordinatorInputKey> children = this.nametreeHierarchy.get(key);
296 if ((children != null) && !children.isEmpty()) {
297 for (final CoordinatorInputKey child : children) {
298 initializeRenderer(child);
299 }
300 }
301
302 final RendererSite site = this.rendererKeys.get(key);
303 site.init();
304 }
305
306
307
308
309 public ExportGraphBuilder getGraphBuilder() {
310
311 return new ExportGraphBuilder();
312 }
313
314
315
316
317 public EnumSet<SourceEnum> getSource(String namespace) {
318 return GeneDataProvider.this.coordinatorInfo.getSource(namespace);
319 }
320
321
322
323
324 public TransformGraph getTransformationGraph() {
325
326 throw new AssertionError("Should not be called.");
327 }
328
329
330
331
332 public Object offerObject(String namespace) throws ExportException {
333 namespace = StringTools.nonNullStr(namespace);
334
335 final List<RendererSite> renderers = this.rendererNamespaces
336 .get(namespace);
337 if ((renderers == null) || renderers.isEmpty()) {
338
339
340 try {
341 final RendererInfo info = GeneDataProvider.this.selector
342 .getRendererInfo(namespace, EnumSet
343 .of(ResultEnum.OBJECT));
344 final IRenderer renderer = info.newRenderer();
345 this.tempStorage.put(namespace, renderer);
346 return renderer.offerObject();
347 } catch (EditorException ex) {
348 throw new ExportException(ex);
349 }
350 }
351 for (final RendererSite r : renderers) {
352 if (r.renderer.getInfo().sourceTypes
353 .contains(SourceEnum.OBJECT))
354 return r.renderer.offerObject();
355 }
356 return null;
357 }
358
359
360
361
362
363
364
365 public Source partialResultEvent(final DocumentFragment processed,
366 final NamespacePath path, final Source source,
367 final String sourceNamespace, final CoordinatorInputKey key)
368 throws ExportException, IOException {
369
370 RendererSite renderer = null;
371
372 IRenderer r = this.tempStorage.get(sourceNamespace);
373 if ((r != null)
374 && r.getInfo().sourceTypes.contains(SourceEnum
375 .valueOf(source.getClass()))) {
376
377 this.tempStorage.remove(sourceNamespace);
378 renderer = registerRenderer(r, key);
379 assert renderer.getSource() == null;
380 }
381
382
383 if (renderer == null) {
384 renderer = this.rendererKeys.get(key);
385 if (renderer != null) {
386
387 assert renderer.getSource() != null;
388 }
389 }
390
391 if (renderer == null) {
392 final EnumSet<ResultEnum> sourceKind = EnumSet.of(SourceEnum
393 .valueOf(source.getClass()).getPair());
394 try {
395 final RendererInfo info = GeneDataProvider.this.selector
396 .getRendererInfo(sourceNamespace, sourceKind);
397 r = info.newRenderer();
398 renderer = registerRenderer(r, key);
399 assert renderer.getSource() == null;
400 } catch (EditorException ex) {
401 throw new ExportException(ex);
402 }
403 }
404 assert renderer != null;
405 this.keyMap.put(this.rendererKeys.get(key).id, key);
406
407
408
409
410
411
412 renderer.setSource(source);
413
414
415 final DOMSource result = new DOMSource();
416 result.setNode(createHierarchyElement(source, renderer));
417
418 this.deletedKeys.remove(key);
419 return result;
420 }
421 /***
422 * Registers renderer into the <code>rendererKeys</code> and
423 * <code>rendererNamespaces</code>.
424 * @param renderer renderer to register. Must not be initialized.
425 * @param key
426 * @return the socket instance.
427 */
428 private RendererSite registerRenderer(final IRenderer renderer,
429 final CoordinatorInputKey key) {
430 final RendererSite rs = new RendererSite(renderer, key);
431 if (this.rendererKeys.put(key, rs) != null)
432 throw new IllegalArgumentException(
433 "renderer is already registered under key " + key);
434 List<RendererSite> renderers = this.rendererNamespaces
435 .get(key.targetNamespace);
436 if (renderers == null) {
437 renderers = new ArrayList<RendererSite>();
438 this.rendererNamespaces.put(key.targetNamespace, renderers);
439 }
440 renderers.add(rs);
441 this.newKeys.add(key);
442 return rs;
443 }
444 /***
445 * Creates the <code>keyref</code> element, containing all
446 * <code>emp:mark</code> elements.
447 * @param source the data source. In case of Object source, no
448 * <code>emp:mark</code> are generated. This probably changes later,
449 * but it requires wide GENE changes.
450 * @param renderer the renderer.
451 * @return the <code>keyref</code> element.
452 */
453 private Element createHierarchyElement(final Source source,
454 final RendererSite renderer) {
455 final Element result = doc.createElementNS(renderer.renderer
456 .getInfo().sourceNamespace, KEYREF_ELEMENT_NAME);
457 result.setAttributeNS(null, ID_ATTRIBUTE_NAME, renderer.id);
458 if (source instanceof ObjectSource) {
459
460
461 return result;
462 }
463
464
465
466
467 final List<ProcessingInstruction> mark = new ArrayList<ProcessingInstruction>();
468 getDescendantMarkElements(((DOMSource) source).getNode(), mark,
469 new HashSet<String>());
470
471 for (final ProcessingInstruction m : mark) {
472 final Element cr = doc.createElementNS(
473 result.getNamespaceURI(), CHILD_RENDERER_ELEMENT_NAME);
474 final String empId = SplittedDocHolder.getGeneRef(m);
475 cr.setAttributeNS(null, ID_ATTRIBUTE_NAME, empId);
476 final Element clone = (Element) doc.importNode(m, true);
477 cr.appendChild(clone);
478 result.appendChild(cr);
479 }
480 return result;
481 }
482 /***
483 * Retrieves all {@link SplittedDocHolder#PI_GENEREF_TARGET} processing instructions. Filters out multiple
484 * instances of {@link SplittedDocHolder#PI_GENEREF_TARGET} with same id.
485 * @param node walk through descendants of this node. Returns empty list
486 * when <code>null</code>.
487 * @param refs place all ref PIs here.
488 * @param ids ids of elements present in the result.
489 */
490 private void getDescendantMarkElements(final Node node,
491 List<ProcessingInstruction> refs, Set<String> ids) {
492 if (node == null)
493 return;
494 final String id = SplittedDocHolder.getGeneRef(node);
495 if(id!=null){
496 if (ids.contains(id))
497 return;
498
499 ids.add(id);
500 refs.add((ProcessingInstruction)node);
501 }
502
503 for (Node child = node.getFirstChild(); child != null; child = child
504 .getNextSibling()) {
505 getDescendantMarkElements(child, refs, ids);
506 }
507 }
508
509
510
511
512 public void dispose() {
513
514 }
515
516
517
518
519 public IConfigurator getConfigurator() {
520
521 return null;
522 }
523
524
525
526
527 public CoordinatorInfo getInfo() {
528 return coordinatorInfo;
529 }
530
531
532
533
534 public StreamResult requestResult(String fileName) throws IOException {
535 final StreamResult result = new StreamResult(fileName);
536 result.setOutputStream(ExportUtils.openStream(new File(fileName)));
537 return result;
538 }
539
540
541
542
543 public Result startExport(File systemId) throws ExportException,
544 IOException {
545 assert this.keyMap.isEmpty();
546
547 this.geneIdMapping.clear();
548 this.newKeys.clear();
549 this.deletedKeys.clear();
550 this.deletedKeys.addAll(this.rendererKeys.keySet());
551
552
553 this.rendererTree = new DOMResult();
554 this.rendererTree.setNode(doc.createDocumentFragment());
555 return this.rendererTree;
556 }
557 /***
558 * <p>
559 * Here a coordinator output is written. This output is intended to show
560 * the tree hierarchy of renderers. For further description please see
561 * {@link #partialResultEvent(DocumentFragment, NamespacePath, Source, String, CoordinatorInputKey)}.
562 * </p>
563 */
564 private DOMResult rendererTree = null;
565 /***
566 * <p>
567 * Maps input pipe ID to a renderer instance. Filled in
568 * {@link #partialResultEvent(DocumentFragment, NamespacePath, Source, String, CoordinatorInputKey)}
569 * method.
570 * </p>
571 * <p>
572 * {@link #deletedKeys Deleted keys} are automatically removed in
573 * {@link #finishExport()}.
574 * </p>
575 */
576 public final Map<CoordinatorInputKey, RendererSite> rendererKeys = new HashMap<CoordinatorInputKey, RendererSite>();
577 /***
578 * Maps namespace of the document that the renderer processes, to a
579 * renderer instance. Contains same renderer instances as
580 * {@link #rendererKeys}.
581 */
582 private final Map<String, List<RendererSite>> rendererNamespaces = new HashMap<String, List<RendererSite>>();
583 /***
584 * <p>
585 * Temporary storage of renderer instances. When coordinator is queried
586 * for object offer and no renderer for given namespace exists, one is
587 * constructed and placed here. When the instance is really needed, it
588 * is moved to {@link #rendererKeys} and {@link #rendererNamespaces}
589 * maps.
590 * </p>
591 * <p>
592 * Only renderers able to process Object source are placed here.
593 * </p>
594 */
595 private final Map<String, IRenderer> tempStorage = new HashMap<String, IRenderer>();
596 /***
597 * Maps {@link RendererSite}'s id to the coordinator input key. Filled
598 * in
599 * {@link #partialResultEvent(DocumentFragment, NamespacePath, Source, String, CoordinatorInputKey)}
600 * method, and cleared when the GENE output processing finishes.
601 */
602 private final Map<String, CoordinatorInputKey> keyMap = new HashMap<String, CoordinatorInputKey>();
603 /***
604 * The root key of the hierarchy.
605 */
606 public CoordinatorInputKey rootKey;
607 /***
608 * <p>
609 * The nametree (key) hierarchy. Maps key to a set of its children. If
610 * key is missing from the map, maps to <code>null</code> value or an
611 * empty set then the nametree does not have any children.
612 * </p>
613 * <p>
614 * {@link #deletedKeys Deleted keys} are automatically removed in
615 * {@link #finishExport()}.
616 * </p>
617 */
618 public final Map<CoordinatorInputKey, Set<CoordinatorInputKey>> nametreeHierarchy = new HashMap<CoordinatorInputKey, Set<CoordinatorInputKey>>();
619 /***
620 * <p>
621 * Maps GENE-generated ids to the coordinator input key instance. Used
622 * by renderer context to map from GENE id (provided to the renderer) to
623 * child renderer instance.
624 * </p>
625 * <p>
626 * Constructed in {@link #finishExport()}.
627 * </p>
628 */
629 public final Map<String, CoordinatorInputKey> geneIdMapping = new HashMap<String, CoordinatorInputKey>();
630 /***
631 * <p>
632 * Contains set of new keys (keys that were not introduced in previous
633 * GENE output processing).
634 * </p>
635 * <p>
636 * Cleared in {@link #startExport(URLDir, String, String)}, filled in
637 * {@link #partialResultEvent(DocumentFragment, NamespacePath, Source, String, CoordinatorInputKey)}.
638 * </p>
639 */
640 public final Set<CoordinatorInputKey> newKeys = new HashSet<CoordinatorInputKey>();
641 /***
642 * <p>
643 * Contains set of keys that were introduced in previous GENE output
644 * processing but they are missing in current data.
645 * </p>
646 * <p>
647 * Initialized in {@link #startExport(File)},
648 * processed in
649 * {@link #partialResultEvent(DocumentFragment, NamespacePath, Source, String, CoordinatorInputKey)}.
650 * </p>
651 */
652 public final Set<CoordinatorInputKey> deletedKeys = new HashSet<CoordinatorInputKey>();
653
654
655
656
657
658
659 public void alterContext(IExporter exporter, ExportContext context,
660 NamespacePath path) {
661
662 context.isRoot = true;
663 context.parentNamespace = null;
664 }
665 }
666 /***
667 * Represents the renderer with its environment.
668 * @author Martin Vysny
669 */
670 public final class RendererSite {
671 /***
672 * Constructor.
673 * @param renderer the renderer instance.
674 * @param input the input path identifier.
675 */
676 public RendererSite(final IRenderer renderer,
677 final CoordinatorInputKey input) {
678 super();
679 if (renderer == null)
680 throw new IllegalArgumentException("null renderer");
681 this.renderer = renderer;
682 this.preprocessor = renderer.createPreprocessor();
683 if (this.preprocessor != null) {
684 this.preprocessor.init(input);
685 }
686 }
687 /***
688 * The renderer instance.
689 */
690 public final IRenderer renderer;
691 /***
692 * Input preprocessor instance.
693 */
694 private final IInputPreprocessor preprocessor;
695 /***
696 * Source data for the renderer. May be DOM or Object only. Do not set
697 * directly, use {@link #setSource(Source)} instead.
698 */
699 private IChangeCollector source;
700 /***
701 * Sets given source to the renderer.
702 * @param source the source to set.
703 */
704 public void setSource(final Source source) {
705 if (this.source == null) {
706 if (source instanceof DOMSource) {
707 this.source = new DOMChangeCollector();
708 } else if (source instanceof ObjectSource) {
709 this.source = new ObjectChangeCollector();
710 } else
711 throw new IllegalArgumentException(
712 "Illegal source type: " + source.getClass().getName());
713 this.source.init(source);
714 } else {
715 this.source.reinit(source);
716 }
717 if (this.preprocessor == null) {
718 return;
719 }
720 this.source = this.preprocessor.process(this.source);
721 if (this.source.getSource() == null)
722 throw new IllegalStateException("Preprocessor "
723 + this.preprocessor.getClass().getName()
724 + " failed to initialize result change collector.");
725 }
726 /***
727 * Returns the source object.
728 * @return the source.
729 */
730 public IChangeCollector getSource() {
731 return this.source;
732 }
733 /***
734 * An unique integer id.
735 */
736 public final String id = String
737 .valueOf(++GeneDataProvider.this.rendererSiteId);
738 /***
739 * <code>false</code> if the renderer is not new and needs to
740 * reinitialize instead of initialization.
741 */
742 private boolean isNew = true;
743 /***
744 * Checks if this renderer is new or being reused.
745 * @return <code>false</code> if the renderer is not new and needs to
746 * reinitialize instead of initialization.
747 */
748 public boolean isNew() {
749 return this.isNew;
750 }
751 /***
752 * Initializes (or reinitializes) the renderer.
753 * @throws EditorException if initialization fails.
754 */
755 public void init() throws EditorException {
756 if (this.source == null)
757 throw new IllegalStateException("source is null");
758 if (this.isNew) {
759 this.isNew = false;
760 this.renderer.init(this.source.getSource(),
761 GeneDataProvider.this.context);
762 return;
763 }
764
765 this.renderer.reinit(this.source);
766 }
767 }
768 /***
769 * Unique id for the renderer site instance.
770 */
771 private int rendererSiteId = 0;
772 /***
773 * The coordinator instance.
774 */
775 private final Coordinator coordinator;
776 /***
777 * The coordinator info.
778 */
779 private final CoordinatorInfo coordinatorInfo;
780 /***
781 * Returns the coordinator information instance for the GENE coordinator.
782 * @return coordinator info for this coordinator.
783 */
784 public CoordinatorInfo getCoordinatorInfo() {
785 return this.coordinatorInfo;
786 }
787 /***
788 * The context object for renderers.
789 */
790 private final RendererContext context;
791 /***
792 * The document instance, owning all nodes created by this class.
793 */
794 private static final Document doc = TransformUtils.builder.newDocument();
795 }