1 18 19 package sync4j.exchange.engine.source; 20 21 import java.io.ByteArrayInputStream ; 22 import java.io.Serializable ; 23 import java.security.Principal ; 24 import java.sql.Timestamp ; 25 import java.util.ArrayList ; 26 import java.util.Date ; 27 import java.util.logging.Logger ; 28 import java.util.logging.Level ; 29 30 import sync4j.exchange.xml.XmlParser; 31 32 import sync4j.foundation.pdi.converter.*; 33 import sync4j.foundation.pdi.parser.*; 34 35 import sync4j.framework.logging.Sync4jLogger; 36 import sync4j.framework.engine.SyncItemImpl; 37 import sync4j.framework.engine.SyncItem; 38 import sync4j.framework.engine.SyncItemKey; 39 import sync4j.framework.engine.SyncProperty; 40 import sync4j.framework.engine.SyncItemState; 41 import sync4j.framework.engine.source.SyncSource; 42 import sync4j.framework.engine.source.SyncSourceException; 43 import sync4j.framework.engine.source.AbstractSyncSource; 44 import sync4j.framework.security.Sync4jPrincipal; 45 import sync4j.framework.security.Sync4jPrincipal; 46 import sync4j.framework.server.store.NotFoundException; 47 import sync4j.framework.tools.Base64; 48 49 import sync4j.exchange.items.calendar.model.Calendar; 50 import sync4j.exchange.items.calendar.manager.CalendarManager; 51 import sync4j.exchange.items.calendar.CalendarParseException; 52 import sync4j.exchange.DataAccessException; 53 54 62 public class ExchangeCalendarSyncSource 63 extends ExchangeSyncSource 64 implements SyncSource, Serializable { 65 66 68 private static final String EXCHANGE_HREF_EXTENSION = ".eml"; 69 70 72 private CalendarManager cm = null ; 73 74 76 public ExchangeCalendarSyncSource() { 77 } 78 79 81 84 public SyncItem setSyncItem(Principal principal, SyncItem syncItem) 85 throws SyncSourceException { 86 87 Calendar calendar = null ; 88 Calendar newCalendar = null ; 89 90 String href = null ; 91 String content = null ; 92 String itemKey = null ; 93 String username = null ; 94 String credentials = null ; 95 96 boolean isAddCalendar = false ; 97 98 try { 99 100 username = ((Sync4jPrincipal)principal).getUsername() ; 101 102 credentials = ((Sync4jPrincipal)principal).getEncodedCredentials() ; 103 104 itemKey = syncItem.getKey().getKeyAsString(); 105 106 href = getHref(itemKey); 110 111 if (href == null) { 112 href = String.valueOf(System.currentTimeMillis()) + 117 EXCHANGE_HREF_EXTENSION; 118 isAddCalendar = true; 119 } 120 121 if (log.isLoggable(Level.FINEST)) { 122 if (!isAddCalendar) { 123 log.finest(itemKey + " already exists: updating"); 124 } else { 125 log.finest(itemKey + " is new: adding"); 126 } 127 } 128 129 calendar = getCalendarFromSyncItem(syncItem); 130 131 calendar.setHref(href); 132 133 cm = getCalendarManager(); 134 135 newCalendar = cm.setCalendar (calendar , 136 username , 137 credentials , 138 exchangeFolder); 139 140 if (isAddCalendar) { 141 toChangedItems(newCalendar.getId(), ITEM_ADD); 142 } else { 143 toChangedItems(newCalendar.getId(), ITEM_UPDATE); 144 } 145 146 147 syncItem = getSyncItem(newCalendar); 148 149 return syncItem; 150 151 } catch (Exception e) { 152 if (newCalendar != null) { 153 if (isAddCalendar) { 154 toChangedItems(newCalendar.getId(), ITEM_ADD_ERROR); 155 } else { 156 toChangedItems(newCalendar.getId(), ITEM_UPDATE_ERROR); 157 } 158 } 159 throw new SyncSourceException( "Error setting the item " + 160 syncItem + " " + e.getMessage(), e) ; 161 } 162 163 } 164 165 168 public SyncItem[] setSyncItems(Principal principal, SyncItem[] syncItems) 169 throws SyncSourceException { 170 171 ArrayList syncItemsInError = new ArrayList () ; 172 ArrayList ret = new ArrayList () ; 173 174 for (int i=0, l = syncItems.length; i < l; ++i) { 175 try { 176 ret.add(setSyncItem(principal, syncItems[i])); 177 } catch (SyncSourceException e) { 178 syncItemsInError.add(syncItems[i]); 179 } 180 } 181 182 if (syncItemsInError.size() > 0) { 183 throw new SyncSourceException("Error setting the following items: " + 184 syncItemsInError.toString() 185 ); 186 } 187 188 if (log.isLoggable(Level.SEVERE)) { 189 log.severe("Exchange SyncSource " + 190 sourceURI + 191 " - set syncItems"); 192 } 193 194 return (SyncItem[])ret.toArray(new SyncItem[] {}); 195 196 } 197 198 201 public SyncItem getSyncItemFromId(Principal principal, 202 SyncItemKey syncItemKey) 203 throws SyncSourceException{ 204 205 SyncItem[] syncItems = 206 getSyncItemsFromIds(principal, new SyncItemKey[] {syncItemKey}); 207 208 if ((syncItems == null) || (syncItems.length == 0)) { 209 return null; 210 } 211 212 return syncItems[0]; 213 214 } 215 216 219 public SyncItem[] getSyncItemsFromIds(Principal principal, 220 SyncItemKey[] syncItemKeys) 221 throws SyncSourceException { 222 223 ArrayList syncItems = null ; 224 Calendar calendar = null ; 225 226 String username = null ; 227 String credentials = null ; 228 229 String id = null ; 230 231 username = ((Sync4jPrincipal) principal).getUsername() ; 232 credentials = ((Sync4jPrincipal) principal).getEncodedCredentials() ; 233 234 syncItems = new ArrayList (); 235 236 int l = syncItemKeys.length; 237 238 for (int i=0; ((syncItemKeys != null) && (i < l)); ++i) { 239 240 id = syncItemKeys[i].getKeyAsString(); 241 242 try { 243 cm = getCalendarManager(); 244 calendar = cm.getCalendarById(username , 245 credentials , 246 id , 247 this.exchangeFolder); 248 } catch (DataAccessException e) { 249 250 Throwable previous = e.getCause(); 251 252 if (previous instanceof NotFoundException) { 253 254 Logger log = Sync4jLogger.getLogger("source"); 255 if (log.isLoggable(Level.SEVERE)) { 256 log.severe 257 ("Calendar not found while reading Exchange database: " + 258 e.getMessage() ); 259 } 260 261 Logger. 262 getLogger(LOG_NAME). 263 throwing(getClass(). 264 getName(), "readExchangeDatabase", e); 265 266 } else{ 267 throw new SyncSourceException("Error reading items", e); 268 } 269 } 270 271 if (calendar != null) { 272 calendar.setModificationStatus(SyncItemState.NEW) ; 273 syncItems.add(getSyncItem(calendar)) ; 274 } 275 276 } 277 278 return (SyncItem[]) syncItems.toArray(new SyncItem[syncItems.size()]); 279 280 } 281 282 285 public SyncItemKey[] getNewSyncItemKeys(Principal principal, 286 Timestamp since ) 287 throws SyncSourceException { 288 return null; 289 } 290 291 294 public SyncItem[] getNewSyncItems(Principal principal, 295 Timestamp since ) 296 throws SyncSourceException { 297 298 String ids[] = null; 299 300 ids = this.getNewItemIds(); 301 302 if (log.isLoggable(Level.SEVERE)) { 303 log.severe("Exchange SyncSource " + 304 sourceURI + 305 " - getting new sync items" ); 306 } 307 308 if(ids == null || !(ids.length > 0)) { 309 return new SyncItem[0]; 310 } 311 312 return filterSyncItems(principal, ids, SyncItemState.NEW); 313 314 } 315 316 319 public SyncItemKey[] getDeletedSyncItemKeys(Principal principal, 320 Timestamp since ) 321 throws SyncSourceException { 322 return null; 323 } 324 325 328 public SyncItem[] getDeletedSyncItems(Principal principal, 329 Timestamp since ) 330 throws SyncSourceException { 331 332 String [] ids = null ; 333 SyncItem[] syncItems = null ; 334 335 ids = this.getDeleteItemIds(); 336 337 int l = ids.length; 338 339 syncItems = new SyncItem[l]; 340 341 for (int i = 0; i < l; i++) { 342 343 syncItems[i] = new SyncItemImpl(this, ids[i], SyncItemState.DELETED); 344 } 345 346 if (log.isLoggable(Level.SEVERE)) { 347 log.severe("Exchange SyncSource " + 348 sourceURI + 349 " - getting deleted sync items" ); 350 } 351 352 return syncItems; 353 354 } 355 356 359 public SyncItem[] getUpdatedSyncItems(Principal principal, Timestamp since) 360 throws SyncSourceException { 361 362 String ids[] = null; 363 364 ids = this.getUpdateItemIds(); 365 366 if (log.isLoggable(Level.SEVERE)) { 367 log.severe("Exchange SyncSource " + 368 sourceURI + 369 " - getting updated sync items" ); 370 } 371 372 if(ids == null || !(ids.length > 0)) { 373 return new SyncItem[0]; 374 } 375 376 return filterSyncItems(principal, ids, SyncItemState.UPDATED); 377 378 } 379 380 public SyncItemKey[] getUpdatedSyncItemKeys(Principal principal, 381 Timestamp since) 382 throws SyncSourceException { 383 return null; 384 } 385 386 389 public void removeSyncItem(Principal principal, SyncItem syncItem) 390 throws SyncSourceException { 391 392 Calendar calendar = null ; 393 394 String username = null ; 395 String credentials = null ; 396 397 String id = null ; 398 String href = null ; 399 400 id = syncItem.getKey().getKeyAsString() ; 401 402 username = ((Sync4jPrincipal) principal).getUsername() ; 403 credentials = ((Sync4jPrincipal) principal).getEncodedCredentials() ; 404 405 href = getHref(id); 406 407 try { 408 if (href != null) { 409 calendar = new Calendar(id) ; 410 calendar.setHref(href) ; 411 this.cm.removeCalendar(calendar , 412 username , 413 credentials , 414 exchangeFolder) ; 415 toChangedItems(calendar.getId(), ITEM_REMOVE); 416 } else { 417 toChangedItems(calendar.getId(), ITEM_REMOVE_ERROR); 418 } 419 } catch (DataAccessException e) { 420 toChangedItems(calendar.getId(), ITEM_REMOVE_ERROR); 421 throw new SyncSourceException("Error reading items", e); 422 } 423 424 if (log.isLoggable(Level.SEVERE)) { 425 log.severe("Exchange SyncSource " + 426 sourceURI + 427 " - removing sync items" ); 428 } 429 430 431 } 432 433 436 public void removeSyncItems(Principal principal, SyncItem[] syncItems) 437 throws SyncSourceException { 438 439 ArrayList syncItemsInError = new ArrayList (); 440 441 for (int i=0, l = syncItems.length ; i < l; ++i) { 442 try { 443 removeSyncItem(principal, syncItems[i]); 444 } catch (SyncSourceException e) { 445 syncItemsInError.add(syncItems[i]); 446 } 447 } 449 if (syncItemsInError.size() > 0) { 450 throw new SyncSourceException( "Error deleting the following items: " 451 + syncItemsInError.toString() 452 ); 453 } 454 455 if (log.isLoggable(Level.SEVERE)) { 456 log.severe("Exchange SyncSource " + 457 sourceURI + 458 " - removing sync items" ); 459 } 460 461 } 462 463 466 public SyncItem[] getAllSyncItems(Principal principal) 467 throws SyncSourceException { 468 return filterSyncItems(principal, SyncItemState.NEW); 469 } 470 471 475 public SyncItem getSyncItemFromTwin(Principal principal, SyncItem syncItem) 476 throws SyncSourceException { 477 478 String username = ((Sync4jPrincipal) principal).getUsername(); 479 String credentials = ((Sync4jPrincipal) principal).getEncodedCredentials(); 480 SyncItem syncTwin = null; 481 482 try { 483 this.cm = getCalendarManager(); 484 Calendar calendar = getCalendarFromSyncItem(syncItem); 485 Calendar twin = this.cm.getCalendarTwin(calendar, 486 username, 487 credentials, 488 exchangeFolder); 489 490 if (twin != null) { 491 syncTwin = getSyncItem(twin); 492 } 493 494 } catch (DataAccessException ex) { 495 throw new SyncSourceException("Error getting twin", ex); 496 } 497 498 return syncTwin; 499 } 500 501 502 507 public SyncItem[] getSyncItemsFromTwins(Principal principal, 508 SyncItem[] syncItems) throws 509 SyncSourceException { 510 511 ArrayList items = new ArrayList (); 512 513 for (int i = 0, l = syncItems.length; i < l; ++i) { 514 items.add(getSyncItemFromTwin(principal, syncItems[i])); 515 } 516 517 return (SyncItem[]) items.toArray(new SyncItem[items.size()]); 518 519 } 520 522 private Calendar getCalendar(String id , 523 String content , 524 Date t ) 525 throws SyncSourceException { 526 527 Calendar c = new Calendar(id); 528 529 c.setLastUpdate(t) ; 530 531 if (content != null && content.length() > 0) { 532 533 if (isEncode()) { 534 content = new String (Base64.decode(content)); 535 } 536 537 if (TYPE_ICAL.equals(getType())) { 538 ical2Calendar(content, c); 539 } else { 540 sife2Calendar(content, c); 541 } 542 } 543 544 return c; 545 546 } 547 548 549 550 563 private SyncItem[] filterSyncItems(Principal principal , 564 String [] ids , 565 char state) 566 throws SyncSourceException { 567 568 Calendar[] calendars = null ; 569 570 String username = null ; 571 String credentials = null ; 572 573 username = ((Sync4jPrincipal) principal).getUsername() ; 574 credentials = ((Sync4jPrincipal) principal).getEncodedCredentials() ; 575 576 try { 577 578 this.cm = getCalendarManager(); 579 580 581 calendars = this.cm.getCalendars (username , 582 credentials , 583 ids , 584 this.exchangeFolder) ; 585 586 } catch (DataAccessException e) { 587 throw new SyncSourceException("Error reading calendar: " + 588 e.getMessage(), e); 589 } 590 591 return getSyncItems(calendars, state); 592 593 } 594 595 608 private SyncItem[] filterSyncItems(Principal principal , 609 char state) 610 throws SyncSourceException { 611 612 Calendar[] calendars = null ; 613 614 String username = null ; 615 String credentials = null ; 616 617 username = ((Sync4jPrincipal) principal).getUsername() ; 618 credentials = ((Sync4jPrincipal) principal).getEncodedCredentials() ; 619 620 try { 621 622 this.cm = getCalendarManager(); 623 624 calendars = this.cm.getAllCalendars (username , 625 credentials , 626 this.exchangeFolder) ; 627 628 } catch (DataAccessException e) { 629 throw new SyncSourceException("Error reading calendar: " + 630 e.getMessage(), e); 631 } 632 633 return getSyncItems(calendars, state); 634 635 } 636 637 645 private SyncItem[] getSyncItems(Calendar[] calendars, 646 char state) 647 throws SyncSourceException { 648 649 SyncItem[] syncItems = null; 650 651 int l = calendars.length; 652 653 syncItems = new SyncItem [l]; 654 655 for (int i=0; i < l; i++) { 656 calendars [i].setModificationStatus(state) ; 657 syncItems [i] = getSyncItem(calendars[i]) ; 658 } 659 660 return syncItems; 661 662 } 663 664 671 private SyncItem getSyncItem(Calendar exchangeCalendar) 672 throws SyncSourceException { 673 674 SyncItem syncItem = null ; 675 String content = null ; 676 677 sync4j.foundation.pdi.event.Calendar 678 calendar = new sync4j.foundation.pdi.event.Calendar(); 679 680 syncItem = new SyncItemImpl(this , 681 exchangeCalendar.getId () , 682 exchangeCalendar.getModificationStatus ()); 683 684 calendar.setEvent(exchangeCalendar); 685 if (TYPE_ICAL.equals(getType())) { 686 content = calendar2ical(calendar); 687 } else { 688 content = calendar2sife(calendar); 689 } 690 691 if (this.isEncode()) { 692 syncItem.setProperty( 693 new SyncProperty(SyncItem.PROPERTY_BINARY_CONTENT, 694 Base64.encode(content.getBytes()) 695 )); 696 697 syncItem.setProperty( 698 new SyncProperty(SyncItem.PROPERTY_FORMAT,"b64") 699 ); 700 701 } else { 702 syncItem.setProperty( 703 new SyncProperty(SyncItem.PROPERTY_BINARY_CONTENT, 704 content.getBytes()) 705 ); 706 } 707 708 return syncItem; 709 710 } 711 712 721 private String calendar2ical(sync4j.foundation.pdi.event.Calendar c) 722 throws SyncSourceException { 723 try { 724 return new CalendarToIcalendar(deviceTimeZone, deviceCharset).convert(c); 725 } catch (ConverterException e) { 726 throw new SyncSourceException( "Conversion error for item " 727 + ((Calendar)c.getEvent()).getId() 728 + ": " 729 + e.getMessage() 730 , e 731 ); 732 } 733 } 734 735 744 private String calendar2sife(sync4j.foundation.pdi.event.Calendar c) 745 throws SyncSourceException { 746 try { 747 return new CalendarToXML(deviceTimeZone, deviceCharset).convert(c); 748 } catch (ConverterException e) { 749 throw new SyncSourceException( "Convertion error for item " 750 + ((Calendar)c.getEvent()).getId() 751 + ": " 752 + e.getMessage() 753 , e 754 ); 755 } 756 } 757 758 759 768 private void ical2Calendar (String content, Calendar c) 769 throws SyncSourceException { 770 771 if ((content == null) || (content.length()==0)) { 775 return; 776 } 777 778 779 ByteArrayInputStream is = null ; 780 ICalendarParser parser = null ; 781 782 sync4j.foundation.pdi.event.Calendar calendar = null ; 783 sync4j.foundation.pdi.event.Event event = null ; 784 785 try { 786 787 792 content = content.replaceAll("=\r\n","\r\n "); 793 794 is = new ByteArrayInputStream (content.getBytes()); 795 796 798 parser = new ICalendarParser(is, deviceTimeZoneDescr, deviceCharset); 799 parser.setLogger(log); 800 801 calendar = (sync4j.foundation.pdi.event.Calendar)parser.iCalendar(); 802 803 event = calendar.getEvent(); 807 808 c.setAlarm(event.getAlarm()); 809 c.setCategories(event.getCategories()); 810 c.setClassEvent(event.getClassEvent()); 811 c.setDescription(event.getDescription()); 812 c.setLatitude(event.getLatitude()); 813 c.setLongitude(event.getLongitude()); 814 c.setLocation(event.getLocation()); 815 c.setPriority(event.getPriority()); 816 c.setStatus(event.getStatus()); 817 c.setSummary(event.getSummary()); 818 c.setDtEnd(event.getDtEnd()); 819 c.setDtStart(event.getDtStart()); 820 c.setDuration(event.getDuration()); 821 c.setTransp(event.getTransp()); 822 c.setOrganizer(event.getOrganizer()); 823 c.setUrl(event.getUrl()); 824 c.setUid(event.getUid()); 825 c.setRrule(event.getRrule()); 826 c.setContact(event.getContact()); 827 c.setCreated(event.getCreated()); 828 c.setDtStamp(event.getDtStamp()); 829 c.setLastModified(event.getLastModified()); 830 c.setSequence(event.getSequence()); 831 c.setXTag(event.getXTags()); 832 c.setAllDay(new Boolean (event.isAllDay())); 833 c.setMeetingStatus(event.getMeetingStatus()); 834 c.setMileage(event.getMileage()); 835 c.setReminder(event.getReminder()); 836 c.setReplyTime(event.getReplyTime()); 837 c.setRecurrencePattern(event.getRecurrencePattern()); 838 839 } catch (Exception e) { 840 throw new SyncSourceException( "Convertion error for item " 841 + c.getId() 842 + ": " 843 + e.getMessage() 844 , e 845 ); 846 } finally { 847 if (is != null) try { is.close(); } catch (Exception e) {} 848 } 849 } 850 851 852 862 private void sife2Calendar (String content, Calendar c) 863 throws SyncSourceException { 864 if ((content == null) || (content.length()==0)) { 868 return; 869 } 870 871 872 ByteArrayInputStream is = null ; 873 XMLEventParser parser = null ; 874 875 sync4j.foundation.pdi.event.Calendar calendar = null ; 876 sync4j.foundation.pdi.event.Event event = null ; 877 878 try { 879 is = new ByteArrayInputStream (content.getBytes()); 880 881 883 parser = new XMLEventParser(is); 884 885 calendar = (sync4j.foundation.pdi.event.Calendar)parser.parse(); 886 887 event = calendar.getEvent(); 891 892 c.setAlarm(event.getAlarm()); 893 c.setCategories(event.getCategories()); 894 c.setClassEvent(event.getClassEvent()); 895 c.setDescription(event.getDescription()); 896 c.setLatitude(event.getLatitude()); 897 c.setLongitude(event.getLongitude()); 898 c.setLocation(event.getLocation()); 899 c.setPriority(event.getPriority()); 900 c.setStatus(event.getStatus()); 901 c.setSummary(event.getSummary()); 902 c.setDtEnd(event.getDtEnd()); 903 c.setDtStart(event.getDtStart()); 904 c.setDuration(event.getDuration()); 905 c.setTransp(event.getTransp()); 906 c.setOrganizer(event.getOrganizer()); 907 c.setUrl(event.getUrl()); 908 c.setUid(event.getUid()); 909 c.setRrule(event.getRrule()); 910 c.setContact(event.getContact()); 911 c.setCreated(event.getCreated()); 912 c.setDtStamp(event.getDtStamp()); 913 c.setLastModified(event.getLastModified()); 914 c.setSequence(event.getSequence()); 915 c.setXTag(event.getXTags()); 916 c.setAllDay(new Boolean (event.isAllDay())); 917 c.setMeetingStatus(event.getMeetingStatus()); 918 c.setMileage(event.getMileage()); 919 c.setReminder(event.getReminder()); 920 c.setReplyTime(event.getReplyTime()); 921 c.setRecurrencePattern(event.getRecurrencePattern()); 922 923 } catch (Exception e) { 924 throw new SyncSourceException( "Parsing error for item " 925 + c.getId() 926 + ": " 927 + e.getMessage() 928 , e 929 ); 930 } finally { 931 if (is != null) try { is.close(); } catch (Exception e) {} 932 } 933 } 934 935 942 private CalendarManager getCalendarManager() 943 throws DataAccessException { 944 945 if (this.cm == null) { 946 this.cm = new CalendarManager(this.getHost() , 947 this.getPort()); 948 } 949 950 return this.cm; 951 952 } 953 954 959 private Calendar getCalendarFromSyncItem(SyncItem syncItem) 960 throws SyncSourceException { 961 962 String content = null; 963 Calendar calendar = null; 964 965 String itemKey = syncItem.getKey().getKeyAsString(); 966 967 byte[] itemContent = 968 (byte[]) syncItem.getPropertyValue( 969 SyncItem.PROPERTY_BINARY_CONTENT); 970 971 if (itemContent == null) { 972 itemContent = new byte[0]; 973 } 974 975 content = new String (itemContent); 976 977 Date t = 978 (Timestamp ) syncItem.getPropertyValue(SyncItem.PROPERTY_TIMESTAMP); 979 980 calendar = getCalendar(itemKey, content, t); 981 982 return calendar; 983 } 984 } 985 | Popular Tags |