| 1 64 65 package com.jcorporate.expresso.core.dbobj; 66 67 import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap; 68 import com.jcorporate.expresso.core.cache.CacheException; 69 import com.jcorporate.expresso.core.cache.CacheManager; 70 import com.jcorporate.expresso.core.cache.CacheSystem; 71 import com.jcorporate.expresso.core.cache.Cacheable; 72 import com.jcorporate.expresso.core.controller.Transition; 73 import com.jcorporate.expresso.core.dataobjects.BaseDataObject; 74 import com.jcorporate.expresso.core.dataobjects.DataException; 75 import com.jcorporate.expresso.core.dataobjects.DataField; 76 import com.jcorporate.expresso.core.dataobjects.DataFieldMetaData; 77 import com.jcorporate.expresso.core.dataobjects.DataObject; 78 import com.jcorporate.expresso.core.dataobjects.DataObjectMetaData; 79 import com.jcorporate.expresso.core.dataobjects.DataTransferObject; 80 import com.jcorporate.expresso.core.dataobjects.DefaultDataField; 81 import com.jcorporate.expresso.core.dataobjects.jdbc.FieldRangeParser; 82 import com.jcorporate.expresso.core.dataobjects.jdbc.JDBCDataObject; 83 import com.jcorporate.expresso.core.dataobjects.jdbc.JDBCObjectMetaData; 84 import com.jcorporate.expresso.core.dataobjects.jdbc.JDBCUtil; 85 import com.jcorporate.expresso.core.db.DBConnection; 86 import com.jcorporate.expresso.core.db.DBConnectionPool; 87 import com.jcorporate.expresso.core.db.DBException; 88 import com.jcorporate.expresso.core.db.exception.DBRecordNotFoundException; 89 import com.jcorporate.expresso.core.misc.ConfigJdbc; 90 import com.jcorporate.expresso.core.misc.ConfigManager; 91 import com.jcorporate.expresso.core.misc.ConfigurationException; 92 import com.jcorporate.expresso.core.misc.DateTime; 93 import com.jcorporate.expresso.core.misc.StringUtil; 94 import com.jcorporate.expresso.core.registry.RequestRegistry; 95 import com.jcorporate.expresso.core.security.filters.Filter; 96 import com.jcorporate.expresso.kernel.util.ClassLocator; 97 import com.jcorporate.expresso.kernel.util.FastStringBuffer; 98 import com.jcorporate.expresso.services.dbobj.ChangeLog; 99 import com.jcorporate.expresso.services.dbobj.DBObjLimit; 100 import com.jcorporate.expresso.services.dbobj.Setup; 101 import org.apache.log4j.Logger; 102 import org.apache.oro.text.regex.Pattern; 103 import org.apache.oro.text.regex.PatternMatcher; 104 import org.apache.oro.text.regex.Perl5Matcher; 105 106 import java.io.IOException ; 107 import java.io.InputStream ; 108 import java.io.ObjectInputStream ; 109 import java.io.ObjectOutputStream ; 110 import java.lang.reflect.Method ; 111 import java.math.BigDecimal ; 112 import java.sql.SQLException ; 113 import java.text.DecimalFormat ; 114 import java.text.NumberFormat ; 115 import java.text.ParseException ; 116 import java.util.ArrayList ; 117 import java.util.Collections ; 118 import java.util.Enumeration ; 119 import java.util.HashMap ; 120 import java.util.Iterator ; 121 import java.util.List ; 122 import java.util.Locale ; 123 import java.util.Map ; 124 import java.util.StringTokenizer ; 125 import java.util.Vector ; 126 127 128 141 public abstract class DBObject 142 extends JDBCDataObject 143 implements Cacheable, LookupInterface { 144 145 146 152 public static final String UPDATE_CHANGED_ONLY = "UPDATE_CHANGED_ONLY"; 153 154 157 public static final String ATTRIBUTE_ERROR = "error"; 158 159 163 public static final String ATTRIBUTE_ERROR_MESSAGE = "error-message"; 164 165 168 public static final String ATTRIBUTE_PAGE_LIMIT = "pageLimit"; 169 170 173 public static final String EVENT_ADD = "A"; 174 175 178 public static final String EVENT_DELETE = "D"; 179 180 183 public static final String EVENT_UPDATE = "U"; 184 185 186 193 transient protected static final BigDecimal BIG_DECIMAL_ZERO = new BigDecimal (0.0); 194 195 196 200 transient private static Logger log = Logger.getLogger(DBObject.class); 201 202 203 206 transient private static final long DBOBJLIMIT_CACHE_TTL = 60 * 1000 * 30; 207 208 211 transient private static ConcurrentReaderHashMap sCacheStats = new ConcurrentReaderHashMap(); 212 213 214 217 transient final private static CacheUtils cacheUtils = new CacheUtils(); 218 219 223 transient private static ThreadLocal patternMatcher = new ThreadLocal () { 224 protected synchronized Object initialValue() { 225 return new Perl5Matcher(); 226 } 227 }; 228 private static Logger slog = null; 229 public static final String WHERE_KEYWORD = " WHERE "; 230 231 237 protected PatternMatcher getPatternMatcher() { 238 return (PatternMatcher) patternMatcher.get(); 239 } 240 241 242 246 transient private static FieldRangeParser rangeVerifier = new FieldRangeParser(); 247 248 249 253 260 private Class mFilter = null; 261 262 267 private Map fieldData = null; 268 269 270 274 private HashMap fieldErrors = null; 275 276 277 286 private Locale myLocale = Locale.getDefault(); 287 288 289 292 private ArrayList foundKeys = null; 293 294 297 private HashMap attributes = null; 298 299 300 private int myCacheSize = -2; 301 302 303 307 boolean anyFieldsToRetrieveMulti = false; 308 309 310 313 public static final String INT_MASK = "^[+-]?[0-9]+"; 314 315 318 public static final String FLOAT_MASK = "^([+-]?)(?=\\d|\\.\\d)\\d*(\\.\\d*)?([Ee]([+-]?\\d+))?$"; 319 320 323 public static final String EMAIL_MASK = 324 "^[A-Za-z0-9\\-\\.\\_]+" 325 + "@" 326 + "[A-Za-z0-9\\-\\.\\_]+" 327 + "\\." 328 + "[a-zA-Z]{2,6}$"; public static final String IS_CHECK_RELATIONAL_INTEGRITY = "isCheckRelationalIntegrity"; 330 331 338 public DBObject() 339 throws DBException { 340 initialize(); 341 } 342 343 355 public DBObject(DBConnection newConnection) 356 throws DBException { 357 this(newConnection, newConnection.getDataContext()); 358 } 359 360 361 378 public DBObject(DBConnection newConnection, String setupTablesContext) 379 throws DBException { 380 this(); 381 setConnection(newConnection, setupTablesContext); 382 } 383 384 394 public DBObject(RequestContext request) 395 throws DBException { 396 this(); 397 setDataContext(request.getDBName()); 398 setLocale(request.getLocale()); 399 } 400 401 407 public Locale getLocale() { 408 return myLocale; 409 } 410 411 417 public void setLocale(Locale newLocale) { 418 myLocale = newLocale; 419 } 420 421 427 public DBObject(String newdbKey) 428 throws DBException { 429 this(); 430 setDataContext(newdbKey); 431 } 432 433 443 public void add() 444 throws DBException { 445 446 getExecutor().add(this); 447 448 449 if (getDef().isLoggingEnabled()) { 450 ChangeLog myChangeLog = new ChangeLog(); 451 myChangeLog.setDataContext(getDataContext()); 452 myChangeLog.setField("ObjectChanged", myClassName); 453 myChangeLog.setField("RecordKey", getMyKeys()); 454 myChangeLog.setField("Operation", EVENT_ADD); 455 myChangeLog.setField("ChangedField", "ALL"); 456 myChangeLog.add(); 457 458 459 myUpdates = null; 460 } 461 462 cacheIsChangedComparison(); 464 setStatus(BaseDataObject.STATUS_CURRENT); 465 notifyListeners(EVENT_ADD); 466 } 467 468 480 public synchronized int loadFromConnection(DBConnection connection) 481 throws DBException { 482 String oneFieldName = null; 483 Object tmpData = null; 484 int fieldCount = 0; 485 JDBCObjectMetaData metadata = getJDBCMetaData(); 486 for (Iterator it = metadata.getFieldListArray().iterator(); it.hasNext();) { 487 oneFieldName = (String ) it.next(); 488 489 try { 490 DataFieldMetaData oneField = metadata.getFieldMetadata(oneFieldName); 491 if (oneField.isDateType()) { 492 tmpData = getCustomStringFieldValue(connection, oneFieldName); 493 } else { 494 if (!oneField.isLongBinaryType() && !oneField.isLongCharacterType()) { 495 if (connection.isStringNotTrim()) { 496 tmpData = connection.getStringNoTrim(oneFieldName); 497 } else { 498 tmpData = connection.getString(oneFieldName); 499 } 500 } else { 501 if (oneField.isLongBinaryType()) { 502 tmpData = null; 503 InputStream is = connection.getBinaryStream(oneFieldName); 504 if (is != null) { 505 byte[] bstr = new byte[LONGBINARY_READ_DEFAULT_SIZE]; 506 int j = is.read(bstr); 507 if (j > 0) { 508 byte[] content = new byte[j]; 509 System.arraycopy(bstr, 0, content, 0, j); 510 tmpData = content; 511 } 512 } 513 } else { 514 tmpData = connection.getStringNoTrim(oneFieldName); 515 } 516 } 517 518 } 524 525 this.set(oneFieldName, tmpData); 527 fieldCount++; 528 } catch (DBException de) { 529 if (log.isDebugEnabled()) { 530 log.debug("Failed to load field.", de); 531 } 532 533 } catch (Exception e) { 535 if (log.isDebugEnabled()) { 536 log.debug("Failed to load field.", e); 537 } 538 539 } 541 542 } 543 544 545 setDataContext(getDataContext()); 546 cacheIsChangedComparison(); 547 setStatus(BaseDataObject.STATUS_CURRENT); 548 549 return fieldCount; 550 } 551 552 559 public void cacheIsChangedComparison() throws DBException { 560 for (Iterator i = getMetaData().getFieldListArray().iterator(); i.hasNext();) { 561 String oneFieldName = (String ) i.next(); 562 DataField field = getDataField(oneFieldName); 563 field.cacheIsChangedComparison(); 564 } 565 } 566 567 568 575 public void addFoundKeys(String fieldName) { 576 if (foundKeys == null) { 577 foundKeys = new ArrayList (); 578 } 579 580 foundKeys.add(fieldName); 581 } 582 583 593 protected synchronized void addDetail(String objName, 594 String keyFieldsLocal, 595 String keyFieldsForeign) 596 throws DBException { 597 getDef().addDetail(objName, keyFieldsLocal, keyFieldsForeign); 598 } 599 600 614 protected synchronized void addField(String fieldName, String fieldType, 615 int fieldSize, int fieldPrecision, 616 boolean allowNull, 617 String fieldDescription) 618 throws DBException { 619 getDef().addField(fieldName, fieldType, fieldSize, fieldPrecision, 620 allowNull, fieldDescription); 621 } 622 623 624 642 protected synchronized void addField(String fieldName, String fieldType, 643 int fieldSize, boolean allowNull, 644 String fieldDescription) 645 throws DBException { 646 getDef().addField(fieldName, fieldType, fieldSize, allowNull, 647 fieldDescription); 648 } 649 650 651 658 public synchronized void addIfNeeded() 659 throws DBException { 660 661 DBObject searchObj = newInstance(); 662 searchObj.setDataContext(getDataContext()); 663 664 String oneFieldName = null; 665 666 for (Iterator i = getKeyFieldListIterator(); i.hasNext();) { 667 oneFieldName = (String ) i.next(); 668 DataFieldMetaData oneField = getFieldMetaData(oneFieldName); 669 String value = getField(oneFieldName); 670 671 if (value.length() == 0) { 673 log.warn( 674 "a key field is empty, and yet DBObject.addIfNeeded() only uses primary-key fields for search; should you be using searchAndRetrieve() method instead? this addIfNeeded() will add ONLY if there is no other object of this type; after one object, it will always fail."); 675 } 676 677 if (!oneField.isVirtual()) { 678 searchObj.setField(oneFieldName, value); 679 } 680 } 681 if (!searchObj.find()) { 682 add(); 683 } 684 } 685 686 687 695 protected void addFieldError(String fieldName, String errorMessage) { 696 if (fieldErrors == null) { 697 fieldErrors = new HashMap(5); 698 } 699 700 fieldErrors.put(fieldName, new DBObject.FieldError(fieldName, errorMessage)); 701 } 702 703 711 public String getFieldErrorMessage(String fieldName) { 712 if (fieldErrors == null) { 713 return null; 714 } 715 716 DBObject.FieldError fe = (DBObject.FieldError) fieldErrors.get(fieldName); 717 if (fe == null) { 718 return null; 719 } 720 721 return fe.getErrorMessage(); 722 } 723 724 730 public boolean hasError(String fieldName) { 731 try { 732 DataField df = getDataField(fieldName); 733 if (df.getAttribute(ATTRIBUTE_ERROR) != null) { 734 return true; 735 } 736 } catch (DBException ex) { 737 log.error("Invalid field name: " + fieldName, ex); 738 return false; 739 } 740 741 if (fieldErrors == null) { 742 return false; 743 } 744 745 DBObject.FieldError fe = (DBObject.FieldError) fieldErrors.get(fieldName); 746 if (fe == null) { 747 return false; 748 } 749 750 return true; 751 } 752 753 758 public boolean hasErrors() { 759 if (fieldErrors == null || fieldErrors.isEmpty()) { 760 return false; 761 } 762 763 return true; 764 } 765 766 771 protected void clearError(String fieldName) { 772 if (fieldErrors == null) { 773 return; 774 } 775 776 fieldErrors.remove(fieldName); 777 } 778 779 789 protected void addIndex(String indexName, String fieldNames, 790 boolean isUnique) 791 throws IllegalArgumentException , DBException { 792 getDef().addIndex(indexName, fieldNames, isUnique); 793 } 794 795 804 protected synchronized void addKey(String keyFieldName) 805 throws DBException { 806 getDef().addKey(keyFieldName); 807 } 808 809 810 816 public synchronized void addOrUpdate() 817 throws DBException { 818 DBObject searchObj = newInstance(); 819 boolean canUpdate = true; 821 String oneFieldName = null; 822 JDBCObjectMetaData metadata = getJDBCMetaData(); 823 for (Iterator i = metadata.getKeyFieldListArray().iterator(); i.hasNext();) { 824 oneFieldName = (String ) i.next(); 825 DataField df = getDataField(oneFieldName); 826 if (df == null || df.isNull()) { 827 canUpdate = false; break; 829 } 830 831 searchObj.setField(oneFieldName, getField(oneFieldName)); 832 } 833 834 if (!canUpdate) { 835 add(); 836 return; 837 } 838 839 840 try { 841 searchObj
|