001: package org.apache.ojb.broker.ant;
002:
003: /* Copyright 2004-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.IOException;
019: import java.io.Reader;
020: import java.io.StringReader;
021: import java.io.Writer;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import org.apache.commons.beanutils.DynaBean;
026: import org.apache.commons.digester.Digester;
027: import org.apache.commons.digester.ExtendedBaseRules;
028: import org.apache.commons.digester.Rule;
029: import org.apache.commons.digester.RuleSetBase;
030: import org.apache.ddlutils.Platform;
031: import org.apache.ddlutils.model.Column;
032: import org.apache.ddlutils.model.Database;
033: import org.apache.ojb.broker.metadata.ClassDescriptor;
034: import org.apache.ojb.broker.metadata.DescriptorRepository;
035: import org.xml.sax.Attributes;
036: import org.xml.sax.EntityResolver;
037: import org.xml.sax.InputSource;
038:
039: /**
040: * Provides data input and output via DdlUtils.
041: *
042: * @author Thomas Dudziak
043: */
044: public class DdlUtilsDataHandling {
045: private class DynaFactoryCreateRule extends Rule {
046: /**
047: * {@inheritDoc}
048: */
049: public void begin(String namespace, String name,
050: Attributes attributes) throws Exception {
051: DynaBean bean = _preparedModel.createBeanFor(name);
052:
053: if (bean == null) {
054: throw new DataTaskException("Unknown element " + name);
055: }
056:
057: for (int idx = 0; idx < attributes.getLength(); idx++) {
058: String attrName = attributes.getLocalName(idx);
059: String attrValue = attributes.getValue(idx);
060: Column column = _preparedModel.getColumnFor(name,
061: attrName);
062:
063: if (column == null) {
064: throw new DataTaskException("Unknown attribute "
065: + attrName + " of element " + name);
066: }
067: bean.set(column.getName(), attrValue);
068: }
069: DdlUtilsDataHandling.this ._digester.push(bean);
070: }
071:
072: /**
073: * {@inheritDoc}
074: */
075: public void end(String namespace, String name) throws Exception {
076: DynaBean bean = (DynaBean) DdlUtilsDataHandling.this ._digester
077: .pop();
078:
079: ((DataSet) DdlUtilsDataHandling.this ._digester.peek())
080: .add(bean);
081: }
082: }
083:
084: public class DataRuleSet extends RuleSetBase {
085: /**
086: * {@inheritDoc}
087: */
088: public void addRuleInstances(Digester digester) {
089: digester.addObjectCreate("dataset", DataSet.class);
090: digester
091: .addRule("*/dataset/*", new DynaFactoryCreateRule());
092: }
093: }
094:
095: /** The database model */
096: private Database _dbModel;
097: /** The platform */
098: private Platform _platform;
099: /** The prepared model */
100: private PreparedModel _preparedModel;
101: /** The digester for parsing the XML */
102: private Digester _digester;
103:
104: /**
105: * Creates a new data handling object.
106: */
107: public DdlUtilsDataHandling() {
108: _digester = new Digester();
109: _digester.setEntityResolver(new EntityResolver() {
110: public InputSource resolveEntity(String publicId,
111: String systemId) {
112: // we don't care about the DTD for data files
113: return new InputSource(new StringReader(""));
114: }
115:
116: });
117: _digester.setNamespaceAware(true);
118: _digester.setValidating(false);
119: _digester.setUseContextClassLoader(true);
120: _digester.setRules(new ExtendedBaseRules());
121: _digester.addRuleSet(new DataRuleSet());
122: }
123:
124: /**
125: * Sets the model that the handling works on.
126: *
127: * @param databaseModel The database model
128: * @param objModel The object model
129: */
130: public void setModel(Database databaseModel,
131: DescriptorRepository objModel) {
132: _dbModel = databaseModel;
133: _preparedModel = new PreparedModel(objModel, databaseModel);
134: }
135:
136: /**
137: * Sets the (connected) database platform to work against.
138: *
139: * @param platform The platform
140: */
141: public void setPlatform(Platform platform) {
142: _platform = platform;
143: }
144:
145: /**
146: * Writes a DTD that can be used for data XML files matching the current model to the given writer.
147: *
148: * @param output The writer to write the DTD to
149: */
150: public void getDataDTD(Writer output) throws DataTaskException {
151: try {
152: output.write("<!ELEMENT dataset (\n");
153: for (Iterator it = _preparedModel.getElementNames(); it
154: .hasNext();) {
155: String elementName = (String) it.next();
156:
157: output.write(" ");
158: output.write(elementName);
159: output.write("*");
160: output.write(it.hasNext() ? " |\n" : "\n");
161: }
162: output
163: .write(")>\n<!ATTLIST dataset\n name CDATA #REQUIRED\n>\n");
164: for (Iterator it = _preparedModel.getElementNames(); it
165: .hasNext();) {
166: String elementName = (String) it.next();
167: List classDescs = _preparedModel
168: .getClassDescriptorsMappingTo(elementName);
169:
170: if (classDescs == null) {
171: output.write("\n<!-- Indirection table");
172: } else {
173: output.write("\n<!-- Mapped to : ");
174: for (Iterator classDescIt = classDescs.iterator(); classDescIt
175: .hasNext();) {
176: ClassDescriptor classDesc = (ClassDescriptor) classDescIt
177: .next();
178:
179: output.write(classDesc.getClassNameOfObject());
180: if (classDescIt.hasNext()) {
181: output.write("\n ");
182: }
183: }
184: }
185: output.write(" -->\n<!ELEMENT ");
186: output.write(elementName);
187: output.write(" EMPTY>\n<!ATTLIST ");
188: output.write(elementName);
189: output.write("\n");
190:
191: for (Iterator attrIt = _preparedModel
192: .getAttributeNames(elementName); attrIt
193: .hasNext();) {
194: String attrName = (String) attrIt.next();
195:
196: output.write(" ");
197: output.write(attrName);
198: output.write(" CDATA #");
199: output.write(_preparedModel.isRequired(elementName,
200: attrName) ? "REQUIRED" : "IMPLIED");
201: output.write("\n");
202: }
203: output.write(">\n");
204: }
205: } catch (IOException ex) {
206: throw new DataTaskException(ex);
207: }
208: }
209:
210: /**
211: * Returns the sql necessary to add the data XML contained in the given input stream.
212: * Note that the data is expected to match the repository metadata (not the table schema).
213: * Also note that you should not use the reader after passing it to this method except closing
214: * it (which is not done automatically).
215: *
216: * @param input A reader returning the content of the data file
217: * @param output The writer to write the sql to
218: */
219: public void getInsertDataSql(Reader input, Writer output)
220: throws DataTaskException {
221: try {
222: DataSet set = (DataSet) _digester.parse(input);
223:
224: set.createInsertionSql(_dbModel, _platform, output);
225: } catch (Exception ex) {
226: if (ex instanceof DataTaskException) {
227: // is not declared by digester, but may be thrown
228: throw (DataTaskException) ex;
229: } else {
230: throw new DataTaskException(ex);
231: }
232: }
233: }
234:
235: /**
236: * Returns the sql necessary to add the data XML contained in the given input stream.
237: * Note that the data is expected to match the repository metadata (not the table schema).
238: * Also note that you should not use the reader after passing it to this method except closing
239: * it (which is not done automatically).
240: *
241: * @param input A reader returning the content of the data file
242: * @param batchSize The batch size; use 1 for not batch insertion
243: */
244: public void insertData(Reader input, int batchSize)
245: throws DataTaskException {
246: try {
247: DataSet set = (DataSet) _digester.parse(input);
248:
249: set.insert(_platform, _dbModel, batchSize);
250: } catch (Exception ex) {
251: if (ex instanceof DataTaskException) {
252: // is not declared by digester, but may be thrown
253: throw (DataTaskException) ex;
254: } else {
255: throw new DataTaskException(ex);
256: }
257: }
258: }
259: }
|