View Javadoc

1   package org.apache.ojb.broker.ant;
2   
3   /* Copyright 2005 The Apache Software Foundation
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  import java.io.File;
19  import java.io.FileInputStream;
20  import java.util.ArrayList;
21  import java.util.Iterator;
22  import java.util.Properties;
23  
24  import org.apache.ddlutils.io.DatabaseIO;
25  import org.apache.ddlutils.model.Database;
26  import org.apache.ddlutils.task.DatabaseTaskBase;
27  import org.apache.ojb.broker.PBKey;
28  import org.apache.ojb.broker.metadata.DescriptorRepository;
29  import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
30  import org.apache.ojb.broker.metadata.MetadataManager;
31  import org.apache.ojb.broker.metadata.RepositoryPersistor;
32  import org.apache.tools.ant.AntClassLoader;
33  import org.apache.tools.ant.BuildException;
34  import org.apache.tools.ant.DirectoryScanner;
35  import org.apache.tools.ant.Project;
36  import org.apache.tools.ant.types.FileSet;
37  
38  /**
39   * Task for inserting data XML that is defined in terms of the repository elements.
40   * 
41   * @author Thomas Dudziak
42   */
43  public class RepositoryDataTask extends DatabaseTaskBase
44  {
45      /** The sub tasks to execute. */
46      private ArrayList _commands = new ArrayList();
47      /** The alias of the jdbc connection to use (empty = default connection) */
48      private String _jcdAlias;
49      /** The properties file */
50      private File _ojbPropertiesFile;
51      /** The repository file */
52      private File _repositoryFile;
53      /** A single schema file to read. */
54      private File _singleSchemaFile = null;
55      /** The input files. */
56      private ArrayList _fileSets = new ArrayList();
57      /** Whether XML input files are validated against the internal or an external DTD. */
58      private boolean _useInternalDtd = true;
59  
60  
61      /**
62       * Sets the alias of the jdbc connection to use.
63       * 
64       * @param alias The alias of the connection
65       */
66      public void setJcdAlias(String alias)
67      {
68          _jcdAlias = alias;
69      }
70  
71      /**
72       * Returns the alias of the jdbc connection.
73       * 
74       * @return The alias
75       */
76      public String getJcdAlias()
77      {
78          return _jcdAlias;
79      }
80  
81      /**
82       * Returns the ojb properties file, per default 'OJB.properties' in the current directory.
83       * 
84       * @return The ojb properties file
85       */
86      public File getOjbPropertiesFile()
87      {
88          return _ojbPropertiesFile;
89      }
90      /**
91       * Sets the ojb properties file.
92       *
93       * @param ojbPropertiesFile The ojb properties file
94       */
95      public void setOjbPropertiesFile(File ojbPropertiesFile)
96      {
97          _ojbPropertiesFile = ojbPropertiesFile;
98      }
99  
100     /**
101      * Returns the repository file.
102      * 
103      * @return The repository file
104      */
105     public File getRepositoryFile()
106     {
107         return _repositoryFile;
108     }
109 
110     /**
111      * Sets the repository file (per default the one configured in the ojb properties file is used).
112      * 
113      * @param file The repository file
114      */
115     public void setRepositoryFile(File file)
116     {
117         _repositoryFile = file;
118     }
119 
120     /**
121      * Specifies whether XML schema files are validated against the internal or an external DTD.
122      *
123      * @param useInternalDtd <code>true</code> if input files are to be validated against the internal DTD
124      */
125     public void setUseInternalDtd(boolean useInternalDtd)
126     {
127         _useInternalDtd = useInternalDtd;
128     }
129 
130     /**
131      * Adds a fileset specifying the schema files.
132      * 
133      * @param fileset The additional input files
134      */
135     public void addConfiguredFileset(FileSet fileset)
136     {
137         _fileSets.add(fileset);
138     }
139 
140     /**
141      * Set the xml schema describing the application model.
142      *
143      * @param schemaFile The schema
144      */
145     public void setSchemaFile(File schemaFile)
146     {
147         _singleSchemaFile = schemaFile;
148     }
149 
150     /**
151      * Adds the "write dtd to file"-command.
152      * 
153      * @param command The command
154      */
155     public void addWriteDtdToFile(WriteDtdToFileCommand command)
156     {
157         _commands.add(command);
158     }
159 
160     /**
161      * Adds the "write data to database"-command.
162      * 
163      * @param command The command
164      */
165     public void addWriteDataToDatabase(WriteDataToDatabaseCommand command)
166     {
167         _commands.add(command);
168     }
169 
170     /**
171      * Adds the "write data sql to file"-command.
172      * 
173      * @param command The command
174      */
175     public void addWriteDataSqlToFile(WriteDataSqlToFileCommand command)
176     {
177         _commands.add(command);
178     }
179 
180     /**
181      * {@inheritDoc}
182      */
183     protected Database readModel()
184     {
185         DatabaseIO reader = new DatabaseIO();
186         Database   model  = null;
187 
188         reader.setUseInternalDtd(_useInternalDtd);
189         if ((_singleSchemaFile != null) && !_fileSets.isEmpty())
190         {
191             throw new BuildException("Please use either the schemafile attribute or the sub fileset element, but not both");
192         }
193         if (_singleSchemaFile != null)
194         {
195             model = readSingleSchemaFile(reader, _singleSchemaFile);
196         }
197         else
198         {
199             for (Iterator it = _fileSets.iterator(); it.hasNext();)
200             {
201                 FileSet          fileSet    = (FileSet)it.next();
202                 File             fileSetDir = fileSet.getDir(getProject());
203                 DirectoryScanner scanner    = fileSet.getDirectoryScanner(getProject());
204                 String[]         files      = scanner.getIncludedFiles();
205     
206                 for (int idx = 0; (files != null) && (idx < files.length); idx++)
207                 {
208                     Database curModel = readSingleSchemaFile(reader, new File(fileSetDir, files[idx]));
209     
210                     if (model == null)
211                     {
212                         model = curModel;
213                     }
214                     else if (curModel != null)
215                     {
216                         try
217                         {
218                             model.mergeWith(curModel);
219                         }
220                         catch (IllegalArgumentException ex)
221                         {
222                             throw new BuildException("Could not merge with schema from file "+files[idx]+": "+ex.getLocalizedMessage(), ex);
223                         }
224                     }
225                 }
226             }
227         }
228         return model;
229     }
230 
231     /**
232      * Reads a single schema file.
233      * 
234      * @param reader     The schema reader 
235      * @param schemaFile The schema file
236      * @return The model
237      */
238     private Database readSingleSchemaFile(DatabaseIO reader, File schemaFile)
239     {
240         Database model = null;
241 
242         if (!schemaFile.isFile())
243         {
244             log("Path "+schemaFile.getAbsolutePath()+" does not denote a schema file", Project.MSG_ERR);
245         }
246         else if (!schemaFile.canRead())
247         {
248             log("Could not read schema file "+schemaFile.getAbsolutePath(), Project.MSG_ERR);
249         }
250         else
251         {
252             try
253             {
254                 model = reader.read(schemaFile);
255                 log("Read schema file "+schemaFile.getAbsolutePath(), Project.MSG_INFO);
256             }
257             catch (Exception ex)
258             {
259                 throw new BuildException("Could not read schema file "+schemaFile.getAbsolutePath()+": "+ex.getLocalizedMessage(), ex);
260             }
261         }
262         return model;
263     }
264 
265     /**
266      * Initializes OJB for the purposes of this task.
267      * 
268      * @return The metadata manager used by OJB
269      */
270     private MetadataManager initOJB()
271     {
272         try
273         {
274             if (_ojbPropertiesFile == null)
275             {
276                 _ojbPropertiesFile = new File("OJB.properties");
277                 if (!_ojbPropertiesFile.exists())
278                 {
279                     throw new BuildException("Could not find OJB.properties, please specify it via the ojbpropertiesfile attribute");
280                 }
281             }
282             else
283             {
284                 if (!_ojbPropertiesFile.exists())
285                 {
286                     throw new BuildException("Could not load the specified OJB properties file "+_ojbPropertiesFile);
287                 }
288                 log("Using properties file "+_ojbPropertiesFile.getAbsolutePath(), Project.MSG_INFO);
289                 System.setProperty("OJB.properties", _ojbPropertiesFile.getAbsolutePath());
290             }
291 
292             MetadataManager     metadataManager = MetadataManager.getInstance();
293             RepositoryPersistor persistor       = new RepositoryPersistor();
294 
295             if (_repositoryFile != null)
296             {
297                 if (!_repositoryFile.exists())
298                 {
299                     throw new BuildException("Could not load the specified repository file "+_repositoryFile);
300                 }
301                 log("Loading repository file "+_repositoryFile.getAbsolutePath(), Project.MSG_INFO);
302 
303                 // this will load the info from the specified repository file
304                 // and merge it with the existing info (if it has been loaded)
305                 metadataManager.mergeConnectionRepository(persistor.readConnectionRepository(_repositoryFile.getAbsolutePath()));
306                 metadataManager.mergeDescriptorRepository(persistor.readDescriptorRepository(_repositoryFile.getAbsolutePath()));
307             }
308             else if (metadataManager.connectionRepository().getAllDescriptor().isEmpty() &&
309                      metadataManager.getGlobalRepository().getDescriptorTable().isEmpty())
310             {
311                 // Seems nothing was loaded, probably because we're not starting in the directory
312                 // that the properties file is in, and the repository file path is relative
313                 // So lets try to resolve this path and load the repository info manually
314                 Properties props = new Properties();
315 
316                 props.load(new FileInputStream(_ojbPropertiesFile));
317     
318                 String repositoryPath = props.getProperty("repositoryFile", "repository.xml");
319                 File   repositoryFile = new File(repositoryPath);
320     
321                 if (!repositoryFile.exists())
322                 {
323                     repositoryFile = new File(_ojbPropertiesFile.getParentFile(), repositoryPath);
324                 }
325                 metadataManager.mergeConnectionRepository(persistor.readConnectionRepository(repositoryFile.getAbsolutePath()));
326                 metadataManager.mergeDescriptorRepository(persistor.readDescriptorRepository(repositoryFile.getAbsolutePath()));
327             }
328             // we might have to determine the default pb key ourselves
329             if (metadataManager.getDefaultPBKey() == null)
330             {
331                 for (Iterator it = metadataManager.connectionRepository().getAllDescriptor().iterator(); it.hasNext();)
332                 {
333                     JdbcConnectionDescriptor descriptor = (JdbcConnectionDescriptor)it.next();
334 
335                     if (descriptor.isDefaultConnection())
336                     {
337                         metadataManager.setDefaultPBKey(new PBKey(descriptor.getJcdAlias(), descriptor.getUserName(), descriptor.getPassWord()));
338                         break;
339                     }
340                 }
341             }
342             return metadataManager;
343         }
344         catch (Exception ex)
345         {
346             if (ex instanceof BuildException)
347             {
348                 throw (BuildException)ex;
349             }
350             else
351             {
352                 throw new BuildException(ex);
353             }
354         }
355     }
356 
357     /**
358      * {@inheritDoc}
359      */
360     public void execute() throws BuildException
361     {
362         if (_commands.isEmpty())
363         {
364             log("No sub tasks specified, so there is nothing to do.", Project.MSG_INFO);
365             return;
366         }
367 
368         ClassLoader    sysClassLoader = Thread.currentThread().getContextClassLoader();
369         AntClassLoader newClassLoader = new AntClassLoader(getClass().getClassLoader(), true);
370 
371         // we're changing the thread classloader so that we can access resources
372         // from the classpath used to load this task's class
373         Thread.currentThread().setContextClassLoader(newClassLoader);
374         
375         try
376         {
377             MetadataManager      manager  = initOJB();
378             Database             dbModel  = readModel();
379             DescriptorRepository objModel = manager.getGlobalRepository();
380 
381             if (dbModel == null)
382             {
383                 throw new BuildException("No database model specified");
384             }
385             for (Iterator it = _commands.iterator(); it.hasNext();)
386             {
387                 Command cmd = (Command)it.next();
388 
389                 cmd.setPlatform(getPlatform());
390                 cmd.execute(this, dbModel, objModel);
391             }
392         }
393         finally
394         {
395             // rollback of our classloader change
396             Thread.currentThread().setContextClassLoader(sysClassLoader);
397         }
398     }
399 }