001 package org.apache.ojb.broker.ant;
002
003 /* Copyright 2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import java.io.File;
019 import java.io.FileInputStream;
020 import java.util.ArrayList;
021 import java.util.Iterator;
022 import java.util.Properties;
023
024 import org.apache.ddlutils.io.DatabaseIO;
025 import org.apache.ddlutils.model.Database;
026 import org.apache.ddlutils.task.DatabaseTaskBase;
027 import org.apache.ojb.broker.PBKey;
028 import org.apache.ojb.broker.metadata.DescriptorRepository;
029 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
030 import org.apache.ojb.broker.metadata.MetadataManager;
031 import org.apache.ojb.broker.metadata.RepositoryPersistor;
032 import org.apache.tools.ant.AntClassLoader;
033 import org.apache.tools.ant.BuildException;
034 import org.apache.tools.ant.DirectoryScanner;
035 import org.apache.tools.ant.Project;
036 import org.apache.tools.ant.types.FileSet;
037
038 /**
039 * Task for inserting data XML that is defined in terms of the repository elements.
040 *
041 * @author Thomas Dudziak
042 */
043 public class RepositoryDataTask extends DatabaseTaskBase
044 {
045 /** The sub tasks to execute. */
046 private ArrayList _commands = new ArrayList();
047 /** The alias of the jdbc connection to use (empty = default connection) */
048 private String _jcdAlias;
049 /** The properties file */
050 private File _ojbPropertiesFile;
051 /** The repository file */
052 private File _repositoryFile;
053 /** A single schema file to read. */
054 private File _singleSchemaFile = null;
055 /** The input files. */
056 private ArrayList _fileSets = new ArrayList();
057 /** Whether XML input files are validated against the internal or an external DTD. */
058 private boolean _useInternalDtd = true;
059
060
061 /**
062 * Sets the alias of the jdbc connection to use.
063 *
064 * @param alias The alias of the connection
065 */
066 public void setJcdAlias(String alias)
067 {
068 _jcdAlias = alias;
069 }
070
071 /**
072 * Returns the alias of the jdbc connection.
073 *
074 * @return The alias
075 */
076 public String getJcdAlias()
077 {
078 return _jcdAlias;
079 }
080
081 /**
082 * Returns the ojb properties file, per default 'OJB.properties' in the current directory.
083 *
084 * @return The ojb properties file
085 */
086 public File getOjbPropertiesFile()
087 {
088 return _ojbPropertiesFile;
089 }
090 /**
091 * Sets the ojb properties file.
092 *
093 * @param ojbPropertiesFile The ojb properties file
094 */
095 public void setOjbPropertiesFile(File ojbPropertiesFile)
096 {
097 _ojbPropertiesFile = ojbPropertiesFile;
098 }
099
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 }