KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > binding > model > TreeContext


1 /*
2 Copyright (c) 2004-2005, Dennis M. Sosnoski
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29 package org.jibx.binding.model;
30
31 import java.util.ArrayList JavaDoc;
32 import java.util.HashSet JavaDoc;
33
34 import org.jibx.binding.util.ObjectStack;
35
36 /**
37  * Tracks the validation state. This includes the current validation phase, as
38  * well as order-dependent state information collected while walking the tree
39  * structure of a binding model.
40  *
41  * @author Dennis M. Sosnoski
42  * @version 1.0
43  */

44  
45 public class TreeContext
46 {
47     /** Global definition context (outside of binding). */
48     private DefinitionContext m_globalContext;
49     
50     /** Binding element model root (may be <code>null</code>, if not configured
51      by caller). */

52     private BindingElement m_bindingRoot;
53     
54     /** Stack of items for parent hierarchy to current node in tree. */
55     private ObjectStack m_treeHierarchy;
56     
57     /** Class locator set by environment code. */
58     private IClassLocator m_locator;
59     
60     /** Set of elements to be skipped in walking tree. */
61     private HashSet JavaDoc m_skipSet;
62     
63     /**
64      * Constructor.
65      */

66     public TreeContext(IClassLocator iloc) {
67         m_locator = iloc;
68         m_treeHierarchy = new ObjectStack();
69         m_skipSet = new HashSet JavaDoc();
70     }
71     
72     /**
73      * Set the global definition context. This context is external to the actual
74      * binding definition, providing defaults that can be overridden by values
75      * set within the actual binding.
76      *
77      * @param dctx global definition context
78      */

79     public void setGlobalDefinitions(DefinitionContext dctx) {
80         m_globalContext = dctx;
81     }
82     
83     /**
84      * Tour complete binding model tree. This tours the entire binding model,
85      * starting from the root binding element. Using this method automatically
86      * sets the root binding element for access by processing performed during
87      * the tour. It <b>must</b> be used for the binding element in order to
88      * handle included binding definitions properly.
89      *
90      * @param root binding element root of tree
91      * @param visitor target visitor for element notifications
92      */

93     public void tourTree(BindingElement root, ModelVisitor visitor) {
94         
95         // set up binding root reference for access during processing
96
BindingElement hold = m_bindingRoot;
97         m_bindingRoot = root;
98         
99         // run the actual tour
100
tourTree((ElementBase)root, visitor);
101         
102         // restore prior binding root reference
103
m_bindingRoot = hold;
104     }
105     
106     /**
107      * Tour binding model tree. This recursively traverses the binding model
108      * tree rooted in the supplied element, notifying the visitor of each
109      * element visited during the traversal. Elements with fatal errors are
110      * skipped in processing, along with all child elements.
111      *
112      * @param root node of tree to be toured
113      * @param visitor target visitor for element notifications
114      */

115     public void tourTree(ElementBase root, ModelVisitor visitor) {
116         
117         // check for fatal error on element
118
if (m_skipSet.contains(root)) {
119             return;
120         }
121         
122         // visit the actual root of tree
123
boolean expand = false;
124         m_treeHierarchy.push(root);
125         switch (root.type()) {
126             
127             case ElementBase.BINDING_ELEMENT:
128                 expand = visitor.visit((BindingElement)root);
129                 break;
130                 
131             case ElementBase.COLLECTION_ELEMENT:
132                 expand = visitor.visit((CollectionElement)root);
133                 break;
134                 
135             case ElementBase.FORMAT_ELEMENT:
136                 visitor.visit((FormatElement)root);
137                 break;
138                 
139             case ElementBase.INCLUDE_ELEMENT:
140                 expand = visitor.visit((IncludeElement)root);
141                 break;
142                 
143             case ElementBase.INPUT_ELEMENT:
144                 expand = visitor.visit((InputElement)root);
145                 break;
146                 
147             case ElementBase.MAPPING_ELEMENT:
148                 expand = visitor.visit((MappingElement)root);
149                 break;
150                 
151             case ElementBase.NAMESPACE_ELEMENT:
152                 visitor.visit((NamespaceElement)root);
153                 break;
154                 
155             case ElementBase.OUTPUT_ELEMENT:
156                 expand = visitor.visit((OutputElement)root);
157                 break;
158                 
159             case ElementBase.SPLIT_ELEMENT:
160                 expand = visitor.visit((SplitElement)root);
161                 break;
162                 
163             case ElementBase.STRUCTURE_ELEMENT:
164                 expand = visitor.visit((StructureElement)root);
165                 break;
166                 
167             case ElementBase.TEMPLATE_ELEMENT:
168                 expand = visitor.visit((TemplateElement)root);
169                 break;
170                 
171             case ElementBase.VALUE_ELEMENT:
172                 visitor.visit((ValueElement)root);
173                 break;
174             
175             default:
176                 throw new IllegalStateException JavaDoc
177                     ("Internal error: unknown element type");
178                 
179         }
180         
181         // check for expansion needed
182
if (expand && !m_skipSet.contains(root)) {
183             if (root instanceof IncludeElement) {
184                 
185                 // include just delegates to the included binding element
186
BindingElement binding = ((IncludeElement)root).getBinding();
187                 if (binding != null) {
188                     m_treeHierarchy.pop();
189                     tourTree((ElementBase)binding, visitor);
190                     m_treeHierarchy.push(root);
191                 }
192                 
193             } else if (root instanceof NestingElementBase) {
194                 
195                 // process each container child as root of own tree
196
ArrayList JavaDoc childs = null;
197                 if (root instanceof MappingElement) {
198                     childs = ((MappingElement)root).topChildren();
199                     for (int i = 0; i < childs.size(); i++) {
200                         tourTree((ElementBase)childs.get(i), visitor);
201                     }
202                 }
203                 if (root instanceof BindingElement) {
204                     childs = ((BindingElement)root).topChildren();
205                 } else {
206                     childs = ((NestingElementBase)root).children();
207                 }
208                 for (int i = 0; i < childs.size(); i++) {
209                     tourTree((ElementBase)childs.get(i), visitor);
210                 }
211             }
212         }
213         
214         // exit the actual root of tree
215
switch (root.type()) {
216             
217             case ElementBase.BINDING_ELEMENT:
218                 visitor.exit((BindingElement)root);
219                 break;
220                 
221             case ElementBase.COLLECTION_ELEMENT:
222                 visitor.exit((CollectionElement)root);
223                 break;
224                 
225             case ElementBase.INCLUDE_ELEMENT:
226                 visitor.exit((IncludeElement)root);
227                 break;
228                 
229             case ElementBase.INPUT_ELEMENT:
230                 visitor.exit((InputElement)root);
231                 break;
232                 
233             case ElementBase.MAPPING_ELEMENT:
234                 visitor.exit((MappingElement)root);
235                 break;
236                 
237             case ElementBase.OUTPUT_ELEMENT:
238                 visitor.exit((OutputElement)root);
239                 break;
240                 
241             case ElementBase.SPLIT_ELEMENT:
242                 visitor.exit((SplitElement)root);
243                 break;
244                 
245             case ElementBase.STRUCTURE_ELEMENT:
246                 visitor.exit((StructureElement)root);
247                 break;
248                 
249             case ElementBase.TEMPLATE_ELEMENT:
250                 visitor.exit((TemplateElement)root);
251                 break;
252                 
253             case ElementBase.VALUE_ELEMENT:
254                 visitor.exit((ValueElement)root);
255                 break;
256             
257             default:
258                 break;
259                 
260         }
261         m_treeHierarchy.pop();
262     }
263     
264     /**
265      * Get depth of nesting in binding.
266      *
267      * @return nesting depth
268      */

269     public int getNestingDepth() {
270         return m_treeHierarchy.size();
271     }
272     
273     /**
274      * Peek current element of hierarchy.
275      */

276     protected ElementBase peekElement() {
277         return (ElementBase)m_treeHierarchy.peek();
278     }
279     
280     /**
281      * Check if a component is being skipped due to a fatal error.
282      *
283      * @param obj component to be checked
284      * @return flag for component being skipped
285      */

286     public boolean isSkipped(Object JavaDoc obj) {
287         return m_skipSet.contains(obj);
288     }
289     
290     /**
291      * Add element to set to be skipped.
292      *
293      * @param skip
294      */

295     protected void addSkip(Object JavaDoc skip) {
296         if (skip instanceof ElementBase) {
297             m_skipSet.add(skip);
298         }
299     }
300     
301     /**
302      * Get root element of binding.
303      *
304      * @return root element of binding
305      * @throws IllegalStateException if no root element known
306      */

307     public BindingElement getBindingRoot() {
308         if (m_bindingRoot == null) {
309             throw new IllegalStateException JavaDoc("No binding root defined");
310         } else {
311             return m_bindingRoot;
312         }
313     }
314     
315     /**
316      * Set root element of binding. This should be called by the user if an
317      * element other than the binding element is going to be used as the root
318      * for a tour.
319      *
320      * @param root root element of binding
321      */

322     public void setBindingRoot(BindingElement root) {
323         m_bindingRoot = root;
324     }
325     
326     /**
327      * Get containing element. This is equivalent to the generation
328      * <code>1</code> parent, except that it checks for the case where there's
329      * no parent present.
330      *
331      * @return binding definition component for parent element, or
332      * <code>null</code> if no parent
333      */

334     public NestingElementBase getParentElement() {
335         if (m_treeHierarchy.size() > 1) {
336             return (NestingElementBase)m_treeHierarchy.peek(1);
337         } else {
338             return null;
339         }
340     }
341     
342     /**
343      * Get containing element at generation level. All except the zero-level
344      * containing element are guaranteed to be instances of {@link
345      * org.jibx.binding.model.NestingElementBase}.
346      *
347      * @param level generation level of parent
348      * @return binding definition component for parent at level
349      */

350     public ElementBase getParentElement(int level) {
351         return (ElementBase)m_treeHierarchy.peek(level);
352     }
353     
354     /**
355      * Get parent container information. This returns the innermost containing
356      * binding component which refers to an object.
357      *
358      * @return innermost containing element referencing bound object
359      */

360     public ContainerElementBase getParentContainer() {
361         int index = 1;
362         while (index < m_treeHierarchy.size()) {
363             NestingElementBase nest =
364                 (NestingElementBase)m_treeHierarchy.peek(index++);
365             if (nest instanceof ContainerElementBase) {
366                 return (ContainerElementBase)nest;
367             }
368         }
369         throw new IllegalStateException JavaDoc("Internal error: no container");
370     }
371     
372     /**
373      * Get parent container with linked object. This returns the innermost
374      * containing binding component which defines a context object.
375      *
376      * @return innermost containing element defining a context object
377      */

378     public ContainerElementBase getContextObject() {
379         int index = 1;
380         while (index < m_treeHierarchy.size()) {
381             NestingElementBase nest =
382                 (NestingElementBase)m_treeHierarchy.peek(index++);
383             if (nest instanceof ContainerElementBase) {
384                 ContainerElementBase contain = (ContainerElementBase)nest;
385                 if (contain.getActualType() != null) {
386                     return contain;
387                 }
388             }
389         }
390         throw new IllegalStateException JavaDoc("Internal error: no context object");
391     }
392     
393     /**
394      * Check if binding supports input.
395      *
396      * @return <code>true</code> if input binding, <code>false</code> if not
397      */

398     public boolean isInBinding() {
399         return m_bindingRoot == null ? true : m_bindingRoot.isInBinding();
400     }
401     
402     /**
403      * Check if binding supports output.
404      *
405      * @return <code>true</code> if output binding, <code>false</code> if not
406      */

407     public boolean isOutBinding() {
408         return m_bindingRoot == null ? true : m_bindingRoot.isOutBinding();
409     }
410     
411     /**
412      * Get innermost containing definition context.
413      *
414      * @return innermost definition context containing this element
415      */

416     public DefinitionContext getDefinitions() {
417         int index = 1;
418         while (index < m_treeHierarchy.size()) {
419             NestingElementBase nest =
420                 (NestingElementBase)m_treeHierarchy.peek(index++);
421             if (nest.getDefinitions() != null) {
422                 return nest.getDefinitions();
423             }
424         }
425         if (m_globalContext == null) {
426             throw new IllegalStateException JavaDoc
427                 ("Internal error: no definition context");
428         } else {
429             return m_globalContext;
430         }
431     }
432     
433     /**
434      * Get definition context for innermost nesting element. If the context for
435      * this element isn't already defined it's created by the call.
436      *
437      * @return definition context for innermost nesting element
438      */

439     public DefinitionContext getCurrentDefinitions() {
440         NestingElementBase parent = getParentElement();
441         DefinitionContext dctx = parent.getDefinitions();
442         if (dctx == null) {
443             dctx = new DefinitionContext(getDefinitions());
444             parent.setDefinitions(dctx);
445         }
446         return dctx;
447     }
448     
449     /**
450      * Get definition context for innermost nesting element for use by a
451      * <b>format</b>. If the context for this element isn't already defined it's
452      * created by the call, along with the contexts for any containing elements.
453      * This is ugly, but necessary to keep the tree structure of contexts from
454      * getting split when other items are added by the registration pass (since
455      * the formats are registered in the prevalidation pass).
456      *
457      * @return definition context for innermost nesting element
458      */

459     public DefinitionContext getFormatDefinitions() {
460         NestingElementBase parent = getParentElement();
461         DefinitionContext dctx = parent.getDefinitions();
462         if (dctx == null) {
463             
464             // scan to find innermost nesting with context
465
int index = 1;
466             DefinitionContext pctx = null;
467             while (++index < m_treeHierarchy.size()) {
468                 NestingElementBase nest =
469                     (NestingElementBase)m_treeHierarchy.peek(index);
470                 pctx = nest.getDefinitions();
471                 if (pctx != null) {
472                     break;
473                 }
474             }
475             
476             // add contexts for all ancestors to level
477
while (index >= 2) {
478                 dctx = new DefinitionContext(pctx);
479                 NestingElementBase nest =
480                     (NestingElementBase)m_treeHierarchy.peek(--index);
481                 nest.setDefinitions(dctx);
482                 pctx = dctx;
483             }
484         }
485         return dctx;
486     }
487     
488     /**
489      * Get class information. Finds a class by name using the class locator
490      * configured by the environment code.
491      *
492      * @param name fully-qualified name of class to be found
493      * @return class information, or <code>null</code> if class not found
494      */

495     public IClass getClassInfo(String JavaDoc name) {
496         return m_locator.getClassInfo(name);
497     }
498     
499     /**
500      * Get requiried class information. Finds a class by name using the class
501      * locator configured by the environment code. If the class cannot be found
502      * a runtime exception is thrown.
503      *
504      * @param name fully-qualified name of class to be found
505      * @return class information
506      */

507     public IClass getRequiredClassInfo(String JavaDoc name) {
508         IClass iclas = m_locator.getClassInfo(name);
509         if (iclas == null) {
510             throw new IllegalStateException JavaDoc("Internal error: class " + name +
511                 " cannot be found");
512         } else {
513             return iclas;
514         }
515     }
516 }
Popular Tags