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: /** The sub tasks to execute. */
045: private ArrayList _commands = new ArrayList();
046: /** The alias of the jdbc connection to use (empty = default connection) */
047: private String _jcdAlias;
048: /** The properties file */
049: private File _ojbPropertiesFile;
050: /** The repository file */
051: private File _repositoryFile;
052: /** A single schema file to read. */
053: private File _singleSchemaFile = null;
054: /** The input files. */
055: private ArrayList _fileSets = new ArrayList();
056: /** Whether XML input files are validated against the internal or an external DTD. */
057: private boolean _useInternalDtd = true;
058:
059: /**
060: * Sets the alias of the jdbc connection to use.
061: *
062: * @param alias The alias of the connection
063: */
064: public void setJcdAlias(String alias) {
065: _jcdAlias = alias;
066: }
067:
068: /**
069: * Returns the alias of the jdbc connection.
070: *
071: * @return The alias
072: */
073: public String getJcdAlias() {
074: return _jcdAlias;
075: }
076:
077: /**
078: * Returns the ojb properties file, per default 'OJB.properties' in the current directory.
079: *
080: * @return The ojb properties file
081: */
082: public File getOjbPropertiesFile() {
083: return _ojbPropertiesFile;
084: }
085:
086: /**
087: * Sets the ojb properties file.
088: *
089: * @param ojbPropertiesFile The ojb properties file
090: */
091: public void setOjbPropertiesFile(File ojbPropertiesFile) {
092: _ojbPropertiesFile = ojbPropertiesFile;
093: }
094:
095: /**
096: * Returns the repository file.
097: *
098: * @return The repository file
099: */
100: public File getRepositoryFile() {
101: return _repositoryFile;
102: }
103:
104: /**
105: * Sets the repository file (per default the one configured in the ojb properties file is used).
106: *
107: * @param file The repository file
108: */
109: public void setRepositoryFile(File file) {
110: _repositoryFile = file;
111: }
112:
113: /**
114: * Specifies whether XML schema files are validated against the internal or an external DTD.
115: *
116: * @param useInternalDtd <code>true</code> if input files are to be validated against the internal DTD
117: */
118: public void setUseInternalDtd(boolean useInternalDtd) {
119: _useInternalDtd = useInternalDtd;
120: }
121:
122: /**
123: * Adds a fileset specifying the schema files.
124: *
125: * @param fileset The additional input files
126: */
127: public void addConfiguredFileset(FileSet fileset) {
128: _fileSets.add(fileset);
129: }
130:
131: /**
132: * Set the xml schema describing the application model.
133: *
134: * @param schemaFile The schema
135: */
136: public void setSchemaFile(File schemaFile) {
137: _singleSchemaFile = schemaFile;
138: }
139:
140: /**
141: * Adds the "write dtd to file"-command.
142: *
143: * @param command The command
144: */
145: public void addWriteDtdToFile(WriteDtdToFileCommand command) {
146: _commands.add(command);
147: }
148:
149: /**
150: * Adds the "write data to database"-command.
151: *
152: * @param command The command
153: */
154: public void addWriteDataToDatabase(
155: WriteDataToDatabaseCommand command) {
156: _commands.add(command);
157: }
158:
159: /**
160: * Adds the "write data sql to file"-command.
161: *
162: * @param command The command
163: */
164: public void addWriteDataSqlToFile(WriteDataSqlToFileCommand command) {
165: _commands.add(command);
166: }
167:
168: /**
169: * {@inheritDoc}
170: */
171: protected Database readModel() {
172: DatabaseIO reader = new DatabaseIO();
173: Database model = null;
174:
175: reader.setUseInternalDtd(_useInternalDtd);
176: if ((_singleSchemaFile != null) && !_fileSets.isEmpty()) {
177: throw new BuildException(
178: "Please use either the schemafile attribute or the sub fileset element, but not both");
179: }
180: if (_singleSchemaFile != null) {
181: model = readSingleSchemaFile(reader, _singleSchemaFile);
182: } else {
183: for (Iterator it = _fileSets.iterator(); it.hasNext();) {
184: FileSet fileSet = (FileSet) it.next();
185: File fileSetDir = fileSet.getDir(getProject());
186: DirectoryScanner scanner = fileSet
187: .getDirectoryScanner(getProject());
188: String[] files = scanner.getIncludedFiles();
189:
190: for (int idx = 0; (files != null)
191: && (idx < files.length); idx++) {
192: Database curModel = readSingleSchemaFile(reader,
193: new File(fileSetDir, files[idx]));
194:
195: if (model == null) {
196: model = curModel;
197: } else if (curModel != null) {
198: try {
199: model.mergeWith(curModel);
200: } catch (IllegalArgumentException ex) {
201: throw new BuildException(
202: "Could not merge with schema from file "
203: + files[idx] + ": "
204: + ex.getLocalizedMessage(),
205: ex);
206: }
207: }
208: }
209: }
210: }
211: return model;
212: }
213:
214: /**
215: * Reads a single schema file.
216: *
217: * @param reader The schema reader
218: * @param schemaFile The schema file
219: * @return The model
220: */
221: private Database readSingleSchemaFile(DatabaseIO reader,
222: File schemaFile) {
223: Database model = null;
224:
225: if (!schemaFile.isFile()) {
226: log("Path " + schemaFile.getAbsolutePath()
227: + " does not denote a schema file", Project.MSG_ERR);
228: } else if (!schemaFile.canRead()) {
229: log("Could not read schema file "
230: + schemaFile.getAbsolutePath(), Project.MSG_ERR);
231: } else {
232: try {
233: model = reader.read(schemaFile);
234: log("Read schema file " + schemaFile.getAbsolutePath(),
235: Project.MSG_INFO);
236: } catch (Exception ex) {
237: throw new BuildException("Could not read schema file "
238: + schemaFile.getAbsolutePath() + ": "
239: + ex.getLocalizedMessage(), ex);
240: }
241: }
242: return model;
243: }
244:
245: /**
246: * Initializes OJB for the purposes of this task.
247: *
248: * @return The metadata manager used by OJB
249: */
250: private MetadataManager initOJB() {
251: try {
252: if (_ojbPropertiesFile == null) {
253: _ojbPropertiesFile = new File("OJB.properties");
254: if (!_ojbPropertiesFile.exists()) {
255: throw new BuildException(
256: "Could not find OJB.properties, please specify it via the ojbpropertiesfile attribute");
257: }
258: } else {
259: if (!_ojbPropertiesFile.exists()) {
260: throw new BuildException(
261: "Could not load the specified OJB properties file "
262: + _ojbPropertiesFile);
263: }
264: log("Using properties file "
265: + _ojbPropertiesFile.getAbsolutePath(),
266: Project.MSG_INFO);
267: System.setProperty("OJB.properties", _ojbPropertiesFile
268: .getAbsolutePath());
269: }
270:
271: MetadataManager metadataManager = MetadataManager
272: .getInstance();
273: RepositoryPersistor persistor = new RepositoryPersistor();
274:
275: if (_repositoryFile != null) {
276: if (!_repositoryFile.exists()) {
277: throw new BuildException(
278: "Could not load the specified repository file "
279: + _repositoryFile);
280: }
281: log("Loading repository file "
282: + _repositoryFile.getAbsolutePath(),
283: Project.MSG_INFO);
284:
285: // this will load the info from the specified repository file
286: // and merge it with the existing info (if it has been loaded)
287: metadataManager.mergeConnectionRepository(persistor
288: .readConnectionRepository(_repositoryFile
289: .getAbsolutePath()));
290: metadataManager.mergeDescriptorRepository(persistor
291: .readDescriptorRepository(_repositoryFile
292: .getAbsolutePath()));
293: } else if (metadataManager.connectionRepository()
294: .getAllDescriptor().isEmpty()
295: && metadataManager.getGlobalRepository()
296: .getDescriptorTable().isEmpty()) {
297: // Seems nothing was loaded, probably because we're not starting in the directory
298: // that the properties file is in, and the repository file path is relative
299: // So lets try to resolve this path and load the repository info manually
300: Properties props = new Properties();
301:
302: props.load(new FileInputStream(_ojbPropertiesFile));
303:
304: String repositoryPath = props.getProperty(
305: "repositoryFile", "repository.xml");
306: File repositoryFile = new File(repositoryPath);
307:
308: if (!repositoryFile.exists()) {
309: repositoryFile = new File(_ojbPropertiesFile
310: .getParentFile(), repositoryPath);
311: }
312: metadataManager.mergeConnectionRepository(persistor
313: .readConnectionRepository(repositoryFile
314: .getAbsolutePath()));
315: metadataManager.mergeDescriptorRepository(persistor
316: .readDescriptorRepository(repositoryFile
317: .getAbsolutePath()));
318: }
319: // we might have to determine the default pb key ourselves
320: if (metadataManager.getDefaultPBKey() == null) {
321: for (Iterator it = metadataManager
322: .connectionRepository().getAllDescriptor()
323: .iterator(); it.hasNext();) {
324: JdbcConnectionDescriptor descriptor = (JdbcConnectionDescriptor) it
325: .next();
326:
327: if (descriptor.isDefaultConnection()) {
328: metadataManager.setDefaultPBKey(new PBKey(
329: descriptor.getJcdAlias(), descriptor
330: .getUserName(), descriptor
331: .getPassWord()));
332: break;
333: }
334: }
335: }
336: return metadataManager;
337: } catch (Exception ex) {
338: if (ex instanceof BuildException) {
339: throw (BuildException) ex;
340: } else {
341: throw new BuildException(ex);
342: }
343: }
344: }
345:
346: /**
347: * {@inheritDoc}
348: */
349: public void execute() throws BuildException {
350: if (_commands.isEmpty()) {
351: log("No sub tasks specified, so there is nothing to do.",
352: Project.MSG_INFO);
353: return;
354: }
355:
356: ClassLoader sysClassLoader = Thread.currentThread()
357: .getContextClassLoader();
358: AntClassLoader newClassLoader = new AntClassLoader(getClass()
359: .getClassLoader(), true);
360:
361: // we're changing the thread classloader so that we can access resources
362: // from the classpath used to load this task's class
363: Thread.currentThread().setContextClassLoader(newClassLoader);
364:
365: try {
366: MetadataManager manager = initOJB();
367: Database dbModel = readModel();
368: DescriptorRepository objModel = manager
369: .getGlobalRepository();
370:
371: if (dbModel == null) {
372: throw new BuildException("No database model specified");
373: }
374: for (Iterator it = _commands.iterator(); it.hasNext();) {
375: Command cmd = (Command) it.next();
376:
377: cmd.setPlatform(getPlatform());
378: cmd.execute(this , dbModel, objModel);
379: }
380: } finally {
381: // rollback of our classloader change
382: Thread.currentThread()
383: .setContextClassLoader(sysClassLoader);
384: }
385: }
386: }
|