1 24 package org.ofbiz.entity.util; 25 26 import java.io.ByteArrayInputStream ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.io.InputStreamReader ; 30 import java.io.Reader ; 31 import java.io.StringWriter ; 32 import java.net.URL ; 33 import java.util.ArrayList ; 34 import java.util.List ; 35 import java.util.Map ; 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 ; 48 import org.w3c.dom.Element ; 49 import org.w3c.dom.Node ; 50 import org.xml.sax.ErrorHandler ; 51 import org.xml.sax.SAXException ; 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 74 public class EntitySaxReader implements javolution.xml.sax.ContentHandler, ErrorHandler { 75 76 public static final String module = EntitySaxReader.class.getName(); 77 public static final int DEFAULT_TX_TIMEOUT = 7200; 78 79 protected org.xml.sax.Locator locator; 80 protected GenericDelegator delegator; 81 protected EntityEcaHandler ecaHandler = null; 82 protected GenericValue currentValue = null; 83 protected CharSequence currentFieldName = null; 84 protected CharSequence 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 valuesToWrite = new ArrayList (valuesPerWrite); 97 98 protected boolean isParseForTemplate = false; 99 protected CharSequence templatePath = null; 100 protected Node rootNodeForTemplate = null; 101 protected Node currentNodeForTemplate = null; 102 protected Document documentForTemplate = null; 103 104 protected EntitySaxReader() {} 105 106 public EntitySaxReader(GenericDelegator delegator, int transactionTimeout) { 107 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 content) throws SAXException , java.io.IOException { 190 if (content == null) { 191 Debug.logWarning("content was null, doing nothing", module); 192 return 0; 193 } 194 ByteArrayInputStream bis = new ByteArrayInputStream (content.getBytes()); 195 196 return this.parse(bis, "Internal Content"); 197 } 198 199 public long parse(URL location) throws SAXException , java.io.IOException { 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 is, String docDescription) throws SAXException , java.io.IOException { 209 210 215 216 229 230 RealtimeParser parser = new RealtimeParser(16384); 231 232 parser.setContentHandler(this); 233 parser.setErrorHandler(this); 234 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 if (valuesToWrite.size() > 0) { 248 writeValues(valuesToWrite); 249 valuesToWrite.clear(); 250 } 251 TransactionUtil.commit(beganTransaction); 252 } catch (Exception e) { 253 String 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 ("A transaction error occurred reading data", e); 257 } 258 } catch (GenericTransactionException e) { 259 throw new SAXException ("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 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 { 270 if (isParseForTemplate) { 271 if (this.currentNodeForTemplate != null) { 273 Node newNode = this.documentForTemplate.createTextNode(new String (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 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 {} 292 293 public void endElement(CharSequence namespaceURI, CharSequence localName, CharSequence fullName) throws org.xml.sax.SAXException { 294 if (Debug.verboseOn()) Debug.logVerbose("endElement: localName=" + localName + ", fullName=" + fullName + ", numberRead=" + numberRead, module); 295 String fullNameString = fullName.toString(); 296 if ("entity-engine-xml".equals(fullNameString)) { 297 return; 298 } 299 if ("entity-engine-transform-xml".equals(fullNameString)) { 300 URL templateUrl = UtilURL.fromResource(templatePath.toString()); 302 303 if (templateUrl == null) { 304 throw new SAXException ("Could not find transform template with resource path: " + templatePath); 305 } else { 306 try { 307 Reader templateReader = new InputStreamReader (templateUrl.openStream()); 308 309 StringWriter outWriter = new StringWriter (); 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 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 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 } 334 335 numberRead += reader.parse(s); 336 } catch (TemplateException e) { 337 throw new SAXException ("Error storing value", e); 338 } catch(IOException e) { 339 throw new SAXException ("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 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 if (!currentValue.containsPrimaryKey()) { 376 if (currentValue.getModelEntity().getPksSize() == 1) { 377 ModelField modelField = currentValue.getModelEntity().getOnlyPk(); 378 String newSeq = delegator.getNextSeqId(currentValue.getEntityName()); 379 currentValue.setString(modelField.getName(), newSeq); 380 } else { 381 throw new SAXException ("Cannot store value with incomplete primary key with more than 1 primary key field: " + currentValue); 382 } 383 } 384 385 try { 386 if (useTryInsertMethod) { 387 try { 389 currentValue.create(); 390 } catch (GenericEntityException e1) { 391 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 errMsg = "Error storing value"; 408 Debug.logError(e, errMsg, module); 409 throw new SAXException (errMsg, e); 410 } 411 } 412 } 413 } 414 415 public void endPrefixMapping(CharSequence prefix) throws org.xml.sax.SAXException {} 416 417 public void ignorableWhitespace(char[] values, int offset, int count) throws org.xml.sax.SAXException { 418 } 421 422 public void processingInstruction(CharSequence target, CharSequence instruction) throws org.xml.sax.SAXException {} 423 424 public void setDocumentLocator(org.xml.sax.Locator locator) { 425 this.locator = locator; 426 } 427 428 public void skippedEntity(CharSequence name) throws org.xml.sax.SAXException {} 429 430 public void startDocument() throws org.xml.sax.SAXException {} 431 432 public void startElement(CharSequence namepsaceURI, CharSequence localName, CharSequence fullName, Attributes attributes) throws org.xml.sax.SAXException { 433 if (Debug.verboseOn()) Debug.logVerbose("startElement: localName=" + localName + ", fullName=" + fullName + ", attributes=" + attributes, module); 434 String fullNameString = fullName.toString(); 435 if ("entity-engine-xml".equals(fullNameString)) { 436 CharSequence maintainTx = attributes.getValue("maintain-timestamps"); 438 if (maintainTx != null) { 439 this.setMaintainTxStamps("true".equalsIgnoreCase(maintainTx.toString())); 440 } 441 442 CharSequence doCacheClear = attributes.getValue("do-cache-clear"); 444 if (doCacheClear != null) { 445 this.setDoCacheClear("true".equalsIgnoreCase(doCacheClear.toString())); 446 } 447 448 CharSequence ecaDisable = attributes.getValue("disable-eeca"); 450 if (ecaDisable != null) { 451 this.setDisableEeca("true".equalsIgnoreCase(ecaDisable.toString())); 452 } 453 454 CharSequence 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 newElement = this.documentForTemplate.createElement(fullNameString); 472 int length = attributes.getLength(); 473 for (int i = 0; i < length; i++) { 474 CharSequence name = attributes.getLocalName(i); 475 CharSequence 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 currentFieldName = fullName; 496 } else { 497 String entityName = fullNameString; 498 499 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 if (this.maintainTxStamps) { 513 currentValue.setIsFromEntitySync(true); 514 } 515 } catch (Exception 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 name = attributes.getLocalName(i); 524 CharSequence value = attributes.getValue(i); 525 526 if (name == null || name.length() == 0) { 527 name = attributes.getQName(i); 528 } 529 try { 530 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 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(CharSequence arg0, CharSequence arg1) throws SAXException {} 548 549 551 public void error(org.xml.sax.SAXParseException exception) throws org.xml.sax.SAXException { 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 exception) throws org.xml.sax.SAXException { 556 Debug.logError(exception, "Fatal Error reading XML on line " + exception.getLineNumber() + ", column " + exception.getColumnNumber(), module); 557 throw new SAXException ("Fatal Error reading XML on line " + exception.getLineNumber() + ", column " + exception.getColumnNumber(), exception); 558 } 559 560 public void warning(org.xml.sax.SAXParseException exception) throws org.xml.sax.SAXException { 561 Debug.logWarning(exception, "Warning reading XML on line " + exception.getLineNumber() + ", column " + exception.getColumnNumber(), module); 562 } 563 } 564 | Popular Tags |