KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > schema2beans > DDParser


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.schema2beans;
21
22 import java.util.*;
23 import java.io.*;
24
25
26 /**
27  * This class provides an implementation of the Iterator interface.
28  *
29  * Providing a parsing string (/prop1/prop2/...), the iterator parses
30  * the specified BaseBean, searching for the specified properties.
31  * As the hasMore()/next() methods are called, the parser goes over
32  * all the instances of the BaseBean tree.
33  *
34  * For example, assuming we have: /Book/Chapters/Title, the iterator
35  * would return all the titles of all the Chapters of the book.
36  *
37  * The iterator always returns elements of the type specified as the
38  * last element of the parsing string. In the above example, the
39  * parser would return only Title elements.
40  *
41  * If the parsing string is /EnterpriseBean/Entity, the parser would
42  * return all the Entity beans of the tree. Therefore, the type returned
43  * can be either a BaseBean or a final property type. Note that in case
44  * of a final property value, only objects are returned. Scalar types
45  * are wrapped using the appropriate class (int/Integer, ...).
46  *
47  * TODO: support for attributes, keys and limited arrays (only first
48  * element for example).
49  *
50  */

51 public class DDParser implements Iterator {
52
53     public static class DDLocation {
54     BaseBean root;
55     String JavaDoc name;
56     int index;
57     int type;
58     
59     public DDLocation(BaseBean r) {
60         this(r, null, -1, 0);
61     }
62     
63     public DDLocation(BaseBean r, String JavaDoc n, int i, int type) {
64         this.root = r;
65         this.name = n;
66         if (i != -1) {
67         // This gets the internal index value that doesn't change
68
// even when an element of the array is removed
69
this.index = r.indexToId(n, i);
70         } else
71         this.index = i;
72         
73         this.type = type;
74     }
75     
76     public void removeValue() {
77         if (this.index != -1) {
78         this.root.removeValue(this.name,
79         this.root.getValueById(this.name,
80         this.index));
81         }
82         else
83         this.root.setValue(this.name, null);
84     }
85     
86     public void setValue(String JavaDoc value) {
87         Object JavaDoc v = value;
88         
89         if (Common.isBoolean(this.type))
90         v = Boolean.valueOf(value);
91         
92         if (this.index != -1)
93         this.root.setValueById(this.name, this.index, v);
94         else
95         this.root.setValue(this.name, v);
96     }
97     
98     public Object JavaDoc getValue() {
99         if (this.root == null || this.name == null)
100         return null;
101
102         if (this.index != -1)
103         return this.root.getValueById(this.name, this.index);
104         else
105         return this.root.getValue(this.name);
106     }
107     
108     public BaseBean getRoot() {
109         return this.root;
110     }
111     
112     public String JavaDoc getName() {
113         return this.name;
114     }
115     
116     public int getIndex() {
117         if (this.name != null)
118         return this.root.idToIndex(this.name, this.index);
119         return this.index;
120     }
121     
122     public boolean isNode() {
123         return Common.isBean(this.type);
124     }
125     
126     public String JavaDoc toString() { // BEGIN_NOI18N
127
if (this.root != null) {
128         return "BaseBean(" + this.root.name() + "." +
129         Integer.toHexString(this.root.hashCode()) + ") " +
130             this.name + "[" +
131             ((this.name==null)?"i"+this.index:
132             ""+this.root.idToIndex(this.name, this.index)) +
133             "] - isNode: " +
134             this.isNode();
135         } else {
136         return "BaseBean(null)";
137         }
138     } // END_NOI18N
139
}
140     
141     /**
142      * There is one such class per property specified in the parsing string.
143      * For example, if the parsing string is /Book/Chapters/Title,
144      * we would have three instances of the PropParser class. One for Book,
145      * one Chapters and another one for Title. Furthermore, the PropParser
146      * instances would be linked to each other through the parent/child
147      * attributes (Book.parent = null, Book.child = Chapters, ...)
148      *
149      * This class really implements the Iterator logic, using a bottom/up
150      * algorithm: the DDParser.next() always asks for the element of the
151      * last PropParser (the one with child = null). Then this element
152      * either return what's available, either asks for its next parent
153      * in order to get new values. Its parent, in turns might asks for
154      * new values to its parents, and so on, until the root is reached and
155      * nothing else is available.
156      */

157     static class PropParser {
158     String JavaDoc name;
159     int pos;
160     Object JavaDoc[] values;
161     BaseProperty baseProp;
162     PropParser parent;
163     PropParser child;
164     Object JavaDoc cache;
165     boolean hasCache;
166     BaseBean curParent;
167     String JavaDoc keyName;
168     String JavaDoc keyValue;
169     boolean autoCreate;
170     
171     
172     PropParser(String JavaDoc n, boolean autoCreate) {
173         int i = n.indexOf('=');
174         if (i != -1) {
175         int j = n.indexOf('.');
176         if (j != -1 && j < i) {
177             this.name = n.substring(0, j);
178             this.keyName = n.substring(j+1, i);
179             this.keyValue = n.substring(i+1);
180         } else {
181             this.name = n.substring(0, i);
182             this.keyName = null;
183             this.keyValue = n.substring(i+1);
184         }
185         } else {
186         if(n.indexOf('.') != -1) {
187             throw new IllegalStateException JavaDoc(Common.getMessage(
188             "DDParserCannotUseKeyWithOutValue_msg", n));
189         }
190         
191         this.name = n;
192         this.keyName = null;
193         this.keyValue = null;
194         }
195         
196         if (this.keyValue != null && (this.keyValue.length() > 0) &&
197         (this.keyValue.charAt(0) == '\'' ||
198         this.keyValue.charAt(0) == '"')) { // NOI18N
199

200         this.keyValue =
201         this.keyValue.substring(1, this.keyValue.length()-1);
202         }
203         
204         this.autoCreate = autoCreate;
205         this.parent = null;
206         this.pos = 0;
207         this.cache = null;
208         this.parent = null;
209         this.child = null;
210         this.hasCache = false;
211         this.curParent = null;
212     }
213     
214     DDLocation getLocation() {
215         return new DDParser.DDLocation(this.curParent, this.name,
216                        ((this.baseProp.isIndexed())?
217                         this.pos-1:-1),
218                       ((BeanProp)this.baseProp).getType());
219     }
220     
221     void setBaseProperty(BaseProperty bp) {
222         this.baseProp = bp;
223     }
224     
225     BaseBean getCurBaseBean(boolean lastProp) {
226         
227         while(true) {
228         int p = this.seekNext();
229         if (p != -1) {
230             // Pos for the next one if intermediate
231
if (!lastProp)
232             this.pos++;
233             return (BaseBean)this.values[p];
234         }
235         try {
236             if (!this.updateValues())
237             break;
238         } catch(NoSuchElementException e) {
239             break;
240         }
241         }
242         
243         return null;
244     }
245     
246         int seekNext() {
247             // Seek doesn't move the pos - next() does
248
if (this.baseProp.isBean()) {
249                 while(this.values.length>this.pos
250                       && this.values[this.pos] == null) {
251                     this.pos++;
252                 }
253             }
254             if (this.values.length == this.pos)
255                 return -1;
256             return this.pos;
257         }
258     
259     static final char WILD_CHAR = '*';
260     private boolean checkValueMatch(Object JavaDoc o1, Object JavaDoc o2) {
261         
262         if (o1 == null || o2 == null) {
263         return false;
264         } else {
265         String JavaDoc s1 = o1.toString();
266         String JavaDoc s2 = o2.toString();
267         if (s1.charAt(0) == WILD_CHAR) {
268             return s2.endsWith(s1.substring(1));
269         } else
270             if (s1.charAt(s1.length()-1) == WILD_CHAR) {
271             return s2.startsWith(s1.substring(0, s1.length()-1));
272             } else {
273             return s1.equals(s2);
274             }
275         }
276     }
277     
278         // BaseBean is the parent - get our values from it
279
void setValues(BaseBean b) {
280             this.curParent = b;
281             if (baseProp.isIndexed()) {
282                 this.values = b.getValues(this.name);
283             } else {
284                 this.values = new Object JavaDoc[1];
285                 this.values[0] = b.getValue(this.name);
286             }
287         
288             // If any keyName/keyValue is used, apply it to the values
289
if (this.baseProp.isBean()) {
290                 if (this.keyName != null && this.keyValue != null) {
291             
292                     ArrayList arr = new ArrayList();
293                     Object JavaDoc o1 = Common.getComparableObject(this.keyValue);
294                     for (int i=0; i<this.values.length; i++) {
295                         BaseBean bb = (BaseBean)(this.values[i]);
296                         if (bb != null) {
297                             Object JavaDoc o2 = Common.
298                                 getComparableObject(bb.getValue(this.keyName));
299                 
300                             if (this.checkValueMatch(o1, o2)) {
301                                 arr.add(values[i]);
302                             }
303                         }
304                     }
305                     this.values = arr.toArray();
306                 }
307             } else {
308                 if (this.keyValue != null) {
309                     ArrayList arr = new ArrayList();
310                     Object JavaDoc o1 = Common.getComparableObject(this.keyValue);
311                     for (int i=0; i<this.values.length; i++) {
312                         if (this.values[i] != null) {
313                             Object JavaDoc o2 =
314                                 Common.getComparableObject(this.values[i]);
315                 
316                             if (this.checkValueMatch(o1, o2)) {
317                                 arr.add(values[i]);
318                             }
319                         }
320                     }
321                     this.values = arr.toArray();
322                 }
323             }
324         
325             // Find out if there is something left
326
boolean empty = true;
327             for (int i=0; i<this.values.length; i++)
328                 if (this.values[i] != null) {
329                     empty = false;
330                     break;
331                 }
332         
333             if (empty) {
334                 if (this.autoCreate) {
335                     if (this.baseProp.isBean()) {
336                         BaseBean bb = b.newInstance(this.name);
337                         if (this.keyName != null)
338                             bb.setValue(this.keyName, this.keyValue);
339                         if (this.baseProp.isIndexed())
340                             b.addValue(this.name, bb);
341                         else
342                             b.setValue(this.name, bb);
343             
344                         this.values = new Object JavaDoc[] {bb};
345                     } else
346                         if (this.keyValue != null) {
347                             this.values = new Object JavaDoc[] {this.keyValue};
348                             if (this.baseProp.isIndexed()) {
349                                 b.setValue(this.name, this.values);
350                             } else {
351                                 b.setValue(this.name, this.keyValue);
352                             }
353                         }
354                 } else {
355                     values = new Object JavaDoc[0];
356                 }
357             }
358         
359             this.pos = 0;
360         }
361     
362         // We already returned everything we have - try to get new ones
363
boolean updateValues() {
364             if (this.parent != null) {
365                 BaseBean b = null;
366                 do {
367                     b = (BaseBean)this.parent.next();
368                     if (b != null) {
369                         this.setValues(b);
370                         return true;
371                     }
372                 } while (b == null);
373             }
374             return false;
375         }
376     
377         // If we can populate our cache with a new one, we have 1 more
378
boolean hasNext() {
379             if (!this.hasCache) {
380                 try {
381                     this.cache = this.next();
382                     this.hasCache = true;
383                 } catch(NoSuchElementException e) {
384                     return false;
385                 }
386             }
387             return true;
388         }
389     
390         // Return the next one available
391
Object JavaDoc next() {
392             if (this.hasCache) {
393                 this.hasCache = false;
394                 return this.cache;
395             } else {
396                 int p = this.seekNext();
397                 if (p != -1) {
398                     this.pos++;
399                     return this.values[p];
400                 } else {
401                     if (this.updateValues() == true)
402                         return this.next();
403                     else
404                         throw new NoSuchElementException();
405                 }
406             }
407         }
408     }
409     
410     //
411
// This references the last PropParser of the structure described by
412
// the parsing string.
413
//
414
private PropParser parser;
415     private BaseBean root;
416     private Object JavaDoc current;
417     private boolean singleRoot;
418     private boolean empty;
419     
420     /**
421      * Build the PropParser from the parsing String. The PropParser
422      * class does all the work.
423      */

424     public DDParser(BaseBean root, String JavaDoc parse) {
425         //System.out.println("DDParser: parse="+parse+" root="+root);
426

427     boolean autoCreate = false; // Force the creation of the path
428

429     //
430
// Extract the property names from the parsing string
431
// and allocate the PropParser instances
432
//
433
parse = parse.trim();
434     
435     if (parse.endsWith("!")) { // NOI18N
436
autoCreate = true;
437         parse = parse.substring(0, parse.length()-1);
438     }
439     
440     while (parse != null &&
441            (parse.startsWith("/") || parse.startsWith("."))) // NOI18N
442
parse = parse.substring(1);
443     while (parse != null && parse.endsWith("/")) // NOI18N
444
parse = parse.substring(0, parse.length()-1);
445     
446     if (parse.equals("")) { // NOI18N
447
this.singleRoot = true;
448         this.root = root;
449         return;
450     }
451     
452     
453     PropParser prev = null;
454     PropParser cur = null;
455     String JavaDoc n;
456     
457     int pos = 0;
458     boolean skip = false;
459     
460     for (int i=0; i<parse.length(); i++) {
461         char c = parse.charAt(i);
462         
463         if (c == '"' || c == '\'') // NOI18N
464
skip = !skip;
465         
466         if (skip)
467             continue;
468         
469         boolean last = (i==(parse.length()-1));
470         if (c == '/' || last) {
471             if (last)
472                 n = parse.substring(pos, i+1);
473             else
474                 n = parse.substring(pos, i);
475             pos = i+1;
476             if (root.getProperty() == null) {
477                 System.out.println("root.getProperty="+root.getProperty());
478                 System.out.println("parse="+parse);
479                 System.out.println("n="+n);
480                 System.out.println("!Skipping DDParser search!");
481                 continue;
482             }
483             if (!root.getProperty().hasName(n) || last) {
484                 cur = new PropParser(n, autoCreate);
485                 if (prev != null) {
486                     prev.child = cur;
487                     cur.parent = prev;
488                 }
489                 prev = cur;
490             }
491         }
492     }
493     
494     this.parser = cur;
495     
496     if (cur != null) {
497         while (cur.parent != null)
498             cur = cur.parent;
499     }
500     
501     //
502
// Initialize the PropParser instances
503
//
504
BaseBean bean = root;
505     do {
506         BaseProperty[] p = bean.listProperties();
507         String JavaDoc name = cur.name;
508         boolean found = false;
509         
510         for (int j=0; (j<p.length) && !found; j++) {
511             if (p[j].hasName(name)) {
512                 //System.out.println("Found name="+name);
513

514                 // Structure description of the property
515
cur.setBaseProperty(p[j]);
516                 // Set the values
517
cur.setValues(bean);
518             
519                 if (p[j].isBean())
520                     bean = cur.getCurBaseBean(cur.child==null);
521                 else {
522                     if (cur.child != null)
523                         throw new IllegalStateException JavaDoc(Common.getMessage(
524                             "FinalPropertyNotDeclaredAtEndOfParsingString_msg",
525                                                                         name));
526                 }
527                 found = true;
528             }
529         }
530         if (!found) {
531             throw new NoSuchElementException(Common.getMessage(
532                              "NotFoundInPropertyList_msg", name,
533                              root.toString()));
534         }
535         cur = cur.child;
536     } while (cur != null && bean != null);
537     
538     if (bean == null) {
539         //
540
// It might happen that one of the element in the parsing path
541
// doesn't exist in the current graph (simply because not set)
542
// In this case, the parser has nothing to return.
543
//
544
this.empty = true;
545     }
546     else
547         this.empty = false;
548     }
549     
550     public boolean hasNext() {
551         if (!this.empty) {
552             boolean more;
553             if (this.singleRoot)
554                 more = (this.root != null);
555             else
556                 more = this.parser.hasNext();
557             if (!more)
558                 this.current = null;
559             return more;
560         }
561         return false;
562     }
563     
564     public Object JavaDoc next() {
565         if (!this.empty) {
566             if (this.singleRoot) {
567                 if (this.root != null) {
568                     this.current = this.root;
569                     this.root = null;
570                 } else
571                     throw new NoSuchElementException();
572             } else
573                 this.current = this.parser.next();
574             //System.out.println("next="+current);
575
return this.current;
576         }
577         throw new NoSuchElementException();
578     }
579     
580     public Object JavaDoc current() {
581     return this.current;
582     }
583     
584     public void remove() {
585     throw new UnsupportedOperationException JavaDoc();
586     }
587     
588     /**
589      * Return the current position of the parser. The position is made of
590      * a baseBean (parent of the property), the property name, and its index
591      * value, if this is an indexed property.
592      */

593     public DDLocation getLocation() {
594     if (!this.empty) {
595         if (this.singleRoot)
596         return new DDLocation((BaseBean)this.current);
597         else
598         return this.parser.getLocation();
599     }
600     return null;
601     }
602 }
603
604
605
Popular Tags