KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > search > CmsSearchManager


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/search/CmsSearchManager.java,v $
3  * Date : $Date: 2006/03/27 15:13:37 $
4  * Version: $Revision: 1.55 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.search;
33
34 import org.opencms.db.CmsPublishedResource;
35 import org.opencms.file.CmsObject;
36 import org.opencms.file.CmsResource;
37 import org.opencms.file.CmsResourceFilter;
38 import org.opencms.i18n.CmsMessageContainer;
39 import org.opencms.main.CmsEvent;
40 import org.opencms.main.CmsException;
41 import org.opencms.main.CmsIllegalArgumentException;
42 import org.opencms.main.CmsIllegalStateException;
43 import org.opencms.main.CmsLog;
44 import org.opencms.main.I_CmsEventListener;
45 import org.opencms.main.OpenCms;
46 import org.opencms.report.CmsLogReport;
47 import org.opencms.report.I_CmsReport;
48 import org.opencms.scheduler.I_CmsScheduledJob;
49 import org.opencms.search.documents.I_CmsDocumentFactory;
50 import org.opencms.search.documents.I_CmsTermHighlighter;
51 import org.opencms.security.CmsRole;
52 import org.opencms.security.CmsRoleViolationException;
53 import org.opencms.util.CmsStringUtil;
54 import org.opencms.util.CmsUUID;
55
56 import java.io.File JavaDoc;
57 import java.io.IOException JavaDoc;
58 import java.util.ArrayList JavaDoc;
59 import java.util.Collections JavaDoc;
60 import java.util.HashMap JavaDoc;
61 import java.util.Iterator JavaDoc;
62 import java.util.LinkedList JavaDoc;
63 import java.util.List JavaDoc;
64 import java.util.Map JavaDoc;
65
66 import org.apache.commons.collections.map.LRUMap;
67 import org.apache.commons.logging.Log;
68 import org.apache.lucene.analysis.Analyzer;
69 import org.apache.lucene.index.IndexReader;
70 import org.apache.lucene.index.IndexWriter;
71 import org.apache.lucene.search.Similarity;
72 import org.apache.lucene.store.FSDirectory;
73
74 /**
75  * Implements the general management and configuration of the search and
76  * indexing facilities in OpenCms.<p>
77  *
78  * @author Carsten Weinholz
79  * @author Thomas Weckert
80  *
81  * @version $Revision: 1.55 $
82  *
83  * @since 6.0.0
84  */

85 public class CmsSearchManager implements I_CmsScheduledJob, I_CmsEventListener {
86
87     /** Scheduler parameter: Update only a specified list of indexes. */
88     public static final String JavaDoc JOB_PARAM_INDEXLIST = "indexList";
89
90     /** Scheduler parameter: Write the output of the update to the logfile. */
91     public static final String JavaDoc JOB_PARAM_WRITELOG = "writeLog";
92
93     /** The log object for this class. */
94     private static final Log LOG = CmsLog.getLog(CmsSearchManager.class);
95
96     /** The Admin cms object to index Cms resources. */
97     private CmsObject m_adminCms;
98
99     /** Configured analyzers for languages using &lt;analyzer&gt;. */
100     private HashMap JavaDoc m_analyzers;
101
102     /** A map of document factory configurations. */
103     private Map JavaDoc m_documentTypeConfigs;
104
105     /** A map of document factories keyed by their matching Cms resource types and/or mimetypes. */
106     private Map JavaDoc m_documentTypes;
107
108     /** The class used to highlight the search terms in the excerpt of a search result. */
109     private I_CmsTermHighlighter m_highlighter;
110
111     /** A list of search indexes. */
112     private List JavaDoc m_indexes;
113
114     /** Seconds to wait for an index lock. */
115     private int m_indexLockMaxWaitSeconds = 10;
116
117     /** Configured index sources. */
118     private Map JavaDoc m_indexSources;
119
120     /** The max. char. length of the excerpt in the search result. */
121     private int m_maxExcerptLength;
122
123     /** Path to index files below WEB-INF/. */
124     private String JavaDoc m_path;
125
126     /** The cache for storing search results. */
127     private Map JavaDoc m_resultCache;
128
129     /** The result cache size. */
130     private String JavaDoc m_resultCacheSize;
131
132     /** Timeout for abandoning indexing thread. */
133     private String JavaDoc m_timeout;
134
135     /**
136      * Default constructer when called as cron job.<p>
137      */

138     public CmsSearchManager() {
139
140         m_documentTypes = new HashMap JavaDoc();
141         m_documentTypeConfigs = new HashMap JavaDoc();
142         m_analyzers = new HashMap JavaDoc();
143         m_indexes = new ArrayList JavaDoc();
144         m_indexSources = new HashMap JavaDoc();
145
146         if (CmsLog.INIT.isInfoEnabled()) {
147             CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_START_SEARCH_CONFIG_0));
148         }
149     }
150
151     /**
152      * Adds an analyzer.<p>
153      *
154      * @param analyzer an analyzer
155      */

156     public void addAnalyzer(CmsSearchAnalyzer analyzer) {
157
158         m_analyzers.put(analyzer.getLocale(), analyzer);
159
160         if (CmsLog.INIT.isInfoEnabled()) {
161             CmsLog.INIT.info(Messages.get().getBundle().key(
162                 Messages.INIT_ADD_ANALYZER_2,
163                 analyzer.getLocale(),
164                 analyzer.getClassName()));
165         }
166     }
167
168     /**
169      * Adds a document type.<p>
170      *
171      * @param documentType a document type
172      */

173     public void addDocumentTypeConfig(CmsSearchDocumentType documentType) {
174
175         m_documentTypeConfigs.put(documentType.getName(), documentType);
176
177         if (CmsLog.INIT.isInfoEnabled()) {
178             CmsLog.INIT.info(Messages.get().getBundle().key(
179                 Messages.INIT_SEARCH_DOC_TYPES_2,
180                 documentType.getName(),
181                 documentType.getClassName()));
182         }
183     }
184
185     /**
186      * Adds a search index to the configuration.<p>
187      *
188      * @param searchIndex the search index to add
189      */

190     public void addSearchIndex(CmsSearchIndex searchIndex) {
191
192         if (searchIndex.getSources() == null || searchIndex.getPath() == null) {
193             if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) {
194                 try {
195                     searchIndex.initialize();
196                 } catch (CmsSearchException e) {
197                     // should never happen
198
}
199             }
200         }
201
202         // name: not null or emtpy and unique
203
String JavaDoc name = searchIndex.getName();
204         if (CmsStringUtil.isEmptyOrWhitespaceOnly(name)) {
205             throw new CmsIllegalArgumentException(Messages.get().container(
206                 Messages.ERR_SEARCHINDEX_CREATE_MISSING_NAME_0));
207         }
208         if (m_indexSources.keySet().contains(name)) {
209             throw new CmsIllegalArgumentException(Messages.get().container(
210                 Messages.ERR_SEARCHINDEX_CREATE_INVALID_NAME_1,
211                 name));
212         }
213
214         m_indexes.add(searchIndex);
215
216         if (CmsLog.INIT.isInfoEnabled()) {
217             CmsLog.INIT.info(Messages.get().getBundle().key(
218                 Messages.INIT_ADD_SEARCH_INDEX_2,
219                 searchIndex.getName(),
220                 searchIndex.getProject()));
221         }
222     }
223
224     /**
225      * Adds a search index source configuration.<p>
226      *
227      * @param searchIndexSource a search index source configuration
228      */

229     public void addSearchIndexSource(CmsSearchIndexSource searchIndexSource) {
230
231         m_indexSources.put(searchIndexSource.getName(), searchIndexSource);
232
233         if (CmsLog.INIT.isInfoEnabled()) {
234             CmsLog.INIT.info(Messages.get().getBundle().key(
235                 Messages.INIT_SEARCH_INDEX_SOURCE_2,
236                 searchIndexSource.getName(),
237                 searchIndexSource.getIndexerClassName()));
238         }
239     }
240
241     /**
242      * Implements the event listener of this class.<p>
243      *
244      * @see org.opencms.main.I_CmsEventListener#cmsEvent(org.opencms.main.CmsEvent)
245      */

246     public void cmsEvent(CmsEvent event) {
247
248         switch (event.getType()) {
249             case I_CmsEventListener.EVENT_CLEAR_CACHES:
250                 if (m_resultCache != null) {
251                     m_resultCache.clear();
252                 }
253                 if (LOG.isDebugEnabled()) {
254                     LOG.debug(Messages.get().getBundle().key(Messages.LOG_EVENT_CLEAR_CACHES_0));
255                 }
256                 break;
257             case I_CmsEventListener.EVENT_PUBLISH_PROJECT:
258                 // event data contains a list of the published resources
259
CmsUUID publishHistoryId = new CmsUUID((String JavaDoc)event.getData().get(I_CmsEventListener.KEY_PUBLISHID));
260                 if (LOG.isDebugEnabled()) {
261                     LOG.debug(Messages.get().getBundle().key(Messages.LOG_EVENT_PUBLISH_PROJECT_1, publishHistoryId));
262                 }
263                 I_CmsReport report = (I_CmsReport)event.getData().get(I_CmsEventListener.KEY_REPORT);
264                 updateAllIndexes(m_adminCms, publishHistoryId, report);
265                 if (LOG.isDebugEnabled()) {
266                     LOG.debug(Messages.get().getBundle().key(
267                         Messages.LOG_EVENT_PUBLISH_PROJECT_FINISHED_1,
268                         publishHistoryId));
269                 }
270                 break;
271             default:
272         // no operation
273
}
274     }
275
276     /**
277      * Returns an unmodifiable view (read-only) of the Analyzers Map.<p>
278      *
279      * @return an unmodifiable view (read-only) of the Analyzers Map
280      */

281     public Map JavaDoc getAnalyzers() {
282
283         return Collections.unmodifiableMap(m_analyzers);
284     }
285
286     /**
287      * Returns the CmsSearchAnalyzer Object.<p>
288      * @param locale unique locale key to specify the CmsSearchAnalyzer in HashMap
289      * @return the CmsSearchAnalyzer Object
290      */

291     public CmsSearchAnalyzer getCmsSearchAnalyzer(String JavaDoc locale) {
292
293         return (CmsSearchAnalyzer)m_analyzers.get(locale);
294     }
295
296     /**
297      * Returns the name of the directory below WEB-INF/ where the search indexes are stored.<p>
298      *
299      * @return the name of the directory below WEB-INF/ where the search indexes are stored
300      */

301     public String JavaDoc getDirectory() {
302
303         return m_path;
304     }
305
306     /**
307      * Returns a document type config.<p>
308      *
309      * @param name the name of the document type config
310      * @return the document type config.
311      */

312     public CmsSearchDocumentType getDocumentTypeConfig(String JavaDoc name) {
313
314         return (CmsSearchDocumentType)m_documentTypeConfigs.get(name);
315     }
316
317     /**
318      * Returns an unmodifiable view (read-only) of the DocumentTypeConfigs Map.<p>
319      *
320      * @return an unmodifiable view (read-only) of the DocumentTypeConfigs Map
321      */

322     public Map JavaDoc getDocumentTypeConfigs() {
323
324         return Collections.unmodifiableMap(m_documentTypeConfigs);
325     }
326
327     /**
328      * Returns the highlighter.<p>
329      *
330      * @return the highlighter
331      */

332     public I_CmsTermHighlighter getHighlighter() {
333
334         return m_highlighter;
335     }
336
337     /**
338      * Returns the index belonging to the passed name.<p>
339      * The index must exist already.
340      *
341      * @param indexName then name of the index
342      * @return an object representing the desired index
343      */

344     public CmsSearchIndex getIndex(String JavaDoc indexName) {
345
346         for (int i = 0, n = m_indexes.size(); i < n; i++) {
347             CmsSearchIndex searchIndex = (CmsSearchIndex)m_indexes.get(i);
348
349             if (indexName.equalsIgnoreCase(searchIndex.getName())) {
350                 return searchIndex;
351             }
352         }
353
354         return null;
355     }
356
357     /**
358      * Returns the seconds to wait for an index lock during an update operation.<p>
359      *
360      * @return the seconds to wait for an index lock during an update operation
361      */

362     public int getIndexLockMaxWaitSeconds() {
363
364         return m_indexLockMaxWaitSeconds;
365     }
366
367     /**
368      * Returns the names of all configured indexes.<p>
369      *
370      * @return list of names
371      */

372     public List JavaDoc getIndexNames() {
373
374         List JavaDoc indexNames = new ArrayList JavaDoc();
375         for (int i = 0, n = m_indexes.size(); i < n; i++) {
376             indexNames.add(((CmsSearchIndex)m_indexes.get(i)).getName());
377         }
378
379         return indexNames;
380     }
381
382     /**
383      * Returns a search index source for a specified source name.<p>
384      *
385      * @param sourceName the name of the index source
386      * @return a search index source
387      */

388     public CmsSearchIndexSource getIndexSource(String JavaDoc sourceName) {
389
390         return (CmsSearchIndexSource)m_indexSources.get(sourceName);
391     }
392
393     /**
394      * Returns the max. excerpt length.<p>
395      *
396      * @return the max excerpt length
397      */

398     public int getMaxExcerptLength() {
399
400         return m_maxExcerptLength;
401     }
402
403     /**
404      * Returns the result cache size.<p>
405      *
406      * @return the result cache size
407      */

408     public String JavaDoc getResultCacheSize() {
409
410         return m_resultCacheSize;
411     }
412
413     /**
414      * Returns an unmodifiable list of all configured <code>{@link CmsSearchIndex}</code> instances.<p>
415      *
416      * @return an unmodifiable list of all configured <code>{@link CmsSearchIndex}</code> instances
417      */

418     public List JavaDoc getSearchIndexes() {
419
420         return Collections.unmodifiableList(m_indexes);
421     }
422
423     /**
424      * Returns an unmodifiable view (read-only) of the SearchIndexSources Map.<p>
425      *
426      * @return an unmodifiable view (read-only) of the SearchIndexSources Map
427      */

428     public Map JavaDoc getSearchIndexSources() {
429
430         return Collections.unmodifiableMap(m_indexSources);
431     }
432
433     /**
434      * Returns the timeout to abandon threads indexing a resource.<p>
435      *
436      * @return the timeout to abandon threads indexing a resource
437      */

438     public String JavaDoc getTimeout() {
439
440         return m_timeout;
441     }
442
443     /**
444      * Initializes the search manager.<p>
445      *
446      * @param cms the cms object
447      *
448      * @throws CmsRoleViolationException in case the given opencms object does not have <code>{@link CmsRole#SEARCH_MANAGER}</code> permissions
449      */

450     public void initialize(CmsObject cms) throws CmsRoleViolationException {
451
452         cms.checkRole(CmsRole.SEARCH_MANAGER);
453         try {
454             // store the Admin cms to index Cms resources
455
m_adminCms = OpenCms.initCmsObject(cms);
456         } catch (CmsException e) {
457             // this should never happen
458
}
459         // make sure the site root is the root site
460
m_adminCms.getRequestContext().setSiteRoot("/");
461
462         // init. the search result cache
463
LRUMap hashMap = new LRUMap(Integer.parseInt(m_resultCacheSize));
464         m_resultCache = Collections.synchronizedMap(hashMap);
465
466         if (OpenCms.getMemoryMonitor().enabled()) {
467             OpenCms.getMemoryMonitor().register(getClass().getName() + ".m_resultCache", hashMap);
468         }
469
470         initializeIndexes();
471
472         // register the modified default similarity implementation
473
Similarity.setDefault(new CmsSearchSimilarity());
474
475         // register this object as event listener
476
OpenCms.addCmsEventListener(this, new int[] {
477             I_CmsEventListener.EVENT_CLEAR_CACHES,
478             I_CmsEventListener.EVENT_PUBLISH_PROJECT});
479     }
480
481     /**
482      * Initializes all configured document types and search indexes.<p>
483      *
484      * This methods needs to be called if after a change in the index configuration has been made.
485      */

486     public void initializeIndexes() {
487
488         initAvailableDocumentTypes();
489         initSearchIndexes();
490     }
491
492     /**
493      * Updates the indexes from as a scheduled job.<p>
494      *
495      * @param cms the OpenCms user context to use when reading resources from the VFS
496      * @param parameters the parameters for the scheduled job
497      *
498      * @throws Exception if something goes wrong
499      *
500      * @return the String to write in the scheduler log
501      *
502      * @see org.opencms.scheduler.I_CmsScheduledJob#launch(org.opencms.file.CmsObject, java.util.Map)
503      */

504     public final String JavaDoc launch(CmsObject cms, Map JavaDoc parameters) throws Exception JavaDoc {
505
506         CmsSearchManager manager = OpenCms.getSearchManager();
507
508         I_CmsReport report = null;
509         boolean writeLog = Boolean.valueOf((String JavaDoc)parameters.get(JOB_PARAM_WRITELOG)).booleanValue();
510
511         if (writeLog) {
512             report = new CmsLogReport(cms.getRequestContext().getLocale(), CmsSearchManager.class);
513         }
514
515         List JavaDoc updateList = null;
516         String JavaDoc indexList = (String JavaDoc)parameters.get(JOB_PARAM_INDEXLIST);
517         if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(indexList)) {
518             // index list has been provided as job parameter
519
updateList = new ArrayList JavaDoc();
520             String JavaDoc[] indexNames = CmsStringUtil.splitAsArray(indexList, '|');
521             for (int i = 0; i < indexNames.length; i++) {
522                 // check if the index actually exists
523
if (manager.getIndex(indexNames[i]) != null) {
524                     updateList.add(indexNames[i]);
525                 } else {
526                     if (LOG.isWarnEnabled()) {
527                         LOG.warn(Messages.get().getBundle().key(Messages.LOG_NO_INDEX_WITH_NAME_1, indexNames[i]));
528                     }
529                 }
530             }
531         }
532
533         long startTime = System.currentTimeMillis();
534
535         if (updateList == null) {
536             // all indexes need to be updated
537
manager.rebuildAllIndexes(report);
538         } else {
539             // rebuild only the selected indexes
540
manager.rebuildIndexes(updateList, report);
541         }
542
543         long runTime = System.currentTimeMillis() - startTime;
544
545         String JavaDoc finishMessage = Messages.get().getBundle().key(
546             Messages.LOG_REBUILD_INDEXES_FINISHED_1,
547             CmsStringUtil.formatRuntime(runTime));
548
549         if (LOG.isInfoEnabled()) {
550             LOG.info(finishMessage);
551         }
552         return finishMessage;
553     }
554
555     /**
556      * Rebuilds (if required creates) all configured indexes.<p>
557      *
558      * @param report the report object to write messages (or <code>null</code>)
559      *
560      * @throws CmsException if something goes wrong
561      */

562     public void rebuildAllIndexes(I_CmsReport report) throws CmsException {
563
564         rebuildAllIndexes(report, false);
565     }
566
567     /**
568      * Rebuilds (if required creates) all configured indexes.<p>
569      *
570      * @param report the report object to write messages (or <code>null</code>)
571      * @param wait signals to wait until all the indexing threads are finished
572      *
573      * @throws CmsException if something goes wrong
574      */

575     public void rebuildAllIndexes(I_CmsReport report, boolean wait) throws CmsException {
576
577         CmsMessageContainer container = null;
578         for (int i = 0, n = m_indexes.size(); i < n; i++) {
579             // iterate all configured seach indexes
580
CmsSearchIndex searchIndex = (CmsSearchIndex)m_indexes.get(i);
581             try {
582                 // update the index
583
updateIndex(searchIndex, report, wait, null, null);
584             } catch (CmsException e) {
585                 container = new CmsMessageContainer(
586                     Messages.get(),
587                     Messages.ERR_INDEX_REBUILD_ALL_1,
588                     new Object JavaDoc[] {searchIndex.getName()});
589                 LOG.error(Messages.get().getBundle().key(Messages.ERR_INDEX_REBUILD_ALL_1, searchIndex.getName()), e);
590             }
591         }
592         if (container != null) {
593             // throw stored exception
594
throw new CmsSearchException(container);
595         }
596     }
597
598     /**
599      * Rebuilds (if required creates) the index with the given name.<p>
600      *
601      * @param indexName the name of the index to rebuild
602      * @param report the report object to write messages (or <code>null</code>)
603      *
604      * @throws CmsException if something goes wrong
605      */

606     public void rebuildIndex(String JavaDoc indexName, I_CmsReport report) throws CmsException {
607
608         // get the search index by name
609
CmsSearchIndex index = getIndex(indexName);
610         // update the index
611
updateIndex(index, report, false, null, null);
612     }
613
614     /**
615      * Rebuilds (if required creates) the List of indexes with the given name.<p>
616      *
617      * @param indexNames the names (String) of the index to rebuild
618      * @param report the report object to write messages (or <code>null</code>)
619      *
620      * @throws CmsException if something goes wrong
621      */

622     public void rebuildIndexes(List JavaDoc indexNames, I_CmsReport report) throws CmsException {
623
624         Iterator JavaDoc i = indexNames.iterator();
625         while (i.hasNext()) {
626             String JavaDoc indexName = (String JavaDoc)i.next();
627             // get the search index by name
628
CmsSearchIndex index = getIndex(indexName);
629             if (index != null) {
630                 // update the index
631
updateIndex(index, report, false, null, null);
632             } else {
633                 if (LOG.isWarnEnabled()) {
634                     LOG.warn(Messages.get().getBundle().key(Messages.LOG_NO_INDEX_WITH_NAME_1, indexName));
635                 }
636             }
637         }
638     }
639
640     /**
641      * Removes a search index from the configuration.<p>
642      *
643      * @param searchIndex the search index to remove
644      */

645     public void removeSearchIndex(CmsSearchIndex searchIndex) {
646
647         m_indexes.remove(searchIndex);
648
649         if (LOG.isInfoEnabled()) {
650             LOG.info(Messages.get().getBundle().key(
651                 Messages.LOG_REMOVE_SEARCH_INDEX_2,
652                 searchIndex.getName(),
653                 searchIndex.getProject()));
654         }
655     }
656
657     /**
658      * Removes all indexes included in the given list (which must contain the name of an index to remove).<p>
659      *
660      * @param indexNames the names of the index to remove
661      */

662     public void removeSearchIndexes(List JavaDoc indexNames) {
663
664         Iterator JavaDoc i = indexNames.iterator();
665         while (i.hasNext()) {
666             String JavaDoc indexName = (String JavaDoc)i.next();
667             // get the search index by name
668
CmsSearchIndex index = getIndex(indexName);
669             if (index != null) {
670                 // remove the index
671
removeSearchIndex(index);
672             } else {
673                 if (LOG.isWarnEnabled()) {
674                     LOG.warn(Messages.get().getBundle().key(Messages.LOG_NO_INDEX_WITH_NAME_1, indexName));
675                 }
676             }
677         }
678     }
679
680     /**
681      * Removes this indexsource from the OpenCms configuration (if it is not used any more).<p>
682      *
683      *
684      *
685      * @param indexsource the indexsource to remove from the configuration
686      *
687      * @return true if remove was successful, false if preconditions for removal are ok but the given
688      * searchindex was unknown to the manager.
689      *
690      * @throws CmsIllegalStateException if the given indexsource is still used by at least one
691      * <code>{@link CmsSearchIndex}</code>.
692      *
693      */

694     public boolean removeSearchIndexSource(CmsSearchIndexSource indexsource) throws CmsIllegalStateException {
695
696         // validation if removal will be granted
697
Iterator JavaDoc itIndexes = m_indexes.iterator();
698         CmsSearchIndex idx;
699         // the list for collecting indexes that use the given indexdsource
700
List JavaDoc referrers = new LinkedList JavaDoc();
701         // the current list of referred indexsources of the iterated index
702
List JavaDoc refsources;
703         while (itIndexes.hasNext()) {
704             idx = (CmsSearchIndex)itIndexes.next();
705             refsources = idx.getSources();
706             if (refsources != null) {
707                 if (refsources.contains(indexsource)) {
708                     referrers.add(idx);
709                 }
710             }
711         }
712         if (referrers.size() > 0) {
713             throw new CmsIllegalStateException(Messages.get().container(
714                 Messages.ERR_INDEX_SOURCE_DELETE_2,
715                 indexsource.getName(),
716                 referrers.toString()));
717         }
718
719         // remove operation (no exception)
720
return m_indexSources.remove(indexsource.getName()) != null;
721
722     }
723
724     /**
725      * Sets the name of the directory below WEB-INF/ where the search indexes are stored.<p>
726      *
727      * @param value the name of the directory below WEB-INF/ where the search indexes are stored
728      */

729     public void setDirectory(String JavaDoc value) {
730
731         m_path = value;
732     }
733
734     /**
735      * Sets the highlighter.<p>
736      *
737      * A highlighter is a class implementing org.opencms.search.documents.I_TermHighlighter.<p>
738      *
739      * @param highlighter the package/class name of the highlighter
740      */

741     public void setHighlighter(String JavaDoc highlighter) {
742
743         try {
744             m_highlighter = (I_CmsTermHighlighter)Class.forName(highlighter).newInstance();
745         } catch (Exception JavaDoc exc) {
746             m_highlighter = null;
747         }
748     }
749
750     /**
751      * Sets the seconds to wait for an index lock during an update operation.<p>
752      *
753      * @param value the seconds to wait for an index lock during an update operation
754      */

755     public void setIndexLockMaxWaitSeconds(int value) {
756
757         m_indexLockMaxWaitSeconds = value;
758     }
759
760     /**
761      * Sets the max. excerpt length.<p>
762      *
763      * @param maxExcerptLength the max. excerpt length to set
764      */

765     public void setMaxExcerptLength(String JavaDoc maxExcerptLength) {
766
767         try {
768             m_maxExcerptLength = Integer.parseInt(maxExcerptLength);
769         } catch (Exception JavaDoc e) {
770             LOG.error(Messages.get().getBundle().key(Messages.LOG_PARSE_EXCERPT_LENGTH_FAILED_1, maxExcerptLength), e);
771             m_maxExcerptLength = 1024;
772         }
773     }
774
775     /**
776      * Sets the result cache size.<p>
777      *
778      * @param value the result cache size
779      */

780     public void setResultCacheSize(String JavaDoc value) {
781
782         m_resultCacheSize = value;
783     }
784
785     /**
786      * Sets the timeout to abandon threads indexing a resource.<p>
787      *
788      * @param value the timeout in milliseconds
789      */

790     public void setTimeout(String JavaDoc value) {
791
792         m_timeout = value;
793     }
794
795     /**
796      * Checks is a given index is locked, if so waits for a numer of seconds and checks again,
797      * until either the index is unlocked or a limit of seconds set by <code>{@link #setIndexLockMaxWaitSeconds(int)}</code>
798      * is reached.<p>
799      *
800      * @param index the index to check the lock for
801      * @param report the report to write error messages on
802      *
803      * @return <code>true</code> if the index is locked
804      */

805     protected boolean checkIndexLock(CmsSearchIndex index, I_CmsReport report) {
806
807         File JavaDoc indexPath = new File JavaDoc(index.getPath());
808         // check if the target index path already exists
809
if (!indexPath.exists()) {
810             // if the folder does not yet exist it is also not locked
811
return false;
812         }
813
814         // check if the index is locked
815
boolean indexLocked = true;
816         try {
817             int lockSecs = 0;
818             while (indexLocked && (lockSecs < m_indexLockMaxWaitSeconds)) {
819                 indexLocked = IndexReader.isLocked(index.getPath());
820                 if (indexLocked) {
821                     // index is still locked, wait one second
822
report.println(Messages.get().container(
823                         Messages.RPT_SEARCH_INDEXING_LOCK_WAIT_2,
824                         index.getName(),
825                         new Integer JavaDoc(m_indexLockMaxWaitSeconds - lockSecs)), I_CmsReport.FORMAT_ERROR);
826                     // sleep one second
827
Thread.sleep(1000);
828                     lockSecs++;
829                 }
830             }
831         } catch (Exception JavaDoc e) {
832             LOG.error(Messages.get().getBundle().key(
833                 Messages.LOG_IO_INDEX_READER_OPEN_2,
834                 index.getPath(),
835                 index.getName()), e);
836         }
837
838         return indexLocked;
839     }
840
841     /**
842      * Returns an analyzer for the given language.<p>
843      * The analyzer is selected according to the analyzer configuration.
844      *
845      * @param locale a language id, i.e. de, en, it
846      * @return the appropriate lucene analyzer
847      * @throws CmsIndexException if something goes wrong
848      */

849     protected Analyzer getAnalyzer(String JavaDoc locale) throws CmsIndexException {
850
851         Analyzer analyzer = null;
852         String JavaDoc className = null;
853
854         CmsSearchAnalyzer analyzerConf = (CmsSearchAnalyzer)m_analyzers.get(locale);
855         if (analyzerConf == null) {
856             throw new CmsIndexException(Messages.get().container(Messages.ERR_ANALYZER_NOT_FOUND_1, locale));
857         }
858
859         try {
860             className = analyzerConf.getClassName();
861             Class JavaDoc analyzerClass = Class.forName(className);
862
863             // added param for snowball analyzer
864
String JavaDoc stemmerAlgorithm = analyzerConf.getStemmerAlgorithm();
865             if (stemmerAlgorithm != null) {
866                 analyzer = (Analyzer)analyzerClass.getDeclaredConstructor(new Class JavaDoc[] {String JavaDoc.class}).newInstance(
867                     new Object JavaDoc[] {stemmerAlgorithm});
868             } else {
869                 analyzer = (Analyzer)analyzerClass.newInstance();
870             }
871
872         } catch (Exception JavaDoc e) {
873             throw new CmsIndexException(Messages.get().container(Messages.ERR_LOAD_ANALYZER_1, className), e);
874         }
875
876         return analyzer;
877     }
878
879     /**
880      * Returns a lucene document factory for given resource.<p>
881      * The type of the document factory is selected by the type of the resource
882      * and the mimetype of the resource content according to the documenttype configuration.
883      *
884      * @param resource a cms resource
885      * @return a lucene document factory or null
886      */

887     protected I_CmsDocumentFactory getDocumentFactory(A_CmsIndexResource resource) {
888
889         String JavaDoc documentTypeKey = resource.getDocumentKey(true);
890
891         I_CmsDocumentFactory factory = (I_CmsDocumentFactory)m_documentTypes.get(documentTypeKey);
892         if (factory == null) {
893             factory = (I_CmsDocumentFactory)m_documentTypes.get(resource.getDocumentKey(false));
894         }
895
896         return factory;
897     }
898
899     /**
900      * Returns the set of names of all configured documenttypes.<p>
901      *
902      * @return the set of names of all configured documenttypes
903      */

904     protected List JavaDoc getDocumentTypes() {
905
906         List JavaDoc names = new ArrayList JavaDoc();
907         for (Iterator JavaDoc i = m_documentTypes.values().iterator(); i.hasNext();) {
908             I_CmsDocumentFactory factory = (I_CmsDocumentFactory)i.next();
909             names.add(factory.getName());
910         }
911
912         return names;
913     }
914
915     /**
916      * Returns the common cache for buffering search results.<p>
917      *
918      * @return the cache
919      */

920     protected Map JavaDoc getResultCache() {
921
922         return m_resultCache;
923     }
924
925     /**
926      * Initializes the available Cms resource types to be indexed.<p>
927      *
928      * A map stores document factories keyed by a string representing
929      * a colon separated list of Cms resource types and/or mimetypes.<p>
930      *
931      * The keys of this map are used to trigger a document factory to convert
932      * a Cms resource into a Lucene index document.<p>
933      *
934      * A document factory is a class implementing the interface
935      * {@link org.opencms.search.documents.I_CmsDocumentFactory}.<p>
936      */

937     protected void initAvailableDocumentTypes() {
938
939         CmsSearchDocumentType documenttype = null;
940         String JavaDoc className = null;
941         String JavaDoc name = null;
942         I_CmsDocumentFactory documentFactory = null;
943         List JavaDoc resourceTypes = null;
944         List JavaDoc mimeTypes = null;
945         Class JavaDoc c = null;
946
947         m_documentTypes = new HashMap JavaDoc();
948
949         List JavaDoc keys = new ArrayList JavaDoc(m_documentTypeConfigs.keySet());
950         for (int i = 0, n = keys.size(); i < n; i++) {
951
952             documenttype = (CmsSearchDocumentType)(m_documentTypeConfigs.get(keys.get(i)));
953             name = documenttype.getName();
954
955             try {
956                 className = documenttype.getClassName();
957                 resourceTypes = documenttype.getResourceTypes();
958                 mimeTypes = documenttype.getMimeTypes();
959
960                 if (name == null) {
961                     throw new CmsIndexException(Messages.get().container(Messages.ERR_DOCTYPE_NO_NAME_0));
962                 }
963                 if (className == null) {
964                     throw new CmsIndexException(Messages.get().container(Messages.ERR_DOCTYPE_NO_CLASS_DEF_0));
965                 }
966                 if (resourceTypes.size() == 0) {
967                     throw new CmsIndexException(Messages.get().container(Messages.ERR_DOCTYPE_NO_RESOURCETYPE_DEF_0));
968                 }
969
970                 try {
971                     c = Class.forName(className);
972                     documentFactory = (I_CmsDocumentFactory)c.getConstructor(new Class JavaDoc[] {String JavaDoc.class}).newInstance(
973                         new Object JavaDoc[] {name});
974                 } catch (ClassNotFoundException JavaDoc exc) {
975                     throw new CmsIndexException(
976                         Messages.get().container(Messages.ERR_DOCCLASS_NOT_FOUND_1, className),
977                         exc);
978                 } catch (Exception JavaDoc exc) {
979                     throw new CmsIndexException(Messages.get().container(Messages.ERR_DOCCLASS_INIT_1, className), exc);
980                 }
981
982                 for (Iterator JavaDoc key = documentFactory.getDocumentKeys(resourceTypes, mimeTypes).iterator(); key.hasNext();) {
983                     m_documentTypes.put(key.next(), documentFactory);
984                 }
985
986             } catch (CmsException e) {
987                 if (LOG.isWarnEnabled()) {
988                     LOG.warn(Messages.get().getBundle().key(Messages.LOG_DOCTYPE_CONFIG_FAILED_1, name), e);
989                 }
990             }
991         }
992     }
993
994     /**
995      * Initializes the configured search indexes.<p>
996      *
997      * This initializes also the list of Cms resources types
998      * to be indexed by an index source.<p>
999      */

1000    protected void initSearchIndexes() {
1001
1002        CmsSearchIndex index = null;
1003        for (int i = 0, n = m_indexes.size(); i < n; i++) {
1004            index = (CmsSearchIndex)m_indexes.get(i);
1005            // reset disabled flag
1006
index.setEnabled(true);
1007            // check if the index has been configured correctly
1008
if (index.checkConfiguration(m_adminCms)) {
1009                // the index is configured correctly
1010
try {
1011                    index.initialize();
1012                } catch (CmsException e) {
1013                    // in this case the index will be disabled
1014
if (CmsLog.INIT.isInfoEnabled()) {
1015                        CmsLog.INIT.info(Messages.get().getBundle().key(
1016                            Messages.INIT_SEARCH_INIT_FAILED_1,
1017                            index.getName()), e);
1018                    }
1019                }
1020            }
1021            if (CmsLog.INIT.isInfoEnabled()) {
1022                // output a log message if the index was successfully configured or not
1023
if (index.isEnabled()) {
1024                    CmsLog.INIT.info(Messages.get().getBundle().key(
1025                        Messages.INIT_INDEX_CONFIGURED_2,
1026                        index.getName(),
1027                        index.getProject()));
1028                } else {
1029                    CmsLog.INIT.info(Messages.get().getBundle().key(
1030                        Messages.INIT_INDEX_NOT_CONFIGURED_2,
1031                        index.getName(),
1032                        index.getProject()));
1033                }
1034            }
1035        }
1036    }
1037
1038    /**
1039     * Incrementally updates all indexes that have their rebuild mode set to <code>"auto"</code>
1040     * after resources have been published.<p>
1041     *
1042     * @param adminCms an OpenCms user context with Admin permissions
1043     * @param publishHistoryId the history ID of the published project
1044     * @param report the report to write the output to
1045     */

1046    protected synchronized void updateAllIndexes(CmsObject adminCms, CmsUUID publishHistoryId, I_CmsReport report) {
1047
1048        List JavaDoc publishedResources;
1049        try {
1050            // read the list of all published resources
1051
publishedResources = adminCms.readPublishedResources(publishHistoryId);
1052        } catch (CmsException e) {
1053            LOG.error(
1054                Messages.get().getBundle().key(Messages.LOG_READING_CHANGED_RESOURCES_FAILED_1, publishHistoryId),
1055                e);
1056            return;
1057        }
1058
1059        List JavaDoc updateResources = new ArrayList JavaDoc();
1060        Iterator JavaDoc itPubRes = publishedResources.iterator();
1061        while (itPubRes.hasNext()) {
1062            CmsPublishedResource res = (CmsPublishedResource)itPubRes.next();
1063            if (res.isFolder() || res.isUnChanged() || !res.isVfsResource()) {
1064                // folders, unchanged resources and non vfs resources don't need to be indexed after publish
1065
continue;
1066            }
1067            if (res.isDeleted() || res.isNew() || res.isChanged()) {
1068                if (updateResources.contains(res)) {
1069                    // resource may have been added as a sibling of another resource
1070
// in this case we make sure to use the value from the publih list because of the "deleted" flag
1071
updateResources.remove(res);
1072                    // "equals()" implementation of published resource only checks for path,
1073
// so the removed value may have a different "deleted" or "modified" status value
1074
updateResources.add(res);
1075                } else {
1076                    // resource not yet contained in the list
1077
updateResources.add(res);
1078                    // check for the siblings (not for deleted resources, these are already gone)
1079
if (!res.isDeleted() && (res.getSiblingCount() > 1)) {
1080                        // this resource has siblings
1081
try {
1082                            // read siblings from the online project
1083
List JavaDoc siblings = adminCms.readSiblings(res.getRootPath(), CmsResourceFilter.ALL);
1084                            Iterator JavaDoc itSib = siblings.iterator();
1085                            while (itSib.hasNext()) {
1086                                // check all siblings
1087
CmsResource sibling = (CmsResource)itSib.next();
1088                                CmsPublishedResource sib = new CmsPublishedResource(sibling);
1089                                if (!updateResources.contains(sib)) {
1090                                    // ensure sibling is added only once
1091
updateResources.add(sib);
1092                                }
1093                            }
1094                        } catch (CmsException e) {
1095                            // ignore, just use the original resource
1096
if (LOG.isWarnEnabled()) {
1097                                LOG.warn(Messages.get().getBundle().key(
1098                                    Messages.LOG_UNABLE_TO_READ_SIBLINGS_1,
1099                                    res.getRootPath()), e);
1100                            }
1101                        }
1102                    }
1103                }
1104            }
1105        }
1106
1107        // cache for the generated documents (to avoid multiple text extraction in case of overlapping indexes)
1108
Map JavaDoc documentCache = Collections.synchronizedMap(new LRUMap(256));
1109
1110        if (!updateResources.isEmpty()) {
1111            // sort the resource to update
1112
Collections.sort(updateResources);
1113            // only update the indexes if the list of remaining published resources is not empty
1114
Iterator JavaDoc i = m_indexes.iterator();
1115            while (i.hasNext()) {
1116                CmsSearchIndex index = (CmsSearchIndex)i.next();
1117                if (CmsSearchIndex.REBUILD_MODE_AUTO.equals(index.getRebuildMode())) {
1118                    // only update indexes which have the rebuild mode set to "auto"
1119
try {
1120                        updateIndex(index, report, false, updateResources, documentCache);
1121                    } catch (CmsException e) {
1122                        LOG.error(
1123                            Messages.get().getBundle().key(Messages.LOG_UPDATE_INDEX_FAILED_1, index.getName()),
1124                            e);
1125                    }
1126                }
1127            }
1128        }
1129    }
1130
1131    /**
1132     * Updates (if required creates) the index with the given name.<p>
1133     *
1134     * If the optional List of <code>{@link CmsPublishedResource}</code> instances is provided, the index will be
1135     * incrementally updated for these resources only. If this List is <code>null</code> or empty,
1136     * the index will be fully rebuild.<p>
1137     *
1138     * @param index the index to update or rebuild
1139     * @param report the report to write output messages to
1140     * @param wait signals to wait until all the indexing threads are finished
1141     * @param resourcesToIndex an (optional) list of <code>{@link CmsPublishedResource}</code> objects to update in the index
1142     * @param documentCache a cache for the created search documents, to avoid multiple text extraction
1143     *
1144     * @throws CmsException if something goes wrong
1145     */

1146    protected synchronized void updateIndex(
1147        CmsSearchIndex index,
1148        I_CmsReport report,
1149        boolean wait,
1150        List JavaDoc resourcesToIndex,
1151        Map JavaDoc documentCache) throws CmsException {
1152
1153        // copy the stored admin context for the indexing
1154
CmsObject cms = OpenCms.initCmsObject(m_adminCms);
1155        // make sure a report is available
1156
if (report == null) {
1157            report = new CmsLogReport(cms.getRequestContext().getLocale(), CmsSearchManager.class);
1158        }
1159
1160        // check if the index has been configured correctly
1161
if (!index.checkConfiguration(cms)) {
1162            // the index is disabled
1163
return;
1164        }
1165
1166        // set site root and project for this index
1167
cms.getRequestContext().setSiteRoot("/");
1168        // switch to the index project
1169
cms.getRequestContext().setCurrentProject(cms.readProject(index.getProject()));
1170
1171        if ((resourcesToIndex == null) || resourcesToIndex.isEmpty()) {
1172            // rebuild the complete index
1173

1174            if (checkIndexLock(index, report)) {
1175                // unable to lock the index for updating
1176
try {
1177                    // try to force unlock on the index (full rebuild is done anyway)
1178
IndexReader.unlock(FSDirectory.getDirectory(index.getPath(), false));
1179                } catch (Exception JavaDoc e) {
1180                    // unable to force unlock of Lucene index, we can't continue this way
1181
CmsMessageContainer msg = Messages.get().container(
1182                        Messages.ERR_INDEX_LOCK_FAILED_1,
1183                        index.getName());
1184                    report.println(msg, I_CmsReport.FORMAT_ERROR);
1185                    throw new CmsIndexException(msg, e);
1186                }
1187            }
1188
1189            // create a new thread manager for the indexing threads
1190
// please note: document cache _must_ be null for full rebuild
1191
// since there may be diffeences between online and offline projects,
1192
// which can only be ignored if a resource has just been published (then online=offline)
1193
CmsIndexingThreadManager threadManager = new CmsIndexingThreadManager(
1194                report,
1195                Long.parseLong(m_timeout),
1196                index.getName(),
1197                null);
1198
1199            IndexWriter writer = null;
1200            try {
1201                // create a new index writer
1202
writer = index.getIndexWriter(true);
1203
1204                // ouput start information on the report
1205
report.println(
1206                    Messages.get().container(Messages.RPT_SEARCH_INDEXING_REBUILD_BEGIN_1, index.getName()),
1207                    I_CmsReport.FORMAT_HEADLINE);
1208
1209                // iterate all configured index sources of this index
1210
Iterator JavaDoc sources = index.getSources().iterator();
1211                while (sources.hasNext()) {
1212                    // get the next index source
1213
CmsSearchIndexSource source = (CmsSearchIndexSource)sources.next();
1214                    // create the indexer
1215
I_CmsIndexer indexer = source.getIndexer().newInstance(cms, report, index);
1216                    // new index creation, use all resources from the index source
1217
indexer.rebuildIndex(writer, threadManager, source);
1218                }
1219
1220                // wait for indexing threads to finish
1221
while (wait && threadManager.isRunning()) {
1222                    try {
1223                        Thread.sleep(1000);
1224                    } catch (InterruptedException JavaDoc e) {
1225                        // just continue with the loop after interruption
1226
}
1227                }
1228                // optimize the generated index
1229
try {
1230                    writer.optimize();
1231                } catch (IOException JavaDoc e) {
1232                    if (LOG.isWarnEnabled()) {
1233                        LOG.warn(Messages.get().getBundle().key(
1234                            Messages.LOG_IO_INDEX_WRITER_OPTIMIZE_1,
1235                            index.getPath(),
1236                            index.getName()), e);
1237                    }
1238                }
1239
1240                // ouput finish information on the report
1241
report.println(
1242                    Messages.get().container(Messages.RPT_SEARCH_INDEXING_REBUILD_END_1, index.getName()),
1243                    I_CmsReport.FORMAT_HEADLINE);
1244
1245            } finally {
1246                if (writer != null) {
1247                    try {
1248                        writer.close();
1249                    } catch (IOException JavaDoc e) {
1250                        if (LOG.isWarnEnabled()) {
1251                            LOG.warn(Messages.get().getBundle().key(
1252                                Messages.LOG_IO_INDEX_WRITER_CLOSE_2,
1253                                index.getPath(),
1254                                index.getName()), e);
1255                        }
1256                    }
1257                }
1258            }
1259
1260            // show information about indexing runtime
1261
threadManager.reportStatistics();
1262
1263        } else {
1264            // update the existing index
1265

1266            List JavaDoc updateCollections = new ArrayList JavaDoc();
1267
1268            boolean hasResourcesToDelete = false;
1269            boolean hasResourcesToUpdate = false;
1270
1271            // iterate all configured index sources of this index
1272
Iterator JavaDoc sources = index.getSources().iterator();
1273            while (sources.hasNext()) {
1274                // get the next index source
1275
CmsSearchIndexSource source = (CmsSearchIndexSource)sources.next();
1276                // create the indexer
1277
I_CmsIndexer indexer = source.getIndexer().newInstance(cms, report, index);
1278                // collect the resources to update
1279
CmsSearchIndexUpdateData updateData = indexer.getUpdateData(source, resourcesToIndex);
1280                if (!updateData.isEmpty()) {
1281                    // add the update collection to the internal pipeline
1282
updateCollections.add(updateData);
1283                    hasResourcesToDelete = hasResourcesToDelete | updateData.hasResourcesToDelete();
1284                    hasResourcesToUpdate = hasResourcesToUpdate | updateData.hasResourceToUpdate();
1285                }
1286            }
1287
1288            if (hasResourcesToDelete || hasResourcesToUpdate) {
1289                // ouput start information on the report
1290
report.println(
1291                    Messages.get().container(Messages.RPT_SEARCH_INDEXING_UPDATE_BEGIN_1, index.getName()),
1292                    I_CmsReport.FORMAT_HEADLINE);
1293            }
1294
1295            if (checkIndexLock(index, report)) {
1296                // unable to lock the index for updating
1297
CmsMessageContainer msg = Messages.get().container(Messages.ERR_INDEX_LOCK_FAILED_1, index.getName());
1298                report.println(msg, I_CmsReport.FORMAT_ERROR);
1299                throw new CmsIndexException(msg);
1300            }
1301
1302            if (hasResourcesToDelete) {
1303                // delete the resource from the index
1304
IndexReader reader = null;
1305                try {
1306                    reader = IndexReader.open(index.getPath());
1307                } catch (IOException JavaDoc e) {
1308                    LOG.error(Messages.get().getBundle().key(
1309                        Messages.LOG_IO_INDEX_READER_OPEN_2,
1310                        index.getPath(),
1311                        index.getName()), e);
1312                }
1313                if (reader != null) {
1314                    try {
1315                        Iterator JavaDoc i = updateCollections.iterator();
1316                        while (i.hasNext()) {
1317                            CmsSearchIndexUpdateData updateCollection = (CmsSearchIndexUpdateData)i.next();
1318                            if (updateCollection.hasResourcesToDelete()) {
1319                                updateCollection.getIndexer().deleteResources(
1320                                    reader,
1321                                    updateCollection.getResourcesToDelete());
1322                            }
1323                        }
1324                    } finally {
1325                        try {
1326                            // close the reader after all resources have been deleted
1327
reader.close();
1328                        } catch (IOException JavaDoc e) {
1329                            LOG.error(Messages.get().getBundle().key(
1330                                Messages.LOG_IO_INDEX_READER_CLOSE_2,
1331                                index.getPath(),
1332                                index.getName()), e);
1333                        }
1334                    }
1335                }
1336            }
1337
1338            if (hasResourcesToUpdate) {
1339
1340                // create a new thread manager
1341
CmsIndexingThreadManager threadManager = new CmsIndexingThreadManager(
1342                    report,
1343                    Long.parseLong(m_timeout),
1344                    index.getName(),
1345                    documentCache);
1346
1347                IndexWriter writer = null;
1348                try {
1349
1350                    // create an index writer that updates the current index
1351
writer = index.getIndexWriter(false);
1352
1353                    Iterator JavaDoc i = updateCollections.iterator();
1354                    while (i.hasNext()) {
1355                        CmsSearchIndexUpdateData updateCollection = (CmsSearchIndexUpdateData)i.next();
1356                        if (updateCollection.hasResourceToUpdate()) {
1357                            updateCollection.getIndexer().updateResources(
1358                                writer,
1359                                threadManager,
1360                                updateCollection.getResourcesToUpdate());
1361                        }
1362                    }
1363
1364                    // wait for indexing threads to finish
1365
while (wait && threadManager.isRunning()) {
1366                        try {
1367                            Thread.sleep(1000);
1368                        } catch (InterruptedException JavaDoc e) {
1369                            // just continue with the loop after interruption
1370
}
1371                    }
1372
1373                } finally {
1374                    if (writer != null) {
1375                        try {
1376                            writer.close();
1377                        } catch (IOException JavaDoc e) {
1378                            LOG.error(Messages.get().getBundle().key(
1379                                Messages.LOG_IO_INDEX_WRITER_CLOSE_2,
1380                                index.getPath(),
1381                                index.getName()), e);
1382                        }
1383                    }
1384                }
1385            }
1386
1387            if (hasResourcesToDelete || hasResourcesToUpdate) {
1388                // ouput finish information on the report
1389
report.println(
1390                    Messages.get().container(Messages.RPT_SEARCH_INDEXING_UPDATE_END_1, index.getName()),
1391                    I_CmsReport.FORMAT_HEADLINE);
1392            }
1393        }
1394
1395        // clear the cache for search results
1396
m_resultCache.clear();
1397    }
1398}
Popular Tags