KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > directory > jxplorer > DataQuery


1 package com.ca.directory.jxplorer;
2
3 import com.ca.directory.jxplorer.broker.Broker;
4 import com.ca.commons.naming.*;
5
6 import java.util.Hashtable JavaDoc;
7 import java.util.Vector JavaDoc;
8 import java.util.ArrayList JavaDoc;
9 import javax.naming.NamingException JavaDoc;
10
11 /**
12  * Helper class for Broker, this encapsulates an ldap-like data
13  * request that is placed on the Broker queue for eventual resolution.
14  * Broker Request objects are intended to be used once, and then
15  * discarded.
16  */

17
18 public class DataQuery
19 {
20     /**
21      * The following gives the 'type' of the query.
22      */

23     // could use OO for this, but seems unnecessary; would only create class sprawl for
24
// so many similar classes. - CB
25

26     public static final int UNKNOWN = 0; /** an unknown type **/
27     public static final int EXISTS = 1; /** an existance check query **/
28     public static final int READENTRY = 2; /** a read of a single entry **/
29     public static final int LIST = 4; /** list the immediate children of an entry **/
30     public static final int SEARCH = 8; /** a search query **/
31     public static final int MODIFY = 16; /** a modify request **/
32     public static final int COPY = 32; /** a copy request **/
33     //public static final int GETALLOC = 64; /** get all object class request **/
34
public static final int GETRECOC = 128; /** get recommended object classes request **/
35     public static final int EXTENDED = 256; /** an extended data query: i.e. a user inherited extension class **/
36
37     protected Vector JavaDoc listeners = new Vector JavaDoc();
38
39     protected int type = 0;
40
41     static int noRequests = 0;
42
43     public int id; // debugging
44

45     protected boolean myStatus = false;
46
47     protected ArrayList JavaDoc myArrayList = null;
48
49     protected DXEntry myEntry = null;
50
51     protected DXNamingEnumeration myEnum = null;
52
53     protected Exception JavaDoc myEx = null;
54
55
56     // The following data variables are set initially in the
57
// constructor, and never again modified.
58

59     protected DN requestDN = null;
60     protected DN oldDN = null;
61
62     protected DXEntry oldEntry = null;
63     protected DXEntry newEntry = null;
64
65     protected String JavaDoc filter = null;
66     
67     protected String JavaDoc[] returnAttrs = null;
68
69     protected int searchLevel = 2; //TE: 0 = search base object, 1 = search next level, 2 = seach full subtree.
70

71     protected Hashtable JavaDoc extendedData = null; // convenience object for extended queries
72

73
74     // These booleans relate to which stage of the query life cycle the
75
// query is at - at the start, they are all false. When the query
76
// is being executed 'working' is true. Finally 'ready' is true.
77
// If the user cancels the query, the broker should pick this up
78
// and ignore the query.
79

80     protected boolean ready = false; // whether the query if completed
81

82     protected boolean cancelled = false; // whether the user has cancelled this query.
83

84     protected boolean working = false; // whether this request is currently being run by a broker thread
85

86     protected boolean squelched = false; // whether this request has been consumed by a selfish listener
87

88     // XXX Break into sub-classes?
89

90     public DataQuery()
91     {
92         id = noRequests++;
93     }
94
95     /**
96      * Constructor for Get all Object Class requests
97      */

98
99     public DataQuery(int type)
100     {
101         this.type = type;
102
103         if (type == EXTENDED)
104             extendedData = new Hashtable JavaDoc();
105
106         id = noRequests++;
107     }
108
109     /**
110      * Constructor for List, Read Entry, Exists, and get Recommended Object Class requests.
111      */

112
113     public DataQuery(int type, DN dn)
114     {
115         this(type);
116         requestDN = dn;
117         if (type != DataQuery.LIST && type != DataQuery.READENTRY && type != DataQuery.EXISTS )// && type != DataQuery.GETRECOC)
118
setException(new Exception JavaDoc("Bad Constructor call (ii) for DataQuery of Type " + type));
119     }
120
121     /**
122      * Constructor for Copy requests
123      */

124
125     public DataQuery(int type, DN oldDN, DN newDN)
126     {
127         this(type);
128         requestDN = newDN;
129         this.oldDN = oldDN;
130         if (type != DataQuery.COPY)
131             setException(new Exception JavaDoc("Bad Constructor call (iii) for DataQuery of Type " + type));
132     }
133
134     /**
135      * Constructor for Modify requests
136      */

137
138     public DataQuery(int type, DXEntry oldEntry, DXEntry newEntry)
139     {
140         this(type);
141         this.oldEntry = oldEntry;
142         this.newEntry = newEntry;
143         if (type != DataQuery.MODIFY)
144             setException(new Exception JavaDoc("Bad Constructor call (iv) for DataQuery of Type " + type));
145     }
146     
147     /**
148      * Constructor for Search requests
149      */

150
151     public DataQuery(int type, DN dn, String JavaDoc filter, int level, String JavaDoc[] returnAttrs)
152     {
153         this(type);
154         requestDN = dn;
155         this.filter = filter;
156         this.returnAttrs = returnAttrs;
157         searchLevel = level;
158         if (type != DataQuery.SEARCH)
159             setException(new Exception JavaDoc("Bad Constructor call (v) for DataQuery of Type " + type));
160     }
161
162     /**
163      * Prevents any other data listeners from using the data query. Indicates that
164      * the current data listener has handled the data, and that no other data listener
165      * should bother. This method nullifies any data (including exception information).
166      */

167
168     public void squelch()
169     {
170         squelched = true;
171
172         myArrayList = null;
173         myEntry = null;
174         myEnum = null;
175         myEx = null;
176         requestDN = null;
177         oldDN = null;
178         oldEntry = null;
179         newEntry = null;
180         filter = null;
181     }
182
183
184     /**
185     * Flags whether a data listener has already consumed this data query ('event'), and
186     * the data has been 'used up'.
187     */

188
189     public boolean isSquelched() { return squelched; }
190
191     /**
192      * Attempt to cancel this request by setting a cancelled
193      * flag and an exception. There is no way to 'uncancel' a
194      * request. The cancel flag should be picked up by the broker.
195      */

196
197     public void cancel()
198     {
199         cancelled = true;
200         setException(new Exception JavaDoc("Request Cancelled"));
201     }
202
203     /**
204      * Returns whether this request has been cancelled.
205      */

206
207     public boolean isCancelled()
208     {
209         return cancelled;
210     }
211
212     /**
213      * Registers that this query is currently being operated on by a broker.
214      * This is cancelled when the query is 'finished()'.
215      */

216
217      public void setRunning()
218      {
219          working = true;
220      }
221
222      /**
223       * Returns whether the query is currently being operated on by a broker.
224       */

225
226      public boolean isRunning()
227      {
228          return working;
229      }
230
231
232
233     /**
234      * Called when the operation is complete. While it
235      * is not an error to call this method multiple times,
236      * subsequent calls will have no effect.
237      */

238
239     public synchronized void finish()
240     {
241         if (ready == true) return; // only run this method once!
242

243         ready = true;
244         if (!cancelled)
245         {
246             notifyAll();
247             fireDataEvent();
248         }
249         working = false;
250     }
251
252     /**
253      * Notifies all interested listeners. Note that the most
254      * recently added listener is notified first, giving it
255      * first option on handling any errors generated.
256      */

257
258     protected void fireDataEvent()
259     {
260         while(listeners.size() > 0 && !squelched) // while there are still listeners, and this hasn't been squelched.
261
{
262             DataListener current = (DataListener)listeners.lastElement();
263             listeners.removeElementAt(listeners.size()-1);
264             current.dataReady(this);
265         }
266     }
267
268     /**
269      * Utility translation method
270      */

271
272     public String JavaDoc getTypeString()
273     {
274         switch (type)
275         {
276             case UNKNOWN: return "Unknown";
277             case EXISTS: return "Existance check";
278             case READENTRY: return "Read entry";
279             case LIST: return "List";
280             case SEARCH: return "Search";
281             case MODIFY: return "Modify";
282             case COPY: return "Copy";
283 // case GETALLOC: return "Get all objectclasses from schema";
284
// case GETRECOC: return "Get recommended objectclasses from schema";
285
case EXTENDED: return "Extended request";
286         }
287         return "UNDEFINED";
288     }
289
290     /**
291      * Return a string representation of the Broker Request (usually for debugging).
292      */

293
294     public String JavaDoc toString()
295     {
296         String JavaDoc ret = "query ("+id+"): " + getTypeString();
297
298         if (type == SEARCH)
299             ret += " filter: " + filter;
300         else if (requestDN != null)
301             ret += " on " + requestDN;
302
303         if (ready() == false)
304             return (ret + " : (request pending)");
305         else
306             return (ret + " : (completed)");
307
308 /* {
309
310             Object o = getResult();
311             if (o == null)
312                 return (ret + " : (null)");
313             else
314                 return (ret + " : " + getResult().toString());
315         }
316 */

317     }
318
319     /**
320      * Get the result of the request as a generic object (which must be cast
321      * correctly to be used). (Usually for debugging).
322      */

323
324     public Object JavaDoc getResult()
325     {
326         try
327         {
328             switch (type)
329             {
330                 case UNKNOWN: return "UNKNOWN";
331                 case EXISTS: return new Boolean JavaDoc(getStatus());
332                 case READENTRY: return getEntry();
333                 case LIST: return getEnumeration();
334                 case SEARCH: return getEnumeration();
335                 case MODIFY: return new Boolean JavaDoc(getStatus());
336                 case COPY: return new Boolean JavaDoc(getStatus());
337 // case GETALLOC: return getObjectClasses();
338
// case GETRECOC: return getObjectClasses();
339
case EXTENDED: return getAllExtendedData();
340             }
341             return "UNDEFINED";
342         }
343         catch (NamingException JavaDoc e)
344         {
345             return e;
346         }
347     }
348
349     /** Unsynchronized Methods to set data variables **/
350
351     public DataQuery setArrayList(ArrayList JavaDoc v) { myArrayList = v; return this;}
352
353     public DataQuery setStatus(boolean b) { myStatus = b; return this;}
354
355     public DataQuery setEntry(DXEntry d) { myEntry = d; return this;}
356
357     public DataQuery setEnum(DXNamingEnumeration d) { myEnum = d; return this;}
358
359     public DataQuery setException(Exception JavaDoc e) { myEx = e; return this;}
360
361     //public void setType(int t) { type = t; }
362

363
364     /** DataQuery Interface **/
365
366     /**
367      * Used by some thread-friendly applications that wish to
368      * poll the state of the DataResult. Returns false
369      * until the data request has been completed (which
370      * includes an error occurring).
371      * @return true if the request has been completed.
372      */

373     public boolean ready() { return ready; }
374
375     /**
376      * Used by thread-friendly application to register a
377      * listener that will be called when the request has
378      * been completed (or an error thrown).<p>
379      *
380      * Note that this listener is somewhat unusual, as it
381      * will only ever trigger a maximum of one time.<p>
382      *
383      * if this method is called on a DataResult that has
384      * already been completed, it will be triggered immediately.
385      * This may cause listener code to be triggered <i>before</i>
386      * any code subsequent to the addDataListener() call.<p>
387      *
388      * @param l the listener to be notified when the data
389      * operation has been completed.
390      */

391
392     public synchronized void addDataListener(DataListener l)
393     {
394         if (ready)
395             l.dataReady(this); // if data ready, fire immediately
396
else
397             listeners.add(l); // otherwise add to listener list.
398
}
399
400
401     synchronized void keepWaiting()
402         throws NamingException JavaDoc
403     {
404         // XXX BIG UGLY HACK
405
// We need to make sure that thread is not waiting for itself. This can happen if a pluggable editor
406
// (run from jndiThread) tries to get the result from a DataQuery immediately. Currently this is done
407
// by checking the thread name string (yuck). Maybe it would be better to do away with the facility
408
// altogether, and disallow DataQueries to return anything unless they are 'ready()'.
409

410         String JavaDoc current = Thread.currentThread().getName();
411
412         if ("jndiBroker Thread searchBroker Thread schemaBroker Thread".indexOf(current)>-1)
413         {
414             System.err.println("ERROR - Thread " + current + " possibly blocking on self");
415             throw new NamingException JavaDoc("Thread Blockage (?) during Naming operation - attempt to force immediate data read from: " + current + " thread. Consider using unthreaded Broker classes rather than DataQuery.");
416         }
417
418         try
419         {
420             notifyAll();
421             wait();
422         } catch (InterruptedException JavaDoc e)
423         {
424             System.out.println("Thread: " + Thread.currentThread().getName() + " interrupted in DataQuery:keepWaiting() loop \n " + e);
425         }; // block until data is cooked
426
}
427
428     /**
429      * Returns the status of an operation. This will
430      * block until the transaction has finished, so thread
431      * friendly applications should wait until the
432      * DataResult is 'ready' before calling this method.<p>
433      *
434      * This method should be used to read the response from
435      * DataSource methods modifyEntry() and copyTree(),
436      * and DataSource operations such as exists() and isActive().
437      *
438      * Throws a NamingException if called inapropriately
439      * (i.e. if no result of this type would be possible).
440      *
441      * @return the success status of the operation.
442      */

443
444     public boolean getStatus()
445         throws NamingException JavaDoc
446     {
447         while (!ready()) keepWaiting();
448
449         if (type == MODIFY || type == COPY || type == EXISTS)
450             return myStatus;
451         else
452             throw new NamingException JavaDoc("Improper call of getStatus for a DataQuery of Type " + getTypeString());
453     }
454     /**
455      * A list of Name-Class Pairs from a 'getChildren()'
456      * DataSource operation. This will
457      * block until the transaction has finished, so thread
458      * friendly applications should wait until the
459      * DataResult is 'ready' before calling this method.<p>
460      *
461      * Throws a NamingException if called inapropriately
462      * (i.e. if no result of this type would be possible).
463      *
464      * This method should be used to read the response from
465      * DataSource getChildren() method.
466      * @return the NameClass pairs representing the children
467      * of a given entry, or of SearchResults representing the
468      * result of a search request.
469      */

470     public DXNamingEnumeration getEnumeration()
471         throws NamingException JavaDoc
472     {
473         try
474         {
475             while (!ready()) keepWaiting();
476
477             if (type == LIST || type == SEARCH)
478                 return myEnum;
479             else
480                 throw new NamingException JavaDoc("Improper call of getNameClassPairs for a DataQuery of Type " + getTypeString());
481
482         }
483         catch (NamingException JavaDoc e)
484         {
485             throw new NamingException JavaDoc(e.toString());
486         }
487     }
488
489     /**
490      * A DXEntry from a 'getEntry()'
491      * DataSource operation. This will
492      * block until the transaction has finished, so thread
493      * friendly applications should wait until the
494      * DataResult is 'ready' before calling this method.<p>
495      *
496      * Throws a NamingException if called inapropriately
497      * (i.e. if no result of this type would be possible).
498      *
499      * This method should be used to read the response from
500      * DataSource getEntry() method.
501      */

502     public DXEntry getEntry()
503         throws NamingException JavaDoc
504     {
505         while (!ready()) keepWaiting();
506
507         if (type == READENTRY)
508             return myEntry;
509         else
510             throw new NamingException JavaDoc("Improper call of getEntry for a DataQuery of Type " + getTypeString());
511     }
512     /**
513      * A vector of strings representing ObjectClasses from either a
514      * DataSource getObjectClasses() or a getRecommendedObjectClasses()
515      * operation. This will
516      * block until the transaction has finished, so thread
517      * friendly applications should wait until the
518      * DataResult is 'ready' before calling this method.<p>
519      *
520      * Throws a NamingException if called inapropriately
521      * (i.e. if no result of this type would be possible).
522      *
523      * This method should be used to read the response from
524      * DataSource getObjectClasses() or a getRecommendedObjectClasses() method.
525      */

526
527     public ArrayList JavaDoc getObjectClasses()
528         throws NamingException JavaDoc
529     {
530         while (!ready()) keepWaiting();
531
532 // if (type == GETALLOC || type == GETRECOC)
533
if (type == GETRECOC)
534             return myArrayList;
535         else
536             throw new NamingException JavaDoc("Improper call of getObjectClasses for a DataQuery of Type " + getTypeString());
537     }
538
539     /**
540      * Indicates that an error has occured. This will
541      * block until the transaction has finished, so thread
542      * friendly applications should wait until the
543      * DataResult is 'ready' before calling this method.<p>
544      * It returns null if there is no exception.<p>
545      * @return the exception experienced by the directory
546      * operation, or null if no error found.
547      */

548
549     public Exception JavaDoc getException()
550     {
551         try
552         {
553             while (!ready()) keepWaiting();
554         }
555         catch (NamingException JavaDoc e) { return e; }
556
557         return myEx; // which is null, unless an exception occurred...
558
}
559
560     /**
561      * Returns whether an error has occured. This will
562      * block until the transaction has finished, so thread
563      * friendly applications should wait until the
564      * DataResult is 'ready' before calling this method.<p>
565      * It returns false if there is no exception.<p>
566      * @return whether an exception occured in the execution of
567      * this query
568      */

569
570     public boolean hasException()
571     {
572         try
573         {
574             while (!ready()) keepWaiting();
575         }
576         catch (NamingException JavaDoc e)
577         {
578             myEx = e;
579             return true;
580         }
581
582         return (myEx!=null);
583     }
584
585
586     /**
587      * This clears the exception status of a DataResult,
588      * indicating that the exception has been handled.
589      * It is not an error to call this method if no
590      * exception exists, and this method has no effect
591      * on exceptions that may occur later (e.g. if this
592      * method is called before the DataResult is ready()
593      * it may have no effect.)
594      */

595     public void clearException()
596     {
597         myEx = null;
598     }
599
600
601
602     public int getType() { return type; }
603
604
605
606     // Read-only access methods to data variables.
607

608     public DN requestDN() { return (requestDN==null)?null:new DN(requestDN); }
609
610     public DN oldDN() { return (oldDN==null)?null:new DN(oldDN); }
611
612     public DXEntry oldEntry() { return (oldEntry==null)?null:new DXEntry(oldEntry); }
613
614     public DXEntry newEntry() { return (newEntry==null)?null:new DXEntry(newEntry); }
615
616     public String JavaDoc filter() { return (filter==null)?null:filter; }
617     
618     public String JavaDoc[] returnAttributes() { return (returnAttrs==null)?null:returnAttrs; }
619
620     public int searchLevel() { return searchLevel; }
621
622
623     /**
624      * This provides a method of returning arbitrary information from
625      * an extended request.
626      * @return a hashtable of named objects (use addExtendedData to set these).
627      */

628
629     public Hashtable JavaDoc getAllExtendedData() { return extendedData; }
630
631     /**
632      * Returns a named data object from the extended data queries object store.
633      * @param name case insensitive name of a previously added object.
634      */

635
636     public Object JavaDoc getExtendedData(String JavaDoc name) { return extendedData.get(name.toLowerCase()); }
637
638     /**
639      * This provides a method for setting arbitrary information for
640      * the use of an extended request.
641      */

642
643     public void setExtendedData(String JavaDoc name, Object JavaDoc o) { if (extendedData != null) extendedData.put(name.toLowerCase(),o); }
644
645     /**
646      * Users intending to make Extended requests should write (potentially anonymous)
647      * derived classes of DataQuery, extending this method. Derived class writers
648      * should be carefull to only use the *unthreaded* methods of the Broker, in
649      * order to avoid possible thread problems.
650      */

651
652     public void doExtendedRequest(Broker b) { return; }
653
654 }
655
656
657
Popular Tags