KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > genimen > djeneric > repository > util > DjObjectImporter


1 /* Copyright (c) 2001-2005 by Genimen BV (www.genimen.com) All rights reserved.
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, is permitted provided that the following conditions are met: -
5  * Redistributions of source code must retain the above copyright notice, this
6  * list of conditions and the following disclaimer. - Redistributions in binary
7  * form must reproduce the above copyright notice, this list of conditions and
8  * the following disclaimer in the documentation and/or other materials
9  * provided with the distribution. - All advertising materials mentioning
10  * features or use of this software must display the following acknowledgment:
11  * "This product includes Djeneric." - Products derived from this software may
12  * not be called "Djeneric" nor may "Djeneric" appear in their names without
13  * prior written permission of Genimen BV. - Redistributions of any form
14  * whatsoever must retain the following acknowledgment: "This product includes
15  * Djeneric."
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL GENIMEN BV, DJENERIC.ORG, OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */

29
30 package com.genimen.djeneric.repository.util;
31
32 import java.io.BufferedInputStream JavaDoc;
33 import java.io.IOException JavaDoc;
34 import java.io.InputStream JavaDoc;
35 import java.util.ArrayList JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.Iterator JavaDoc;
38
39 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
40 import javax.xml.parsers.ParserConfigurationException JavaDoc;
41 import javax.xml.transform.TransformerException JavaDoc;
42
43 import org.apache.xpath.XPathAPI;
44 import org.w3c.dom.Document JavaDoc;
45 import org.w3c.dom.Element JavaDoc;
46 import org.w3c.dom.Node JavaDoc;
47 import org.w3c.dom.NodeList JavaDoc;
48 import org.w3c.dom.traversal.NodeIterator;
49 import org.xml.sax.InputSource JavaDoc;
50 import org.xml.sax.SAXException JavaDoc;
51
52 import com.genimen.djeneric.language.Messages;
53 import com.genimen.djeneric.repository.DjAssociation;
54 import com.genimen.djeneric.repository.DjExtent;
55 import com.genimen.djeneric.repository.DjList;
56 import com.genimen.djeneric.repository.DjObject;
57 import com.genimen.djeneric.repository.DjRelation;
58 import com.genimen.djeneric.repository.DjSession;
59 import com.genimen.djeneric.repository.DjUid;
60 import com.genimen.djeneric.repository.exceptions.CanNotDeleteException;
61 import com.genimen.djeneric.repository.exceptions.CatalogException;
62 import com.genimen.djeneric.repository.exceptions.DjenericException;
63 import com.genimen.djeneric.repository.exceptions.ObjectNotDefinedException;
64 import com.genimen.djeneric.structure.ExtentUsage;
65 import com.genimen.djeneric.structure.RelationUsage;
66 import com.genimen.djeneric.util.DjBase64;
67 import com.genimen.djeneric.util.DjLogger;
68 import com.genimen.djeneric.util.DjStatusDisplayer;
69
70 /**
71  * @author Wido Riezebos
72
73  * Typical usage:
74  *
75  * DjObjectImporter importer = new DjObjectImporter(session);
76  * importer.load(inputstream, shouldMerge);
77  * DjUid[] unresolved = importer.resolve();
78  * HashMap internal2external = importer.getInteral2ExternalMapping();
79  *
80  * if (unresolved.length > 0)
81  * aborted = !resolveReferences(session, unresolved, internal2external);
82  *
83  * if (!aborted)
84  * {
85  * importer.apply();
86  * session.commit();
87  * }
88  */

89 public class DjObjectImporter
90 {
91   DjSession _session;
92   DjList _created = new DjList();
93   DjList _deleted = new DjList();
94   DjList _updated = new DjList();
95   HashMap JavaDoc _createdOids = new HashMap JavaDoc();
96   Document JavaDoc _xmlDoc;
97   DjStatusDisplayer _statusDisplayer = null;
98   HashMap JavaDoc _uids;
99   HashMap JavaDoc _uidsReversed;
100   HashMap JavaDoc _objectidToExternalObject;
101   HashMap JavaDoc _structs;
102   DjUid[] _unresolved;
103
104   public DjObjectImporter(DjSession session)
105   {
106     _session = session;
107   }
108
109   public void load(InputStream JavaDoc stream, boolean mergeDetails) throws SAXException JavaDoc, IOException JavaDoc,
110       ParserConfigurationException JavaDoc, TransformerException JavaDoc, DjenericException
111   {
112     InputSource JavaDoc is = new InputSource JavaDoc(new BufferedInputStream JavaDoc(stream));
113     DocumentBuilderFactory JavaDoc dfactory = DocumentBuilderFactory.newInstance();
114
115     setStatus(Messages.getString("ObjectImporter.ParseInput"));
116     _xmlDoc = dfactory.newDocumentBuilder().parse(is);
117
118     _uids = getUids();
119     _uidsReversed = getReversedMap(_uids);
120     _objectidToExternalObject = new HashMap JavaDoc();
121
122     setStatus(Messages.getString("ObjectImporter.FetchStructures"));
123     _structs = getStructures();
124     precreateObjects(mergeDetails);
125   }
126
127   public DjUid[] resolve() throws TransformerException JavaDoc, DjenericException
128   {
129     // First make sure all objects are present in the objectidToExternalObject hashmap
130
// i.e. we need to create new objects for non-root objects and we need to check
131
// whether root-objects still exist. If they do: query them and make them empty;
132
// if they don't: create them.
133

134     _unresolved = resolveUids();
135
136     return _unresolved;
137   }
138
139   /**
140    * Returns a HashMap with an objectid (Long) to DjObject mapping
141    * The id is the (internal) objectid used in the import file.
142    * This is the same ID returned by DjUid.getAssociatedObjectid()
143    * @return
144    */

145   public HashMap JavaDoc getInteral2ExternalMapping()
146   {
147     return _objectidToExternalObject;
148   }
149
150   public void apply() throws TransformerException JavaDoc, DjenericException
151   {
152     if (resolveUids().length > 0) throw new ImportAbortedException("Not all external objects were resolved");
153
154     // All objects are present in objectidToExternalObject now.
155
// Next: update all the properties of the objects
156

157     updateProperties();
158     setStatus(Messages.getString("ObjectImporter.completed"));
159   }
160
161   protected HashMap JavaDoc getReversedMap(HashMap JavaDoc uids)
162   {
163     HashMap JavaDoc result = new HashMap JavaDoc(uids.size());
164     Iterator JavaDoc it = uids.keySet().iterator();
165     while (it.hasNext())
166     {
167       Object JavaDoc key = it.next();
168       result.put(uids.get(key), key);
169     }
170     return result;
171   }
172
173   protected void updateProperties() throws TransformerException JavaDoc, DjenericException
174   {
175     NodeList JavaDoc lst = XPathAPI.selectNodeList(_xmlDoc, "/djenericexport/object");
176
177     for (int i = 0; i < lst.getLength(); i++)
178     {
179       int pct = (int) (((double) i / (double) lst.getLength()) * 100);
180       if (i % 10 == 0) setStatus(Messages.getString("ObjectImporter.Import", String.valueOf(pct)));
181
182       Element JavaDoc object = (Element JavaDoc) lst.item(i);
183       updateProperties(object);
184     }
185   }
186
187   protected void updateProperties(Element JavaDoc objectElement) throws DjenericException, TransformerException JavaDoc
188   {
189     Long JavaDoc objectid = new Long JavaDoc(objectElement.getAttribute("id"));
190     DjObject object = (DjObject) _objectidToExternalObject.get(objectid);
191     if (object == null) throw new DjenericException("Internal error: object with internal id " + objectid + " missing");
192
193     NodeList JavaDoc lst = XPathAPI.selectNodeList(objectElement, "property");
194
195     for (int i = 0; i < lst.getLength(); i++)
196     {
197       Element JavaDoc prop = (Element JavaDoc) lst.item(i);
198       String JavaDoc name = prop.getAttribute("name");
199       String JavaDoc type = prop.getAttribute("type");
200
201       if ("uidptr".equals(type))
202       {
203         Long JavaDoc id = new Long JavaDoc(prop.getFirstChild().getNodeValue());
204         DjObject master = (DjObject) _objectidToExternalObject.get(id);
205         if (master == null) throw new DjenericException("Internal error: object with internal id " + id + " missing");
206
207         object.set(name, master);
208       }
209       else if ("text".equals(type)) object.setString(name, prop.getFirstChild().getNodeValue());
210       else if ("simple".equals(type)) object.setString(name, prop.getFirstChild().getNodeValue());
211       else if ("byte".equals(type))
212       {
213         String JavaDoc uu = prop.getFirstChild().getNodeValue();
214         byte[] bytes = DjBase64.decode(uu);
215         object.setBytes(name, bytes);
216       }
217     }
218     if (object.isModified() && !_createdOids.containsKey(new Long JavaDoc(object.getObjectId()))) _updated.add(object);
219   }
220
221   protected void precreateObjects(boolean mergeDetails) throws TransformerException JavaDoc, DjenericException
222   {
223     NodeList JavaDoc lst = XPathAPI.selectNodeList(_xmlDoc, "/djenericexport/object");
224
225     for (int i = 0; i < lst.getLength(); i++)
226     {
227       int pct = (int) (((double) i / (double) lst.getLength()) * 100);
228       if (i % 10 == 0) setStatus(Messages.getString("ObjectImporter.LoadAndCreate", String.valueOf(pct)));
229       Element JavaDoc object = (Element JavaDoc) lst.item(i);
230       if ("true".equals(object.getAttribute("rootobject")))
231       {
232         processRootObject(object, mergeDetails);
233       }
234       else
235       {
236         createOrLoadObject(object);
237       }
238     }
239   }
240
241   protected void createOrLoadObject(Element JavaDoc object) throws DjenericException
242   {
243     Long JavaDoc internalId = new Long JavaDoc(object.getAttribute("id"));
244     DjUid uid = (DjUid) _uids.get(internalId);
245
246     if (uid.getPropertyCount() == 0)
247     {
248       DjLogger.log("Warning: extent " + uid.getExtent().getName() + " had no UID defined at the time of export");
249       DjLogger.log(" object will be created without checking for prior existence");
250       createNewObject(object, internalId);
251     }
252     else
253     {
254       try
255       {
256         DjObject existingObject = _session.getObject(uid);
257         _objectidToExternalObject.put(internalId, existingObject);
258       }
259       catch (ObjectNotDefinedException onde)
260       {
261         createNewObject(object, internalId);
262       }
263     }
264   }
265
266   protected void createNewObject(Element JavaDoc object, Long JavaDoc internalId) throws DjenericException
267   {
268     DjObject newObject = _session.createObject(object.getAttribute("extent"));
269     _objectidToExternalObject.put(internalId, newObject);
270     _created.add(newObject);
271     _createdOids.put(new Long JavaDoc(newObject.getObjectId()), newObject);
272   }
273
274   protected void processRootObject(Element JavaDoc object, boolean mergeDetails) throws TransformerException JavaDoc, DjenericException
275   {
276     DjUid uid = createUid(object, _uids);
277     if (uid.getPropertyCount() == 0)
278     {
279       DjLogger.log("Warning: extent " + uid.getExtent().getName() + " had no UID defined at the time of export");
280       DjLogger.log(" object will be created without checking for prior existence");
281       Long JavaDoc internalId = new Long JavaDoc(object.getAttribute("id"));
282       createNewObject(object, internalId);
283     }
284     else
285     {
286       try
287       {
288         DjObject existingObject = _session.getObject(uid);
289         _objectidToExternalObject.put(new Long JavaDoc(object.getAttribute("id")), existingObject);
290         ExtentUsage structure = (ExtentUsage) _structs.get(new Long JavaDoc(object.getAttribute("structure")));
291         if (structure == null) throw new CatalogException("Error in import structure; invalid structure ptr: "
292                                                           + object.getAttribute("structure"));
293
294         if (!mergeDetails) cleanupDetails(existingObject, structure);
295       }
296       catch (ObjectNotDefinedException onde)
297       {
298         createOrLoadObject(object);
299       }
300     }
301   }
302
303   protected void cleanupDetails(DjObject existingObject, ExtentUsage structure) throws CanNotDeleteException,
304       DjenericException
305   {
306     for (int i = 0; i < structure.getDetailRelationCount(); i++)
307     {
308       RelationUsage relus = structure.getDetailRelation(i);
309       String JavaDoc relationName = relus.getRelation().getName();
310       DjAssociation assoc = existingObject.getDetailAssociationByName(relationName, relus.getDetail().getExtent());
311       DjList details = assoc.getObjects();
312       for (int del = 0; del < details.size(); del++)
313       {
314         DjObject toBeCleaned = details.getDjenericObjectAt(del);
315         boolean mustDie = !_uidsReversed.containsKey(toBeCleaned.getUID());
316
317         cleanupDetails(toBeCleaned, relus.getDetail());
318
319         if (mustDie)
320         {
321           if (!toBeCleaned.isMarkedForDelete()) _deleted.add(toBeCleaned);
322           toBeCleaned.markForDelete();
323         }
324       }
325     }
326   }
327
328   protected DjUid[] resolveUids() throws DjenericException
329   {
330     Iterator JavaDoc it = _uids.keySet().iterator();
331     ArrayList JavaDoc unresolved = new ArrayList JavaDoc();
332
333     while (it.hasNext())
334     {
335       DjUid uid = (DjUid) _uids.get(it.next());
336
337       if (!_objectidToExternalObject.containsKey(new Long JavaDoc(uid.getAssociatedObjectid())))
338       {
339         try
340         {
341           DjObject object = _session.getObject(uid);
342           _objectidToExternalObject.put(new Long JavaDoc(uid.getAssociatedObjectid()), object);
343         }
344         catch (ObjectNotDefinedException onde)
345         {
346           unresolved.add(uid);
347         }
348       }
349     }
350     return (DjUid[]) unresolved.toArray(new DjUid[0]);
351   }
352
353   protected HashMap JavaDoc getUids() throws TransformerException JavaDoc, DjenericException
354   {
355     NodeList JavaDoc lst = XPathAPI.selectNodeList(_xmlDoc, "/djenericexport/uid");
356     HashMap JavaDoc result = new HashMap JavaDoc();
357
358     int uidCount = lst.getLength();
359     for (int i = 0; i < uidCount; i++)
360     {
361       int pct = (int) (((double) i / (double) uidCount) * 100);
362       if (i % 10 == 0) setStatus(Messages.getString("ObjectImporter.FetchUids", String.valueOf(uidCount), String
363           .valueOf(pct)));
364
365       Element JavaDoc elem = (Element JavaDoc) lst.item(i);
366       DjUid uid = createUid(elem, result);
367       result.put(new Long JavaDoc(uid.getAssociatedObjectid()), uid);
368     }
369     return result;
370   }
371
372   // The following method will work on elements of type object AND uid
373
// Furthermore this method is optimized (not to use XPath for performance reasons)
374
protected DjUid createUid(Element JavaDoc elem, HashMap JavaDoc existingUids) throws TransformerException JavaDoc, DjenericException
375   {
376     DjExtent extent = _session.getPersistenceManager().getExtent(elem.getAttribute("extent"));
377     DjUid uid = new DjUid(extent);
378     uid.setAssociatedObjectid(Long.parseLong(elem.getAttribute("id")));
379
380     NodeList JavaDoc children = elem.getChildNodes();
381     for (int i = 0; i < children.getLength(); i++)
382     {
383       Node JavaDoc child = children.item(i);
384       if (!(child instanceof Element JavaDoc)) continue;
385
386       Element JavaDoc childElement = (Element JavaDoc) child;
387       String JavaDoc elementName = childElement.getNodeName();
388       if ("property".equals(elementName))
389       {
390         String JavaDoc name = childElement.getAttribute("name");
391         String JavaDoc type = childElement.getAttribute("type");
392
393         if (extent.getProperty(name).isPartOfUID())
394         {
395           if ("uid".equals(type))
396           {
397             NodeList JavaDoc nl = childElement.getChildNodes();
398             Element JavaDoc u = null;
399
400             for (int x = 0; x < nl.getLength(); x++)
401               if (nl.item(x) instanceof Element JavaDoc)
402               {
403                 u = (Element JavaDoc) nl.item(x);
404                 break;
405               }
406
407             uid.setProperty(name, createUid(u, existingUids));
408           }
409           if ("uidptr".equals(type))
410           {
411             Long JavaDoc id = new Long JavaDoc(childElement.getFirstChild().getNodeValue());
412             DjUid refuid = (DjUid) existingUids.get(id);
413             if (refuid == null) throw new CatalogException("Error in import structure: invalid uidptr: " + id);
414
415             uid.setProperty(name, refuid);
416           }
417           else if ("text".equals(type)) uid.setProperty(name, childElement.getFirstChild().getNodeValue());
418         }
419       }
420       else if ("descr".equals(elementName))
421       {
422         uid.setDescriptor(childElement.getFirstChild().getNodeValue());
423       }
424     }
425     return uid;
426   }
427
428   protected HashMap JavaDoc getStructures() throws TransformerException JavaDoc, DjenericException
429   {
430     NodeIterator it = XPathAPI.selectNodeIterator(_xmlDoc, "/djenericexport/structure");
431     HashMap JavaDoc result = new HashMap JavaDoc();
432
433     Element JavaDoc elem = (Element JavaDoc) it.nextNode();
434     while (elem != null)
435     {
436       ExtentUsage struct = createStructure(elem);
437       result.put(new Long JavaDoc(elem.getAttribute("id")), struct);
438       elem = (Element JavaDoc) it.nextNode();
439     }
440     return result;
441   }
442
443   protected ExtentUsage createStructure(Element JavaDoc elem) throws TransformerException JavaDoc, DjenericException
444   {
445     ExtentUsage struct = new ExtentUsage(_session.getPersistenceManager().getExtent(elem.getAttribute("extent")));
446
447     NodeIterator it = XPathAPI.selectNodeIterator(elem, "detail");
448
449     Element JavaDoc detail = (Element JavaDoc) it.nextNode();
450     while (detail != null)
451     {
452       buildDetailStruct(struct, detail);
453       detail = (Element JavaDoc) it.nextNode();
454     }
455
456     return struct;
457   }
458
459   protected void buildDetailStruct(ExtentUsage master, Element JavaDoc detailElem) throws TransformerException JavaDoc,
460       DjenericException
461   {
462     DjExtent extent = _session.getPersistenceManager().getExtent(detailElem.getAttribute("extent"));
463     ExtentUsage detail = new ExtentUsage(extent);
464     String JavaDoc relationName = detailElem.getAttribute("relation");
465
466     DjRelation relation = master.getExtent().getDetailRelation(relationName);
467     master.addDetail(detail, relation);
468
469     // Now handle nested details recursively
470
NodeIterator it = XPathAPI.selectNodeIterator(detailElem, "detail");
471
472     detailElem = (Element JavaDoc) it.nextNode();
473     while (detailElem != null)
474     {
475       buildDetailStruct(detail, detailElem);
476       detailElem = (Element JavaDoc) it.nextNode();
477     }
478   }
479
480   protected void setStatus(String JavaDoc msg)
481   {
482     if (_statusDisplayer != null) _statusDisplayer.setStatusMessageNow(msg, true);
483   }
484
485   public DjList getCreated()
486   {
487     return _created;
488   }
489
490   public DjList getDeleted()
491   {
492     return _deleted;
493   }
494
495   public DjList getUpdated()
496   {
497     return _updated;
498   }
499
500   public DjStatusDisplayer getStatusDisplayer()
501   {
502     return _statusDisplayer;
503   }
504
505   public void setStatusDisplayer(DjStatusDisplayer statusDisplayer)
506   {
507     _statusDisplayer = statusDisplayer;
508   }
509
510 }
511
Popular Tags