1 17 18 package org.objectweb.jac.aspects.persistence; 19 20 import java.sql.Connection ; 21 import java.sql.ResultSet ; 22 import java.sql.SQLException ; 23 import java.util.Arrays ; 24 import java.util.Collection ; 25 import java.util.HashMap ; 26 import java.util.Hashtable ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.Map ; 30 import java.util.Vector ; 31 import org.apache.log4j.Logger; 32 import org.objectweb.jac.core.rtti.ClassItem; 33 import org.objectweb.jac.core.rtti.CollectionItem; 34 import org.objectweb.jac.core.rtti.FieldItem; 35 import org.objectweb.jac.util.Strings; 36 37 42 43 public abstract class SQLStorage implements Storage,java.io.Serializable { 44 static Logger logger = Logger.getLogger("persistence.storage"); 45 static Logger loggerSql = Logger.getLogger("persistence.sql"); 46 47 49 protected Connection db; 50 51 53 protected SQLStorage(PersistenceAC ac) throws SQLException { 54 this. ac = ac; 55 } 56 57 62 public SQLStorage(PersistenceAC ac, Connection db) throws SQLException { 63 this. ac = ac; 64 setConnection(db); 65 } 66 67 protected String id; 68 public String getId() { 69 return id; 70 } 71 public void setId(String id) { 72 this.id = id; 73 } 74 75 public void close() {} 76 77 82 83 protected void setConnection(Connection db) throws SQLException { 84 this.db = db; 85 updateJacNames(); 86 } 87 88 91 protected abstract boolean hasTable(String name) throws Exception ; 92 93 96 protected void updateJacNames() throws SQLException { 97 ResultSet rs = executeQuery( 98 "SELECT roots.id, roots.name, classes.classid from roots,classes where "+ 99 "not roots.name like '%#%' and roots.id=classes.id"); 100 execute("BEGIN TRANSACTION"); 101 try { 102 while (rs.next()) { 103 String classname = Strings.getShortClassName(rs.getString("classid")).toLowerCase(); 104 String name = rs.getString("name"); 105 if (name.startsWith(classname) && 106 name.length()>classname.length() && 107 name.charAt(classname.length())!='#') 108 { 109 String newName = classname+"#"+name.substring(classname.length()); 110 executeUpdate("update roots set name='"+newName+"' where name='"+name+"'"); 111 } 112 } 113 execute("COMMIT"); 114 } catch (Exception e) { 115 execute("ROLLBACK"); 116 logger.error("Failed to update jac names"); 117 } 118 } 119 120 protected int executeUpdate(String query) throws SQLException { 121 try { 122 loggerSql.debug(query); 123 return db.createStatement().executeUpdate(query); 124 } catch (SQLException e) { 125 logger.error("executeUpdate query failed: "+query); 126 throw e; 127 } 128 } 129 130 protected ResultSet executeQuery(String query) throws SQLException { 131 try { 132 loggerSql.debug(query); 133 return db.createStatement().executeQuery(query); 134 } catch (SQLException e) { 135 logger.error("executeQuery query failed: "+query); 136 throw e; 137 } 138 } 139 140 protected boolean execute(String query) throws SQLException { 141 try { 142 loggerSql.debug(query); 143 return db.createStatement().execute(query); 144 } catch (SQLException e) { 145 logger.error("execute query failed: "+query); 146 throw e; 147 } 148 } 149 150 protected boolean executeSilent(String query) throws SQLException { 151 return db.createStatement().execute(query); 152 } 153 154 public void deleteObject(OID oid) throws Exception 155 { 156 logger.debug("deleteObject("+oid+")"); 157 executeUpdate("delete from objects where id="+oid.localId()); 158 executeUpdate("delete from roots where id="+oid.localId()); 159 } 161 162 public void setField(OID oid, FieldItem field, Object object) 163 throws Exception 164 { 165 logger.debug("setField("+oid+","+field.getName()+","+object+")"); 166 String value = ValueConverter.objectToString(this,object); 167 String fieldID = field.getName(); 168 String query = "insert into objects (id,fieldID,value) values "+ 169 "("+oid.localId()+",'"+fieldID+"','"+addSlashes(value)+"')"; 170 if (executeUpdate(query)==0) { 171 logger.error("setField failed : "+oid+","+fieldID+","+value); 172 } 173 } 174 175 public void updateField(OID oid, FieldItem field, Object object) 176 throws Exception 177 { 178 logger.debug("updateField("+oid+","+field+","+object+")"); 179 String fieldID = field.getName(); 180 String value = ValueConverter.objectToString(this,object); 181 String query = "update objects set value='"+addSlashes(value)+"' where "+ 182 "id="+oid.localId()+" and fieldID='"+fieldID+"'"; 183 if (executeUpdate(query)==0) { 184 setField(oid,field,object); 185 } 186 } 187 188 public Object getField(OID oid, FieldItem field) 189 throws Exception 190 { 191 logger.debug("getField("+oid+","+field.getName()+")"); 192 checkStorage(); 193 String fieldID = field.getName(); 194 ResultSet rs = executeQuery("select value from objects where id="+oid.localId()+ 195 " and fieldID='"+fieldID+"'"); 196 if (rs.next()) { 197 return ValueConverter.stringToObject(this,rs.getString("value")); 198 } else { 199 if (field.isPrimitive()) { 200 logger.warn("no such field in storage "+oid+","+fieldID); 201 } 202 return null; 203 } 204 } 205 206 public StorageField[] getFields(OID oid, ClassItem cl, FieldItem[] fields) 207 throws Exception 208 { 209 logger.debug("getFields "+oid+","+cl+","+Arrays.asList(fields)); 210 if (fields.length == 0) { 212 return new StorageField[0]; 213 } 214 String fieldlist = "("; 215 boolean first = true; 216 for (int i=0; i<fields.length; i++) { 217 if (!fields[i].isCalculated() && !fields[i].isTransient()) { 218 if (!first) 219 fieldlist += " or "; 220 fieldlist += "fieldID='"+fields[i].getName()+"'"; 221 first = false; 222 } 223 } 224 fieldlist += ")"; 225 226 StorageField fieldValues[] = new StorageField[fields.length]; 227 String query = "select * from objects where id="+oid.localId()+" and "+fieldlist; 228 ResultSet rs = executeQuery(query); 229 230 int i=0; 231 while (rs.next()) { 232 FieldItem field = cl.getField(rs.getString("fieldID")); 233 fieldValues[i] = new StorageField( 234 cl,field, 235 ValueConverter.stringToObject(this,rs.getString("value"))); 236 i++; 237 } 238 return fieldValues; 239 } 240 241 public void removeField(OID oid, FieldItem field, Object value) 242 throws Exception 243 { 244 logger.debug("removeField("+oid+","+field+","+value+")"); 245 String fieldID = field.getName(); 246 executeUpdate("delete from objects where id="+oid.localId()+ 247 " and fieldID='"+fieldID+"'"); 248 } 249 250 public Collection getRootObjects() throws Exception { 251 logger.debug("getRootObjects"); 252 String sql = "select id from roots"; 253 ResultSet rs = executeQuery(sql); 254 Vector result = new Vector (); 255 while (rs.next()) { 256 result.add(new LongOID(this,rs.getLong("value"))); 257 } 258 logger.debug("getRootObjects returns " + result); 259 return result; 260 } 261 262 264 public OID getCollectionID(OID oid, CollectionItem collection) 265 throws Exception 266 { 267 return getOID("select value from objects where "+ 268 "id="+oid.localId()+" and fieldID='"+collection.getName()+"'"); 269 } 270 271 public List getCollectionValues(OID oid, CollectionItem collection, 272 String table, String orderBy) 273 throws Exception 274 { 275 logger.debug("getCollectionValues("+oid+","+collection+")"); 276 String fieldID = collection.getName(); 277 278 String sql = "select "+table+".value from "+table+",objects where "+ 279 "objects.id="+oid.localId()+ 280 " and objects.fieldID='"+fieldID+"'"+ 281 " and objects.value="+table+".id"; 282 if (orderBy!=null) { 283 sql += " order by " + orderBy; 284 } 285 286 ResultSet rs = executeQuery(sql); 287 Vector result = new Vector (); 288 while (rs.next()) { 289 result.add(ValueConverter.stringToObject(this,rs.getString("value"))); 290 } 291 logger.debug("getCollectionValues returns " + result); 292 return result; 293 } 294 295 public boolean collectionContains(String table, OID cid, Object value) 296 throws Exception 297 { 298 ResultSet res = executeQuery( 299 "select id from "+table+" where "+ 300 "id="+cid.localId()+" and value='"+ 301 addSlashes(ValueConverter.objectToString(this,value))+"'"); 302 return res.next(); 303 } 304 305 307 public void clearList(OID cid) 308 throws Exception 309 { 310 logger.debug("clearList("+cid+")"); 311 executeUpdate("delete from lists where id="+cid.localId()); 312 } 313 314 public List getList(OID oid, CollectionItem collection) 315 throws Exception 316 { 317 return getList(getCollectionID(oid,collection)); 318 } 319 320 public List getList(OID cid) 321 throws Exception 322 { 323 logger.debug("getList("+cid+")"); 324 ResultSet rs = executeQuery("select value from lists "+ 325 "where id="+cid.localId()+" order by index"); 326 Vector result = new Vector (); 327 while (rs.next()) { 328 result.add( 329 ValueConverter.stringToObject(this,rs.getString("value"))); 330 } 331 logger.debug("getList returns " + result); 332 return result; 333 } 334 335 public long getListSize(OID cid) 336 throws Exception 337 { 338 return getLong("select count(*) from lists where id="+cid.localId()); 339 } 340 341 public boolean listContains(OID cid, Object value) 342 throws Exception 343 { 344 return collectionContains("lists",cid,value); 345 } 346 347 public Object getListItem(OID cid, long index) 348 throws Exception 349 { 350 ResultSet rs = 351 executeQuery("select value from lists where "+ 352 "id="+cid.localId()+" order by index limit 1 offset "+index); 353 if (rs.next()) { 354 return ValueConverter.stringToObject(this,rs.getString("value")); 355 } else { 356 return null; 357 } 358 } 359 360 public long getIndexInList(OID cid, Object value) 361 throws Exception 362 { 363 ResultSet rs = executeQuery( 364 "select min(index) as index from lists where "+ 365 "id="+cid.localId()+" and value='"+ 366 addSlashes(ValueConverter.objectToString(this,value))+"'"); 367 if (rs.next()) { 368 long index = rs.getLong(1); 369 return getLong("select count(*) from lists where id="+cid.localId()+ 370 " and index<="+index)-1; 371 } else { 372 return -1; 373 } 374 } 375 376 protected long getInternalIndexInList(OID cid, Object value) 377 throws Exception 378 { 379 ResultSet rs = executeQuery( 380 "select min(index) as index from lists where "+ 381 "id="+cid.localId()+" and value='"+ 382 addSlashes(ValueConverter.objectToString(this,value))+"'"); 383 if (rs.next()) { 384 long result = rs.getLong(1); 385 if (rs.wasNull()) 386 return -1; 387 else 388 return result; 389 } else { 390 return -1; 391 } 392 } 393 394 public long getLastIndexInList(OID cid, Object value) 395 throws Exception 396 { 397 ResultSet rs = executeQuery( 398 "select max(index) from lists where "+ 399 "id="+cid.localId()+" and value='"+ 400 addSlashes(ValueConverter.objectToString(this,value))+"'"); 401 if (rs.next()) { 402 long index = rs.getLong(1); 403 return getLong("select count(*) from lists where id="+cid.localId()+ 404 " and index<="+index)-1; 405 } else { 406 return -1; 407 } 408 } 409 410 public void addToList(OID cid, long position, Object value) 411 throws Exception 412 { 413 logger.debug("addToList("+cid+","+position+","+value+")"); 414 executeUpdate("update lists set index=index+1 where id="+cid.localId()+ 415 " and index>="+position); 416 executeUpdate( 417 "insert into lists (id,index,value) values "+ 418 "("+cid.localId()+","+position+",'"+ 419 addSlashes(ValueConverter.objectToString(this,value))+"')"); 420 } 421 422 public void addToList(OID cid, Object value) 423 throws Exception 424 { 425 logger.debug("addToList("+cid+","+value+")"); 426 long size = getListSize(cid); 427 String indexExpr; 428 if (size==0) 429 indexExpr = "0"; 430 else 431 indexExpr = "select max(index)+1 from lists where id="+cid.localId(); 432 executeUpdate( 433 "insert into lists (id,index,value) values "+ 434 "("+cid.localId()+",("+indexExpr+"),'"+ 435 addSlashes(ValueConverter.objectToString(this,value))+"')"); 436 } 437 438 public void setListItem(OID cid, long index, Object value) 439 throws Exception 440 { 441 logger.debug("setListItem("+cid+","+index+","+value+")"); 442 executeUpdate("update lists set value='"+ 443 addSlashes(ValueConverter.objectToString(this,value))+ 444 " where id="+cid.localId()+" and index="+index); 445 } 446 447 public void removeFromList(OID cid, long position) 448 throws Exception 449 { 450 logger.debug("removeFromList("+cid+","+position+")"); 451 ResultSet rs = executeQuery("select index from lists where "+ 453 "id="+cid.localId()+" order by index limit 1,"+position); 454 long index = rs.getLong("index"); 455 executeUpdate("delete from lists where "+"id="+cid.localId()+" and index="+index); 456 } 457 458 public void removeFromList(OID cid, Object value) 459 throws Exception 460 { 461 logger.debug("removeFromList("+cid+","+value+")"); 462 long index = getInternalIndexInList(cid,value); 463 executeUpdate("delete from lists where "+"id="+cid.localId()+" and index="+index); 464 } 465 466 468 public void clearSet(OID cid) 469 throws Exception 470 { 471 logger.debug("clearSet("+cid+")"); 472 executeUpdate("delete from sets where id="+cid.localId()); 473 } 474 475 public List getSet(OID oid, CollectionItem collection) throws Exception { 476 return getSet(getCollectionID(oid,collection)); 477 } 478 479 public List getSet(OID cid) throws Exception { 480 logger.debug("getSet("+cid+")"); 481 ResultSet rs = executeQuery("select value from sets "+ 482 "where id="+cid.localId()); 483 Vector result = new Vector (); 484 while (rs.next()) { 485 result.add( 486 ValueConverter.stringToObject(this,rs.getString("value"))); 487 } 488 logger.debug("getSet returns " + result); 489 return result; 490 } 491 492 public long getSetSize(OID cid) 493 throws Exception 494 { 495 return getLong("select count(*) from sets where id="+cid.localId()); 496 } 497 498 public boolean setContains(OID cid, Object value) 499 throws Exception 500 { 501 return collectionContains("sets",cid,value); 502 } 503 504 public boolean addToSet(OID cid, Object value) 505 throws Exception 506 { 507 logger.debug("addToSet("+cid+","+value+")"); 508 if (!collectionContains("sets",cid,value)) { 509 executeUpdate( 510 "insert into sets (id,value) values "+"("+cid.localId()+",'"+ 511 addSlashes(ValueConverter.objectToString(this,value))+"')"); 512 return true; 513 } else { 514 return false; 515 } 516 } 517 518 public boolean removeFromSet(OID cid, Object value) 519 throws Exception 520 { 521 logger.debug("removeFromSet("+cid+","+value+")"); 522 boolean result = collectionContains("set",cid,value); 523 if (result) 524 executeUpdate( 525 "delete from sets where "+ 526 "id="+cid.localId()+" and value='"+ 527 addSlashes(ValueConverter.objectToString(this,value))+"'"); 528 return result; 529 } 530 531 533 public void clearMap(OID cid) 534 throws Exception 535 { 536 logger.debug("clearMap("+cid+")"); 537 executeUpdate("delete from maps where id="+cid.localId()); 538 } 539 540 public Map getMap(OID oid, CollectionItem collection) 541 throws Exception 542 { 543 return getMap(getCollectionID(oid,collection)); 544 } 545 546 public Map getMap(OID cid) throws Exception 547 { 548 logger.debug("getMap("+cid+")"); 549 ResultSet rs = 550 executeQuery("select value,key from maps where id="+cid.localId()); 551 Map result = new HashMap (); 552 while (rs.next()) { 553 result.put( 554 ValueConverter.stringToObject(this,rs.getString("key")), 555 ValueConverter.stringToObject(this,rs.getString("value"))); 556 } 557 logger.debug("getMap returns " + result); 558 return result; 559 } 560 561 public long getMapSize(OID cid) 562 throws Exception 563 { 564 return getLong("select count(*) from maps where id="+cid.localId()); 565 } 566 567 public Object putInMap(OID cid, Object key, Object value) 568 throws Exception 569 { 570 logger.debug("putInMap("+cid+","+key+"->"+value+")"); 571 if (mapContainsKey(cid,key)) { 572 Object old = getFromMap(cid,key); 573 executeUpdate( 574 "update maps set "+ 575 "key='"+addSlashes(ValueConverter.objectToString(this,key))+"',"+ 576 "value='"+addSlashes(ValueConverter.objectToString(this,value))+"' "+ 577 "where id="+cid.localId()+ 578 " and key='"+addSlashes(ValueConverter.objectToString(this,key))+"'"); 579 return old; 580 } else { 581 executeUpdate( 582 "insert into maps (id,key,value) values "+ 583 "("+cid.localId()+",'"+ 584 addSlashes(ValueConverter.objectToString(this,key))+ 585 "','"+addSlashes(ValueConverter.objectToString(this,value))+"')"); 586 return null; 587 } 588 } 589 590 public Object getFromMap(OID cid, Object key) 591 throws Exception 592 { 593 logger.debug("getFromMap("+cid+","+key+")"); 594 ResultSet res = executeQuery( 595 "select value from maps where "+ 596 "id="+cid.localId()+" and key='"+ 597 addSlashes(ValueConverter.objectToString(this,key))+"'"); 598 if (res.next()) { 599 return ValueConverter.stringToObject(this,res.getString("value")); 600 } else { 601 return null; 602 } 603 } 604 605 public boolean mapContainsKey(OID cid, Object key) 606 throws Exception 607 { 608 logger.debug("mapContainsKey("+cid+","+key+")"); 609 ResultSet res = executeQuery( 610 "select value from maps where "+ 611 "id="+cid.localId()+" and key='"+ 612 addSlashes(ValueConverter.objectToString(this,key))+"'"); 613 return res.next(); 614 } 615 616 public boolean mapContainsValue(OID cid, Object value) 617 throws Exception 618 { 619 return collectionContains("maps",cid,value); 620 } 621 622 public Object removeFromMap(OID cid, Object key) 623 throws Exception 624 625 { 626 logger.debug("removeFromMap("+cid+","+key+")"); 627 if (!mapContainsKey(cid,key)) { 628 return null; 629 } else { 630 Object result = getFromMap(cid,key); 631 executeUpdate( 632 "delete from maps where "+ 633 "id="+cid.localId()+" and key='"+ 634 addSlashes(ValueConverter.objectToString(this,key))+"'"); 635 return result; 636 } 637 } 638 639 public abstract String newName(String className) throws Exception ; 640 641 public abstract Map getNameCounters() throws Exception ; 642 643 public abstract void updateNameCounters(Map counters) throws Exception ; 644 645 public OID getOIDFromName(String name) 646 throws Exception 647 { 648 ResultSet rs = executeQuery( 649 "select id from roots where name='"+name+"'"); 650 if (rs.next()) { 651 return new LongOID(this,rs.getLong("id")); 652 } else { 653 return null; 654 } 655 } 656 657 public String getNameFromOID(OID oid) throws Exception 658 { 659 ResultSet rs = executeQuery( 660 "select name from roots where id="+oid.localId()); 661 if (rs.next()) { 662 return rs.getString("name"); 663 } else { 664 return null; 665 } 666 } 667 668 public void bindOIDToName(OID oid, String name) throws Exception 669 { 670 logger.debug("bindOIDToName "+oid+" -> "+name); 671 executeUpdate("insert into roots (id,name) values ("+ 672 oid.localId()+",'"+name+"')"); 673 } 674 675 public void deleteName(String name) throws Exception 676 { 677 logger.debug("deleteName("+name+")"); 678 executeUpdate("delete from roots where name='"+name+"'"); 679 } 680 681 public String getClassID(OID oid) throws Exception 682 { 683 ResultSet rs = executeQuery("select classid from classes where id="+oid.localId()); 684 if (rs.next()) { 685 String classID = rs.getString("classid"); 686 logger.debug("getClassID("+oid+") -> "+classID); 687 return classID; 688 } else { 689 throw new NoSuchOIDError(oid); 690 } 691 } 692 693 public Collection getObjects(ClassItem cl) throws Exception 694 { 695 logger.debug("getObjects("+cl.getName()+")"); 696 Vector result = new Vector (); 697 getObjects(cl,result); 698 return result; 699 } 700 701 protected void getObjects(ClassItem cl, Vector objects) throws SQLException { 702 String query = "select id from classes"; 703 if (cl != null) { 704 query += " where classes.classid='"+cl.getName()+"'"; 705 } 706 707 ResultSet rs = executeQuery(query); 708 while (rs.next()) { 709 objects.add(new LongOID(this,rs.getLong("id"))); 710 } 711 712 Iterator i = cl.getChildren().iterator(); 713 while(i.hasNext()) { 714 ClassItem subclass = (ClassItem)i.next(); 715 getObjects(subclass,objects); 716 } 717 } 718 719 public void startTransaction() throws SQLException { 720 execute("BEGIN TRANSACTION"); 721 } 722 723 public void commit() throws SQLException { 724 execute("COMMIT"); 725 } 726 727 public void rollback() throws SQLException { 728 execute("ROLLBACK"); 729 } 730 731 735 protected void checkStorage() { 736 if (db==null) { 737 logger.error("connection is NULL"); 738 throw new InvalidStorageException("connection is NULL"); 739 } 740 } 741 742 747 public OID createObject(String className) throws Exception { 748 LongOID res = new LongOID(this,getNextVal("object_id")); 749 executeUpdate("insert into classes (id,classid) values ("+ 750 res.localId()+",'"+className+"')"); 751 return res; 752 } 753 754 757 public abstract long getNextVal(String sequence) throws Exception ; 758 759 public long getLong(String query) throws Exception { 760 ResultSet rs = executeQuery(query); 761 rs.next(); 762 return rs.getLong(1); 763 } 764 765 public int getInt(String query, int defaultValue) throws Exception { 766 ResultSet rs = executeQuery(query); 767 if (rs.next()) 768 return rs.getInt(1); 769 else 770 return defaultValue; 771 } 772 773 public OID getOID(String query) throws Exception { 774 return new LongOID(this,getLong(query)); 775 } 776 777 public static class InvalidStorageException extends RuntimeException { 778 public InvalidStorageException(String msg) { 779 super(msg); 780 } 781 } 782 783 784 public static String addSlashes(String str) { 785 StringBuffer res = new StringBuffer (str.length()); 786 for (int i=0; i<str.length();i++) { 787 if (str.charAt(i)=='\'' || str.charAt(i)=='\\') { 788 res.append('\\'); 789 } 790 res.append(str.charAt(i)); 791 } 792 return res.toString(); 793 } 794 795 PersistenceAC ac; 796 } 797 | Popular Tags |