KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > entity > util > EntitySaxReader


1 /*
2  * $Id: EntitySaxReader.java 6257 2005-12-06 18:04:10Z jaz $
3  *
4  * Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */

24 package org.ofbiz.entity.util;
25
26 import java.io.ByteArrayInputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.InputStreamReader JavaDoc;
30 import java.io.Reader JavaDoc;
31 import java.io.StringWriter JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.util.ArrayList JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36
37 import freemarker.ext.beans.BeansWrapper;
38 import freemarker.ext.dom.NodeModel;
39 import freemarker.template.Configuration;
40 import freemarker.template.Template;
41 import freemarker.template.TemplateException;
42 import freemarker.template.TemplateHashModel;
43 import javolution.lang.Text;
44 import javolution.util.FastMap;
45 import javolution.xml.sax.Attributes;
46 import javolution.xml.sax.RealtimeParser;
47 import org.w3c.dom.Document JavaDoc;
48 import org.w3c.dom.Element JavaDoc;
49 import org.w3c.dom.Node JavaDoc;
50 import org.xml.sax.ErrorHandler JavaDoc;
51 import org.xml.sax.SAXException JavaDoc;
52
53 import org.ofbiz.base.util.Base64;
54 import org.ofbiz.base.util.Debug;
55 import org.ofbiz.base.util.UtilURL;
56 import org.ofbiz.base.util.UtilXml;
57 import org.ofbiz.entity.GenericDelegator;
58 import org.ofbiz.entity.GenericEntityException;
59 import org.ofbiz.entity.GenericValue;
60 import org.ofbiz.entity.eca.EntityEcaHandler;
61 import org.ofbiz.entity.model.ModelEntity;
62 import org.ofbiz.entity.model.ModelField;
63 import org.ofbiz.entity.transaction.GenericTransactionException;
64 import org.ofbiz.entity.transaction.TransactionUtil;
65
66 /**
67  * SAX XML Parser Content Handler for Entity Engine XML files
68  *
69  * @author <a HREF="mailto:jonesde@ofbiz.org">David E. Jones</a>
70  * @author <a HREF="mailto:jaz@ofbiz.org">Andy Zeneski</a>
71  * @version $Rev: 6257 $
72  * @since 2.0
73  */

74 public class EntitySaxReader implements javolution.xml.sax.ContentHandler, ErrorHandler JavaDoc {
75
76     public static final String JavaDoc module = EntitySaxReader.class.getName();
77     public static final int DEFAULT_TX_TIMEOUT = 7200;
78
79     protected org.xml.sax.Locator JavaDoc locator;
80     protected GenericDelegator delegator;
81     protected EntityEcaHandler ecaHandler = null;
82     protected GenericValue currentValue = null;
83     protected CharSequence JavaDoc currentFieldName = null;
84     protected CharSequence JavaDoc currentFieldValue = null;
85     protected long numberRead = 0;
86
87     protected int valuesPerWrite = 100;
88     protected int valuesPerMessage = 1000;
89     protected int transactionTimeout = 7200;
90     protected boolean useTryInsertMethod = false;
91     protected boolean maintainTxStamps = false;
92     protected boolean createDummyFks = false;
93     protected boolean doCacheClear = true;
94     protected boolean disableEeca = false;
95
96     protected List JavaDoc valuesToWrite = new ArrayList JavaDoc(valuesPerWrite);
97
98     protected boolean isParseForTemplate = false;
99     protected CharSequence JavaDoc templatePath = null;
100     protected Node JavaDoc rootNodeForTemplate = null;
101     protected Node JavaDoc currentNodeForTemplate = null;
102     protected Document JavaDoc documentForTemplate = null;
103
104     protected EntitySaxReader() {}
105
106     public EntitySaxReader(GenericDelegator delegator, int transactionTimeout) {
107         // clone the delegator right off so there is no chance of making change to the initial object
108
this.delegator = delegator.cloneDelegator();
109         this.transactionTimeout = transactionTimeout;
110     }
111
112     public EntitySaxReader(GenericDelegator delegator) {
113         this(delegator, DEFAULT_TX_TIMEOUT);
114     }
115
116     public int getValuesPerWrite() {
117         return this.valuesPerWrite;
118     }
119
120     public void setValuesPerWrite(int valuesPerWrite) {
121         this.valuesPerWrite = valuesPerWrite;
122     }
123
124     public int getValuesPerMessage() {
125         return this.valuesPerMessage;
126     }
127
128     public void setValuesPerMessage(int valuesPerMessage) {
129         this.valuesPerMessage = valuesPerMessage;
130     }
131
132     public int getTransactionTimeout() {
133         return this.transactionTimeout;
134     }
135
136     public void setUseTryInsertMethod(boolean value) {
137         this.useTryInsertMethod = value;
138     }
139
140     public void setTransactionTimeout(int transactionTimeout) throws GenericTransactionException {
141         if (this.transactionTimeout != transactionTimeout) {
142             TransactionUtil.setTransactionTimeout(transactionTimeout);
143             this.transactionTimeout = transactionTimeout;
144         }
145     }
146
147     public boolean getMaintainTxStamps() {
148         return this.maintainTxStamps;
149     }
150
151     public void setMaintainTxStamps(boolean maintainTxStamps) {
152         this.maintainTxStamps = maintainTxStamps;
153     }
154
155     public boolean getCreateDummyFks() {
156         return this.createDummyFks;
157     }
158
159     public void setCreateDummyFks(boolean createDummyFks) {
160         this.createDummyFks = createDummyFks;
161     }
162
163     public boolean getDoCacheClear() {
164         return this.doCacheClear;
165     }
166
167     public void setDoCacheClear(boolean doCacheClear) {
168         this.doCacheClear = doCacheClear;
169     }
170
171     public boolean getDisableEeca() {
172         return this.disableEeca;
173     }
174
175     public void setDisableEeca(boolean disableEeca) {
176         this.disableEeca = disableEeca;
177         if (disableEeca) {
178             if (this.ecaHandler == null) {
179                 this.ecaHandler = delegator.getEntityEcaHandler();
180             }
181             this.delegator.setEntityEcaHandler(null);
182         } else {
183             if (ecaHandler != null) {
184                 this.delegator.setEntityEcaHandler(ecaHandler);
185             }
186         }
187     }
188
189     public long parse(String JavaDoc content) throws SAXException JavaDoc, java.io.IOException JavaDoc {
190         if (content == null) {
191             Debug.logWarning("content was null, doing nothing", module);
192             return 0;
193         }
194         ByteArrayInputStream JavaDoc bis = new ByteArrayInputStream JavaDoc(content.getBytes());
195
196         return this.parse(bis, "Internal Content");
197     }
198
199     public long parse(URL JavaDoc location) throws SAXException JavaDoc, java.io.IOException JavaDoc {
200         if (location == null) {
201             Debug.logWarning("location URL was null, doing nothing", module);
202             return 0;
203         }
204         Debug.logImportant("Beginning import from URL: " + location.toExternalForm(), module);
205         return this.parse(location.openStream(), location.toString());
206     }
207
208     public long parse(InputStream JavaDoc is, String JavaDoc docDescription) throws SAXException JavaDoc, java.io.IOException JavaDoc {
209
210         /* NOTE: this method is not used because it doesn't work with various parsers...
211          String orgXmlSaxDriver = System.getProperty("org.xml.sax.driver");
212          if (UtilValidate.isEmpty(orgXmlSaxDriver)) orgXmlSaxDriver = "org.apache.xerces.parsers.SAXParser";
213          XMLReader reader = XMLReaderFactory.createXMLReader(orgXmlSaxDriver);
214          */

215
216         /* This code is for a standard SAXParser and XMLReader like xerces or such; for speed we are using the Javolution reader
217         XMLReader reader = null;
218
219         try {
220             SAXParserFactory parserFactory = SAXParserFactory.newInstance();
221             SAXParser parser = parserFactory.newSAXParser();
222
223             reader = parser.getXMLReader();
224         } catch (javax.xml.parsers.ParserConfigurationException e) {
225             Debug.logError(e, "Failed to get a SAX XML parser", module);
226             throw new IllegalStateException("Failed to get a SAX XML parser");
227         }
228         */

229
230         RealtimeParser parser = new RealtimeParser(16384);
231
232         parser.setContentHandler(this);
233         parser.setErrorHandler(this);
234         // LocalResolver lr = new UtilXml.LocalResolver(new DefaultHandler());
235
// reader.setEntityResolver(lr);
236

237         numberRead = 0;
238         try {
239             boolean beganTransaction = false;
240             if (transactionTimeout > -1) {
241                 beganTransaction = TransactionUtil.begin(transactionTimeout);
242                 Debug.logImportant("Transaction Timeout set to " + transactionTimeout / 3600 + " hours (" + transactionTimeout + " seconds)", module);
243             }
244             try {
245                 parser.parse(is);
246                 // make sure all of the values to write got written...
247
if (valuesToWrite.size() > 0) {
248                     writeValues(valuesToWrite);
249                     valuesToWrite.clear();
250                 }
251                 TransactionUtil.commit(beganTransaction);
252             } catch (Exception JavaDoc e) {
253                 String JavaDoc errMsg = "An error occurred saving the data, rolling back transaction (" + beganTransaction + ")";
254                 Debug.logError(e, errMsg, module);
255                 TransactionUtil.rollback(beganTransaction, errMsg, e);
256                 throw new SAXException JavaDoc("A transaction error occurred reading data", e);
257             }
258         } catch (GenericTransactionException e) {
259             throw new SAXException JavaDoc("A transaction error occurred reading data", e);
260         }
261         Debug.logImportant("Finished " + numberRead + " values from " + docDescription, module);
262         return numberRead;
263     }
264
265     protected void writeValues(List JavaDoc valuesToWrite) throws GenericEntityException {
266         delegator.storeAll(valuesToWrite, doCacheClear, createDummyFks);
267     }
268
269     public void characters(char[] values, int offset, int count) throws org.xml.sax.SAXException JavaDoc {
270         if (isParseForTemplate) {
271             // if null, don't worry about it
272
if (this.currentNodeForTemplate != null) {
273                 Node JavaDoc newNode = this.documentForTemplate.createTextNode(new String JavaDoc(values, offset, count));
274                 this.currentNodeForTemplate.appendChild(newNode);
275             }
276             return;
277         }
278
279         if (currentValue != null && currentFieldName != null) {
280             Text value = Text.valueOf(values, offset, count);
281
282             // Debug.logInfo("characters: value=" + value, module);
283
if (currentFieldValue == null) {
284                 currentFieldValue = value;
285             } else {
286                 currentFieldValue = Text.valueOf(currentFieldValue).concat(value);
287             }
288         }
289     }
290
291     public void endDocument() throws org.xml.sax.SAXException JavaDoc {}
292
293     public void endElement(CharSequence JavaDoc namespaceURI, CharSequence JavaDoc localName, CharSequence JavaDoc fullName) throws org.xml.sax.SAXException JavaDoc {
294         if (Debug.verboseOn()) Debug.logVerbose("endElement: localName=" + localName + ", fullName=" + fullName + ", numberRead=" + numberRead, module);
295         String JavaDoc fullNameString = fullName.toString();
296         if ("entity-engine-xml".equals(fullNameString)) {
297             return;
298         }
299         if ("entity-engine-transform-xml".equals(fullNameString)) {
300             // transform file & parse it, then return
301
URL JavaDoc templateUrl = UtilURL.fromResource(templatePath.toString());
302
303             if (templateUrl == null) {
304                 throw new SAXException JavaDoc("Could not find transform template with resource path: " + templatePath);
305             } else {
306                 try {
307                     Reader JavaDoc templateReader = new InputStreamReader JavaDoc(templateUrl.openStream());
308
309                     StringWriter JavaDoc outWriter = new StringWriter JavaDoc();
310                     Configuration config = new Configuration();
311                     config.setObjectWrapper(BeansWrapper.getDefaultInstance());
312                     config.setSetting("datetime_format", "yyyy-MM-dd HH:mm:ss.SSS");
313
314                     Template template = new Template("FMImportFilter", templateReader, config);
315                     NodeModel nodeModel = NodeModel.wrap(this.rootNodeForTemplate);
316
317                     Map JavaDoc context = FastMap.newInstance();
318                     BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
319                     TemplateHashModel staticModels = wrapper.getStaticModels();
320                     context.put("Static", staticModels);
321
322                     context.put("doc", nodeModel);
323                     template.process(context, outWriter);
324                     String JavaDoc s = outWriter.toString();
325                     if (Debug.verboseOn()) Debug.logVerbose("transformed xml: " + s, module);
326
327                     EntitySaxReader reader = new EntitySaxReader(delegator);
328                     reader.setUseTryInsertMethod(this.useTryInsertMethod);
329                     try {
330                         reader.setTransactionTimeout(this.transactionTimeout);
331                     } catch (GenericTransactionException e1) {
332                         // couldn't set tx timeout, shouldn't be a big deal
333
}
334
335                     numberRead += reader.parse(s);
336                 } catch (TemplateException e) {
337                     throw new SAXException JavaDoc("Error storing value", e);
338                 } catch(IOException JavaDoc e) {
339                     throw new SAXException JavaDoc("Error storing value", e);
340                 }
341             }
342
343             return;
344         }
345
346         if (isParseForTemplate) {
347             this.currentNodeForTemplate = this.currentNodeForTemplate.getParentNode();
348             return;
349         }
350
351         if (currentValue != null) {
352             if (currentFieldName != null) {
353                 if (currentFieldValue != null && currentFieldValue.length() > 0) {
354                     if (currentValue.getModelEntity().isField(currentFieldName.toString())) {
355                         ModelEntity modelEntity = currentValue.getModelEntity();
356                         ModelField modelField = modelEntity.getField(currentFieldName.toString());
357                         String JavaDoc type = modelField.getType();
358                         if (type != null && type.equals("blob")) {
359                             byte strData[] = new byte[currentFieldValue.length()];
360                             strData = currentFieldValue.toString().getBytes();
361                             byte binData[] = new byte[currentFieldValue.length()];
362                             binData = Base64.base64Decode(strData);
363                             currentValue.setBytes(currentFieldName.toString(), binData);
364                         } else {
365                             currentValue.setString(currentFieldName.toString(), currentFieldValue.toString());
366                         }
367                     } else {
368                         Debug.logWarning("Ignoring invalid field name [" + currentFieldName + "] found for the entity: " + currentValue.getEntityName() + " with value=" + currentFieldValue, module);
369                     }
370                     currentFieldValue = null;
371                 }
372                 currentFieldName = null;
373             } else {
374                 // before we write currentValue check to see if PK is there, if not and it is one field, generate it from a sequence using the entity name
375
if (!currentValue.containsPrimaryKey()) {
376                     if (currentValue.getModelEntity().getPksSize() == 1) {
377                         ModelField modelField = currentValue.getModelEntity().getOnlyPk();
378                         String JavaDoc newSeq = delegator.getNextSeqId(currentValue.getEntityName());
379                         currentValue.setString(modelField.getName(), newSeq);
380                     } else {
381                         throw new SAXException JavaDoc("Cannot store value with incomplete primary key with more than 1 primary key field: " + currentValue);
382                     }
383                 }
384
385                 try {
386                     if (useTryInsertMethod) {
387                         // this technique is faster for data sets where most, if not all, values do not already exist in the database
388
try {
389                             currentValue.create();
390                         } catch (GenericEntityException e1) {
391                             // create failed, try a store, if that fails too we have a real error and the catch outside of this should handle it
392
currentValue.store();
393                         }
394                     } else {
395                         valuesToWrite.add(currentValue);
396                         if (valuesToWrite.size() >= valuesPerWrite) {
397                             writeValues(valuesToWrite);
398                             valuesToWrite.clear();
399                         }
400                     }
401                     numberRead++;
402                     if ((numberRead % valuesPerMessage) == 0) {
403                         Debug.logImportant("Another " + valuesPerMessage + " values imported: now up to " + numberRead, module);
404                     }
405                     currentValue = null;
406                 } catch (GenericEntityException e) {
407                     String JavaDoc errMsg = "Error storing value";
408                     Debug.logError(e, errMsg, module);
409                     throw new SAXException JavaDoc(errMsg, e);
410                 }
411             }
412         }
413     }
414
415     public void endPrefixMapping(CharSequence JavaDoc prefix) throws org.xml.sax.SAXException JavaDoc {}
416
417     public void ignorableWhitespace(char[] values, int offset, int count) throws org.xml.sax.SAXException JavaDoc {
418         // String value = new String(values, offset, count);
419
// Debug.logInfo("ignorableWhitespace: value=" + value, module);
420
}
421
422     public void processingInstruction(CharSequence JavaDoc target, CharSequence JavaDoc instruction) throws org.xml.sax.SAXException JavaDoc {}
423
424     public void setDocumentLocator(org.xml.sax.Locator JavaDoc locator) {
425         this.locator = locator;
426     }
427
428     public void skippedEntity(CharSequence JavaDoc name) throws org.xml.sax.SAXException JavaDoc {}
429
430     public void startDocument() throws org.xml.sax.SAXException JavaDoc {}
431
432     public void startElement(CharSequence JavaDoc namepsaceURI, CharSequence JavaDoc localName, CharSequence JavaDoc fullName, Attributes attributes) throws org.xml.sax.SAXException JavaDoc {
433         if (Debug.verboseOn()) Debug.logVerbose("startElement: localName=" + localName + ", fullName=" + fullName + ", attributes=" + attributes, module);
434         String JavaDoc fullNameString = fullName.toString();
435         if ("entity-engine-xml".equals(fullNameString)) {
436             // check the maintain-timestamp flag
437
CharSequence JavaDoc maintainTx = attributes.getValue("maintain-timestamps");
438             if (maintainTx != null) {
439                 this.setMaintainTxStamps("true".equalsIgnoreCase(maintainTx.toString()));
440             }
441
442             // check the do-cache-clear flag
443
CharSequence JavaDoc doCacheClear = attributes.getValue("do-cache-clear");
444             if (doCacheClear != null) {
445                 this.setDoCacheClear("true".equalsIgnoreCase(doCacheClear.toString()));
446             }
447
448             // check the disable-eeca flag
449
CharSequence JavaDoc ecaDisable = attributes.getValue("disable-eeca");
450             if (ecaDisable != null) {
451                 this.setDisableEeca("true".equalsIgnoreCase(ecaDisable.toString()));
452             }
453
454             // check the use-dummy-fk flag
455
CharSequence JavaDoc dummyFk = attributes.getValue("create-dummy-fk");
456             if (dummyFk != null) {
457                 this.setCreateDummyFks("true".equalsIgnoreCase(dummyFk.toString()));
458             }
459
460             return;
461         }
462
463         if ("entity-engine-transform-xml".equals(fullNameString)) {
464             templatePath = attributes.getValue("template");
465             isParseForTemplate = true;
466             documentForTemplate = UtilXml.makeEmptyXmlDocument();
467             return;
468         }
469
470         if (isParseForTemplate) {
471             Element JavaDoc newElement = this.documentForTemplate.createElement(fullNameString);
472             int length = attributes.getLength();
473             for (int i = 0; i < length; i++) {
474                 CharSequence JavaDoc name = attributes.getLocalName(i);
475                 CharSequence JavaDoc value = attributes.getValue(i);
476
477                 if (name == null || name.length() == 0) {
478                     name = attributes.getQName(i);
479                 }
480                 newElement.setAttribute(name.toString(), value.toString());
481             }
482
483             if (this.currentNodeForTemplate == null) {
484                 this.currentNodeForTemplate = newElement;
485                 this.rootNodeForTemplate = newElement;
486             } else {
487                 this.currentNodeForTemplate.appendChild(newElement);
488                 this.currentNodeForTemplate = newElement;
489             }
490             return;
491         }
492
493         if (currentValue != null) {
494             // we have a nested value/CDATA element
495
currentFieldName = fullName;
496         } else {
497             String JavaDoc entityName = fullNameString;
498
499             // if a dash or colon is in the tag name, grab what is after it
500
if (entityName.indexOf('-') > 0) {
501                 entityName = entityName.substring(entityName.indexOf('-') + 1);
502             }
503             if (entityName.indexOf(':') > 0) {
504                 entityName = entityName.substring(entityName.indexOf(':') + 1);
505             }
506
507             try {
508                 currentValue = delegator.makeValue(entityName, null);
509                 // TODO: do we really want this? it makes it so none of the values imported have create/update timestamps set
510
// DEJ 10/16/04 I think they should all be stamped, so commenting this out
511
// JAZ 12/10/04 I think it should be specified when creating the reader
512
if (this.maintainTxStamps) {
513                     currentValue.setIsFromEntitySync(true);
514                 }
515             } catch (Exception JavaDoc e) {
516                 Debug.logError(e, module);
517             }
518
519             if (currentValue != null) {
520                 int length = attributes.getLength();
521
522                 for (int i = 0; i < length; i++) {
523                     CharSequence JavaDoc name = attributes.getLocalName(i);
524                     CharSequence JavaDoc value = attributes.getValue(i);
525
526                     if (name == null || name.length() == 0) {
527                         name = attributes.getQName(i);
528                     }
529                     try {
530                         // treat empty strings as nulls
531
if (value != null && value.length() > 0) {
532                             if (currentValue.getModelEntity().isField(name.toString())) {
533                                 currentValue.setString(name.toString(), value.toString());
534                             } else {
535                                 Debug.logWarning("Ignoring invalid field name [" + name + "] found for the entity: " + currentValue.getEntityName() + " with value=" + value, module);
536                             }
537                         }
538                     } catch (Exception JavaDoc e) {
539                         Debug.logWarning(e, "Could not set field " + entityName + "." + name + " to the value " + value, module);
540                     }
541                 }
542             }
543         }
544     }
545
546     //public void startPrefixMapping(String prefix, String uri) throws org.xml.sax.SAXException {}
547
public void startPrefixMapping(CharSequence JavaDoc arg0, CharSequence JavaDoc arg1) throws SAXException JavaDoc {}
548
549     // ======== ErrorHandler interface implementations ========
550

551     public void error(org.xml.sax.SAXParseException JavaDoc exception) throws org.xml.sax.SAXException JavaDoc {
552         Debug.logWarning(exception, "Error reading XML on line " + exception.getLineNumber() + ", column " + exception.getColumnNumber(), module);
553     }
554
555     public void fatalError(org.xml.sax.SAXParseException JavaDoc exception) throws org.xml.sax.SAXException JavaDoc {
556         Debug.logError(exception, "Fatal Error reading XML on line " + exception.getLineNumber() + ", column " + exception.getColumnNumber(), module);
557         throw new SAXException JavaDoc("Fatal Error reading XML on line " + exception.getLineNumber() + ", column " + exception.getColumnNumber(), exception);
558     }
559
560     public void warning(org.xml.sax.SAXParseException JavaDoc exception) throws org.xml.sax.SAXException JavaDoc {
561         Debug.logWarning(exception, "Warning reading XML on line " + exception.getLineNumber() + ", column " + exception.getColumnNumber(), module);
562     }
563 }
564
Popular Tags