1 17 package org.alfresco.repo.search.impl.lucene; 18 19 import java.io.File ; 20 import java.util.ArrayList ; 21 import java.util.HashMap ; 22 import java.util.List ; 23 import java.util.Map ; 24 25 import javax.transaction.RollbackException ; 26 import javax.transaction.SystemException ; 27 import javax.transaction.Transaction ; 28 import javax.transaction.xa.XAException ; 29 import javax.transaction.xa.XAResource ; 30 import javax.transaction.xa.Xid ; 31 32 import org.alfresco.error.AlfrescoRuntimeException; 33 import org.alfresco.repo.search.IndexerException; 34 import org.alfresco.repo.search.QueryRegisterComponent; 35 import org.alfresco.repo.search.SearcherException; 36 import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; 37 import org.alfresco.repo.search.transaction.LuceneIndexLock; 38 import org.alfresco.repo.search.transaction.SimpleTransaction; 39 import org.alfresco.repo.search.transaction.SimpleTransactionManager; 40 import org.alfresco.repo.transaction.AlfrescoTransactionSupport; 41 import org.alfresco.repo.transaction.TransactionUtil; 42 import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; 43 import org.alfresco.service.cmr.dictionary.DictionaryService; 44 import org.alfresco.service.cmr.repository.ContentService; 45 import org.alfresco.service.cmr.repository.NodeService; 46 import org.alfresco.service.cmr.repository.StoreRef; 47 import org.alfresco.service.namespace.NamespaceService; 48 import org.alfresco.service.transaction.TransactionService; 49 import org.alfresco.util.GUID; 50 import org.apache.commons.io.FileUtils; 51 import org.apache.commons.logging.Log; 52 import org.apache.commons.logging.LogFactory; 53 import org.apache.lucene.index.IndexWriter; 54 import org.apache.lucene.search.BooleanQuery; 55 import org.apache.lucene.store.Lock; 56 import org.quartz.Job; 57 import org.quartz.JobDataMap; 58 import org.quartz.JobExecutionContext; 59 import org.quartz.JobExecutionException; 60 61 73 74 public class LuceneIndexerAndSearcherFactory implements LuceneIndexerAndSearcher, XAResource 75 { 76 private DictionaryService dictionaryService; 77 78 private NamespaceService nameSpaceService; 79 80 private int queryMaxClauses; 81 82 private int indexerBatchSize; 83 84 private int indexerMinMergeDocs; 85 86 private int indexerMergeFactor; 87 88 private int indexerMaxMergeDocs; 89 90 private String lockDirectory; 91 92 97 98 private static Map <Xid , Map <StoreRef, LuceneIndexer>> activeIndexersInGlobalTx = new HashMap <Xid , Map <StoreRef, LuceneIndexer>>(); 99 100 103 private static Map <Xid , Map <StoreRef, LuceneIndexer>> suspendedIndexersInGlobalTx = new HashMap <Xid , Map <StoreRef, LuceneIndexer>>(); 104 105 108 109 private static ThreadLocal <Map <StoreRef, LuceneIndexer>> threadLocalIndexers = new ThreadLocal <Map <StoreRef, LuceneIndexer>>(); 110 111 114 115 private int timeout = DEFAULT_TIMEOUT; 116 117 120 private static final int DEFAULT_TIMEOUT = 600000; 121 122 125 126 private NodeService nodeService; 127 128 private LuceneIndexLock luceneIndexLock; 129 130 private FullTextSearchIndexer luceneFullTextSearchIndexer; 131 132 private String indexRootLocation; 133 134 private ContentService contentService; 135 136 private QueryRegisterComponent queryRegister; 137 138 private int indexerMaxFieldLength; 139 140 143 144 public LuceneIndexerAndSearcherFactory() 145 { 146 super(); 147 } 148 149 154 155 public void setNodeService(NodeService nodeService) 156 { 157 this.nodeService = nodeService; 158 } 159 160 public void setDictionaryService(DictionaryService dictionaryService) 161 { 162 this.dictionaryService = dictionaryService; 163 } 164 165 public void setNameSpaceService(NamespaceService nameSpaceService) 166 { 167 this.nameSpaceService = nameSpaceService; 168 } 169 170 public void setLuceneIndexLock(LuceneIndexLock luceneIndexLock) 171 { 172 this.luceneIndexLock = luceneIndexLock; 173 } 174 175 public void setLuceneFullTextSearchIndexer(FullTextSearchIndexer luceneFullTextSearchIndexer) 176 { 177 this.luceneFullTextSearchIndexer = luceneFullTextSearchIndexer; 178 } 179 180 public void setIndexRootLocation(String indexRootLocation) 181 { 182 this.indexRootLocation = indexRootLocation; 183 } 184 185 public void setQueryRegister(QueryRegisterComponent queryRegister) 186 { 187 this.queryRegister = queryRegister; 188 } 189 190 196 197 private boolean inGlobalTransaction() 198 { 199 try 200 { 201 return SimpleTransactionManager.getInstance().getTransaction() != null; 202 } 203 catch (SystemException e) 204 { 205 return false; 206 } 207 } 208 209 215 private SimpleTransaction getTransaction() throws IndexerException 216 { 217 try 218 { 219 return SimpleTransactionManager.getInstance().getTransaction(); 220 } 221 catch (SystemException e) 222 { 223 throw new IndexerException("Failed to get transaction", e); 224 } 225 } 226 227 234 public LuceneIndexer getIndexer(StoreRef storeRef) throws IndexerException 235 { 236 AlfrescoTransactionSupport.bindLucene(this); 240 241 if (inGlobalTransaction()) 242 { 243 SimpleTransaction tx = getTransaction(); 244 Map <StoreRef, LuceneIndexer> indexers = activeIndexersInGlobalTx.get(tx); 246 if (indexers == null) 247 { 248 if (suspendedIndexersInGlobalTx.containsKey(tx)) 249 { 250 throw new IndexerException("Trying to obtain an index for a suspended transaction."); 251 } 252 indexers = new HashMap <StoreRef, LuceneIndexer>(); 253 activeIndexersInGlobalTx.put(tx, indexers); 254 try 255 { 256 tx.enlistResource(this); 257 } 258 catch (IllegalStateException e) 260 { 261 throw new IndexerException("", e); 262 } 263 catch (RollbackException e) 264 { 265 throw new IndexerException("", e); 266 } 267 catch (SystemException e) 268 { 269 throw new IndexerException("", e); 270 } 271 } 272 LuceneIndexer indexer = indexers.get(storeRef); 273 if (indexer == null) 274 { 275 indexer = createIndexer(storeRef, getTransactionId(tx, storeRef)); 276 indexers.put(storeRef, indexer); 277 } 278 return indexer; 279 } 280 else 281 { 283 return getThreadLocalIndexer(storeRef); 284 } 285 286 } 287 288 private LuceneIndexer getThreadLocalIndexer(StoreRef storeRef) 289 { 290 Map <StoreRef, LuceneIndexer> indexers = threadLocalIndexers.get(); 291 if (indexers == null) 292 { 293 indexers = new HashMap <StoreRef, LuceneIndexer>(); 294 threadLocalIndexers.set(indexers); 295 } 296 LuceneIndexer indexer = indexers.get(storeRef); 297 if (indexer == null) 298 { 299 indexer = createIndexer(storeRef, GUID.generate()); 300 indexers.put(storeRef, indexer); 301 } 302 return indexer; 303 } 304 305 311 private static String getTransactionId(Transaction tx, StoreRef storeRef) 312 { 313 if (tx instanceof SimpleTransaction) 314 { 315 SimpleTransaction simpleTx = (SimpleTransaction) tx; 316 return simpleTx.getGUID(); 317 } 318 else 319 { 320 Map <StoreRef, LuceneIndexer> indexers = threadLocalIndexers.get(); 321 if (indexers != null) 322 { 323 LuceneIndexer indexer = indexers.get(storeRef); 324 if (indexer != null) 325 { 326 return indexer.getDeltaId(); 327 } 328 } 329 return null; 330 } 331 } 332 333 340 private LuceneIndexerImpl createIndexer(StoreRef storeRef, String deltaId) 341 { 342 LuceneIndexerImpl indexer = LuceneIndexerImpl.getUpdateIndexer(storeRef, deltaId, this); 343 indexer.setNodeService(nodeService); 344 indexer.setDictionaryService(dictionaryService); 345 indexer.setLuceneIndexLock(luceneIndexLock); 346 indexer.setLuceneFullTextSearchIndexer(luceneFullTextSearchIndexer); 347 indexer.setContentService(contentService); 348 return indexer; 349 } 350 351 354 public LuceneSearcher getSearcher(StoreRef storeRef, boolean searchDelta) throws SearcherException 355 { 356 String deltaId = null; 357 LuceneIndexer indexer = null; 358 if (searchDelta) 359 { 360 deltaId = getTransactionId(getTransaction(), storeRef); 361 if (deltaId != null) 362 { 363 indexer = getIndexer(storeRef); 364 } 365 } 366 LuceneSearcher searcher = getSearcher(storeRef, indexer); 367 return searcher; 368 } 369 370 378 private LuceneSearcher getSearcher(StoreRef storeRef, LuceneIndexer indexer) throws SearcherException 379 { 380 LuceneSearcherImpl searcher = LuceneSearcherImpl.getSearcher(storeRef, indexer, this); 381 searcher.setNamespacePrefixResolver(nameSpaceService); 382 searcher.setLuceneIndexLock(luceneIndexLock); 383 searcher.setNodeService(nodeService); 384 searcher.setDictionaryService(dictionaryService); 385 searcher.setQueryRegister(queryRegister); 386 return searcher; 387 } 388 389 392 393 public void commit(Xid xid, boolean onePhase) throws XAException 394 { 395 try 396 { 397 Map <StoreRef, LuceneIndexer> indexers = activeIndexersInGlobalTx.get(xid); 400 if (indexers == null) 401 { 402 if (suspendedIndexersInGlobalTx.containsKey(xid)) 403 { 404 throw new XAException ("Trying to commit indexes for a suspended transaction."); 405 } 406 else 407 { 408 return; 410 } 411 } 412 413 if (onePhase) 414 { 415 if (indexers.size() == 0) 416 { 417 return; 418 } 419 else if (indexers.size() == 1) 420 { 421 for (LuceneIndexer indexer : indexers.values()) 422 { 423 indexer.commit(); 424 } 425 return; 426 } 427 else 428 { 429 throw new XAException ("Trying to do one phase commit on more than one index"); 430 } 431 } 432 else 433 { 435 for (LuceneIndexer indexer : indexers.values()) 436 { 437 indexer.commit(); 438 } 439 return; 440 } 441 } finally 442 { 443 activeIndexersInGlobalTx.remove(xid); 444 } 445 } 446 447 public void end(Xid xid, int flag) throws XAException 448 { 449 Map <StoreRef, LuceneIndexer> indexers = activeIndexersInGlobalTx.get(xid); 450 if (indexers == null) 451 { 452 if (suspendedIndexersInGlobalTx.containsKey(xid)) 453 { 454 throw new XAException ("Trying to commit indexes for a suspended transaction."); 455 } 456 else 457 { 458 return; 460 } 461 } 462 if (flag == XAResource.TMSUSPEND) 463 { 464 activeIndexersInGlobalTx.remove(xid); 465 suspendedIndexersInGlobalTx.put(xid, indexers); 466 } 467 else if (flag == TMFAIL) 468 { 469 activeIndexersInGlobalTx.remove(xid); 470 suspendedIndexersInGlobalTx.remove(xid); 471 } 472 else if (flag == TMSUCCESS) 473 { 474 activeIndexersInGlobalTx.remove(xid); 475 } 476 } 477 478 public void forget(Xid xid) throws XAException 479 { 480 activeIndexersInGlobalTx.remove(xid); 481 suspendedIndexersInGlobalTx.remove(xid); 482 } 483 484 public int getTransactionTimeout() throws XAException 485 { 486 return timeout; 487 } 488 489 public boolean isSameRM(XAResource xar) throws XAException 490 { 491 return (xar instanceof LuceneIndexerAndSearcherFactory); 492 } 493 494 public int prepare(Xid xid) throws XAException 495 { 496 Map <StoreRef, LuceneIndexer> indexers = activeIndexersInGlobalTx.get(xid); 498 if (indexers == null) 499 { 500 if (suspendedIndexersInGlobalTx.containsKey(xid)) 501 { 502 throw new XAException ("Trying to commit indexes for a suspended transaction."); 503 } 504 else 505 { 506 return XAResource.XA_OK; 508 } 509 } 510 boolean isPrepared = true; 511 boolean isModified = false; 512 for (LuceneIndexer indexer : indexers.values()) 513 { 514 try 515 { 516 isModified |= indexer.isModified(); 517 indexer.prepare(); 518 } 519 catch (IndexerException e) 520 { 521 isPrepared = false; 522 } 523 } 524 if (isPrepared) 525 { 526 if (isModified) 527 { 528 return XAResource.XA_OK; 529 } 530 else 531 { 532 return XAResource.XA_RDONLY; 533 } 534 } 535 else 536 { 537 throw new XAException ("Failed to prepare: requires rollback"); 538 } 539 } 540 541 public Xid [] recover(int arg0) throws XAException 542 { 543 return new Xid [0]; 550 } 551 552 public void rollback(Xid xid) throws XAException 553 { 554 try 556 { 557 Map <StoreRef, LuceneIndexer> indexers = activeIndexersInGlobalTx.get(xid); 558 if (indexers == null) 559 { 560 if (suspendedIndexersInGlobalTx.containsKey(xid)) 561 { 562 throw new XAException ("Trying to commit indexes for a suspended transaction."); 563 } 564 else 565 { 566 return; 568 } 569 } 570 for (LuceneIndexer indexer : indexers.values()) 571 { 572 indexer.rollback(); 573 } 574 } finally 575 { 576 activeIndexersInGlobalTx.remove(xid); 577 } 578 } 579 580 public boolean setTransactionTimeout(int timeout) throws XAException 581 { 582 this.timeout = timeout; 583 return true; 584 } 585 586 public void start(Xid xid, int flag) throws XAException 587 { 588 Map <StoreRef, LuceneIndexer> active = activeIndexersInGlobalTx.get(xid); 589 Map <StoreRef, LuceneIndexer> suspended = suspendedIndexersInGlobalTx.get(xid); 590 if (flag == XAResource.TMJOIN) 591 { 592 if ((active != null) && (suspended == null)) 594 { 595 return; 596 } 597 else 598 { 599 throw new XAException ("Trying to rejoin transaction in an invalid state"); 600 } 601 602 } 603 else if (flag == XAResource.TMRESUME) 604 { 605 if ((active == null) && (suspended != null)) 607 { 608 suspendedIndexersInGlobalTx.remove(xid); 609 activeIndexersInGlobalTx.put(xid, suspended); 610 return; 611 } 612 else 613 { 614 throw new XAException ("Trying to rejoin transaction in an invalid state"); 615 } 616 617 } 618 else if (flag == XAResource.TMNOFLAGS) 619 { 620 if ((active == null) && (suspended == null)) 621 { 622 return; 623 } 624 else 625 { 626 throw new XAException ("Trying to start an existing or suspended transaction"); 627 } 628 } 629 else 630 { 631 throw new XAException ("Unkown flags for start " + flag); 632 } 633 634 } 635 636 639 640 643 644 public void commit() throws IndexerException 645 { 646 try 647 { 648 Map <StoreRef, LuceneIndexer> indexers = threadLocalIndexers.get(); 649 if (indexers != null) 650 { 651 for (LuceneIndexer indexer : indexers.values()) 652 { 653 try 654 { 655 indexer.commit(); 656 } 657 catch (IndexerException e) 658 { 659 rollback(); 660 throw e; 661 } 662 } 663 } 664 } finally 665 { 666 if (threadLocalIndexers.get() != null) 667 { 668 threadLocalIndexers.get().clear(); 669 threadLocalIndexers.set(null); 670 } 671 } 672 } 673 674 679 public int prepare() throws IndexerException 680 { 681 boolean isPrepared = true; 682 boolean isModified = false; 683 Map <StoreRef, LuceneIndexer> indexers = threadLocalIndexers.get(); 684 if (indexers != null) 685 { 686 for (LuceneIndexer indexer : indexers.values()) 687 { 688 try 689 { 690 isModified |= indexer.isModified(); 691 indexer.prepare(); 692 } 693 catch (IndexerException e) 694 { 695 isPrepared = false; 696 throw new IndexerException("Failed to prepare: requires rollback", e); 697 } 698 } 699 } 700 if (isPrepared) 701 { 702 if (isModified) 703 { 704 return XAResource.XA_OK; 705 } 706 else 707 { 708 return XAResource.XA_RDONLY; 709 } 710 } 711 else 712 { 713 throw new IndexerException("Failed to prepare: requires rollback"); 714 } 715 } 716 717 720 public void rollback() 721 { 722 Map <StoreRef, LuceneIndexer> indexers = threadLocalIndexers.get(); 723 724 if (indexers != null) 725 { 726 for (LuceneIndexer indexer : indexers.values()) 727 { 728 try 729 { 730 indexer.rollback(); 731 } 732 catch (IndexerException e) 733 { 734 735 } 736 } 737 } 738 739 if (threadLocalIndexers.get() != null) 740 { 741 threadLocalIndexers.get().clear(); 742 threadLocalIndexers.set(null); 743 } 744 745 } 746 747 public void flush() 748 { 749 Map <StoreRef, LuceneIndexer> indexers = threadLocalIndexers.get(); 751 752 if (indexers != null) 753 { 754 for (LuceneIndexer indexer : indexers.values()) 755 { 756 indexer.flushPending(); 757 } 758 } 759 } 760 761 public void setContentService(ContentService contentService) 762 { 763 this.contentService = contentService; 764 } 765 766 public String getIndexRootLocation() 767 { 768 return indexRootLocation; 769 } 770 771 public int getIndexerBatchSize() 772 { 773 return indexerBatchSize; 774 } 775 776 public void setIndexerBatchSize(int indexerBatchSize) 777 { 778 this.indexerBatchSize = indexerBatchSize; 779 } 780 781 public int getIndexerMaxMergeDocs() 782 { 783 return indexerMaxMergeDocs; 784 } 785 786 public void setIndexerMaxMergeDocs(int indexerMaxMergeDocs) 787 { 788 this.indexerMaxMergeDocs = indexerMaxMergeDocs; 789 } 790 791 public int getIndexerMergeFactor() 792 { 793 return indexerMergeFactor; 794 } 795 796 public void setIndexerMergeFactor(int indexerMergeFactor) 797 { 798 this.indexerMergeFactor = indexerMergeFactor; 799 } 800 801 public int getIndexerMinMergeDocs() 802 { 803 return indexerMinMergeDocs; 804 } 805 806 public void setIndexerMinMergeDocs(int indexerMinMergeDocs) 807 { 808 this.indexerMinMergeDocs = indexerMinMergeDocs; 809 } 810 811 public String getLockDirectory() 812 { 813 return lockDirectory; 814 } 815 816 public void setLockDirectory(String lockDirectory) 817 { 818 this.lockDirectory = lockDirectory; 819 System.setProperty("org.apache.lucene.lockdir", lockDirectory); 822 File lockDir = new File (lockDirectory); 824 if (!lockDir.exists()) 825 { 826 lockDir.mkdirs(); 827 } 828 830 File [] children = lockDir.listFiles(); 831 if (children != null) 832 { 833 for (int i = 0; i < children.length; i++) 834 { 835 File child = children[i]; 836 if (child.isFile()) 837 { 838 if (child.exists() && !child.delete() && child.exists()) 839 { 840 throw new IllegalStateException ("Failed to delete " + child); 841 } 842 } 843 } 844 } 845 } 846 847 public int getQueryMaxClauses() 848 { 849 return queryMaxClauses; 850 } 851 852 public void setQueryMaxClauses(int queryMaxClauses) 853 { 854 this.queryMaxClauses = queryMaxClauses; 855 BooleanQuery.setMaxClauseCount(this.queryMaxClauses); 856 } 857 858 public void setWriteLockTimeout(long timeout) 859 { 860 IndexWriter.WRITE_LOCK_TIMEOUT = timeout; 861 } 862 863 public void setCommitLockTimeout(long timeout) 864 { 865 IndexWriter.COMMIT_LOCK_TIMEOUT = timeout; 866 } 867 868 public void setLockPollInterval(long time) 869 { 870 Lock.LOCK_POLL_INTERVAL = time; 871 } 872 873 public int getIndexerMaxFieldLength() 874 { 875 return indexerMaxFieldLength; 876 } 877 878 public void setIndexerMaxFieldLength(int indexerMaxFieldLength) 879 { 880 this.indexerMaxFieldLength = indexerMaxFieldLength; 881 System.setProperty("org.apache.lucene.maxFieldLength", "" + indexerMaxFieldLength); 882 } 883 884 893 public static class LuceneIndexBackupComponent 894 { 895 private static Log logger = LogFactory.getLog(LuceneIndexerAndSearcherFactory.class); 896 897 private TransactionService transactionService; 898 private LuceneIndexerAndSearcherFactory factory; 899 private NodeService nodeService; 900 private String targetLocation; 901 902 public LuceneIndexBackupComponent() 903 { 904 } 905 906 911 public void setTransactionService(TransactionService transactionService) 912 { 913 this.transactionService = transactionService; 914 } 915 916 921 public void setFactory(LuceneIndexerAndSearcherFactory factory) 922 { 923 this.factory = factory; 924 } 925 926 931 public void setNodeService(NodeService nodeService) 932 { 933 this.nodeService = nodeService; 934 } 935 936 941 public void setTargetLocation(String targetLocation) 942 { 943 this.targetLocation = targetLocation; 944 } 945 946 949 public void backup() 950 { 951 TransactionWork<Object > backupWork = new TransactionWork<Object >() 952 { 953 public Object doWork() throws Exception 954 { 955 backupImpl(); 956 return null; 957 } 958 }; 959 TransactionUtil.executeInUserTransaction(transactionService, backupWork); 960 } 961 962 private void backupImpl() 963 { 964 File targetDir = new File (targetLocation); 966 if (targetDir.exists() && !targetDir.isDirectory()) 967 { 968 throw new AlfrescoRuntimeException("Target location is a file and not a directory: " + targetDir); 969 } 970 File targetParentDir = targetDir.getParentFile(); 971 if (targetParentDir == null) 972 { 973 throw new AlfrescoRuntimeException("Target location may not be a root directory: " + targetDir); 974 } 975 File tempDir = new File (targetParentDir, "indexbackup_temp"); 976 977 List <StoreRef> storeRefs = nodeService.getStores(); 979 980 List <StoreRef> lockedStores = new ArrayList <StoreRef>(storeRefs.size()); 982 try 983 { 984 for (StoreRef storeRef : storeRefs) 985 { 986 factory.luceneIndexLock.getWriteLock(storeRef); 987 lockedStores.add(storeRef); 988 } 989 File indexRootDir = new File (factory.indexRootLocation); 990 backupDirectory(indexRootDir, tempDir, targetDir); 992 } 993 catch (Throwable e) 994 { 995 throw new AlfrescoRuntimeException("Failed to copy Lucene index root: \n" + 996 " Index root: " + factory.indexRootLocation + "\n" + 997 " Target: " + targetDir, 998 e); 999 } 1000 finally 1001 { 1002 for (StoreRef storeRef : lockedStores) 1003 { 1004 try 1005 { 1006 factory.luceneIndexLock.releaseWriteLock(storeRef); 1007 } 1008 catch (Throwable e) 1009 { 1010 logger.error("Failed to release index lock for store " + storeRef, e); 1011 } 1012 } 1013 } 1014 if (logger.isDebugEnabled()) 1015 { 1016 logger.debug("Backed up Lucene indexes: \n" + 1017 " Target directory: " + targetDir); 1018 } 1019 } 1020 1021 1025 private void backupDirectory(File sourceDir, File tempDir, File targetDir) throws Exception 1026 { 1027 if (!sourceDir.exists()) 1028 { 1029 return; 1031 } 1032 if (tempDir.exists()) 1034 { 1035 FileUtils.deleteDirectory(tempDir); 1036 if (tempDir.exists()) 1037 { 1038 throw new AlfrescoRuntimeException("Temp directory exists and cannot be deleted: " + tempDir); 1039 } 1040 } 1041 FileUtils.copyDirectory(sourceDir, tempDir, true); 1043 if (!tempDir.exists()) 1045 { 1046 throw new AlfrescoRuntimeException("Copy to temp location failed"); 1047 } 1048 FileUtils.deleteDirectory(targetDir); 1050 if (targetDir.exists()) 1051 { 1052 throw new AlfrescoRuntimeException("Failed to delete older files from target location"); 1053 } 1054 tempDir.renameTo(targetDir); 1056 if (!targetDir.exists()) 1058 { 1059 throw new AlfrescoRuntimeException("Failed to rename temporary directory to target backup directory"); 1060 } 1061 } 1062 } 1063 1064 1069 public static class LuceneIndexBackupJob implements Job 1070 { 1071 1072 public static final String KEY_LUCENE_INDEX_BACKUP_COMPONENT = "luceneIndexBackupComponent"; 1073 1074 1077 public void execute(JobExecutionContext context) throws JobExecutionException 1078 { 1079 JobDataMap jobData = context.getJobDetail().getJobDataMap(); 1080 LuceneIndexBackupComponent backupComponent = (LuceneIndexBackupComponent) jobData.get(KEY_LUCENE_INDEX_BACKUP_COMPONENT); 1081 if (backupComponent == null) 1082 { 1083 throw new JobExecutionException("Missing job data: " + KEY_LUCENE_INDEX_BACKUP_COMPONENT); 1084 } 1085 backupComponent.backup(); 1087 } 1088 } 1089} 1090 | Popular Tags |