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