KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opensubsystems > patterns > listdata > persist > db > ListDatabaseTestUtils


1 /*
2  * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
3  *
4  * Project: OpenSubsystems
5  *
6  * $Id: ListDatabaseTestUtils.java,v 1.4 2007/02/20 04:22:42 bastafidli Exp $
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21
22 package org.opensubsystems.patterns.listdata.persist.db;
23
24 import java.sql.Connection JavaDoc;
25 import java.sql.PreparedStatement JavaDoc;
26 import java.sql.SQLException JavaDoc;
27 import java.sql.Statement JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.logging.Logger JavaDoc;
34
35 import javax.transaction.UserTransaction JavaDoc;
36
37 import org.opensubsystems.core.data.DataObject;
38 import org.opensubsystems.core.error.OSSException;
39 import org.opensubsystems.core.persist.BasicDataFactory;
40 import org.opensubsystems.core.persist.DataFactoryManager;
41 import org.opensubsystems.core.persist.db.Database;
42 import org.opensubsystems.core.persist.db.DatabaseConnectionFactoryImpl;
43 import org.opensubsystems.core.persist.db.DatabaseFactoryImpl;
44 import org.opensubsystems.core.persist.db.DatabaseImpl;
45 import org.opensubsystems.core.persist.db.DatabaseSchemaManager;
46 import org.opensubsystems.core.persist.db.DatabaseUpdateOperation;
47 import org.opensubsystems.core.persist.db.ModifiableDatabaseSchema;
48 import org.opensubsystems.core.util.CallContext;
49 import org.opensubsystems.core.util.DatabaseUtils;
50 import org.opensubsystems.core.util.Log;
51 import org.opensubsystems.core.util.MyTimer;
52 import org.opensubsystems.core.util.NumberUtils;
53 import org.opensubsystems.patterns.listdata.data.ListDefinition;
54 import org.opensubsystems.patterns.listdata.data.ListOptions;
55 import org.opensubsystems.patterns.listdata.persist.ListFactory;
56
57 /**
58  * Class used by JUnit tests derived from ListDatabaseFactoryTest class. Each
59  * such class should derive its own class from this class and implement all
60  * required methods. The functionality provided by the implemented methods
61  * it used to execute the generic tests for list pattern functionality.
62  *
63  * The idea is that the derived class specifies how to constructs the in memory
64  * tested data objects using two specified string values (here called column one
65  * and column two) and then specifies how to insert them to the database and how
66  * to delete them from the database. Then the generic tests using these specific
67  * methods as well as other utility methods from this class test list pattern
68  * implementation and behavior of the tested data object.
69  *
70  * @version $Id: ListDatabaseTestUtils.java,v 1.4 2007/02/20 04:22:42 bastafidli Exp $
71  * @author Julo Legeny
72  * @code.reviewer Miro Halas
73  * @code.reviewed 1.38 2007/01/18 06:08:41 bastafidli
74  */

75 public abstract class ListDatabaseTestUtils
76 {
77    // Constants ////////////////////////////////////////////////////////////////
78

79    /**
80     * Constant used to return test data which were created without any parent.
81     */

82    public static final String JavaDoc NO_PARENT = "NO_PARENT";
83    
84    // Attributes ///////////////////////////////////////////////////////////////
85

86    /**
87     * Class representing database specific ListFactory interface implementation
88     * for the tested data object.
89     */

90    protected Class JavaDoc m_clsListFactoryClass;
91    
92    /**
93     * Class that implements ListDatabaseSchema interface for the tested data
94     * object.
95     */

96    protected Class JavaDoc m_clsListDatabaseSchemaClass;
97    
98    /**
99     * Array with codes for all columns that stores data for the tested data
100     * object.
101     */

102    protected int[] m_arrAllColumnCodes;
103    
104    /**
105     * Code that represents column storing the first value used to generate the
106     * tested data object. It is assumed that this code is part of
107     * m_arrAllColumnCodes.
108     */

109    protected int m_iColumnOneCode;
110    
111    /**
112     * Code that represents column storing the second value used to generate the
113     * tested data object. It is assumed that this code is part of
114     * m_arrAllColumnCodes.
115     */

116    protected int m_iColumnTwoCode;
117    
118    // Cached values ////////////////////////////////////////////////////////////
119

120    /**
121     * Logger to use in this class
122     */

123    private static Logger JavaDoc s_logger = Log.getInstance(ListDatabaseTestUtils.class);
124    
125    // Constructors /////////////////////////////////////////////////////////////
126

127    /**
128     * Constructor
129     *
130     * @param clsListFactoryClass - class representing database specific
131     * ListFactory interface implementation for the
132     * tested data object
133     * @param clsListDatabaseSchemaClass - class representing database specific
134     * ListDatabaseSchema implementation for
135     * the tested data object
136     * @param arrAllColumnCodes - array with codes for all columns that stores
137     * data for the tested data object
138     * @param iColumnOneCode - Code that represents column storing the first
139     * value used to generate the tested data object. It
140     * is assumed that this code is part of
141     * arrAllColumnCodes.
142     * @param iColumnTwoCode - Code that represents column storing the second
143     * value used to generate the tested data object. It
144     * is assumed that this code is part of
145     * arrAllColumnCodes.
146     */

147    public ListDatabaseTestUtils(
148       Class JavaDoc clsListFactoryClass,
149       Class JavaDoc clsListDatabaseSchemaClass,
150       int[] arrAllColumnCodes,
151       int iColumnOneCode,
152       int iColumnTwoCode
153    )
154    {
155       m_clsListFactoryClass = clsListFactoryClass;
156       m_clsListDatabaseSchemaClass = clsListDatabaseSchemaClass;
157       m_arrAllColumnCodes = arrAllColumnCodes;
158       m_iColumnOneCode = iColumnOneCode;
159       m_iColumnTwoCode = iColumnTwoCode;
160    }
161    
162    // Public methods ///////////////////////////////////////////////////////////
163

164    // Methods that needs to be implemented in the derived classes //////////////
165

166    /**
167     * If the tested data object requires any kind of "parent" records, it should
168     * create them in this method using the two passed string values and return
169     * it. If the tested type of data objects doesn't require any parent records
170     * it should just return null.
171     *
172     * @param iDomainId - domain id where the the particular data object will
173     * belong to. This is applicable only if data object exist
174     * in domain. Otherwise this can be ignored.
175     * @param str1 - column one value to create the parent records
176     * @param str2 - column two value to create the parent records
177     * @return Object - some object identifying the parent, this will be passed
178     * to the insert method to create data in the parent. Return
179     * null if your data type doesn't support parents.
180     * This value is on purpose not a data object in case the
181     * tests needs to fake some data and create them in the
182     * database directly by executing SQL. It can then return
183     * custom objects identifying the created data to be used
184     * later in the tests.
185     * @throws Exception - an error has occured
186     */

187    protected abstract Object JavaDoc insertParent(
188       int iDomainId,
189       String JavaDoc str1,
190       String JavaDoc str2
191    ) throws Exception JavaDoc;
192
193    /**
194     * If the insertParent created any parent object then these needs to be
195     * deleted to cleanup the database. Implement
196     *
197     * @param parent - value returned by insertParent method that represents the
198     * parent object that needs to be deleted
199     * @param iDomainId - domain id where the the particular data is supposed to
200     * belong to. This is applicable only if data object exist
201     * in domain. Otherwise this can be ignored.
202     * @throws Exception - an error has occured
203     */

204    protected abstract void deleteParent(
205       Object JavaDoc parent,
206       int iDomainId
207    ) throws Exception JavaDoc;
208
209    /**
210     * Construct instance of tested data object that can be later inserted to the
211     * database using the specifiend values.
212     *
213     * @param parent - if this data type supports parents then this provides
214     * parent object created by insertParent method to insert
215     * the new data items into. Otherwise it is null.
216     * @param iDomainId - domain id where the the particular data object will
217     * belong to. This is applicable only if data object exist
218     * in domain. Otherwise this can be ignored.
219     * @param str1 - column one value to create the tested data object
220     * @param str2 - column two value to create the tested data object
221     * @return DataObject - constructed data object
222     * @throws Exception - an error has occured
223     */

224    protected abstract DataObject constructData(
225       Object JavaDoc parent,
226       int iDomainId,
227       String JavaDoc str1,
228       String JavaDoc str2
229    ) throws Exception JavaDoc;
230
231    /**
232     * Delete all instances of tested data object that were previously
233     * constructed for a specified parent using the specified prefixes for
234     * values used to populate column one and two. The expectations are that this
235     * method will efficiently deletes all the affected data objects using the
236     * specified prefixes since there can be large number of these.
237     *
238     * We provide convenience method deleteData(...., String) where you can
239     * just specify string that takes domain id (if the data is in domain) and
240     * two prefixes.
241     *
242     * @param parent - if this data type supports parents then this provides
243     * parent object created by insertParent method to insert
244     * the new data items into. Otherwise it is null.
245     * @param iDomainId - domain id where the the particular data object belongs
246     * to. This is applicable only if data object exist
247     * in domain. Otherwise this can be ignored.
248     * @param strPrefix1 - prefix used to construct column one values whe the
249     * tested data objects were created. There is multiple
250     * data objects with this prefix and all of the affected
251     * data objects must be deleted.
252     * @param strPrefix2 - prefix used to construct column two values whe the
253     * tested data objects were created. There is multiple
254     * data objects with this prefix and all of the affected
255     * data objects must be deleted.
256     * @throws Exception - an error has occured
257     */

258    protected abstract void deleteData(
259       Object JavaDoc parent,
260       int iDomainId,
261       String JavaDoc strPrefix1,
262       String JavaDoc strPrefix2
263    ) throws Exception JavaDoc;
264
265    /**
266     * Get value of the attribute represented by the first column code specified
267     * in the constructor.
268     *
269     * @param data - tested data object
270     * @return String - value of the attribute represented by the first column
271     * code specified in the constructor
272     */

273    public abstract String JavaDoc getColumnOneValue(
274       DataObject data
275    );
276    
277    /**
278     * Get value of the attribute represented by the second column code specified
279     * in the constructor.
280     *
281     * @param data - tested data object
282     * @return String - value of the attribute represented by the second column
283     * code specified in the constructor
284     */

285    public abstract String JavaDoc getColumnTwoValue(
286       DataObject data
287    );
288    
289    // Public methods to implement tests ////////////////////////////////////////
290

291    /**
292     * Get codes for all columns that stores data for the tested data object.
293     *
294     * @return int[] - array with codes for all columns
295     */

296    public final int[] getAllColumnCodes(
297    )
298    {
299       return m_arrAllColumnCodes;
300    }
301    
302    /**
303     * Get code that represents column storing the first value used to generate
304     * the tested data object. It is assumed that this code is part of values
305     * returned from getAllColumnCodes.
306     *
307     * @return int - code of column one
308     */

309    public final int getColumnOneCode(
310    )
311    {
312       return m_iColumnOneCode;
313    }
314    
315    /**
316     * Get code that represents column storing the second value used to generate
317     * the tested data object. It is assumed that this code is part of values
318     * returned from getAllColumnCodes.
319     *
320     * @return int - code of column two
321     */

322    public final int getColumnTwoCode(
323    )
324    {
325       return m_iColumnTwoCode;
326    }
327    
328    /**
329     * Get class representing database specific ListFactory interface
330     * implementation for the tested data object.
331     *
332     * @return Class - class implementing ListFactory interface
333     * @throws OSSException - an error has occured
334     */

335    public final Class JavaDoc getListFactoryClass(
336    ) throws OSSException
337    {
338       return m_clsListFactoryClass;
339    }
340    
341    /**
342     * Get instance of ListFactory able to retrieve the tested data object from
343     * the database.
344     *
345     * @return ListFactory - instance of ListFactory
346     * @throws OSSException - an error has occured
347     */

348    public final ListFactory getListFactory(
349    ) throws OSSException
350    {
351       return (ListFactory)DataFactoryManager.getInstance(getListFactoryClass());
352    }
353    
354    /**
355     * Get class that implements ListDatabaseSchema interface.
356     *
357     * @return ListDatabaseSchema - instance of ListDatabaseSchema
358     * @throws OSSException - an error has occured
359     */

360    public final Class JavaDoc getListDatabaseSchemaClass(
361    ) throws OSSException
362    {
363       return m_clsListDatabaseSchemaClass;
364    }
365    
366    /**
367     * Get instance of ListDatabaseSchema able to retrieve the tested data
368     * provide and execute database specific operations.
369     *
370     * @return ListDatabaseSchema - instance of ListDatabaseSchema
371     * @throws OSSException - an error has occured
372     */

373    public final ListDatabaseSchema getListDatabaseSchema(
374    ) throws OSSException
375    {
376       return (ListDatabaseSchema)DatabaseSchemaManager.getInstance(
377                 getListDatabaseSchemaClass());
378    }
379
380    /**
381     * Get expected results for columns 1 if the list is sorted using this column.
382     *
383     * @return String[] - array of returned column one values
384     */

385    public String JavaDoc[] getExpectedResultListColumnOne()
386    {
387       return new String JavaDoc[] {"01_junit_test", "02_junit_test", "03_junit_test",
388                            "04_junit_test", "05_junit_test", "06_junit_test",
389                            "07_junit_test", "08_junit_test", "09_junit_test",
390                            "10_junit_test", "11_junit_test", "12_junit_test",
391                            "13_junit_test", "14_junit_test", "15_junit_test",
392                            "16_junit_test", "17_junit_test", "18_junit_test",
393                            "19_junit_test", "20_junit_test", "21_junit_test",
394                            "22_junit_test", "23_junit_test", "24_junit_test",
395                            "25_junit_test",
396                           };
397    }
398    
399    /**
400     * Get expected results for columns 2 if the list is sorted using this column.
401     *
402     * @return String[] - array of returned column two values
403     */

404    public String JavaDoc[] getDefaultResultListColumnTwo()
405    {
406       return new String JavaDoc[] {"a", "b", "c", "d", "e", "f", "g", "h", "i",
407                            "j", "k", "l", "m", "n", "o", "p", "q", "r",
408                            "s", "t", "u", "v", "w", "x", "y",
409                           };
410    }
411    
412    /**
413     * Insert small set of data records to conduct tests with. The data are
414     * inserted in specific order so that we can test if they are retrieved
415     * correctly. The data are inserted to the current domain, which is domain
416     * specified by CallContext.getInstance().getCurrentDomainId().
417     *
418     * @param transaction - transaction to use to insert data
419     * @return Object - index 0 - if this class supports parent then the returned
420     * object is the parent to which test data were
421     * inserted. If it doesn't support parents, then
422     * it is null.
423     * - index 1 - the test data created by this method. The
424     * keys are the created parents and values are the
425     * lists of test data created for each parent.
426     * If the tested data object doesn't support
427     * parent, the key is the NO_PARENT constant.
428     * @throws Exception - an error has occured
429     */

430    public final Object JavaDoc[] insertTestData(
431       UserTransaction JavaDoc transaction
432    ) throws Exception JavaDoc
433    {
434       Object JavaDoc parent = null;
435       DataObject data;
436       Map JavaDoc mapData = new HashMap JavaDoc(2);
437       List JavaDoc dataItems = new ArrayList JavaDoc();
438       int iDomainId = CallContext.getInstance().getCurrentDomainId();
439
440       transaction.begin();
441       try
442       {
443          parent = insertParent(iDomainId, "1_parent_junit_test", "a");
444          
445          // Insert data in such an order that the order of database generated
446
// ids doesn't reflect the ordering of values in column 1 or column 2
447
data = insertData(parent, iDomainId, "07_junit_test", "g");
448          dataItems.add(data);
449          data = insertData(parent, iDomainId, "20_junit_test", "t");
450          dataItems.add(data);
451          data = insertData(parent, iDomainId, "21_junit_test", "u");
452          dataItems.add(data);
453          data = insertData(parent, iDomainId, "25_junit_test", "y");
454          dataItems.add(data);
455          data = insertData(parent, iDomainId, "08_junit_test", "h");
456          dataItems.add(data);
457          data = insertData(parent, iDomainId, "04_junit_test", "d");
458          dataItems.add(data);
459          data = insertData(parent, iDomainId, "17_junit_test", "q");
460          dataItems.add(data);
461          data = insertData(parent, iDomainId, "11_junit_test", "k");
462          dataItems.add(data);
463          data = insertData(parent, iDomainId, "12_junit_test", "l");
464          dataItems.add(data);
465          data = insertData(parent, iDomainId, "13_junit_test", "m");
466          dataItems.add(data);
467          data = insertData(parent, iDomainId, "09_junit_test", "i");
468          dataItems.add(data);
469          data = insertData(parent, iDomainId, "10_junit_test", "j");
470          dataItems.add(data);
471          data = insertData(parent, iDomainId, "14_junit_test", "n");
472          dataItems.add(data);
473          data = insertData(parent, iDomainId, "18_junit_test", "r");
474          dataItems.add(data);
475          data = insertData(parent, iDomainId, "19_junit_test", "s");
476          dataItems.add(data);
477          data = insertData(parent, iDomainId, "05_junit_test", "e");
478          dataItems.add(data);
479          data = insertData(parent, iDomainId, "24_junit_test", "x");
480          dataItems.add(data);
481          data = insertData(parent, iDomainId, "15_junit_test", "o");
482          dataItems.add(data);
483          data = insertData(parent, iDomainId, "02_junit_test", "b");
484          dataItems.add(data);
485          data = insertData(parent, iDomainId, "01_junit_test", "a");
486          dataItems.add(data);
487          data = insertData(parent, iDomainId, "03_junit_test", "c");
488          dataItems.add(data);
489          data = insertData(parent, iDomainId, "06_junit_test", "f");
490          dataItems.add(data);
491          data = insertData(parent, iDomainId, "22_junit_test", "v");
492          dataItems.add(data);
493          data = insertData(parent, iDomainId, "23_junit_test", "w");
494          dataItems.add(data);
495          data = insertData(parent, iDomainId, "16_junit_test", "p");
496          dataItems.add(data);
497
498          if (parent != null)
499          {
500             Object JavaDoc parent2;
501          
502             mapData.put(parent, dataItems);
503             dataItems = new ArrayList JavaDoc();
504             
505             // This data type support parents so just to make it more
506
// interesting, insert very similar names to different parent
507
parent2 = insertParent(iDomainId, "2_parent_junit_test", "b");
508
509             data = insertData(parent2, iDomainId, "01_2_junit_test", "a");
510             dataItems.add(data);
511             data = insertData(parent2, iDomainId, "02_2_junit_test", "b");
512             dataItems.add(data);
513             data = insertData(parent2, iDomainId, "03_2_junit_test", "c");
514             dataItems.add(data);
515             data = insertData(parent2, iDomainId, "04_2_junit_test", "d");
516             dataItems.add(data);
517             data = insertData(parent2, iDomainId, "05_2_junit_test", "e");
518             dataItems.add(data);
519             data = insertData(parent2, iDomainId, "06_2_junit_test", "f");
520             dataItems.add(data);
521             data = insertData(parent2, iDomainId, "07_2_junit_test", "g");
522             dataItems.add(data);
523             data = insertData(parent2, iDomainId, "08_2_junit_test", "h");
524             dataItems.add(data);
525             data = insertData(parent2, iDomainId, "09_2_junit_test", "i");
526             dataItems.add(data);
527             data = insertData(parent2, iDomainId, "10_2_junit_test", "j");
528             dataItems.add(data);
529             data = insertData(parent2, iDomainId, "11_2_junit_test", "k");
530             dataItems.add(data);
531             data = insertData(parent2, iDomainId, "12_2_junit_test", "l");
532             dataItems.add(data);
533             data = insertData(parent2, iDomainId, "13_2_junit_test", "m");
534             dataItems.add(data);
535             data = insertData(parent2, iDomainId, "14_2_junit_test", "n");
536             dataItems.add(data);
537             data = insertData(parent2, iDomainId, "15_2_junit_test", "o");
538             dataItems.add(data);
539             data = insertData(parent2, iDomainId, "16_2_junit_test", "p");
540             dataItems.add(data);
541             data = insertData(parent2, iDomainId, "17_2_junit_test", "q");
542             dataItems.add(data);
543             data = insertData(parent2, iDomainId, "18_2_junit_test", "r");
544             dataItems.add(data);
545             data = insertData(parent2, iDomainId, "19_2_junit_test", "s");
546             dataItems.add(data);
547             data = insertData(parent2, iDomainId, "20_2_junit_test", "t");
548             dataItems.add(data);
549             data = insertData(parent2, iDomainId, "21_2_junit_test", "u");
550             dataItems.add(data);
551             data = insertData(parent2, iDomainId, "22_2_junit_test", "v");
552             dataItems.add(data);
553             data = insertData(parent2, iDomainId, "23_2_junit_test", "w");
554             dataItems.add(data);
555             data = insertData(parent2, iDomainId, "24_2_junit_test", "x");
556             dataItems.add(data);
557             data = insertData(parent2, iDomainId, "25_2_junit_test", "y");
558             dataItems.add(data);
559
560             mapData.put(parent2, dataItems);
561          }
562          else
563          {
564             mapData.put(NO_PARENT, dataItems);
565          }
566         
567          transaction.commit();
568       }
569       catch (Throwable JavaDoc thr)
570       {
571          transaction.rollback();
572          throw new Exception JavaDoc(thr);
573       }
574       
575       return new Object JavaDoc[] {parent, mapData};
576    }
577    
578    /**
579     * Delete all test data inserted by insertTestData method. The data are
580     * expected to exist in current domain, which is domain specified by
581     * CallContext.getInstance().getCurrentDomainId().
582     *
583     * @param transaction - transaction to use when deleting data
584     * @param insertedData - data inserted by the insertTestData method that
585     * needs to be deleted
586     * @throws Exception - an error has occured
587     */

588    public final void deleteTestData(
589       UserTransaction JavaDoc transaction,
590       Object JavaDoc[] insertedData
591    ) throws Exception JavaDoc
592    {
593       int iDomainId = CallContext.getInstance().getCurrentDomainId();
594       
595       transaction.begin();
596       try
597       {
598          Map JavaDoc mapData = (Map JavaDoc)insertedData[1];
599          Map.Entry JavaDoc item;
600          
601          for (Iterator JavaDoc items = mapData.entrySet().iterator(); items.hasNext();)
602          {
603             item = (Map.Entry JavaDoc)items.next();
604             // First delete the created data
605
deleteDataObjects((List JavaDoc)item.getValue(), iDomainId);
606             if (!NO_PARENT.equals(item.getKey()))
607             {
608                deleteParent(item.getKey(), iDomainId);
609             }
610          }
611          transaction.commit();
612       }
613       catch (Throwable JavaDoc thr)
614       {
615          transaction.rollback();
616          throw new Exception JavaDoc(thr);
617       }
618    }
619
620    /**
621     * Insert data records for load tests if they were not inserted yet. The data
622     * are inserted in given order so that we can test if they are retrieved
623     * correctly.
624     *
625     * @param transaction - transaction to use to insert data or null if no
626     * transaction should be used since the caller will
627     * control the transaction
628     * @param iLoadTestListSize - number of tested data objects to insert
629     * @return Object - index 0 - if this class supports parent then the returned
630     * object is the parent to which test data were
631     * inserted. If it doesn't support parents, then
632     * it is null.
633     * - index 1 - the load test data created by this method. The
634     * keys are the parents and values are the lists
635     * identifying the prefixes for column one and
636     * two values used to generate the data. If the
637     * tested data object doesn't support parent, the
638     * key is the NO_PARENT constans.
639     * @throws Exception - an error has occured
640     */

641    public final Object JavaDoc[] insertLoadTestData(
642       UserTransaction JavaDoc transaction,
643       int iLoadTestListSize
644    ) throws Exception JavaDoc
645    {
646       return insertLoadTestData(transaction, iLoadTestListSize,
647                                 CallContext.getInstance().getCurrentDomainId(),
648                                 0, false);
649    }
650    
651    /**
652     * Delete all data inserted for the load tests using the insertLoadTestData
653     * method.
654     *
655     * @param transaction - transaction
656     * @param insertedData - data inserted by the insertLoadTestData method that
657     * needs to be deleted
658     * @throws Exception - an error has occured
659     */

660    public final void deleteLoadTestData(
661       UserTransaction JavaDoc transaction,
662       Object JavaDoc[] insertedData
663    ) throws Exception JavaDoc
664    {
665       deleteLoadTestData(transaction, insertedData,
666                          CallContext.getInstance().getCurrentDomainId());
667    }
668    
669    /**
670     * Update database statistics with expectation to improve performance of
671     * queries (usually after a large number of data were inserted or deleted) by
672     * analyzing the modified tables. ANALYZE query. The tables that will be
673     * updated are retrieved using method getModifiableTableNames in
674     * ListDatabaseSchemainterface
675     *
676     * @throws Exception - an error has occured
677     */

678    public final void analyzeDatabase(
679    ) throws Exception JavaDoc
680    {
681       String JavaDoc[] arrQueryAnalyze = null;
682
683       Object JavaDoc[] arrResults = null;
684       ListDatabaseSchema schema = getListDatabaseSchema();
685       
686       if (schema instanceof ModifiableDatabaseSchema)
687       {
688          Map JavaDoc mapTables;
689          
690          mapTables = ((ModifiableDatabaseSchema)schema).getModifiableTableNames();
691          arrResults = DatabaseImpl.getInstance().getSQLAnalyzeFunctionCall(
692                                                     mapTables);
693       }
694       
695       // If the DB doesn't support analyze query, it will return null value
696
// and nothing will be executed
697
if (arrResults != null)
698       {
699          Connection JavaDoc dbConnection = null;
700          Statement JavaDoc statement = null;
701          int iIndex = 0;
702          boolean bAutoCommit = false;
703          
704          arrQueryAnalyze = (String JavaDoc[])arrResults[0];
705          bAutoCommit = ((Boolean JavaDoc)arrResults[1]).booleanValue();
706          try
707          {
708             dbConnection = DatabaseConnectionFactoryImpl.getInstance()
709                               .requestConnection(bAutoCommit);
710             try
711             {
712                statement = dbConnection.createStatement();
713                for (iIndex = 0; iIndex < arrQueryAnalyze.length; iIndex++)
714                {
715                   statement.executeUpdate(arrQueryAnalyze[iIndex]);
716                }
717             }
718             finally
719             {
720                DatabaseUtils.closeStatement(statement);
721             }
722             
723             // TODO: Improve: Is there a need for any database to commit the
724
// data?
725
}
726          catch (Throwable JavaDoc thr)
727          {
728             throw new Exception JavaDoc(thr);
729          }
730          finally
731          {
732             DatabaseConnectionFactoryImpl.getInstance().returnConnection(
733                                                            dbConnection);
734          }
735       }
736    }
737    
738    /**
739     * Ge list options initialized to default values that will be used during
740     * list pattern tests.
741     *
742     * @param parent - if this class supports parent then the return object is
743     * the parent to which test data were inserted. If it doesn't
744     * support parents, then it is null.
745     * @return ListOptions - default ListOptions for tests
746     * @throws OSSException - an error has occured
747     */

748    public ListOptions getDefaultListOptions(
749       Object JavaDoc parent
750    ) throws OSSException
751    {
752       ListOptions options = new ListOptions(getListFactoryClass());
753       ListDefinition defaultListFilter = getListFactory().getDefaultListDefinition();
754
755       // The list will be by default sorted by the first specified column
756
// rather then by the default order of the data insertion
757
defaultListFilter.setOrdering(new int[] {getColumnOneCode()},
758                                     ListDefinition.ORDER_ASCENDING_ARRAY);
759
760       options.setDefinitionId(DataObject.NEW_ID_STR);
761       options.setDefinition(defaultListFilter);
762       options.setPageSize(defaultListFilter.getPageSize());
763       options.setOrdering(defaultListFilter.getOrderColumnCodes(),
764                           defaultListFilter.getOrderDirections());
765       // We have to guarantee that our columns 1 and 2 are always retrieved
766
// therefore include them in the show columns
767
// options.setRetrieveColumnCodes(defaultListFilter.getShowColumnCodes());
768
options.setShowColumnCodes(DatabaseUtils.mergeColumnsSafely(
769                                     defaultListFilter.getShowColumnCodes(),
770                                     new int[] {getColumnOneCode(), getColumnTwoCode()}));
771       // It should work even if it is null since this should be setup by the
772
// database layer
773
options.setRetrieveColumnCodes(null);
774       options.setDomainId(CallContext.getInstance().getCurrentDomainId());
775       
776       return options;
777    }
778    
779    /**
780     * Print debug info for ListOptions
781     *
782     * @param options - ListOptions to print
783     */

784    public void printDebug(
785       ListOptions options
786    )
787    {
788       System.out.println("List size" + options.getActualListSize() +
789                          " Begin position: " + options.getBeginPosition() +
790                          " End position: " + options.getEndPosition() +
791                          " Actual page: " + options.getActualPage());
792    }
793    
794    /**
795     * Print debug infor for specified data
796     *
797     * @param dataList - List to print
798     */

799    public void printDebug(
800       List JavaDoc dataList
801    )
802    {
803       DataObject data;
804       Iterator JavaDoc items;
805       int iIndex;
806       for (items = dataList.iterator(), iIndex = 0; items.hasNext(); iIndex++)
807       {
808          data = (DataObject)items.next();
809          System.out.println("Index" + iIndex +
810                             " 1: " + getColumnOneValue(data) +
811                             " 2: " + getColumnTwoValue(data));
812       }
813    }
814    
815    // Helper methods ///////////////////////////////////////////////////////////
816

817    /**
818     * Insert to the database record representing tested data object that is
819     * generated using the values specified for two columns of the data object.
820     *
821     * @param parent - if this data type supports parents then this provides
822     * parent object created by insertParent method to insert
823     * the new data items into. Otherwise it is null.
824     * @param iDomainId - domain id where the the particular data object will
825     * belong to. This is applicabe only if data object exist
826     * in domain. Otherwise this can be infored.
827     * @param str1 - column one value to create the tested data object
828     * @param str2 - column two value to create the tested data object
829     * @return DataObject - inserted data object
830     * @throws Exception - an error has occured
831     */

832    protected DataObject insertData(
833       Object JavaDoc parent,
834       int iDomainId,
835       String JavaDoc str1,
836       String JavaDoc str2
837    ) throws Exception JavaDoc
838    {
839       DataObject data = null;
840
841       data = constructData(parent, iDomainId, str1, str2);
842       data = createDataObject(data);
843       return data;
844    }
845
846    /**
847     * Insert efficiently to the database multiple records representing tested
848     * data object that are generated using the specified values
849     *
850     * @param parent - if this data type supports parents then this provides
851     * parent object created by insertParent method to insert
852     * the new data items into. Otherwise it is null.
853     * @param iDomainId - domain id where the the particular data object will
854     * belong to. This is applicabe only if data object exist
855     * in domain. Otherwise this can be infored.
856     * @param iCount - number of tested data objects to insert
857     * @param iStartNumber - starting number for generating unique values for the
858     * columns
859     * @param bAditionalData - flag if there will be added additional data for
860     * particular data object
861     * @return List - identifiers used to construct multiple items, these are
862     * prefixes used to generate column 1 and column 2 values
863     * to construct and insert the multiple data objects
864     * @throws Exception - an error has occured
865     */

866    protected List JavaDoc insertMultipleData(
867       Object JavaDoc parent,
868       int iDomainId,
869       int iCount,
870       int iStartNumber,
871       boolean bAditionalData
872    ) throws Exception JavaDoc
873    {
874       List JavaDoc lstReturn = new ArrayList JavaDoc(2);
875       List JavaDoc lstDataObjects = new ArrayList JavaDoc();
876       int iIndex;
877       int iOuterIndex;
878       int iOuterIndexCount = 0;
879       int iEndIndex = Database.BATCH_ITERATOR;
880       int iActualCount = iStartNumber + 1;
881       MyTimer timer = new MyTimer();
882       boolean isNotFullListForLastCycle = false;
883       long timeDuration = 0;
884       int iItemsPerSecons = 0;
885       DataObject data = null;
886       int iDigitCount = 8;
887       String JavaDoc strColumnOnePrefix = "test_1_";
888       String JavaDoc strColumnTwoPrefix = "test_2_";
889       
890       lstReturn.add(strColumnOnePrefix);
891       lstReturn.add(strColumnTwoPrefix);
892       if (iCount % Database.BATCH_ITERATOR > 0)
893       {
894          iOuterIndexCount = (iCount / Database.BATCH_ITERATOR) + 1;
895          isNotFullListForLastCycle = true;
896       }
897       else
898       {
899          iOuterIndexCount = (iCount / Database.BATCH_ITERATOR);
900       }
901
902       timer.reset();
903
904       if (bAditionalData)
905       {
906          iDigitCount = 9;
907       }
908
909       for (iOuterIndex = 1; iOuterIndex <= iOuterIndexCount; iOuterIndex++)
910       {
911          // Setup end index for the last cycle
912
if ((iOuterIndex == iOuterIndexCount) && (isNotFullListForLastCycle))
913          {
914             iEndIndex = iCount % Database.BATCH_ITERATOR;
915          }
916
917          lstDataObjects.clear();
918          for (iIndex = 1; iIndex <= iEndIndex; iIndex++)
919          {
920             data = constructData(parent, iDomainId,
921                                  strColumnOnePrefix
922                                  + NumberUtils.getDigitNumberString(iActualCount,
923                                                                     iDigitCount),
924                                  strColumnTwoPrefix
925                                  + NumberUtils.getDigitNumberString(iActualCount,
926                                                                     iDigitCount));
927             lstDataObjects.add(data);
928             iActualCount++;
929          }
930
931          createDataObjects(lstDataObjects);
932       }
933
934       timer.stop();
935       timeDuration = timer.getDuration();
936       if (timeDuration > 0)
937       {
938          iItemsPerSecons = (int)(((iCount * 1000)) / timeDuration);
939       }
940       s_logger.info("Total duration to create " + iCount +
941                     " data objects was " + timer.toString() + " which is " +
942                     (iItemsPerSecons > 0 ? Integer.toString(iItemsPerSecons)
943                                          : "undefined")
944                     + " items/sec");
945       return lstReturn;
946    }
947
948    /**
949     * Insert data records for load tests if they were not inserted yet. The data
950     * are inserted in given order so that we can test if they are retrieved
951     * correctly.
952     *
953     * @param transaction - transaction to use to insert data or null if no
954     * transaction should be used since the caller will
955     * control the transaction
956     * @param iLoadTestListSize - number of tested data objects to insert
957     * @param iDomainId - if of domain where to insert the extra data
958     * @param iStartNumber - starting number for generating unique values for the
959     * columns
960     * @param bAditionalData - flag if there will be added additional data for
961     * particular data object
962     * @return Object - index 0 - if this class supports parent then the returned
963     * object is the parent to which test data were
964     * inserted. If it doesn't support parents, then
965     * it is null.
966     * - index 1 - the load test data created by this method. The
967     * keys are the parents and values are the lists
968     * identifying the prefixes for column one and
969     * two values used to generate the data. If the
970     * tested data object doesn't support parent, the
971     * key is the NO_PARENT constans.
972     * @throws Exception - an error has occured
973     */

974    protected final Object JavaDoc[] insertLoadTestData(
975       UserTransaction JavaDoc transaction,
976       int iLoadTestListSize,
977       int iDomainId,
978       int iStartNumber,
979       boolean bAditionalData
980    ) throws Exception JavaDoc
981    {
982       Object JavaDoc parent = null;
983       Map JavaDoc mapLoadTestData;
984       
985       if (transaction != null)
986       {
987          transaction.begin();
988       }
989       try
990       {
991          List JavaDoc data;
992          
993          // Allocate immediately here in case they are loaded just
994
// partially so they can be deleted safely
995
mapLoadTestData = new HashMap JavaDoc();
996
997          parent = insertParent(iDomainId, "1_parent_junit_test", "a");
998          data = insertMultipleData(parent, iDomainId, iLoadTestListSize,
999                                    iStartNumber, bAditionalData);
1000         
1001         if (parent != null)
1002         {
1003            Object JavaDoc parent1 = null;
1004            
1005            mapLoadTestData.put(parent, data);
1006            // This data type support parents so just to make it more
1007
// interesting, insert very similar names to different parent
1008
// this way we can test if the list is correctly retrieved just for
1009
// the parent we specify
1010
parent1 = insertParent(iDomainId, "2_parent_junit_test", "b");
1011            data = insertMultipleData(parent1, iDomainId, iLoadTestListSize,
1012                                      iStartNumber, bAditionalData);
1013            mapLoadTestData.put(parent1, data);
1014         }
1015         else
1016         {
1017            mapLoadTestData.put(NO_PARENT, data);
1018         }
1019         if (transaction != null)
1020         {
1021            transaction.commit();
1022         }
1023      }
1024      catch (Throwable JavaDoc thr)
1025      {
1026         if (transaction != null)
1027         {
1028            transaction.rollback();
1029         }
1030         throw new Exception JavaDoc(thr);
1031      }
1032      
1033      if (transaction != null)
1034      {
1035         // Call ANALYZE query after inserting all data to update indexes
1036
// but do it only if this method controls transaction since if
1037
// somebody else controls the transaction then there might be
1038
// additional data that will be inserted before the tables can be
1039
// analyzed
1040
analyzeDatabase();
1041      }
1042      
1043      return new Object JavaDoc[] {parent, mapLoadTestData};
1044   }
1045   
1046   /**
1047    * Delete all data inserted for the load tests using the insertLoadTestData
1048    * method.
1049    *
1050    * @param transaction - transaction to use to delete data or null if no
1051    * transaction should be used since the caller will
1052    * control the transaction
1053    * @param insertedData - data inserted by the insertLoadTestData method that
1054    * needs to be deleted
1055    * @param iDomainId - domain id where to delete the inserted data
1056    * @throws Exception - an error has occured
1057    */

1058   protected final void deleteLoadTestData(
1059      UserTransaction JavaDoc transaction,
1060      Object JavaDoc[] insertedData,
1061      int iDomainId
1062   ) throws Exception JavaDoc
1063   {
1064      if (transaction != null)
1065      {
1066         transaction.begin();
1067      }
1068      try
1069      {
1070         Map JavaDoc mapData = (Map JavaDoc)insertedData[1];
1071         Map.Entry JavaDoc item;
1072         Object JavaDoc objParent;
1073         List JavaDoc lstPrefixes;
1074         
1075         for (Iterator JavaDoc items = mapData.entrySet().iterator(); items.hasNext();)
1076         {
1077            item = (Map.Entry JavaDoc)items.next();
1078            objParent = item.getKey();
1079            lstPrefixes = (List JavaDoc)item.getValue();
1080            
1081            // First delete the created data
1082
deleteData(objParent, iDomainId,
1083                       // doInsertMultipleData used two prefixes that were
1084
// stored in the returned array
1085
(String JavaDoc)lstPrefixes.get(0),
1086                       (String JavaDoc)lstPrefixes.get(1));
1087            if (!NO_PARENT.equals(objParent))
1088            {
1089               deleteParent(objParent, iDomainId);
1090            }
1091         }
1092         if (transaction != null)
1093         {
1094            transaction.commit();
1095         }
1096      }
1097      catch (Throwable JavaDoc thr)
1098      {
1099         if (transaction != null)
1100         {
1101            transaction.rollback();
1102         }
1103         throw new Exception JavaDoc(thr);
1104      }
1105      
1106      if (transaction != null)
1107      {
1108         // Call ANALYZE query after delte all data to update indexes
1109
// but do it only if this method controls transaction since if
1110
// somebody else controls the transaction then there might be
1111
// additional data that will be deleted before the tables can be
1112
// analyzed
1113
analyzeDatabase();
1114      }
1115   }
1116   
1117   /**
1118    * Create data object. This method can be overwritten for particular data
1119    * object to account for any specific beaviour.
1120    *
1121    * @param data - data object that will be created
1122    * @return DataObject - data object that was just created
1123    * @throws OSSException - exception occured during create
1124    */

1125   protected DataObject createDataObject(
1126      DataObject data
1127   ) throws OSSException
1128   {
1129      return ((BasicDataFactory)getListFactory()).create(data);
1130   }
1131
1132   /**
1133    * Delete data object. This method can be overwritten for particular data
1134    * object to account for any specific beaviour.
1135    *
1136    * @param data - data object that will be deleted
1137    * @param iDomainId - this is the domain id in which we expect the data object
1138    * to exist (if the data object contains domain id, it
1139    * should be the same as the one we specify as an argument)
1140    * @throws OSSException - an error has occured
1141    */

1142   protected void deleteDataObject(
1143      DataObject data,
1144      int iDomainId
1145   ) throws OSSException
1146   {
1147      if (data != null)
1148      {
1149         ((BasicDataFactory)getListFactory()).delete(data.getId(), iDomainId);
1150      }
1151   }
1152
1153   /**
1154    * Create list of data objects efficiently if possible. This method can be
1155    * overwritten for particular data object to account for any specific
1156    * beaviour.
1157    *
1158    * @param lstDataObjects - list of data object that will be created
1159    * @throws OSSException - exception occured during create
1160    */

1161   protected void createDataObjects(
1162      List JavaDoc lstDataObjects
1163   ) throws OSSException
1164   {
1165      ((BasicDataFactory)getListFactory()).create(lstDataObjects);
1166   }
1167
1168   /**
1169    * Deletes list of data objects efficiently if possible. This method can be
1170    * overwritten for particular data object to account for any specific
1171    * beaviour.
1172    *
1173    * @param lstDataObjects - list of data object that will be deleted
1174    * @param iDomainId - if of domain where we expect all the specified data
1175    * objects to exist (in case they exist in the domain)
1176    * @throws OSSException - an error has occured
1177    */

1178   protected void deleteDataObjects(
1179      List JavaDoc lstDataObjects,
1180      int iDomainId
1181   ) throws OSSException
1182   {
1183      if (lstDataObjects != null)
1184      {
1185         DataObject data;
1186         for (Iterator JavaDoc items = lstDataObjects.iterator(); items.hasNext();)
1187         {
1188            data = (DataObject)items.next();
1189            deleteDataObject(data, iDomainId);
1190         }
1191      }
1192   }
1193   
1194   /**
1195    * Convenience method to delete all instances of tested data object that were
1196    * previously constructed for a specified parent using the specified prefixes
1197    * for values used to populate column one and two. This method can be used
1198    * only if the list factory is in fact derived from DatabaseFactoryImpl and
1199    * the schema implements ModifiableDatabaseSchema.
1200    *
1201    * @param parent - if this data type supports parents then this provides
1202    * parent object created by insertParent method to insert
1203    * the new data items into. Otherwise it is null.
1204    * @param iDomainId - domain id where the the particular data object belongs
1205    * to. This is applicable only if data object exist
1206    * in domain. Otherwise this can be ignored.
1207    * @param strPrefix1 - prefix used to construct column one values whe the
1208    * tested data objects were created. There is multiple
1209    * data objects with this prefix and all of the affected
1210    * data objects must be deleted.
1211    * @param strPrefix2 - prefix used to construct column two values whe the
1212    * tested data objects were created. There is multiple
1213    * data objects with this prefix and all of the affected
1214    * data objects must be deleted.
1215    * @param strDeleteByListTestPrefixesQuery - query that deletes all the data
1216    * using the specified prefixes
1217    * in specified domain (if the
1218    * tested data object exists in
1219    * domain). If bSubstitueValues is
1220    * true then the query need to take
1221    * prefix 1 as first argument,
1222    * prefix 2 as second argument
1223    * and optional domain id as the
1224    * last argument
1225    * @param bSubstitueValues - if true then the prefix 1, 2 and domain id will
1226    * be substitued to the passed in query when a
1227    * prepared statement is created otherwise if it is
1228    * false then assumption is that the query doesn't
1229    * contain any variables that needs substitution.
1230    * @throws Exception - an error has occured
1231    */

1232   protected void deleteData(
1233      Object JavaDoc parent,
1234      final int iDomainId,
1235      final String JavaDoc strPrefix1,
1236      final String JavaDoc strPrefix2,
1237      String JavaDoc strDeleteByListTestPrefixesQuery,
1238      final boolean bSubstitueValues
1239   ) throws Exception JavaDoc
1240   {
1241      DatabaseUpdateOperation dbop = new DatabaseUpdateOperation(
1242         (DatabaseFactoryImpl)getListFactory(),
1243         strDeleteByListTestPrefixesQuery,
1244         (ModifiableDatabaseSchema)getListDatabaseSchema(),
1245         DatabaseUpdateOperation.DBOP_DELETE, null)
1246      {
1247         protected void performOperation(
1248            DatabaseFactoryImpl dbfactory,
1249            Connection JavaDoc cntConnection,
1250            PreparedStatement JavaDoc pstmQuery
1251         ) throws OSSException,
1252                  SQLException JavaDoc
1253         {
1254            final int iUpdated;
1255            if (bSubstitueValues)
1256            {
1257               int iIndex = 1;
1258            
1259               if (m_dbschema.isInDomain())
1260               {
1261                  pstmQuery.setInt(iIndex++, iDomainId);
1262               }
1263               pstmQuery.setString(iIndex++, strPrefix1);
1264               pstmQuery.setString(iIndex++, strPrefix2);
1265            }
1266            iUpdated = pstmQuery.executeUpdate();
1267            // set up number of updated domains
1268
setReturnData(new Integer JavaDoc(iUpdated));
1269         }
1270      };
1271      dbop.executeUpdate();
1272   }
1273}
1274
Popular Tags