1 20 21 22 package org.snmp4j.agent.mo; 23 24 import java.io.*; 25 import java.util.*; 26 27 import org.snmp4j.*; 28 import org.snmp4j.agent.*; 29 import org.snmp4j.agent.io.*; 30 import org.snmp4j.agent.request.*; 31 import org.snmp4j.agent.util.*; 32 import org.snmp4j.log.*; 33 import org.snmp4j.mp.*; 34 import org.snmp4j.smi.*; 35 36 50 public class DefaultMOTable implements MOTable, MOScope, 51 SerializableManagedObject { 52 53 private static LogAdapter logger = 54 LogFactory.getLogger(DefaultMOTable.class); 55 56 private OID oid; 57 private MOTableIndex indexDef; 58 private MOColumn[] columns; 59 protected MOTableModel model; 60 61 private boolean isVolatile; 62 63 protected WeakHashMap newRows; 64 protected WeakHashMap pendingChanges; 65 66 private transient Vector moChangeListeners; 67 private transient Vector moTableRowListeners; 68 69 private transient WeakHashMap walkCache; 70 71 private static Comparator columnComparator = new Comparator() { 72 73 public int compare(Object o1, Object o2) { 74 int id1 = (o1 instanceof MOColumn) ? 75 ((MOColumn)o1).getColumnID() : ((Integer )o1).intValue(); 76 int id2 = (o2 instanceof MOColumn) ? 77 ((MOColumn)o2).getColumnID() : ((Integer )o2).intValue(); 78 return id1 - id2; 79 } 80 }; 81 82 public DefaultMOTable(OID oid, MOTableIndex indexDef, MOColumn[] columns) { 83 this(oid, indexDef, columns, new DefaultMOMutableTableModel()); 84 } 85 86 public DefaultMOTable(OID oid, MOTableIndex indexDef, 87 MOColumn[] columns, MOTableModel model) { 88 this.oid = oid; 89 this.indexDef = indexDef; 90 this.columns = columns; 91 this.model = model; 92 registerColumns(); 93 } 94 95 private void registerColumns() { 96 for (int i=0; i<columns.length; i++) { 97 columns[i].setTable(this); 98 } 99 } 100 101 public MOTableCellInfo getCellInfo(OID oid) { 102 return new CellInfo(oid); 103 } 104 105 public int getColumnIndex(int id) { 106 int col = Arrays.binarySearch(columns, new Integer (id), columnComparator); 107 return col; 108 } 109 110 public MOColumn getColumn(int index) { 111 return columns[index]; 112 } 113 114 public int getColumnCount() { 115 return columns.length; 116 } 117 118 133 public MOTableRow createRow(OID index, Variable[] initialValues) { 134 if (model instanceof MOMutableTableModel) { 135 Variable[] values = initialValues; 136 if (values.length < getColumnCount()) { 137 values = getDefaultValues(); 138 System.arraycopy(initialValues, 0, values, 0, initialValues.length); 139 } 140 MOTableRow row = 141 ((MOMutableTableModel)model).createRow(index, values); 142 MOTableRowEvent rowEvent = 143 new MOTableRowEvent(this, this, row, MOTableRowEvent.CREATE, true); 144 fireRowChanged(rowEvent); 145 if (rowEvent.getVetoStatus() == SnmpConstants.SNMP_ERROR_SUCCESS) { 146 return row; 147 } 148 } 149 return null; 150 } 151 152 public MOTableRow createRow(OID index) { 153 return createRow(index, getDefaultValues()); 154 } 155 156 168 public boolean addRow(MOTableRow row) { 169 if (model instanceof MOMutableTableModel) { 170 MOTableRowEvent rowEvent = 171 new MOTableRowEvent(this, this, row, MOTableRowEvent.ADD, true); 172 fireRowChanged(rowEvent); 173 if (rowEvent.getVetoStatus() == SnmpConstants.SNMP_ERROR_SUCCESS) { 174 ((MOMutableTableModel)model).addRow(row); 175 } 176 return true; 177 } 178 return false; 179 } 180 181 public MOTableRow removeRow(OID index) { 182 if (model instanceof MOMutableTableModel) { 183 MOTableRow row = model.getRow(index); 184 if (row == null) { 185 return null; 186 } 187 MOTableRowEvent rowEvent = 188 new MOTableRowEvent(this, this, row, MOTableRowEvent.DELETE, true); 189 fireRowChanged(rowEvent); 190 if (rowEvent.getVetoStatus() == SnmpConstants.SNMP_ERROR_SUCCESS) { 191 return ((MOMutableTableModel)model).removeRow(index); 192 } 193 } 194 return null; 195 } 196 197 206 public int removeAll() { 207 int count = 0; 208 if (model instanceof MOMutableTableModel) { 209 while (model.getRowCount() > 0) { 210 MOTableRow row = model.firstRow(); 211 if (row != null) { 212 MOTableRowEvent rowEvent = 213 new MOTableRowEvent(this, this, row, MOTableRowEvent.DELETE, true); 214 fireRowChanged(rowEvent); 215 if (rowEvent.getVetoStatus() == SnmpConstants.SNMP_ERROR_SUCCESS) { 216 ((MOMutableTableModel) model).removeRow(row.getIndex()); 217 } 218 count++; 219 } 220 } 221 } 222 else { 223 count = -1; 224 } 225 return count; 226 } 227 228 public void commit(SubRequest request) { 229 OID cellOID = request.getVariableBinding().getOid(); 230 MOTableCellInfo cell = getCellInfo(cellOID); 231 MOMutableColumn col = (MOMutableColumn) getColumn(cell.getColumn()); 232 if (logger.isDebugEnabled()) { 233 logger.debug("Committing sub-request ("+ 234 request.getVariableBinding()+") for column: "+col); 235 } 236 synchronized (model) { 238 MOMutableTableRow row; 239 if (hasNewRows(request.getRequest())) { 240 row = (MOMutableTableRow) 241 getNewRows(request.getRequest()).get(cell.getIndex()); 242 addRow(row); 243 } 244 else { 245 row = (MOMutableTableRow) model.getRow(cell.getIndex()); 246 } 247 Variable oldValue = null; 248 if (moChangeListeners != null) { 249 oldValue = row.getValue(cell.getColumn()); 250 MOChangeEvent changeEvent = 251 new MOChangeEvent(this, new CellProxy(cell), 252 cell.getCellOID(), 253 oldValue, 254 request.getVariableBinding().getVariable(), 255 false); 256 fireBeforeMOChange(changeEvent); 257 } 258 ChangeSet changeSet = getPendingChangeSet(request, cell.getIndex()); 259 col.commit(request, row, changeSet, cell.getColumn()); 261 if (moChangeListeners != null) { 262 MOChangeEvent changeEvent = 263 new MOChangeEvent(this, new CellProxy(cell), 264 cell.getCellOID(), 265 oldValue, 266 request.getVariableBinding().getVariable(), 267 false); 268 fireAfterMOChange(changeEvent); 269 } 270 if (isChangeSetComplete(request, cell.getIndex(), cell.getColumn())) { 271 if (row instanceof MOMutableRow2PC) { 272 ((MOMutableRow2PC) row).commitRow(request, changeSet); 273 } 274 if (moTableRowListeners != null) { 275 MOTableRowEvent rowEvent = 276 new MOTableRowEvent(this, this, row, MOTableRowEvent.UPDATED); 277 fireRowChanged(rowEvent); 278 } 279 } 280 } 281 } 282 283 public final OID getIndexPart(OID anyOID) { 284 int offset = oid.size()+1; 285 if ((anyOID.size() <= offset) || (!anyOID.startsWith(oid))) { 286 return null; 287 } 288 return new OID(anyOID.getValue(), offset, anyOID.size() - offset); 289 } 290 291 public OID getCellOID(OID index, int col) { 292 OID retval = new OID(oid); 293 retval.append(columns[col].getColumnID()); 294 retval.append(index); 295 return retval; 296 } 297 298 private MOTableCellInfo getNextCell(int col, 299 OID indexLowerBound, 300 boolean isLowerBoundIncluded) { 301 for (int i=col; i<columns.length; i++) { 302 Iterator it = model.tailIterator(indexLowerBound); 303 if (!it.hasNext()) { 304 if (indexLowerBound == null) { 305 return null; 306 } 307 indexLowerBound = null; 308 isLowerBoundIncluded = true; 309 continue; 310 } 311 else { 312 if ((indexLowerBound != null) && (!isLowerBoundIncluded)) { 313 MOTableRow row = (MOTableRow) it.next(); 314 if (row.getIndex().compareTo(indexLowerBound) > 0) { 315 return new CellInfo(row.getIndex(), i, columns[i].getColumnID(), 317 row); 318 } 319 } 320 indexLowerBound = null; 321 isLowerBoundIncluded = true; 322 if (it.hasNext()) { 323 MOTableRow row = (MOTableRow) it.next(); 324 if (row == null) { 325 continue; 326 } 327 return new CellInfo(row.getIndex(), i, columns[i].getColumnID(), row); 328 } 329 } 330 } 331 return null; 332 } 333 334 public OID find(MOScope range) { 335 MOTableCellInfo cellInfo = findCell(range, null); 336 if (cellInfo != null) { 337 return cellInfo.getCellOID(); 338 } 339 return null; 340 } 341 342 protected MOTableCellInfo findCell(MOScope range, SubRequest request) { 343 synchronized (model) { 344 if (model.getRowCount() == 0) { 346 return null; 347 } 348 MOTableCellInfo cellInfo = getCellInfo(range.getLowerBound()); 349 int col = cellInfo.getColumn(); 350 boolean exactMatch = true; 351 if (col < 0) { 352 col = (-col) - 1; 353 exactMatch = false; 354 } 355 if (col >= columns.length) { 356 return null; 357 } 358 boolean lowerIncluded = (!exactMatch) || range.isLowerIncluded(); 359 RowCacheEntry rowEntry = null; 360 if (request != null) { 361 rowEntry = getWalkCacheEntry(request, cellInfo, lowerIncluded); 362 } 363 MOTableCellInfo next; 364 if (rowEntry != null) { 365 next = new CellInfo(rowEntry.row.getIndex(), 366 col, cellInfo.getColumnID(), rowEntry.row); 367 } 368 else { 369 next = getNextCell(col, cellInfo.getIndex(), lowerIncluded); 370 if ((request != null) && (next != null) && (next.getColumn() == col)) { 371 addWalkCacheEntry(request, cellInfo.getIndex(), lowerIncluded, 372 ((CellInfo)next).row); 373 } 374 } 375 if (next != null) { 376 OID cellOID = next.getCellOID(); 377 if (range.isCovered(new OIDScope(cellOID))) { 378 return next; 379 } 380 } 381 } 382 return null; 383 } 384 385 private void addWalkCacheEntry(SubRequest request, 386 OID lowerBound, 387 boolean lowerIncluded, 388 MOTableRow row) { 389 if (walkCache == null) { 390 walkCache = new WeakHashMap(4); 391 } 392 walkCache.put(request.getRequest(), 393 new RowCacheEntry(row, lowerBound, lowerIncluded)); 394 } 395 396 private RowCacheEntry getWalkCacheEntry(SubRequest request, 397 MOTableCellInfo cellInfo, 398 boolean lowerIncluded) { 399 if (walkCache != null) { 400 RowCacheEntry entry = (RowCacheEntry) walkCache.get(request.getRequest()); 401 if (entry == null) { 402 return null; 403 } 404 if (((entry.searchLowerBound == null) && (cellInfo.getIndex() == null)) || 405 ((entry.searchLowerBound != null) && 406 (entry.searchLowerBound.equals(cellInfo.getIndex())) && 407 (lowerIncluded == entry.searchLowerBoundIncluded))) { 408 return entry; 409 } 410 } 411 return null; 412 } 413 414 public MOScope getScope() { 415 return this; 416 } 417 418 public Variable getValue(OID cellOID) { 419 MOTableCellInfo cell = getCellInfo(cellOID); 420 if ((cell.getIndex() != null) && 421 (cell.getColumn() >= 0) && (cell.getColumn() < columns.length)) { 422 return getValue(cell.getIndex(), cell.getColumn()); 423 } 424 return null; 425 } 426 427 public Variable getValue(OID index, int col) { 428 MOTableRow row = model.getRow(index); 429 return getValue(row, col); 430 } 431 432 protected Variable getValue(MOTableRow row, int col) { 433 if (row != null) { 434 return columns[col].getValue(row, col); 435 } 436 return null; 437 } 438 439 public void get(SubRequest request) { 440 OID cellOID = request.getVariableBinding().getOid(); 441 MOTableCellInfo cell = getCellInfo(cellOID); 442 if ((cell.getIndex() != null) && 443 (cell.getColumn() >= 0) && (cell.getColumn() < columns.length)) { 444 MOColumn col = getColumn(cell.getColumn()); 445 MOTableRow row = model.getRow(cell.getIndex()); 446 if (row == null) { 447 request.getVariableBinding().setVariable(Null.noSuchInstance); 448 } 449 else if (col != null) { 450 col.get(request, row, cell.getColumn()); 451 } 452 else { 453 request.getStatus().setErrorStatus(PDU.noAccess); 454 } 455 } 456 else { 457 if (cell.getColumn() >= 0) { 458 request.getVariableBinding().setVariable(Null.noSuchInstance); 459 } 460 else { 461 request.getVariableBinding().setVariable(Null.noSuchObject); 462 } 463 } 464 request.completed(); 465 } 466 467 public boolean next(SubRequest request) { 468 DefaultMOScope scope = new DefaultMOScope(request.getScope()); 469 MOTableCellInfo nextCell; 470 while ((nextCell = findCell(scope, request)) != null) { 471 if (columns[nextCell.getColumn()].getAccess().isAccessibleForRead()) { 472 Variable value; 473 if ((nextCell instanceof CellInfo) && 475 (((CellInfo)nextCell).getRow() != null)) { 476 value = getValue(((CellInfo)nextCell).getRow(), nextCell.getColumn()); 477 } 478 else { 479 value = getValue(nextCell.getIndex(), nextCell.getColumn()); 480 } 481 if (value == null) { 482 scope.setLowerBound(nextCell.getCellOID()); 483 scope.setLowerIncluded(false); 484 } 485 else { 486 request.getVariableBinding().setOid(nextCell.getCellOID()); 487 request.getVariableBinding().setVariable(value); 488 request.completed(); 489 return true; 490 } 491 } 492 else { 493 if (nextCell.getColumn()+1 < getColumnCount()) { 494 OID nextColOID = new OID(getOID()); 495 nextColOID.append(columns[nextCell.getColumn()+1].getColumnID()); 496 scope.setLowerBound(nextColOID); 497 scope.setLowerIncluded(false); 498 } 499 else { 500 return false; 501 } 502 } 503 } 504 return false; 505 } 506 507 513 public void prepare(SubRequest request) { 514 OID cellOID = request.getVariableBinding().getOid(); 515 MOTableCellInfo cell = getCellInfo(cellOID); 516 if (cell.getIndex() == null) { 517 request.getStatus().setErrorStatus(PDU.inconsistentName); 518 return; 519 } 520 if ((cell.getColumn() >= 0) && (cell.getColumn() < columns.length)) { 521 MOColumn col = getColumn(cell.getColumn()); 522 if (logger.isDebugEnabled()) { 523 logger.debug("Preparing sub-request ("+request.getVariableBinding()+")"+ 524 " for column: "+col); 525 } 526 if ((col instanceof MOMutableColumn) && 527 (col.getAccess().isAccessibleForWrite())) { 528 MOMutableColumn mcol = (MOMutableColumn)col; 529 if (getIndexDef().isValidIndex(cell.getIndex())) { 531 MOTableRow row = model.getRow(cell.getIndex()); 532 if (row == null) { 533 row = (MOTableRow) 535 getNewRows(request.getRequest()).get(cell.getIndex()); 536 } 537 if (row != null) { 538 prepare(request, cell, mcol, row, false); 539 request.completed(); 540 return; 541 } 542 else if (model instanceof MOMutableTableModel) { 543 if (logger.isDebugEnabled()) { 544 logger.debug("Trying to create new row '"+cell.getIndex()+"'"); 545 } 546 MOMutableTableModel mmodel = (MOMutableTableModel)model; 547 try { 549 row = createRow(request, cell, mmodel); 550 if (row == null) { 551 request.getStatus().setErrorStatus(PDU.noCreation); 552 } 553 else { 554 prepare(request, cell, mcol, row, true); 555 request.completed(); 556 } 557 } 558 catch (UnsupportedOperationException ex) { 559 request.getStatus().setErrorStatus(PDU.noCreation); 560 } 561 } 562 else { 563 request.getStatus().setErrorStatus(PDU.noCreation); 564 } 565 } 566 else { 567 if (logger.isDebugEnabled()) { 569 logger.debug("Invalid index '"+cell.getIndex()+ 570 "' for row creation in table "+getID()); 571 } 572 request.getStatus().setErrorStatus(PDU.noCreation); 573 } 574 } 575 else { 576 request.getStatus().setErrorStatus(PDU.notWritable); 578 } 579 } 580 else { 581 request.getStatus().setErrorStatus(PDU.noCreation); 582 } 583 } 584 585 private MOTableRow createRow(SubRequest request, MOTableCellInfo cell, 586 MOMutableTableModel mmodel) 587 throws UnsupportedOperationException 588 { 589 MOColumn col = getColumn(cell.getColumn()); 590 if (!col.getAccess().isAccessibleForCreate()) { 591 return null; 593 } 594 Variable[] initialValues = new Variable[getColumnCount()]; 595 getChangesFromRequest(cell.getIndex(), null, request, 596 initialValues, true, true); 597 MOTableRow row = mmodel.createRow(cell.getIndex(), initialValues); 598 getNewRows(request.getRequest()).put(row.getIndex(), row); 599 return row; 600 } 601 602 private void prepare(SubRequest request, MOTableCellInfo cell, 603 MOMutableColumn mcol, MOTableRow row, boolean creation) { 604 if (moChangeListeners != null) { 605 MOChangeEvent changeEvent = 606 new MOChangeEvent(this, new CellProxy(cell), 607 cell.getCellOID(), 608 (creation) ? null : row.getValue(cell.getColumn()), 609 request.getVariableBinding().getVariable(), 610 true); 611 fireBeforePrepareMOChange(changeEvent); 612 if (changeEvent.getDenyReason() != PDU.noError) { 613 request.getStatus().setErrorStatus(changeEvent.getDenyReason()); 614 } 615 } 616 ChangeSet changeSet = getPendingChangeSet(request, cell.getIndex()); 617 if (changeSet == null) { 618 changeSet = addPendingChanges(request, row, creation); 619 } 620 if ((moTableRowListeners != null) && (!request.hasError())) { 621 if (isChangeSetComplete(request, row.getIndex(), cell.getColumn())) { 622 MOTableRowEvent rowEvent = 623 new MOTableRowEvent(this, this, row, changeSet, (creation) ? 624 MOTableRowEvent.CREATE :MOTableRowEvent.CHANGE, 625 true); 626 fireRowChanged(rowEvent); 627 if (rowEvent.getVetoStatus() != PDU.noError) { 628 if (rowEvent.getVetoColumn() >= 0) { 629 int colID = columns[rowEvent.getVetoColumn()].getColumnID(); 630 OID prefix = new OID(getOID()); 631 prefix.append(colID); 632 SubRequest r = request.getRequest().find(prefix); 633 if (r != null) { 634 r.getStatus().setErrorStatus(rowEvent.getVetoStatus()); 635 } 636 else { 637 request.getRequest().setErrorStatus(rowEvent.getVetoStatus()); 638 } 639 } 640 else { 641 request.getRequest().setErrorStatus(rowEvent.getVetoStatus()); 642 } 643 } 644 } 645 } 646 if (request.getStatus().getErrorStatus() == PDU.noError) { 647 mcol.prepare(request, row, changeSet, cell.getColumn()); 648 MOChangeEvent changeEvent = 649 new MOChangeEvent(this, new CellProxy(cell), 650 cell.getCellOID(), 651 row.getValue(cell.getColumn()), 652 request.getVariableBinding().getVariable(), 653 true); 654 fireAfterPrepareMOChange(changeEvent); 655 if (changeEvent.getDenyReason() != PDU.noError) { 656 request.getStatus().setErrorStatus(changeEvent.getDenyReason()); 657 } 658 else { 659 if ((row instanceof MOMutableRow2PC) && 660 (isChangeSetComplete(request, row.getIndex(), cell.getColumn()))) { 661 ((MOMutableRow2PC)row).prepareRow(request, changeSet); 662 } 663 } 664 } 665 } 666 667 protected int getChangesFromRequest(OID index, 668 MOTableRow row, 669 SubRequest request, 670 Variable[] values, 671 boolean setDefaultValues, 672 boolean newRow) { 673 int lastChangedColumn = -1; 674 if (setDefaultValues) { 676 for (int i = 0; (i < values.length) && (i < getColumnCount()); i++) { 677 if (columns[i] instanceof MOMutableColumn) { 678 values[i] = ((MOMutableColumn) columns[i]).getDefaultValue(); 679 } 680 } 681 } 682 Request req = request.getRequest(); 683 for (Iterator it = req.iterator(); it.hasNext();) { 684 SubRequest sreq = (SubRequest) it.next(); 685 OID id = sreq.getVariableBinding().getOid(); 686 MOTableCellInfo cellInfo = getCellInfo(id); 687 if (index.equals(cellInfo.getIndex())) { 688 int col = cellInfo.getColumn(); 689 if ((col >= 0) && (col < values.length)) { 690 Variable v = sreq.getVariableBinding().getVariable(); 691 if ((v != null) && 693 ((row == null) || (newRow) || 694 (row.size() <= col) || 695 (!v.equals(row.getValue(col))))) { 696 values[col] = v; 697 lastChangedColumn = col; 698 } 699 } 700 } 701 } 702 return lastChangedColumn; 703 } 704 705 protected boolean hasNewRows(Object key) { 706 return ((newRows != null) && (newRows.get(key) != null)); 707 } 708 709 protected Map getNewRows(Object key) { 710 if (newRows == null) { 711 newRows = new WeakHashMap(4); 712 } 713 Map rowMap = (Map) newRows.get(key); 714 if (rowMap == null) { 715 rowMap = new HashMap(5); 716 newRows.put(key, rowMap); 717 } 718 return rowMap; 719 } 720 721 protected synchronized boolean isChangeSetComplete(SubRequest subRequest, 722 OID index, 723 int column) { 724 ChangeSet changeSet = getPendingChangeSet(subRequest, index); 725 if (changeSet != null) { 726 return (changeSet.getLastChangedColumn() == column); 727 } 728 return true; 729 } 730 731 751 752 protected synchronized ChangeSet addPendingChanges(SubRequest subRequest, 753 MOTableRow row, 754 boolean newRow) { 755 if (pendingChanges == null) { 756 pendingChanges = new WeakHashMap(4); 757 } 758 Map rowMap = (Map) pendingChanges.get(subRequest.getRequest()); 759 if (rowMap == null) { 760 rowMap = new HashMap(5); 761 pendingChanges.put(subRequest.getRequest(), rowMap); 762 } 763 Variable[] values = new Variable[getColumnCount()]; 764 int lastChangedColumn = 765 getChangesFromRequest(row.getIndex(), row, subRequest, 766 values, newRow, newRow); 767 ChangeSet changeSet = new ChangeSet(row.getIndex(), values); 768 changeSet.lastChangedColumn = lastChangedColumn; 769 rowMap.put(row.getIndex(), changeSet); 770 return changeSet; 771 } 772 773 774 protected ChangeSet getPendingChangeSet(SubRequest subRequest, 775 OID index) { 776 if (pendingChanges != null) { 777 Map rowMap = (Map) pendingChanges.get(subRequest.getRequest()); 778 if (rowMap != null) { 779 return (ChangeSet) rowMap.get(index); 780 } 781 } 782 return null; 783 } 784 785 786 public void cleanup(SubRequest request) { 787 OID cellOID = request.getVariableBinding().getOid(); 788 MOTableCellInfo cell = getCellInfo(cellOID); 789 if (cell.getIndex() == null) { 790 return; 791 } 792 MOColumn col = getColumn(cell.getColumn()); 793 if (logger.isDebugEnabled()) { 794 logger.debug("Cleaning-up sub-request ("+ 795 request.getVariableBinding()+") for column: "+col); 796 } 797 MOMutableTableRow row = (MOMutableTableRow) model.getRow(cell.getIndex()); 798 if ((row != null) && (col instanceof MOMutableColumn)) { 799 ((MOMutableColumn) col).cleanup(request, row, cell.getColumn()); 800 } 801 if ((row instanceof MOMutableRow2PC) && 802 isChangeSetComplete(request, row.getIndex(), cell.getColumn())) { 803 ((MOMutableRow2PC)row).cleanupRow(request, 804 getPendingChangeSet(request, 805 row.getIndex())); 806 } 807 request.completed(); 808 } 809 810 public void undo(SubRequest request) { 811 OID cellOID = request.getVariableBinding().getOid(); 812 MOTableCellInfo cell = getCellInfo(cellOID); 813 MOMutableColumn col = (MOMutableColumn) getColumn(cell.getColumn()); 814 if (logger.isDebugEnabled()) { 815 logger.debug("Undoing sub-request ("+ 816 request.getVariableBinding()+") for column: "+col); 817 } 818 if (hasNewRows(request.getRequest())) { 819 ((MOMutableTableModel)model).removeRow(cell.getIndex()); 820 } 821 else { 822 MOMutableTableRow row = (MOMutableTableRow) model.getRow(cell.getIndex()); 823 if (row != null) { 824 col.undo(request, row, cell.getColumn()); 825 } 826 if ((row instanceof MOMutableRow2PC) && 827 isChangeSetComplete(request, row.getIndex(), cell.getColumn())) { 828 ((MOMutableRow2PC)row).undoRow(request, getPendingChangeSet(request, row.getIndex())); 829 } 830 } 831 } 832 833 public OID getOID() { 834 return oid; 835 } 836 837 public void setModel(MOTableModel model) { 838 this.model = model; 839 } 840 841 public void setVolatile(boolean isVolatile) { 842 this.isVolatile = isVolatile; 843 } 844 845 public MOTableModel getModel() { 846 return model; 847 } 848 849 public MOColumn[] getColumns() { 850 return columns; 851 } 852 853 public MOTableIndex getIndexDef() { 854 return indexDef; 855 } 856 857 public boolean isVolatile() { 858 return isVolatile; 859 } 860 861 public OID getLowerBound() { 862 return oid; 863 } 864 865 public OID getUpperBound() { 866 OID upperBound = new OID(oid); 867 int lastID = oid.size()-1; 868 873 upperBound.set(lastID, oid.get(lastID)+1); 874 return upperBound; 875 } 876 877 public boolean isLowerIncluded() { 878 return false; 879 } 880 881 public boolean isUpperIncluded() { 882 return false; 883 } 884 885 public boolean isCovered(MOScope other) { 886 return DefaultMOScope.covers(this, other); 887 } 888 889 public boolean isOverlapping(MOScope other) { 890 return DefaultMOScope.overlaps(this, other); 891 } 892 893 public synchronized void addMOChangeListener(MOChangeListener l) { 894 if (moChangeListeners == null) { 895 moChangeListeners = new Vector(2); 896 } 897 moChangeListeners.add(l); 898 } 899 900 public synchronized void removeMOChangeListener(MOChangeListener l) { 901 if (moChangeListeners != null) { 902 moChangeListeners.remove(l); 903 } 904 } 905 906 protected void fireBeforePrepareMOChange(MOChangeEvent changeEvent) { 907 if (moChangeListeners != null) { 908 Vector listeners = moChangeListeners; 909 int count = listeners.size(); 910 for (int i = 0; i < count; i++) { 911 ((MOChangeListener) listeners.elementAt(i)).beforePrepareMOChange(changeEvent); 912 } 913 } 914 } 915 916 protected void fireAfterPrepareMOChange(MOChangeEvent changeEvent) { 917 if (moChangeListeners != null) { 918 Vector listeners = moChangeListeners; 919 int count = listeners.size(); 920 for (int i = 0; i < count; i++) { 921 ((MOChangeListener) listeners.elementAt(i)).afterPrepareMOChange(changeEvent); 922 } 923 } 924 } 925 926 protected void fireBeforeMOChange(MOChangeEvent changeEvent) { 927 if (moChangeListeners != null) { 928 Vector listeners = moChangeListeners; 929 int count = listeners.size(); 930 for (int i = 0; i < count; i++) { 931 ((MOChangeListener) listeners.elementAt(i)).beforeMOChange(changeEvent); 932 } 933 } 934 } 935 936 protected void fireAfterMOChange(MOChangeEvent changeEvent) { 937 if (moChangeListeners != null) { 938 Vector listeners = moChangeListeners; 939 int count = listeners.size(); 940 for (int i = 0; i < count; i++) { 941 ((MOChangeListener) listeners.elementAt(i)).afterMOChange(changeEvent); 942 } 943 } 944 } 945 946 public synchronized void addMOTableRowListener(MOTableRowListener l) { 947 if (moTableRowListeners == null) { 948 moTableRowListeners = new Vector(2); 949 } 950 moTableRowListeners.add(l); 951 } 952 953 public synchronized void removeMOTableRowListener(MOTableRowListener l) { 954 if (moTableRowListeners != null) { 955 moTableRowListeners.remove(l); 956 } 957 } 958 959 protected void fireRowChanged(MOTableRowEvent event) { 960 if (moTableRowListeners != null) { 961 Vector listeners = moTableRowListeners; 962 int count = listeners.size(); 963 for (int i = 0; i < count; i++) { 964 ((MOTableRowListener) listeners.elementAt(i)).rowChanged(event); 965 } 966 } 967 } 968 969 public static class ChangeSet implements MOTableRow { 970 971 private OID index; 972 private Variable[] values; 973 private int lastChangedColumn = -1; 974 975 public ChangeSet(OID index, Variable[] values) { 976 this.index = index; 977 this.values = values; 978 } 979 980 public OID getIndex() { 981 return index; 982 } 983 984 public int getLastChangedColumn() { 985 return lastChangedColumn; 986 } 987 988 public void setValue(int column, Variable value) { 989 values[column] = value; 990 this.lastChangedColumn = column; 991 } 992 993 public Variable getValue(int column) { 994 return values[column]; 995 } 996 997 public MOTableRow getBaseRow() { 998 return null; 999 } 1000 1001 public int size() { 1002 return values.length; 1003 } 1004 1005 public void setBaseRow(MOTableRow baseRow) { 1006 throw new UnsupportedOperationException (); 1007 } 1008 } 1009 1010 class CellProxy implements ManagedObject { 1011 1012 private MOTableCellInfo cellInfo; 1013 private MOScope scope; 1014 1015 public CellProxy(MOTableCellInfo cellInfo) { 1016 this.cellInfo = cellInfo; 1017 this.scope = new OIDScope(cellInfo.getCellOID()); 1018 } 1019 1020 public MOScope getScope() { 1021 return scope; 1022 } 1023 1024 public OID find(MOScope range) { 1025 if (range.isCovered(scope)) { 1026 return cellInfo.getCellOID(); 1027 } 1028 return null; 1029 } 1030 1031 public void get(SubRequest request) { 1032 DefaultMOTable.this.get(request); 1033 } 1034 1035 public boolean next(SubRequest request) { 1036 return DefaultMOTable.this.next(request); 1037 } 1038 1039 public void prepare(SubRequest request) { 1040 DefaultMOTable.this.prepare(request); 1041 } 1042 1043 public void commit(SubRequest request) { 1044 DefaultMOTable.this.commit(request); 1045 } 1046 1047 public void undo(SubRequest request) { 1048 DefaultMOTable.this.undo(request); 1049 } 1050 1051 public void cleanup(SubRequest request) { 1052 DefaultMOTable.this.cleanup(request); 1053 } 1054 1055 public MOTable getTable() { 1056 return DefaultMOTable.this; 1057 } 1058 } 1059 1060 class CellInfo implements MOTableCellInfo { 1061 1062 private OID index; 1063 private int id = 0; 1064 private int col = -1; 1065 private MOTableRow row; 1066 1067 public CellInfo(OID oid) { 1068 this.index = getIndexPart(oid); 1069 if ((oid.size() > DefaultMOTable.this.oid.size()) && 1070 (oid.startsWith(DefaultMOTable.this.oid))) { 1071 id = oid.get(DefaultMOTable.this.oid.size()); 1072 } 1073 1078 } 1079 1080 public CellInfo(OID index, int column, int columnID) { 1081 this.index = index; 1082 this.col = column; 1083 this.id = columnID; 1084 } 1085 1086 public CellInfo(OID index, int column, int columnID, MOTableRow row) { 1087 this(index, column, columnID); 1088 this.row = row; 1089 } 1090 1091 public OID getIndex() { 1092 return index; 1093 } 1094 1095 public int getColumn() { 1096 if (col < 0) { 1097 col = getColumnIndex(id); 1098 } 1099 return col; 1100 } 1101 1102 public int getColumnID() { 1103 return id; 1104 } 1105 1106 public OID getCellOID() { 1107 return DefaultMOTable.this.getCellOID(index, col); 1108 } 1109 1110 public MOTableRow getRow() { 1111 return row; 1112 } 1113 } 1114 1115 public OID getID() { 1116 return getLowerBound(); 1117 } 1118 1119 public void load(MOInput input) throws IOException { 1120 if (input.getImportMode() == ImportModes.REPLACE_CREATE) { 1121 int count = removeAll(); 1122 if (logger.isDebugEnabled()) { 1123 logger.debug("Removed "+count+" rows from "+getID()+ 1124 " because importing with a REPLACE import mode"); 1125 } 1126 } 1127 Sequence seq = input.readSequence(); 1128 for (int i=0; i<seq.getSize(); i++) { 1129 IndexedVariables rowValues = input.readIndexedVariables(); 1130 boolean rowExists = model.containsRow(rowValues.getIndex()); 1131 if ((input.getImportMode() == ImportModes.CREATE) && (rowExists)) { 1132 logger.debug("Row '" + rowValues.getIndex() + 1133 "' not imported because it already exists in table " + 1134 getID() + " and import mode is CREATE"); 1135 continue; 1136 } 1137 if (rowExists) { 1138 removeRow(rowValues.getIndex()); 1139 } 1140 1141 if ((rowExists) || 1142 ((input.getImportMode() == ImportModes.CREATE) || 1143 (input.getImportMode() == ImportModes.REPLACE_CREATE) || 1144 (input.getImportMode() == ImportModes.UPDATE_CREATE))) { 1145 MOTableRow row = null; 1146 try { 1147 row = createRow(rowValues.getIndex(), rowValues.getValues()); 1148 } 1149 catch (UnsupportedOperationException uoex) { 1150 logger.debug("Could not create row by row factory: " + 1151 uoex.getMessage()); 1152 } 1154 if (row == null) { 1155 row = 1156 new DefaultMOTableRow(rowValues.getIndex(), rowValues.getValues()); 1157 fireRowChanged(new MOTableRowEvent(this, 1158 this, row, MOTableRowEvent.CREATE)); 1159 } 1160 addRow(row); 1161 } 1162 } 1163 } 1164 1165 public void save(MOOutput output) throws IOException { 1166 List rowsToSave = new LinkedList(); 1167 synchronized (model) { 1168 for (Iterator it = model.iterator(); it.hasNext(); ) { 1169 MOTableRow row = (MOTableRow) it.next(); 1170 boolean volatileRow = false; 1171 for (int i = 0; i < columns.length; i++) { 1172 if (columns[i].isVolatile(row, i)) { 1173 volatileRow = true; 1174 break; 1175 } 1176 } 1177 if (!volatileRow) { 1178 Variable[] values = new Variable[columns.length]; 1179 for (int i=0; i<columns.length; i++) { 1180 values[i] = row.getValue(i); 1181 } 1182 IndexedVariables rowValues = 1183 new IndexedVariables(row.getIndex(), values); 1184 rowsToSave.add(rowValues); 1185 } 1186 } 1187 } 1188 Sequence group = new Sequence(rowsToSave.size()); 1189 output.writeSequence(group); 1190 for (Iterator it = rowsToSave.iterator(); it.hasNext(); ) { 1191 IndexedVariables rowValues = (IndexedVariables) it.next(); 1192 output.writeIndexedVariables(rowValues); 1193 } 1194 } 1195 1196 public Variable[] getDefaultValues() { 1197 Variable[] values = new Variable[getColumnCount()]; 1198 for (int i = 0; (i < values.length); i++) { 1199 if (columns[i] instanceof MOMutableColumn) { 1200 values[i] = ((MOMutableColumn) columns[i]).getDefaultValue(); 1201 } 1202 } 1203 return values; 1204 } 1205 1206 public String toString() { 1207 return "DefaultMOTable[id="+getID()+",index="+getIndexDef()+",columns="+ 1208 Arrays.asList(getColumns())+"]"; 1209 } 1210 1211 public boolean covers(OID oid) { 1212 return isCovered(new DefaultMOScope(oid, true, oid, true)); 1213 } 1214 1215 1216 private static class RowCacheEntry { 1217 private MOTableRow row; 1218 private OID searchLowerBound; 1219 private boolean searchLowerBoundIncluded; 1220 1221 RowCacheEntry(MOTableRow row, 1222 OID searchLowerBound, boolean searchLowerBoundIncluded) { 1223 this.row = row; 1224 this.searchLowerBound = searchLowerBound; 1225 this.searchLowerBoundIncluded = searchLowerBoundIncluded; 1226 } 1227 } 1228} 1229 | Popular Tags |