Source code: com/sample/addressbook/dumbdb/DumbDB.java
1 /*
2 * DumbDB.java
3 *
4 * Copyright (c) 2001, 2002 Aendvari, Ltd. All Rights Reserved.
5 *
6 * See the file LICENSE for terms of use.
7 *
8 */
9
10 package com.sample.addressbook.dumbdb;
11
12 import java.util.*;
13 import java.io.*;
14
15 import javax.servlet.*;
16 import javax.servlet.http.*;
17
18 import java.beans.*;
19 import java.lang.reflect.*;
20 import java.lang.NoSuchMethodException;
21 import java.lang.IllegalAccessException;
22
23 import com.aendvari.common.model.*;
24 import com.aendvari.common.model.xalan.*;
25
26 import com.aendvari.griffin.util.XmlUtil;
27 import com.aendvari.griffin.bean.transform.BeanTransformer;
28 import com.aendvari.griffin.bean.transform.InspectedBean;
29
30 import com.aendvari.common.util.*;
31
32
33 /**
34 * <p>This class is used to fake a dumb database.</p>
35 *
36 * <p>
37 * It is only used for this application so that it can be demonstrated without
38 * the need of a proper database.
39 * </p>
40 *
41 * <p>Please <b>do not</b> use this class for anything other than testing/prototype purposes.</p>
42 *
43 * @author Scott Milne
44 *
45 */
46
47 public class DumbDB
48 {
49 /* Variables */
50
51 /** The "database". */
52 private TreeMap database;
53
54 /* The auto incremental */
55 private int increment;
56
57 /* Path to the XML files for the data */
58 private String path;
59
60
61 /* Static methods */
62 public static DumbDB getDumbDB(HttpServletRequest request, String attrName)
63 {
64 return (DumbDB)request.getSession().getAttribute(attrName);
65 }
66
67
68 /* Internal Classes */
69
70 private class EntryComparator implements Comparator
71 {
72 public int compare(Object object1, Object object2)
73 {
74 String data1 = (String)object1;
75 String data2 = (String)object2;
76
77 //return Integer.parseInt(data1) < Integer.parseInt(data2);
78 return data1.compareToIgnoreCase(data2);
79 }
80 }
81
82
83 /* Constructors */
84
85 /** DO NOT USE THIS DIRECTLY */
86 protected DumbDB()
87 {
88 database = new TreeMap(new EntryComparator());
89 increment = 0;
90 this.path = "";
91 }
92
93 public DumbDB(String path)
94 {
95 database = new TreeMap(new EntryComparator());
96 increment = 0;
97 this.path = path;
98
99 loadDumbDb(this, path);
100 }
101
102
103 /* Accessors */
104
105 public TreeMap getDatabase() { return database; }
106 public void setDatabase(TreeMap db) { database = db; }
107 public ArrayList getAllEntries() { return new ArrayList(database.values()); }
108
109 public int newIncrement() { return ++increment; }
110 public int getIncrement() { return increment; }
111 public void setIncrement(int inc) { increment = inc; }
112
113
114 /* Methods */
115
116 public String toString()
117 {
118 String data = "DumbDB[";
119 data += "increment="+increment+",";
120 data += "path="+path+",";
121 data += "database="+database+"]";
122 return data;
123 }
124
125 /**
126 * Get an object from the db by it's ID.
127 *
128 * @param id The id to which the object is related.
129 *
130 */
131
132 public Object getObjectById( String id )
133 {
134 return database.get(id);
135 }
136
137 /**
138 * Update an object in the db by it's ID.
139 *
140 * @param id The id to which the object is related.
141 * @param data The data object to store.
142 *
143 */
144
145 public void updateObjectById( String id, Object data )
146 {
147 database.put(id, data);
148 saveDumbDb(this, path);
149 }
150
151 /**
152 * Delete an object in the db by it's ID.
153 *
154 * @param id The id to which the object is related.
155 * @param data The data object to store.
156 *
157 */
158
159 public void deleteObjectById( String id )
160 {
161 database.remove(id);
162 saveDumbDb(this, path);
163 }
164
165 /**
166 * Insert an object into the db by it's ID.
167 *
168 * @param data The data object to store.
169 *
170 */
171
172 public void insertObject( Object data )
173 {
174 String id = Integer.toString(getIncrement());
175
176 database.put(id, data);
177
178 saveDumbDb(this, path);
179 }
180
181 /**
182 * Extract an object from the db using the value of an attribute within the object.
183 * All attributes given must match for the object to be returned.
184 *
185 * @param attributes A HashMap of name/value atrributes
186 * @param likeMatch Should a "indexOf" match be used (true).
187 * False means "equals" is used.
188 *
189 */
190
191 public Object getObjectByAttributeValues(HashMap attributes, boolean likeMatch )
192 {
193 Object beanObj = null;
194
195 // go through each value array checking for the value
196 Iterator keysIterator = attributes.keySet().iterator();
197 while (keysIterator.hasNext())
198 {
199 // create the "key" node and examine the propery for the key
200 String attributeName = (String)keysIterator.next();
201 String attributeValue = (String)attributes.get(attributeName);
202
203 // if the value is blank, don't bother with it
204 if (attributeValue.equals(""))
205 {
206 continue;
207 }
208
209 StringTokenizer tokens = new StringTokenizer(attributeName, ".");
210 String segment = tokens.nextToken();
211
212 Object attribute = null;
213 Object tmpBeanObj = getObjectByAttributeValueInternal(segment, attributeValue);
214
215 if (tmpBeanObj != null)
216 {
217 attribute = getBeanProperty(tmpBeanObj, segment);
218
219 // stop when end of path is reached
220 while (tokens.hasMoreTokens())
221 {
222 // search children for next segment
223 segment = tokens.nextToken();
224
225 attribute = getBeanProperty(attribute, segment);
226
227 if (attribute != null)
228 {
229 Class valueClass = attribute.getClass();
230
231 if( valueClass.isAssignableFrom(String.class) )
232 {
233 String attrValue = (String)attribute;
234
235 if (likeMatch)
236 {
237 if (attrValue.indexOf(attributeValue) != -1)
238 {
239 beanObj = tmpBeanObj;
240 }
241 else
242 {
243 beanObj = null;
244 }
245 }
246 else
247 {
248 if (attrValue.equals(attributeValue))
249 {
250 beanObj = tmpBeanObj;
251 }
252 else
253 {
254 beanObj = null;
255 }
256 }
257 }
258 }
259 }
260 }
261 }
262
263 return beanObj;
264 }
265
266 /**
267 * Extract a collection of objects from the db using the name/value pairs within the object.
268 * All attributes given must match for the object to be returned.
269 *
270 * @param attributes A HashMap of name/value atrributes
271 * @param likeMatch Should a "indexOf" match be used (true).
272 * False means "equals" is used.
273 *
274 */
275
276 public Collection getObjectsByAttributeValues(HashMap attributes, boolean likeMatch )
277 {
278 ArrayList objects = new ArrayList();
279
280 // go through each value array checking for the value
281 Iterator keysIterator = attributes.keySet().iterator();
282 while (keysIterator.hasNext())
283 {
284 // create the "key" node and examine the propery for the key
285 String attributeName = (String)keysIterator.next();
286 String attributeValue = (String)attributes.get(attributeName);
287
288 // ignore empty query attributes
289 if (attributeValue.length() == 0) continue;
290
291 StringTokenizer tokens = new StringTokenizer(attributeName, ".");
292 String segment = tokens.nextToken();
293
294 Object attribute = null;
295 Collection beanObjs = getObjectsByAttributeValueInternal(segment, attributeValue );
296
297 Iterator beansIterator = beanObjs.iterator();
298 while (beansIterator.hasNext())
299 {
300 Object beanObj = beansIterator.next();
301 tokens = new StringTokenizer(attributeName, ".");
302
303 segment = tokens.nextToken();
304 attribute = getBeanProperty(beanObj, segment);
305
306 // stop when end of path is reached
307 while (tokens.hasMoreTokens())
308 {
309 // search children for next segment
310 segment = tokens.nextToken();
311
312 attribute = getBeanProperty(attribute, segment);
313
314 if (attribute != null)
315 {
316 Class valueClass = attribute.getClass();
317
318 if( valueClass.isAssignableFrom(String.class) )
319 {
320 String attrValue = (String)attribute;
321
322 if (likeMatch)
323 {
324 if (attrValue.indexOf(attributeValue) != -1)
325 {
326 objects.add(beanObj);
327 }
328 else
329 {
330 objects.remove(beanObj);
331 }
332 }
333 else
334 {
335 if (attrValue.equals(attributeValue))
336 {
337 objects.add(beanObj);
338 }
339 else
340 {
341 objects.remove(beanObj);
342 }
343 }
344 }
345 }
346 }
347 }
348 }
349
350 return objects;
351 }
352
353 /**
354 * Extract an object from the db using the value of an attribute within the object.
355 * This returns the first matching object.
356 *
357 * @param attributeName The name of the attribute.
358 * @param attributeValue The value of the attribute.
359 * @param likeMatch Should a "indexOf" match be used (true).
360 * False means "equals" is used.
361 *
362 */
363
364 public Object getObjectByAttributeValue(String attributeName, String attributeValue, boolean likeMatch )
365 {
366 StringTokenizer tokens = new StringTokenizer(attributeName, ".");
367 String segment = tokens.nextToken();
368
369 Object attribute = null;
370 Object beanObj = getObjectByAttributeValueInternal(segment, attributeValue );
371
372 if (beanObj != null)
373 {
374 attribute = getBeanProperty(beanObj, segment);
375
376 // stop when end of path is reached
377 while (tokens.hasMoreTokens())
378 {
379 // search children for next segment
380 segment = tokens.nextToken();
381
382 attribute = getBeanProperty(attribute, segment);
383
384 Class valueClass = attribute.getClass();
385 if( valueClass.isAssignableFrom(String.class) )
386 {
387 String attrValue = (String)attribute;
388
389 if (likeMatch)
390 {
391 if (attrValue.indexOf(attributeValue) != -1)
392 {
393 return beanObj;
394 }
395 }
396 else
397 {
398 if (attrValue.equals(attributeValue))
399 {
400 return beanObj;
401 }
402 }
403 }
404 }
405 }
406
407 return null;
408 }
409
410 /**
411 * Extract a collection of objects from the db using the value of an attribute within the object.
412 * This returns all matching objects.
413 *
414 * @param attributeName The name of the attribute.
415 * @param attributeValue The value of the attribute.
416 * @param likeMatch Should a "indexOf" match be used (true).
417 * False means "equals" is used.
418 *
419 */
420
421 public Collection getObjectsByAttributeValue( String attributeName, String attributeValue, boolean likeMatch )
422 {
423 StringTokenizer tokens = new StringTokenizer(attributeName, ".");
424 String segment = tokens.nextToken();
425
426 ArrayList objects = new ArrayList();
427 Object attribute = null;
428 Collection beanObjs = getObjectsByAttributeValueInternal(segment, attributeValue );
429
430 Iterator keysIterator = beanObjs.iterator();
431 while (keysIterator.hasNext())
432 {
433 Object beanObj = keysIterator.next();
434 tokens = new StringTokenizer(attributeName, ".");
435
436 segment = tokens.nextToken();
437 attribute = getBeanProperty(beanObj, segment);
438
439 // stop when end of path is reached
440 while (tokens.hasMoreTokens())
441 {
442 segment = tokens.nextToken();
443
444 attribute = getBeanProperty(attribute, segment);
445
446 Class valueClass = attribute.getClass();
447 if( valueClass.isAssignableFrom(String.class) )
448 {
449 String attrValue = (String)attribute;
450
451 if (likeMatch)
452 {
453 if (attrValue.indexOf(attributeValue) != -1)
454 {
455 objects.add(beanObj);
456 }
457 }
458 else
459 {
460 if (attrValue.equals(attributeValue))
461 {
462 objects.add(beanObj);
463 }
464 }
465 }
466 }
467 }
468
469 return objects;
470 }
471
472
473 /**
474 * Save the db into the given file as XML.
475 *
476 * @param db The database to load into.
477 * @param path The path to the file to use.
478 *
479 */
480
481 private void saveDumbDb( DumbDB db, String path )
482 {
483 try
484 {
485 XalanModelTree modelTree = new XalanModelTree();
486
487 ModelNode dbNode = modelTree.createNode("db","");
488 modelTree.getRootNode().appendChild(dbNode);
489
490 // load the node with "data" (from the bean)
491 BeanTransformer.beanToModel( db, dbNode, true );
492
493 String data = XmlUtil.ViewNode(modelTree.getModelTree());
494
495 PrintWriter xmlOut
496 = new PrintWriter(new BufferedWriter(new FileWriter(path)));
497
498 xmlOut.println(data);
499
500 xmlOut.flush();
501 xmlOut.close();
502 }
503 catch( Exception exception )
504 {
505 exception.printStackTrace();
506 }
507 }
508
509 /**
510 * Load the db from the given XML file.
511 *
512 * @param db The database to load into.
513 * @param path The path to the file to use.
514 *
515 */
516
517 private void loadDumbDb( DumbDB db, String path )
518 {
519 try
520 {
521 XalanModelTree modelTree = new XalanModelTree();
522 modelTree.loadFromFile(path);
523
524 ModelNode dbNode = modelTree.getNode(modelTree.getRootNode(), "/db");
525
526 // update the contact with the new data
527 if (modelTree.getRootNode() != null)
528 {
529 db =
530 (DumbDB)BeanTransformer.updateBeanFromModel( db, dbNode );
531 }
532 }
533 catch( Exception exception )
534 {
535 exception.printStackTrace();
536 }
537 }
538
539 /**
540 * Internal Method.
541 */
542
543 private Object getObjectByAttributeValueInternal( String attributeName, String attributeValue )
544 {
545 Iterator keysIterator = database.keySet().iterator();
546 while (keysIterator.hasNext())
547 {
548 String key = (String)keysIterator.next();
549 Object dataItem = database.get(key);
550
551 Object beanValue = getBeanProperty(dataItem, attributeName);
552 if (beanValue != null)
553 {
554 return dataItem;
555 }
556 }
557
558 return null;
559 }
560
561 /**
562 * Internal Method.
563 */
564
565 private Collection getObjectsByAttributeValueInternal( String attributeName, String attributeValue )
566 {
567 ArrayList objects = new ArrayList();
568
569 Iterator keysIterator = database.keySet().iterator();
570 while (keysIterator.hasNext())
571 {
572 String key = (String)keysIterator.next();
573 Object dataItem = database.get(key);
574
575 Object beanValue = getBeanProperty(dataItem, attributeName);
576
577 if (beanValue != null)
578 {
579 objects.add(dataItem);
580 }
581 }
582
583 return objects;
584 }
585
586 /**
587 * Internal Method.
588 */
589
590 private Object getBeanProperty(Object beanObject, String propertyName)
591 {
592 try
593 {
594 // transverse the bean
595 BeanInfo beanInfo = Introspector.getBeanInfo( beanObject.getClass() );
596
597 // get all the properties of the bean
598 PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
599
600 // for each property, get the set/get methods if available
601 int index=0;
602 for (index=0; index<propertyDescriptors.length; index++)
603 {
604 PropertyDescriptor property = propertyDescriptors[index];
605
606 // skip the type "class", it is actually the bean itself
607 if( property.getName().equals(propertyName) )
608 {
609 // use reflection to ask the bean property for it's value
610 Method getMethod = property.getReadMethod();
611 Object returnObj = getMethod.invoke( beanObject, null );
612
613 return returnObj;
614 }
615 }
616 }
617 catch (Exception exception)
618 {
619 exception.printStackTrace();
620 }
621
622 return null;
623 }
624 }
625