~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to schema2beans/rt/src/org/netbeans/modules/schema2beans/DDRegistryParser.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
 
 
42
package org.netbeans.modules.schema2beans;
 
43
 
 
44
import java.util.*;
 
45
 
 
46
 
 
47
/**
 
48
 *  The DDRegistryParser is a parser/Iterator on a set of graphs, as
 
49
 *  registered in the schema2beans registry (DDRegistry).
 
50
 *
 
51
 *  DDParser is a parser/Iterator on a single schema2beans graph, using
 
52
 *  a schema2beans path description to define what should be parsed.
 
53
 *  DDRegistryParser extend the functiionality of DDParser by providing
 
54
 *  a parsing mechanism on a set of graphs (instead of a single one) and
 
55
 *  by adding more syntax to the DDParser schema2beans path syntax.
 
56
 *
 
57
 *  Where DDParser defined a DDLocation to define a location reference in
 
58
 *  the parsed graph, DDRegistryParser defines a DDCursor. The DDCursor
 
59
 *  defines a location on a set of graphs (a DDCursor might have a parent
 
60
 *  root defined in another graph).
 
61
 *
 
62
 *  The DDRegistryParser instances are created by the DDRegistry.
 
63
 */
 
64
public class DDRegistryParser implements Iterator {
 
65
    
 
66
    static final String CURRENT_CURSOR = ".";   // NOI18N
 
67
    
 
68
    /**
 
69
     *  Analyze and resolve the vriable references specified in the path
 
70
     */
 
71
    static public class PathResolver {
 
72
        
 
73
        static final char VARBEGIN              = '{';
 
74
        static final char VAREND                = '}';
 
75
        static final char VALUE                 = '#';
 
76
        
 
77
        //  Current module (display/non unique) name
 
78
        static final String VAR_MODNAME = "mname";      // NOI18N
 
79
        
 
80
        //  Current module unique name
 
81
        static final String VAR_UNAME   = "uname";      // NOI18N
 
82
        
 
83
        //  Parent schema2beans type of the specified type {#ptype.EnvEntry}
 
84
        //  would be either Session or Entity.
 
85
        static final String VAR_PTYPE   = "ptype";      // NOI18N
 
86
        
 
87
        static final String VAR_TYPE    = "type";       // NOI18N
 
88
        
 
89
        
 
90
        String result = null;
 
91
 
 
92
        //
 
93
        public PathResolver() {
 
94
        }
 
95
        
 
96
        //
 
97
        public PathResolver(DDCursor cursor, String path) {
 
98
            this.result = this.resolvePath(cursor, path);
 
99
        }
 
100
        
 
101
        
 
102
        static boolean needResolving(String path) {
 
103
            if (path != null)
 
104
                return (path.indexOf(VARBEGIN) != -1);
 
105
            else
 
106
                return false;
 
107
        }
 
108
        
 
109
        /**
 
110
         *  This resolve all the variables referenced in the path string
 
111
         *  using the knowledge of its current location. A variable is
 
112
         *  defined with braces {}, and might use any of the values:
 
113
         *
 
114
         *      #mname, #uname, #ptype, #type
 
115
         *
 
116
         *  or any reference to a property of the current graph:
 
117
         *
 
118
         *     {NodeName}   // no # in this case
 
119
         *
 
120
         */
 
121
        String resolvePath(DDCursor cur, String path) {
 
122
            if(path.indexOf(VARBEGIN) != -1) {
 
123
                int i1 = path.indexOf(VARBEGIN);
 
124
                int i2 = path.indexOf(VAREND);
 
125
                String v =
 
126
                (String)this.resolvePathVar(cur, path.substring(i1+1, i2));
 
127
                return path.substring(0, i1).trim() + v +
 
128
                this.resolvePath(cur, path.substring(i2+1));
 
129
            }
 
130
            return path.trim();
 
131
        }
 
132
        
 
133
        Object resolvePathVar(DDCursor cur, String path) {
 
134
            //path = path.trim();
 
135
            
 
136
            if (path.indexOf(VARBEGIN) != -1 || path.indexOf(VAREND) != -1) {
 
137
                throw new IllegalArgumentException(Common.getMessage(
 
138
                "CannotNestDeclaration_msg"));
 
139
            }
 
140
            
 
141
            if (path.indexOf('#') == 0 ) {
 
142
                path = path.substring(1, path.length());
 
143
                
 
144
                String remSuffix = null;
 
145
                int idx = path.indexOf('-');
 
146
                if (idx != -1) {
 
147
                    //  Might have to remove a suffix from the value
 
148
                    remSuffix = path.substring(idx+1);
 
149
                    path = path.substring(0, idx);
 
150
                }
 
151
                
 
152
                if (path.startsWith(VAR_MODNAME)) {
 
153
                    int in = path.indexOf(':');
 
154
                    if (in != -1) {
 
155
                        String name = path.substring(in+1);
 
156
                        path = this.getDDNameValue(cur, name).toString();;
 
157
                        path = cur.getRegistry().getName(path);
 
158
                    } else {
 
159
                        path = cur.getRegistry().getName(cur);
 
160
                    }
 
161
                } else
 
162
                    if (path.startsWith(VAR_UNAME)) {
 
163
                        path = cur.getRegistry().getID(cur);
 
164
                    } else
 
165
                        if (path.startsWith(VAR_PTYPE)) {
 
166
                            int i = path.indexOf('.');
 
167
                            if (i != -1) {
 
168
                                String t = path.substring(i+1);
 
169
                                DDCursor pc = cur;
 
170
                                BaseBean bean;
 
171
                                do {
 
172
                                    bean = this.getBean(pc.getRoot(), t);
 
173
                                    if (bean == null) {
 
174
                                        pc = pc.getParent();
 
175
                                    }
 
176
                                } while(bean == null && pc != null);
 
177
                                
 
178
                                if (bean != null) {
 
179
                                    path = bean.parent().name();
 
180
                                }
 
181
                            }
 
182
                        } else
 
183
                            if (path.startsWith(VAR_TYPE)) {
 
184
                                path = cur.getRoot().name();
 
185
                            }
 
186
                
 
187
                if (remSuffix != null) {
 
188
                    if (path.endsWith(remSuffix)) {
 
189
                        path = path.substring(0, path.length() -
 
190
                        remSuffix.length());
 
191
                    }
 
192
                }
 
193
                
 
194
                return path;
 
195
            } else {
 
196
                return this.getDDNameValue(cur, path);
 
197
            }
 
198
        }
 
199
        
 
200
        private Object getDDNameValue(DDCursor pc, String path) {
 
201
            Object val = null;
 
202
            
 
203
            //  Look for the value in the DDCursors and current graph
 
204
            //  hierarchy (look first in the graph then in other DDCursors)
 
205
            do {
 
206
                val = this.getValue(pc.getRoot(), path);
 
207
                if (val == null) {
 
208
                    pc = pc.getParent();
 
209
                }
 
210
            } while(val == null && pc != null);
 
211
            return val;
 
212
        }
 
213
        
 
214
        BaseBean getBean(BaseBean root, String name) {
 
215
            while (root != null && !root.isRoot()) {
 
216
                if (root.hasName(name))
 
217
                    return root;
 
218
                root = root.parent();
 
219
            }
 
220
            return null;
 
221
        }
 
222
        
 
223
        String getValue(BaseBean root, String name) {
 
224
            String val = null;
 
225
            if (root != null) {
 
226
                do {
 
227
                    try {
 
228
                        val = (String)root.getValue(name);
 
229
                        break;
 
230
                    } catch(Exception e) {
 
231
                        // Unknown property name - ignore it
 
232
                    }
 
233
                    root = root.parent();
 
234
                } while (root != null && !root.isRoot());
 
235
            }
 
236
            return val;
 
237
        }
 
238
        
 
239
        public String toString() {
 
240
            return this.result;
 
241
        }
 
242
    }
 
243
 
 
244
    /**
 
245
     *  DDCursor is a location reference in one of the DDRegistry graphs.
 
246
     *  Note that DDCursor can be created in two different ways: from a schema2beans
 
247
     *  path or from a schema2beans node (BaseBean).
 
248
     */
 
249
    static public class DDCursor {
 
250
        DDCursor        parent;
 
251
        BaseBean        root;
 
252
        DDRegistry      registry;
 
253
        
 
254
        public DDCursor(DDCursor parent, String path) {
 
255
            this(parent, (BaseBean)null);
 
256
            this.resolve(path);
 
257
        }
 
258
        
 
259
        public DDCursor(DDCursor parent, BaseBean root) {
 
260
            this.parent = parent;
 
261
            this.root = root;
 
262
            if (this.registry == null && parent != null)
 
263
                this.registry = parent.registry;
 
264
        }
 
265
        
 
266
        public DDCursor(DDRegistry reg, String path) {
 
267
            this.parent = null;
 
268
            this.root = null;
 
269
            this.registry = reg;
 
270
            this.resolve(path);
 
271
        }
 
272
        
 
273
        public DDCursor(DDRegistry reg, BaseBean root) {
 
274
            this.parent = null;
 
275
            this.root = root;
 
276
            this.registry = reg;
 
277
        }
 
278
        
 
279
        public DDRegistry getRegistry() {
 
280
            return this.registry;
 
281
        }
 
282
        
 
283
        public BaseBean getRoot() {
 
284
            return this.root;
 
285
        }
 
286
        
 
287
        public DDCursor getParent() {
 
288
            return this.parent;
 
289
        }
 
290
        
 
291
        public Object getValue(String name) {
 
292
            if (root != null)
 
293
                return this.root.getValue(name);
 
294
            else
 
295
                return null;
 
296
        }
 
297
        
 
298
        void resolve(String path) {
 
299
            
 
300
            if (path == null) return;
 
301
            path = path.trim();
 
302
            if (path.equals("")) return;        // NOI18N
 
303
            
 
304
            if (path.startsWith("[") && path.endsWith("]")) {   // NOI18N
 
305
                this.resolveGraph(path.substring(1,path.length()-1));
 
306
                return;
 
307
            }
 
308
            
 
309
            //  Find the proper root
 
310
            if (this.parent == null) {
 
311
                throw new IllegalStateException(Common.getMessage(
 
312
                "CantResolveBecauseMissingParent_msg", path));
 
313
            }
 
314
            
 
315
            //  Resolve any embeded {} variables
 
316
            if (PathResolver.needResolving(path))
 
317
                path = (new PathResolver(this.parent, path)).toString();
 
318
            
 
319
            BaseBean root = this.parent.getRoot();
 
320
            
 
321
            if (root != null) {
 
322
                DDParser p = new DDParser(root, path);
 
323
                if (p.hasNext()) {
 
324
                    Object o = p.next();
 
325
                    if (o instanceof BaseBean) {
 
326
                        this.root = (BaseBean)o;
 
327
                    } else {
 
328
                        throw new IllegalStateException(
 
329
                        Common.getMessage(
 
330
                        "ParsingPathDoesntResolveToGraphNodeElement_msg",
 
331
                        path, o.getClass().getName(), o.toString()));
 
332
                    }
 
333
                } else {
 
334
                    throw new IllegalStateException(Common.getMessage(
 
335
                    "NoElementFoundPath_msg", path));
 
336
                }
 
337
            } else {
 
338
                throw new IllegalStateException(Common.getMessage(
 
339
                "NoRootFoundForPath_msg", path));
 
340
            }
 
341
        }
 
342
        
 
343
        void resolveGraph(String path) {
 
344
            String pathRoot = null;
 
345
            
 
346
            if (PathResolver.needResolving(path))
 
347
                path = (new PathResolver(this.parent, path)).toString();
 
348
            
 
349
            int idx = path.indexOf(':');
 
350
            if (idx != -1) {
 
351
                pathRoot = path.substring(idx+1);
 
352
                path = path.substring(0, idx);
 
353
            }
 
354
            
 
355
            BaseBean[] beans = this.registry.getRoots(path);
 
356
 
 
357
            if (beans.length > 0) {
 
358
                this.root = beans[0];
 
359
                if (pathRoot != null) {
 
360
                    DDCursor cur = new DDRegistryParser.DDCursor(this,
 
361
                                                                 pathRoot);
 
362
                    this.root = cur.getRoot();
 
363
                }
 
364
            }
 
365
        }
 
366
        
 
367
        public String toString() {
 
368
            String p, r;
 
369
            
 
370
            if (this.parent != null)
 
371
                p = this.parent.toString();
 
372
            else
 
373
                p = "-";        // NOI18N
 
374
            
 
375
            if (this.root != null)
 
376
                r = root.name();
 
377
            else
 
378
                r = "-";        // NOI18N
 
379
            return "Parent:"+p+" Root:"+r;      // NOI18N
 
380
        }
 
381
        
 
382
        public String dump() {
 
383
            if (this.root != null)
 
384
                return this.root.dumpBeanNode();
 
385
            else
 
386
                return "<null graph>";  // NOI18N
 
387
        }
 
388
    }
 
389
    
 
390
    
 
391
    DDRegistry          registry;
 
392
    
 
393
    //
 
394
    //  The root of the parsing can be defined by:
 
395
    //          - a parent parser
 
396
    //          - a parent cursor
 
397
    //          - a graph reference in the scope definition: [graph_name]
 
398
    //
 
399
    DDRegistryParser    parentParser = null;
 
400
    DDCursor            parentCursor = null;
 
401
    DDRegistryParser    parserRoot = null;
 
402
    
 
403
    ParserSet           parser = null;
 
404
    
 
405
    public DDRegistryParser(DDRegistry reg, DDRegistryParser rp,
 
406
                            String path) {
 
407
        this.registry = reg;
 
408
        this.initialize(path, rp, null);
 
409
    }
 
410
    
 
411
    public DDRegistryParser(DDRegistry reg, DDCursor cursor,
 
412
                            String path) {
 
413
        this.registry = reg;
 
414
        this.initialize(path, null, cursor);
 
415
    }
 
416
    
 
417
    public DDRegistryParser(DDRegistry reg, String path) {
 
418
        this.registry = reg;
 
419
        this.initialize(path, null, null);
 
420
    }
 
421
    
 
422
    public DDRegistry getRegistry() {
 
423
        return this.registry;
 
424
    }
 
425
    
 
426
    /**
 
427
     *  Initialize the parser. Either the parser or cursor is set, not both.
 
428
     */
 
429
    void initialize(String path, DDRegistryParser regParser, DDCursor cursor) {
 
430
        String graphName = null;
 
431
        String subpath = null;
 
432
        String parsingPath = null;
 
433
        
 
434
        //
 
435
        //      A scope ([NAME]) refers to a graph or set of graphs in the
 
436
        //      registry. In such case, the scope is the root of the parser
 
437
        //      (and parserRoot = null) since we'll get our root beans from the
 
438
        //      scope and not from the parent parser or cursor 
 
439
        //      (if any specified).
 
440
        //
 
441
        //path = path.trim();   
 
442
        
 
443
        DDCursor cur = cursor;
 
444
        if (cur == null && regParser != null)
 
445
            cur = regParser.getCursor();
 
446
        
 
447
        if (path.startsWith("[")) { // NOI18N
 
448
            int idx = path.indexOf(']');
 
449
            graphName = path.substring(1, idx);
 
450
            
 
451
            if (path.length() > idx+1)
 
452
                path = path.substring(idx+1, path.length());
 
453
            else
 
454
                path = ".";     // NOI18N
 
455
            
 
456
            idx = graphName.indexOf(':');
 
457
            if (idx != -1) {
 
458
                subpath = graphName.substring(idx+1, graphName.length()-1);
 
459
                graphName = graphName.substring(0, idx);
 
460
 
 
461
                if (PathResolver.needResolving(subpath))
 
462
                    subpath = (new PathResolver(cur, subpath)).toString();
 
463
            }
 
464
            
 
465
            if (PathResolver.needResolving(graphName))
 
466
                graphName = (new PathResolver(cur, graphName)).toString();
 
467
            
 
468
            if (graphName.equals(CURRENT_CURSOR) && cursor != null)
 
469
                graphName = null;
 
470
        }
 
471
        
 
472
        if (PathResolver.needResolving(path))
 
473
            parsingPath = (new PathResolver(cur, path)).toString();
 
474
        else
 
475
            parsingPath = path;
 
476
        
 
477
        
 
478
        if (graphName == null && regParser == null && cursor == null) {
 
479
            throw new IllegalStateException(Common.getMessage(
 
480
            "CantFindRootForParser_msg"));
 
481
        }
 
482
        
 
483
        //
 
484
        //      We know that we have a parent root - if the graphName 
 
485
        //      is specified, then we get the root from the registry
 
486
        //
 
487
        if (graphName != null) {
 
488
            
 
489
            //
 
490
            //  The parser is initialized with an absolute graph
 
491
            //  name reference, such as [ejbmodule]
 
492
            //  That means that we get 1-n BaseBean(s) from the registry
 
493
            //  that we use as the root of the parsing.
 
494
            //
 
495
            BaseBean[] beans = this.registry.getRoots(graphName);
 
496
            this.parser = new ParserSet(beans, null, parsingPath);
 
497
            this.parser.setRoot();
 
498
        } else if (regParser != null) {
 
499
            
 
500
            //
 
501
            //  The parser is initialized from another parser. That means
 
502
            //  that the current position of the other parser is used
 
503
            //  as the root of this new parser. However, we need to consider
 
504
            //  two cases: 1. the other parser has defined a set of roots
 
505
            //  (previous case when the parser is initialized with []),
 
506
            //  2. the other parser has only one root.
 
507
            //  If the other parser was initialized as a set of roots,
 
508
            //  we need to get all of them to initialize this parser (or
 
509
            //  we'll miss the 2-n graphs in the parsing).
 
510
            //
 
511
            if (regParser.isRoot() && regParser.getRoots().length > 1) {
 
512
                BaseBean[] beans = regParser.getRoots();
 
513
                
 
514
                //      If the other parser has a parsingPath, we need to
 
515
                //      get the beans using this parsingPath
 
516
                if (regParser.hasParsingPath()) {
 
517
                    String pp = regParser.getParsingPath();
 
518
                    ArrayList tmpArr = new ArrayList();
 
519
                    
 
520
                    for (int i=0; i<beans.length; i++) {
 
521
                        DDParser tmp = new DDParser(beans[i], pp);
 
522
                        if (tmp.hasNext())
 
523
                            tmpArr.add(tmp.next());
 
524
                    }
 
525
                    BaseBean[] newBeans = new BaseBean[tmpArr.size()];
 
526
                    beans = (BaseBean[])tmpArr.toArray(newBeans);
 
527
                }
 
528
                
 
529
                this.parser = new ParserSet(beans, null, parsingPath);
 
530
            } else {
 
531
                while (regParser.current() == null && regParser.hasNext())
 
532
                    regParser.next();
 
533
                
 
534
                this.parser = new ParserSet((BaseBean)regParser.current(), cur,
 
535
                                            parsingPath);
 
536
                
 
537
            }
 
538
            
 
539
        } else if (cursor != null) {
 
540
            //
 
541
            //  The parser is initialized from a DDCursor position.
 
542
            //
 
543
            this.parser = new ParserSet(cursor.getRoot(), cur, parsingPath);
 
544
        } else {
 
545
            throw new IllegalStateException( Common.getMessage(
 
546
            "NoParentSpecified_msg"));
 
547
        }
 
548
    }
 
549
    
 
550
    
 
551
    boolean isRoot() {
 
552
        return this.parser.isRoot();
 
553
    }
 
554
    
 
555
    boolean hasParsingPath() {
 
556
        return this.parser.hasParsingPath();
 
557
    }
 
558
    
 
559
    String getParsingPath() {
 
560
        return this.parser.getParsingPath();
 
561
    }
 
562
    
 
563
    BaseBean[] getRoots() {
 
564
        return this.parser.getRoots();
 
565
    }
 
566
    
 
567
    //  Reset the current ParsetSet to use the next available root from the
 
568
    //  parent.
 
569
    public Object next() {
 
570
        return this.parser.next();
 
571
    }
 
572
    
 
573
    public boolean hasNext() {
 
574
        return this.parser.hasNext();
 
575
    }
 
576
    
 
577
    public DDCursor getCursor() {
 
578
        Object o = this.current();
 
579
        
 
580
        if (o instanceof BaseBean) {
 
581
            BaseBean b = (BaseBean)o;
 
582
            if (b == null && this.hasNext())
 
583
                b = (BaseBean)this.next();
 
584
            if (b != null)
 
585
                return new DDCursor(this.registry, b);
 
586
        } else {
 
587
            //  Return our parent cursor or build a new one
 
588
            DDCursor cur = this.parser.getParentCursor();
 
589
            if (cur == null) {
 
590
                BaseBean[] beans = this.parser.getRoots();
 
591
                cur = new DDCursor(this.registry, beans[0]);
 
592
            }
 
593
            return cur;
 
594
        }
 
595
        return null;
 
596
    }
 
597
    
 
598
    public DDParser.DDLocation getLocation() {
 
599
        return this.parser.getLocation();
 
600
    }
 
601
    
 
602
    public Object current() {
 
603
        return this.parser.current();
 
604
    }
 
605
    
 
606
    public void remove() {
 
607
        throw new UnsupportedOperationException();
 
608
    }
 
609
    
 
610
    public Object getValue(String ddName) {
 
611
        BaseBean b = (BaseBean)this.current();
 
612
        if (b == null && this.hasNext())
 
613
            b = (BaseBean)this.next();
 
614
        
 
615
        if (b != null) {
 
616
            //  This will seach for the ddName element in the current
 
617
            //  graph and will also search in the ParentCursor graph
 
618
            //  if the element is not found
 
619
            DDCursor cur = new DDCursor(this.parser.getParentCursor(), b);
 
620
            PathResolver p = new PathResolver();
 
621
            Object obj = p.resolvePathVar(cur, ddName);
 
622
            return obj;
 
623
        }
 
624
        
 
625
        return null;
 
626
    }
 
627
    
 
628
    
 
629
    /**
 
630
     *  ParserSet handle the parsing of a set of graph through the usage
 
631
     *  of DDParser. DDRegistryParser delegates the multi-graph parsing to
 
632
     *  this inner class.
 
633
     */
 
634
    class ParserSet {
 
635
        private BaseBean[]      roots;
 
636
        private int             cur;
 
637
        private String          parsingPath;
 
638
        private DDParser        curParser;
 
639
        private boolean         isRoot;
 
640
        private DDCursor        parentCursor;
 
641
        
 
642
        ParserSet(BaseBean[] roots, DDCursor cur, String path) {
 
643
            if (roots != null && roots.length > 0 && roots[0] != null) {
 
644
                this.cur = 0;
 
645
                this.isRoot = false;
 
646
                this.roots = roots;
 
647
                this.parsingPath = path;
 
648
                this.parentCursor = cur;
 
649
                this.adjustPathRoot();
 
650
                this.newParser();
 
651
            } else {
 
652
                throw new IllegalArgumentException(Common.getMessage(
 
653
                "NoRootSpecified_msg", path));
 
654
            }
 
655
        }
 
656
        
 
657
        ParserSet(BaseBean root, DDCursor cur, String path) {
 
658
            this(new BaseBean[] {root}, cur, path);
 
659
        }
 
660
        
 
661
        void adjustPathRoot() {
 
662
            if (this.parsingPath.startsWith("../")) {   // NOI18N
 
663
                int i = this.parsingPath.lastIndexOf("../");    // NOI18N
 
664
                int n = i/3;
 
665
                do {
 
666
                    for (int j=0; j<this.roots.length; j++) {
 
667
                        if (this.roots[j].isRoot())
 
668
                            throw new Schema2BeansRuntimeException(Common.getMessage(
 
669
                            "CantAccessBaseBeanNode_msg", this.parsingPath));
 
670
                        this.roots[j] = this.roots[j].parent();
 
671
                    }
 
672
                } while(n-- > 0);
 
673
                this.parsingPath = this.parsingPath.substring(i+3);
 
674
            }
 
675
        }
 
676
        
 
677
        BaseBean[] getRoots() {
 
678
            return this.roots;
 
679
        }
 
680
        
 
681
        DDCursor getParentCursor() {
 
682
            return this.parentCursor;
 
683
        }
 
684
        
 
685
        void setRoot() {
 
686
            this.isRoot = true;
 
687
        }
 
688
        
 
689
        boolean isRoot() {
 
690
            return this.isRoot;
 
691
        }
 
692
        
 
693
        boolean hasParsingPath() {
 
694
            if (this.parsingPath != null)
 
695
                return !this.parsingPath.equals(".");   // NOI18N
 
696
            else
 
697
                return false;
 
698
        }
 
699
        
 
700
        String getParsingPath() {
 
701
            return this.parsingPath;
 
702
        }
 
703
        
 
704
        private boolean newParser() {
 
705
            if (this.cur < this.roots.length) {
 
706
                try {
 
707
                    this.curParser =
 
708
                        new DDParser(this.roots[this.cur++], this.parsingPath);
 
709
                    return true;
 
710
                } catch(NoSuchElementException e) {
 
711
                    //  If the element is not found, try with our parent root,
 
712
                    //  this might be a linked graph.
 
713
                    if(this.parentCursor != null) {
 
714
                        this.cur = 0;
 
715
                        this.roots =
 
716
                            new BaseBean[] {this.parentCursor.getRoot()};
 
717
                        this.parentCursor = this.parentCursor.getParent();
 
718
                        return this.newParser();
 
719
                    }
 
720
                    else
 
721
                        throw e;
 
722
                }
 
723
            }
 
724
            return false;
 
725
        }
 
726
        
 
727
        //
 
728
        boolean hasNext() {
 
729
            boolean more = this.curParser.hasNext();
 
730
            
 
731
            while (!more && this.newParser())
 
732
                more = this.curParser.hasNext();
 
733
            
 
734
            return more;
 
735
        }
 
736
        
 
737
        DDParser.DDLocation getLocation() {
 
738
            return this.curParser.getLocation();
 
739
        }
 
740
        
 
741
        //      Return what the parser has currently
 
742
        Object current() {
 
743
            return this.curParser.current();
 
744
        }
 
745
        
 
746
        //      Get the next element available from our set of parsers
 
747
        Object next() {
 
748
            if (this.hasNext()) {
 
749
                return this.curParser.next();
 
750
            } else {
 
751
                throw new NoSuchElementException();
 
752
            }
 
753
        }
 
754
    }
 
755
}