KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > directory > jxplorer > broker > OfflineBroker


1
2 package com.ca.directory.jxplorer.broker;
3
4 import javax.naming.*;
5 import javax.naming.directory.*;
6
7 import java.util.*;
8 import java.util.logging.Logger JavaDoc;
9 import java.util.logging.Level JavaDoc;
10
11 import com.ca.directory.jxplorer.*;
12 import com.ca.commons.naming.*;
13 import com.ca.commons.jndi.SchemaOps;
14
15 import java.awt.Component JavaDoc;
16
17 /**
18  * This sets up a 'virtual broker' that reads info in, and allows
19  * the user to operate on it, without any server being involved. The
20  * data is usually (always?) read from an ldif file.
21  */

22
23 public class OfflineBroker extends Broker
24 {
25     Hashtable nodes; // stored node dn keys (as strings), and nodes
26
Component JavaDoc display;
27
28     private static Logger JavaDoc log = Logger.getLogger(OfflineBroker.class.getName());
29
30     /**
31      * Data node class. Tuned for 10ish children.
32      *
33      */

34     
35     class Node
36     {
37         DXEntry entry;
38         
39         //DXAttributes myAtts;
40
Vector children;
41         DN dn;
42         NameClassPair namePair;
43
44         /**
45          * constructor for a node with a dn and a set of attribute
46          */

47         public Node(DXEntry entry)
48         {
49             this.entry = entry;
50             dn = entry.getDN();
51             children = new Vector(10);
52             namePair = new NameClassPair(dn.getLowestRDN().toString(), dn.getLowestRDN().getAtt());
53         }
54         
55         public void addChild(Node n) { children.add(n); }
56         
57         public void removeChild(Node n) { children.remove(n); }
58         
59         public void updateAttributes(DXAttributes a)
60         {
61             try
62             {
63                 NamingEnumeration attset = a.getAll();
64                 while (attset.hasMore())
65                     entry.put((Attribute)attset.next());
66             }
67             catch (NamingException e)
68             {
69                 log.log(Level.WARNING, "unusual error in OfflineBroker::updateAttributes", e);
70             }
71         }
72         
73         /**
74          * Returns enumeration of Children as NameClassPairs
75          */

76          
77         public DXNamingEnumeration getChildren()
78         {
79             DXNamingEnumeration result = new DXNamingEnumeration();
80             for (int i=0; i<children.size(); i++)
81                 result.add(((Node)children.elementAt(i)).getNameClassPair());
82             return result;
83         }
84      
85         /**
86          * Returns enumeration of children as Nodes
87          */

88          
89         public NamingEnumeration getChildNodes()
90         {
91             DXNamingEnumeration result = new DXNamingEnumeration();
92             for (int i=0; i<children.size(); i++)
93                 result.add(children.elementAt(i));
94             return result;
95         }
96
97         /**
98          * Gets a NameClassPair for the present node, i.e.
99          * something like NameClassPair(cn=Fred Bloggs, cn)
100          */

101         public NameClassPair getNameClassPair() { return namePair; }
102         
103         /**
104          * Get Attributes for current Node.
105          */

106         public DXEntry getEntry() { return entry; }
107         
108         /**
109          * Gets the full dn for the current node.
110          */

111         public DN getDN() { return dn; }
112         
113         /**
114          * Looks up the parent in the big nodes Hashtable.
115          * @return Returns null if the parent isn't found,
116          * returns parent node otherwise.
117          */

118          
119         public Node getParent()
120         {
121             DN parentDN = dn.parentDN();
122             if (parentDN == null) return null;
123             Node Parent = (Node)nodes.get(parentDN.toString());
124             return Parent;
125         }
126         
127         public String JavaDoc toString() { return dn.toString(); }
128     }
129
130     /**
131      * Constructor for Offline Broker does nothing except
132      * initialise the big hashtable that is at the core
133      * of the class.
134      */

135     public OfflineBroker(Component JavaDoc graphicsDisplay)
136     {
137         display = graphicsDisplay;
138         nodes = new Hashtable(1000);
139     }
140
141     /**
142      * Empties the core Hashtable in preparation for a new
143      * ldif file to be read in.
144      */

145      
146      public void clear()
147      {
148          nodes.clear();
149      }
150
151     /**
152      * gets the children of a particular DN as an enumeration
153      * @param nodeDN the DN to retrieve children for
154      *
155      * @return an enumeration of NameClassPair-s to be the
156      * sub-nodes of the given node. returns null if nodeDN
157      * not found at all.
158      */

159      
160      public DXNamingEnumeration children(DN nodeDN)
161      {
162          Node N = (Node)nodes.get(nodeDN.toString());
163          return (N==null)? null : N.getChildren() ;
164      }
165     
166
167     /**
168      * whether the data source is currently on-line.
169      * @return on-line status
170      */

171      
172      public boolean isActive() { return true; }
173
174     /**
175      * Whether there are any nodes in our offline broker (effectively, if the ldif file read was successful)
176      * @return
177      */

178      public boolean hasData() { return !nodes.isEmpty(); }
179
180     /**
181      * Gets a list of all known schemaOps object classes.
182      * @return all known object classes, as . This will be
183      * null if this data source does not support
184      * this feature.
185      */

186     public Vector objectClasses() { return null; }
187     
188     /**
189      * Gets a list of the object classes most likely
190      * to be used for the next Level of the DN...
191      * @param dn the dn of the parent to determine likely
192      * child object classes for
193      * @return list of recommended object classes...
194      */

195      
196      public Vector recommendedObjectClasses(DN dn) { return null; }
197      
198      /**
199       * Returns the context for the schemaOps. This
200       * may be null if the directory does not support
201       * schemaOps.
202       * @return null - not implemented.
203       */

204       
205      public SchemaOps getSchemaOps() { return null; }
206      
207    /**
208     * Make a new entry with the provided DN.
209     * @param entry the DN and attributes of the new object.
210     * @return the operation's success status
211     */

212     
213     protected boolean addNode(DXEntry entry)
214     {
215         DN nodeDN = entry.getDN();
216         
217         log.fine("adding node " + nodeDN);
218         
219         Node N = new Node(entry);
220         nodes.put(nodeDN.toString(), N);
221         Node P = N.getParent();
222         
223         if (P==null)
224         {
225             if (nodeDN.size()>1) // so there *should* be a parent!
226
{
227                 addNode(new DXEntry(new DXAttributes(new DXAttribute("structuralTreeNode", "true")), nodeDN.parentDN())); // add a 'fake' node to pad the tree out...
228
P = (Node)nodes.get(nodeDN.parentDN().toString());
229             }
230         }
231         log.fine("parent = " + ((P==null)?"null":P.toString()));
232         if (P != null) P.addChild(N);
233         return true; // not very discriminating
234
}
235     
236    /**
237     * Update an entry with the designated DN.
238     * @param oldSet the old set of attributes of the object.
239     * @param newSet the replacement set of attributes..
240     * @return the operation's success status
241     */

242    
243     public boolean updateNode(DXEntry oldSet, DXEntry newSet)
244     {
245         log.fine("offline cache updating " + oldSet.getDN().toString());
246         Node N = (Node)nodes.get(oldSet.getDN().toString());
247         if (N==null) return false;
248         N.updateAttributes(newSet);
249         return true;
250     }
251     
252    /**
253     * deletes an entry with the given DN. If the entry has subordinates,
254     * they are also deleted.
255     *
256     * @param nodeDN the DN of the tree root to delete (may be a single entry).
257     * @return the operation's success status
258     */

259     
260     public boolean deleteTree(DN nodeDN) // may be a single node.
261
{
262         log.fine("offline cache deleting " + nodeDN.toString());
263         Node N = (Node)nodes.get(nodeDN.toString());
264         
265         if (N==null) return false;
266         
267         Enumeration children = N.getChildNodes();
268         while (children.hasMoreElements())
269             deleteTree(((Node)children.nextElement()).getDN());
270             
271         nodes.remove(nodeDN.toString());
272         Node parent = N.getParent(); // this node tells its parent to remove this
273
if (parent != null) parent.removeChild(N); // node from the parent's child list...
274
return true;
275     }
276     
277    /**
278     * Moves a DN to a new DN, including all subordinate entries.
279     * (nb it is up to the implementer how this is done; e.g. if it is an
280     * ldap broker, it may choose rename, or copy-and-delete, as appropriate)
281     *
282     * @param oldNodeDN the original DN of the sub tree root (may be a single
283     * entry).
284     * @param newNodeDN the target DN for the tree to be moved to.
285     */

286     
287     public void move(DN oldNodeDN, DN newNodeDN) // may be a single node.
288
throws NamingException
289     {
290         unthreadedCopy(oldNodeDN, newNodeDN); // brutal...
291
deleteTree(oldNodeDN); // ... but it works.
292
}
293     
294
295     
296     
297    /**
298     * Checks whether the current data source is modifiable. (Nb.,
299     * a directory may have different access controls defined on
300     * different parts of the directory: if this is the case, the
301     * directory may return true to isModifiable(), however a
302     * particular modify attempt may still fail.
303     *
304     * @return whether the directory is modifiable
305     */

306     
307     public boolean isModifiable() { return true; }
308     
309
310
311     /**
312      * We don't actually have an underlying DirContext, so return null...
313      */

314      
315      public DirContext getDirContext() { return null; }
316      
317      
318      
319     /**
320      * Method for the Broker interface - chains to
321      * children().
322      */

323      
324     public DataQuery doListQuery(DataQuery request)
325     {
326         request.setEnum(children(request.requestDN()));
327         return request;
328     }
329                 
330     /**
331      * Method for the Broker interface - chains to
332      * search().
333      */

334      
335     public DataQuery doSearchQuery(DataQuery request)
336     {
337         request.setException(new Exception JavaDoc("offline searches not allowed"));
338         return request;
339     }
340                 
341                 
342     /**
343      * Method for the Broker interface - chains to
344      * getObjectClasses().
345      */

346      
347     public DataQuery doGetAllOCsQuery(DataQuery request)
348     {
349         request.setException(new Exception JavaDoc("offline object class list not implemented"));
350         return request;
351     }
352                 
353     /**
354      * Method for the Broker interface - chains to
355      * getRecommendedObjectClasses.
356      */

357      
358     public DataQuery doGetRecOCsQuery(DataQuery request)
359     {
360         request.setException(new Exception JavaDoc("offline object class list not implemented"));
361         return request;
362     }
363     
364     /**
365      * returns the next level of a directory tree, returning
366      * a Enumeration of the results
367      *
368      * @param searchbase the node in the tree to expand
369      * @return list of results (NameClassPair); the next layer of the tree...
370      */

371      
372     public DXNamingEnumeration unthreadedList(DN searchbase)
373     {
374         return children(searchbase);
375     }
376         
377     /**
378      * Not Implemented.
379      *
380      * @param dn the distinguished name (relative to initial context in ldap) to seach from.
381      * @param filter the non-null filter to use for the search
382      * @param search_level whether to search the base object, the next level or the whole subtree.
383      * @param returnAttributes a vector of string names of attributes to return in the search. (Currently inoperative)
384      * @return list of results ('SearchResult's); the next layer of the tree...
385      */

386      
387     public DXNamingEnumeration unthreadedSearch(DN dn, String JavaDoc filter, int search_level, String JavaDoc[] returnAttributes)
388     {
389         return null;
390     }
391     
392    /**
393     * Copies a DN representing a subtree to a new subtree, including
394     * copying all subordinate entries.
395     *
396     * @param oldNodeDN the original DN of the sub tree root
397     * to be copied (may be a single entry).
398     * @param newNodeDN the target DN for the tree to be moved to.
399     */

400     
401     public void unthreadedCopy(DN oldNodeDN, DN newNodeDN)
402         throws NamingException
403     {
404         Node Old = (Node)nodes.get(oldNodeDN.toString()); // get the Node to copy
405
if (Old==null)
406             throw new NamingException("null old dn passed to unthreaded copy"); // sanity check
407

408         addNode(new DXEntry(Old.getEntry(), newNodeDN)); // create a copy of Old
409
Node New = (Node)nodes.get(newNodeDN.toString()); // get the newly created copy
410
Enumeration children = Old.getChildNodes(); // get the old nodes children...
411
while (children.hasMoreElements()) // ...and for each child
412
{
413             Node child = (Node)children.nextElement(); // identify the child node
414
DN NewChildDN = new DN(New.getDN()); // get the 'New' nodes DN...
415
NewChildDN.addChildRDN(child.getDN().getLowestRDN().toString()); // ... and add to it the child rdn that is being copied
416
unthreadedCopy(child.getDN(),NewChildDN); // copy (and therefore create) the child node copy
417
}
418     }
419     
420
421
422    /**
423     * Checks the existence of a particular DN, without (necessarily)
424     * reading any attributes.
425     * @param nodeDN the DN to check.
426     * @return the existence of the nodeDN (or false if an error occurs).
427     */

428     
429     public boolean unthreadedExists(DN nodeDN)
430     {
431         return nodes.containsKey(nodeDN.toString());
432     }
433     
434     /**
435      * Not implemented.
436      */

437
438     public Vector unthreadedGetAllOCs() { return null; }
439
440     /**
441      * Reads an entry with all its attributes from
442      * the directory.
443      * @param entryDN the DN of the object to read.
444      * @param returnAttributes a vector of string names of attributes to return in the search.
445      * (null means 'return all entries', a zero length array means 'return no attributes'.)
446      */

447      
448     public DXEntry unthreadedReadEntry(DN entryDN, String JavaDoc[] returnAttributes)
449     {
450         if (returnAttributes != null)
451             log.info("warning: att list read entries not implemented in offline broker");
452             
453         Node N = (Node)nodes.get(entryDN.toString());
454         return (N==null)? new DXEntry(entryDN) : N.getEntry();
455     }
456         
457         
458    /**
459     * Update an entry with the designated DN.
460     * @param oldEntry the old set of attributes of the object.
461     * @param newEntry the replacement set of attributes..
462     */

463     
464     public void unthreadedModify(DXEntry oldEntry, DXEntry newEntry)
465         throws NamingException
466     {
467         if (oldEntry == null && newEntry == null)
468         {
469              // nothing to do.
470
}
471         else if (oldEntry == null) // add
472
{
473             addNode(newEntry);
474         }
475         else if (newEntry == null) // delete
476
{
477             deleteTree(oldEntry.getDN());
478         }
479         else
480         {
481
482             // remove naming attributes to avoid name/dn conflicts...
483
// XXX work to do here supporting multi-valued naming atts...
484

485             RDN singleValRDN = oldEntry.getDN().getLowestRDN();
486             String JavaDoc namingAtt = singleValRDN.getAtt();
487             String JavaDoc namingVal = singleValRDN.getRawVal();
488             oldEntry.remove(namingAtt);
489             newEntry.remove(namingAtt);
490             newEntry.put(new DXAttribute(namingAtt, namingVal));
491
492             if (oldEntry.getDN().equals(newEntry.getDN()) == false)
493             {
494                 move(oldEntry.getDN(), newEntry.getDN());
495                 oldEntry.putDN(newEntry.getDN());
496             }
497
498             // check for change of attributes done in modify()
499

500             updateNode(oldEntry, newEntry);
501         }
502     }
503
504     /**
505      * Not implemented.
506      * @param dn the dn of the parent to determine likely
507      * child object classes for
508      * @return list of recommended object classes...
509      */

510     
511     public ArrayList unthreadedGetRecOCs(DN dn) { return null; }
512      
513 }
Popular Tags