001: /* ComponentInfo.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Tue May 31 11:27:13 2005, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2005 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.zk.ui.metainfo;
020:
021: import java.util.Map;
022: import java.util.HashMap;
023: import java.util.List;
024: import java.util.LinkedList;
025: import java.util.Iterator;
026: import java.util.Set;
027: import java.util.Collection;
028: import java.util.Collections;
029:
030: import org.zkoss.lang.D;
031: import org.zkoss.lang.Strings;
032: import org.zkoss.lang.Classes;
033: import org.zkoss.util.CollectionsX;
034:
035: import org.zkoss.zk.ui.Page;
036: import org.zkoss.zk.ui.Component;
037: import org.zkoss.zk.ui.Executions;
038: import org.zkoss.zk.ui.UiException;
039: import org.zkoss.zk.ui.ext.DynamicTag;
040: import org.zkoss.zk.ui.event.Events;
041: import org.zkoss.zk.ui.sys.ComponentCtrl;
042: import org.zkoss.zk.ui.sys.ComponentsCtrl;
043: import org.zkoss.zk.ui.util.Composer;
044: import org.zkoss.zk.ui.util.Condition;
045: import org.zkoss.zk.ui.util.ConditionImpl;
046: import org.zkoss.zk.ui.util.ForEach;
047: import org.zkoss.zk.ui.util.ForEachImpl;
048: import org.zkoss.zk.ui.metainfo.impl.MultiComposer;
049: import org.zkoss.zk.xel.ExValue;
050: import org.zkoss.zk.xel.impl.EvaluatorRef;
051:
052: /**
053: * Represents a componennt instance defined in a ZUML page.
054: *
055: * <p>Though serializable, we can restore {@link #getPageDefinition}
056: * correctly after deserialized.
057: *
058: * <p>Note:it is not thread-safe.
059: *
060: * <p>It is serializable.
061: *
062: * @author tomyeh
063: */
064: public class ComponentInfo extends NodeInfo implements Cloneable,
065: Condition, java.io.Externalizable {
066: /** Note: it is NodeInfo's job to serialize _evalr. */
067: private transient EvaluatorRef _evalr;
068: private transient NodeInfo _parent; //it is restored by its parent
069: private transient ComponentDefinition _compdef;
070: /** The implemetation class (use). */
071: private ExValue _implcls;
072: /** A list of {@link Property}, or null if no property at all. */
073: private List _props;
074: /** A Map of event handler to handle events. */
075: private EventHandlerMap _evthds;
076: /** the annotation map. Note: it doesn't include what are defined in _compdef. */
077: private AnnotationMap _annots;
078: /** The tag name for the dyanmic tag. Used only if this implements {@link DynamicTag}*/
079: private String _tag;
080: /** The effectiveness condition (see {@link #isEffective}).
081: * If null, it means effective.
082: */
083: private ConditionImpl _cond;
084: /** The fulfill condition.
085: */
086: private String _fulfill;
087: /** The apply attribute.
088: */
089: private ExValue _apply;
090: /** The forward condition.
091: */
092: private String _forward;
093: /** The forEach, forEachBegin and forEachEnd attribute,
094: * which are used to evaluate this info multiple times.
095: */
096: private String[] _forEach;
097:
098: /** Constructs the information about how to create component.
099: * @param parent the parent; never null.
100: * @param compdef the component definition; never null
101: * @param tag the tag name; Note: if component implements
102: * {@link DynamicTag}, this argument must be specified.
103: * If {@link DynamicTag} is not implemented, this argument must
104: * be null.
105: */
106: public ComponentInfo(NodeInfo parent, ComponentDefinition compdef,
107: String tag) {
108: if (parent == null || compdef == null)
109: throw new IllegalArgumentException(
110: "parent and compdef required");
111:
112: _parent = parent;
113: _compdef = compdef;
114: _tag = tag;
115: _parent.appendChildDirectly(this );
116: _evalr = parent.getEvaluatorRef();
117: }
118:
119: /** Constructs the info about how to create a component that is not
120: * a dynamic tag.
121: * @param parent the parent; never null.
122: */
123: public ComponentInfo(NodeInfo parent, ComponentDefinition compdef) {
124: this (parent, compdef, null);
125: }
126:
127: /** This constructor is used only for {@link java.io.Externalizable}.
128: * Don't call it, otherwise.
129: * @since 3.0.0
130: */
131: public ComponentInfo() {
132: }
133:
134: /** Returns the language definition that {@link #getComponentDefinition}
135: * belongs to, or null if the component definition is temporary.
136: */
137: public LanguageDefinition getLanguageDefinition() {
138: return _compdef.getLanguageDefinition();
139: }
140:
141: /** Returns the component definition, or null if it is PageDefinition.
142: */
143: public ComponentDefinition getComponentDefinition() {
144: return _compdef;
145: }
146:
147: /** Returns the tag name, or null if no tag name.
148: * @since 3.0.0
149: */
150: public String getTag() {
151: return _tag;
152: }
153:
154: /** Sets the parent.
155: */
156: public void setParent(NodeInfo parent) {
157: //we don't check if parent is changed (since we have to move it
158: //to the end)
159: if (_parent != null)
160: _parent.removeChildDirectly(this );
161:
162: _parent = parent;
163:
164: if (_parent != null)
165: _parent.appendChildDirectly(this );
166: }
167:
168: /** Used for implementation only. */
169: /*package*/void setParentDirectly(NodeInfo parent) {
170: _parent = parent;
171: }
172:
173: /** Returns the property name to which the text enclosed within
174: * the element (associated with this component definition) is assigned to.
175: *
176: * <p>Default: null (means to create a Label component as the child)
177: *
178: * @see ComponentDefinition#getTextAs
179: * @since 3.0.0
180: */
181: public String getTextAs() {
182: return _compdef.getTextAs();
183: }
184:
185: /** Returns the fulfill condition that controls when to create
186: * the child components, or null if the child components
187: * are created at the time when the page is loaded.
188: *
189: * <p>Default: null.
190: *
191: * <p>There are several forms:<br/>
192: * "eventName", "targetId.evetName", "id1/id2.evetName",
193: * and "${elExpr}.eventName".
194: * <p>Since 3.0.2, you can specify a list of fulfill conditions by
195: * separating them with comma. For example:<br/>
196: * "id1.event1, id2/id3.event2"
197: *
198: * <p>If not null, the child components specified in
199: * {@link #getChildren} are created, when the event sepcified in
200: * the fulfill condition is received at the first time.
201: *
202: * <p>It is the value specified in the fulfill attribute.
203: *
204: * @since 2.4.0
205: */
206: public String getFulfill() {
207: return _fulfill;
208: }
209:
210: /** Sets the fulfill condition that controls when to create
211: * the child components.
212: *
213: * <p>If not null, the child components specified in
214: * {@link #getChildren} are created, when the event sepcified in
215: * the fulfill condition is received at the first time.
216: *
217: * @param fulfill the fulfill condition. There are several forms:<br/>
218: * "eventName", "targetId.evetName", "id1/id2.evetName",
219: * and "${elExpr}.eventName".
220: * <p>Since 3.0.2, you can specify a list of fulfill conditions by
221: * separating them with comma. For example:<br/>
222: * "id1.event1, id2/id3.event2"
223: * @since 2.4.0
224: */
225: public void setFulfill(String fulfill) {
226: _fulfill = fulfill != null && fulfill.length() > 0 ? fulfill
227: : null;
228: }
229:
230: /** Returns the composer for this info, or null if not available.
231: * It evaluates the value returned by {@link #getApply}.
232: *
233: * @see #getApply
234: * @since 3.0.0
235: */
236: public Composer getComposer(Page page) {
237: return getComposer(page, null);
238: }
239:
240: /** Returns the composer for this info, or nuull if not available.
241: *
242: * @param comp the component used as the self variable to resolve
243: * EL expressions, if any.
244: * Notice that UI engine uses the parent component for this argument.
245: * If comp is null, it is the same as {@link #getComposer(Page)}.
246: * If comp is not null, it is used as the self variable.
247: * @see #getApply
248: * @since 3.0.1
249: */
250: public Composer getComposer(Page page, Component comp) {
251: if (_apply != null) {
252: Object o = comp != null ? _apply.getValue(_evalr
253: .getEvaluator(), comp) : _apply.getValue(_evalr
254: .getEvaluator(), page);
255: ;
256: try {
257: if (o instanceof String) {
258: final String s = (String) o;
259: if (s.indexOf(',') >= 0)
260: o = CollectionsX.parse(null, s, ',');
261: }
262:
263: if (o instanceof Collection) {
264: final Collection c = (Collection) o;
265: int sz = c.size();
266: switch (sz) {
267: case 0:
268: return null;
269: case 1:
270: o = c.iterator().next();
271: break;
272: default:
273: o = c.toArray(new Object[sz]);
274: break;
275: }
276: }
277:
278: if (o instanceof Object[])
279: return MultiComposer
280: .getComposer(page, (Object[]) o);
281:
282: if (o instanceof String) {
283: final String clsnm = ((String) o).trim();
284: o = page != null ? page.resolveClass(clsnm)
285: .newInstance() : Classes
286: .newInstanceByThread(clsnm);
287: } else if (o instanceof Class)
288: o = ((Class) o).newInstance();
289:
290: if (o instanceof Composer)
291: return (Composer) o;
292: } catch (Exception ex) {
293: throw UiException.Aide.wrap(ex);
294: }
295: if (o != null)
296: throw new UiException(Composer.class
297: + " not implemented by " + o);
298: }
299: return null;
300: }
301:
302: /** Returns the apply attribute that is the class that implements
303: * {@link Composer}, an instance of it or null.
304: *
305: * @since 3.0.0
306: * @see #getComposer
307: */
308: public String getApply() {
309: return _apply != null ? _apply.getRawValue() : null;
310: }
311:
312: /** Sets the apply attribute that is used to initialize
313: * the component.
314: *
315: * @param apply the attribute which must be the class that implements
316: * {@link org.zkoss.zk.ui.util.Composer}, an instance of it, or null.
317: * El expressions are allowed, but self means the parent, if not null,
318: * or page, if root, (after all, the component is not created yet).
319: * @since 3.0.0
320: */
321: public void setApply(String apply) {
322: _apply = apply != null && apply.length() > 0 ? new ExValue(
323: apply, Object.class) : null;
324: }
325:
326: /** Returns the forward condition that controls how to forward
327: * an event, that is received by the component created
328: * by this info, to another component.
329: *
330: * <p>Default: null.
331: *
332: * <p>If not null, when the component created by this
333: * info receives the event specified in the forward condition,
334: * it will forward it to the target component, which is also
335: * specified in the forward condition.
336: *
337: * @since 3.0.0
338: * @see #setForward
339: */
340: public String getForward() {
341: return _forward;
342: }
343:
344: /** Sets the forward condition that controls when to forward
345: * an event receiving by this component to another component.
346: *
347: * <p>The basic format:<br/>
348: * <code>onEvent1=id1/id2.onEvent2</code>
349: *
350: * <p>It means when onEvent1 is received, onEvent2 will be posted
351: * to the component with the specified path (id1/id2).
352: *
353: * <p>If onEvent1 is omitted, it is assumed to be onClick (and
354: * the equal sign need not to be specified.
355: * If the path is omitted, it is assumed to be the space owner
356: * {@link Component#getSpaceOwner}.
357: *
358: * <p>For example, "onOK" means "onClick=onOK".
359: *
360: * <p>You can specify several forward conditions by separating
361: * them with comma as follows:
362: *
363: * <p><code>onChanging=onChanging,onChange=onUpdate,onOK</code>
364: *
365: * @param forward the forward condition. There are several forms:
366: * "onEvent1", "target.onEvent1" and "onEvent1(target.onEvent2)",
367: * where target could be "id", "id1/id2" or "${elExpr}".
368: * The EL expression must return either a path or a reference to
369: * a component.
370: * @since 3.0.0
371: */
372: public void setForward(String forward) {
373: _forward = forward != null && forward.length() > 0 ? forward
374: : null;
375: }
376:
377: /** Returns a readonly list of properties ({@link Property}) (never null).
378: * @since 2.4.0
379: */
380: public List getProperties() {
381: return _props != null ? _props : Collections.EMPTY_LIST;
382: //it is better to protect with Collections.unmodifiableList
383: //but for better performance...
384: }
385:
386: /** Adds a property initializer.
387: * It will initialize a component when created with this info.
388: * @param name the member name. The component must have a valid setter
389: * for it.
390: * @param value the value. It might contain expressions (${}).
391: */
392: public void addProperty(String name, String value,
393: ConditionImpl cond) {
394: if (name == null || name.length() == 0)
395: throw new IllegalArgumentException("name");
396:
397: if (_props == null)
398: _props = new LinkedList();
399: _props.add(new Property(_evalr, name, value, cond));
400: }
401:
402: /** Adds an event handler.
403: *
404: * @param name the event name.
405: * @param zscript the script.
406: */
407: public void addEventHandler(String name, ZScript zscript,
408: ConditionImpl cond) {
409: if (name == null || zscript == null)
410: throw new IllegalArgumentException(
411: "name and zscript cannot be null");
412: //if (!Events.isValid(name))
413: // throw new IllegalArgumentException("Invalid event name: "+name);
414: //AbstractParser has checked it, so no need to check again
415:
416: final EventHandler evthd = new EventHandler(_evalr, zscript,
417: cond);
418: if (_evthds == null)
419: _evthds = new EventHandlerMap();
420: _evthds.add(name, evthd);
421: }
422:
423: /** Returns a readonly collection of event names (String),
424: * or an empty collection if no event name is registered.
425: *
426: * <p>To add an event handler, use {@link #addEventHandler} instead.
427: *
428: * @since 3.0.2
429: */
430: public Set getEventHandlerNames() {
431: return _evthds != null ? _evthds.getEventNames()
432: : Collections.EMPTY_SET;
433: }
434:
435: /** Sets the effectiveness condition.
436: */
437: public void setCondition(ConditionImpl cond) {
438: _cond = cond;
439: }
440:
441: /** Returns the forEach object if the forEach attribute is defined
442: * (or {@link #setForEach} is called).
443: *
444: * <p>If comp is not null, both pagedef and page are ignored.
445: * If comp is null, page must be specified.
446: *
447: * @param page the page. It is used only if comp is null.
448: * @param comp the component.
449: * @return the forEach object to iterate this info multiple times,
450: * or null if this info shall be interpreted only once.
451: */
452: public ForEach getForEach(Page page, Component comp) {
453: return _forEach == null ? null : comp != null ? ForEachImpl
454: .getInstance(_evalr, comp, _forEach[0], _forEach[1],
455: _forEach[2]) : ForEachImpl.getInstance(_evalr,
456: page, _forEach[0], _forEach[1], _forEach[2]);
457: }
458:
459: /** Sets the forEach attribute, which is usually an expression.
460: * @param expr the expression to return a collection of objects, or
461: * null/empty to denote no iteration.
462: */
463: public void setForEach(String expr, String begin, String end) {
464: _forEach = expr != null && expr.length() > 0 ? new String[] {
465: expr, begin, end } : null;
466: }
467:
468: /** Returns whether the forEach condition is defined.
469: * @since 3.0.0
470: */
471: public boolean withForEach() {
472: return _forEach != null;
473: }
474:
475: /** Returns the class name (String) that implements the component.
476: */
477: public String getImplementationClass() {
478: return _implcls != null ? _implcls.getRawValue() : null;
479: }
480:
481: /** Sets the class name to implements the component.
482: */
483: public void setImplementationClass(String clsnm) {
484: _implcls = clsnm != null && clsnm.length() > 0 ? new ExValue(
485: clsnm, Object.class) : null;
486: }
487:
488: /** Creates an component based on this info (never null).
489: *
490: * <p>Like {@link ComponentDefinition#newInstance},
491: * this method doesn't invoke {@link #applyProperties}.
492: * It is caller's job to invoke them if necessary.
493: * Since the value of properties might depend on the component tree,
494: * it is better to assign the component with a proper parent
495: * before calling {@link #applyProperties}.
496: *
497: * @since 3.0.2
498: */
499: public Component newInstance(Page page, Component parent) {
500: Object implcls = evalImplClass(page, parent);
501: ComponentsCtrl.setCurrentInfo(this );
502: final Component comp;
503: try {
504: comp = implcls instanceof Class ? _compdef
505: .newInstance((Class) implcls) : _compdef
506: .newInstance(page, (String) implcls);
507: } catch (Exception ex) {
508: throw UiException.Aide.wrap(ex);
509: } finally {
510: ComponentsCtrl.setCurrentInfo((ComponentInfo) null);
511: }
512: if (comp instanceof DynamicTag)
513: ((DynamicTag) comp).setTag(_tag);
514: return comp;
515: }
516:
517: /** Evaluates the implementation claas, and rerturn either a class (Class),
518: * a class name (String), or null.
519: */
520: private Object evalImplClass(Page page, Component parent) {
521: return _implcls == null ? null : parent != null ? _implcls
522: .getValue(_evalr.getEvaluator(), parent) : _implcls
523: .getValue(_evalr.getEvaluator(), page);
524: }
525:
526: /** Creates an component based on this info (never null).
527: * It is the same as newInstance(page, null).
528: *
529: * <p>If the implementation class ({@link #getImplementationClass})
530: * doesn't have any EL expression, or its EL expresson doesn't
531: * referece to the self variable, the result is the same.
532: *
533: * <p>This method is preserved for backward compatibility.
534: * It is better to use {@link #newInstance(Page, Component)}.
535: */
536: public Component newInstance(Page page) {
537: return newInstance(page, null);
538: }
539:
540: /** Resolves and returns the class for the component represented
541: * by this info (never null).
542: *
543: * <p>Unlike {@link #getImplementationClass},
544: * this method will resolve a class name (String) to a class (Class),
545: * if necessary.
546: *
547: * @param page the page to check whether the class is defined
548: * in its interpreters. Ignored if null.
549: * This method will search the class loader of the current thread.
550: * If not found, it will search the interpreters of the specifed
551: * page ({@link Page#getLoadedInterpreters}).
552: * Note: this method won't attach the component to the specified page.
553: * @exception ClassNotFoundException if the class not found
554: * @since 3.0.2
555: */
556: public Class resolveImplementationClass(Page page, Component parent)
557: throws ClassNotFoundException {
558: Object implcls = evalImplClass(page, parent);
559: return implcls instanceof Class ? (Class) implcls : _compdef
560: .resolveImplementationClass(page, (String) implcls);
561: }
562:
563: /** Resolves and returns the class for the component represented
564: * by this info (never null).
565: * It is the same as resolveImplementationClass(page, null).
566: *
567: * <p>If the implementation class ({@link #getImplementationClass})
568: * doesn't have any EL expression, or its EL expresson doesn't
569: * referece to the self variable, the result is the same.
570: *
571: * <p>This method is preserved for backward compatibility.
572: * It is better to use {@link #resolveImplementationClass(Page, Component)}.
573: * @since 3.0.0
574: */
575: public Class resolveImplementationClass(Page page)
576: throws ClassNotFoundException {
577: return resolveImplementationClass(page, null);
578: }
579:
580: /** Returns the annotation map defined in this info, or null
581: * if no annotation is ever defined.
582: */
583: public AnnotationMap getAnnotationMap() {
584: return _annots;
585: }
586:
587: /** Applies the event handlers, annotations, properties and
588: * custom attributes to the specified component.
589: *
590: * <p>It also invokes {@link ComponentDefinition#applyProperties}.
591: *
592: * @since 3.0.0
593: */
594: public void applyProperties(Component comp) {
595: _compdef.applyProperties(comp);
596:
597: if (_evthds != null)
598: ((ComponentCtrl) comp).addSharedEventHandlerMap(_evthds);
599:
600: if (_props != null) {
601: for (Iterator it = _props.iterator(); it.hasNext();) {
602: final Property prop = (Property) it.next();
603: prop.assign(comp);
604: }
605: }
606: }
607:
608: /** Evaluates and retrieves properties to the specified map from
609: * {@link ComponentDefinition} (and {@link ComponentInfo}).
610: *
611: * @param propmap the map to store the retrieved properties
612: * (String name, Object value).
613: * If null, a HashMap instance is created.
614: * @param owner the owner page; used if parent is null
615: * @param parent the parent component (may be null)
616: * @param defIncluded whether to call {@link ComponentDefinition#evalProperties}.
617: */
618: public Map evalProperties(Map propmap, Page owner,
619: Component parent, boolean defIncluded) {
620: if (defIncluded)
621: propmap = _compdef.evalProperties(propmap, owner, parent);
622: else if (propmap == null)
623: propmap = new HashMap();
624:
625: if (_props != null) {
626: for (Iterator it = _props.iterator(); it.hasNext();) {
627: final Property prop = (Property) it.next();
628: if (parent != null) {
629: if (prop.isEffective(parent))
630: propmap.put(prop.getName(), prop
631: .getValue(parent));
632: } else {
633: if (prop.isEffective(owner))
634: propmap.put(prop.getName(), prop
635: .getValue(owner));
636: }
637: }
638: }
639: return propmap;
640: }
641:
642: /** Associates an annotation to this component info.
643: *
644: * @param annotName the annotation name (never null, nor empty).
645: * @param annotAttrs a map of attributes, or null if no attribute at all.
646: * The attribute must be in a pair of strings (String name, String value).
647: */
648: public void addAnnotation(String annotName, Map annotAttrs) {
649: if (_annots == null)
650: _annots = new AnnotationMap();
651: _annots.addAnnotation(annotName, annotAttrs);
652: }
653:
654: /** Adds an annotation to the specified proeprty of this component
655: * info.
656: *
657: * @param propName the property name (never nul, nor empty).
658: * @param annotName the annotation name (never null, nor empty).
659: * @param annotAttrs a map of attributes, or null if no attribute at all.
660: * The attribute must be in a pair of strings (String name, String value).
661: */
662: public void addAnnotation(String propName, String annotName,
663: Map annotAttrs) {
664: if (_annots == null)
665: _annots = new AnnotationMap();
666: _annots.addAnnotation(propName, annotName, annotAttrs);
667: }
668:
669: //Condition//
670: public boolean isEffective(Component comp) {
671: return _cond == null || _cond.isEffective(_evalr, comp);
672: }
673:
674: public boolean isEffective(Page page) {
675: return _cond == null || _cond.isEffective(_evalr, page);
676: }
677:
678: //NodeInfo//
679: public PageDefinition getPageDefinition() {
680: return _evalr.getPageDefinition();
681: }
682:
683: public NodeInfo getParent() {
684: return _parent;
685: }
686:
687: protected EvaluatorRef getEvaluatorRef() {
688: return _evalr;
689: }
690:
691: //Cloneable//
692: /** Clones this info.
693: * After cloned, {@link #getParent} is null.
694: */
695: public Object clone() {
696: try {
697: final ComponentInfo info = (ComponentInfo) super .clone();
698: info._parent = null;
699: if (_annots != null)
700: info._annots = (AnnotationMap) _annots.clone();
701: if (_props != null)
702: info._props = new LinkedList(_props);
703: if (_evthds != null)
704: info._evthds = (EventHandlerMap) _evthds.clone();
705: return info;
706: } catch (CloneNotSupportedException ex) {
707: throw new InternalError();
708: }
709: }
710:
711: //Object//
712: public String toString() {
713: final StringBuffer sb = new StringBuffer(64).append(
714: "[ComponentInfo: ").append(_compdef.getName());
715: if (_tag != null)
716: sb.append(" <").append(_tag).append('>');
717: return sb.append(']').toString();
718: }
719:
720: //Externalizable//
721: public final void writeExternal(java.io.ObjectOutput out)
722: throws java.io.IOException {
723: if (getSerializingEvalRef() != _evalr) {
724: pushSerializingEvalRef(_evalr);
725: try {
726: out.writeObject(_evalr);
727: writeMembers(out);
728: } finally {
729: popSerializingEvalRef();
730: }
731: } else {
732: out.writeObject(null); //to save space, don't need to write evalr
733: writeMembers(out);
734: }
735: }
736:
737: /** Don't override this method. Rather, override {@link #readMembers}.
738: * @since 3.0.0
739: */
740: public final void readExternal(java.io.ObjectInput in)
741: throws java.io.IOException, ClassNotFoundException {
742: _evalr = (EvaluatorRef) in.readObject();
743: final EvaluatorRef top = getSerializingEvalRef();
744: if (_evalr == null)
745: _evalr = top;
746:
747: if (_evalr != null && top != _evalr) {
748: pushSerializingEvalRef(_evalr);
749: try {
750: readMembers(in);
751: } finally {
752: popSerializingEvalRef();
753: }
754: } else {
755: readMembers(in);
756: }
757: }
758:
759: private void writeMembers(java.io.ObjectOutput out)
760: throws java.io.IOException {
761: out.writeObject(_children);
762:
763: final LanguageDefinition langdef = _compdef
764: .getLanguageDefinition();
765: if (langdef != null) {
766: out.writeObject(langdef.getName());
767: out.writeObject(_compdef.getName());
768: } else {
769: out.writeObject(_compdef);
770: }
771:
772: out.writeObject(_implcls);
773: out.writeObject(_props);
774: out.writeObject(_evthds);
775: out.writeObject(_annots);
776: out.writeObject(_tag);
777: out.writeObject(_cond);
778: out.writeObject(_fulfill);
779: out.writeObject(_apply);
780: out.writeObject(_forward);
781: out.writeObject(_forEach);
782: }
783:
784: private void readMembers(java.io.ObjectInput in)
785: throws java.io.IOException, ClassNotFoundException {
786: _children = (List) in.readObject();
787: for (Iterator it = _children.iterator(); it.hasNext();) {
788: final Object o = it.next();
789: if (o instanceof ComponentInfo)
790: ((ComponentInfo) o).setParentDirectly(this );
791: }
792:
793: final Object v = in.readObject();
794: if (v instanceof String) {
795: final LanguageDefinition langdef = LanguageDefinition
796: .lookup((String) v);
797: _compdef = langdef.getComponentDefinition((String) in
798: .readObject());
799: } else {
800: _compdef = (ComponentDefinition) v;
801: }
802:
803: _implcls = (ExValue) in.readObject();
804: _props = (List) in.readObject();
805: _evthds = (EventHandlerMap) in.readObject();
806: _annots = (AnnotationMap) in.readObject();
807: _tag = (String) in.readObject();
808: _cond = (ConditionImpl) in.readObject();
809: _fulfill = (String) in.readObject();
810: _apply = (ExValue) in.readObject();
811: _forward = (String) in.readObject();
812: _forEach = (String[]) in.readObject();
813: }
814:
815: /** Writes the evaluator reference.
816: * It is called by {@link EvalRefStub} to serialize
817: * the evaluator reference, in order to minimize the number of bytes
818: * to serialize.
819: */
820: /*package*/static final void writeEvalRef(
821: java.io.ObjectOutputStream s, EvaluatorRef evalr)
822: throws java.io.IOException {
823: s.writeObject(getSerializingEvalRef() != evalr ? evalr : null);
824: }
825:
826: /*package*/static final EvaluatorRef readEvalRef(
827: java.io.ObjectInputStream s) throws java.io.IOException,
828: ClassNotFoundException {
829: final EvaluatorRef evalr = (EvaluatorRef) s.readObject();
830: return evalr != null ? evalr : getSerializingEvalRef();
831: }
832:
833: /** Returns the evaluator reference of the info that is being serialized.
834: * It is used to minimize the bytes to write when serialized.
835: */
836: private static final EvaluatorRef getSerializingEvalRef() {
837: final List stack = (List) _evalRefStack.get();
838: return stack == null || stack.isEmpty() ? null
839: : (EvaluatorRef) stack.get(0);
840: }
841:
842: /** Pushes the sepcified evaluator referene to be the current one.
843: */
844: private static final void pushSerializingEvalRef(EvaluatorRef evalr) {
845: List stack = (List) _evalRefStack.get();
846: if (stack == null)
847: _evalRefStack.set(stack = new LinkedList());
848: stack.add(0, evalr);
849: }
850:
851: /** Pops out the current evaluator reference.
852: */
853: private static final void popSerializingEvalRef() {
854: ((List) _evalRefStack.get()).remove(0);
855: }
856:
857: private static final ThreadLocal _evalRefStack = new ThreadLocal();
858: }
|