2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * $Id: ComponentBean.java 465962 2006-10-20 03:29:04Z gvanmatre $
20   */
21  package org.apache.shale.clay.config.beans;
22  
23  import java.io.Serializable;
24  import java.util.Collection;
25  import java.util.Iterator;
26  import java.util.Map;
27  import java.util.TreeSet;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.shale.util.Messages;
32  
33  /***
34   * <p>This is the base class of most of the metadata that is used by the
35   * {@link org.apache.shale.clay.component.Clay} component to build
36   * a component subtree.
37   *
38   * <dl>
39   * <dt> There are three sources that populate this object:
40   * <dd> {@link org.apache.shale.clay.config.ClayXmlParser} - from XML config files
41   * <dd> {@link org.apache.shale.clay.parser.builder.Builder} - extending classes
42   * <dd> {@link org.apache.shale.clay.component.Clay} - <code>shapeValidator</code>
43   *      a <code>validator</code> style of event method binding
44   * </dl>
45   * </p>
46   */
47  public class ComponentBean extends AbstractBean implements Comparable, Serializable {
48  
49      /***
50       * <p>Unique id used by the Serializable interface.</p>
51       */
52      private static final long serialVersionUID = 3907217039524312373L;
53  
54      /***
55       * <p>Common Logging utility class.</p>
56       */
57      private static Log log;
58      static {
59          log = LogFactory.getLog(ComponentBean.class);
60      }
61  
62      /***
63       * <p>A class scoped unique sequence counter.</p>
64       */
65      private static long uniqueSequence = -1;
66  
67      /***
68       * @return the next <code>uniqueSequence</code>
69       */
70      private synchronized long generateId() {
71         return ++uniqueSequence;
72      }
73  
74      /***
75       * <p>The config beans unique sequence.  The value is
76       * populated from a call to <code>generateId</code>.</p>
77       */
78      private long jspId = -1;
79  
80      /***
81       * <p>Returns a unique id that will stick to the config bean.
82       * This is clay's version of the <code>JspIdConsumer</code>
83       * in JSP 2.1.</p>
84       *
85       * @return unique id for a view element
86       */
87      public String getJspId() {
88         if (jspId == -1) {
89             jspId = generateId();
90         }
91         return Long.toString(jspId);
92      }
93  
94      /***
95       * <p>
96       * Message resources for this class.
97       * </p>
98       */
99      private static Messages messages = new Messages(
100             "org.apache.shale.clay.Bundle", ComponentBean.class
101             .getClassLoader());
102 
103     /***
104      * <p>Unique id that points to component meta information.</p>
105      */
106     private String jsfid = null;
107 
108     /***
109      * <p>This value pair collection is used to set the property values for JSF object
110      * implementing <code>UIComponent, Validator, ValueChangeListener, ActionListener
111      * and Converter</code>.
112      * </p>
113      */
114     private Map attributes = new Attributes();
115 
116     /***
117      * <p>An object reference that shows a generalization relationship through the
118      * metadata.  The <code>extends</code> attribute will hold the <code>jsfid</code>
119      * of the parent this instance extends.
120      * </p>
121      */
122     private ComponentBean isAParent = null;
123 
124     /***
125      * <p>An object reference that shows a composition relationship.  This reference
126      * will point to the parent that holds this object instance in one of it's collections.
127      *</p>
128      */
129     private ComponentBean hasAParent = null;
130 
131     /***
132      * <p>The <code>componentType</code> relates to a JSF component type used use to instantiate
133      * the component using abstract factories.  For component's like <code>ActionListener and
134      * ValueChangeListener</code>, that are not registered in the faces configuration file, the
135      * <code>componentType</code> is the fully qualified class name.
136      * </p>
137      */
138     private String componentType = null;
139 
140     /***
141      * <p>The <code>jsfid</code> of the meta component parent.</p>
142      */
143     private String extendsElementId = null;
144 
145     /***
146      * <p>Child meta components that form composition under another meta
147      * component instance.  Each instance in this set will be a instance
148      * of {@link ElementBean} and uniquely identified by <code>renderId</code>
149      * </p>
150      */
151     private Collection children = new TreeSet();
152 
153     /***
154      *  <p>Boolean flag indicates the meta inheritance of this component
155      *  has been resolved.</p>
156      */
157     private boolean isInheritanceFinal = false;
158 
159     /***
160      *  <p>Reference to an associated {@link ComponentBean} that is an instance of
161      *  {@link ConverterBean} and is used to instantiate a JSF <code>Converter</code>.
162      *  </p>
163      */
164     private ComponentBean converter = null;
165 
166     /***
167      *  <p>Reference to a set of associated {@link ComponentBean} that is an instance of
168      *  {@link ValidatorBean} and is used to instantiate a JSF <code>Validator</code>.
169      *  </p>
170      */
171     private TreeSet validators = new TreeSet();
172 
173     /***
174      *  <p>Reference to a set of associated {@link ComponentBean} that is an instance of
175      *  {@link ValueChangeListenerBean} and is used to instantiate a JSF <code>ValueChangeListener</code>.
176      *  </p>
177      */
178     private TreeSet valueChangeListeners = new TreeSet();
179 
180     /***
181      *  <p>Reference to a set of associated {@link ComponentBean} that is an instance of
182      *  {@link ActionListenerBean} and is used to instantiate a JSF <code>ActionListener</code>.
183      *  </p>
184      */
185     private TreeSet actionListeners = new TreeSet();
186 
187     /***
188      * <p>This attribute used when defining the template style of page composition where the
189      * body of the HTML element is rendered by the component ignoring the HTML.
190      */
191     private String allowBody = null;
192 
193     /***
194      * <p>Use this property to add the component to the parent's facet collection rather than
195      * the default children collection.</p>
196      */
197     private String facetName = null;
198 
199     /***
200      * <p>The replacement symbol table for the component meta-data.</p>
201      */
202     private Map symbols = new Attributes();
203 
204     /***
205      * <p>This property only applies when using the {@link org.apache.shale.clay.component.Clay}
206      * template features.  A <code>true</code> value is returned if the HTML child nodes under
207      * the node that this meta component is bound to should be rendered; otherwise, a <code>"false"</code>
208      * value is returned indicating the child nodes should be ignored.
209      * </p>
210      *
211      * @return literal string "true" if allow body is on
212      */
213     public String getAllowBody() {
214         return allowBody;
215     }
216 
217     /***
218      * <p>This property only applies when using the {@link org.apache.shale.clay.component.Clay}
219      * template features.  Sets a Boolean string value that indicating if the child HTML nodes
220      * under the node that this component is bound to should render or ignore its child nodes.
221      * </p>
222      *
223      * @param allowBody indicates how the child markup nodes are processed
224      *
225      */
226     public void setAllowBody(String allowBody) {
227         this.allowBody = allowBody;
228     }
229 
230     /***
231      * <p>Returns a boolean representation of the <code>allowBody</code> property.
232      * The default is <code>true</code></p>
233      *
234      * @return <code>true</code> if allowBody has a literal string value of "true"
235      */
236     public boolean getIsBodyAllowed() {
237        boolean f = true;
238        try {
239            if (allowBody != null) {
240                f = Boolean.valueOf(allowBody).booleanValue();
241            }
242        } catch (Exception e) {
243            f = true;
244        }
245 
246        return f;
247     }
248 
249   /***
250    * <p>Returns the facet name that will be used as the identifier when adding the
251    * component to the parent facets collection.</p>
252    *
253    * @return facetName
254    */
255    public String getFacetName() {
256       return facetName;
257    }
258 
259    /***
260     * <p>Sets the facet name that will be used as the identifier when adding the
261     * component to the parent facets collection.</p>
262     *
263     * @param facetName component grouping
264     */
265    public void setFacetName(String facetName) {
266       this.facetName = facetName;
267    }
268 
269    /***
270     * @return a value list of the object's state
271     */
272    public String toString() {
273         StringBuffer buff = new StringBuffer();
274         buff.append("jsfid=\"").append(jsfid).append(
275                 "\" componentType=\"").append(componentType).append(
276                 "\" extends=\"").append(extendsElementId).append("\"")
277                 .append(" allowBody=\"").append(allowBody)
278                 .append("\" ").append("facetName=\"").append(facetName)
279                 .append("\"");
280 
281         return buff.toString();
282     }
283 
284     /***
285      * <p>Returns the component type that is used to instantiate the associated
286      * JSF component.<p>
287      *
288      * @return component type
289      */
290     public String getComponentType() {
291         return componentType;
292     }
293 
294     /***
295      * <p>Returns the <code>jsfid</code> of the meta component that this
296      * instance inherits from.<p>
297      *
298      * @return extended jsfid
299      */
300     public String getExtends() {
301         return extendsElementId;
302     }
303 
304     /***
305      * <p>Sets the component type uses by abstract factories to instantiate
306      * associated JSF resources.</p>
307      *
308      * @param componentType used to create a JSF resource
309      */
310     public void setComponentType(String componentType) {
311         this.componentType = componentType;
312     }
313 
314     /***
315      * <p>Sets the <code>jsfid</code> of the meta component that this meta
316      * component inherits from.
317      * </p>
318      *
319      * @param extendsElementId extending jsfid
320      */
321     public void setExtends(String extendsElementId) {
322         this.extendsElementId = extendsElementId;
323     }
324 
325     /***
326      * <p>Returns a <code>Iterator</code> to the <code>children</code> set.
327      * Each item in the set is uniquely identified by its
328      * <code>renderId</code> property and an instance of {@link ElementBean}.
329      * </p>
330      *
331      * @return iterator for the children collection
332      */
333     public Iterator getChildrenIterator() {
334 
335         return children.iterator();
336     }
337 
338     /***
339      *<p>Returns a set of children that are instances of {@link ElementBean}.
340      *</p>
341      *
342      * @return children collection
343      */
344     public Collection getChildren() {
345         return children;
346     }
347 
348     /***
349      * <p>Merges two sets of children {@link org.apache.shale.clay.config.beans.ElementBean}. Items in the source
350      * collection will replace those in the target with the same <code>renderId</code>
351      * </p>
352      *
353      * @param collection of child components
354      */
355     public void setChildren(Collection collection) {
356         children.addAll(collection);
357     }
358 
359     /***
360      * <p>Adds a child {@link org.apache.shale.clay.config.beans.ElementBean} to the <code>children</code> set and
361      * fixes up the composition parent relationship.</p>
362      *
363      * @param obj element bean added as a child
364      */
365     public void addChild(ElementBean obj) {
366         if (obj.getJsfid() != null) {
367             obj.setHasAParent(this);
368             children.add(obj);
369         } else {
370             log.error(messages.getMessage("missing.jsfid.error", new Object[] {"ElementBean.jsfid", getJsfid()}));
371         }
372     }
373 
374     /***
375      * <p>This <code>Comparable</code> implementation makes the
376      * <code>jsfid</code> attribute the unique identifier for the object in a
377      * set.</p>
378      *
379      * @param obj target object to compare to
380      * @return weighted value based on the jsfid property
381      */
382     public int compareTo(Object obj) {
383         return ((ComponentBean) obj).getJsfid().compareTo(
384                 getJsfid());
385     }
386 
387     /***
388      * <p>Gets a meta converter bean used to instantiate a jsf <code>Converter</code>.</p>
389      *
390      * @return converter assigned to the component
391      */
392     public ComponentBean getConverter() {
393         return converter;
394     }
395 
396     /***
397      * <p>Adds a {@link ConverterBean} and assigns the composition parent.</p>
398      *
399      * @param bean converter assigned to this component
400      */
401     public void addConverter(ConverterBean bean) {
402         if (bean.getJsfid() != null) {
403             bean.setHasAParent(this);
404             converter = bean;
405         } else {
406             log.error(messages.getMessage("missing.jsfid.error", new Object[] {"ConverterBean.jsfid", getJsfid()}));
407         }
408     }
409 
410     /***
411      * <p>Returns a <code>Collection</code> of meta validators used to create jsf <code>Validator</code>
412      * object instances.
413      *
414      * @return collection of validators
415      */
416     public Collection getValidators() {
417         return validators;
418     }
419 
420     /***
421      * <p>Adds a collection of {@link ValidatorBean} to the <code>validator</code> set.  Each
422      * instance is uniquely identified in the collection by the <code>jsfid</code>.
423      * </p>
424      *
425      * @param collection of validators added to the component
426      */
427     public void setValidators(Collection collection) {
428         validators.addAll(collection);
429     }
430 
431     /***
432      * <p>Returns a <code>Iterator</code> to the <code>validator</code> set.  Each
433      * object will be an instance of {@link ValidatorBean}.
434      * </p>
435      *
436      * @return Iterator of the components validators collection
437      */
438     public Iterator getValidatorIterator() {
439 
440         return validators.iterator();
441     }
442 
443     /***
444      * <p>Adds a {@link ValidatorBean} and assigns the composition parent.</p>
445      *
446      * @param bean validator to add to the component
447      */
448     public void addValidator(ValidatorBean bean) {
449         if (bean.getJsfid() != null) {
450             validators.add(bean);
451         } else {
452             log.error(messages.getMessage("missing.jsfid.error",
453                     new Object[] {"ValidatorBean.jsfid", getJsfid()}));
454         }
455     }
456 
457     /***
458      * <p>Returns a <code>Iterator</code> to the <code>valueChangeListeners</code> set.
459      * Each {@link ValueChangeListenerBean} in the collection is uniquely identified
460      * by <code>jsfid</code>.
461      *</p>
462      *
463      * @return collection of value change listeners
464      */
465     public Collection getValueChangeListeners() {
466         return valueChangeListeners;
467     }
468 
469     /***
470      * <p>Merges a collection of {@link org.apache.shale.clay.config.beans.ValueChangeListenerBean} where items in the
471      * source collection with the same <code>jsfid</code> will override items
472      * in the target set with the same identifier.
473      * </p>
474      *
475      * @param collection of value change listeners added to the component
476      */
477     public void setValueChangeListeners(Collection collection) {
478         valueChangeListeners.addAll(collection);
479     }
480 
481     /***
482      * <p>Returns a <code>Iterator</code> for the <code>valueChangeListener</code> set
483      * of {@link ValueChangeListenerBean}.<p>
484      *
485      * @return iterator for the collection of value change listeners
486      */
487     public Iterator getValueChangeListenerIterator() {
488         return valueChangeListeners.iterator();
489     }
490 
491     /***
492      * <p>Adds a {@link ValueChangeListenerBean} to the set where each instance is
493      * uniquely identified by <code>jsfid</code>.</p>
494      *
495      * @param bean value change listener added to the components collection of listeners
496      */
497     public void addValueChangeListener(ValueChangeListenerBean bean) {
498         if (bean.getJsfid() != null) {
499             valueChangeListeners.add(bean);
500         } else {
501             log.error(messages.getMessage("missing.jsfid.error",
502                     new Object[] {"ValueChangeListenerBean.jsfid", getJsfid()}));
503         }
504     }
505 
506     /***
507      * <p>Returns a <code>Collection</code> of {@link ActionListenerBean}. </p>
508      *
509      * @return collection of the component's action listeners
510      */
511     public Collection getActionListeners() {
512         return actionListeners;
513     }
514 
515     /***
516      * <p>Merges two collections where items in the source collection will override
517      * those in the target collection of {@link ActionListenerBean} by the <code>jsfid</code>
518      * property.</p>
519      *
520      * @param collection of action listeners added to the components set
521      */
522     public void setActionListeners(Collection collection) {
523         actionListeners.addAll(collection);
524     }
525 
526     /***
527      * <p>Returns an <code>Iterator</code> for the <code>actionListeners</code> set of
528      * {@link ActionListenerBean}.
529      * </p>
530      *
531      * @return iterator of the component's action listeners set
532      */
533     public Iterator getActionListenerIterator() {
534 
535         return actionListeners.iterator();
536     }
537 
538     /***
539      * <p>Adds an {@link ActionListenerBean} to the <code>actionListeners</code> set.  Each
540      * instance is uniquely identified by the <code>jsfid</code> property.
541      * </p>
542      *
543      * @param bean action listener added to the component
544      */
545     public void addActionListener(ActionListenerBean bean) {
546         if (bean.getJsfid() != null) {
547             actionListeners.add(bean);
548         } else {
549             log.error(messages.getMessage("missing.jsfid.error",
550               new Object[] {"ActionListenerBean.jsfid", getJsfid()}));
551         }
552     }
553 
554     /***
555      * <p>This inner class provides implementation for an <code>Iterator</code> handeling
556      * {@link AttributeBean} objects in the <code>attributes</code> collection.
557      * </p>
558      *
559      * @return iterator for the components attributes Map
560      */
561     public Iterator getAttributeIterator() {
562 
563         return new Iterator() {
564             /***
565              * <p>Graps a <code>Iterator</code> instance of the attributes entry set</p>
566              */
567             private Iterator entrySet = getAttributes().entrySet().iterator();
568             /***
569              * <p>Decorates the <code>Iterator</code> of the private <code>entrySet</code></p>
570              */
571             public boolean hasNext() {
572                 return entrySet.hasNext();
573             }
574             /***
575              * <p>Returns the next {@link AttributeBean} in the Map collection</p>
576              */
577             public Object next() {
578                 Map.Entry e = (Map.Entry) entrySet.next();
579                 return e.getValue();
580             }
581 
582             /***
583              * <p>This method is not applicable for this class and has an empty
584              * method body but has to be implemented to realize the <code>Iterator</code>
585              * interface.
586              * </p>
587              */
588             public void remove() {
589             }
590         };
591 
592     }
593 
594     /***
595      * <p>Returns a {@link AttributeBean} by the classes <code>name</code> property.</p>
596      *
597      * @param key attribute name
598      * @return attribute bean for the key
599      */
600     public AttributeBean getAttribute(String key) {
601         return (AttributeBean) getAttributes().get(key);
602     }
603 
604     /***
605      * <p>Adds a {@link AttributeBean} to the <code>attributes</code> Map collection where
606      * the <code>name</code> property is the key identifier in the value pair relationship.
607      * </p>
608      *
609      * @param obj attribute bean added to the attributes Map
610      */
611     public void addAttribute(AttributeBean obj) {
612         if (obj.getName() != null) {
613             obj.setHasAParent(this);
614             attributes.put(obj.getName(), obj);
615         } else {
616             log.error(messages.getMessage("missing.jsfid.error", new Object[] {"AttributeBean.jsfid", getJsfid()}));
617         }
618 
619     }
620 
621     /***
622      * <p>Returns the a <code>Map</code> collection of {@link AttributeBean} objects.</p>
623      *
624      * @return attributes map
625      */
626     public Map getAttributes() {
627 
628         return attributes;
629     }
630 
631     /***
632      * <p>Returns the unique meta component identifier.</p>
633      *
634      * @return jsfid
635      */
636     public String getJsfid() {
637         return jsfid;
638     }
639 
640     /***
641      * <p>Merges a set of {@link AttributeBean} where items in the source
642      * collection override items in the target collection by the object's
643      * <code>jsfid</code> property.
644      * </p>
645      *
646      * @param map of attributes to be merged
647      */
648     public void setAttributes(Map map) {
649         attributes.putAll(map);
650     }
651 
652     /***
653      * <p>Sets the unique meta component identifier.</p>
654      *
655      * @param jsfid identifier
656      */
657     public void setJsfid(String jsfid) {
658         this.jsfid = jsfid;
659     }
660 
661     /***
662      * <p>Returns the parent component that aggregates this object.</p>
663      *
664      * @return composition parent
665      */
666     public ComponentBean getHasAParent() {
667         return hasAParent;
668     }
669 
670     /***
671      * <p>Returns the parent component that generalizes this object.</p>
672      *
673      * @return inheritance parent
674      */
675     public ComponentBean getIsAParent() {
676         return isAParent;
677     }
678 
679     /***
680      * <p>Sets the parent that owns this component.</p>
681      *
682      * @param bean composition parent
683      */
684     public void setHasAParent(ComponentBean bean) {
685         hasAParent = bean;
686     }
687 
688     /***
689      * <p>Sets the component that this instance extends.</p>
690      *
691      * @param bean inheritance parent
692      */
693     public void setIsAParent(ComponentBean bean) {
694         isAParent = bean;
695     }
696 
697     /***
698      * <p>Returns a xpath like string describing how this component
699      * fits into the overall composition.</p>
700      *
701      * @return composition client id
702      */
703     public StringBuffer getHasAClientId() {
704         StringBuffer id = null;
705 
706         if (getHasAParent() != null) {
707             id = getHasAParent().getHasAClientId();
708         } else {
709             id = new StringBuffer();
710         }
711 
712         id.append("/").append(getJsfid());
713 
714         return id;
715     }
716 
717     /***
718      * <p>Returns an xpath like string that describes the heritage
719      * of this component.</p>
720      *
721      * @return inheritance client id
722      */
723     public StringBuffer getIsAClientId() {
724         StringBuffer id = new StringBuffer();
725 
726         ComponentBean parent = getIsAParent();
727         while (parent != null) {
728             id.insert(0, parent.getJsfid() + (id.length() > 0 ? ":" : ""));
729             parent = parent.getIsAParent();
730         }
731         parent = null;
732 
733         return id;
734     }
735 
736     /***
737      * <p>Returns a boolean flag indicating that the meta inheritances
738      * has been resolved.</p>
739      *
740      * @return <code>true</code> if inheritance has been resolved
741      */
742     public boolean isInheritanceFinal() {
743         return isInheritanceFinal;
744     }
745 
746     /***
747      * <p>Sets a boolean flag indicating that the meta inheritances
748      * have been resolved.</p>
749      *
750      * @param b <code>true</code> if inheritance has been resolved
751      */
752     public void setInheritanceFinal(boolean b) {
753         isInheritanceFinal = b;
754     }
755 
756     /***
757      * <p>Returns the identifier that will populate the JSF <code>UIComponent.id</code>
758      *  property and is used to name the component within the tree.
759      * </p>
760      *
761      * @return component's id
762      */
763     public String getId() {
764         AttributeBean attr = (AttributeBean) attributes.get("id");
765         if (attr != null) {
766            return attr.getValue();
767         }
768 
769         return null;
770     }
771 
772     /***
773      * <p>Sets the identifier that is used to populate the JSF <code>UIComponent.id</code>
774      * property. </p>
775      *
776      * @param id component's identifier
777      */
778     public void setId(String id) {
779         AttributeBean attr = new AttributeBean();
780         attr.setBindingType(AttributeBean.BINDING_TYPE_NONE);
781         attr.setValue(id);
782         attr.setName("id");
783         addAttribute(attr);
784     }
785 
786     /***
787      * <p>Adds a symbol identified by the
788      * {@link SymbolBean} to the symbols collection.</p>
789      *
790      * @param symbol added to the symbols Map
791      */
792     public void addSymbol(SymbolBean symbol) {
793        if (symbol.getName() != null && symbol.getName().length() > 0) {
794             StringBuffer buff = new StringBuffer(symbol.getName());
795             if (buff.charAt(0) != '@') {
796                buff.insert(0, '@');
797                symbol.setName(buff.toString());
798             }
799 
800             symbols.put(symbol.getName(), symbol);
801         }
802     }
803 
804     /***
805      * <p>Returns the replacement symbols assigned to the component.
806      * The key value represents the literal replacement string.
807      * The value Map property represents target {@link SymbolBean}.</p>
808      *
809      * @return map of symbols
810      */
811     public Map getSymbols() {
812        return symbols;
813     }
814 
815     /***
816      * <p>Returns a {@link SymbolBean} from the <code>symbols</code>
817      * Map by <code>name</code>.  Prepends a '@' character to the
818      * <code>name</code> if it doesn't exist.</p>
819      *
820      * @param name of the symbol
821      * @return symbol bean identified by name
822      */
823     public SymbolBean getSymbol(String name) {
824         StringBuffer tmp = new StringBuffer(name);
825         if (tmp.charAt(0) != '@') {
826             tmp.insert(0, '@');
827         }
828 
829         SymbolBean symbol = (SymbolBean) symbols.get(tmp.toString());
830 
831         return symbol;
832     }
833 
834 }
835