View Javadoc

1   /***
2    * Copyright 2007 ATG DUST Project
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * 
7    * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8    * 
9    * Unless required by applicable law or agreed to in writing, software 
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and limitations under the License.
13   */
14  
15  package atg.adapter.gsa;
16  
17  import java.io.File;
18  import java.io.FileNotFoundException;
19  import java.io.FileOutputStream;
20  import java.io.FileWriter;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.io.PrintWriter;
25  import java.sql.Connection;
26  import java.sql.PreparedStatement;
27  import java.sql.ResultSet;
28  import java.sql.SQLException;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.HashMap;
32  import java.util.HashSet;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.Properties;
37  
38  import javax.sql.DataSource;
39  
40  import junit.framework.Assert;
41  
42  import org.apache.log4j.Logger;
43  
44  import atg.adapter.gsa.xml.TemplateParser;
45  import atg.adapter.gsa.xml.VersioningContextUtil;
46  import atg.adapter.version.VersionRepository;
47  import atg.naming.NameContext;
48  import atg.nucleus.Configuration;
49  import atg.nucleus.GenericService;
50  import atg.nucleus.Nucleus;
51  import atg.nucleus.NucleusNameResolver;
52  import atg.nucleus.NucleusTestUtils;
53  import atg.nucleus.ServiceEvent;
54  import atg.nucleus.ServiceException;
55  import atg.repository.Repository;
56  import atg.repository.RepositoryException;
57  import atg.test.util.DBUtils;
58  import atg.versionmanager.VersionManager;
59  import atg.versionmanager.Workspace;
60  import atg.versionmanager.exceptions.VersionException;
61  
62  /***
63   * A utility class to simplify testing with GSARepositories inside of junit
64   * tests.
65   * 
66   * @author adamb
67   * @version $Revision: #28 $
68   */
69  public class GSATestUtils {
70    public static List<File> mFilesCreated = new ArrayList<File>();
71    public static String sClassName = "atg.adapter.gsa.InitializingGSA";
72    public static String sVersionedClassName = "atg.adapter.gsa.InitializingVersionRepository";
73    private boolean mVersioned = false;
74    private static GSATestUtils SINGLETON_DEFAULT = null;
75    private static GSATestUtils SINGLETON_VERSIONED = null;
76    
77    private static Logger log = Logger.getLogger(GSATestUtils.class);
78  
79    /***
80     * @param pB
81     */
82    public GSATestUtils(boolean pB) {
83      mVersioned = pB;
84       
85    }
86    /***
87     * Duplicates the given array of repositories.
88     * This method first binds the repositories into nucleus under the name XXXX-Shadow,
89     * where XXXX is the original name.
90     * After all repositories are bound, then they are started.
91     * This allows for repositories with circular references to each other to be deplicated.
92     * The pRepositories array and pDS array should be in sync. That is the first item in the
93     * repository array, pRepositories,  will use the first data source in the pDS array and so on.
94     * @param pRepositories
95     * @param pDS
96     * @return
97     */
98    public static Repository [] duplicateRepositories(GSARepository [] pRepositories, DataSource [] pDS) throws ServiceException {
99      GSARepository [] newReps = new GSARepository[pRepositories.length];
100     for (int i = 0 ; i < pRepositories.length; i++ ) {
101       newReps[i] = (GSARepository)duplicateRepository(pRepositories[i],pDS[i],false);
102     }
103     for (int i = 0 ; i < newReps.length; i++ ) {
104       startRepository(pRepositories[i], pRepositories[i].getServiceConfiguration(), pRepositories[i].getNucleus(), newReps[i]);
105     }
106     return newReps;
107   }
108   public static Repository duplicateRepository(GSARepository pRepository,DataSource pDS) throws ServiceException{
109     return duplicateRepository(pRepository, pDS,true);
110   }
111   /***
112    * Duplicates the given repository, binds it into nucleus with the suffix "-Shadow"
113    * @param pStart If true, also starts the repository
114    */
115   public static Repository duplicateRepository(GSARepository pRepository,DataSource pDS,boolean pStart) throws ServiceException{
116     Configuration c = pRepository.getServiceConfiguration();
117     Nucleus n = pRepository.getNucleus();
118     NucleusNameResolver r = new NucleusNameResolver(n, n,
119         pRepository.getNameContext(), true);
120     GSARepository newRepository = null;
121     if(pRepository instanceof VersionRepository) {
122       newRepository = (GSARepository) c.createNewInstance(((VersionRepository)pRepository).getWrappedRepository());
123       c.configureService(newRepository, r, ((VersionRepository)pRepository).getWrappedRepository());
124     }
125     else {
126       newRepository = (GSARepository) c.createNewInstance(pRepository);
127       c.configureService(newRepository, r, pRepository);
128     }
129     newRepository.setDataSource(pDS);
130     newRepository.setForeignRepositorySuffix("-Shadow");
131 
132     /*
133     // Fool this new repository into thinking that it has been
134     // bound to the same name context as the original repository
135     // This changes will make sure that getAbsoluteName() returns
136     // a correct value.
137     NameContext nc = ((GenericService) pRepository).getNameContext();
138     NameContextBindingEvent bindingEvent = new NameContextBindingEvent(pRepository
139         .getName()+"-Shadow", newRepository, pRepository.getNameContext());
140     newRepository.nameContextElementBound(bindingEvent);
141     */
142     NameContext nc = ((GenericService) pRepository).getNameContext();
143     nc.putElement(pRepository.getName()+"-Shadow", newRepository);
144 
145     if (pStart) 
146       startRepository(pRepository, c, n, newRepository);
147     return newRepository;
148   }
149   /***
150    * @param pRepository
151    * @param c
152    * @param n
153    * @param newRepository
154    * @throws ServiceException
155    */
156   private static void startRepository(GSARepository pRepository, Configuration c, Nucleus n, GSARepository newRepository) throws ServiceException {
157     ServiceEvent ev = new ServiceEvent(pRepository, newRepository, n, c);
158     /*
159      * We are purposefully not putting the new repository into the parent's name
160      * context. The existing repository is always the valid one. We're starting
161      * this new guy, then we're going to synchronize on the repository and get
162      * all of its info into us.
163      */
164 
165     // we have to set the new repository as temporary so it won't call
166     // restart and start an infinite recursion
167 //    newRepository.setIsTemporaryInstantiation(true);
168     
169     // But don't load data
170     if (newRepository instanceof InitializingGSA)
171       ((InitializingGSA)newRepository).setImportFiles(null);
172 
173 
174     newRepository.startService(ev);
175     if (newRepository.isRunning()) {
176       synchronized (pRepository) {
177 //        newRepository.copyFromOtherRepository(pRepository);
178         newRepository.invalidateCaches();
179       }
180     }
181   }
182   /***
183    * Given a directory, pRoot, this method creates the minimal .properties files
184    * required to startup a GSA Repository from Nucleus.
185    * 
186    * The pJDBCProperties parameter should contain the JDBC properties used to
187    * create a FakeXADataSource. Required Properties are: driver URL user
188    * password
189    * 
190    * For example, driver=solid.jdbc.SolidDriver URL=jdbc:solid://localhost:1313
191    * user=admin password=admin
192    * 
193    * <BR>
194    * One should call the <code>cleanup()</code> method to remove any files
195    * created by this method call.
196    * 
197    * @param pRoot
198    *          The root directory of the testing configpath
199    * @param pRepositoryPath
200    *          The Nucleus path of your testing repository
201    * @param pDefinitionFiles
202    *          Array of Nucleus paths to definition files
203    * @param pJDBCProperties
204    *          properties object containing JDBC connection information
205    * @param pImportFile
206    * @throws IOException
207    * @throws Exception
208    * @see GSATestUtils.cleanup
209    */
210   public  void initializeMinimalConfigpath(File pRoot,
211       String pRepositoryPath, String[] pDefinitionFiles,
212       Properties pJDBCProperties, String pCreateSQLAbsolutePath, String pDropSQLAbsolutePath, String[] pImportFile) throws IOException, Exception {
213     initializeMinimalConfigpath(pRoot, pRepositoryPath, pDefinitionFiles, pJDBCProperties, pCreateSQLAbsolutePath, pDropSQLAbsolutePath, pImportFile, true);
214   }
215   
216   /***
217    * Given a directory, pRoot, this method creates the minimal .properties files
218    * required to startup a GSA Repository from Nucleus.
219    * 
220    * The pJDBCProperties parameter should contain the JDBC properties used to
221    * create a FakeXADataSource. Required Properties are: driver URL user
222    * password
223    * 
224    * For example, driver=solid.jdbc.SolidDriver URL=jdbc:solid://localhost:1313
225    * user=admin password=admin
226    * 
227    * <BR>
228    * One should call the <code>cleanup()</code> method to remove any files
229    * created by this method call.
230    * 
231    * @param pRoot
232    *          The root directory of the testing configpath
233    * @param pRepositoryPath
234    *          The Nucleus path of your testing repository
235    * @param pDefinitionFiles
236    *          Array of Nucleus paths to definition files
237    * @param pJDBCProperties
238    *          properties object containing JDBC connection information
239    * @param pImportFile
240    * @param pLogging if true log to stdout, else logging is disabled
241    * @throws IOException
242    * @throws Exception
243    * @see GSATestUtils.cleanup
244    */
245   public  void initializeMinimalConfigpath(File pRoot,
246       String pRepositoryPath, String[] pDefinitionFiles,
247       Properties pJDBCProperties, String pCreateSQLAbsolutePath, String pDropSQLAbsolutePath, String[] pImportFile, boolean pLogging) throws IOException, Exception {
248    initializeMinimalConfigpath(pRoot, pRepositoryPath, pDefinitionFiles, pJDBCProperties, pCreateSQLAbsolutePath, pDropSQLAbsolutePath, pImportFile, pLogging, null, null);
249   
250   }
251   
252   
253   public  void initializeMinimalConfigpath(File pRoot,
254       String pRepositoryPath, String[] pDefinitionFiles,
255       Properties pJDBCProperties, String pCreateSQLAbsolutePath, String pDropSQLAbsolutePath, String[] pImportFile, boolean pLogging, String pFakeXADataSourceComponentName, String pJTDataSourceComponentName) throws IOException, Exception {
256     if (pRepositoryPath != null)
257       createRepositoryPropertiesFile(pRoot, pRepositoryPath,
258           pDefinitionFiles, pCreateSQLAbsolutePath, pDropSQLAbsolutePath, pImportFile, pJTDataSourceComponentName);
259     createTransactionManager(pRoot);
260     createUserTransaction(pRoot);
261     createXMLToolsFactory(pRoot);
262     createIdGenerator(pRoot);
263     createClientLockManager(pRoot);
264     DBUtils.createJTDataSource(pRoot);
265     if(pJDBCProperties != null)
266       GSATestUtils.createFakeXADataSource(pRoot, pJDBCProperties,pFakeXADataSourceComponentName);
267     else 
268       GSATestUtils.createFakeXADataSource(pRoot,DBUtils.getHSQLDBInMemoryDBConnection(), pFakeXADataSourceComponentName);
269     if(pFakeXADataSourceComponentName == null && pJTDataSourceComponentName == null)
270       DBUtils.createJTDataSource(pRoot);
271     else 
272       DBUtils.createJTDataSource(pRoot, pJTDataSourceComponentName, pFakeXADataSourceComponentName);
273     createGlobal(pRoot);
274     createScreenLog(pRoot, pLogging);
275     createIdSpaces(pRoot);
276     if(pJDBCProperties != null)
277       createIDGeneratorTables(new DBUtils(pJDBCProperties));
278     else 
279       createIDGeneratorTables(new DBUtils(DBUtils.getHSQLDBInMemoryDBConnection()));
280     createSQLRepositoryEventServer(pRoot);
281     createNucleus(pRoot);
282   
283   }
284 
285   // ---------------------------
286   /***
287    * Deletes any files created by initializing the configpath
288    *  
289    */
290   public  void cleanup() {
291     Iterator<File> iter = mFilesCreated.iterator();
292     while (iter.hasNext()) {
293       File f =  iter.next();
294       f.delete();
295     }
296     mFilesCreated.clear();
297   }
298 
299   // ---------------------------
300   /***
301    * Writes the idspaces.xml file
302    */
303   public  File createIdSpaces(File pRoot) throws IOException {
304     String idspaces = "<?xml version=\"1.0\" encoding=\"utf-8\"?><!DOCTYPE id-spaces SYSTEM \"http://www.atg.com/dtds/idgen/idgenerator_1.0.dtd\"><id-spaces><id-space name=\"__default__\" seed=\"1\" batch-size=\"100000\"/><id-space name=\"jms_msg_ids\" seed=\"0\" batch-size=\"10000\"/><id-space name=\"layer\" seed=\"0\" batch-size=\"100\"/></id-spaces>";
305     File idspacesFile = new File(pRoot.getAbsolutePath()
306         + "/atg/dynamo/service/idspaces.xml");
307     if (idspacesFile.exists())
308       idspacesFile.delete();
309     idspacesFile.getParentFile().mkdirs();
310     idspacesFile.createNewFile();
311     FileWriter out = new FileWriter(idspacesFile);
312     try {
313       out.write(idspaces);
314       out.write("\n");
315     }
316     catch (IOException e) {
317       e.printStackTrace();
318 
319     }
320     finally {
321       out.flush();
322       out.close();
323     }
324     return idspacesFile;
325   }
326   
327   // ---------------------------------
328   /*** Creates Nucleus' Nucleus.properties
329    * 
330    */
331   public File createNucleus(File pRoot) throws IOException {
332     Properties prop = new Properties();
333     prop.put("initialServiceName","/Initial");
334     return NucleusTestUtils.createProperties("Nucleus", pRoot, "atg.nucleus.Nucleus", prop);
335   }
336   
337 
338 //---------------------------
339   public  static File createFakeXADataSource(File pRoot,
340       Properties pJDBCProperties, String pName) throws IOException {
341     /*---- #
342      * @version $Id:
343      *          //product/DAS/main/templates/DAS/config/config/atg/dynamo/service/jdbc/FakeXADataSource.properties#3
344      *          $$Change: 410369 $
345      *          #-------------------------------------------------------------------
346      *          #------------------------------------------------------------------- #
347      *          This is a non-XA DataSource that creates simulated
348      *          XAConnections. # It is useful when a true XADataSource cannot be
349      *          obtained. Note that # the behaviour of the Connections will not
350      *          be that of normal # XAConnections, i.e. they will not be able to
351      *          participate in # two-phase commits in the true two-phase commit
352      *          style.
353      *          #-------------------------------------------------------------------
354      * 
355      * $class=atg.service.jdbc.FakeXADataSource
356      * 
357      * driver=solid.jdbc.SolidDriver URL=jdbc:solid://localhost:1313 user=admin
358      * password=admin
359      *  
360      */
361     String name = pName;
362     if (name == null)
363       name = "FakeXADataSource";
364     pJDBCProperties.put("transactionManager",
365         "/atg/dynamo/transaction/TransactionManager");
366     return NucleusTestUtils.createProperties(name, new File(pRoot
367         .getAbsolutePath()
368         + "/atg/dynamo/service/jdbc"), "atg.service.jdbc.FakeXADataSource",
369         pJDBCProperties);
370   }
371   
372   // ---------------------------------
373   /***
374    * @param pRoot
375    * @throws IOException
376    */
377   public static File createJTDataSource(File pRoot) throws IOException {
378     return createJTDataSource(pRoot, null,null);
379   }
380 
381   // ------------------------------------
382   /***
383    * Creates a new JTDataSource component. The name of the component may
384    * be specified by passing in a non null value for pName.
385    * Also the name of the FakeXADataSource may be specified by passing in a non null name.
386    * Otherwise the defaults are JTDataSource and FakeXADataSource.
387    * 
388    * @param pRoot
389    * @param pName
390    * @param pFakeXAName
391    * @return
392    * @throws IOException
393    */
394   public static File createJTDataSource(File pRoot, String pName, String pFakeXAName)
395       throws IOException {
396     /*
397      * ---- #
398      * 
399      * @version $Id:
400      *          //product/DAS/main/templates/DAS/config/config/atg/dynamo/service/jdbc/JTDataSource.properties#3
401      *          $$Change: 410369 $
402      *          #-------------------------------------------------------------------
403      *          #------------------------------------------------------------------- #
404      *          This is a pooling DataSource that creates Connections registered #
405      *          with the calling threads current Transaction. It must always be #
406      *          given a TransactionManager and an XADataSource.
407      *          #-------------------------------------------------------------------
408      * 
409      * $class=atg.service.jdbc.MonitoredDataSource # only use this data source
410      * if you do not have an JDBC driver # which provides true XA data sources
411      * dataSource=/atg/dynamo/service/jdbc/FakeXADataSource # Minimum and
412      * maximum number of connections to keep in the pool min=10 max=10
413      * blocking=true
414      * 
415      * #maxBlockTime= #maxCreateTime= #maxCreateAttempts= # # This will log any
416      * SQLWarnings that are generated. By default, we turn # these off since
417      * they tend to be informational, not really warnings. If # you want the
418      * full traceback for where these messages are generated, # set
419      * loggingWarning to true. # loggingSQLWarning=false # # The monitored
420      * connection by default logs all sql through the log info # path. #
421      * loggingSQLInfo=false
422      */
423     String name = pName;
424     if (name == null)
425       name = "JTDataSource";
426 
427     String fakeXAName = pFakeXAName;
428     if (fakeXAName == null) fakeXAName = 
429     "FakeXADataSource";
430 
431     Properties props = new Properties();
432     props.put("dataSource", "/atg/dynamo/service/jdbc/" + fakeXAName);
433     props.put("transactionManager",
434         "/atg/dynamo/transaction/TransactionManager");
435     props.put("min", "10");
436     props.put("max", "20");
437     props.put("blocking", "true");
438     props.put("loggingSQLWarning", "false");
439     props.put("loggingSQLInfo", "false");
440     props.put("loggingSQLDebug", "false");
441 
442 
443     return NucleusTestUtils.createProperties(name, new File(pRoot
444         .getAbsolutePath()
445         + "/atg/dynamo/service/jdbc"), "atg.service.jdbc.MonitoredDataSource",
446         props);
447   }
448 
449   // ---------------------------------
450   /***
451    * Creates a SQLRepositoryEventServer
452    * 
453    * @param pRoot
454    * @return
455    */
456   public  File createSQLRepositoryEventServer(File pRoot)
457       throws IOException {
458 
459     Properties prop = new Properties();
460     prop.put("handlerCount", "0");
461     return NucleusTestUtils.createProperties("SQLRepositoryEventServer",
462         new File(pRoot.getAbsolutePath() + "/atg/dynamo/server"),
463         "atg.adapter.gsa.event.GSAEventServer", prop);
464   }
465 
466   // ---------------------------
467   /***
468    * Creates a ScreenLog component
469    * 
470    * @param pRoot
471    * @param pLogging TODO
472    * @return
473    * @throws IOException
474    */
475   public  File createScreenLog(File pRoot, boolean pLogging) throws IOException {
476     Properties prop = new Properties();
477     prop.put("cropStackTrace", "false");
478     prop.put("loggingEnabled", String.valueOf(pLogging));
479     return NucleusTestUtils.createProperties("ScreenLog", new File(pRoot
480         .getAbsolutePath()
481         + "/atg/dynamo/service/logging"),
482         "atg.nucleus.logging.PrintStreamLogger", prop);
483   }
484 
485   // ---------------------------
486   /***
487    * Creates a GLOBAL.properties
488    * 
489    * @param pRoot
490    * @param pJDBCProperties
491    * @return
492    * @throws IOException
493    */
494   public  File createGlobal(File pRoot) throws IOException {
495     Properties prop = new Properties();
496     prop.put("logListeners", "atg/dynamo/service/logging/ScreenLog");
497     prop.put("loggingDebug","false");
498     return NucleusTestUtils.createProperties("GLOBAL", new File(pRoot
499         .getAbsolutePath()
500         + "/"), null, prop);
501 
502   }
503 
504   // ---------------------------------
505   /***
506    * @param pRoot
507    * @throws IOException
508    */
509   public  File createClientLockManager(File pRoot) throws IOException {
510     /*
511      * @version $Id:
512      *          //product/DAS/main/templates/DAS/config/config/atg/dynamo/service/ClientLockManager.properties#3
513      *          $$Change: 410369 $
514      *          $class=atg.service.lockmanager.ClientLockManager
515      *          lockServerAddress=localhost lockServerPort=9010
516      *          useLockServer=false
517      */
518     Properties props = new Properties();
519     props.put("lockServerAddress", "localhost");
520     props.put("lockServerPort", "9010");
521     props.put("useLockServer", "false");
522     return NucleusTestUtils.createProperties("ClientLockManager", new File(
523         pRoot.getAbsolutePath() + "/atg/dynamo/service"),
524         "atg.service.lockmanager.ClientLockManager", props);
525   }
526   // ---------------------------------
527   /***
528    * @param pRoot
529    * @throws IOException
530    */
531   public  File createIdGenerator(File pRoot) throws IOException {
532     /*
533      * @version $Id:
534      *          //product/DAS/main/templates/DAS/config/config/atg/dynamo/service/IdGenerator.properties#3
535      *          $$Change: 410369 $
536      *          #-------------------------------------------------------------------
537      *          #------------------------------------------------------------------- #
538      *          Default id generator service. This service generates ids using
539      *          an # SQL database table. The ids are suitable for use with
540      *          persistent # objects.
541      *          #-------------------------------------------------------------------
542      * 
543      * $class=atg.service.idgen.SQLIdGenerator
544      * 
545      * dataSource=/atg/dynamo/service/jdbc/JTDataSource
546      * transactionManager=/atg/dynamo/transaction/TransactionManager
547      * XMLToolsFactory=/atg/dynamo/service/xml/XMLToolsFactory # all properties
548      * of type XMLFile *MUST* use an absolute # component path. Applications
549      * should append generally # append to this property.
550      * initialIdSpaces=/atg/dynamo/service/idspaces.xml
551      * 
552      * ---- #
553      */
554     Properties props = new Properties();
555     props.put("dataSource", "/atg/dynamo/service/jdbc/JTDataSource");
556     props.put("transactionManager",
557         "/atg/dynamo/transaction/TransactionManager");
558     props.put("XMLToolsFactory", "/atg/dynamo/service/xml/XMLToolsFactory");
559     // props.put("initialIdSpaces", "/atg/dynamo/service/idspaces.xml ");
560     return NucleusTestUtils.createProperties("IdGenerator", new File(pRoot
561         .getAbsolutePath()
562         + "/atg/dynamo/service/"), "atg.service.idgen.SQLIdGenerator", props);
563   }
564   // ---------------------------------
565   /***
566    * @param pRoot
567    * @throws IOException
568    */
569   public  File createXMLToolsFactory(File pRoot) throws IOException {
570     /*
571      * ---- #
572      * 
573      * @version $Id:
574      *          //product/DAS/main/templates/DAS/config/config/atg/dynamo/service/xml/XMLToolsFactory.properties#3
575      *          $$Change: 410369 $
576      *          $class=atg.xml.tools.apache.ApacheXMLToolsFactory $scope=global
577      *          parserFeatures=
578      * 
579      * ---- #
580      */
581     File root = new File(pRoot.getAbsolutePath() + "/atg/dynamo/service/xml");
582     return NucleusTestUtils.createProperties("XMLToolsFactory", root,
583         "atg.xml.tools.apache.ApacheXMLToolsFactory", new Properties());
584   }
585   // ---------------------------------
586   /***
587    * @param pRoot
588    * @throws IOException
589    */
590   public  File createTransactionManager(File pRoot) throws IOException {
591     /*
592      * *
593      * 
594      * @version $Id:
595      *          //product/DAS/main/templates/DAS/config/config/atg/dynamo/transaction/TransactionManager.properties#3
596      *          $$Change: 410369 $ ############################## # # The Dynamo
597      *          implementation of javax.transaction.TransactionManager #
598      * 
599      * $class=atg.dtm.TransactionManagerImpl
600      */
601     Properties props = new Properties();
602     props.put("loggingDebug","false");
603     File root = new File(pRoot, "/atg/dynamo/transaction");
604     root.mkdirs();
605     NucleusTestUtils.createProperties("TransactionDemarcationLogging", root,
606         "atg.dtm.TransactionDemarcationLogging", props);
607     
608     return NucleusTestUtils.createProperties("TransactionManager", root,
609         "atg.dtm.TransactionManagerImpl", props);
610   }
611   // ---------------------------------
612   /***
613    * Creates the UserTransaction component
614    */
615   public File createUserTransaction(File pRoot) throws IOException {
616     Properties props = new Properties();
617     props.put("transactionManager","/atg/dynamo/transaction/TransactionManager");
618     return NucleusTestUtils.createProperties("UserTransaction",new File(pRoot,"/atg/dynamo/transaction"),"atg.dtm.UserTransactionImpl",props);
619   }
620   
621   // ---------------------------------
622   /***
623    * Creates a .properties file for the given repository.
624    * The actual repository implementation is a
625    * <code>atg.adapter.gsa.InitializingGSA</code> class.
626    * This implementation is used instead because it has the ability
627    * to create tables and import data before the repository starts.
628    * @param pRoot
629    * @param pRepositoryPath
630    * @param pDefinitionFiles
631    * @param pSQLAbsolutePath
632    * @param pDropSQLAbsolutePath
633    * @param pImportFiles
634    * @throws IOException
635    */
636   public  File createRepositoryPropertiesFile(File pRoot,
637       String pRepositoryPath, String[] pDefinitionFiles, String pCreateSQLAbsolutePath, String pDropSQLAbsolutePath, String[] pImportFiles) throws IOException {
638     return createRepositoryPropertiesFile(pRoot, pRepositoryPath, pDefinitionFiles, pCreateSQLAbsolutePath, pDropSQLAbsolutePath, pImportFiles, null);
639   }
640   // ---------------------------------
641   /***
642    * Creates a .properties file for the given repository.
643    * The actual repository implementation is a
644    * <code>atg.adapter.gsa.InitializingGSA</code> class.
645    * This implementation is used instead because it has the ability
646    * to create tables and import data before the repository starts.
647    * @param pRoot
648    * @param pRepositoryPath
649    * @param pDefinitionFiles
650    * @param pSQLAbsolutePath
651    * @param pDropSQLAbsolutePath
652    * @param pImportFiles
653    * @throws IOException
654    */
655   public  File createRepositoryPropertiesFile(File pRoot,
656       String pRepositoryPath, String[] pDefinitionFiles, String pCreateSQLAbsolutePath, String pDropSQLAbsolutePath, String[] pImportFiles, String pJTDataSourceName) throws IOException {
657     /*
658      * #
659      * 
660      * @version $Id: //test/UnitTests/base/main/src/Java/atg/adapter/gsa/GSATestUtils.java#28 $$Change: 410369 $ $class=atg.adapter.gsa.GSARepository
661      * 
662      * repositoryName=RefRepository definitionFiles=/atg/repository/lv/ref.xml
663      * XMLToolsFactory=/atg/dynamo/service/xml/XMLToolsFactory
664      * transactionManager=/atg/dynamo/transaction/TransactionManager
665      * idGenerator=/atg/dynamo/service/IdGenerator
666      * dataSource=/atg/dynamo/service/jdbc/JTDataSource
667      * lockManager=/atg/dynamo/service/ClientLockManager
668      * groupContainerPath=/atg/registry/RepositoryGroups
669      * useSetUnicodeStream=true ---- #
670      */
671     //    String clazz = "atg.adapter.gsa.GSARepository";
672     String clazz = sClassName;
673     if(mVersioned)
674       clazz = sVersionedClassName;
675     
676     Properties props = new Properties();
677     props.put("repositoryName", "TestRepository"+System.currentTimeMillis());
678     StringBuffer definitionFiles = new StringBuffer();
679     for (int i = 0; i < pDefinitionFiles.length; i++) {
680       Object obj = this.getClass().getClassLoader().getResource(pDefinitionFiles[i]);
681       if (obj != null) {
682         log.debug("Repository definition file "
683                 + pDefinitionFiles[i]
684                 + " Does not exist in configpath. But it does in classpath. Copying over to configpath");
685         copyToConfigpath(pRoot, pDefinitionFiles[i]);
686       } else if(obj == null && !new File(pRoot, pDefinitionFiles[i]).exists()){
687         throw new AssertionError("ERROR: Repository definition file "
688             + pDefinitionFiles[i] + "  not found in classpath or configpath: " + pRoot);
689       }
690         
691       definitionFiles.append("/"+pDefinitionFiles[i]);
692       if (i < (pDefinitionFiles.length - 1))
693         definitionFiles.append(",");
694     }
695     props.put("definitionFiles", definitionFiles.toString());
696     if(pImportFiles != null){
697       StringBuffer importFiles = new StringBuffer();
698       for (int i = 0; i < pImportFiles.length; i++) {
699         Object obj = this.getClass().getClassLoader().getResource(
700             pDefinitionFiles[i]);
701         if (obj != null) {
702           System.out
703               .println("DEBUG: import file "
704                   + pDefinitionFiles[i]
705                   + " Does not exist in configpath. But it does in classpath. Copying over to configpath");
706           copyToConfigpath(pRoot, pImportFiles[i]);
707         } else if (obj == null && !new File(pRoot, pImportFiles[i]).exists()) {
708           throw new AssertionError("ERROR: Repository definition file "
709               + pDefinitionFiles[i] + "  not found in classpath or configpath.");
710         }
711 
712         importFiles.append(new File(pRoot, pImportFiles[i]).getAbsolutePath());
713         if (i < (pImportFiles.length - 1))
714           importFiles.append(",");
715       }
716       props.put("importFiles", importFiles.toString());
717       props.put("importEveryStartup", "true");
718     }
719     props.put("XMLToolsFactory", "/atg/dynamo/service/xml/XMLToolsFactory");
720     props.put("transactionManager",
721         "/atg/dynamo/transaction/TransactionManager");
722     props.put("idGenerator", "/atg/dynamo/service/IdGenerator");
723     if(pJTDataSourceName == null)
724       props.put("dataSource", "/atg/dynamo/service/jdbc/JTDataSource");
725     else 
726       props.put("dataSource", "/atg/dynamo/service/jdbc/"+pJTDataSourceName);
727     props.put("lockManager", "/atg/dynamo/service/ClientLockManager");
728     props.put("idspaces", "/atg/dynamo/service/idspaces.xml");
729     props.put("groupContainerPath", "/atg/registry/RepositoryGroups");
730     props.put("restartingAfterTableCreation", "false");
731     props.put("createTables", "true");
732     props.put("loggingError", "true");    
733     if(pCreateSQLAbsolutePath != null)
734       props.put("sqlCreateFiles","default="+pCreateSQLAbsolutePath);
735     
736     if(pDropSQLAbsolutePath != null)
737       props.put("sqlDropFiles","default="+pDropSQLAbsolutePath);    
738     props.put("loggingDebug", "false");
739     props.put("loggingCreateTables", "false");
740 //    props.put("debugLevel", "7");
741 
742     // InitializingGSA specific properties
743     props.put("dropTablesIfExist", "true");
744     props.put("dropTablesAtShutdown", "false");
745     props.put("stripReferences","true");
746     int endIndex = pRepositoryPath.lastIndexOf("/");
747     String repositoryDir = pRepositoryPath.substring(0, endIndex);
748     String repositoryName = pRepositoryPath.substring(endIndex + 1,
749         pRepositoryPath.length());
750     File root = new File(pRoot, repositoryDir);
751     root.mkdirs();
752 
753     if(mVersioned) props.putAll(additionalVersionProperties(pRoot,pRepositoryPath, repositoryName)); 
754     return NucleusTestUtils
755         .createProperties(repositoryName, root, clazz, props);
756   }
757   
758 /***
759    * @param pRoot
760  * @param pRepositoryPath
761  * @param pRepositoryName
762  * @return
763  * @throws IOException
764    */
765   protected  Map<String, String> additionalVersionProperties(File pRoot, String pRepositoryPath, String pRepositoryName) throws IOException {
766     
767     copyToConfigpath(pRoot, "atg/adapter/version/versionmanager/versionManagerRepository.xml");
768     GSATestUtils.getGSATestUtils()
769         .createRepositoryPropertiesFile(
770             pRoot,
771             "/atg/adapter/version/versionmanager/VersionManagerRepository",
772             new String[] { "/atg/adapter/version/versionmanager/versionManagerRepository.xml" }, null, null, null);
773     // create the AssetFactory
774     NucleusTestUtils
775     .createProperties("/atg/adapter/version/versionmanager/AssetFactory", pRoot, "atg.versionmanager.impl.AssetFactoryRepositoryImpl", null);
776     // create the AssetVersionFactory
777     NucleusTestUtils
778     .createProperties("/atg/adapter/version/versionmanager/AssetVersionFactory", pRoot, "atg.versionmanager.impl.AssetVersionFactoryRepositoryImpl", null);
779     
780     NucleusTestUtils
781     .createProperties("/atg/adapter/version/versionmanager/BranchFactory", pRoot, "atg.versionmanager.impl.BranchFactoryRepositoryImpl", null);
782     
783     NucleusTestUtils
784     .createProperties("/atg/adapter/version/versionmanager/DevelopmentLineFactory", pRoot, "atg.versionmanager.impl.DevelopmentLineFactoryRepositoryImpl", null);
785     
786     NucleusTestUtils
787     .createProperties("/atg/adapter/version/versionmanager/SnapshotFactory", pRoot, "atg.versionmanager.impl.SnapshotFactoryRepositoryImpl", null);
788         
789     NucleusTestUtils
790     .createProperties("/atg/adapter/version/versionmanager/WorkspaceFactory", pRoot, "atg.versionmanager.impl.WorkspaceFactoryRepositoryImpl", null);
791     Properties props = new Properties();
792     
793     props.put("assetFactory","AssetFactory");
794     props.put("repository","VersionManagerRepository");
795     props.put("branchFactory","BranchFactory");
796     props.put("developmentLineFactory","DevelopmentLineFactory");
797     props.put("snapshotFactory","SnapshotFactory");
798     props.put("assetVersionFactory","AssetVersionFactory");
799     props.put("workspaceFactory","WorkspaceFactory");
800     props.put("versionedRepositories",pRepositoryName+"="+pRepositoryPath);
801     props.put("sendCheckinEvents","false");
802     props.put("clientLockManager","/atg/dynamo/service/ClientLockManager");
803     
804     NucleusTestUtils
805     .createProperties("/atg/adapter/version/versionmanager/VersionManagerService", pRoot, "atg.versionmanager.VersionManager", props);
806 
807     //create a version manager and version manager repository
808     //createVersionManager();
809     Map<String, String> extraProps= new HashMap<String, String>();
810     props.put("versionManager", "/atg/adapter/version/versionmanager/VersionManagerService");
811     props.put("versionItemsByDefault", "true");
812     return extraProps;
813   }
814 
815   /***
816  * @param prop
817  * @throws FileNotFoundException
818  * @throws IOException
819  */
820 public void copyToConfigpath(File pConfigRoot, String pString) throws FileNotFoundException, IOException {
821   copyToConfigpath(pConfigRoot, pString, null);
822 }
823 
824 /***
825  * @param prop
826  * @param configPath where in config path the file must be copied.
827  * @throws FileNotFoundException
828  * @throws IOException
829  */
830 public void copyToConfigpath(File pConfigRoot, String pString, String configPath) throws FileNotFoundException, IOException {
831   // create the version manager repository
832   pConfigRoot.mkdirs();
833   String path = pString;
834   if(configPath == null)
835     configPath = path.substring(0, path.lastIndexOf('/'));
836   File dir = new File(pConfigRoot, configPath);
837   dir.mkdirs();
838   File prop = new File(dir, path.substring(path.lastIndexOf('/')));
839   if (prop.exists()) prop.delete();
840   prop.createNewFile();
841   OutputStream os = new FileOutputStream(prop);
842   InputStream dataStream = this.getClass().getClassLoader().getResourceAsStream(pString);
843   while(dataStream.available() != 0){
844     byte[] buff = new byte[1024];
845     int available = dataStream.available();
846     dataStream.read(buff);
847     os.write(buff, 0, available >= 1024 ? 1024: available); 
848   }
849   os.flush();
850 }
851 
852   //---------------------------------
853   /***
854    * Creates a .properties file for the given repository.
855    * The actual repository implementation is a
856    * <code>atg.adapter.gsa.InitializingGSA</code> class.
857    * This implementation is used instead because it has the ability
858    * to create tables and import data before the repository starts.
859    * @param pRoot
860    * @param pRepositoryPath
861    * @param pDefinitionFiles
862    * @throws IOException
863    */
864   public  File createVersionRepositoryPropertiesFile(File pRoot,
865       String pRepositoryPath, String[] pDefinitionFiles) throws IOException {
866     /*
867      * #
868      * 
869      * @version $Id: //test/UnitTests/base/main/src/Java/atg/adapter/gsa/GSATestUtils.java#28 $$Change: 410369 $ $class=atg.adapter.gsa.GSARepository
870      * 
871      * repositoryName=RefRepository definitionFiles=/atg/repository/lv/ref.xml
872      * XMLToolsFactory=/atg/dynamo/service/xml/XMLToolsFactory
873      * transactionManager=/atg/dynamo/transaction/TransactionManager
874      * idGenerator=/atg/dynamo/service/IdGenerator
875      * dataSource=/atg/dynamo/service/jdbc/JTDataSource
876      * lockManager=/atg/dynamo/service/ClientLockManager
877      * groupContainerPath=/atg/registry/RepositoryGroups
878      * useSetUnicodeStream=true ---- #
879      */
880     //    String clazz = "atg.adapter.gsa.GSARepository";
881     String clazz = "atg.adapter.gsa.InitializingVersionRepository";
882     Properties props = new Properties();
883     props.put("repositoryName", "TestRepository");
884     StringBuffer definitionFiles = new StringBuffer();
885     for (int i = 0; i < pDefinitionFiles.length; i++) {
886       definitionFiles.append(pDefinitionFiles[i]);
887       if (i < (pDefinitionFiles.length - 1))
888         definitionFiles.append(",");
889     }
890     props.put("definitionFiles", definitionFiles.toString());
891     props.put("XMLToolsFactory", "/atg/dynamo/service/xml/XMLToolsFactory");
892     props.put("transactionManager",
893         "/atg/dynamo/transaction/TransactionManager");
894     props.put("idGenerator", "/atg/dynamo/service/IdGenerator");
895     props.put("dataSource", "/atg/dynamo/service/jdbc/JTDataSource");
896     props.put("lockManager", "/atg/dynamo/service/ClientLockManager");
897     props.put("groupContainerPath", "/atg/registry/RepositoryGroups");
898     props.put("versionManager", "/atg/test/version/VersionManager");
899     props.put("versionItemByDefault", "true");
900     props.put("loggingDebug", "true");
901 //    props.put("debugLevel", "7");
902 
903     // InitializingGSA specific properties
904     props.put("dropTablesIfExist", "true");
905     props.put("dropTablesAtShutdown", "false");
906     props.put("stripReferences","true");
907     int endIndex = pRepositoryPath.lastIndexOf("/");
908     String repositoryDir = pRepositoryPath.substring(0, endIndex);
909     String repositoryName = pRepositoryPath.substring(endIndex + 1,
910         pRepositoryPath.length());
911     File root = new File(pRoot, repositoryDir);
912     root.mkdirs();
913 
914     ;
915 
916     return NucleusTestUtils
917         .createProperties(repositoryName, root, clazz, props);
918   }
919   
920   // ---------------------------------
921   /***
922    * Returns all the tables names used for the given repository.
923    */
924   public   String []  getTableNames(GSARepository pRepository) throws Exception {
925     ArrayList<String> names = new ArrayList<String>();
926     String[] descriptorNames = pRepository.getItemDescriptorNames();
927     
928     GSAItemDescriptor itemDescriptors[];
929     
930     int i, length = descriptorNames.length;
931     
932     itemDescriptors = new GSAItemDescriptor[length];
933     for (i=0; i<length; i++) {
934       itemDescriptors[i] = (GSAItemDescriptor)pRepository.getItemDescriptor(descriptorNames[i]);
935     }
936     
937   //  String create = null;
938  //   String index = null;
939     for (i=0; i<length; i++) {
940       GSAItemDescriptor desc = itemDescriptors[i];
941       Table[] tables = desc.getTables();
942       if ( tables != null ) {
943         for (int j = 0; j < tables.length; j++) {
944           String name = tables[j].getName();
945           names.add(name);
946         }
947       }
948     }
949     return (String[])names.toArray(new String[0]);
950   }
951   // ---------------------------------
952   /***
953    * Given a repository, and the DBUtils object used to create the connection for that
954    * Repository, this method asserts that all the tables are empty
955    * @param dbTwo
956    * @param storeRepository
957    * @throws Exception
958    * @throws SQLException
959    */
960   public  void assertEmptyRepository(DBUtils dbTwo, GSARepository storeRepository) throws Exception, SQLException {
961     String [] namesAfter  = getTableNames(storeRepository);
962     for (int i = 0 ; i < namesAfter.length; i++) {
963       log.info(namesAfter[i] + ":" + dbTwo.getRowCount(namesAfter[i]));
964       Assert.assertEquals(0,dbTwo.getRowCount(namesAfter[i]));
965     }
966   }
967   // ---------------------------------
968   /***
969    * Creates the das_id_generator tables using the given database
970    * @param db
971    * @throws SQLException
972    */
973   public  void createIDGeneratorTables(DBUtils db) throws SQLException {
974     try {
975       if(!db.isDB2())
976       db
977           .update(" create table das_id_generator (id_space_name   varchar(60)     not null,"
978               + "seed    numeric(19,0)   not null, batch_size      integer not null, prefix  varchar(10)     null,"
979               + " suffix  varchar(10)     null, primary key (id_space_name)) ");
980       else 
981         db
982         .update(" create table das_id_generator (id_space_name   varchar(60)     not null,"
983             + "seed    numeric(19,0)   not null, batch_size      integer not null, prefix  varchar(10)  default   null,"
984             + " suffix  varchar(10)   default  null, primary key (id_space_name)) ");
985     }
986     catch (SQLException e) {
987       // drop and try again
988       log.info("DROPPING DAS_ID_GENERATOR");
989       db.update("drop table das_id_generator");
990       if(!db.isDB2())
991         db
992             .update(" create table das_id_generator (id_space_name   varchar(60)     not null,"
993                 + "seed    numeric(19,0)   not null, batch_size      integer not null, prefix  varchar(10)     null,"
994                 + " suffix  varchar(10)     null, primary key (id_space_name)) ");
995         else 
996           db
997           .update(" create table das_id_generator (id_space_name   varchar(60)     not null,"
998               + "seed    numeric(19,0)   not null, batch_size      integer not null, prefix  varchar(10)  default   null,"
999               + " suffix  varchar(10)   default  null, primary key (id_space_name)) ");
1000 
1001       
1002     }
1003   }
1004   
1005   /***
1006    * @param pVerRep
1007    * @param pImportFiles
1008    * @param pWorkspaceName
1009    * @param pDoWithoutTransaction
1010    * @param pWorkspaceComment
1011    * @throws VersionException
1012    */
1013   public static void importFiles(VersionRepository pVerRep,
1014       String[] pImportFiles, String pWorkspaceName, boolean pDoWithoutTransaction,
1015       String pWorkspaceComment, boolean pCheckin) throws VersionException {
1016     VersionManager vm = pVerRep.getVersionManager();
1017     Workspace ws = vm.getWorkspaceByName(pWorkspaceName);
1018     if (ws == null)
1019       throw new IllegalArgumentException("No such workspace " + pWorkspaceName);
1020     
1021     if(TemplateParser.importFiles(pVerRep, pImportFiles, new PrintWriter(
1022         System.out), pDoWithoutTransaction, VersioningContextUtil.createVersioningContext(ws
1023         .getName(), pWorkspaceComment, pCheckin)) != 0)
1024       throw new AssertionError("Versioned import failed");
1025   }
1026 
1027   /***
1028    * @return
1029    */
1030   public static GSATestUtils getGSATestUtils() {
1031     if(SINGLETON_DEFAULT == null)
1032        SINGLETON_DEFAULT = new GSATestUtils(false);
1033    return SINGLETON_DEFAULT;
1034   }
1035   
1036   /***
1037    * @return
1038    */
1039   public static GSATestUtils getVersionedGSATestUtils() {
1040     if(SINGLETON_VERSIONED == null)
1041       SINGLETON_VERSIONED = new GSATestUtils(true);
1042     return SINGLETON_VERSIONED;
1043     
1044   }
1045   
1046   
1047   /***
1048    * Dump all the data from a table to the console
1049    * @param pTable
1050    * @throws SQLException
1051    */
1052   public static void dumpTable(Table pTable, Collection<String> pPrintColumnNames) throws SQLException {
1053     GSARepository gsa = pTable.getItemDescriptor().getGSARepository();
1054     Connection c = null;
1055     PreparedStatement st = null;
1056     try {
1057       c = gsa.getConnection();
1058       pTable.loadColumnInfo(c);
1059       Collection<?> colNames = pPrintColumnNames;
1060       Map<?, ?> map = ((Map<?, ?>) gsa.getColumnInfoCache().get(
1061           pTable.mName));
1062       if(map == null)
1063         map = ((Map<?, ?>) gsa.getColumnInfoCache().get(
1064           pTable.mName.toUpperCase()));
1065       if(pPrintColumnNames.isEmpty())
1066       colNames = map.keySet();
1067       Iterator<?> iter0 = colNames.iterator();
1068       String sql = "SELECT ";
1069       while (iter0.hasNext()) {
1070         Object obj = iter0.next();
1071         if (iter0.hasNext())
1072           sql += obj + ",";
1073         else
1074           sql += obj;
1075       }
1076       sql += " FROM " + pTable.getBaseName();
1077       st = c.prepareStatement(sql);
1078       ResultSet rs = st.executeQuery();
1079       System.out.print("DUMP FOR TABLE: " + pTable.getBaseName().toUpperCase()
1080           + "\n");
1081       Iterator<?> iter1 = colNames.iterator();
1082       int truncateThreshold = 20;
1083       while (iter1.hasNext()) {
1084         String colname  =  (String)iter1.next();
1085         System.out.print( colname.substring(0, colname.length() > 18 ? 18:colname.length()));
1086         for (int i = 0; i < truncateThreshold-colname.length(); i++) {
1087           System.out.print(" ");
1088         }
1089         System.out.print(" ");
1090       }
1091       System.out.print("\n");
1092       while (rs.next()) {
1093         int i = 1;
1094         Iterator<?> iter = colNames.iterator();
1095         while (iter.hasNext()) {
1096           //String columnName =  iter.next();
1097           iter.next();
1098           Object obj = rs.getObject(i++);
1099           if(obj == null) obj = "NULL";
1100           System.out.print( obj.toString().substring(0, obj.toString().length() > truncateThreshold ? truncateThreshold:obj.toString().length()));
1101           for (int j = 0; j < truncateThreshold-obj.toString().length(); j++) {
1102             System.out.print(" ");
1103           }
1104           System.out.print(" ");
1105 //            for (int j = 0; j < columnName.length() - obj.toString().length(); j++) {
1106 //              System.out.print(" ");
1107 //            }
1108 //          System.out.print(obj.toString().substring(0, (obj.toString().length() > columnName.length()+18 ? columnName.length(): obj.toString().length()) ) + "        ");
1109         }
1110       }
1111     } finally {
1112       if (st != null)
1113         st.close();
1114     }
1115   }
1116 
1117   /***
1118    * @param pVersionRepository
1119    * @param pString
1120    */
1121   public static void dumpTables(GSARepository pRepository, String pItemDescriptorName) throws RepositoryException, SQLException {
1122     GSAItemDescriptor itemdesc = (GSAItemDescriptor) pRepository.getItemDescriptor(pItemDescriptorName);
1123     Table[] tables = itemdesc.getTables();
1124     HashSet<String> doneTables = new HashSet<String>();
1125     for (int i = 0; tables != null && i < tables.length; i++) {
1126       Table table = tables[i];
1127       if(doneTables.contains(table.getName())) continue;
1128       dumpTable(table, new ArrayList<String>());
1129       doneTables.add(table.getName());
1130     }
1131   }
1132 }