KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > directory > jxplorer > viewer > tableviewer > AttributeTableModel


1 package com.ca.directory.jxplorer.viewer.tableviewer;
2
3 import java.util.*;
4 import javax.swing.*;
5 import javax.swing.table.*;
6 import javax.swing.event.*;
7
8 import javax.naming.*;
9 import javax.naming.directory.*;
10
11 import com.ca.commons.naming.*;
12
13 public class AttributeTableModel extends AbstractTableModel
14 {
15
16     protected boolean dataChanged = false; // whether the user has modified the data.
17

18     int noRows = 0;
19
20     DXEntry oldEntry; // the original, unedited data
21

22     Vector attributeTypes = new Vector(); // vector of string IDs
23
Vector attributeValues = new Vector(); // vector of attributeValues
24

25     /**
26      * The number of naming values (e.g. the length of the
27      * namingTypes/namingRawValues vectors).
28      */

29
30     int numberNamingValues;
31
32
33     /**
34      * <p>The ordered list of naming types (e.g. ['cn', 'id']) </p>
35      * <p>The namingTypes and namingRawValues arrays are set from
36      * the RDN. They are then used to identify the corresponding
37      * naming AttributeValues, which are used to recreate the RDN
38      * later (as required).</p>
39      * <p>So the logic goes RDN -> string arrays -> array of naming
40      * attributes -> RDN
41      */

42
43     String JavaDoc[] namingTypes;
44
45     /**
46      * The ordered list of naming values (e.g. ['Joe Bloggs', '7670001'])
47      */

48
49     String JavaDoc[] namingRawValues;
50
51     /**
52      * Returns the size of the naming RDN.
53      */

54
55     public int getRDNSize()
56     {
57         return numberNamingValues;
58     }
59
60     /**
61      * Returns the class of the objects in the different columns:
62      * AttributeType.class for col 0, AttributeValue.class for col 1.
63      */

64
65     public Class JavaDoc getColumnClass(int c)
66     {
67         return (c==1)?AttributeValue.class: AttributeType.class;
68     }
69
70     /**
71      * Returns number of columns (=2)
72      */

73     public int getColumnCount() { return 2; }
74
75     /**
76      * Returns number of rows (varies dynamically)
77      */

78     public int getRowCount() { return noRows;}
79
80     /**
81      * Allows a cell value to be set (should only ever be the
82      * second column, col=1).
83      */

84     public void setValueAt(Object JavaDoc aValue,int row,int col)
85     {
86         dataChanged = true;
87
88         if (col == 1) // which it jolly well should...
89
{
90             if (aValue instanceof AttributeValue) // replace an attributeValues
91
{
92                 attributeValues.set(row, aValue);
93             }
94             else // ... or update it.
95
{
96                 ((AttributeValue)attributeValues.elementAt(row)).update(aValue);
97             }
98             fireTableCellUpdated(row, col);
99         }
100     }
101
102     /**
103      * Returns a value as a string. Null and zero length string are
104      * made 1 character blank strings, so that the joke called swing
105      * printing can be kludged to work.
106      */

107
108     public String JavaDoc getStringValueAt(int row, int col)
109     {
110         String JavaDoc s = getValueAt(row,col).toString();
111         if ((s == null) || (s.length()==0))
112             s = " ";
113         return s;
114     }
115
116     /**
117      * Return the object at a given position.
118      */

119     public Object JavaDoc getValueAt(int row, int col)
120     {
121         return (col==0)?attributeTypes.elementAt(row):attributeValues.elementAt(row);
122     }
123
124     /**
125      * Whether a particular column is editable (yes if col!=0)
126      */

127     public boolean isCellEditable(int row, int col)
128     {
129         if (col == 0) return false; // can't edit attribute names
130
if (col > 1) return false; // should never happen.
131
if (attributeTypes.elementAt(row).toString().equalsIgnoreCase("objectclass"))
132             return false; // can't edit object classes (this way)
133

134         return true;
135     }
136
137     /**
138      * Gets column header names.
139      */

140     public String JavaDoc getColumnName(int columnIndex)
141     {
142         return (columnIndex == 0)?("attribute type"):("value");
143     }
144
145     /**
146      * 'Resets' the value of all attribute Value cells back to their original value.
147      */

148
149     public void reset()
150     {
151         dataChanged = false;
152
153         /*
154          * Return each attribute to the original value.
155          */

156
157         for (int i=0; i<attributeValues.size(); i++)
158             ((AttributeValue)attributeValues.elementAt(i)).reset();
159
160         /*
161          * Return the naming attribute list to the original
162          * (if necessary)
163          */

164
165         RDN rdn = oldEntry.getRDN();
166
167         if (rdn.equals(getRDN()) == false)
168             setRDN(rdn);
169
170         /*
171          * All done - and the data has probably changed!
172          */

173
174         fireChange();
175     }
176
177
178     /**
179      * Removes all data leaving an empty table.
180      */

181     public void clear()
182     {
183         dataChanged = false; // well, it sorta has I guess, but this is only done when
184
// we're starting from scratch.
185

186         noRows = 0;
187         attributeTypes.clear();
188         attributeValues.clear();
189         fireChange();
190
191     }
192
193     /**
194      * Insert a set of attributes into the table.
195      */

196
197     public void insertAttributes(DXEntry entry)
198     {
199
200         /*
201          * Check that we've got data to edit.
202          */

203
204         if (entry==null) return;
205
206         /*
207          * Clear the decks for the new entry.
208          */

209
210         oldEntry = entry;
211         noRows = 0;
212         attributeTypes.clear();
213         attributeValues.clear();
214
215         /*
216          * work through the attributes, adding each attribute to the
217          * table model.
218          */

219
220         try
221         {
222             /*
223              * First, figure out the naming attibutes. setRDN sets
224              * the string array of naming types/values. Once set, these
225              * are used by insertAttribute to mark them as special values.
226              */

227
228             RDN rdn = entry.getRDN();
229             setRDN(rdn);
230
231             /*
232              * First, get the mandatory attributes which every entry 'MUST' contain.
233              */

234
235             DXNamingEnumeration mandatory = (DXNamingEnumeration)entry.getMandatory();
236
237             while (mandatory.hasMore())
238                 insertAttribute(((DXAttribute)mandatory.next()), AttributeType.MANDATORY);
239
240             /*
241              * Then add the 'MAY' contain optional attributes.
242              */

243
244             DXNamingEnumeration active = (DXNamingEnumeration)entry.getAllNonNull();
245             active.sort();
246
247             while (active.hasMore())
248             {
249                 DXAttribute temp = (DXAttribute) active.next();
250
251                 if (mandatory.contains(temp)==false && (temp.size()>0) && (temp.get() != null))
252                 {
253                     temp.sort();
254                     insertAttribute(temp, AttributeType.NORMAL);
255                 }
256             }
257
258             // finally add attributes without values (i.e. ones that the user could add)
259
// XXX need special code for null Binary attributes...
260

261             DXNamingEnumeration possible = (DXNamingEnumeration)entry.getAll();
262             possible.sort();
263
264             while (possible.hasMore())
265             {
266                 DXAttribute temp = (DXAttribute) possible.next();
267                 if (mandatory.contains(temp)==false && ((temp.size()==0) || (temp.get() == null)))
268                 {
269                     insertAttribute(temp, AttributeType.NORMAL);
270                 }
271             }
272
273             fireChange();
274
275             // This particular action we ignore, since it is the one that initially
276
// sets up the table.
277
dataChanged = false;
278         }
279         catch (NamingException e)
280         {
281             System.err.println("Naming Exception in AttributeTableModel: " + e);
282         }
283         catch (Exception JavaDoc e2)
284         {
285             System.err.println("Unexpected Exception in AttributeTableModel: " + e2);
286             e2.printStackTrace();
287         }
288
289     }
290
291     /**
292      * Sets up the list of naming attribute types - values pairs.
293      * (usually there is only ONE naming value, but sometimes an
294      * entry is multi valued).
295      * @param rdn the RDN to extract the naming information from.
296      */

297
298     protected void setRDN(RDN rdn)
299     {
300         numberNamingValues = rdn.size(); // almost always 1, but sometimes...
301
namingTypes = new String JavaDoc[numberNamingValues];
302         namingRawValues = new String JavaDoc[numberNamingValues];
303
304         for (int i=0; i<numberNamingValues; i++)
305         {
306             namingTypes[i] = rdn.getAtt(i);
307             namingRawValues[i] = rdn.getRawVal(i);
308         }
309     }
310
311
312
313     /**
314      * Adds a single attribute, and (possibly multiple, or blank) values
315      * to the table.
316      */

317
318     public void insertAttribute(DXAttribute att, int type)
319         throws NamingException
320     {
321         //boolean addingNamingValue = false;
322
String JavaDoc namingValue = null; // the exact naming value for this attribute (if any)
323

324         String JavaDoc ID = att.getID();
325         NamingEnumeration values = att.getAll();
326         //shiba modified to enable list selection
327
AttributeValue newAV = new AttributeValue(ID, ""); ;
328
329         /*
330          * Add the Attribute to the internal data vectors.
331          */

332
333         if (att.size() == 0) // the attribute has no data (although the user may enter some later)
334
{
335             newAV = new AttributeValue(ID, "");
336             if (att.isString() == false)
337             {
338                 newAV.setBinary(true);
339             }
340             addAttribute(ID, newAV, type);
341         }
342         else // The attribute already has one or more data values.
343
{
344             /*
345              * Check if we're adding a naming value - returns null if not...
346              */

347
348             namingValue = getAnyNamingValue(ID);
349             // XXX If we want to support binary naming attributes, we would need to do some
350
// nifty base-64 encoding comparison stuff here...
351
if (namingValue != null && att.isString() == false)
352                 throw new NamingException("Binary naming attributes not supported in JXplorer: can't use attribute " + ID + " to name an entry");
353
354             while (values.hasMore())
355             {
356
357                 newAV = new AttributeValue(ID, values.next());
358
359                 /*
360                  * Set a Binary Attribute
361                  */

362
363                 if (att.isString()==false)
364                 {
365                     newAV.setBinary(true);
366                 }
367
368                 /*
369                  * Checks (and possibly Flags) that an AttributeValue
370                  * is a Naming Value.
371                  */

372
373                 if (namingValue != null && newAV.getStringValue().equalsIgnoreCase(namingValue))
374                         newAV.setNamingStatus(true);
375
376                 /*
377                  * Adds the attribute to the table.
378                  */

379
380                 addAttribute(ID, newAV, type);
381             }
382         }
383         //shiba modified to enable list selection
384
if (att instanceof DXAttribute)
385         {
386             if (((DXAttribute)att).hasOptions())
387                 newAV.setOptions(((DXAttribute)att).getOptions());
388             newAV.setBinary(!((DXAttribute)att).isString());
389         }
390     }
391
392
393     /**
394      * Determines whether a particular attribute ID is part of an RDN Attribute Value Assertion (AVA),
395      * and if so, returnes the attribute value (for visual tagging in the display later on).
396      *
397      * @param ID the attribute ID to be tested, e.g. "cn"
398      * @return the value (if any) corresponding to this i.d. - eg. "smith" if the rdn was "cn=smith" and "cn" was passed in.
399      */

400     private String JavaDoc getAnyNamingValue(String JavaDoc ID)
401     {
402         for (int i=0; i<numberNamingValues; i++)
403             if (ID.equalsIgnoreCase(namingTypes[i]))
404                 return namingRawValues[i];
405
406         return null; // no value found.
407
}
408
409
410
411     public void addAttribute(String JavaDoc ID, AttributeValue val, int type)
412     {
413         attributeTypes.add(new AttributeType(ID, (type==AttributeType.MANDATORY)));
414         attributeValues.add(val);
415         noRows++;
416     }
417
418     public void addAttribute(String JavaDoc ID, AttributeValue val, int type, int indexPos)
419     {
420         attributeTypes.add(indexPos, new AttributeType(ID, (type==AttributeType.MANDATORY)));
421         attributeValues.add(indexPos, val);
422         noRows++;
423     }
424
425     public void deleteAttribute(String JavaDoc ID, int indexPos)
426     {
427         if (attributeTypes.elementAt(indexPos).toString().equals(ID))
428         {
429             ((AttributeValue)attributeValues.elementAt(indexPos)).update(new String JavaDoc(""));
430         }
431         else
432             System.err.println("Internal error: attempt to delete attribute with invalid ID in AttributeTableModel"+
433                                "\n att name = " + attributeTypes.elementAt(indexPos).toString() + " ID = " + ID);
434     }
435
436     public void fireChange()
437     {
438         dataChanged = true;
439
440         fireTableChanged(new TableModelEvent(this));
441     }
442
443     public DXEntry getOldEntry()
444     {
445         return oldEntry;
446     }
447
448     /**
449      * <p>Returns the escaped RDN (possibly multi-valued).</p>
450      *
451      * <p>Implementation Note: The returned RDN is created based on the internal naming
452      * type/value arrays, which must be synched with the user modified
453      * attribute list</p>
454      */

455
456     public RDN getRDN()
457     {
458         String JavaDoc rdn = "";
459         for (int i=0; i<attributeValues.size(); i++)
460         {
461             AttributeValue entryValue = (AttributeValue)attributeValues.get(i);
462             if (entryValue.isNaming())
463             {
464                 if (rdn.length()>0)
465                     rdn += "+";
466                 rdn += attributeTypes.get(i).toString() + "=" + NameUtility.escape(entryValue.getStringValue());
467             }
468         }
469
470         // in some ultra-wierd cases, the naming attribute can be made invisible due to access controls. While
471
// you might think anyone who does this gets what they deserve, we try to recover by using the 'old entry'
472
// DN.
473

474         if ("".equals(rdn))
475             rdn = oldEntry.getRDN().toString();
476
477
478         return new RDN(rdn);
479 /*
480         StringBuffer rdn = new StringBuffer();
481         for (int i=0; i<numberNamingValues; i++) // usually only 1...
482         {
483             if (i > 0)
484                 rdn.append('+');
485
486             rdn.append(namingTypes[i]);
487             rdn.append('=');
488             rdn.append(NameUtility.escape(namingRawValues[i]));
489         }
490         return new RDN(rdn.toString());
491 */

492     }
493
494     /**
495      * Returns a new entry
496      */

497
498     public DXEntry getNewEntry()
499     {
500         /*
501          * Sort out the name of the entry, based on the (possibly)
502          * edited attribute value fields.
503          */

504
505         DN newDN = new DN(oldEntry.getDN());
506
507
508         RDN newRDN = getRDN();
509
510
511
512         newDN.setRDN(newRDN, newDN.size()-1);
513
514         /*
515          * Create an empty DXEntry object, initialised with the new name.
516          */

517
518         DXEntry newEntry = new DXEntry(newDN);
519
520         /*
521          * Work through all the known attributes, adding the atts to the
522          * new entry.
523          */

524
525         AttributeValue test;
526         String JavaDoc id;
527
528         for (int i=0; i<attributeTypes.size(); i++)
529         {
530             test = (AttributeValue)attributeValues.elementAt(i);
531             if (!test.isEmpty())
532             {
533                 id = attributeTypes.elementAt(i).toString();
534                 BasicAttribute exists = (BasicAttribute)newEntry.get(id);
535                 if (exists == null) // no values of this att. already registered
536
newEntry.put(new BasicAttribute(id, test.value()));
537                 else
538                     exists.add(test.value());
539             }
540         }
541
542         if (oldEntry.getStatus() == DXEntry.NEW) // old entry isn't in directory yet.
543
{
544             newEntry.setStatus(DXEntry.NEW);
545         }
546
547         return newEntry;
548     }
549
550     /**
551      * Reads all the values for a given attribute
552      * from the table.
553      */

554     public Attribute getAttribute(String JavaDoc ID)
555     {
556         BasicAttribute returnAtt = new BasicAttribute(ID);
557         for (int i=0; i<attributeTypes.size(); i++)
558             if (ID.equals(attributeTypes.elementAt(i).toString()))
559             {
560                 Object JavaDoc o = ((AttributeValue)attributeValues.elementAt(i)).value();
561
562                 // don't allow zero length string attributes...
563
if (o!= null && o instanceof String JavaDoc)
564                 {
565                     if (((String JavaDoc)o).length() == 0)
566                         o = null;
567                 }
568
569                 if (o != null) // only add if there is a real value...
570
returnAtt.add(o);
571
572             }
573
574         return returnAtt;
575     }
576
577     /**
578      * Brute force search to find an attributeType given only the name.
579      * rarely used - main use is when popupTool tries to create a new
580      * attribute value entry, knowing only the type name.
581      */

582
583     public boolean isMandatory(String JavaDoc attributeTypeName)
584     {
585         for ( int i=0; i<attributeTypes.size(); i++)
586         {
587             if (((AttributeType)attributeTypes.elementAt(i)).toString().equals(attributeTypeName))
588             {
589                 return ((AttributeType)attributeTypes.elementAt(i)).isMandatory();
590             }
591         }
592         System.err.println("unable to find type name " + attributeTypeName);
593         return false; // couldn't find it.
594
}
595
596     /**
597      * Checks that all mandatory attributes have at least one value entered.
598      */

599
600     // surprisingly messy ftn.
601
// Check through type list...
602
// find new type
603
// check if mandatory
604
// if mandatory, check values
605
// -> if no values found, return false
606
// continue until no types left.
607

608     public boolean checkMandatoryAttributesSet()
609     {
610         AttributeType type, testType;
611         AttributeValue value;
612         String JavaDoc ID = "";
613         boolean inDoubt = false;
614         int i=0;
615
616         while (i<noRows) // for all rows
617
{
618             type = (AttributeType)attributeTypes.elementAt(i);
619
620             if (type.isMandatory()) // find mandatory types
621
{
622                 ID = type.toString();
623                 inDoubt = true;
624                 testType = type;
625
626                 while (ID.equals(testType.toString()) && i<noRows) // cycle through all the values for that
627
{ // mandatory attribute...
628
if (inDoubt) // ... until we find a valid value
629
{
630                         value = (AttributeValue)attributeValues.elementAt(i);
631                         if (value.isEmpty()==false) // !!! found a valid value
632
inDoubt = false;
633                     }
634                     i++;
635                     if (i<noRows) testType = (AttributeType)attributeTypes.elementAt(i);
636                 }
637
638                 if (inDoubt) // Iff still in doubt, means no valid value was found
639
return false; // *** RETURN FALSE *** - mandatory value not filled in!
640
}
641             else
642             {
643                 i++;
644             }
645         }
646
647         return true; // *** RETURN TRUE *** - no unfilled out mandatory value found.
648
}
649
650     /**
651      * This removes a component from the array of naming atts, and
652      * sets the currentValue object to be a naming value.
653      */

654
655     public void removeNamingComponent(AttributeType currentType, AttributeValue currentValue)
656     {
657
658         try
659         {
660             String JavaDoc type = currentType.getValue();
661             String JavaDoc value = currentValue.getStringValue();
662
663             if ("".equals(type) || "".equals(value)) // which it really, really shouldn't...
664
return;
665             if (numberNamingValues == 1) // it would be a bad idea to remove the last naming value
666
return;
667
668             dataChanged = true;
669
670             for (int i=0; i<numberNamingValues; i++)
671             {
672                 if (type.equals(namingTypes[i]) && value.equals(namingRawValues[i]))
673                 {
674                     int removeRow = i;
675                     namingTypes = removeRowFromArray(namingTypes, removeRow);
676                     namingRawValues = removeRowFromArray(namingRawValues, removeRow);
677                     numberNamingValues--;
678                     break;
679                 }
680             }
681
682             for (int i=0; i<attributeValues.size(); i++)
683             {
684                 AttributeValue attval = (AttributeValue)attributeValues.get(i);
685                 if (attval.getID().equals(type))
686                     if (attval.getStringValue().equals(value))
687                     {
688                         attval.setNamingStatus(false);
689                     }
690             }
691         }
692         catch (Exception JavaDoc e) // nope, we won't be doing that.
693
{
694             e.printStackTrace();
695             return;
696         }
697
698     }
699
700
701     protected static String JavaDoc[] removeRowFromArray(String JavaDoc[] array, int removeRow)
702     {
703         int originalLength = array.length;
704         if (removeRow < 0 || removeRow >= originalLength)
705             return array;
706
707         String JavaDoc[] temp = new String JavaDoc[array.length-1];
708
709         if (removeRow > 0)
710             System.arraycopy(array, 0, temp, 0, removeRow);
711
712         if (removeRow < originalLength-1)
713             System.arraycopy(array, removeRow+1, temp, removeRow, (originalLength-removeRow-1));
714
715         return temp;
716     }
717
718
719     public void dumpNamingArrays()
720     {
721         System.out.println("dump naming array");
722         for (int i=0; i<numberNamingValues; i++)
723         {
724             System.out.println(i + " type " + namingTypes[i]);
725             System.out.println(i + " value " + namingRawValues[i]);
726         }
727     }
728
729
730     public void addNamingComponent(AttributeType currentType, AttributeValue currentValue)
731     {
732
733         String JavaDoc type = currentType.getValue();
734         String JavaDoc value = currentValue.getStringValue();
735
736         if ("".equals(type) || "".equals(value)) // which it really, really shouldn't...
737
return;
738
739         dataChanged = true;
740
741         String JavaDoc[] tempTypes = new String JavaDoc[numberNamingValues+1];
742         String JavaDoc[] tempRawValues = new String JavaDoc[numberNamingValues+1];
743
744         System.arraycopy(namingTypes, 0, tempTypes, 0, numberNamingValues);
745         System.arraycopy(namingRawValues, 0, tempRawValues, 0, numberNamingValues);
746
747         tempTypes[numberNamingValues] = type;
748         tempRawValues[numberNamingValues] = value;
749
750         numberNamingValues++;
751
752         namingTypes = tempTypes;
753         namingRawValues = tempRawValues;
754
755         currentValue.setNamingStatus(true);
756     }
757
758
759
760     /**
761      * This returns whether the table data has been modified
762      * since the original display of the entry.
763      */

764
765     public boolean changedByUser()
766     {
767         return dataChanged;
768     }
769 }
Popular Tags