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