KickJava   Java API By Example, From Geeks To Geeks.

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


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
24 import java.beans.*;
25
26 /**
27  * The intent of this class is to provide a schema2beans graph registry,
28  * where the graphs are stored by unique name and type. Combined with
29  * the DDRegistryParser, the DDRegistry provides a sort of meta-schema2beans
30  * graph where we can ask for all the graphs of one type and ask for a
31  * parser on any set of graphs. These are the two main goals of this class.
32  *
33  * 1. provide a common and central place where we can keep track
34  * of all the graphs that we have created. Naming the graphs by
35  * unique name and type allows to get either one specific graph
36  * or a set of graphs.
37  *
38  * 2. provide a meta-schema2beans graph view for parsing any set of graphs.
39  * For example, to get a parser on all the graphs of type 'ejb'
40  * (assuming we registered graphs of this type).
41  *
42  * Therefore, this class provides two kind of methods: to add/remove graphs
43  * to the registry and to create a DDRegistry parser. A DDRegistryParser is
44  * an Iterator that returns all the elements described a schema2beans tree path.
45  *
46  * The registry also provides a convenient class (DDChangeMarker) that helps
47  * keeping track of any change.
48  */

49 public class DDRegistry extends Object JavaDoc {
50     
51     /**
52      * The goal of this class is to provide a simple way to know if a graph
53      * or a set of graphs had their content changed. The ChangeMarker can
54      * be used to implemenent a cache mechanism, in order to avoid parsing
55      * the graphs if nothing in the graph changed since the last parsing.
56      *
57      * A ChangeMarker is created by the registry, ddReg.newChangeMarker().
58      * We can add to the changeMarger a BaseBean graph, a Cursor or another
59      * ChangeMarker. So, ChangeMarker can be nested, and any modification in
60      * a nested ChangeMarker would need that the upper ChangeMarker have been
61      * been modified.
62      */

63     public static class DDChangeMarker {
64     
65     private DDRegistry reg;
66     private long timestamp;
67     
68     private ArrayList elts = null;
69     
70     DDChangeMarker(DDRegistry reg) {
71         this.reg = reg;
72         this.elts = new ArrayList();
73         this.timestamp = 0L;
74     }
75     
76     
77     public int size() {
78         return this.elts.size();
79     }
80     
81     /**
82      * If any graph of the added marker change, the current marker is
83      * also considered changed.
84      */

85     public void add(DDChangeMarker cm) {
86         if (cm == this) {
87         Thread.dumpStack();
88         }
89         this.elts.add(cm);
90     }
91     
92     /**
93      * Add a graph to the marker list. If any change occurs in this graph
94      * after resetMarker() is called, hasChanged() would return true.
95      */

96     public void add(BaseBean b) {
97         RegEntry re = this.reg.getRegEntry(b, false);
98         if (re != null && !this.elts.contains(re)) {
99         this.elts.add(re);
100         }
101     }
102     
103     /**
104      * Add the graph the cursor belongs to, to the marker list
105      */

106     public void add(DDRegistryParser.DDCursor c) {
107         String JavaDoc id = this.reg.getID(c);
108         if (id != null) {
109         BaseBean b = this.reg.getRoot(id);
110         this.add(b);
111         }
112     }
113     
114     /**
115      * removal methods.
116      */

117     public void remove(DDChangeMarker cm) {
118         this.elts.remove(cm);
119     }
120     
121     public void remove(BaseBean b) {
122         RegEntry re = this.reg.getRegEntry(b, false);
123         if (re != null)
124         this.elts.remove(re);
125     }
126     
127     public void remove(DDRegistryParser.DDCursor c) {
128         String JavaDoc id = this.reg.getID(c);
129         if (id != null) {
130         BaseBean b = this.reg.getRoot(id);
131         this.remove(b);
132         }
133     }
134
135     /**
136      * Reset the marke change time. Any change that happened before now
137      * are ignored.
138      */

139     public void resetTime() {
140         this.timestamp = System.currentTimeMillis();
141     }
142     
143     /**
144      * Return true if a change event happen between the last resetTime
145      * and now.
146      */

147     public boolean hasChanged() {
148         boolean b = this.hasChanged(this.timestamp);
149         return b;
150     }
151     
152     private boolean hasChanged(long ts) {
153         for(int i=0; i<this.elts.size(); i++) {
154         Object JavaDoc o = this.elts.get(i);
155         
156         if (o == null)
157             continue;
158         
159         if (o instanceof DDChangeMarker) {
160             if (((DDChangeMarker)o).hasChanged(ts)) {
161             return true;
162             }
163         } else
164             if (o instanceof RegEntry) {
165             if (((RegEntry)o).getTimestamp() > ts) {
166                 return true;
167             }
168             }
169         }
170         return false;
171     }
172
173     /**
174      * Dump all the registered markers
175      */

176     public String JavaDoc dump() {
177         return this.dump(new StringBuffer JavaDoc(), "", // NOI18N
178
this.timestamp).toString();
179     }
180     
181     public StringBuffer JavaDoc dump(StringBuffer JavaDoc sb, String JavaDoc indent, long ts) { // BEGIN_NOI18N
182

183         sb.append(indent + this.toString() + "\n");
184         
185         for(int i=0; i<this.elts.size(); i++) {
186         Object JavaDoc o = this.elts.get(i);
187         
188         if (o == null)
189             continue;
190         
191         if (o instanceof DDChangeMarker) {
192             ((DDChangeMarker)o).dump(sb, indent + " ", ts);
193         } else
194             if (o instanceof RegEntry) {
195             RegEntry re = (RegEntry)o;
196             sb.append(indent + " " + re.getBean() + "-0x" +
197             Integer.toHexString(re.getBean().hashCode()));
198             long l = re.getTimestamp();
199             if (l > ts) {
200                 sb.append(" Changed (bean ts:" + l
201                       + " > cm ts:" + ts );
202                 // + ") - last event: " + re.getLastEvent());
203
} else {
204                 sb.append(" No_Change (bean ts:" + l
205                       + " < cm ts:" + ts + ")");
206             }
207             sb.append("\n");
208             }
209         }
210         return sb;
211     } // END_NOI18N
212

213     public String JavaDoc toString() {
214         return "DDChangeMarker-0x" + Integer.toHexString(this.hashCode()); // NOI18N
215
}
216     }
217     
218     /*
219      * Change event listener used by the change marker class
220      */

221     public class ChangeTracer implements PropertyChangeListener {
222     DDRegistry reg;
223     
224     public ChangeTracer(DDRegistry reg) {
225         this.reg = reg;
226     }
227     
228     public void propertyChange(PropertyChangeEvent e) {
229         
230         try {
231         BaseBean s = (BaseBean)e.getSource();
232         RegEntry re = this.reg.getRegEntry(s, false);
233         re.setTimestamp();
234         //String trc =
235
// s.graphManager().getKeyPropertyName(e.getPropertyName());
236
//re.setLastEvent(trc);
237
} catch(Exception JavaDoc ex) {
238         }
239     }
240     }
241     
242     private ArrayList scopes;
243     private ChangeTracer changeTracer;
244
245
246     //
247
public DDRegistry() {
248     this.scopes = new ArrayList();
249     this.changeTracer = new ChangeTracer(this);
250     }
251     
252     /**
253      * Create a new entry in the DD graph registry. The schema2beans graph
254      * bean is added to registry using a unique name (ID), such as a unique
255      * internal identifier, and a non unique name (name),
256      * such as a display name.
257      *
258      * Any number of non unique type can also be associated to a graph
259      * entry, see the method addType.
260      *
261      */

262     public void createEntry(BaseBean bean, String JavaDoc ID, String JavaDoc name) {
263     RegEntry entry = this.getRegEntry(bean, false);
264     if (entry != null) {
265         throw new IllegalArgumentException JavaDoc(Common.getMessage(
266         "BeanGraphAlreadyInRegistry_msg", bean.name()));
267     }
268     
269     entry = this.getRegEntry(ID);
270     if (entry != null) {
271         throw new IllegalArgumentException JavaDoc(Common.getMessage(
272         "CantRegisterGraphSameID_msg", bean.name(), entry, ID));
273     }
274     bean.addPropertyChangeListener(this.changeTracer);
275     this.scopes.add(new RegEntry(bean, ID, name));
276     }
277
278     /**
279      * Change the schema2beans graph for the unique entry ID. This method
280      * might be used if another graph should replace an existing entry.
281      */

282     public void updateEntry(String JavaDoc ID, BaseBean bean) {
283     RegEntry entry = this.getRegEntry(ID);
284     if (entry != null)
285         entry.setBean(bean);
286     else
287         throw new IllegalArgumentException JavaDoc(Common.getMessage(
288         "CantUpdateGraphNotInRegistry_msg", ID));
289     }
290     
291     /**
292      * Remove an entry in the registry.
293      */

294     public void removeEntry(BaseBean bean) {
295     RegEntry entry = this.getRegEntry(bean, false);
296     if (entry != null) {
297         entry.getBean().removePropertyChangeListener(this.changeTracer);
298         this.removeRegEntry(entry);
299     }
300     }
301     
302     /**
303      * Rename a graph entry unique ID to a new unique ID entry and new
304      * non unique name.
305      */

306     public void renameEntry(String JavaDoc oldID, String JavaDoc newID, String JavaDoc newName) {
307     RegEntry entry = this.getRegEntry(oldID);
308     if (entry != null) {
309         entry.setID(newID);
310         if (newName != null)
311         entry.setName(newName);
312     }
313     }
314
315     /**
316      * Rename a graph unique ID to a new unique ID.
317      */

318     public void renameEntry(String JavaDoc oldID, String JavaDoc newID) {
319     this.renameEntry(oldID, newID, null);
320     }
321
322     /**
323      * Remove a registry entry.
324      */

325     public void removeEntry(String JavaDoc ID) {
326     RegEntry entry = this.getRegEntry(ID);
327     if (entry != null)
328         entry.getBean().removePropertyChangeListener(this.changeTracer);
329     this.removeRegEntry(entry);
330     }
331     
332     /**
333      * This return a new change marker instance, that can be used to know
334      * if any graph of the registry has changed.
335      */

336     public DDChangeMarker createChangeMarker() {
337     return new DDChangeMarker(this);
338     }
339     
340     /**
341      * Return true of the specified schema2beans graph is registered with the
342      * specified type.
343      */

344     public boolean hasType(BaseBean bean, String JavaDoc type) {
345     RegEntry r = this.getRegEntry(bean, false);
346     if (r != null)
347         return r.hasType(type);
348     return false;
349     }
350     
351     /**
352      * Reset the change timestamp of all the registered graphs.
353      */

354     public void clearCache() {
355     for (int i=0; i<this.scopes.size(); i++) {
356         RegEntry se = (RegEntry)this.scopes.get(i);
357         if (se != null)
358         se.setTimestamp();
359     }
360     }
361     
362     /**
363      * Reset the change timestamp of the specified graph.
364      */

365     public void clearCache(BaseBean bean) {
366     this.setTimestamp(bean);
367     }
368     
369     public void setTimestamp(BaseBean bean) {
370     RegEntry r = this.getRegEntry(bean, false);
371     if (r != null)
372         r.setTimestamp();
373     }
374     
375     public long getTimestamp(BaseBean bean) {
376     RegEntry r = this.getRegEntry(bean, false);
377     if (r != null)
378         return r.getTimestamp();
379     return 0L;
380     }
381
382     /**
383      * Having a schema2beans graph, this method return its unique ID.
384      */

385     public String JavaDoc getID(BaseBean bean) {
386     RegEntry r = this.getRegEntry(bean, false);
387     if (r != null)
388         return r.getID();
389     return null;
390     }
391     
392     /**
393      * Return the unique ID of the graph where the cursor points to.
394      * Note that a DDCursor is a location reference (pointer to any
395      * schema2beans graph) in any graph of the registry.
396      */

397     public String JavaDoc getID(DDRegistryParser.DDCursor c) {
398     RegEntry r = this.getRegEntry(c.getRoot(), false);
399     if (r != null)
400         return r.getID();
401     return null;
402     }
403     
404     /**
405      * Same as getID but return the non unique name.
406      */

407     public String JavaDoc getName(DDRegistryParser.DDCursor c) {
408     RegEntry r = this.getRegEntry(c.getRoot(), false);
409     if (r != null)
410         return r.getName();
411     return null;
412     }
413     
414
415     /**
416      * Create a new DDRegistryParser (parser on a set of graph), based
417      * on another parser current location and schema2beans path.
418      */

419     public DDRegistryParser newParser(DDRegistryParser parser, String JavaDoc path) {
420     return new DDRegistryParser(this, parser, path);
421     }
422     
423     /**
424      * Create a new DDRegistryParser based on a current position in a graph
425      * and a schema2beans path.
426      */

427     public DDRegistryParser newParser(DDRegistryParser.DDCursor cursor,
428                       String JavaDoc path) {
429     return new DDRegistryParser(this, cursor, path);
430     }
431     
432     /**
433      * Create a DDRegistryParser based on a scope value. A scope value is
434      * either a unique graph name or a type value. If more than one graph
435      * are registered under the type specified, the parser will go through
436      * all the graphs. If the ID is specified or the scope is a one graph type,
437      * the the parser will go through only the specified graph.
438      *
439      * The scope syntax is: [name]
440      */

441     public DDRegistryParser newParser(String JavaDoc scope) {
442     return new DDRegistryParser(this, scope);
443     }
444     
445     /**
446      * Create a cursor location
447      */

448     public DDRegistryParser.DDCursor newCursor(DDRegistryParser.DDCursor c,
449                            String JavaDoc path) {
450     return new DDRegistryParser.DDCursor(c, path);
451     }
452     
453     /**
454      * Create a cursor location
455      */

456     public DDRegistryParser.DDCursor newCursor(String JavaDoc path) {
457     return new DDRegistryParser.DDCursor(this, path);
458     }
459     
460     /**
461      * Create a cursor location
462      */

463     public DDRegistryParser.DDCursor newCursor(BaseBean bean) {
464     return new DDRegistryParser.DDCursor(this, bean);
465     }
466     
467     /**
468      * Add a type to the entry (the type doesn't have to be unique)
469      */

470     public void addType(BaseBean bean, String JavaDoc type) {
471     
472     if (DDLogFlags.debug) {
473         TraceLogger.put(TraceLogger.DEBUG, TraceLogger.SVC_DD,
474         DDLogFlags.DBG_REG, 1, DDLogFlags.ADDTYPE,
475         bean.name() + " " + type);
476     }
477     
478     RegEntry se = this.getRegEntry(bean, true);
479     se.add(type);
480     }
481
482     /**
483      * Return the name of the unique graph ID
484      */

485     public String JavaDoc getName(String JavaDoc ID) {
486     RegEntry r = this.getRegEntry(ID);
487     if (r!= null)
488         return r.getName();
489     return null;
490     }
491     
492     /**
493      * Trace/debug method. Return the list of all the registered graphs
494      */

495     public String JavaDoc dump() {
496     StringBuffer JavaDoc s = new StringBuffer JavaDoc();
497     for (int i=0; i<this.scopes.size(); i++) {
498         RegEntry se = (RegEntry)this.scopes.get(i);
499         if (se != null) {
500         s.append(se.toString() + "\n"); // NOI18N
501
}
502     }
503     return s.toString();
504     }
505     
506     /**
507      * Trace/debug method. Return the XML content of all the registered graphs.
508      */

509     public String JavaDoc dumpAll() {
510     StringBuffer JavaDoc s = new StringBuffer JavaDoc();
511     for (int i=0; i<this.scopes.size(); i++) {
512         RegEntry se = (RegEntry)this.scopes.get(i);
513         if (se != null) {
514         s.append("\n*** Graph:" + se.toString() + "\n"); // NOI18N
515
s.append(se.getBean().dumpBeanNode());
516         }
517     }
518     return s.toString();
519     }
520     
521     /**
522      * Return the entry for the BaseBean, if any.
523      */

524     public RegEntry getRegEntry(BaseBean bean, boolean raise) {
525     for (int i=0; i<this.scopes.size(); i++) {
526         RegEntry se = (RegEntry)this.scopes.get(i);
527         if (se.getBean() == bean) {
528         return se;
529         }
530     }
531     // Didn't find it - try to look for the root
532
if ((bean != null) && !bean.isRoot()) {
533         do {
534         bean = bean.parent();
535         } while(bean != null && !bean.isRoot());
536         return this.getRegEntry(bean, raise);
537     }
538     
539     if (raise) {
540         throw new IllegalArgumentException JavaDoc(Common.getMessage(
541         "BeanGraphEntryNotInRegistry_msg", bean.name()));
542     } else
543         return null;
544     }
545     
546     /**
547      * Return the entry for the BaseBean, if any.
548      */

549     private RegEntry getRegEntry(String JavaDoc ID) {
550     for (int i=0; i<this.scopes.size(); i++) {
551         RegEntry se = (RegEntry)this.scopes.get(i);
552         if (se.getID().equals(ID))
553         return se;
554     }
555     return null;
556     }
557     
558     /**
559      * Return the entry for the BaseBean, if any.
560      */

561     private void removeRegEntry(RegEntry entry) {
562     int i = this.scopes.indexOf(entry);
563     if (i != -1)
564         this.scopes.remove(i);
565     }
566     
567     // Remove any blank and [] characters
568
public static String JavaDoc getGraphName(String JavaDoc s) {
569     if (s != null) {
570         s = s.trim();
571         if (s.startsWith("[")) { // NOI18N
572
int i = s.indexOf(']');
573         if (i != -1)
574             s = s.substring(1,i);
575         else
576             return null;
577         }
578     }
579     return s;
580     }
581
582     /*
583      * Check if there is any graph of this name in the registry
584      */

585     public boolean hasGraph(String JavaDoc str) {
586     return this.hasGraph(str, null);
587     }
588     
589     public boolean hasGraph(String JavaDoc str, DDRegistryParser.DDCursor c) {
590     String JavaDoc s = getGraphName(str);
591     if (s != null) {
592         if (!s.equals(DDRegistryParser.CURRENT_CURSOR))
593         return (this.getRoot(s) != null);
594         else {
595         if (c == null)
596             return true;
597         else
598             return (this.getID(c) != null);
599         }
600     }
601     return false;
602     }
603     
604     static public String JavaDoc createGraphName(String JavaDoc s) {
605     if (s != null) {
606         //s = s.trim();
607
int i = s.indexOf('[');
608         if (i != -1 && i<s.indexOf(']'))
609         return s;
610         else
611         return "["+s+"]"; // NOI18N
612
} else {
613         throw new IllegalArgumentException JavaDoc(Common.getMessage(
614         "GraphNameCantBeNull_msg"));
615     }
616     }
617     
618     /**
619      * Return the bean root for this name (either unique name or scope)
620      */

621     public BaseBean getRoot(String JavaDoc s) {
622     BaseBean[] r = this.getRoots(s);
623     if (r.length>0)
624         return r[0];
625     return null;
626     }
627     
628     /**
629      * Return all the bean roots for this name (either unique name or scope)
630      */

631     public BaseBean[] getRoots(String JavaDoc s) {
632     s = getGraphName(s);
633     // Try to get the root by name, then by type
634
RegEntry se = this.getRegEntry(s);
635     if (se == null) {
636         ArrayList list = new ArrayList();
637         for (int i=0; i<this.scopes.size(); i++) {
638         se = (RegEntry)this.scopes.get(i);
639         if (se.hasType(s))
640             list.add(se.getBean());
641         }
642         BaseBean[] ret = new BaseBean[list.size()];
643         return (BaseBean[])list.toArray(ret);
644     } else
645         return (new BaseBean[] {se.getBean()});
646     }
647     
648     /**
649      * Iterator on a list of DDParser
650      */

651     class IterateParser implements Iterator {
652     private ArrayList list;
653     private int pos;
654     public IterateParser() {
655         this.list = new ArrayList();
656     }
657     
658     void addParser(BaseBean b, String JavaDoc parsingPath) {
659         this.list.add(new DDParser(b, parsingPath));
660     }
661     
662     public boolean hasNext() {
663         if (pos < list.size())
664         return true;
665         else
666         return false;
667     }
668     
669     public Object JavaDoc next() {
670         return this.list.get(pos++);
671     }
672     
673     public void remove() {
674         throw new UnsupportedOperationException JavaDoc();
675     }
676     }
677     
678     
679     /**
680      * All the types a schema2beans graph belongs to.
681      */

682     
683     static class RegEntry {
684     private BaseBean bean;
685     private ArrayList types;
686     private String JavaDoc ID;
687     private String JavaDoc name;
688     private long timestamp;
689     //private String info;
690

691     RegEntry(BaseBean b, String JavaDoc ID, String JavaDoc name) {
692         this.bean = b;
693         this.types = new ArrayList();
694         this.ID = ID;
695         this.name = name;
696         this.setTimestamp();
697     }
698     
699     /* For trace purpose
700     void setLastEvent(String e) {
701         this.info = e;
702     }
703     
704     String getLastEvent() {
705         return this.info;
706         }*/

707     
708     // For the caching mechanism (DDChangeMarker)
709
void setTimestamp() {
710         this.timestamp = System.currentTimeMillis();
711     }
712     
713     long getTimestamp() {
714         return this.timestamp;
715     }
716     
717     void setBean(BaseBean bean) {
718         this.bean = bean;
719     }
720     
721     BaseBean getBean() {
722         return this.bean;
723     }
724     
725     String JavaDoc getName() {
726         return this.name;
727     }
728     
729     String JavaDoc getID() {
730         return this.ID;
731     }
732     
733     void setID(String JavaDoc ID) {
734         this.ID = ID;
735     }
736     
737     void setName(String JavaDoc name) {
738         this.name = name;
739     }
740     
741     void add(String JavaDoc type) {
742         this.types.add(type);
743     }
744     
745     boolean hasType(String JavaDoc type) {
746         for (int i=0; i<this.types.size(); i++) {
747         String JavaDoc t = (String JavaDoc)this.types.get(i);
748         if (type != null && t.equals(type))
749             return true;
750         }
751         return false;
752     }
753     
754     public String JavaDoc toString() {
755         String JavaDoc s = this.bean.name() + "(id:" + ID + "-name:" + name + ")" + " ["; // NOI18N
756
for (int i=0; i<this.types.size(); i++) {
757         String JavaDoc t = (String JavaDoc)this.types.get(i);
758         s += " " + t; // NOI18N
759
}
760         return s + "]"; // NOI18N
761

762     }
763     }
764 }
765
Popular Tags