1 18 package sync4j.server.engine; 19 20 import java.util.*; 21 import java.util.Map ; 22 import java.util.logging.Logger ; 23 import java.util.logging.Level ; 24 import java.sql.Timestamp ; 25 26 import java.security.Principal ; 27 28 import sync4j.framework.core.*; 29 import sync4j.framework.protocol.CommandIdGenerator; 30 import sync4j.framework.protocol.ProtocolUtil; 31 import sync4j.framework.engine.SyncOperationStatus; 32 import sync4j.framework.engine.SyncOperation; 33 import sync4j.framework.engine.SyncItemKey; 34 import sync4j.framework.engine.SyncItem; 35 import sync4j.framework.engine.SyncItemImpl; 36 import sync4j.framework.engine.SyncProperty; 37 import sync4j.framework.engine.SyncItemMapping; 38 import sync4j.framework.engine.SyncItemState; 39 import sync4j.framework.engine.SyncConflict; 40 import sync4j.framework.engine.source.*; 41 import sync4j.framework.server.ClientMapping; 42 import sync4j.framework.server.error.MappingException; 43 import sync4j.framework.logging.Sync4jLogger; 44 45 import sync4j.server.engine.Sync4jOperationStatus; 46 47 53 public class EngineHelper { 54 55 public static Logger log = Sync4jLogger.getLogger(Sync4jEngine.LOG_NAME); 56 57 77 public static Status[] 78 generateStatusCommands(SyncOperationStatus[] operationStatus, 79 String msgId , 80 CommandIdGenerator idGenerator ) { 81 HashMap statusMap = new HashMap(); 82 83 ArrayList itemList = null; 84 StatusKey key = null; 85 86 ModificationCommand cmd = null; 87 for (int i=0; i < operationStatus.length ; ++i) { 88 89 cmd = ((Sync4jOperationStatus)operationStatus[i]).getCmd(); 90 91 if ((cmd == null) || (cmd.isNoResp())) { 92 continue; } 94 95 key = new StatusKey( 102 cmd, 103 operationStatus[i].getStatusCode() 104 ); 105 106 itemList = (ArrayList)statusMap.get(key); 107 108 if (itemList == null){ 109 itemList = new ArrayList(); 110 statusMap.put(key, itemList); 111 } 112 SyncItemKey keyA = 116 operationStatus[i].getOperation().getSyncItemA().getKey(); 117 SyncItemKey mapKeyA = 118 operationStatus[i].getOperation().getSyncItemA().getMappedKey(); 119 itemList.add(mapKeyA == null ? keyA : mapKeyA); 120 } 121 122 ArrayList ret = new ArrayList(); 126 127 Item[] items = null; 128 129 Iterator i = statusMap.keySet().iterator(); 130 while(i.hasNext()) { 131 key = (StatusKey)i.next(); 132 133 itemList = (ArrayList)statusMap.get(key); 134 135 items = new Item[itemList.size()]; 136 137 for (int j = 0; j<items.length; ++j) { 138 items[j] = new Item( 139 null, 140 new Source(((SyncItemKey)itemList.get(j)).getKeyAsString()), 141 null, 142 null, 143 false 144 ); 145 146 } 147 ret.add( 148 new Status( 149 idGenerator.next() , 150 msgId , 151 key.cmd.getCmdID().getCmdID() , 152 key.cmd.getName() , 153 null , 154 (items.length == 1) ? 155 new SourceRef(items[0].getSource()) : 156 null , 157 null , 158 null , 159 new Data(key.statusCode) , 160 (items.length > 1) ? 161 items : 162 new Item[0] 163 ) 164 ); 165 } 166 return (Status[])ret.toArray(new Status[ret.size()]); 167 } 168 169 181 public static 182 ItemizedCommand[] operationsToCommands(ClientMapping clientMapping, 183 SyncOperation[] operations , 184 String sourceName , 185 CommandIdGenerator idGenerator ) { 186 ArrayList commands = new ArrayList(); 187 188 SyncItem item = null; 189 for (int i=0; ((operations != null) && (i<operations.length)); ++i) { 190 191 if (log.isLoggable(Level.FINEST)) { 192 log.finest( "Converting the operation\n" 193 + operations[i] 194 + "\nfor the source " 195 + sourceName 196 ); 197 } 198 199 item = operations[i].getSyncItemB(); 201 if (operations[i].isAOperation() && (item != null)) { 202 203 char op = operations[i].getOperation(); 204 205 if (op == SyncOperation.NOP) { 209 continue; 210 } 211 if (op == SyncOperation.CONFLICT) { 212 if (operations[i].getSyncItemA().getState() == SyncItemState.NEW && 213 operations[i].getSyncItemB().getState() == SyncItemState.SYNCHRONIZED 214 ) { 215 continue; 220 } 221 } 222 commands.add(operationToCommand(clientMapping, operations[i], idGenerator)); 223 } 224 } 225 226 return (ItemizedCommand[])commands.toArray(new ItemizedCommand[0]); 227 } 228 229 239 public static 240 ItemizedCommand operationToCommand(ClientMapping clientMapping, 241 SyncOperation operation , 242 CommandIdGenerator idGenerator ) { 243 ItemizedCommand cmd = null; 244 245 if (idGenerator == null) { 246 log.finest("idGenerator is null. Cannot continue"); 247 throw new NullPointerException ("idGenerator cannot be null!"); 248 } 249 250 char op = operation.getOperation(); 251 252 String itemKey = operation.getSyncItemB().getKey().getKeyAsString(); 260 if (op != SyncOperation.NEW) { 261 String mappedKey = clientMapping.getMappedValueForGuid(itemKey); 262 if (mappedKey != null) { 267 itemKey = mappedKey; 268 } 269 } 270 assert (itemKey != null); 271 272 Meta m = new Meta(); 281 if (operation.getSyncItemB().getPropertyValue(SyncItem.PROPERTY_FORMAT) != null) { 282 m.setFormat((String )operation.getSyncItemB().getPropertyValue(SyncItem.PROPERTY_FORMAT)); 283 } 284 if (operation.getSyncItemB().getPropertyValue(SyncItem.PROPERTY_TYPE) != null) { 285 m.setType((String )operation.getSyncItemB().getPropertyValue(SyncItem.PROPERTY_TYPE)); 286 } else { 287 m.setType(operation.getSyncItemB().getSyncSource().getType()); 288 } 289 290 if (op == SyncOperation.NEW) { 291 cmd = new Add( 292 idGenerator.next(), 293 false , 294 null , 295 m , new Item[] { 297 SyncItemHelper.toItem( 298 itemKey , 299 operation.getSyncItemA(), 300 false , 301 true , 302 true 303 ) 304 } 305 ); 306 } else if (op == SyncOperation.DELETE) { 307 cmd = new Delete( 308 idGenerator.next(), 309 false , 310 false , 311 false , 312 null , 313 null , new Item[] { 315 SyncItemHelper.toItem( 316 itemKey, 317 operation.getSyncItemA(), 318 true, 319 false, 320 false 321 ) 322 } 323 ); 324 } else if (op == SyncOperation.UPDATE) { 325 cmd = new Replace( 326 idGenerator.next(), 327 false , 328 null , 329 m , 330 new Item[] { 331 SyncItemHelper.toItem( 332 itemKey, 333 operation.getSyncItemA(), 334 true, 335 false, 336 true 337 ) 338 } 339 ); 340 } else if (op == SyncOperation.CONFLICT) { 341 char s = operation.getSyncItemB().getState(); 348 349 if (operation.getSyncItemB().getState() == SyncItemState.NOT_EXISTING) { 350 itemKey = operation.getSyncItemA().getKey().getKeyAsString(); 351 } 352 353 switch (s) { 354 case SyncItemState.UPDATED: 355 case SyncItemState.SYNCHRONIZED: 356 cmd = new Replace( 357 idGenerator.next(), 358 false , 359 null , 360 m , 361 new Item[] { 362 SyncItemHelper.toItem( 363 itemKey, 364 operation.getSyncItemA(), 365 true, 366 false, 367 true 368 ) 369 } 370 ); 371 break; 372 case SyncItemState.DELETED: 373 case SyncItemState.NOT_EXISTING: 374 cmd = new Delete( 375 idGenerator.next(), 376 false , 377 false , 378 false , 379 null , 380 null , new Item[] { 382 SyncItemHelper.toItem( 383 itemKey, 384 operation.getSyncItemA(), 385 true, 386 false, 387 false 388 ) 389 } 390 ); 391 break; 392 case SyncItemState.NEW: 393 itemKey = operation.getSyncItemB().getKey().getKeyAsString(); 395 cmd = new Add( 396 idGenerator.next(), 397 false , 398 null , 399 m , new Item[] { 401 SyncItemHelper.toItem( 402 itemKey , 403 operation.getSyncItemA(), 404 false , 405 true , 406 true 407 ) 408 } 409 ); 410 break; 411 } 412 } 413 414 return cmd; 415 } 416 417 434 public static SyncItem[] itemsToSyncItems(ClientMapping clientMapping, 435 SyncSource syncSource , 436 ModificationCommand cmd , 437 char state , 438 long timestamp ) { 439 440 Item[] items = (Item[])cmd.getItems().toArray(new Item[0]); 441 442 if ((items == null) || (items.length == 0)) { 443 return new SyncItem[0]; 444 } 445 446 SyncItem[] syncItems = new SyncItem[items.length]; 447 448 Data d = null; 449 String content = null, key = null, mappedKey = null; 450 for (int i=0; i<items.length; ++i) { 451 d = items[i].getData(); 452 content = (d != null) ? d.getData() : ""; 453 454 key = items[i].getSource().getLocURI(); 455 mappedKey = clientMapping.getMappedValueForLuid(key); 456 457 if (mappedKey != null) { 463 String k = mappedKey; 464 mappedKey = key; 465 key = k; 466 } 467 syncItems[i] = 468 new SyncItemImpl(syncSource, key, mappedKey, state); 469 syncItems[i].setProperty( 470 new SyncProperty(SyncItemHelper.PROPERTY_COMMAND, cmd) 471 ); 472 syncItems[i].setProperty( 473 new SyncProperty(SyncItem.PROPERTY_BINARY_CONTENT, content.getBytes()) 474 ); 475 syncItems[i].setProperty( 476 new SyncProperty(SyncItem.PROPERTY_TIMESTAMP, new Timestamp (timestamp)) 477 ); 478 if (items[i].isMoreData()) { 479 syncItems[i].setState(SyncItemState.PARTIAL); 480 Long size = ProtocolUtil.getLOSize(cmd); 481 if (size != null) { 482 syncItems[i].setProperty( 483 new SyncProperty(SyncItem.PROPERTY_SIZE, size) 484 ); 485 } 486 } 487 } 488 489 return syncItems; 490 } 491 492 504 public static List intersect(final List a, final List b) { 505 int n = 0; 506 SyncItem itemA = null; 507 ArrayList ret = new ArrayList(); 508 SyncItemMapping mapping = null; 509 510 Iterator i = a.iterator(); 511 while(i.hasNext()) { 512 itemA = (SyncItem)i.next(); 513 n = b.indexOf(itemA); 514 if (n >= 0) { 515 mapping = new SyncItemMapping(itemA.getKey()); 516 mapping.setMapping(itemA, (SyncItem)b.get(n)); 517 ret.add(mapping); 518 } 519 } 520 521 return ret; 522 } 523 524 534 public static List buildAmBBm(List items , 535 SyncSource source , 536 Principal principal) { 537 SyncItem itemA, itemB; 538 SyncItemMapping mapping = null; 539 540 ArrayList ret = new ArrayList(); 541 542 Iterator i = items.iterator(); 543 while (i.hasNext()) { 544 itemA = (SyncItem)i.next(); 545 546 if (itemA.getMappedKey() == null) { 551 continue; 552 } 553 554 try { 555 itemB = source.getSyncItemFromId(principal, itemA.getKey()); 556 557 if (itemB != null) { 558 itemB.setState(SyncItemState.SYNCHRONIZED); 559 mapping = new SyncItemMapping(itemA.getKey()); 560 mapping.setMapping(itemA, itemB); 561 ret.add(mapping); 562 } 563 } catch (SyncSourceException e) { 564 String msg = "Error retrieving an item by its key " 565 + itemA.getKey() 566 + " from source " 567 + source 568 + ": " 569 + e.getMessage(); 570 log.severe(msg); 571 log.throwing("EngineHelper", "buildAmBBm", e); 572 } 573 } 574 575 return ret; 576 } 577 578 588 public static List buildAAmBm(List items , 589 SyncSource source , 590 Principal principal) { 591 SyncItem itemA, itemB; 592 SyncItemMapping mapping = null; 593 594 ArrayList ret = new ArrayList(); 595 596 Iterator i = items.iterator(); 597 while (i.hasNext()) { 598 itemB = (SyncItem)i.next(); 599 600 try { 601 itemA = source.getSyncItemFromId(principal, itemB.getKey()); 602 603 if (itemA != null) { 604 itemA.setState(SyncItemState.SYNCHRONIZED); 605 mapping = new SyncItemMapping(itemB.getKey()); 606 mapping.setMapping(itemA, itemB); 607 ret.add(mapping); 608 } 609 } catch (SyncSourceException e) { 610 String msg = "Error retrieving an item by its key " 611 + itemB.getKey() 612 + " from source " 613 + source 614 + ": " 615 + e.getMessage(); 616 log.severe(msg); 617 log.throwing("EngineHelper", "buildAmBBm", e); 618 } 619 } 620 621 return ret; 622 } 623 624 633 public static void updateClientMappings(Map clientMappings, 634 SyncOperation[] operations , 635 boolean slowSync ) 636 throws MappingException { 637 638 ClientMapping clientMapping = null; 639 String guid = null, luid = null; 640 SyncSource clientSource = null; 641 642 for (int i=0; ((operations != null) && (i<operations.length)); ++i) { 643 if (operations[i] instanceof SyncConflict) { 647 continue; 648 } 649 650 clientSource = operations[i].getSyncItemA().getSyncSource(); 651 if (clientSource == null) { 652 continue; 656 } 657 658 clientMapping = (ClientMapping)clientMappings.get(clientSource.getSourceURI()); 659 660 if (slowSync && 664 operations[i].getOperation() != SyncOperation.DELETE) { 665 if (operations[i].getSyncItemA() != null && 666 operations[i].getSyncItemB() != null) { 667 668 guid = operations[i].getSyncItemB().getKey().getKeyAsString(); 669 670 SyncItemKey sikA = operations[i].getSyncItemA().getMappedKey(); 671 if (sikA != null) { 672 luid = sikA.getKeyAsString(); 673 } else { 674 luid = operations[i].getSyncItemA().getKey().getKeyAsString(); 675 } 676 clientMapping.updateMapping(guid , luid); 677 continue; 678 } 679 } else if (operations[i].getOperation() == SyncOperation.DELETE) { 680 guid = operations[i].getSyncItemB().getKey().getKeyAsString(); 681 clientMapping.removeMappedValuesForGuid(guid); 682 } else if (operations[i].getSyncItemA().getState() == SyncItemState.DELETED && 683 operations[i].getSyncItemB().getState() == SyncItemState.DELETED ) { 684 guid = operations[i].getSyncItemB().getKey().getKeyAsString(); 685 clientMapping.removeMappedValuesForGuid(guid); 686 } else if (operations[i].getSyncItemA().getState() == SyncItemState.NEW && 687 operations[i].getSyncItemB().getState() == SyncItemState.DELETED ) { 688 guid = operations[i].getSyncItemB().getKey().getKeyAsString(); 689 clientMapping.removeMappedValuesForGuid(guid); 690 } 691 } 692 } 693 694 703 public static void updateServerMappings(Map clientMappings, 704 SyncOperationStatus[] status , 705 boolean slowSync ) 706 707 throws MappingException { 708 char op; 709 ClientMapping clientMapping = null; 710 String luid = null, guid = null; 711 SyncSource serverSource = null; 712 SyncOperation operation; 713 for (int i=0; ((status != null) && (i<status.length)); ++i) { 714 operation = status[i].getOperation(); 715 op = operation.getOperation(); 716 717 serverSource = status[i].getSyncSource(); 718 if (serverSource == null) { 719 continue; 723 } 724 725 clientMapping = (ClientMapping)clientMappings.get(serverSource.getSourceURI()); 726 727 if (slowSync && 731 (op != SyncOperation.DELETE) && (op != SyncOperation.NEW)) { 732 733 if (operation.getSyncItemA() != null && 734 operation.getSyncItemB() != null) { 735 736 guid = operation.getSyncItemB().getKey().getKeyAsString(); 737 738 SyncItemKey sikA = operation.getSyncItemA().getMappedKey(); 739 if (sikA != null) { 740 luid = sikA.getKeyAsString(); 741 } else { 742 luid = operation.getSyncItemA().getKey().getKeyAsString(); 743 } 744 clientMapping.updateMapping(guid , luid); 745 continue; 746 } 747 } else if(op == SyncOperation.DELETE) { 748 guid = operation.getSyncItemB().getKey().getKeyAsString(); 749 clientMapping.removeMappedValuesForGuid(guid); 750 } else if (op == SyncOperation.NEW) { 751 if (operation.isBOperation()) { 752 luid = operation.getSyncItemA().getKey().getKeyAsString(); 753 guid = operation.getSyncItemB().getKey().getKeyAsString(); 754 clientMapping.updateMapping(guid, luid); 755 } 756 } else if (op == SyncOperation.CONFLICT) { 757 if (SyncConflict.STATE_UPDATED_DELETED.equals(((SyncConflict)operation).getType())) { 758 guid = operation.getSyncItemB().getKey().getKeyAsString(); 759 clientMapping.removeMappedValuesForGuid(guid); 760 } else if (SyncConflict.STATE_DELETED_UPDATED.equals(((SyncConflict)operation).getType())) { 761 luid = operation.getSyncItemA().getKey().getKeyAsString(); 762 guid = operation.getSyncItemB().getKey().getKeyAsString(); 763 clientMapping.updateMapping(guid, luid); 764 } else if (SyncConflict.STATE_UPDATED_UPDATED.equals(((SyncConflict)operation).getType())) { 765 luid = operation.getSyncItemA().getKey().getKeyAsString(); 766 guid = operation.getSyncItemB().getKey().getKeyAsString(); 767 clientMapping.updateMapping(guid, luid); 768 } else if (SyncConflict.STATE_NEW_NEW.equals(((SyncConflict)operation).getType())) { 769 luid = operation.getSyncItemA().getKey().getKeyAsString(); 770 guid = operation.getSyncItemB().getKey().getKeyAsString(); 771 clientMapping.updateMapping(guid, luid); 772 } else { 773 774 assert (!SyncConflict.STATE_DELETED_NEW.equals(((SyncConflict)operation).getType())); 778 assert (!SyncConflict.STATE_DELETED_CONFLICT.equals(((SyncConflict)operation).getType())); 779 assert (!SyncConflict.STATE_UPDATED_NEW.equals(((SyncConflict)operation).getType())); 780 assert (!SyncConflict.STATE_UPDATED_CONFLICT.equals(((SyncConflict)operation).getType())); 781 assert (!SyncConflict.STATE_NEW_DELETED.equals(((SyncConflict)operation).getType())); 782 assert (!SyncConflict.STATE_NEW_UPDATED.equals(((SyncConflict)operation).getType())); 783 assert (!SyncConflict.STATE_NEW_CONFLICT.equals(((SyncConflict)operation).getType())); 784 assert (!SyncConflict.STATE_NONE_CONFLICT.equals(((SyncConflict)operation).getType())); 785 assert (!SyncConflict.STATE_CONFLICT_DELETED.equals(((SyncConflict)operation).getType())); 786 assert (!SyncConflict.STATE_CONFLICT_UPDATED.equals(((SyncConflict)operation).getType())); 787 assert (!SyncConflict.STATE_CONFLICT_NEW.equals(((SyncConflict)operation).getType())); 788 assert (!SyncConflict.STATE_CONFLICT_CONFLICT.equals(((SyncConflict)operation).getType())); 789 } 790 } 791 792 } 793 } 794 795 803 public static DataStore toDataStore(String uri, SyncSourceInfo info) { 804 ContentTypeInfo[] supportedContents = null; 805 ContentTypeInfo preferredContent = null; 806 807 if (info != null) { 808 ContentType[] supportedTypes = info.getSupportedTypes(); 809 ContentType preferredType = info.getPreferredType() ; 810 811 supportedContents = 812 new ContentTypeInfo[supportedTypes.length]; 813 814 for (int i=0; (i<supportedTypes.length); ++i) { 815 supportedContents[i] = new ContentTypeInfo ( 816 supportedTypes[i].type, 817 supportedTypes[i].version 818 ); 819 } 820 821 preferredContent = new ContentTypeInfo( 822 preferredType.type, 823 preferredType.version 824 ); 825 } 826 827 return new DataStore( 828 new SourceRef(uri), 829 null, 830 32, 831 preferredContent , 832 supportedContents, 833 preferredContent , 834 supportedContents, 835 null, 836 new SyncCap(SyncType.ALL_SYNC_TYPES) 837 ); 838 } 839 840 846 public static void resetState(Collection items) { 847 if (items == null) { 848 return; 849 } 850 851 Iterator i = items.iterator(); 852 while (i.hasNext()) { 853 SyncItem s = (SyncItem)i.next(); 854 if (s.getState() != SyncItemState.PARTIAL) { 855 s.setState(SyncItemState.SYNCHRONIZED); 856 } 857 } 858 } 859 860 866 public static void resetState(SyncItem[] items) { 867 if ((items == null) || (items.length == 0)) { 868 return; 869 } 870 871 for (int i=0; i<items.length; ++i) { 872 if (items[i].getState() != SyncItemState.PARTIAL) { 873 items[i].setState(SyncItemState.SYNCHRONIZED); 874 } 875 } 876 } 877 } 878 879 class StatusKey { 880 public ModificationCommand cmd = null; 881 public int statusCode = 0; 882 883 public StatusKey(ModificationCommand cmd, int statusCode) { 884 this.cmd = cmd; 885 this.statusCode = statusCode; 886 } 887 888 public boolean equals(Object o){ 889 if ((o != null) && (o instanceof StatusKey)) { 890 return (((StatusKey)o).cmd.getCmdID().equals(this.cmd.getCmdID())) 891 && (((StatusKey)o).statusCode == this.statusCode); 892 } 893 894 return false; 895 } 896 897 public int hashCode() { 898 return ( String.valueOf(cmd.getCmdID().getCmdID()) 899 + String.valueOf(statusCode) 900 ).hashCode(); 901 } 902 } 903 | Popular Tags |