1 package org.apache.ojb.broker.core; 2 3 17 18 import java.util.ArrayList ; 19 import java.util.Collection ; 20 import java.util.Iterator ; 21 import java.util.List ; 22 import java.sql.SQLException ; 23 24 import org.apache.commons.lang.builder.EqualsBuilder; 25 import org.apache.commons.lang.builder.HashCodeBuilder; 26 import org.apache.commons.lang.builder.ToStringBuilder; 27 import org.apache.commons.lang.ArrayUtils; 28 import org.apache.ojb.broker.MtoNImplementor; 29 import org.apache.ojb.broker.OJBRuntimeException; 30 import org.apache.ojb.broker.PersistenceBrokerException; 31 import org.apache.ojb.broker.PersistenceBrokerSQLException; 32 import org.apache.ojb.broker.accesslayer.ResultSetAndStatement; 33 import org.apache.ojb.broker.core.proxy.ProxyHelper; 34 import org.apache.ojb.broker.metadata.ClassDescriptor; 35 import org.apache.ojb.broker.metadata.CollectionDescriptor; 36 import org.apache.ojb.broker.metadata.DescriptorRepository; 37 import org.apache.ojb.broker.metadata.FieldDescriptor; 38 import org.apache.ojb.broker.metadata.JdbcType; 39 import org.apache.ojb.broker.query.Query; 40 import org.apache.ojb.broker.util.logging.Logger; 41 import org.apache.ojb.broker.util.logging.LoggerFactory; 42 43 53 public class MtoNBroker 54 { 55 private Logger log = LoggerFactory.getLogger(MtoNBroker.class); 56 57 private PersistenceBrokerImpl pb; 58 63 private List tempObjects = new ArrayList (); 64 65 public MtoNBroker(final PersistenceBrokerImpl broker) 66 { 67 this.pb = broker; 68 } 69 70 public void reset() 71 { 72 tempObjects.clear(); 73 } 74 75 83 public void storeMtoNImplementor(CollectionDescriptor cod, Object realObject, Object otherObj, Collection mnKeys) 84 { 85 ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(realObject.getClass()); 86 ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, realObject); 87 String [] pkColumns = cod.getFksToThisClass(); 88 89 ClassDescriptor otherCld = pb.getDescriptorRepository().getDescriptorFor(ProxyHelper.getRealClass(otherObj)); 90 ValueContainer[] otherPkValues = pb.serviceBrokerHelper().getKeyValues(otherCld, otherObj); 91 92 String [] otherPkColumns = cod.getFksToItemClass(); 93 String table = cod.getIndirectionTable(); 94 MtoNBroker.Key key = new MtoNBroker.Key(otherPkValues); 95 96 if(mnKeys.contains(key)) 97 { 98 return; 99 } 100 101 105 for(int i = 0; i < otherPkColumns.length; i++) 106 { 107 int index = ArrayUtils.indexOf(pkColumns, otherPkColumns[i]); 108 if(index != -1) 109 { 110 pkColumns = (String []) ArrayUtils.remove(pkColumns, index); 112 pkValues = (ValueContainer[]) ArrayUtils.remove(pkValues, index); 114 } 115 } 116 117 String [] cols = mergeColumns(pkColumns, otherPkColumns); 118 String insertStmt = pb.serviceSqlGenerator().getInsertMNStatement(table, pkColumns, otherPkColumns); 119 ValueContainer[] values = mergeContainer(pkValues, otherPkValues); 120 GenericObject gObj = new GenericObject(table, cols, values); 121 if(! tempObjects.contains(gObj)) 122 { 123 pb.serviceJdbcAccess().executeUpdateSQL(insertStmt, cld, pkValues, otherPkValues); 124 tempObjects.add(gObj); 125 } 126 } 127 128 135 public List getMtoNImplementor(CollectionDescriptor cod, Object obj) 136 { 137 ResultSetAndStatement rs = null; 138 ArrayList result = new ArrayList (); 139 ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(obj.getClass()); 140 ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, obj); 141 String [] pkColumns = cod.getFksToThisClass(); 142 String [] fkColumns = cod.getFksToItemClass(); 143 String table = cod.getIndirectionTable(); 144 145 String selectStmt = pb.serviceSqlGenerator().getSelectMNStatement(table, fkColumns, pkColumns); 146 147 ClassDescriptor itemCLD = pb.getDescriptorRepository().getDescriptorFor(cod.getItemClass()); 148 Collection extents = pb.getDescriptorRepository().getAllConcreteSubclassDescriptors(itemCLD); 149 if(extents.size() > 0) 150 { 151 itemCLD = (ClassDescriptor) extents.iterator().next(); 152 } 153 FieldDescriptor[] itemClassPKFields = itemCLD.getPkFields(); 154 if(itemClassPKFields.length != fkColumns.length) 155 { 156 throw new PersistenceBrokerException("All pk fields of the element-class need to" + 157 " be declared in the indirection table. Element class is " 158 + itemCLD.getClassNameOfObject() + " with " + itemClassPKFields.length + " pk-fields." + 159 " Declared 'fk-pointing-to-element-class' elements in collection-descriptor are" 160 + fkColumns.length); 161 } 162 try 163 { 164 rs = pb.serviceJdbcAccess().executeSQL(selectStmt, cld, pkValues, Query.NOT_SCROLLABLE); 165 while(rs.m_rs.next()) 166 { 167 ValueContainer[] row = new ValueContainer[fkColumns.length]; 168 for(int i = 0; i < row.length; i++) 169 { 170 row[i] = new ValueContainer(rs.m_rs.getObject(i + 1), itemClassPKFields[i].getJdbcType()); 171 } 172 result.add(new MtoNBroker.Key(row)); 173 } 174 } 175 catch(PersistenceBrokerException e) 176 { 177 throw e; 178 } 179 catch(SQLException e) 180 { 181 throw new PersistenceBrokerSQLException(e); 182 } 183 finally 184 { 185 if(rs != null) rs.close(); 186 } 187 return result; 188 } 189 190 196 public void deleteMtoNImplementor(CollectionDescriptor cod, Object obj) 197 { 198 ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(obj.getClass()); 199 ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, obj); 200 String [] pkColumns = cod.getFksToThisClass(); 201 String table = cod.getIndirectionTable(); 202 String deleteStmt = pb.serviceSqlGenerator().getDeleteMNStatement(table, pkColumns, null); 203 pb.serviceJdbcAccess().executeUpdateSQL(deleteStmt, cld, pkValues, null); 204 } 205 206 214 public void deleteMtoNImplementor(CollectionDescriptor cod, Object obj, Iterator collectionIterator, Collection mnKeys) 215 { 216 if(mnKeys.isEmpty() || collectionIterator == null) 217 { 218 return; 219 } 220 List workList = new ArrayList (mnKeys); 221 MtoNBroker.Key relatedObjKeys; 222 ClassDescriptor relatedCld = pb.getDescriptorRepository().getDescriptorFor(cod.getItemClass()); 223 Object relatedObj; 224 225 while(collectionIterator.hasNext()) 227 { 228 relatedObj = collectionIterator.next(); 229 relatedObjKeys = new MtoNBroker.Key(pb.serviceBrokerHelper().getKeyValues(relatedCld, relatedObj, true)); 230 workList.remove(relatedObjKeys); 231 } 232 233 ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(obj.getClass()); 235 ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, obj); 236 237 String [] pkColumns = cod.getFksToThisClass(); 238 String [] fkColumns = cod.getFksToItemClass(); 239 String table = cod.getIndirectionTable(); 240 String deleteStmt; 241 242 ValueContainer[] fkValues; 243 Iterator iter = workList.iterator(); 244 while(iter.hasNext()) 245 { 246 fkValues = ((MtoNBroker.Key) iter.next()).m_containers; 247 deleteStmt = pb.serviceSqlGenerator().getDeleteMNStatement(table, pkColumns, fkColumns); 248 pb.serviceJdbcAccess().executeUpdateSQL(deleteStmt, cld, pkValues, fkValues); 249 } 250 } 251 252 255 public void storeMtoNImplementor(MtoNImplementor m2n) 256 { 257 if(log.isDebugEnabled()) log.debug("Storing M2N implementor [" + m2n + "]"); 258 insertOrDeleteMtoNImplementor(m2n, true); 259 } 260 261 264 public void deleteMtoNImplementor(MtoNImplementor m2n) 265 { 266 if(log.isDebugEnabled()) log.debug("Deleting M2N implementor [" + m2n + "]"); 267 insertOrDeleteMtoNImplementor(m2n, false); 268 } 269 270 271 274 private void insertOrDeleteMtoNImplementor(MtoNImplementor m2nImpl, boolean insert) 275 throws PersistenceBrokerException 276 { 277 DescriptorRepository dr = pb.getDescriptorRepository(); 279 280 Object leftObject = m2nImpl.getLeftObject(); 281 Class leftClass = m2nImpl.getLeftClass(); 282 Object rightObject = m2nImpl.getRightObject(); 283 Class rightClass = m2nImpl.getRightClass(); 284 285 ClassDescriptor leftCld = dr.getDescriptorFor(leftClass); 289 ClassDescriptor rightCld = dr.getDescriptorFor(rightClass); 290 CollectionDescriptor wanted = m2nImpl.getLeftDescriptor(); 292 293 if(leftObject == null || rightObject == null) 294 { 295 log.error("Can't handle MtoNImplementor in correct way, found a 'null' object"); 298 } 299 else 300 { 301 ValueContainer[] leftPkValues = pb.serviceBrokerHelper().getKeyValues(leftCld, leftObject); 303 ValueContainer[] rightPkValues = pb.serviceBrokerHelper().getKeyValues(rightCld, rightObject); 304 String [] pkLeftColumns = wanted.getFksToThisClass(); 305 String [] pkRightColumns = wanted.getFksToItemClass(); 306 String table = wanted.getIndirectionTable(); 307 if(table == null) throw new PersistenceBrokerException("Can't remove MtoN implementor without an indirection table"); 308 309 String stmt; 310 String [] cols = mergeColumns(pkLeftColumns, pkRightColumns); 311 ValueContainer[] values = mergeContainer(leftPkValues, rightPkValues); 312 if(insert) 313 { 314 stmt = pb.serviceSqlGenerator().getInsertMNStatement(table, pkLeftColumns, pkRightColumns); 315 GenericObject gObj = new GenericObject(table, cols, values); 316 if(!tempObjects.contains(gObj)) 317 { 318 pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld, leftPkValues, rightPkValues); 319 tempObjects.add(gObj); 320 } 321 } 322 else 323 { 324 stmt = pb.serviceSqlGenerator().getDeleteMNStatement(table, pkLeftColumns, pkRightColumns); 325 pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld, leftPkValues, rightPkValues); 326 } 327 } 328 } 329 330 private String [] mergeColumns(String [] first, String [] second) 331 { 332 String [] cols = new String [first.length + second.length]; 333 System.arraycopy(first, 0, cols, 0, first.length); 334 System.arraycopy(second, 0, cols, first.length, second.length); 335 return cols; 336 } 337 338 private ValueContainer[] mergeContainer(ValueContainer[] first, ValueContainer[] second) 339 { 340 ValueContainer[] values = new ValueContainer[first.length + second.length]; 341 System.arraycopy(first, 0, values, 0, first.length); 342 System.arraycopy(second, 0, values, first.length, second.length); 343 return values; 344 } 345 346 347 348 352 355 private static final class Key 356 { 357 final ValueContainer[] m_containers; 358 359 Key(final ValueContainer[] containers) 360 { 361 m_containers = new ValueContainer[containers.length]; 362 363 for(int i = 0; i < containers.length; i++) 364 { 365 Object value = containers[i].getValue(); 366 JdbcType type = containers[i].getJdbcType(); 367 368 if(value instanceof Number ) 375 { 376 value = new Long (((Number ) value).longValue()); 377 } 378 379 m_containers[i] = new ValueContainer(value, type); 380 } 381 } 382 383 public boolean equals(Object other) 384 { 385 if(other == this) 386 { 387 return true; 388 } 389 if(!(other instanceof Key)) 390 { 391 return false; 392 } 393 394 Key otherKey = (Key) other; 395 EqualsBuilder eb = new EqualsBuilder(); 396 397 eb.append(m_containers, otherKey.m_containers); 398 return eb.isEquals(); 399 } 400 401 public int hashCode() 402 { 403 HashCodeBuilder hb = new HashCodeBuilder(); 404 hb.append(m_containers); 405 406 return hb.toHashCode(); 407 } 408 } 409 410 411 412 private static final class GenericObject 416 { 417 private String tablename; 418 private String [] columnNames; 419 private ValueContainer[] values; 420 421 public GenericObject(String tablename, String [] columnNames, ValueContainer[] values) 422 { 423 this.tablename = tablename; 424 this.columnNames = columnNames; 425 this.values = values; 426 if(values != null && columnNames.length != values.length) 427 { 428 throw new OJBRuntimeException("Column name array and value array have NOT same length"); 429 } 430 } 431 432 public boolean equals(Object obj) 433 { 434 if(this == obj) 435 { 436 return true; 437 } 438 boolean result = false; 439 if(obj instanceof GenericObject) 440 { 441 GenericObject other = (GenericObject) obj; 442 result = (tablename.equalsIgnoreCase(other.tablename) 443 && (columnNames != null) 444 && (other.columnNames != null) 445 && (columnNames.length == other.columnNames.length)); 446 447 if(result) 448 { 449 for (int i = 0; i < columnNames.length; i++) 450 { 451 int otherIndex = other.indexForColumn(columnNames[i]); 452 if(otherIndex < 0) 453 { 454 result = false; 455 break; 456 } 457 result = values[i].equals(other.values[otherIndex]); 458 if(!result) break; 459 } 460 } 461 } 462 return result; 463 } 464 465 int indexForColumn(String name) 466 { 467 int result = -1; 468 for (int i = 0; i < columnNames.length; i++) 469 { 470 if(columnNames[i].equals(name)) 471 { 472 result = i; 473 break; 474 } 475 } 476 return result; 477 } 478 479 public int hashCode() 480 { 481 return super.hashCode(); 482 } 483 484 public ValueContainer getValueFor(String columnName) 485 { 486 try 487 { 488 return values[indexForColumn(columnName)]; 489 } 490 catch(Exception e) 491 { 492 throw new OJBRuntimeException("Can't find value for column " + columnName 493 + (indexForColumn(columnName) < 0 ? ". Column name was not found" : ""), e); 494 } 495 } 496 497 public String getTablename() 498 { 499 return tablename; 500 } 501 502 public String [] getColumnNames() 503 { 504 return columnNames; 505 } 506 507 public ValueContainer[] getValues() 508 { 509 return values; 510 } 511 512 public void setValues(ValueContainer[] values) 513 { 514 this.values = values; 515 } 516 517 public String toString() 518 { 519 return new ToStringBuilder(this) 520 .append("tableName", tablename) 521 .append("columnNames", columnNames) 522 .append("values", values) 523 .toString(); 524 } 525 } 526 } 527 | Popular Tags |