1 /*
2 * PROJECT : DAR Runtime and Tools
3 * COPYRIGHT : Copyright (C) 1999-2004 tim.stephenson@enableit.org
4 * LICENSE : GNU LESSER GENERAL PUBLIC LICENSE
5 * Version 2.1, February 1999
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 package org.enableit.db.darrt;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.InputStreamReader;
27 import java.io.OutputStream;
28 import java.io.StringWriter;
29 import java.net.MalformedURLException;
30 import java.net.URL;
31 import java.rmi.RemoteException;
32 import java.util.ArrayList;
33 import java.util.Enumeration;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.zip.ZipEntry;
38 import java.util.zip.ZipFile;
39 import java.util.zip.ZipOutputStream;
40
41 import org.apache.axis.utils.DOM2Writer;
42 import org.apache.log4j.Logger;
43 import org.enableit.db.DBException;
44 import org.enableit.db.beans.Column;
45 import org.enableit.db.beans.Database;
46 import org.enableit.db.beans.ForeignKey;
47 import org.enableit.db.beans.Provider;
48 import org.enableit.db.beans.ProviderExt;
49 import org.enableit.db.beans.RowSet;
50 import org.enableit.db.beans.Schema;
51 import org.enableit.db.beans.Table;
52 import org.exolab.castor.xml.CastorException;
53 import org.exolab.castor.xml.MarshalException;
54 import org.exolab.castor.xml.Unmarshaller;
55 import org.exolab.castor.xml.ValidationException;
56 import org.w3c.dom.Document;
57
58
59 /***
60 * Manipulates Database Archives (.dar) files.
61 */
62 public class DarHandler implements FileProcessor {
63
64 /***
65 * CVS info ABOUT this class and its current version
66 */
67 public static final String ABOUT = "$Revision: 1.13 $";
68
69 /***
70 * Name of .DAR entry representing the schema deployment descriptor.
71 */
72 public static final String SCHEMA_ENTRY = "META-INF/schema.xml";
73
74 /***
75 * The Log4J <code>Logger</code> doing the logging.
76 */
77 private static Logger logger = Logger.getLogger(DarHandler.class);
78
79 private Provider target;
80
81 private List importedRowsets;
82
83 /***
84 * Debug flag
85 */
86 private boolean debug = false;
87
88 /***
89 * Default Constructor.
90 */
91 public DarHandler() {
92 }
93
94 /***
95 * Sets the dar file name.
96 */
97 public void setDebug(boolean debug) {
98 this.debug = debug;
99 }
100
101 public void create(OutputStream out, Database database)
102 throws DBException, DarHandlingException {
103 create(out, database, new ArrayList());
104 }
105
106 /***
107 * Creates a .dar file.
108 *
109 * <p><b>Implementation Note:</b> Once there is a good take up of the
110 * generics capability on JDK 1.5 this method will be refactored into
111 * two or more methods overloading the <code>List<code> parameter with
112 * typed lists.</p>
113 *
114 * @param out The stream to write the .dar to.
115 * @param database Identifies <code>Provider</code> and other meta-data
116 * for the .dar.
117 * @param dataList <code>List</code> of <code>Strings</code> naming
118 * tables to export or <code>RowSets</code> of already exported data.
119 * <em>See implementation note above.</em>
120 * @throws DBException
121 * @throws DarHandlingException
122 */
123 public void create(OutputStream out, Database database, List dataList)
124 throws DBException, DarHandlingException {
125 try {
126 ZipOutputStream zos = new ZipOutputStream(out);
127
128 // Do schema entry
129 zos.putNextEntry(new ZipEntry(SCHEMA_ENTRY));
130
131 StringWriter databaseXml = new StringWriter();
132
133 database.marshal(databaseXml);
134 databaseXml.close();
135 zos.write(databaseXml.toString().getBytes());
136 zos.closeEntry();
137
138 // Do data entries
139 DataHandler dataHandler = new DataHandler();
140
141 dataHandler.setOnlineRefSchema(database.getProvider());
142
143 for (Iterator it = dataList.iterator(); it.hasNext();) {
144 Object obj = it.next();
145
146 if (obj instanceof String) {
147 // Though method accepts table pattern, can supply exact match
148 dataHandler.setTablePattern((String) obj);
149
150 Map dataMap = dataHandler.export();
151
152 logger.debug("data exported: " + dataMap);
153
154 for (Iterator j = dataMap.keySet().iterator(); j.hasNext();) {
155 String key = (String) j.next();
156 Document doc = (Document) dataMap.get(key);
157
158 addDataItem(zos, key, doc);
159 }
160 } else if (obj instanceof RowSet) {
161 RowSet rs = (RowSet) obj;
162
163 addDataItem(zos, rs);
164 } else {
165 throw new IllegalArgumentException();
166 }
167 }
168
169 zos.close();
170 } catch (java.io.IOException e) {
171 logger.error(e.getMessage(), e);
172 throw new DarHandlingException(e.getMessage(), e);
173 } catch (MarshalException e) {
174 logger.error(e.getMessage(), e);
175 throw new DarHandlingException(e.getMessage(), e);
176 } catch (ValidationException e) {
177 logger.error(e.getMessage(), e);
178 throw new DarHandlingException(e.getMessage(), e);
179
180 /* } catch (DBException e) {
181 // Should already be logged
182 throw new DarHandlingException(e.getMessage(), e) ;*/
183 }
184 }
185
186 private void addDataItem(ZipOutputStream zos, RowSet rowSet)
187 throws IOException, DarHandlingException {
188 zos.putNextEntry(new ZipEntry("data/" + rowSet.getTable() + ".xml"));
189
190 StringWriter dataXml = new StringWriter();
191
192 try {
193 rowSet.marshal(dataXml);
194 } catch (MarshalException e) {
195 logger.error(e.getMessage(), e);
196 throw new DarHandlingException(e.getMessage(), e);
197 } catch (ValidationException e) {
198 logger.error(e.getMessage(), e);
199 throw new DarHandlingException(e.getMessage(), e);
200 }
201
202 dataXml.close();
203 zos.write(dataXml.toString().getBytes());
204 zos.closeEntry();
205 }
206
207 private void addDataItem(ZipOutputStream zos, String key, Document doc)
208 throws IOException {
209 // Add zip entry
210 zos.putNextEntry(new ZipEntry("data/" + key + ".xml"));
211
212 StringWriter dataXml = new StringWriter();
213
214 //((RowSet) dataMap.get(key)).marshal(dataXml) ;
215 if (doc != null) {
216 DOM2Writer.serializeAsXML(doc, dataXml, true, false);
217 }
218
219 dataXml.close();
220 zos.write(dataXml.toString().getBytes());
221 zos.closeEntry();
222 }
223
224 /***
225 * Installs a data archive in its entirety.
226 */
227 public void install(URL url)
228 throws DBException {
229 logger.info("METHOD_ENTRY: install, url=" + url);
230
231 List errorSets = new ArrayList();
232
233 try {
234 // Check the dar exists
235 ZipFile dar = null;
236
237 if ("file".equals(url.getProtocol())) {
238 File darFile = new File(url.getFile());
239
240 if (!darFile.exists()) {
241 throw new DarHandlingException("Could not locate dar: "
242 + darFile);
243 }
244
245 dar = new ZipFile(darFile);
246 } else {
247 Object darObj = url.getContent();
248
249 logger.debug("Found dar is instance of: "
250 + dar.getClass().getName());
251 }
252
253 if (dar == null) {
254 throw new DarHandlingException("Could not locate dar: " + url);
255 }
256
257 // Get the deployment descriptor
258 ZipEntry dd = dar.getEntry(SCHEMA_ENTRY);
259 InputStreamReader isr = new InputStreamReader(dar.getInputStream(dd));
260 Database schema = (Database) Unmarshaller.unmarshal(Database.class,
261 isr);
262
263 if (target == null) {
264 target = schema.getProvider();
265 }
266
267 // Install the schema
268 SchemaHandler sh = new SchemaHandler();
269
270 sh.setDebug(debug);
271 sh.setRefDatabase(schema);
272 sh.setOnlineTargetSchema(target);
273 sh.createSchema();
274
275 // Register schema
276 MetaDataFactory mdf = MetaDataFactory.getInstance() ;
277 mdf.setMetaData(target, schema) ;
278
279 // Iterate archive entries processing them according to DAR format
280 DataHandler dh = new DataHandler();
281 // Provider provider = schema.getProvider();
282 List tableList = new ArrayList();
283 importedRowsets = new ArrayList() ;
284
285 for (Enumeration entries = dar.entries();
286 entries.hasMoreElements();) {
287 ZipEntry entry = (ZipEntry) entries.nextElement();
288
289 if (!entry.isDirectory() && entry.getName().startsWith("data/")) {
290 logger.warn("Installing XML data from: " + entry.getName());
291
292 // Collect table names
293 tableList.add(entry.getName().substring(5,
294 entry.getName().lastIndexOf("."))) ;
295
296 // Install data
297 importData(errorSets, dh, target, schema, dar, entry);
298 } else {
299 if (!entry.getName().equals(SCHEMA_ENTRY)) {
300 logger.warn("Unhandled archive entry: "
301 + entry.getName());
302 }
303 }
304 }
305 } catch (IOException e) {
306 logger.error("IO exception: " + e.getMessage(), e);
307 } catch (CastorException e) {
308 logger.error("Castor exception: " + e.getMessage(), e);
309 } finally {
310 if ((errorSets != null) && (errorSets.size() > 0)) {
311 throw new DarHandlingException(errorSets);
312 }
313 }
314
315 logger.info("METHOD_EXIT: install");
316 }
317
318 private void importData(
319 List errorSets, DataHandler dh, Provider provider,
320 Database schema, ZipFile dar, ZipEntry entry)
321 throws DBException, IllegalArgumentException, IOException {
322 logger.info("METHOD_ENTRY importData, provider: "
323 + ProviderExt.toString(provider)) ;
324
325 if (importedRowsets.contains(entry.getName())) {
326 return ;
327 }
328
329 RowSet rows = null;
330 try {
331 // Unmarshal and delegate import to data handler
332 String tableName = entry.getName().substring(5,
333 entry.getName().lastIndexOf("."));
334
335 Table table = getMetaData(schema, tableName);
336
337 // Check if there is reference data to load first
338 for (int i = 0 ; i < table.getColumnCount() ; i++) {
339 Column col = table.getColumn(i) ;
340 if (col.getForeignKey() != null) {
341 ForeignKey fk = col.getForeignKey() ;
342 String fkTable = fk.getFkTableName() ;
343 if (dar.getEntry("data/" + fkTable + ".xml") != null) {
344 logger.warn("Detected dependency on table: " + fkTable) ;
345 String entryName = "data/" + fkTable + ".xml" ;
346 importData(errorSets, dh, provider, schema, dar,
347 dar.getEntry(entryName)) ;
348 importedRowsets.add(entryName) ;
349 }
350 }
351 }
352
353 DataParser parser = DataParserFactory.getInstance(entry
354 .getName());
355
356 rows = parser.getRowSet(dar.getInputStream(entry), table);
357 dh.importData(provider, rows);
358 importedRowsets.add(entry.getName()) ;
359 } catch (DataImportException e) {
360 // Record failure and continue with next file
361 logger.error("Failed to install data from file: "
362 + entry.getName());
363 logger.error("... becos: " + e.getMessage(), e);
364
365 if (e instanceof DataImportException) {
366 errorSets.add(((DataImportException) e)
367 .getErrorRowSet());
368 } else {
369 errorSets.add(rows);
370 }
371 }
372 }
373
374 /***
375 * @param db The entire database def'n containing all table def'ns.
376 * @param tableName The table def'n sought.
377 * @return Table def'n, never null.
378 * @throws DBException If table def not found in either dar or
379 * the target database.
380 */
381 private Table getMetaData(Database db, String tableName) throws DBException {
382 Table table = null ;
383 for (int i = 0 ; i < db.getSchemaCount() ; i++) {
384 Schema schema = db.getSchema(i) ;
385 for (int j = 0 ; j < schema.getTableCount() ; j++) {
386 if (schema.getTable(j).getName().equals(tableName)) {
387 table = schema.getTable(j) ;
388 }
389 }
390 }
391
392 if (table == null) {
393 MetaDataFactory factory = MetaDataFactory.getInstance();
394 table = factory.getMetaData(db.getProvider(), tableName) ;
395 }
396 return table ;
397 }
398
399 /* (non-Javadoc)
400 * @see org.enableit.db.darrt.FileProcessor#process(java.io.File, java.lang.String)
401 */
402 public void process(File file, String fileType)
403 throws ConfigurationException, DBException, RemoteException {
404 try {
405 install(file.toURL());
406 } catch (MalformedURLException e) {
407 String msg = "Error installing DAR";
408
409 logger.error(msg, e);
410 throw new ConfigurationException(msg, e);
411 }
412 }
413
414 /***
415 * Override the target for the DAR file to be imported to.
416 * @see org.enableit.db.darrt.FileProcessor#setProvider(org.enableit.db.beans.Provider)
417 */
418 public void setProvider(Provider provider)
419 throws ConfigurationException, DBException, RemoteException {
420 this.target = provider;
421 }
422 }
This page was automatically generated by Maven